Last active
May 28, 2022 17:07
-
-
Save braden-w/06ed672d577a08bd1e2eb671931333af to your computer and use it in GitHub Desktop.
A Python Notebook that uses the Todoist REST API (v1) and Sync API (v8) to nest all projects with an emoji as the project name underneath a project (to be used like a folder).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Todoist Project Indent\n", | |
" A Python Notebook that uses the Todoist REST API (v1) and Sync API (v8) to nest all projects with an emoji as the project name underneath a project (to be used like a folder)." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Install todoist_api_python using pip, and helper packages\n", | |
"! pip3 install todoist_api_python\n", | |
"! pip3 install python-dotenv\n", | |
"! pip3 install uuid\n", | |
"! pip3 install emoji" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Load Todoist API Token from .env file\n", | |
"import os\n", | |
"from dotenv import load_dotenv\n", | |
"\n", | |
"load_dotenv()\n", | |
"\n", | |
"TODOIST_API_TOKEN = os.environ.get('TODOIST_API_TOKEN')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Set the parent project that we will nest projects under\n", | |
"PARENT_PROJECT_ID = 2284823727" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Helper functions\n", | |
"import emoji\n", | |
"def is_emoji(s: str) -> bool:\n", | |
" return s in emoji.UNICODE_EMOJI['en'].keys() \n", | |
"\n", | |
"def contains_emoji(s: str) -> bool:\n", | |
" return any(is_emoji(c) for c in s)\n", | |
"\n", | |
"def starts_with_emoji(s: str) -> bool:\n", | |
" return is_emoji(s[0])\n", | |
"\n", | |
"def ends_with_emoji(s: str) -> bool:\n", | |
" return is_emoji(s[-1])\n", | |
"\n", | |
"def is_only_emoji(s: str) -> bool:\n", | |
" return all(is_emoji(c) for c in s)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"[Project(id=2211976340, color=39, comment_count=0, favorite=False, name='π§Ά', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2211976340', inbox_project=None, team_inbox=None, order=14, parent_id=None),\n", | |
" Project(id=2253520462, color=37, comment_count=0, favorite=False, name='π', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2253520462', inbox_project=None, team_inbox=None, order=15, parent_id=None),\n", | |
" Project(id=2285881098, color=37, comment_count=0, favorite=False, name='π§', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2285881098', inbox_project=None, team_inbox=None, order=17, parent_id=None),\n", | |
" Project(id=2284922549, color=47, comment_count=0, favorite=False, name='π', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2284922549', inbox_project=None, team_inbox=None, order=20, parent_id=None),\n", | |
" Project(id=2284922560, color=47, comment_count=0, favorite=False, name='π«', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2284922560', inbox_project=None, team_inbox=None, order=21, parent_id=None),\n", | |
" Project(id=2284922587, color=47, comment_count=0, favorite=False, name='π€€', shared=False, sync_id=0, url='https://todoist.com/showProject?id=2284922587', inbox_project=None, team_inbox=None, order=23, parent_id=None)]" | |
] | |
}, | |
"execution_count": 22, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from todoist_api_python.api import TodoistAPI\n", | |
"\n", | |
"api = TodoistAPI(TODOIST_API_TOKEN)\n", | |
"\n", | |
"projects = api.get_projects()\n", | |
"\n", | |
"# For each project, if the project name is an emoji, then add it to the array projects_with_emoji\n", | |
"projects_with_emoji = [project for project in projects if is_only_emoji(project.name)]\n", | |
"projects_with_emoji_without_parent = [project for project in projects_with_emoji if project.parent_id != PARENT_PROJECT_ID]\n", | |
"projects_with_emoji_without_parent" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"{\"full_sync\":true,\"sync_status\":{\"97b18b69-ea13-45df-93ea-5df5db2e089a\":\"ok\"},\"sync_token\":\"GcRSymmpe2RYZ9hhe4C-NzfI3seIkjtWNuhOpQCNQRmxVCdlrSdvtkh5pdrI7yjbw0w2zvFjpJLF8rS2bYMQ13MZNgOQMaWqjnBm-ptzb3cEH6R0pw\",\"temp_id_mapping\":{}}\n", | |
"{\"full_sync\":true,\"sync_status\":{\"7209d593-28cd-41dd-9b08-8051958b9ff0\":\"ok\"},\"sync_token\":\"DDerTZzbF0VH3nBtZJhFg_9A-rDOf2zVYpE-HmuQjt3f7qUZ3S-O6qs-TRK6tpko7HjGY3nOmUI4PusxJwSWkb7PkmBNgRObFjO5J51oVjs_ky8HTA\",\"temp_id_mapping\":{}}\n", | |
"{\"full_sync\":true,\"sync_status\":{\"5da53709-c231-49de-a086-bae6e2646f25\":\"ok\"},\"sync_token\":\"js8lKuOBj7RsIHd_AjES0Gq5VLZVim5Rhh6mVkMgXU5-yMgkcr83iP7fQGh4HRrFXY8BeORR984rmc1j8mGZbGQVbqY0I3NW0YUAAPAtu_5EMcRzhQ\",\"temp_id_mapping\":{}}\n", | |
"{\"full_sync\":true,\"sync_status\":{\"5dccab7d-66ae-4af8-89fa-11690b361c34\":\"ok\"},\"sync_token\":\"3rmZzZJAt2-Ocxxt8-HNdzn9_cN6gBvJv0XV9a9t0hZR5RbGNoT0c7SO2F3Hy0vpPSV4mId5MXB1g64dL2dWl3nq82hQ1UilWvORdQG-akVgc4uUTg\",\"temp_id_mapping\":{}}\n", | |
"{\"full_sync\":true,\"sync_status\":{\"4c66bfc7-20d2-44f2-998a-7a2d48ec2342\":\"ok\"},\"sync_token\":\"_3X5fZtbCDSoNOXuxMpMd3hBV0IEZrzCQ6QdFoU2Rw5oHaLS47KVkTqAmlrNMsArFDNor7HFM9sYIUICVzI9YXW_1rL7H8JjOdhVxABV9tdb0JdqDw\",\"temp_id_mapping\":{}}\n", | |
"{\"full_sync\":true,\"sync_status\":{\"e0d77c78-c99e-4540-89a4-0877d7f76ec7\":\"ok\"},\"sync_token\":\"bnb_2XPRu6r-g_fQZW8v9IN1v4yIB01-KHH1NneuTPUuZa7a8EM1ab6dOpEX9HaJqewed8HK3tIZbuFh7HK-lfupFcr0kau2jq0XdwSxwdbEPFku1g\",\"temp_id_mapping\":{}}\n" | |
] | |
} | |
], | |
"source": [ | |
"import requests\n", | |
"import uuid\n", | |
"\n", | |
"headers = { 'Authorization': f'Bearer {TODOIST_API_TOKEN}'}\n", | |
"reqUrl = \"https://api.todoist.com/sync/v8/sync\"\n", | |
"\n", | |
"# For each project in projects_with_emoji, update it such that its parent project is 2284823727\n", | |
"for project in projects_with_emoji_without_parent:\n", | |
" # Generate a unique uuid for each command\n", | |
" unique_uuid = str(uuid.uuid4())\n", | |
" # Generate a command to update the project's parent project\n", | |
" payload = 'commands=[{\"type\": \"project_move\", \"uuid\": \"%s\", \"args\": {\"id\": %s, \"parent_id\": %s}}]' % (unique_uuid, project.id, PARENT_PROJECT_ID)\n", | |
" response = requests.get(reqUrl, params=payload, headers=headers)\n", | |
" print(response.text)\n" | |
] | |
} | |
], | |
"metadata": { | |
"interpreter": { | |
"hash": "397704579725e15f5c7cb49fe5f0341eb7531c82d19f2c29d197e8b64ab5776b" | |
}, | |
"kernelspec": { | |
"display_name": "Python 3.9.9 64-bit", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.9.13" | |
}, | |
"orig_nbformat": 4 | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment