Ver código fonte

Added classes for Todoistapi, simple main(), and package requirements

master
Wouter Horlings 6 anos atrás
pai
commit
9e364c9df3
3 arquivos alterados com 309 adições e 0 exclusões
  1. +248
    -0
      myTodoist.py
  2. +42
    -0
      requirements.txt
  3. +19
    -0
      taskcheck.py

+ 248
- 0
myTodoist.py Ver arquivo

@@ -0,0 +1,248 @@
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"]

+ 42
- 0
requirements.txt Ver arquivo

@@ -0,0 +1,42 @@
appdirs==1.4.3
asn1crypto==1.2.0
astroid==2.3.3
certifi==2019.9.11
cffi==1.13.1
chardet==3.0.4
configobj==5.0.6
cryptography==2.8
cupshelpers==1.0
gestures==0.2.2
idna==2.8
isort==4.3.21
lazy-object-proxy==1.4.3
mccabe==0.6.1
meson==0.52.0
mutagen==1.41.0
mygpoclient==1.8
onboard==1.4.1
packaging==19.2
pyasn1==0.4.7
pycairo==1.18.2
pycparser==2.19
pycups==1.9.74
PyGObject==3.34.0
pylint==2.4.4
pyOpenSSL==19.0.0
pyparsing==2.4.2
pyserial==3.4
pysmbc==1.0.15.8
PySocks==1.7.1
pytz==2019.3
PyYAML==5.1.2
requests==2.22.0
ruamel.yaml==0.16.5
ruamel.yaml.clib==0.2.0
six==1.13.0
todoist-python==8.1.1
typed-ast==1.4.0
urllib3==1.25.7
wrapt==1.11.2
youtube-dl==2019.11.5
zope.interface==4.7.1

+ 19
- 0
taskcheck.py Ver arquivo

@@ -0,0 +1,19 @@
import sys

from myTodoist import TodoProject,TodoItem,TodoNote,TodoItemList



def main():
# if(len(sys.argv)!=2):
# return
todoist = TodoProject("Master Assignment")
# getattr(todoist, sys.argv[1])()
todoist.checktaskstoday(3)
todoist.checkTasksWithoutNotes()
todoist.checkTasksOverDue()



#print(todoist.getproject())
main()

Carregando…
Cancelar
Salvar