Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

249 Zeilen
9.1KB

  1. from todoist.api import TodoistAPI
  2. import sys
  3. from datetime import date, time, datetime, timedelta
  4. import gi
  5. gi.require_version('Gio', '2.0')
  6. from gi.repository import Gio
  7. ##@brief Simple function to parse string from api to a datetimeformat.
  8. # @param datastr String with date
  9. # @return datetime object with date as specified in string.
  10. def makedatetime(datestr):
  11. if datestr == None:
  12. return None
  13. return datetime.strptime(datestr,"%Y-%m-%d")
  14. ##@brief Simple function to parse iso formated string from api to a datetimeformat.
  15. # @param datastr String with date and time in iso format
  16. # @return datetime object with date as specified in string.
  17. def fromisoformat(datestr):
  18. if datestr == None:
  19. return None
  20. return datetime.strptime(datestr,"%Y-%m-%dT%H:%M:%SZ")
  21. class TodoProject:
  22. ''' Common class for api calls'''
  23. def __init__(self,project=None):
  24. fh_api = open("apikey","r")
  25. self.apikey = fh_api.read()
  26. self.api = TodoistAPI(self.apikey)
  27. self.sync()
  28. if project != None:
  29. if isinstance(project,int):
  30. self.project= project
  31. else:
  32. for project in self.api["projects"]:
  33. if(project["name"] == project):
  34. self.project = project["id"]
  35. else:
  36. self.project == None
  37. self.items = TodoItemList(None,self.api)
  38. def sync(self):
  39. return self.api.sync()
  40. def checktaskstoday(self,tasklimit):
  41. if len(self.items.itemsForDay()) < tasklimit:
  42. self.sendnotification("TASKS","Not enough Tasks Scheduled for today!")
  43. def checkTasksWithoutNotes(self,date=date.today()):
  44. if len(self.items.itemsClosedWithoutNotes())>0:
  45. self.sendnotification("TASKS","There are tasks without a log.")
  46. def checkTasksOverDue(self):
  47. _overdueItems = len(self.items.itemsOverDue())
  48. if _overdueItems==1:
  49. self.sendnotification("TASKS","There is one task over due!")
  50. elif _overdueItems>1:
  51. self.sendnotification("TASKS","There are " + str(_overdueItems) + " tasks over due!")
  52. def sendnotification(self,title,body):
  53. Application = Gio.Application.new("todoist.tasks", Gio.ApplicationFlags.FLAGS_NONE)
  54. Application.register()
  55. Notification = Gio.Notification.new(title)
  56. Notification.set_body(body)
  57. Priority = Gio.NotificationPriority(2)
  58. Notification.set_priority(Priority)
  59. Icon = Gio.ThemedIcon.new("flag")
  60. Notification.set_icon(Icon)
  61. Application.send_notification(None, Notification)
  62. ##
  63. # @class TodoItemList
  64. # @brief Contains a list of items
  65. # Can be called like a list of items but has some aditional methods.
  66. class TodoItemList:
  67. ##
  68. # @brief Constructor
  69. # @param project can be the "name" or "id" of a project. If None the constructor will load all items from all projects
  70. # @param api object form TodoistAPI
  71. def __init__(self,project,api):
  72. self.api = api
  73. self.api.sync()
  74. self.items = []
  75. self.items_by_id = {}
  76. for item in self.api['items']:
  77. todoItem = TodoItem(item,self.api)
  78. if project==None or todoItem.project_id == project:
  79. self.items_by_id[str(todoItem.id)] = todoItem
  80. self.items.append(todoItem)
  81. # Also load all notes and append them to their corresponding item.
  82. for note in self.api['notes']:
  83. todoNote = TodoNote(note,self.api)
  84. self.items_by_id.get(str(todoNote.item_id)).addNote(todoNote)
  85. ##@brief magic method definition to so this object can be used as a list.
  86. # @param key index
  87. def __getitem__(self,key):
  88. return self.items[key]
  89. ##@brief magic method definition to so this object can be used as a list.
  90. def __len__(self):
  91. return len(self.items)
  92. ##@brief magic method definition to so this object can be used as a list.
  93. def __iter__(self):
  94. return iter(self.items)
  95. ##@brief magic method definition to so this object can be used as a list.
  96. def __reversed__(self):
  97. return reversed(self.items)
  98. ##@brief get all items that are due for specified day.
  99. # @_date date-object to specify the search day. Defaults to today.
  100. # @return list of items that have a duedate as specified in _date.
  101. def itemsForDay(self,_date=date.today()):
  102. _items = []
  103. for item in self.items:
  104. if item.dueOnDate(_date):
  105. _items.append(item)
  106. return _items
  107. ##@brief get all items that closed but do not have notes attached to them
  108. # @return list of closed items that do not have notes attached.
  109. def itemsClosedWithoutNotes(self):
  110. _items = []
  111. for item in self.items:
  112. if item.closedWithoutNotes():
  113. _items.append(item)
  114. return _items
  115. ##@brief get all items that are still open but passed there deadline
  116. # @return list of open items that passed their deadline
  117. def itemsOverDue(self):
  118. _items = []
  119. for item in self.items:
  120. if item.isOverDue():
  121. _items.append(item)
  122. return _items
  123. ##@class TodoItem
  124. # @brief Information of an Item/Task
  125. class TodoItem:
  126. ##@brief Constructor of TodoItem-object
  127. # @param item dict that is given by the TodoistAPI
  128. # @param dict that is given via the TodoistAPI
  129. # @param api TodoistAPI object
  130. def __init__(self,item,api):
  131. self.api = api
  132. self.id = item["id"]
  133. self.user_id = item["user_id"]
  134. self.project_id = item["project_id"]
  135. self.content = item["content"]
  136. self.priority = item["priority"]
  137. self.parent_id = item["parent_id"]
  138. self.child_order = item["child_order"]
  139. self.section_id = item["section_id"]
  140. self.day_order = item["day_order"]
  141. self.collapsed = item["collapsed"]
  142. self.labels = item["labels"]
  143. self.assigned_by_uid = item["assigned_by_uid"]
  144. self.responsible_uid = item["responsible_uid"]
  145. self.checked = item["checked"]==1
  146. self.in_history = item["in_history"]
  147. self.is_deleted = item["is_deleted"]
  148. self.sync_id = item["sync_id"]
  149. self.date_added = fromisoformat(item["date_added"])
  150. self.date_completed = fromisoformat(item["date_completed"])
  151. #add also empty list for nodes
  152. self.notes = []
  153. self._due = item["due"]
  154. #check if due is set.
  155. if self._due != None:
  156. self.due_date = makedatetime(self._due["date"])
  157. self.due_timezone = self._due["timezone"]
  158. self.due_string = self._due["string"]
  159. self.due_lang = self._due["lang"]
  160. self.due_is_recurring = self._due["is_recurring"]
  161. else:
  162. self.due_date = None
  163. self.due_timezone = None
  164. self.due_string = None
  165. self.due_lang = None
  166. self.due_is_recurring = None
  167. ##@brief Check wether a duedate is set
  168. # @return True if duedate is set
  169. def hasDue(self):
  170. return self._due != None
  171. ##@brief Check wether the item has passed its deadline
  172. # @return True is overDue
  173. def isOverDue(self):
  174. if self.hasDue() and not self.checked:
  175. return self.due_date.date() < date.today()
  176. else:
  177. return False
  178. ##@brief Check wether the item has has any notes attached to it
  179. # @return True if notes are attached
  180. def hasNotes(self):
  181. return (len(self.notes)>0)
  182. ##@brief add a note to this item.
  183. # @param note object that should be appended to this item
  184. def addNote(self,note):
  185. self.notes.append(note)
  186. ##@brief Check if this task is closed but does not have any notes
  187. # @return True is closed without notes attached
  188. def closedWithoutNotes(self):
  189. return self.checked and not self.hasNotes()
  190. ##@brief Check if this item is almost due(today) but has not notes yet
  191. # @return True if it has no notes but has be finished today
  192. def almostDueWithoutNotes(self):
  193. return self.dueOnDate() and not self.hasNotes()
  194. ##@brief Check if the item is due on specific day
  195. # @param _date date(time) object for which day to check. Defaults to today.
  196. # @return False if not due on specified date
  197. def dueOnDate(self,_date = date.today()):
  198. if self.hasDue():
  199. if isinstance(_date,datetime):
  200. _date = date.date()
  201. return self.due_date.date() == _date
  202. else:
  203. return False
  204. ##@class TodoNote
  205. # @brief Simple implementation for note-objects
  206. class TodoNote:
  207. ##@brief constructor of class
  208. # @param note dict with note-information from api
  209. # @param api TodoistAPI-object
  210. def __init__(self,note,api):
  211. self.id = note["id"]
  212. self.posted_uid = note["posted_uid"]
  213. self.project_id = note["project_id"]
  214. self.item_id = note["item_id"]
  215. self.content = note["content"]
  216. self.file_attachment = note["file_attachment"]
  217. self.uids_to_notify = note["uids_to_notify"]
  218. self.is_deleted = note["is_deleted"]
  219. self.posted = note["posted"]
  220. self.reactions = note["reactions"]