Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

249 řádky
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"]