diff --git a/main.py b/main.py new file mode 100644 index 0000000..b4cc45b --- /dev/null +++ b/main.py @@ -0,0 +1,66 @@ +import os +from notion_client import Client +from pprint import pprint +from dotenv import load_dotenv +from typing import List, Dict +import os.path +import logging + +from sync.notion_to_google_task_sync import ( + authenticate_and_print, + get_all_pages, + get_all_blocks, + get_todo, + create_notion_tasklist, + insert_notion_tasks_in_google_tasks, + add_id_mapping_to_redis, + update_google_tasks, + remove_deleted_tasks_ids_from_redis, +) + +from sync.google_to_notion_task_sync import ( + update_notion_tasks, + remove_deleted_google_tasks, + insert_google_task_into_notion, +) + +if __name__ == "__main__": + + load_dotenv() + NOTION_ID = os.getenv("NOTION_KEY") + if NOTION_ID is None: + raise KeyError("Missing NOTION ID environment variable") + + service = authenticate_and_print() + + # Create Client + client = Client(auth=NOTION_ID) + + # Get all page ids + page_ids = get_all_pages(client) + + # Get every block from each page id + total_blocks = [] + + for page_id in page_ids: + total_blocks.extend(get_all_blocks(client, page_id)) + + # Get all Notion todos + total_notion_tasks = get_todo(client, total_blocks) + + + for page_id in page_ids: + all_blocks = [] + + all_blocks.extend(get_all_blocks(client, page_id)) + notion_tasks = get_todo(client, all_blocks) + + title = client.blocks.retrieve(page_id)["child_page"]["title"] + TASK_LIST_ID = create_notion_tasklist(service, title) + + # Insert tasks from Notion to Google + insert_notion_tasks_in_google_tasks(service, notion_tasks, TASK_LIST_ID) + add_id_mapping_to_redis(service, notion_tasks, TASK_LIST_ID) + remove_deleted_tasks_ids_from_redis(service, total_notion_tasks, TASK_LIST_ID) + update_google_tasks(service, notion_tasks, TASK_LIST_ID) + diff --git a/sync/google_to_notion_task_sync.py b/sync/google_to_notion_task_sync.py index ef54676..1ca7738 100644 --- a/sync/google_to_notion_task_sync.py +++ b/sync/google_to_notion_task_sync.py @@ -1,10 +1,96 @@ """Script that handles the sync from Google Tasks to Notion""" +from notion_client import Client +from typing import List +from sync.notion_to_google_task_sync import r_reverse, r -# Extra features: -# (???) If a task is added to GC, it should be added to Notion as well (???) Where? -# If a task is ticked on Google Calendar, it should be ticket on Notion as well, etc. -# If a task is changed (text edited) in GC it should be changed in Notion as well -# If a task is deleted on GC, if should be deleted in Notion as well +def get_pages_data(client: Client) -> List[str]: + """Get all pages that have enabled the integration""" + # import ipdb;ipdb.set_trace() + pages_data = {} + for page in client.search()["results"]: + title = page["properties"]["title"]["title"][0]["plain_text"] + pages_data[title] = page["id"] + return pages_data + + +def insert_google_task_into_notion(service, client, notion_page_id, task_list_id): + """Insert google tasks into notion""" + + current_google_tasks = [ + {"title": task["title"], "id": task["id"], "status": task["status"]} + for task in service.tasks().list(tasklist=task_list_id).execute()["items"] + ] + + for google_task in current_google_tasks[::-1]: + if r_reverse.get(google_task["id"]) is None: + + if google_task["status"] == "needsAction": + checked = False + else: + checked = True + + notion_task = client.blocks.children.append( + notion_page_id, + children=[ + { + "to_do": { + "rich_text": [{"text": {"content": google_task["title"]}}], + "checked": checked, + } + } + ], + ) + + # this should be done in another function. Use it for demo for now + r.set(notion_task["results"][0]["id"], google_task["id"]) + r_reverse.set(google_task["id"], notion_task["results"][0]["id"]) + + +def remove_deleted_google_tasks(service, client, task_list_id): + """Delete NT that has been removed from GT""" + + current_google_task_ids = [] + + current_google_task_ids = [ + task["id"] + for task in service.tasks() + .list(tasklist=task_list_id, showHidden=True) + .execute()["items"] + ] + + for google_task_id in r_reverse.keys(): + if google_task_id not in current_google_task_ids: + + notion_id_in_db = r_reverse.get(google_task_id) + client.blocks.delete(notion_id_in_db) + r.delete(notion_id_in_db) + r_reverse.delete(google_task_id) + + +def update_notion_tasks(service, client, task_list_id): + """Function that Updates tasks. Closes tasks marked as completed from Notion to Google Takss""" + + current_google_tasks = [ + {"title": task["title"], "id": task["id"], "status": task["status"]} + for task in service.tasks() + .list(tasklist=task_list_id, showHidden=True) + .execute()["items"] + ] + + for google_task in current_google_tasks: + + if r_reverse.get(google_task["id"]) is not None: + block = client.blocks.retrieve(r_reverse.get(google_task["id"])) + + if google_task["status"] == "needsAction": + block["to_do"]["checked"] = False + else: + block["to_do"]["checked"] = True + + block["to_do"]["rich_text"][0]["text"]["content"] = google_task["title"] + block["to_do"]["rich_text"][0]["plain_text"] = google_task["title"] + + client.blocks.update(r_reverse.get(google_task["id"]), **block) diff --git a/sync/notion_to_google_task_sync.py b/sync/notion_to_google_task_sync.py index a1a295a..65e6fdc 100644 --- a/sync/notion_to_google_task_sync.py +++ b/sync/notion_to_google_task_sync.py @@ -15,14 +15,16 @@ from googleapiclient.errors import HttpError import redis -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # ----------------- # SETUP SCOPES = ["https://www.googleapis.com/auth/tasks"] -r = redis.Redis(host="localhost", port=6379, decode_responses=True) +r = redis.Redis(host="localhost", port=6379, decode_responses=True, db=0) + +r_reverse = redis.Redis(host="localhost", port=6379, decode_responses=True, db=1) # ----------------- # NOTION FUNCTIONS @@ -118,11 +120,6 @@ def insert_notion_tasks_in_google_tasks(service, notion_tasks, task_list_id): def update_google_tasks(service, notion_tasks, task_list_id): """Function that Updates tasks. Closes tasks marked as completed from Notion to Google Takss""" - current_google_tasks = [ - {"title": task["title"], "id": task["id"], "status": task["status"]} - for task in service.tasks().list(tasklist=task_list_id).execute()["items"] - ] - for notion_task in notion_tasks: if r.get(notion_task["id"]) is not None: @@ -133,16 +130,14 @@ def update_google_tasks(service, notion_tasks, task_list_id): ).execute() -def create_notion_tasklist(service) -> str: +def create_notion_tasklist(service, title) -> str: """Create a dedicated TaskList in Google Tasks if it does not exist""" for task_list in service.tasklists().list().execute()["items"]: - if task_list["title"] == "Tasks from Notion": + if task_list["title"] == title: return task_list["id"] - new_task_list = ( - service.tasklists().insert(body={"title": "Tasks from Notion"}).execute() - ) + new_task_list = service.tasklists().insert(body={"title": title}).execute() return new_task_list["id"] @@ -170,6 +165,10 @@ def add_id_mapping_to_redis(service, notion_tasks, task_list_id): and notion_task["status"] == google_task["status"] ): r.set(notion_task["id"], google_task["id"]) + r_reverse.set( + google_task["id"], notion_task["id"] + ) # store reverse mapping in db1 + logging.info( f"Successfully added k: {notion_task['id']} v: {google_task['id']}" ) @@ -187,49 +186,6 @@ def remove_deleted_tasks_ids_from_redis(service, notion_tasks, task_list_id): service.tasks().delete( tasklist=task_list_id, task=r.get(notion_id_in_db) ).execute() + google_task_id = r.get(notion_id_in_db) r.delete(notion_id_in_db) - - -if __name__ == "__main__": - - load_dotenv() - NOTION_ID = os.getenv("NOTION_KEY") #NOTION_KEY - if NOTION_ID is None: - raise KeyError("Missing NOTION ID environment variable") - - service = authenticate_and_print() - - # Create Client - client = Client(auth=NOTION_ID) - - # Get all page ids - page_ids = get_all_pages(client) - - # Get every block from each page id - all_blocks = [] - for page_id in page_ids: - all_blocks.extend(get_all_blocks(client, page_id)) - - # Get all Notion todos - notion_tasks = get_todo(client, all_blocks) - - TASK_LIST_ID = create_notion_tasklist(service) - - # Insert tasks from Notion to Google - insert_notion_tasks_in_google_tasks(service, notion_tasks, TASK_LIST_ID) - - # TODO replace .keys() with something more efficient later - # If redis is empty, or new todo has been added, update the database - if not r.keys() or len(r.keys()) < len(notion_tasks): # add a - logging.info("Adding new data to Redis") - add_id_mapping_to_redis(service, notion_tasks, TASK_LIST_ID) - - # If redis has more keys than current notion_tasks, delete the Google task and that key - if len(r.keys()) > len(notion_tasks): - logging.info("Deleting tasks") - remove_deleted_tasks_ids_from_redis(service, notion_tasks, TASK_LIST_ID) - - # Update the state of tasks, whenever needed (checked, changed name, etc.) - update_google_tasks(service, notion_tasks, TASK_LIST_ID) - - + r_reverse.delete(google_task_id)