|
- from todoist.api import TodoistAPI
- import sys
- from datetime import date, time, datetime, timedelta
- import gi
- gi.require_version('Gio', '2.0')
- from gi.repository import Gio
-
-
- ##@brief Simple function to parse string from api to a datetimeformat.
- # @param datastr String with date
- # @return datetime object with date as specified in string.
- def makedatetime(datestr):
- if datestr == None:
- return None
- return datetime.strptime(datestr,"%Y-%m-%d")
-
- ##@brief Simple function to parse iso formated string from api to a datetimeformat.
- # @param datastr String with date and time in iso format
- # @return datetime object with date as specified in string.
- def fromisoformat(datestr):
- if datestr == None:
- return None
- return datetime.strptime(datestr,"%Y-%m-%dT%H:%M:%SZ")
-
- class TodoProject:
- ''' Common class for api calls'''
-
- def __init__(self,project=None):
- fh_api = open("apikey","r")
- self.apikey = fh_api.read()
- self.api = TodoistAPI(self.apikey)
- self.sync()
- if project != None:
- if isinstance(project,int):
- self.project= project
- else:
- for project in self.api["projects"]:
- if(project["name"] == project):
- self.project = project["id"]
- else:
- self.project == None
- self.items = TodoItemList(None,self.api)
-
- def sync(self):
- return self.api.sync()
-
- def checktaskstoday(self,tasklimit):
- if len(self.items.itemsForDay()) < tasklimit:
- self.sendnotification("TASKS","Not enough Tasks Scheduled for today!")
-
- def checkTasksWithoutNotes(self,date=date.today()):
- if len(self.items.itemsClosedWithoutNotes())>0:
- self.sendnotification("TASKS","There are tasks without a log.")
-
- def checkTasksOverDue(self):
- _overdueItems = len(self.items.itemsOverDue())
- if _overdueItems==1:
- self.sendnotification("TASKS","There is one task over due!")
- elif _overdueItems>1:
- self.sendnotification("TASKS","There are " + str(_overdueItems) + " tasks over due!")
-
- def sendnotification(self,title,body):
- Application = Gio.Application.new("todoist.tasks", Gio.ApplicationFlags.FLAGS_NONE)
- Application.register()
- Notification = Gio.Notification.new(title)
- Notification.set_body(body)
- Priority = Gio.NotificationPriority(2)
- Notification.set_priority(Priority)
- Icon = Gio.ThemedIcon.new("flag")
- Notification.set_icon(Icon)
- Application.send_notification(None, Notification)
-
- ##
- # @class TodoItemList
- # @brief Contains a list of items
- # Can be called like a list of items but has some aditional methods.
- class TodoItemList:
-
- ##
- # @brief Constructor
- # @param project can be the "name" or "id" of a project. If None the constructor will load all items from all projects
- # @param api object form TodoistAPI
- def __init__(self,project,api):
- self.api = api
- self.api.sync()
- self.items = []
- self.items_by_id = {}
- for item in self.api['items']:
- todoItem = TodoItem(item,self.api)
- if project==None or todoItem.project_id == project:
- self.items_by_id[str(todoItem.id)] = todoItem
- self.items.append(todoItem)
- # Also load all notes and append them to their corresponding item.
- for note in self.api['notes']:
- todoNote = TodoNote(note,self.api)
- self.items_by_id.get(str(todoNote.item_id)).addNote(todoNote)
-
-
- ##@brief magic method definition to so this object can be used as a list.
- # @param key index
- def __getitem__(self,key):
- return self.items[key]
-
- ##@brief magic method definition to so this object can be used as a list.
- def __len__(self):
- return len(self.items)
-
- ##@brief magic method definition to so this object can be used as a list.
- def __iter__(self):
- return iter(self.items)
-
- ##@brief magic method definition to so this object can be used as a list.
- def __reversed__(self):
- return reversed(self.items)
-
- ##@brief get all items that are due for specified day.
- # @_date date-object to specify the search day. Defaults to today.
- # @return list of items that have a duedate as specified in _date.
- def itemsForDay(self,_date=date.today()):
- _items = []
- for item in self.items:
- if item.dueOnDate(_date):
- _items.append(item)
- return _items
-
- ##@brief get all items that closed but do not have notes attached to them
- # @return list of closed items that do not have notes attached.
- def itemsClosedWithoutNotes(self):
- _items = []
- for item in self.items:
- if item.closedWithoutNotes():
- _items.append(item)
- return _items
-
- ##@brief get all items that are still open but passed there deadline
- # @return list of open items that passed their deadline
- def itemsOverDue(self):
- _items = []
- for item in self.items:
- if item.isOverDue():
- _items.append(item)
- return _items
-
- ##@class TodoItem
- # @brief Information of an Item/Task
- class TodoItem:
- ##@brief Constructor of TodoItem-object
- # @param item dict that is given by the TodoistAPI
- # @param dict that is given via the TodoistAPI
- # @param api TodoistAPI object
- def __init__(self,item,api):
- self.api = api
- self.id = item["id"]
- self.user_id = item["user_id"]
- self.project_id = item["project_id"]
- self.content = item["content"]
- self.priority = item["priority"]
- self.parent_id = item["parent_id"]
- self.child_order = item["child_order"]
- self.section_id = item["section_id"]
- self.day_order = item["day_order"]
- self.collapsed = item["collapsed"]
- self.labels = item["labels"]
- self.assigned_by_uid = item["assigned_by_uid"]
- self.responsible_uid = item["responsible_uid"]
- self.checked = item["checked"]==1
- self.in_history = item["in_history"]
- self.is_deleted = item["is_deleted"]
- self.sync_id = item["sync_id"]
- self.date_added = fromisoformat(item["date_added"])
- self.date_completed = fromisoformat(item["date_completed"])
- #add also empty list for nodes
- self.notes = []
- self._due = item["due"]
- #check if due is set.
- if self._due != None:
- self.due_date = makedatetime(self._due["date"])
- self.due_timezone = self._due["timezone"]
- self.due_string = self._due["string"]
- self.due_lang = self._due["lang"]
- self.due_is_recurring = self._due["is_recurring"]
- else:
- self.due_date = None
- self.due_timezone = None
- self.due_string = None
- self.due_lang = None
- self.due_is_recurring = None
-
- ##@brief Check wether a duedate is set
- # @return True if duedate is set
- def hasDue(self):
- return self._due != None
-
- ##@brief Check wether the item has passed its deadline
- # @return True is overDue
- def isOverDue(self):
- if self.hasDue() and not self.checked:
- return self.due_date.date() < date.today()
- else:
- return False
-
- ##@brief Check wether the item has has any notes attached to it
- # @return True if notes are attached
- def hasNotes(self):
- return (len(self.notes)>0)
-
- ##@brief add a note to this item.
- # @param note object that should be appended to this item
- def addNote(self,note):
- self.notes.append(note)
-
- ##@brief Check if this task is closed but does not have any notes
- # @return True is closed without notes attached
- def closedWithoutNotes(self):
- return self.checked and not self.hasNotes()
-
- ##@brief Check if this item is almost due(today) but has not notes yet
- # @return True if it has no notes but has be finished today
- def almostDueWithoutNotes(self):
- return self.dueOnDate() and not self.hasNotes()
-
- ##@brief Check if the item is due on specific day
- # @param _date date(time) object for which day to check. Defaults to today.
- # @return False if not due on specified date
- def dueOnDate(self,_date = date.today()):
- if self.hasDue():
- if isinstance(_date,datetime):
- _date = date.date()
- return self.due_date.date() == _date
- else:
- return False
- ##@class TodoNote
- # @brief Simple implementation for note-objects
- class TodoNote:
- ##@brief constructor of class
- # @param note dict with note-information from api
- # @param api TodoistAPI-object
- def __init__(self,note,api):
- self.id = note["id"]
- self.posted_uid = note["posted_uid"]
- self.project_id = note["project_id"]
- self.item_id = note["item_id"]
- self.content = note["content"]
- self.file_attachment = note["file_attachment"]
- self.uids_to_notify = note["uids_to_notify"]
- self.is_deleted = note["is_deleted"]
- self.posted = note["posted"]
- self.reactions = note["reactions"]
|