Skip to content

Instantly share code, notes, and snippets.

@lfcipriani
Created April 21, 2020 15:31
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save lfcipriani/be87cc2c066ff34e9c69c6232cdd1fec to your computer and use it in GitHub Desktop.
Todoist Standup update generator
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# This script generates a basic standup update out of completed and due tasks in Todoist.
# It considers business days only and holidays (if configured)
#
# Setup:
#
# Use python >= 3
#
# pip install todoist-python
# pip install workdays
#
# Check config below
#
# Usage:
#
# python todoist_standup.py [YYYY-MM-DD]
# - defaults to today's date if you omit the date
#
import sys
import datetime
import json
import requests
import todoist
import workdays
# -------------- Config --------------
# Todoist token, change the path to a file with the todoist API token as content
token = open("/path/to/secret.txt", "r").read().strip()
# Holidays to take into account. Use YYYY-MM-DD format.
holidays = [
'2020-01-01',
'2020-05-01',
'2020-05-21',
'2020-06-01',
'2020-10-03',
'2020-12-25',
'2020-12-26'
]
# Include only the following project IDs, use empty array to include all projects
projects = [
1111111, # project 1
2222222 # project 2
]
# Ignore unlabeled tasks?
ignore_unlabeled_tasks = False
# Ignore tasks with following labels IDs, use empty array to not ignore any label
labels_to_ignore = [
111111, # label 1
222222, # label 2
333333 # label 3
]
# Ignore tasks with the following titles, matches the exact string. Use empty array to not ignore any task
task_titles_to_ignore = [
'Daily Dev Standup',
'Routine Task'
]
# Feel free to change the standup output
# 'yesterday' and 'today' params are array of strings
def print_standup(yesterday,today):
print("My standup update:")
print("")
print("*What I did in the previous work day?*")
for item in yesterday:
print(f' - {item}')
print("")
print("*What I will do today?*")
for item in today:
print(f' - {item}')
# -------------- End of Config --------------
def main(day):
yesterday = what_you_did_yesterday(day)
today = what_you_will_do_today(day)
print_standup(yesterday, today)
def get_date(str_date):
return datetime.datetime.strptime(str_date, '%Y-%m-%d')
def init_holidays(days):
return map(lambda h: get_date(h), days)
def last_business_day_interval(day):
business_day = workdays.workday(day, -1, init_holidays(holidays))
return business_day.strftime("%Y-%m-%dT%H:%M"), (business_day + datetime.timedelta(days=1)).strftime("%Y-%m-%dT%H:%M")
def ignore_labels(labels):
ignore = False
if ignore_unlabeled_tasks and len(labels) == 0:
return True
for label in labels:
if label in labels_to_ignore:
ignore = True
break
return ignore
def what_you_did_yesterday(day):
api = todoist.TodoistAPI(token)
items = []
since, util = last_business_day_interval(day)
response = api.completed.get_all(limit=200,since=since,until=util)
if 'items' in response:
for item in response['items']:
if item['project_id'] not in projects:
continue
rich_item = api.items.get(item['task_id'])
if not rich_item:
continue
rich_item = rich_item['item']
if ignore_labels(rich_item['labels']):
continue
if rich_item['content'] in task_titles_to_ignore:
continue
items.append(rich_item['content'])
return items
def what_you_will_do_today(day):
# Initializing items with completed tasks of today
items = what_you_did_yesterday(day + datetime.timedelta(days=1))
response = requests.get(
"https://api.todoist.com/rest/v1/tasks",
params={"filter": day.strftime('%Y-%m-%d')},
headers={"Authorization": "Bearer %s" % token}
).json()
for item in response:
if item['project_id'] not in projects:
continue
if ignore_labels(item['label_ids']):
continue
if item['content'] in task_titles_to_ignore:
continue
items.append(item['content'])
return items
if __name__ == '__main__':
day = None
day_arg = sys.argv[1:]
if len(day_arg) != 1:
day = datetime.datetime.today().strftime('%Y-%m-%d')
else:
day = day_arg[0]
day = get_date(day)
main(day)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment