From 962a672cb8e085ea490fb7011572ab1a79784e9a Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:27:10 -0400 Subject: [PATCH 01/13] Add module level docs --- api/ECNQueue.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 7c2ae1d..901bc92 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -1,4 +1,12 @@ -# TODO: Add ECNQueue module documentation +"""A library for interacting with Purdue ECN's Queue. + +This library allows for the creation of and interaction with individual issues called Items. +It also allows for the same with collections of Items called Queues. + +Raises: + # TODO: Add description(s) of when a ValueError is raised. + ValueError: [description] +""" #------------------------------------------------------------------------------# # Imports From 6c446628fde7abf546345a645a1c01ad0f77f358 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:27:57 -0400 Subject: [PATCH 02/13] Remove debug comment --- api/ECNQueue.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 901bc92..3e362a5 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -28,7 +28,6 @@ currentFileDirectory = os.path.dirname(currentFilePath) currentFileDirectoryParent = os.path.dirname(currentFileDirectory) queueDirectory = os.path.join(currentFileDirectoryParent, "q-snapshot") -#queueDirectory = "/usr/site/uds/qcopy/11" # Queues to not load in getQueues() queuesToIgnore = ["archives", "drafts", "inbox"] From d0f9bc60d880fbe3803b8f2cfb96349d480d9054 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:39:34 -0400 Subject: [PATCH 03/13] Add TODO for coral queue issues --- api/ECNQueue.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 3e362a5..8ae9a79 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -32,6 +32,7 @@ # Queues to not load in getQueues() queuesToIgnore = ["archives", "drafts", "inbox"] +# TODO: Investigate coral items not having a From header # B/c some items don't have a From field # See coral259 queuesToIgnore.append("coral") From 0c28cfecf600457a4be02dc323801b25435e909a Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:46:26 -0400 Subject: [PATCH 04/13] Update module docs --- api/ECNQueue.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 8ae9a79..2c89889 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -1,7 +1,23 @@ -"""A library for interacting with Purdue ECN's Queue. - -This library allows for the creation of and interaction with individual issues called Items. -It also allows for the same with collections of Items called Queues. +"""A library for interacting with Purdue ECN's ticketing system. + +This library allows interacting with queue Items (called Items) and collections +of items (called Queues). + +Example: + # Create a single Item (ce100) + >>> item = Item("ce", 100) + # Get the sender's email address from an Item + >>> item = Item("ce", 100) + >>> item.userEmail + + # Create an entire Queue (ce) + >>> queue = Queue("ce") + # Get the number of items in a Queue + >>> queue = Queue("ce") + >>> numItems = len(queue) + + # Get all queues (and their items) + >>> queues = getQueues() Raises: # TODO: Add description(s) of when a ValueError is raised. From a507ac7436455ccd19bea99ecf234e74b3c75c50 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:55:15 -0400 Subject: [PATCH 05/13] Add Item class doc block --- api/ECNQueue.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 2c89889..43ad0f0 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -59,7 +59,27 @@ # Classes #------------------------------------------------------------------------------# class Item: - # TODO: Add Item class documentation + """A single issue. + + Example: + # Create an Item (ce100) + >>> item = Item("ce", 100) + + Attributes: + lastUpdated: An ISO 8601 formatted time string showing the last time the file was updated according to the filesystem. + headers: A list of dictionaries containing header keys and values. + content: A list of section dictionaries. + isLocked: A boolean showing whether or not a lockfile for the item is present. + userEmail: The email address of the person who this item is from. + userName: The real name of the person who this item is from. + userAlias: The Purdue career account alias of the person this item is from. + assignedTo: The Purdue career account alias of the person this item is assigned to + subject: The subject of the original message for this item. + status: The most recent status update for the item. + priority: The most recent priority for this item. + department: The most recent department for this item. + dateReceived: The date this item was created. + """ def __init__(self, queue: str, number: int) -> None: From 4feaaada3d56709da58af5ac37df75777510c1f6 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:57:30 -0400 Subject: [PATCH 06/13] Add Queue doc block --- api/ECNQueue.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 43ad0f0..beab098 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -1174,7 +1174,17 @@ def __repr__(self) -> str: return self.queue + str(self.number) class Queue: - # TODO: Add Queue class documentation + """A collection of items. + + Example: + # Create a queue (ce) + >>> queue = Queue("ce") + + Attributes: + name: The name of the queue. + items: A list of Items in the queue. + jsonData: A JSON serializable representation of the Queue. + """ def __init__(self, name: str) -> None: self.name = name From ab3cb8a859e8a182e2df52b0444aae35a14578e4 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 14:58:09 -0400 Subject: [PATCH 07/13] Update Item doc block --- api/ECNQueue.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index beab098..1d28a59 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -79,6 +79,7 @@ class Item: priority: The most recent priority for this item. department: The most recent department for this item. dateReceived: The date this item was created. + jsonData: A JSON serializable representation of the Item. """ def __init__(self, queue: str, number: int) -> None: From b1d258b7c281434c9241701a60883a3ecfd819ec Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 15:14:25 -0400 Subject: [PATCH 08/13] Permenantly add coral queue to queuesToIgnore --- api/ECNQueue.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 1d28a59..ffc5ac0 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -46,12 +46,7 @@ queueDirectory = os.path.join(currentFileDirectoryParent, "q-snapshot") # Queues to not load in getQueues() -queuesToIgnore = ["archives", "drafts", "inbox"] - -# TODO: Investigate coral items not having a From header -# B/c some items don't have a From field -# See coral259 -queuesToIgnore.append("coral") +queuesToIgnore = ["archives", "drafts", "inbox", "coral"] From fea27fd5d83e1664d3433088cd25cd4ab8ed6dea Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 15:17:19 -0400 Subject: [PATCH 09/13] Update module doc block --- api/ECNQueue.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index ffc5ac0..bc9c8cd 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -19,6 +19,10 @@ # Get all queues (and their items) >>> queues = getQueues() +Attributes: + queueDirectory: The directory to load queues from. + queuesToIgnore: Queues that will not be loaded when running getQueues() + Raises: # TODO: Add description(s) of when a ValueError is raised. ValueError: [description] From 202e04cc62e1f53bce92f762084628b10a445b74 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 15:53:56 -0400 Subject: [PATCH 10/13] Remove getContent function /c no longer neede --- api/ECNQueue.py | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index bc9c8cd..2181861 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -82,13 +82,11 @@ class Item: """ def __init__(self, queue: str, number: int) -> None: - self.queue = queue try: self.number = int(number) except ValueError: - raise ValueError("Could not convert \"" + number + "\" to an integer") - #self.number = number + raise ValueError(" Could not convert \"" + number + "\" to an integer") self.__path = "/".join([queueDirectory, self.queue, str(self.number)]) self.lastUpdated = self.__getLastUpdated() @@ -107,6 +105,7 @@ def __init__(self, queue: str, number: int) -> None: self.building = self.__getMostRecentHeaderByType("Building") self.dateReceived = self.__getFormattedDate(self.__getMostRecentHeaderByType("Date")) + # TODO: Autopopulate jsonData w/ __dir__() command. Exclude `^_` and `jsonData`. self.jsonData = { "queue": self.queue, "number": self.number, @@ -135,6 +134,7 @@ def __getLastUpdated(self) -> str: Returns: str: last modified time of item reported by the filesystem in mm-dd-yy hh:mm am/pm format. """ + # TODO: Simplify this code block by allowing __getFormattedDate to accept milliseconds since the epoch. unixTime = os.path.getmtime(self.__path) formattedTime = time.strftime('%m-%d-%y %I:%M %p', time.localtime(unixTime)) return self.__getFormattedDate(formattedTime) @@ -195,7 +195,8 @@ def __parseHeaders(self) -> list: headerString += line - message = email.message_from_string(headerString + "".join(self.__getContent())) + # message = email.message_from_string(headerString + "".join(self.__getContent())) + message = email.message_from_string(headerString) headers = [] for key in message.keys(): @@ -205,26 +206,6 @@ def __parseHeaders(self) -> list: # TODO: Implement attachment parsing - def __getContent(self) -> list: - """Returns a dictionary of lines of the item body. - - Example: - "Hello. I need help.\\n\\n*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\\nDont Delete" becomes - [ - "Hello. I need help.\\n", - "\\n", - "*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\\n", - "Don't Delete", - ] - - Returns: - list: Lines of the body item. - """ - contentStart = self.__getHeaderBoundary() + 1 - contentEnd = len(self.__rawItem) - 1 - return self.__rawItem[ contentStart : contentEnd ] - - def __parseSections(self) -> list: # List of all item events sections = [] @@ -1253,3 +1234,9 @@ def getQueues() -> list: queues.append(Queue(file)) return queues + +if __name__ == "__main__": + start = time.time() + queues = getQueues() + end = time.time() + print(f'Fetching all queues took {end - start}s') \ No newline at end of file From 0b8776b4a062b0df93c2a9a3f98ab5a902474a2e Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 16:03:35 -0400 Subject: [PATCH 11/13] Remove __getAssignedTo from Item b/c it is no longer needed --- api/ECNQueue.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index 2181861..cea3cc4 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -97,7 +97,7 @@ def __init__(self, queue: str, number: int) -> None: self.userEmail = self.__parseFromData(data="userEmail") self.userName = self.__parseFromData(data="userName") self.userAlias = self.__getUserAlias() - self.assignedTo = self.__getAssignedTo() + self.assignedTo = self.__getMostRecentHeaderByType("Assigned-To") self.subject = self.__getMostRecentHeaderByType("Subject") self.status = self.__getMostRecentHeaderByType("Status") self.priority = self.__getMostRecentHeaderByType("Priority") @@ -1033,7 +1033,6 @@ def __getSortedSections(self, sectionsList: list) -> list: return sortedSections - def __isLocked(self) -> Union[str, bool]: """Returns a string info about the lock if true and a bool False if false @@ -1114,16 +1113,6 @@ def __getUserAlias(self) -> str: """ emailUser, emailDomain = self.userEmail.split("@") return emailUser if emailDomain.endswith("purdue.edu") else "" - - def __getAssignedTo(self) -> str: - """Returns the alias of the person this item was most recently assigned to. - Returns empty string if this item isn't assigned. - - Returns: - str: Alias of the person item is assigned to or empty string. - """ - assignedTo = self.__getMostRecentHeaderByType("Assigned-To") - return assignedTo def __getFormattedDate(self, date: str) -> str: """Returns the date/time formatted as RFC 8601 YYYY-MM-DDTHH:MM:SS+00:00. @@ -1233,10 +1222,4 @@ def getQueues() -> list: if isDirectory and isValid: queues.append(Queue(file)) - return queues - -if __name__ == "__main__": - start = time.time() - queues = getQueues() - end = time.time() - print(f'Fetching all queues took {end - start}s') \ No newline at end of file + return queues \ No newline at end of file From 29f7dab069675a971c59b0a236546cf79537df6c Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 16:03:52 -0400 Subject: [PATCH 12/13] Add todo for queue iteration --- api/ECNQueue.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index cea3cc4..b1fba76 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -1143,6 +1143,7 @@ def toJson(self) -> dict: def __repr__(self) -> str: return self.queue + str(self.number) +# TODO: Make Queue iterable using __iter__. See: https://thispointer.com/python-how-to-make-a-class-iterable-create-iterator-class-for-it/ class Queue: """A collection of items. From b078ed9b51ab2bb3d4bc23110bf57854899e24d6 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 29 Oct 2020 16:08:59 -0400 Subject: [PATCH 13/13] Add comments for default date in getFormattedDate() --- api/ECNQueue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/ECNQueue.py b/api/ECNQueue.py index b1fba76..f5e7c47 100644 --- a/api/ECNQueue.py +++ b/api/ECNQueue.py @@ -1123,8 +1123,8 @@ def __getFormattedDate(self, date: str) -> str: str: Properly formatted date/time recieved or empty string. """ try: - parsedDate = parse(date, default= datetime.datetime(2017, 10, 13, tzinfo=tz.gettz('EDT'))) - #parsedDate = parse(date, default= datetime.datetime(2017, 10, 13, tzinfo=datetime.timezone.) + # This date is never meant to be used. The default attribute is just to set timezone. + parsedDate = parse(date, default=datetime.datetime(1970, 0, 1, tzinfo=tz.gettz('EDT'))) except: return ""