Skip to content

Instantly share code, notes, and snippets.

@braden-w
Last active May 28, 2022 17:07
Show Gist options
  • Save braden-w/06ed672d577a08bd1e2eb671931333af to your computer and use it in GitHub Desktop.
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).
Display the source blob
Display the rendered blob
Raw
{
"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