Exemple #1
0
    def test_CreateTask(self):
        # read api token values
        apitoken = config.get('todoistinfo', 'apitoken')

        # read created task name
        taskname = config.get('todoistinfo', 'taskname')

        # read created task ID
        taskid = config.get('todoistinfo', 'taskid')

        # Complete Task
        api = TodoistAPI(apitoken)
        api.sync()
        created_task = api.items.get_by_id(int(taskid))
        created_task.complete()
        response = api.commit()

        # Verify if the task has been completed successfully
        assert response['items'][0]['content'] == taskname
        assert response['items'][0]['checked'] == 1
        assert 1 in [
            i['checked'] for i in api.state['items'] if i['id'] == int(taskid)
        ]

        # Reopen Task
        created_task.uncomplete()
        response = api.commit()

        # Verify if the task has been reopened successfully
        assert response['items'][0]['content'] == taskname
        assert response['items'][0]['checked'] == 0
        assert 0 in [
            i['checked'] for i in api.state['items'] if i['id'] == int(taskid)
        ]
Exemple #2
0
def main(event, context):
    body = { "tasksUpdated": 0 }

    API_TOKEN = get_token()
    if not API_TOKEN:
        logging.warn('Please set the API token in environment variable.')
        exit()

    today = datetime.utcnow().replace(tzinfo=None)
    api = TodoistAPI(token=API_TOKEN, cache="/tmp/todoist")
    api.sync()
    tasks = api.state['items']
    for task in tasks:
        if task['due_date_utc'] and is_habit(task['content']):
            if is_today(task['due_date_utc']):
                habit = is_habit(task['content'])
                streak = int(habit.group(1)) + 1
                update_streak(task, streak)
                body["tasksUpdated"] += 1
            elif is_due(task['due_date_utc']):
                update_streak(task, 0)
                task.update(date_string='ev day starting tod')
    api.commit()


    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response
Exemple #3
0
def instantiate(project_name, loglevel, date_str):
    api = TodoistAPI(get_api_token())
    api.sync()

    logging.basicConfig(level=getattr(logging, loglevel.upper()))

    project_id = get_project_id(api, project_name)

    date = None if date_str is None else dateutil.parser.parse(date_str).date()
    logging.debug(f"date = {date!r}")

    tasks = api.projects.get_data(project_id)['items']
    instantiable_tasks = [
        task for task in tasks if is_instantiable(task, date)
    ]

    action_count = 0

    for task in instantiable_tasks:
        clone_task(api, task)
        postpone_task(api, task)
        action_count += 2

        # The Todoist API will reject a commit if there are more than 100
        # changes bundled together.  Just to give myself some buffer in case
        # I'm miscounting actions, I commit everytime the action count gets
        # above 80.
        if action_count > 80:
            r = api.commit()
            logging.debug(f"commit = {r!r}")
            action_count = 0

    r = api.commit()
    logging.debug(f"commit = {r!r}")
def handle_payload(request):
    if request.method == 'POST':
        received_json_data = json.loads(
            request.body)  # convert json data to python dict
        if 'events' in received_json_data.keys():
            events = received_json_data["events"]

            for event in events:
                id = event["resource"]
                type = event["type"]
                source = None  # by defualt make  url-source none
                if type == "task":
                    source = "https://app.asana.com/api/1.0/tasks/" + str(id)

                if not source == None:
                    data = requests.get(url=source,
                                        headers={"Authorisation": "Bearer "})

                    jsdata = json.loads(data)

                    if jsdata['data']['assignee']['name'] == 'Stebin Ben':
                        task_name = jsdata['data']['name']
                        api = TodoistAPI(
                            '7441fc19459367f6d69efaa79175461b521e257d')
                        api.sync()
                        project_name = jsdata['data']['memberships'][
                            'project']['name']
                        project1 = api.projects.add(project_name)
                        api.items.add(task_name, project1['id'])
                        api.commit()

        else:
            headers = request.headers
            x_hook = headers['X-Hook-Secret']
            return JsonResponse({"X-Hook-Sercret": x_hook})
Exemple #5
0
def populate_shopping_list(locked_recipes_yaml):
    data = grocery_list.get_grocery_list(locked_recipes_yaml)
    groups = {}
    for item in data.values():
        group_name = item.pop('group')
        if group_name not in groups:
            groups[group_name] = []
        groups[group_name].append(item)

    # Use Sync API instead of REST API. Sync API is faster, since we can batch
    # add items, while with the REST API, we can only add them one by one.
    api = TodoistAPI(SECRETS["todoist_api_token"])
    sections = api.projects.get_data(SHOPPING_LIST_ID)['sections']
    section_name_id_map = {}
    for section in sections:
        section_name_id_map[section['name']] = section['id']

    # Sections on Todoist must match those given in the config.yaml
    assert set(groups.keys()).issubset(set(section_name_id_map.keys()))

    print('Creating shopping list')
    for section_name, group in groups.items():
        section_id = section_name_id_map[section_name]
        for item in group:
            api.items.add(
                content=item['name'],
                description=f"{item['amount']} {item['unit']}",
                project_id=SHOPPING_LIST_ID,
                section_id=section_id,
            )
    api.commit()
Exemple #6
0
def clear_shopping_list():
    print('Clearing shopping list')
    api = TodoistAPI(SECRETS["todoist_api_token"])
    items = api.projects.get_data(SHOPPING_LIST_ID)['items']
    for item in items:
        api.items.get_by_id(item['id']).delete()
    api.commit()
Exemple #7
0
class Todoist(Todolist):
    def __init__(self, list_name=None):
        print("Initializing Todoist API...")
        self.api = TodoistAPI(settings.todoist_key)  # TODO: other users
        self.api.sync()
        self.Project_ID = settings.todoist_project_key# TODO: add option for other projects
        self.project_name = list_name

        '''if list_name is not None:
            projects = self.api.projects
            for project in projects.all('name = ' + list_name):
                if project['name'] == list_name:
                    self.Project_ID = project['id']'''

    def add_task(self, name, desc=None, labels=None, due=None, assign=None):
        
        if labels is not None:
            for label in labels:
                name = name + ' @' + label
        if self.project_name is not None:
            name = name + ' #' + self.project_name
        if due is None:
            task = self.api.items.add(name, self.Project_ID)
        else:
            due = due - timedelta(hours=4)
            task = self.api.items.add(name, self.Project_ID, due_date_utc=due)

        task_id = task['id']

        # PREMIUM!
        #if desc is not None:
        #    self.api.notes.add(task_id, desc)

        print("\tAdded task: Name - " + name)
        self.api.commit()
Exemple #8
0
def main():
    API_TOKEN = get_token()
    today = datetime.utcnow().replace(tzinfo=None)
    if not API_TOKEN:
        logging.error('Please set the API token in environment variable.')
        exit()
    api = TodoistAPI(API_TOKEN)
    api.sync()
    project_id = get_project(api)
    tasks = api.state['items']
    for task in tasks:
        content = task['content']
        if all([
            task['due_date_utc'],
            is_habit(content),
            not project_id or task['project_id'] == project_id
        ]):
            logger.info("Found task id:%s content:%s", task['id'], content[:20])
            date_string = task['date_string'] or 'ev day'
            task_id = task['id']
            due_at = parse(task['due_date_utc'], ignoretz=True)
            days_left = due_at.date() - today.date()
            if days_left:
                habit = is_habit(content)
                streak = int(habit.group(1)) + 1
                update_streak(task, streak)
                api.notes.add(task_id, '[BOT] Streak extended. Yay!')
            else:
                update_streak(task, 0)
                task.update(date_string=date_string + ' starting tod')
                api.notes.add(task_id, '[BOT] Chain broken :(')
    api.commit()
Exemple #9
0
class Todoist():
    def __init__(self, api_key):
        self.api = TodoistAPI(api_key)

    def projToId(self, project):
        for proj in self.api.state['projects']:
            if proj['name'].strip() == project.strip():
                return proj['id']

    def addTaskProj(self, name, project):
        self.api.sync()
        item = self.api.items.add(name, self.projToId(project))
        self.api.commit()
        return item

    def getTasks(self, fil=TaskFillters.defult):
        self.api.sync()
        return [i for i in self.api.state['items'] if fil(vars(i)['data'])]

    def getProj(self, proj):
        proj = self.projToId(proj)
        return self.getTasks(TaskFillters.taskInProj(proj))

    def getProjDue(self, proj):
        proj = self.projToId(proj)
        return self.getTasks(TaskFillters.taskProjDue(proj))

    def deleteTask(self, ID):
        self.api.sync()
        self.api.items.get_by_id(ID).delete()
        self.api.commit()
Exemple #10
0
def main():
    print("Loading config...")
    with open('/home/pi/todoist-ordering/config.json', 'r') as f:
        config = json.load(f)
    api = TodoistAPI(config['apikey'])
    api.sync()
    projects_to_sort = config['projects']
    print("Sorting projects")
    for project in api.state['projects']:
        name = project['name']
        if name in projects_to_sort.keys():
            sortkeys = projects_to_sort[name]
            result = getTasksInProject(project['id'], api.state['items'])
            #     for item in result:
            #         print("Item Content: (" + item['content'] + ")")
            for sortkey in sortkeys:
                sortedResult = sortTasks(result, sortkey)
                print("Sorting project: '" + project['name'] + "' by key: '" +
                      sortkey + "'")
            thisOrder = 0
            for item in sortedResult:
                api.items.reorder([{
                    'id': item['id'],
                    'child_order': thisOrder
                }])
                thisOrder += 1
        #     print("After sort...")
        #     for item in result:
        #         print("Item Content: (" + item['content'] + ")")
            print("Committing...")
        else:
            print("No config for project: '" + project['name'] + "'")

    api.commit()
    print("DONE!")
def todoist_task_uploader(cal, fin):
    """    
    Method to upload/create tasks with Todoist API

    Args:
        cal (string): [name of the project or calendar]
        fin (string): [path to the file]
    """
    school_pid = ''
    subject_count = 0
    task_count = 0
    # Connect with Todoist API
    api = TodoistAPI(os.getenv('API_TOKEN'))
    logging.info('Connection established!')
    api.sync()

    # Search for desire Project (SCHOOL)
    for project in api.state['projects']:
        if 'SCHOOL' in project['name']:
            school_pid = project['id']

    # read file
    logging.info('Reading file...')
    wb = load_workbook(fin)
    logging.info('Creating new project...')
    # Create new Semester Project
    semester = api.projects.add('Semester ' + cal, parent_id=school_pid, color=randint(30, 49))

    for materia in wb.worksheets:
        # Create Section per Subject(Worksheet)
        subject = materia.title.split('-')  # worksheet in format: Subject-label
        section = api.sections.add(subject[0], semester['id'])
        new_label = api.labels.add(subject[1])
        label_id = 2155146353 if subject[1] == 'proyecto' else new_label['id']
        subject_count += 1
        logging.info('Creating section: ' + subject[0])
        logging.info('Creating tasks...')
        for task in materia.values:
            # Create Tasks Per Section
            api.items.add(task[0],
                          due = {
                              "string": task[1],
                              "date": task[1],  # datetime must be text in excel with format: 2021-08-10 not 2021-8-10
                              "recurring": False,
                              },
                          section_id = section['id'],
                          description = task[2],  # type of activity: foro or buzon
                          labels = [2155113156, label_id])  # label 'INICIO' and section label
            task_count += 1

    # Commit Changes and Sync
    logging.info('Committing changes to API...')
    api.commit()
    logging.info("Sync'ing changes to API...")
    api.sync()

    # Print successful message
    logging.info('Successfully created {} section(s) with {} task(s).'.format(subject_count, task_count))
    logging.info('Work done!')
Exemple #12
0
def add_data(api_key, issues):
    """ add tasks to Todoist INBOX due today """
    api = TodoistAPI(api_key)
    api.sync()
    for v in issues:
        api.items.add(v, due={"string": "today"})

    api.commit()
Exemple #13
0
def create_shop_project(key=tovakey):
    api = TodoistAPI(key)
    api.sync()
    payload = request.get_json()
    shop_name = payload["context"]["facts"]["shop_name"]["grammar_entry"]
    added_project = api.projects.add(shop_name)
    api.commit()
    print("ADDED PROJECT:", added_project)
    return action_success_response()
Exemple #14
0
def CreateTodoistTask(taskname):

    # initialize the API object
    token = 'YOUR_TD_TOKEN'  # Todoist API token
    api = TodoistAPI(token)

    # Create a new task
    api.items.add(taskname, None, date_string='today')  # default task setup

    # commit
    api.commit()
Exemple #15
0
def add_task(task_content: str, date: str, priority: int = 4):
    """
    Add a new task to todoist.

    :param priority: Priority of the task
    :param task_content: Task description
    :param date: Due date for task
    """
    api = TodoistAPI(TODOIST_APIKEY)
    api.sync()
    api.items.add(task_content,
                  date_string=date,
                  priority=priority,
                  section_id=INVESTMENT_SECTION_ID)
    api.commit()
Exemple #16
0
def add_tasks(cache):
    PROJECT_ID = os.environ.get("TODOIST_TV_PROJECT_ID")

    api = TodoistAPI(API_KEY)
    api.sync()

    for show in cache.get("_shows_updated"):
        api.items.add(getTaskForShow(cache.get(show)), PROJECT_ID)
    cache["_shows_updated"] = set()

    for film in cache.get("_films_updated"):
        api.items.add(film, PROJECT_ID)
    cache["_films_updated"] = set()

    api.commit()
Exemple #17
0
def create_todoist_clockout_task():
    now = datetime.datetime.now().astimezone(timezone('Europe/Amsterdam'))
    soll = datetime.timedelta(hours=REQUIRED_WORKING_HOURS,
                              minutes=WORKING_MINUTES) + now
    acc = datetime.timedelta(hours=WORKING_HOURS,
                             minutes=WORKING_MINUTES) + now
    clockin_time = str(now.hour) + ':' + str('%02d' % now.minute)
    clockout_time = str(acc.hour) + ':' + str('%02d' % acc.minute)
    soll_time = str(soll.hour) + ':' + str('%02d' % soll.minute)

    task_content = 'Gehen (Gekommen: ' + clockin_time + ', Soll erreicht: ' + soll_time + ')'

    logger.info('Create Todoist Clock-Out Task: ' + task_content +
                ' due at: ' + clockout_time)

    api = TodoistAPI(token=get_token(), cache="/tmp/todoist")
    logger.info("Trying to connect to Todoist API with: %s", get_token())
    if not api.sync():
        logger.warning('Todoist: API Sync failed')
        exit()

    api.items.add(task_content,
                  project_id='178923234',
                  date_string=clockout_time,
                  labels=[2147513595],
                  priority=3)
    if api.commit():
        logger.info("Todoist Clock-Out Task has been created")
Exemple #18
0
    def test_CreateProject(self):
        #read api token values
        apitoken = config.get('todoistinfo', 'apitoken')

        # read project name
        projectname = config.get('todoistinfo', 'projectname')

        '''
        Create project by using API commands
        '''
        api = TodoistAPI(apitoken)
        api.sync()

        create_project = api.projects.add(projectname)
        response = api.commit()

        # Verify if the project has been created successfully
        assert response['projects'][0]['name'] == projectname
        assert projectname in [p['name'] for p in api.state['projects']]
        assert api.projects.get_by_id(create_project['id']) == create_project

        # update the created project ID to ini file
        config.set("todoistinfo", "projectid", str(create_project['id']))
        config.write(open('../test_info.ini', 'w'))

        #Login to mobile apps and verify the project has been created successfully
        Todoist.Login(self)
        sleep(6)
        Todoist.Verify_CreatedProject(self, projectname)
Exemple #19
0
def create_todoist_lastmeal_task():
    now = datetime.datetime.now().astimezone(timezone('Europe/Amsterdam'))
    cleared_time = datetime.timedelta(hours=INTERMITTENT_FASTING_HOURS) + now

    checkin_time = str(now.hour) + ':' + str('%02d' % now.minute)
    checkout_time = str(cleared_time.hour) + ':' + str(
        '%02d' % cleared_time.minute)

    task_content = ' Intermittent Fasting - Cleared to eat (Check in: ' + checkin_time + ')'

    logger.info('Create Todoist LastMeal Task: ' + task_content + ' due at: ' +
                checkout_time)

    api = TodoistAPI(token=get_token(), cache="/tmp/todoist")
    logger.info("Trying to connect to Todoist API with: %s", get_token())
    if not api.sync():
        logger.warning('Todoist: API Sync failed')
        exit()
    api.items.add(task_content,
                  project_id='1509802153',
                  date_string=checkout_time,
                  labels=[2154004914],
                  priority=3)
    if api.commit():
        logger.info("Todoist LastMeal Task has been created")
Exemple #20
0
    def test_CreateTask(self):
        # read api token values
        apitoken = config.get('todoistinfo', 'apitoken')

        # read task name
        taskname = config.get('todoistinfo', 'taskname')

        # read created project ID
        projectid = config.get('todoistinfo', 'projectid')
        '''
        Create task by using API commands
        '''
        api = TodoistAPI(apitoken)
        api.sync()

        create_task = api.items.add(taskname, projectid)
        response = api.commit()

        # Verify if the task has been created successfully
        assert create_task[
            'content'] == taskname, "Task created unsuccessfully."
        assert taskname in [i['content'] for i in api.state['items']]
        assert api.items.get_by_id(create_task['id']) == create_task

        # update the created task ID to ini file
        config.set("todoistinfo", "taskid", str(create_task['id']))
        config.write(open('../test_info.ini', 'w'))
Exemple #21
0
def main():
    API_TOKEN = get_token()
    if not API_TOKEN:
        logging.warn('Please set the API token in environment variable.')
        exit()
    api = TodoistAPI(API_TOKEN)
    api.sync()
    tasks = api.state['items']
    for task in tasks:
        if task['due_date_utc'] and is_habit(task['content']):
            if is_today(task['due_date_utc']):
                habit = is_habit(task['content'])
                streak = int(habit.group(1)) + 1
                update_streak(task, streak)
            elif is_due(task['due_date_utc']):
                update_streak(task, 0)
                task.update(date_string='ev day starting tod')
    api.commit()
Exemple #22
0
class Todoist(object):
    def __init__(self):
        self.api = TodoistAPI(get_token())
        self.api.sync()
        self.api.notes = NotesManager(self.api)
        habit_label_ids = [
            label['id'] for label in self.api.state['labels']
            if label['name'] == 'habit'
        ]
        assert (len(habit_label_ids) == 1)
        self.habit_label_id = habit_label_ids[0]
        self.habits = self.get_habits()
        self.get_datetime()

    def get_datetime(self):
        timezone = self.api.state['user']['tz_info']['timezone']
        tz_location = tz.gettz(timezone)
        now = datetime.now(tz=tz_location)
        self.weekstart = datetime.weekday(now) == self.api.state['user'][
            'start_day'] % 7  #Checks if yesterday was the week start day
        self.off_day = datetime.weekday(now) in [
            i % 7 for i in self.api.state['user']['days_off']
        ]  #Checks if yesterday was an off day
        self.today = now.strftime(TODOIST_DATE_FORMAT)

    def get_habits(self):
        habits = []
        for item in self.api.state['items']:
            if self.habit_label_id in item['labels']:
                habits.append(item)
        return habits

    def update_habit(self):
        for item in self.habits:
            notes = [
                note for note in self.api.state['notes']
                if note['item_id'] == item['id']
            ]
            task = Task(self.api, item, notes)
            if task.is_due(self.today):
                task.no_change(self.today, self.weekstart, self.off_day)
            else:
                task.increase(self.weekstart)
        self.api.commit()
Exemple #23
0
def color_code(key=tovakey):
    api = TodoistAPI(key)
    api.sync()
    payload = request.get_json()
    selected_project = payload["context"]["facts"]["selected_project"][
        "grammar_entry"]
    selected_color = (
        payload["context"]["facts"]["selected_color"]["value"]).split('_')[1]
    print("SELECTED_COLOR: ", selected_color)
    projects = extract_projects(api)
    project_found = False
    for project in projects:
        if project[0].lower() == selected_project.lower():
            project_found = True
            print("project found")
            target_project = api.projects.get_by_id(project[1])
            target_project.update(color=selected_color)
    api.commit()
    return action_success_response()
Exemple #24
0
def main():
    API_TOKEN = get_token()
    today = datetime.utcnow().replace(tzinfo=None)
    if not API_TOKEN:
        logging.warn('Please set the API token in environment variable.')
        exit()
    api = TodoistAPI(API_TOKEN)
    api.sync()
    tasks = api.state['items']
    for task in tasks:
        if task['due'] and is_habit(task['content']) and not task['in_history']:
            if is_today(task['due']['date']):
                habit = is_habit(task['content'])
                streak = int(habit.group(1)) + 1
                update_streak(task, streak)
            elif is_due(task['due']['date']):
                update_streak(task, 0)
                task.update(due={'string': 'ev day starting {}'.format(today_date())})
    api.commit()
Exemple #25
0
def complete_task(key=tovakey):
    api = TodoistAPI(key)
    api.sync()
    payload = request.get_json()
    selected_project = payload["context"]["facts"]["selected_project"][
        "grammar_entry"]
    selected_task = payload["context"]["facts"]["selected_task"][
        "grammar_entry"]
    projects = extract_projects(api)
    for project in projects:
        if project[0].lower() == selected_project.lower():
            print("project found")
            items = api.projects.get_data(project[1])
            for value in items['items']:
                if value['content'] == selected_task:
                    print("task found")
                    task_id = value['id']
                    item = api.items.get_by_id(task_id)
                    item.complete()
                    api.commit()
    return action_success_response()
Exemple #26
0
def main():
    API_TOKEN = get_token()
    if not API_TOKEN:
        logging.warning('Please set the API token in environment variable.')
        exit()
    api = TodoistAPI(API_TOKEN)
    api.sync()
    tasks = api.state['items']
    for task in tasks:
        habit = is_habit(task['content'])
        if task['due'] and habit and not task['in_history']:
            due_date = task['due']['date']
            if is_today(due_date):
                streak = int(habit.group(1)) + 1
                update_streak(task, streak)
            elif is_due(due_date):
                streak = int(habit.group(1)) - 1
                streak = max(0, streak)
                update_streak(task, streak)
                task.update(due={'string': 'ev day starting {}'.format(today_date())})
    api.commit()
Exemple #27
0
def addNewIssueToTodoist(repoFullName, username, issueTitle):
    api = TodoistAPI(TODOIST_API_TOKEN)
    api.sync()
    todoProject = api.projects.get_by_id(find_project_by_name(repoFullName))
    print(todoProject)
    if (todoProject != None):
        if username == 'LSWarss':
            if api.items.get_by_id(find_task_by_name(issueTitle) != None):
                task = api.items.add(issueTitle, project_id=todoProject['id'])
                print(task)
                api.commit()
        else:
            pass
    else:
        todoProject = api.projects.add(repoFullName)
        if username == 'LSWarss':
            if api.items.get_by_id(find_task_by_name(issueTitle) != None):
                task = api.items.add(issueTitle, project_id=todoProject['id'])
                api.commit()
        else:
            pass
Exemple #28
0
class Todoist(object):
    def __init__(self):
        self.api = TodoistAPI(get_token())
        self.api.sync()

    @property
    def today(self):
        timezone = self.api.state['user']['tz_info']['timezone']
        tz_location = tz.gettz(timezone)
        now = datetime.now(tz=tz_location)
        return now.strftime(TODOIST_DATE_FORMAT)

    def update_streak(self):
        items = self.api.state['items']
        for item in items:
            task = Task(item)
            if task.is_habit():
                if task.is_due(self.today):
                    task.decrease(self.today)
                else:
                    task.increase()
        self.api.commit()
def lambda_handler(event, context):
    #Begin
    print(">>>BEGIN<<<")

    p = os.environ['todoistkey']
    api = TodoistAPI(p)
    api.sync()

    for project in event['projects']:
        print(">ID:" + str(project['id']))
        print(">Sortby:" + project['sortby'])
        result = getTasksInProject(project['id'], api.state['items'])
        print("===Item count===")
        print(len(result))
        print("==sort items==")
        sortedResult = sortTasks(result, project['sortby'])
        thisOrder = 0
        for item in sortedResult:
            api.items.reorder([{'id': item['id'], 'child_order': thisOrder}])
            thisOrder += 1
        api.commit()
    print(">>>END<<<")
    return {"ordered": 1}
Exemple #30
0
def handle_payload(request):
    if request.method == 'POST':
        received_json_data = json.loads(request.body)

        if 'events' in received_json_data.keys():
            events = received_json_data["events"]

            for event in events:
                id = event["resource"]
                type = event["type"]
                url = None
                if type == "task":
                    url = "https://app.asana.com/api/1.0/tasks/" + str(id)

                if not url == None:
                    data = requests.get(
                        url=url,
                        headers={
                            "Authorization":
                            "Bearer 0/92f79995f7c1b4b0f751b9a07c8e52c2"
                        })

                    data1 = json.loads(data)
                    if data1['data']['assignee']['name'] == 'Yukta Anand':
                        task_name = data1['data']['name']
                        api = TodoistAPI(
                            '27113e1797906a73a11a7358805ac473499c414e')
                        api.sync()
                        project_name = data1['data']['memberships']['project'][
                            'name']
                        project1 = api.projects.add(project_name)
                        api.items.add(task_name, project1['id'])
                        api.commit()
        else:
            headers = request.headers
            x_hook = headers['X-Hook-Secret']
            return JsonResponse({"X-Hook-Secret": x_hook})
Exemple #31
0
def main():
    """Main process function."""
    parser = argparse.ArgumentParser()
    parser.add_argument('-a', '--api_key', help='Todoist API Key')
    parser.add_argument('-l', '--label', help='The next action label to use', default='next_action')
    parser.add_argument('-d', '--delay', help='Specify the delay in seconds between syncs', default=5, type=int)
    parser.add_argument('--debug', help='Enable debugging', action='store_true')
    parser.add_argument('--inbox', help='The method the Inbox project should be processed',
                        default='parallel', choices=['parallel', 'serial', 'none'])
    parser.add_argument('--parallel_suffix', default='.')
    parser.add_argument('--serial_suffix', default='_')
    parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days',
                        default=7, type=int)
    parser.add_argument('--hide_scheduled', help='', action='store_true')  # TODO: help
    parser.add_argument('--remove_label', help='Remove next action label from unmarked projects', action='store_true')
    parser.add_argument('--onetime', help='Update Todoist once and exit', action='store_true')
    parser.add_argument('--nocache', help='Disables caching data to disk for quicker syncing', action='store_true')
    args = parser.parse_args()

    # Set debug
    if args.debug:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO
    logging.basicConfig(level=log_level)

    # Check we have a API key
    if not args.api_key:
        logging.error('No API key set, exiting...')
        sys.exit(1)

    # Run the initial sync
    logging.debug('Connecting to the Todoist API')

    api_arguments = {'token': args.api_key}
    if args.nocache:
        logging.debug('Disabling local caching')
        api_arguments['cache'] = None

    api = TodoistAPI(**api_arguments)
    logging.debug('Syncing the current state from the API')
    api.sync()

    # Check the next action label exists
    labels = api.labels.all(lambda x: x['name'] == args.label)
    if len(labels) > 0:
        label_id = labels[0]['id']
        logging.debug('Label %s found as label id %d', args.label, label_id)
    else:
        logging.error("Label %s doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label)
        sys.exit(1)

    def get_project_type(project_object):
        """Identifies how a project should be handled."""
        name = project_object['name'].strip()
        if name == 'Inbox' and args.inbox != 'none':
            return args.inbox
        elif name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def get_item_type(item):
        """Identifies how a item with sub items should be handled."""
        name = item['content'].strip()
        if name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def add_label(item, label):
        if label not in item['labels']:
            logging.debug('Updating %s (%d) with label', item['content'], item['id'])
            labels = item['labels']
            labels.append(label)
            api.items.update(item['id'], labels=labels)

    def remove_label(item, label):
        if label in item['labels']:
            logging.debug('Updating %s (%d) without label', item['content'], item['id'])
            labels = item['labels']
            labels.remove(label)
            api.items.update(item['id'], labels=labels)

    # Main loop
    while True:
        try:
            api.sync()
        except Exception as e:
            logging.exception('Error trying to sync with Todoist API: %s' % str(e))
        else:
            for project in api.projects.all(lambda x: not x['is_deleted'] and not x['is_archived']):
                project_type = get_project_type(project)
                items = api.items.all(
                            lambda x: x['project_id'] == project['id']
                                      and not (x['checked'] or x['is_deleted'] or x['is_archived'])
                )
                if project_type:
                    logging.debug('Project %s being processed as %s', project['name'], project_type)

                    # Get all items for the project, sort by the item_order field.
                    items = sorted(
                        items,
                        key=lambda x: x['item_order']
                    )

                    for real_order, item in enumerate(filter(lambda x: x['indent'] == 1, items)):
                        item_type = get_item_type(item)

                        if item.data.get('due_date_utc'):
                            if args.hide_scheduled and not item_type:
                                remove_label(item, label_id)
                                continue

                            # If its too far in the future, remove the next_action tag and skip
                            if args.hide_future > 0:
                                due_date = datetime.strptime(item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000')
                                future_diff = (due_date - datetime.utcnow()).total_seconds()
                                if future_diff >= (args.hide_future * 86400):
                                    remove_label(item, label_id)
                                    continue

                        child_items = get_subitems(items, item)

                        def add_indent1_label():
                            if child_items:
                                remove_label(item, label_id)
                                add_label(child_items[0], label_id)
                                func = remove_label if item_type == 'serial' else add_label
                                for child_item in child_items[1:]:
                                    func(child_item, label_id)
                            else:
                                add_label(item, label_id)

                        def remove_indent1_label():
                            remove_label(item, label_id)
                            for child_item in child_items:
                                remove_label(child_item, label_id)

                        if project_type == 'serial':
                            if real_order == 0:
                                add_indent1_label()
                            else:
                                remove_indent1_label()
                        elif project_type == 'parallel':
                            add_indent1_label()

                elif args.remove_label:
                    for item in items:
                        remove_label(item, label_id)

            if len(api.queue):
                logging.debug('%d changes queued for sync... commiting to Todoist.', len(api.queue))
                api.commit()
            else:
                logging.debug('No changes queued, skipping sync.')

        # If onetime is set, exit after first execution.
        if args.onetime:
            break

        logging.debug('Sleeping for %d seconds', args.delay)
        time.sleep(args.delay)
Exemple #32
0
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument('-a', '--api_key', help='Todoist API Key')
    parser.add_argument('-l', '--label', help='The next action label to use', default='next_action')
    parser.add_argument('-d', '--delay', help='Specify the delay in seconds between syncs', default=5, type=int)
    parser.add_argument('--debug', help='Enable debugging', action='store_true')
    parser.add_argument('--inbox', help='The method the Inbox project should be processed',
                        default='parallel', choices=['parallel', 'serial'])
    parser.add_argument('--parallel_suffix', default='.')
    parser.add_argument('--serial_suffix', default='_')
    parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days',
                        default=7, type=int)
    parser.add_argument('--onetime', help='Update Todoist once and exit', action='store_true')
    args = parser.parse_args()

    # Set debug
    if args.debug:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO
    logging.basicConfig(level=log_level)

    # Check we have a API key
    if not args.api_key:
        logging.error('No API key set, exiting...')
        sys.exit(1)

    # Run the initial sync
    logging.debug('Connecting to the Todoist API')
    api = TodoistAPI(token=args.api_key)
    logging.debug('Syncing the current state from the API')
    api.sync(resource_types=['projects', 'labels', 'items'])

    # Check the next action label exists
    labels = api.labels.all(lambda x: x['name'] == args.label)
    if len(labels) > 0:
        label_id = labels[0]['id']
        logging.debug('Label %s found as label id %d', args.label, label_id)
    else:
        logging.error("Label %s doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label)
        sys.exit(1)

    def get_project_type(project_object):
        """Identifies how a project should be handled"""
        name = project_object['name'].strip()
        if project['name'] == 'Inbox':
            return args.inbox
        elif name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def get_item_type(item):
        """Identifies how a item with sub items should be handled"""
        name = item['content'].strip()
        if name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def add_label(item, label):
        if label not in item['labels']:
            labels = item['labels']
            logging.debug('Updating %s with label', item['content'])
            labels.append(label)
            api.items.update(item['id'], labels=labels)

    def remove_label(item, label):
        if label in item['labels']:
            labels = item['labels']
            logging.debug('Updating %s without label', item['content'])
            labels.remove(label)
            api.items.update(item['id'], labels=labels)

    # Main loop
    while True:
        try:
            api.sync(resource_types=['projects', 'labels', 'items'])
        except Exception as e:
            logging.exception('Error trying to sync with Todoist API: %s' % str(e))
        else:
            for project in api.projects.all():
                project_type = get_project_type(project)
                if project_type:
                    logging.debug('Project %s being processed as %s', project['name'], project_type)

                    items = sorted(api.items.all(lambda x: x['project_id'] == project['id']), key=lambda x: x['item_order'])

                    for item in items:

                        # If its too far in the future, remove the next_action tag and skip
                        if args.hide_future > 0 and 'due_date_utc' in item.data and item['due_date_utc'] is not None:
                            due_date = datetime.strptime(item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000')
                            future_diff = (due_date - datetime.utcnow()).total_seconds()
                            if future_diff >= (args.hide_future * 86400):
                                remove_label(item, label_id)
                                continue

                        item_type = get_item_type(item)
                        child_items = get_subitems(items, item)
                        if item_type:
                            logging.debug('Identified %s as %s type', item['content'], item_type)

                        if item_type or len(child_items) > 0:
                            # Process serial tagged items
                            if item_type == 'serial':
                                for idx, child_item in enumerate(child_items):
                                    if idx == 0:
                                        add_label(child_item, label_id)
                                    else:
                                        remove_label(child_item, label_id)
                            # Process parallel tagged items or untagged parents
                            else:
                                for child_item in child_items:
                                    add_label(child_item, label_id)

                            # Remove the label from the parent
                            remove_label(item, label_id)

                        # Process items as per project type on indent 1 if untagged
                        else:
                            if item['indent'] == 1:
                                if project_type == 'serial':
                                    if item['item_order'] == 1:
                                        add_label(item, label_id)
                                    else:
                                        remove_label(item, label_id)
                                elif project_type == 'parallel':
                                    add_label(item, label_id)

            logging.debug('%d changes queued for sync... commiting if needed', len(api.queue))
            if len(api.queue):
                api.commit()

        if args.onetime:
            break
        logging.debug('Sleeping for %d seconds', args.delay)
        time.sleep(args.delay)
Exemple #33
0
class NextAction(object):
    def __init__(self):
        self.args = None
        self.api = None
        self.next_label_id = None
        self.waitfor_label_id = None
        self.active_label_id = None

    def main(self):
        self.setup()
        self.loop()

    def check_label(self, label):
        # Check if the label exists
        labels = self.api.labels.all(lambda x: x['name'] == label)
        if len(labels) > 0:
            label_id = labels[0]['id']
            logging.debug('Label %s found as label id %d', label, label_id)
            return label_id
        else:
            logging.error(
                "Label %s doesn't exist.", label)
            sys.exit(1)

    def setup(self):
        self.parse_args()

        # Run the initial sync
        logging.debug('Connecting to the Todoist API')
        self.api = TodoistAPI(token=self.args.api_key)
        logging.debug('Syncing the current state from the API')
        self.api.sync()
        self.next_label_id = self.check_label(self.args.label)
        self.active_label_id = self.check_label(self.args.active)
        self.waitfor_label_id = self.check_label(self.args.waitfor)

    def loop(self):
        """
        Main loop
        """
        while True:
            try:
                self.api.sync()
            except Exception as exc:
                logging.exception('Error trying to sync with Todoist API: %s',
                                  exc)
            else:
                self.process(self.api.projects.all())

                logging.debug(
                    '%d changes queued for sync... committing if needed',
                    len(self.api.queue))
                if len(self.api.queue):
                    self.api.commit()

            if self.args.onetime:
                break
            logging.debug('Sleeping for %d seconds', self.args.delay)
            time.sleep(self.args.delay)

    def process(self, projects, parent_indent=0, parent_type=None):
        """
        Process all projects
        """
        current_type = parent_type
        while projects and parent_indent < projects[0]["indent"]:
            # dig deeper
            if projects[0]["indent"] > parent_indent + 1:
                self.process(projects, parent_indent + 1, current_type)
                continue

            project = projects.pop(0)
            current_type = self.get_project_type(project, parent_type)
            if not current_type:
                # project not marked - not touching
                continue

            logging.debug('Project %s being processed as %s',
                          project['name'], current_type)

            def item_filter(x):
                return x['project_id'] == project['id']

            all_items = self.api.items.all(item_filter)
            items = sorted(all_items, key=lambda x: x['item_order'])
            item_objs = []
            while items:
                item_objs.append(Item(items))
            self.process_items(item_objs, current_type)
            self.activate(item_objs)

    def process_items(self, items, parent_type, not_in_first=False):
        """
        Process all tasks in project
        """
        # get the first item for serial
        first = None
        if parent_type == "serial":
            not_checked = [item for item in items if not item.checked]
            if not_checked and not self.is_waitfor(not_checked[0]):
                first = not_checked[0]

        # process items
        parent_active = False
        for item in items:
            current_type = self.get_item_type(item)

            if current_type:
                logging.debug('Identified %s as %s type', item.content,
                              current_type)
            else:
                current_type = parent_type

            if item.children:
                active = self.process_items(item.children, current_type,
                                            not_in_first or
                                            first and item != first)
            else:
                active = False

            if self.check_future(item):
                continue

            active |= self.process_item(item, parent_type, first, not_in_first)
            item.active = active
            parent_active |= active
        return parent_active

    def process_item(self, item, type, first=None, not_in_first=False):
        """
        Process single item
        """
        # untag if checked
        if item.checked or not_in_first:
            return self.remove_label(item, self.next_label_id)
        # don't tag if parent with unchecked child
        elif [child for child in item.children if not child.checked]:
            return self.remove_label(item, self.next_label_id)
        # tag all parallel but not waitfors
        elif type == "parallel" and not self.is_waitfor(item):
            return self.add_label(item, self.next_label_id)
        # tag the first serial
        elif type == "serial" and item == first:
            return self.add_label(item, self.next_label_id)
        # untag otherwise
        else:
            return self.remove_label(item, self.next_label_id)

    def activate(self, items):
        """
        Mark indent 1 items as active if supposed to be
        """
        for item in items:
            if item.active:
                self.add_label(item, self.active_label_id)
            else:
                self.remove_label(item, self.active_label_id)

    def check_future(self, item):
        """
        If its too far in the future, remove the next_action tag and skip
        """
        if self.args.hide_future > 0 and item.due_date_utc:
            due_date = datetime.strptime(item.due_date_utc,
                                         '%a %d %b %Y %H:%M:%S +0000')
            future_diff = (due_date - datetime.utcnow()).total_seconds()
            if future_diff >= (self.args.hide_future * 86400):
                self.remove_label(item, self.next_label_id)
                return True

    def get_project_type(self, project_object, parent_type):
        """
        Identifies how a project should be handled
        """
        name = project_object['name'].strip()
        if name == 'Inbox':
            return self.args.inbox
        elif name[-1] == self.args.parallel_suffix:
            return 'parallel'
        elif name[-1] == self.args.serial_suffix:
            return 'serial'
        elif parent_type:
            return parent_type

    def get_item_type(self, item):
        """
        Identifies how a item with sub items should be handled
        """
        name = item.content.strip()
        if name[-1] == self.args.parallel_suffix:
            return 'parallel'
        elif name[-1] == self.args.serial_suffix:
            return 'serial'

    def add_label(self, item, label):
        if label not in item.labels:
            labels = item.labels
            logging.debug('Updating %s with label %s', item.content, label)
            labels.append(label)
            self.api.items.update(item.id, labels=labels)
        return True

    def remove_label(self, item, label):
        if label in item.labels:
            labels = item.labels
            logging.debug('Updating %s without label %s', item.content, label)
            labels.remove(label)
            self.api.items.update(item.id, labels=labels)
        return False

    def is_waitfor(self, item):
        return self.waitfor_label_id in item.labels

    @staticmethod
    def get_subitems(items, parent_item=None):
        """
        Search a flat item list for child items
        """
        result_items = []
        found = False
        if parent_item:
            required_indent = parent_item['indent'] + 1
        else:
            required_indent = 1
        for item in items:
            if parent_item:
                if not found and item['id'] != parent_item['id']:
                    continue
                else:
                    found = True
                if item['indent'] == parent_item['indent'] and item['id'] != \
                        parent_item['id']:
                    return result_items
                elif item['indent'] == required_indent and found:
                    result_items.append(item)
            elif item['indent'] == required_indent:
                result_items.append(item)
        return result_items

    def parse_args(self):
        """
        Parse command-line arguments
        """
        parser = argparse.ArgumentParser()
        parser.add_argument('-a', '--api_key', help='Todoist API Key')
        parser.add_argument('-l', '--label',
                            help='The next action label to use',
                            default='next_action')
        parser.add_argument('-c', '--active',
                            help='The active level1 parent label',
                            default='active')
        parser.add_argument('-w', '--waitfor',
                            help='The waitfor label',
                            default='waitfor')
        parser.add_argument('-d', '--delay',
                            help='Specify the delay in seconds between syncs',
                            default=5, type=int)
        parser.add_argument('--debug', help='Enable debugging',
                            action='store_true')
        parser.add_argument('--inbox',
                            help='The method the Inbox project should '
                                 'be processed',
                            default='parallel', choices=['parallel', 'serial'])
        parser.add_argument('--parallel_suffix', default='.')
        parser.add_argument('--serial_suffix', default='_')
        parser.add_argument('--hide_future',
                            help='Hide future dated next actions until the '
                                 'specified number of days',
                            default=7, type=int)
        parser.add_argument('--onetime', help='Update Todoist once and exit',
                            action='store_true')
        self.args = parser.parse_args()

        # Set debug
        if self.args.debug:
            log_level = logging.DEBUG
        else:
            log_level = logging.INFO
        logging.basicConfig(level=log_level)

        # Check we have a API key
        if not self.args.api_key:
            logging.error('No API key set, exiting...')
            sys.exit(1)