mirror of https://github.com/Hoffelhas/autodoist
Basic SQLite DB functionality now working. Next: rewrite 'get_task_type()' function, and start some refactoring/debugging.
parent
2625547002
commit
374d216a83
379
autodoist.py
379
autodoist.py
|
@ -1,6 +1,9 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
from todoist_api_python.api import TodoistAPI
|
from todoist_api_python.api import TodoistAPI
|
||||||
|
from todoist_api_python.models import Task
|
||||||
|
from todoist_api_python.models import Section
|
||||||
|
from todoist_api_python.models import Project
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
|
@ -10,6 +13,212 @@ from datetime import datetime, timedelta
|
||||||
import time
|
import time
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from sqlite3 import Error
|
from sqlite3 import Error
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Connect to SQLite database
|
||||||
|
|
||||||
|
|
||||||
|
def create_connection(path):
|
||||||
|
connection = None
|
||||||
|
try:
|
||||||
|
connection = sqlite3.connect(path)
|
||||||
|
logging.info("Connection to SQLite DB successful")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"Could not connect to the SQLite database: the error '{e}' occurred")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return connection
|
||||||
|
|
||||||
|
# Close conenction to SQLite database
|
||||||
|
|
||||||
|
|
||||||
|
def close_connection(connection):
|
||||||
|
try:
|
||||||
|
connection.close()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"Could not close the SQLite database: the error '{e}' occurred")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Execute any SQLite query passed to it in the form of string
|
||||||
|
|
||||||
|
|
||||||
|
def execute_query(connection, query):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
try:
|
||||||
|
cursor.execute(query)
|
||||||
|
connection.commit()
|
||||||
|
logging.debug("Query executed: {}".format(query))
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"The error '{e}' occurred")
|
||||||
|
|
||||||
|
# Pass query to select and read record. Outputs a tuple.
|
||||||
|
|
||||||
|
|
||||||
|
def execute_read_query(connection, query):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
result = None
|
||||||
|
try:
|
||||||
|
cursor.execute(query)
|
||||||
|
result = cursor.fetchall()
|
||||||
|
logging.debug("Query fetched: {}".format(query))
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"The error '{e}' occurred")
|
||||||
|
|
||||||
|
# Construct query and read a value
|
||||||
|
|
||||||
|
|
||||||
|
def db_read_value(connection, model, column):
|
||||||
|
try:
|
||||||
|
if isinstance(model, Task):
|
||||||
|
db_name = 'tasks'
|
||||||
|
goal = 'task_id'
|
||||||
|
elif isinstance(model, Section):
|
||||||
|
db_name = 'sections'
|
||||||
|
goal = 'section_id'
|
||||||
|
elif isinstance(model, Project):
|
||||||
|
db_name = 'projects'
|
||||||
|
goal = 'project_id'
|
||||||
|
|
||||||
|
query = "SELECT %s FROM %s where %s=%r" % (
|
||||||
|
column, db_name, goal, model.id)
|
||||||
|
|
||||||
|
result = execute_read_query(connection, query)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"The error '{e}' occurred")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Construct query and update a value
|
||||||
|
|
||||||
|
|
||||||
|
def db_update_value(connection, model, column, value):
|
||||||
|
|
||||||
|
try:
|
||||||
|
if isinstance(model, Task):
|
||||||
|
db_name = 'tasks'
|
||||||
|
goal = 'task_id'
|
||||||
|
|
||||||
|
elif isinstance(model, Section):
|
||||||
|
db_name = 'sections'
|
||||||
|
goal = 'section_id'
|
||||||
|
|
||||||
|
elif isinstance(model, Project):
|
||||||
|
db_name = 'projects'
|
||||||
|
goal = 'project_id'
|
||||||
|
|
||||||
|
query = """
|
||||||
|
UPDATE
|
||||||
|
%s
|
||||||
|
SET
|
||||||
|
%s = %r
|
||||||
|
WHERE
|
||||||
|
%s = %r
|
||||||
|
""" % (db_name, column, value, goal, model.id)
|
||||||
|
|
||||||
|
result = execute_query(connection, query)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"The error '{e}' occurred")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# Check if the id of a model exists, if not, add to database
|
||||||
|
|
||||||
|
|
||||||
|
def db_check_existance(connection, model):
|
||||||
|
try:
|
||||||
|
if isinstance(model, Task):
|
||||||
|
db_name = 'tasks'
|
||||||
|
goal = 'task_id'
|
||||||
|
elif isinstance(model, Section):
|
||||||
|
db_name = 'sections'
|
||||||
|
goal = 'section_id'
|
||||||
|
elif isinstance(model, Project):
|
||||||
|
db_name = 'projects'
|
||||||
|
goal = 'project_id'
|
||||||
|
|
||||||
|
q_check_existence = "SELECT EXISTS(SELECT 1 FROM %s WHERE %s=%r)" % (
|
||||||
|
db_name, goal, model.id)
|
||||||
|
existence_result = execute_read_query(connection, q_check_existence)
|
||||||
|
|
||||||
|
if existence_result[0][0] == 0:
|
||||||
|
if isinstance(model, Task):
|
||||||
|
q_create = """
|
||||||
|
INSERT INTO
|
||||||
|
tasks (task_id, task_type, parent_type, r_tag)
|
||||||
|
VALUES
|
||||||
|
(%r, %s, %s, %i);
|
||||||
|
""" % (model.id, 'NULL', 'NULL', 0)
|
||||||
|
|
||||||
|
if isinstance(model, Section):
|
||||||
|
q_create = """
|
||||||
|
INSERT INTO
|
||||||
|
sections (section_id, project_type, section_type)
|
||||||
|
VALUES
|
||||||
|
(%r, %s, %s);
|
||||||
|
""" % (model.id, 'NULL', 'NULL')
|
||||||
|
|
||||||
|
if isinstance(model, Project):
|
||||||
|
q_create = """
|
||||||
|
INSERT INTO
|
||||||
|
projects (project_id, project_type)
|
||||||
|
VALUES
|
||||||
|
(%r, %s);
|
||||||
|
""" % (model.id, 'NULL')
|
||||||
|
|
||||||
|
execute_query(connection, q_create)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug(f"The error '{e}' occurred")
|
||||||
|
|
||||||
|
|
||||||
|
# Initialise new database tables
|
||||||
|
|
||||||
|
def initialise_sqlite():
|
||||||
|
|
||||||
|
cwd = os.getcwdb()
|
||||||
|
db_path = os.path.join(cwd, b'metadata.sqlite')
|
||||||
|
|
||||||
|
connection = create_connection(db_path)
|
||||||
|
|
||||||
|
q_create_projects_table = """
|
||||||
|
CREATE TABLE IF NOT EXISTS projects (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
project_id INTEGER,
|
||||||
|
project_type TEXT
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
|
q_create_sections_table = """
|
||||||
|
CREATE TABLE IF NOT EXISTS sections (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
sections_id INTEGER,
|
||||||
|
project_type TEXT,
|
||||||
|
section_type
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
|
q_create_tasks_table = """
|
||||||
|
CREATE TABLE IF NOT EXISTS tasks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
task_id INTEGER,
|
||||||
|
task_type TEXT,
|
||||||
|
parent_type TEXT,
|
||||||
|
r_tag INTEGER
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
|
execute_query(connection, q_create_projects_table)
|
||||||
|
execute_query(connection, q_create_sections_table)
|
||||||
|
execute_query(connection, q_create_tasks_table)
|
||||||
|
|
||||||
|
return connection
|
||||||
|
|
||||||
|
|
||||||
# Makes --help text wider
|
# Makes --help text wider
|
||||||
|
|
||||||
|
@ -75,6 +284,7 @@ def query_yes_no(question, default="yes"):
|
||||||
|
|
||||||
# Check if label exists, if not, create it
|
# Check if label exists, if not, create it
|
||||||
|
|
||||||
|
|
||||||
def verify_label_existance(api, label_name, prompt_mode):
|
def verify_label_existance(api, label_name, prompt_mode):
|
||||||
# Check the regeneration label exists
|
# Check the regeneration label exists
|
||||||
labels = api.get_labels()
|
labels = api.get_labels()
|
||||||
|
@ -113,7 +323,9 @@ def verify_label_existance(api, label_name, prompt_mode):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Initialisation of Autodoist
|
# Initialisation of Autodoist
|
||||||
def initialise(args):
|
|
||||||
|
|
||||||
|
def initialise_api(args):
|
||||||
|
|
||||||
# Check we have a API key
|
# Check we have a API key
|
||||||
if not args.api_key:
|
if not args.api_key:
|
||||||
|
@ -132,8 +344,9 @@ def initialise(args):
|
||||||
|
|
||||||
# Check if proper regeneration mode has been selected
|
# Check if proper regeneration mode has been selected
|
||||||
if args.regeneration is not None:
|
if args.regeneration is not None:
|
||||||
if not set([0,1,2]) & set([args.regeneration]):
|
if not set([0, 1, 2]) & set([args.regeneration]):
|
||||||
logging.error('Wrong regeneration mode. Please choose a number from 0 to 2. Check --help for more information on the available modes.')
|
logging.error(
|
||||||
|
'Wrong regeneration mode. Please choose a number from 0 to 2. Check --help for more information on the available modes.')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# Show which modes are enabled:
|
# Show which modes are enabled:
|
||||||
|
@ -223,7 +436,10 @@ def check_name(args, name):
|
||||||
len_suffix = [len(args.pp_suffix), len(args.ss_suffix),
|
len_suffix = [len(args.pp_suffix), len(args.ss_suffix),
|
||||||
len(args.ps_suffix), len(args.sp_suffix)]
|
len(args.ps_suffix), len(args.sp_suffix)]
|
||||||
|
|
||||||
if name == 'Inbox':
|
if name == None:
|
||||||
|
current_type = None
|
||||||
|
pass
|
||||||
|
elif name == 'Inbox':
|
||||||
current_type = args.inbox
|
current_type = args.inbox
|
||||||
elif name[-len_suffix[0]:] == args.pp_suffix:
|
elif name[-len_suffix[0]:] == args.pp_suffix:
|
||||||
current_type = 'parallel'
|
current_type = 'parallel'
|
||||||
|
@ -233,7 +449,7 @@ def check_name(args, name):
|
||||||
current_type = 'p-s'
|
current_type = 'p-s'
|
||||||
elif name[-len_suffix[3]:] == args.sp_suffix:
|
elif name[-len_suffix[3]:] == args.sp_suffix:
|
||||||
current_type = 's-p'
|
current_type = 's-p'
|
||||||
#TODO: Remove below workarounds if standard notation is changing. Just messy and no longer needed.
|
# TODO: Remove below workarounds if standard notation is changing. Just messy and no longer needed.
|
||||||
# # Workaround for section names, which don't allow '/' symbol.
|
# # Workaround for section names, which don't allow '/' symbol.
|
||||||
# elif args.ps_suffix == '/-' and name[-2:] == '_-':
|
# elif args.ps_suffix == '/-' and name[-2:] == '_-':
|
||||||
# current_type = 'p-s'
|
# current_type = 'p-s'
|
||||||
|
@ -251,34 +467,32 @@ def check_name(args, name):
|
||||||
# Scan the end of a name to find what type it is
|
# Scan the end of a name to find what type it is
|
||||||
|
|
||||||
|
|
||||||
def get_type(args, model, key):
|
def get_type(args, connection, model, key):
|
||||||
|
|
||||||
model_name = ''
|
# model_name = ''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
old_type = model[key] #TODO: METADATA: this information used to be part of the metadata, needs to be retreived from own database
|
# TODO: METADATA: this information used to be part of the metadata, needs to be retreived from own database
|
||||||
|
old_type = ''
|
||||||
|
old_type = db_read_value(connection, model, key)[0][0]
|
||||||
|
|
||||||
except:
|
except:
|
||||||
# logging.debug('No defined project_type: %s' % str(e))
|
# logging.debug('No defined project_type: %s' % str(e))
|
||||||
old_type = None
|
old_type = None
|
||||||
|
|
||||||
try:
|
# model_name = model.name.strip() % TODO: Is this still needed?
|
||||||
model_name = model.name.strip()
|
|
||||||
except:
|
|
||||||
#TODO: Old support for legacy tag in v1 API, can likely be removed since moving to v2.
|
|
||||||
# try:
|
|
||||||
#
|
|
||||||
# object_name = object['content'].strip()
|
|
||||||
# except:
|
|
||||||
# pass
|
|
||||||
pass
|
|
||||||
|
|
||||||
current_type = check_name(args, model_name)
|
try:
|
||||||
|
current_type = check_name(args, model.content) # Tasks
|
||||||
|
except:
|
||||||
|
current_type = check_name(args, model.name) # Project and sections
|
||||||
|
|
||||||
# Check if project type changed with respect to previous run
|
# Check if project type changed with respect to previous run
|
||||||
if old_type == current_type:
|
if old_type == current_type:
|
||||||
type_changed = 0
|
type_changed = 0
|
||||||
else:
|
else:
|
||||||
type_changed = 1
|
type_changed = 1
|
||||||
|
db_update_value(connection, model, key, current_type)
|
||||||
# model.key = current_type #TODO: METADATA: this information used to be part of the metadata, needs to be retreived from own database
|
# model.key = current_type #TODO: METADATA: this information used to be part of the metadata, needs to be retreived from own database
|
||||||
|
|
||||||
return current_type, type_changed
|
return current_type, type_changed
|
||||||
|
@ -286,21 +500,21 @@ def get_type(args, model, key):
|
||||||
# Determine a project type
|
# Determine a project type
|
||||||
|
|
||||||
|
|
||||||
def get_project_type(args, project_model):
|
def get_project_type(args, connection, project_model):
|
||||||
"""Identifies how a project should be handled."""
|
"""Identifies how a project should be handled."""
|
||||||
project_type, project_type_changed = get_type(
|
project_type, project_type_changed = get_type(
|
||||||
args, project_model, 'project_type')
|
args, connection, project_model, 'project_type')
|
||||||
|
|
||||||
return project_type, project_type_changed
|
return project_type, project_type_changed
|
||||||
|
|
||||||
# Determine a section type
|
# Determine a section type
|
||||||
|
|
||||||
|
|
||||||
def get_section_type(args, section_object):
|
def get_section_type(args, connection, section_object):
|
||||||
"""Identifies how a section should be handled."""
|
"""Identifies how a section should be handled."""
|
||||||
if section_object is not None:
|
if section_object is not None:
|
||||||
section_type, section_type_changed = get_type(
|
section_type, section_type_changed = get_type(
|
||||||
args, section_object, 'section_type')
|
args, connection, section_object, 'section_type')
|
||||||
else:
|
else:
|
||||||
section_type = None
|
section_type = None
|
||||||
section_type_changed = 0
|
section_type_changed = 0
|
||||||
|
@ -310,18 +524,20 @@ def get_section_type(args, section_object):
|
||||||
# Determine an task type
|
# Determine an task type
|
||||||
|
|
||||||
|
|
||||||
def get_task_type(args, task, project_type):
|
def get_task_type(args, connection, task, section_type, project_type):
|
||||||
"""Identifies how a task with sub tasks should be handled."""
|
"""Identifies how a task with sub tasks should be handled."""
|
||||||
|
|
||||||
if project_type is None and task.parent_id != 0:
|
if project_type is None and section_type is None and task.parent_id != 0: #TODO: project type and section type, no?
|
||||||
try:
|
try:
|
||||||
task_type = task.parent_type #TODO: METADATA
|
task_type = task.parent_type # TODO: METADATA
|
||||||
task_type_changed = 1
|
task_type_changed = 1
|
||||||
task.task_type = task_type
|
task.task_type = task_type #TODO: METADATA
|
||||||
except:
|
except:
|
||||||
task_type, task_type_changed = get_type(args, task, 'task_type') #TODO: METADATA
|
task_type, task_type_changed = get_type(
|
||||||
|
args, connection, task, 'task_type') # TODO: METADATA
|
||||||
else:
|
else:
|
||||||
task_type, task_type_changed = get_type(args, task, 'task_type') #TODO: METADATA
|
task_type, task_type_changed = get_type(
|
||||||
|
args, connection, task, 'task_type') # TODO: METADATA
|
||||||
|
|
||||||
return task_type, task_type_changed
|
return task_type, task_type_changed
|
||||||
|
|
||||||
|
@ -367,16 +583,6 @@ def update_labels(api, overview_task_ids, overview_task_labels):
|
||||||
|
|
||||||
return filtered_overview_ids
|
return filtered_overview_ids
|
||||||
|
|
||||||
# To handle tasks which have no sections
|
|
||||||
|
|
||||||
|
|
||||||
def create_none_section():
|
|
||||||
none_sec = {
|
|
||||||
'id': None,
|
|
||||||
'name': 'None',
|
|
||||||
'section_order': 0
|
|
||||||
}
|
|
||||||
return none_sec
|
|
||||||
|
|
||||||
# Check if header logic needs to be applied
|
# Check if header logic needs to be applied
|
||||||
|
|
||||||
|
@ -387,7 +593,7 @@ def check_header(level):
|
||||||
method = 0
|
method = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Support for legacy structure
|
# Support for legacy structure #TODO: can probably be removed now due to REST API v2
|
||||||
name = level['name']
|
name = level['name']
|
||||||
method = 1
|
method = 1
|
||||||
except:
|
except:
|
||||||
|
@ -418,6 +624,8 @@ def check_header(level):
|
||||||
return header_all_in_level, unheader_all_in_level
|
return header_all_in_level, unheader_all_in_level
|
||||||
|
|
||||||
# Logic for applying and removing headers
|
# Logic for applying and removing headers
|
||||||
|
|
||||||
|
|
||||||
def modify_headers(task, child_tasks, header_all_in_p, unheader_all_in_p, header_all_in_s, unheader_all_in_s, header_all_in_t, unheader_all_in_t):
|
def modify_headers(task, child_tasks, header_all_in_p, unheader_all_in_p, header_all_in_s, unheader_all_in_s, header_all_in_t, unheader_all_in_t):
|
||||||
if any([header_all_in_p, header_all_in_s, header_all_in_t]):
|
if any([header_all_in_p, header_all_in_s, header_all_in_t]):
|
||||||
if task.content[0] != '*':
|
if task.content[0] != '*':
|
||||||
|
@ -583,14 +791,17 @@ def run_recurring_lists_logic(args, api, item, child_items, child_items_all, reg
|
||||||
# item.content)
|
# item.content)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Contains all main autodoist functionalities
|
# Contains all main autodoist functionalities
|
||||||
|
|
||||||
|
|
||||||
def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
def autodoist_magic(args, api, connection):
|
||||||
|
|
||||||
# Preallocate dictionaries
|
# Preallocate dictionaries and other values
|
||||||
overview_task_ids = {}
|
overview_task_ids = {}
|
||||||
overview_task_labels = {}
|
overview_task_labels = {}
|
||||||
|
next_action_label = args.label
|
||||||
|
regen_labels_id = args.regen_label_names
|
||||||
|
|
||||||
try:
|
try:
|
||||||
projects = api.get_projects()
|
projects = api.get_projects()
|
||||||
|
@ -599,6 +810,13 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
|
|
||||||
for project in projects:
|
for project in projects:
|
||||||
|
|
||||||
|
# Skip processing inbox as intended feature
|
||||||
|
if project.is_inbox_project:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check db existance
|
||||||
|
db_check_existance(connection, project)
|
||||||
|
|
||||||
# To determine if a sequential task was found
|
# To determine if a sequential task was found
|
||||||
first_found_project = False
|
first_found_project = False
|
||||||
|
|
||||||
|
@ -608,7 +826,7 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
# Get project type
|
# Get project type
|
||||||
if next_action_label is not None:
|
if next_action_label is not None:
|
||||||
project_type, project_type_changed = get_project_type(
|
project_type, project_type_changed = get_project_type(
|
||||||
args, project)
|
args, connection, project)
|
||||||
|
|
||||||
if project_type is not None:
|
if project_type is not None:
|
||||||
logging.debug('Identified \'%s\' as %s type',
|
logging.debug('Identified \'%s\' as %s type',
|
||||||
|
@ -616,7 +834,7 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
|
|
||||||
# Get all tasks for the project
|
# Get all tasks for the project
|
||||||
try:
|
try:
|
||||||
project_tasks = api.get_tasks(project_id = project.id)
|
project_tasks = api.get_tasks(project_id=project.id)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
|
||||||
|
@ -627,18 +845,27 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
# get(api._session, endpoint, api._token, '0')['items']
|
# get(api._session, endpoint, api._token, '0')['items']
|
||||||
# $ curl https://api.todoist.com/sync/v9/sync-H "Authorization: Bearer e2f750b64e8fc06ae14383d5e15ea0792a2c1bf3" -d commands='[ {"type": "item_add", "temp_id": "63f7ed23-a038-46b5-b2c9-4abda9097ffa", "uuid": "997d4b43-55f1-48a9-9e66-de5785dfd69b", "args": {"content": "Buy Milk", "project_id": "2203306141","labels": ["Food", "Shopping"]}}]'
|
# $ curl https://api.todoist.com/sync/v9/sync-H "Authorization: Bearer e2f750b64e8fc06ae14383d5e15ea0792a2c1bf3" -d commands='[ {"type": "item_add", "temp_id": "63f7ed23-a038-46b5-b2c9-4abda9097ffa", "uuid": "997d4b43-55f1-48a9-9e66-de5785dfd69b", "args": {"content": "Buy Milk", "project_id": "2203306141","labels": ["Food", "Shopping"]}}]'
|
||||||
|
|
||||||
# for s in [0, 1]: # TODO: TEMPORARELY SKIP SECTIONLESS TASKS
|
# for s in [0,1]:
|
||||||
for s in [1]:
|
# if s == 0:
|
||||||
if s == 0:
|
# sections = Section(None, None, 0, project.id)
|
||||||
sections = [create_none_section()] # TODO: Rewrite
|
# elif s == 1:
|
||||||
elif s == 1:
|
# try:
|
||||||
|
# sections = api.get_sections(project_id=project.id)
|
||||||
|
# except Exception as error:
|
||||||
|
# print(error)
|
||||||
|
|
||||||
|
# Get all sections and add the 'None' section too.
|
||||||
try:
|
try:
|
||||||
sections = api.get_sections(project_id = project.id)
|
sections = api.get_sections(project_id=project.id)
|
||||||
|
sections.insert(0, Section(None, None, 0, project.id))
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
|
||||||
for section in sections:
|
for section in sections:
|
||||||
|
|
||||||
|
# Check db existance
|
||||||
|
db_check_existance(connection, section)
|
||||||
|
|
||||||
# Check if we need to (un)header entire secion
|
# Check if we need to (un)header entire secion
|
||||||
header_all_in_s, unheader_all_in_s = check_header(section)
|
header_all_in_s, unheader_all_in_s = check_header(section)
|
||||||
|
|
||||||
|
@ -647,7 +874,7 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
|
|
||||||
# Get section type
|
# Get section type
|
||||||
section_type, section_type_changed = get_section_type(
|
section_type, section_type_changed = get_section_type(
|
||||||
args, section)
|
args, connection, section)
|
||||||
if section_type is not None:
|
if section_type is not None:
|
||||||
logging.debug('Identified \'%s\' as %s type',
|
logging.debug('Identified \'%s\' as %s type',
|
||||||
section.name, section_type)
|
section.name, section_type)
|
||||||
|
@ -681,6 +908,8 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
dominant_type = None # Reset
|
dominant_type = None # Reset
|
||||||
|
|
||||||
|
db_check_existance(connection, task)
|
||||||
|
|
||||||
# Possible nottes routine for the future
|
# Possible nottes routine for the future
|
||||||
# notes = api.notes.all() TODO: Quick notes test to see what the impact is?
|
# notes = api.notes.all() TODO: Quick notes test to see what the impact is?
|
||||||
# note_content = [x['content'] for x in notes if x['item_id'] == item['id']]
|
# note_content = [x['content'] for x in notes if x['item_id'] == item['id']]
|
||||||
|
@ -698,10 +927,10 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
header_all_in_t, unheader_all_in_t = check_header(task)
|
header_all_in_t, unheader_all_in_t = check_header(task)
|
||||||
|
|
||||||
# Modify headers where needed
|
# Modify headers where needed
|
||||||
#TODO: DISABLED FOR NOW, FIX LATER
|
# TODO: DISABLED FOR NOW, FIX LATER
|
||||||
# modify_headers(header_all_in_p, unheader_all_in_p, header_all_in_s, unheader_all_in_s, header_all_in_t, unheader_all_in_t)
|
# modify_headers(header_all_in_p, unheader_all_in_p, header_all_in_s, unheader_all_in_s, header_all_in_t, unheader_all_in_t)
|
||||||
|
|
||||||
#TODO: Check is regeneration is still needed, now that it's part of core Todoist. Disabled for now.
|
# TODO: Check is regeneration is still needed, now that it's part of core Todoist. Disabled for now.
|
||||||
# Logic for recurring lists
|
# Logic for recurring lists
|
||||||
# if not args.regeneration:
|
# if not args.regeneration:
|
||||||
# try:
|
# try:
|
||||||
|
@ -724,12 +953,14 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
continue
|
continue
|
||||||
if task.content.startswith('*'):
|
if task.content.startswith('*'):
|
||||||
# Remove next action label if it's still present
|
# Remove next action label if it's still present
|
||||||
remove_label(task, next_action_label, overview_task_ids, overview_task_labels)
|
remove_label(task, next_action_label,
|
||||||
|
overview_task_ids, overview_task_labels)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Check task type
|
# Check task type
|
||||||
task_type, task_type_changed = get_task_type(
|
task_type, task_type_changed = get_task_type(
|
||||||
args, task, project_type)
|
args, connection, task, section_type, project_type)
|
||||||
|
|
||||||
if task_type is not None:
|
if task_type is not None:
|
||||||
logging.debug('Identified \'%s\' as %s type',
|
logging.debug('Identified \'%s\' as %s type',
|
||||||
task.content, task_type)
|
task.content, task_type)
|
||||||
|
@ -783,17 +1014,16 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
|
|
||||||
# If there are children
|
# If there are children
|
||||||
if len(child_tasks) > 0:
|
if len(child_tasks) > 0:
|
||||||
|
|
||||||
# Check if task state has changed, if so clean children for good measure
|
# Check if task state has changed, if so clean children for good measure
|
||||||
if task_type_changed == 1:
|
if task_type_changed == 1:
|
||||||
[remove_label(child_task, next_action_label, overview_task_ids, overview_task_labels)
|
[remove_label(child_task, next_action_label, overview_task_ids, overview_task_labels)
|
||||||
for child_task in child_tasks]
|
for child_task in child_tasks]
|
||||||
|
|
||||||
# If a sub-task, inherit parent task type
|
# If a sub-task, inherit parent task type
|
||||||
if task.parent_id !=0:
|
if task.parent_id != 0:
|
||||||
try:
|
# dominant_type = task.parent_type # TODO: METADATA
|
||||||
dominant_type = task.parent_type #TODO: METADATA
|
dominant_type = db_read_value(connection, task, 'parent_type')[0][0]
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Process sequential tagged tasks (task_type can overrule project_type)
|
# Process sequential tagged tasks (task_type can overrule project_type)
|
||||||
if dominant_type == 'sequential' or dominant_type == 'p-s':
|
if dominant_type == 'sequential' or dominant_type == 'p-s':
|
||||||
|
@ -820,13 +1050,17 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
elif dominant_type == 'parallel' or (dominant_type == 's-p' and next_action_label in task.labels):
|
elif dominant_type == 'parallel' or (dominant_type == 's-p' and next_action_label in task.labels):
|
||||||
remove_label(
|
remove_label(
|
||||||
task, next_action_label, overview_task_ids, overview_task_labels)
|
task, next_action_label, overview_task_ids, overview_task_labels)
|
||||||
|
db_update_value(task, 'task_type', 'NULL')
|
||||||
|
|
||||||
for child_task in child_tasks:
|
for child_task in child_tasks:
|
||||||
|
|
||||||
# Ignore headered children
|
# Ignore headered children
|
||||||
if child_task.content.startswith('*'):
|
if child_task.content.startswith('*'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
child_task.parent_type = dominant_type #TODO: METADATA
|
# child_task.parent_type = dominant_type # TODO: METADATA
|
||||||
|
db_update_value(connection, child_task, 'parent_type', dominant_type)
|
||||||
|
|
||||||
if not child_task.is_completed:
|
if not child_task.is_completed:
|
||||||
add_label(
|
add_label(
|
||||||
child_task, next_action_label, overview_task_ids, overview_task_labels)
|
child_task, next_action_label, overview_task_ids, overview_task_labels)
|
||||||
|
@ -923,21 +1157,9 @@ def autodoist_magic(args, api, next_action_label, regen_labels_id):
|
||||||
'Wrong start-date format for task: %s. Please use "start=due-<NUM><d or w>"', task.content)
|
'Wrong start-date format for task: %s. Please use "start=due-<NUM><d or w>"', task.content)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Return all ids and corresponding labels that need to be modified
|
||||||
return overview_task_ids, overview_task_labels
|
return overview_task_ids, overview_task_labels
|
||||||
|
|
||||||
|
|
||||||
# Connect to SQLite database
|
|
||||||
|
|
||||||
def create_connection(path):
|
|
||||||
connection = None
|
|
||||||
try:
|
|
||||||
connection = sqlite3.connect(path)
|
|
||||||
print("Connection to SQLite DB successful")
|
|
||||||
except Error as e:
|
|
||||||
print(f"The error '{e}' occurred")
|
|
||||||
|
|
||||||
return connection
|
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
|
|
||||||
|
|
||||||
|
@ -989,7 +1211,7 @@ def main():
|
||||||
args.regen_label_names = ('Regen_off', 'Regen_all',
|
args.regen_label_names = ('Regen_off', 'Regen_all',
|
||||||
'Regen_all_if_completed')
|
'Regen_all_if_completed')
|
||||||
|
|
||||||
# Set debug
|
# Set logging
|
||||||
if args.debug:
|
if args.debug:
|
||||||
log_level = logging.DEBUG
|
log_level = logging.DEBUG
|
||||||
else:
|
else:
|
||||||
|
@ -1007,7 +1229,10 @@ def main():
|
||||||
check_for_update(current_version)
|
check_for_update(current_version)
|
||||||
|
|
||||||
# Initialise api
|
# Initialise api
|
||||||
api = initialise(args)
|
api = initialise_api(args)
|
||||||
|
|
||||||
|
# Initialise SQLite database
|
||||||
|
connection = initialise_sqlite()
|
||||||
|
|
||||||
# Start main loop
|
# Start main loop
|
||||||
while True:
|
while True:
|
||||||
|
@ -1016,7 +1241,7 @@ def main():
|
||||||
|
|
||||||
# Evaluate projects, sections, and tasks
|
# Evaluate projects, sections, and tasks
|
||||||
overview_task_ids, overview_task_labels = autodoist_magic(
|
overview_task_ids, overview_task_labels = autodoist_magic(
|
||||||
args, api, args.label, args.regen_label_names)
|
args, api, connection)
|
||||||
|
|
||||||
# Commit next action label changes
|
# Commit next action label changes
|
||||||
if args.label is not None:
|
if args.label is not None:
|
||||||
|
|
Loading…
Reference in New Issue