version check logic added

master
Hoffelhas 2020-05-24 11:11:17 +02:00
parent 473964155c
commit 9e9567efaf
1 changed files with 112 additions and 52 deletions

View File

@ -3,29 +3,40 @@
import logging import logging
import argparse import argparse
import requests
from todoist.api import TodoistAPI
import time import time
import sys import sys
from datetime import datetime from datetime import datetime
from todoist.api import TodoistAPI
def main(): def main():
# Version
current_version = 'v1.1'
"""Main process function.""" """Main process function."""
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-a', '--api_key', help='Todoist API Key') parser.add_argument('-a', '--api_key', help='Todoist API Key')
parser.add_argument('-l', '--label', help='The next action label to use', default='next_action') parser.add_argument(
parser.add_argument('-d', '--delay', help='Specify the delay in seconds between syncs', default=10, type=int) '-l', '--label', help='The next action label to use', default='next_action')
parser.add_argument('-r', '--recurring', help='Enable re-use of recurring lists', action='store_true') parser.add_argument(
parser.add_argument('--debug', help='Enable debugging', action='store_true') '-d', '--delay', help='Specify the delay in seconds between syncs', default=10, type=int)
parser.add_argument(
'-r', '--recurring', help='Enable re-use of recurring lists', action='store_true')
parser.add_argument('--debug', help='Enable debugging',
action='store_true')
parser.add_argument('--inbox', help='The method the Inbox project should be processed', parser.add_argument('--inbox', help='The method the Inbox project should be processed',
default=None, choices=['parallel', 'sequential']) default=None, choices=['parallel', 'sequential'])
parser.add_argument('--parallel_suffix', default='//') parser.add_argument('--parallel_suffix', default='//')
parser.add_argument('--sequential_suffix', default='--') parser.add_argument('--sequential_suffix', default='--')
parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days', parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days',
default=7, type=int) default=7, type=int)
parser.add_argument('--onetime', help='Update Todoist once and exit', action='store_true') parser.add_argument(
parser.add_argument('--nocache', help='Disables caching data to disk for quicker syncing', action='store_true') '--onetime', help='Update Todoist once and exit', action='store_true')
parser.add_argument(
'--nocache', help='Disables caching data to disk for quicker syncing', action='store_true')
args = parser.parse_args() args = parser.parse_args()
def initialise(args): def initialise(args):
@ -61,13 +72,41 @@ def main():
labels = api.labels.all(lambda x: x['name'] == args.label) labels = api.labels.all(lambda x: x['name'] == args.label)
if len(labels) > 0: if len(labels) > 0:
label_id = labels[0]['id'] label_id = labels[0]['id']
logging.debug('Label \'%s\' found as label id %d', args.label, label_id) logging.debug('Label \'%s\' found as label id %d',
args.label, label_id)
else: else:
logging.error("Label \'%s\' doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label) logging.error(
"Label \'%s\' doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label)
sys.exit(1) sys.exit(1)
return api, label_id return api, label_id
def check_for_update(current_version):
updateurl = 'https://api.github.com/repos/Hoffelhas/autodoist/releases'
try:
r = requests.get(updateurl)
r.raise_for_status()
release_info_json = r.json()
if not current_version == release_info_json[0]['tag_name']:
logging.info("Your version is not up-to-date! \nYour version: {}\nLatest version: {}\nSee latest version at: {}".format(
current_version, release_info_json[0]['tag_name'], release_info_json[0]['html_url']))
return 1
else:
return 0
except requests.exceptions.ConnectionError as e:
logging.error(
"Error while checking for updates (Connection error): {}".format(e))
return 1
except requests.exceptions.HTTPError as e:
logging.error(
"Error while checking for updates (HTTP error): {}".format(e))
return 1
except requests.exceptions.RequestException as e:
logging.error("Error while checking for updates: {}".format(e))
return 1
def get_type(object, key): def get_type(object, key):
len_suffix = [len(args.parallel_suffix), len(args.sequential_suffix)] len_suffix = [len(args.parallel_suffix), len(args.sequential_suffix)]
@ -102,7 +141,8 @@ def main():
def get_project_type(project_object): def get_project_type(project_object):
"""Identifies how a project should be handled.""" """Identifies how a project should be handled."""
project_type, project_type_changed = get_type(project_object,'project_type') project_type, project_type_changed = get_type(
project_object, 'project_type')
return project_type, project_type_changed return project_type, project_type_changed
@ -134,6 +174,9 @@ def main():
labels.remove(label) labels.remove(label)
api.items.update(item['id'], labels=labels) api.items.update(item['id'], labels=labels)
# Check for updates
check_for_update(current_version)
# Initialise api # Initialise api
api, label_id = initialise(args) api, label_id = initialise(args)
@ -142,16 +185,19 @@ def main():
try: try:
api.sync() api.sync()
except Exception as e: except Exception as e:
logging.exception('Error trying to sync with Todoist API: %s' % str(e)) logging.exception(
'Error trying to sync with Todoist API: %s' % str(e))
else: else:
for project in api.projects.all(): for project in api.projects.all():
# Get project type # Get project type
project_type, project_type_changed = get_project_type(project) project_type, project_type_changed = get_project_type(project)
logging.debug('Project \'%s\' being processed as %s', project['name'], project_type) logging.debug('Project \'%s\' being processed as %s',
project['name'], project_type)
# Get all items for the project # Get all items for the project
items = api.items.all(lambda x: x['project_id'] == project['id']) items = api.items.all(
lambda x: x['project_id'] == project['id'])
# Change top parents_id in order to sort later on # Change top parents_id in order to sort later on
for item in items: for item in items:
@ -159,8 +205,10 @@ def main():
item['parent_id'] = 0 item['parent_id'] = 0
# Sort by parent_id and filter for completable items # Sort by parent_id and filter for completable items
items = sorted(items, key=lambda x: (x['parent_id'], x['child_order'])) items = sorted(items, key=lambda x: (
items = list(filter(lambda x: not x['content'].startswith('*'), items)) x['parent_id'], x['child_order']))
items = list(
filter(lambda x: not x['content'].startswith('*'), items))
# If project type has been changed, clean everything for good measure # If project type has been changed, clean everything for good measure
if project_type_changed == 1: if project_type_changed == 1:
@ -173,9 +221,12 @@ def main():
for item in items: for item in items:
# Determine which child_items exist, both all and the ones that have not been checked yet # Determine which child_items exist, both all and the ones that have not been checked yet
non_checked_items = list(filter(lambda x: x['checked'] == 0, items)) non_checked_items = list(
child_items_all = list(filter(lambda x: x['parent_id'] == item['id'], items)) filter(lambda x: x['checked'] == 0, items))
child_items = list(filter(lambda x: x['parent_id'] == item['id'], non_checked_items)) child_items_all = list(
filter(lambda x: x['parent_id'] == item['id'], items))
child_items = list(
filter(lambda x: x['parent_id'] == item['id'], non_checked_items))
# Logic for recurring lists # Logic for recurring lists
if not args.recurring: if not args.recurring:
@ -200,12 +251,14 @@ def main():
child_item['r_tag'] = 1 child_item['r_tag'] = 1
except Exception as e: except Exception as e:
# If date has never been saved before, create a new entry # If date has never been saved before, create a new entry
logging.debug('New recurring task detected: %s' % str(e)) logging.debug(
'New recurring task detected: %s' % str(e))
item['old_date'] = item['due']['date'] item['old_date'] = item['due']['date']
api.items.update(item['id']) api.items.update(item['id'])
except Exception as e: except Exception as e:
logging.debug('Parent not recurring: %s' % str(e)) logging.debug(
'Parent not recurring: %s' % str(e))
pass pass
try: try:
@ -226,8 +279,10 @@ def main():
continue continue
# Check item type # Check item type
item_type, item_type_changed = get_item_type(item, project_type) item_type, item_type_changed = get_item_type(
logging.debug('Identified \'%s\' as %s type', item['content'], item_type) item, project_type)
logging.debug('Identified \'%s\' as %s type',
item['content'], item_type)
if project_type is None and item_type is None and project_type_changed == 1: if project_type is None and item_type is None and project_type_changed == 1:
# Clean the item and its children # Clean the item and its children
@ -270,7 +325,8 @@ def main():
# Check if state has changed, if so clean for good measure # Check if state has changed, if so clean for good measure
if item_type_changed == 1: if item_type_changed == 1:
[remove_label(child_item, label_id) for child_item in child_items] [remove_label(child_item, label_id)
for child_item in child_items]
# Process sequential tagged items (item_type can overrule project_type) # Process sequential tagged items (item_type can overrule project_type)
if item_type == 'sequential': if item_type == 'sequential':
@ -301,13 +357,16 @@ def main():
# If item is too far in the future, remove the next_action tag and skip # If item is too far in the future, remove the next_action tag and skip
if args.hide_future > 0 and 'due_date_utc' in item.data and item['due_date_utc'] is not None: if args.hide_future > 0 and 'due_date_utc' in item.data and item['due_date_utc'] is not None:
due_date = datetime.strptime(item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000') due_date = datetime.strptime(
future_diff = (due_date - datetime.utcnow()).total_seconds() item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000')
future_diff = (
due_date - datetime.utcnow()).total_seconds()
if future_diff >= (args.hide_future * 86400): if future_diff >= (args.hide_future * 86400):
remove_label(item, label_id) remove_label(item, label_id)
continue continue
if len(api.queue): if len(api.queue):
logging.debug('%d changes queued for sync... commiting to Todoist.', len(api.queue)) logging.debug(
'%d changes queued for sync... commiting to Todoist.', len(api.queue))
api.commit() api.commit()
else: else:
logging.debug('No changes queued, skipping sync.') logging.debug('No changes queued, skipping sync.')
@ -319,5 +378,6 @@ def main():
logging.debug('Sleeping for %d seconds', args.delay) logging.debug('Sleeping for %d seconds', args.delay)
time.sleep(args.delay) time.sleep(args.delay)
if __name__ == '__main__': if __name__ == '__main__':
main() main()