#!/usr/bin/env python from pathlib import Path from pprint import pprint import json import requests class Wrike: ENDPOINT = 'https://www.wrike.com/api/v4' API_KEY = 'YOUR API KEY' @classmethod def _request_wrike(cls, path, params=None): path = Path(path) local_file_path = path.with_suffix('.json') if local_file_path.exists(): return json.loads(local_file_path.read_text()) else: url = f'{cls.ENDPOINT}/{path}' r = requests.get(url, headers={'Authorization': f'bearer {cls.API_KEY}'}, params=params) if r.status_code != requests.codes.ok: print(r.status_code) raise Exception(f'failed request {r.url} {r.status_code} {r.text}') pprint(r.url) pprint(r.text) path.parent.mkdir(parents=True, exist_ok=True) local_file_path.write_text(r.text) return json.loads(r.text) @classmethod def _in_fields(cls, field, fields): return fields and field in fields @classmethod def get_projects(cls, with_fields=None): projects = cls._request_wrike('folders')['data'] if cls._in_fields('tasks', with_fields): for project in projects: project['tasks'] = cls.get_task_tree(project['id'], with_fields) return list(filter(lambda v: not v['scope'].startswith('Rb'), projects)) @classmethod def get_project_tree(cls, with_fields=None): projects = cls.get_projects(with_fields) root_project = list(filter(lambda v: v['scope'] == 'WsRoot', projects)) if len(root_project) > 1: raise Exception('WsRoot is many') root_project = root_project[0] cls._merge_child_projects(root_project, projects) return root_project @classmethod def print_project_tree(cls, project, shift=0, with_fields=None): space = ' ' * shift print(f"{space}> {project['title']} : {project['id']}") if cls._in_fields('tasks', with_fields) and 'tasks' in project: cls.print_tasks(project['tasks'], shift + 1, with_fields) if 'childProjects' in project: for p in project['childProjects']: cls.print_project_tree(p, shift + 2, with_fields) @classmethod def _merge_child_projects(cls, project, projects): for child_id in project['childIds']: for p in projects: if p['id'] == child_id: if 'childProjects' not in project: project['childProjects'] = [] cls._merge_child_projects(p, projects) project['childProjects'].append(p) @classmethod def get_tasks(cls, project_id, with_fields=None): tasks = cls._request_wrike(f'folders/{project_id}/tasks', params={ 'subTasks': True, 'fields': json.dumps([ 'description', 'superTaskIds', 'subTaskIds', 'dependencyIds', ]), })['data'] if cls._in_fields('comments', with_fields): for task in tasks: task['comments'] = cls.get_comments(task['id']) return tasks @classmethod def get_task_tree(cls, project_id, with_fields=None): tasks = cls.get_tasks(project_id, with_fields) for task in tasks: cls._merge_sub_tasks(task, tasks) return tasks @classmethod def print_tasks(cls, tasks, shift=0, with_fields=None): space = ' ' * shift for task in tasks: print(f"{space}* {task['title']} : {task['id']}") if cls._in_fields('comments', with_fields) and 'comments' in task: cls.print_comments(task['comments'], shift + 1) if 'subTasks' in task: cls.print_tasks(task['subTasks'], shift + 2, with_fields) @classmethod def _merge_sub_tasks(cls, task, tasks): task['subTasks'] = [] for sub_task_id in task['subTaskIds']: for t in tasks: if t['id'] == sub_task_id: cls._merge_sub_tasks(t, tasks) task['subTasks'].append(t) tasks.remove(t) @classmethod def get_comments(cls, task_id): return cls._request_wrike(f'tasks/{task_id}/comments')['data'] @classmethod def print_comments(cls, comments, shift=0): space = ' ' * shift for comment in comments: print(f"{space}- {comment['text']} : {comment['id']}") def main(): root_project = Wrike.get_project_tree(with_fields=['tasks', 'comments']) Wrike.print_project_tree(root_project, with_fields=['tasks', 'comments']) with open('wrike.json', 'w') as f: json.dump(root_project, f) if __name__ == '__main__': try: main() except KeyboardInterrupt: pass