diff --git a/apps/__init__.py b/apps/__init__.py index 65e519c..f70615e 100644 --- a/apps/__init__.py +++ b/apps/__init__.py @@ -1,13 +1,84 @@ +import requests class TaskService(object): def __init__(self, config): self.config = config - def add(): + def findAll(): raise NotImplementedError() def modify(): raise NotImplementedError() +class RestService(object): + def __init__(self, api_url, json): + self.api_url = api_url + self.headers = {} + self.json + + def get(self, path): + api_url = self.api_url + + if api_url.endswith('/'): + url = '{0}{1}'.format(api_url, path) + else + url = '{0}/{1}'.format(api_url, path) + + + r = requests.get(url, headers=self.headers) + + if self.json: + + + return r.json() + + return r.content + + def delete(self, id): + api_url = self.api_url + + if api_url.endswith('/'): + url = '{0}{1}'.format(api_url, path) + else + url = '{0}/{1}'.format(api_url, path) + + + r = requests.get(url, headers=self.headers) + + if self.json: + + + return r.json() + + return r.content + + def post(self, data): + api_url = self.api_url + + if api_url.endswith('/'): + url = '{0}{1}'.format(api_url, path) + else + url = '{0}/{1}'.format(api_url, path) + + + r = requests.post(url, data, headers=self.headers) + + if self.json: + + + return r.json() + + return r.content + + + def addHeader(self, type, value): + self.header[type] = value + + + + + + + diff --git a/apps/grocy.py b/apps/grocy.py index 1fdca8e..705c6a2 100644 --- a/apps/grocy.py +++ b/apps/grocy.py @@ -1,14 +1,116 @@ from twservices.apps import TaskService +from datetime import datetime +from twservices.apps import RestService +GROCY_API_KEY_HEADER = 'GROCY_API_KEY' + +# Endpoints +GROCY_FIND_ALL_TASKS_ENDPOINT = '/get-objects/tasks' +GROCY_DELTE_TASK_ENDPOINT = '/delete-object/tasks/{0}' +GROCY_ADD_TASK_ENDPOINT = '/add-object/tasks' class Grocy(TaskService): def __init__(self, config): - self.api_token = config.api_token - self.logger = config.logger - + if config['api'] == None: + raise Exception('api url for Grocy is not defined') + # TODO: check if api is a url + self.api = config['api'] + + if config['token'] == None: + raise Exception('token for Grocy is not defined') + self.token = config['token'] + self.rest_service = self.__initRestService() + + def __convertToGrocyTask(self, task): + grocy_task = {} + grocy_task['id'] = int(task['id']) + + if task['description']: + grocy_task['name'] = str(task['description']) + + if task['annotations'] + grocy_task['description'] = '' + for note in task['annotations']: + grocy_task['description'] += '{}\n'.format(note) + + if task['entry'] and type(task['entry']) is datettime: + grocy_task['row_created_timestamp'] = task['entry'].format('%Y-%m-%d') + + if task['due'] and type(task['due']) is datetime: + grocy_task['due_date'] = task['due'].format('%Y-%m-%d') + + if task['done']: + grocy_task['done'] = task['done'] + + return grocy_task + def __initRestService(self): + if self.api.startswith == '/': + api_url = self.api_url[1:] + if self.api.endswith == '/': + api_url = + pruned_api_url = self.api + rest_service = RestService(self.api, json=True) + rest_service.addHeader('Authorization', self.token) + return rest_service + + def findAll(self): + # Get all tasks as json + try: + response = self.rest_service.get(GROCY_FIND_ALL_TASKS_ENDPOINT) + except Exception as e: + print(str(e)) + raise e + return response + + def delete(self, id): + if not id: + raise Exception('id is not defined') + # Delete a task + try: + response = self.rest_service.get(GROCY_DELTE_TASK_ENDPOINT, id) + except Exception as e: + print(str(e)) + raise e + return response + + def add(self, task): + responses = [] + if not task: + raise Exception('task is not defined') + if not type(task) is list: + tasks = [task] + else: + tasks = task + + try: + for next_task in tasks: + self.__convertToGrocyTask(next_task) + response = self.rest_service.post(GROCY_ADD_TASK_ENDPOINT, task) + responses.append(response) + except Exception as e: + print(str(e)) + raise e + return responses + def modify(self, task); + response = [] + if not task: + raise Exception('task is not defined') + if not type(task) is list: + tasks = [task] + else: + tasks = task + try: + for next_task in tasks: + self.__convertToGrocyTask(next_task) + response = self.rest_service.patch(GROCY_MODIFY_TASK_ENDPOINT, task['id'], task) + responses.append(response) + except Exception as e: + print(str(e)) + raise e + return responses diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..5f13188 --- /dev/null +++ b/cli.py @@ -0,0 +1,36 @@ +import click +from os import path + +APP_NAME = 'twservices' + +def __create_config_file(): + +@click.command() +@click.group() +def main(): + pass + +def get_config_file() + no_config_msg = 'A config file was not found ' + + 'and will be created under {0}. Is that Ok?'.format(click.get_app_dir(APP_NAME)) + cfg_file = path.join(click.get_app_dir(APP_NAME), 'config.yml') + if not path.exists(cfg_file): + create_config_app_dir = click.confirm(no_config_msg) + if create_config_app_dir: + + + + +@main.command() +def sync(): + + + + + + + + + + + diff --git a/sample.config.yml b/sample.config.yml new file mode 100644 index 0000000..020affd --- /dev/null +++ b/sample.config.yml @@ -0,0 +1,6 @@ +logger: + level: debug +grocy: + api: 'https://aerex.me/grocy/api' + token: 'McaeCf5FrT9Sqr96tPcZg9l4uUCexR1fGVGIfDR6qNQxsWECpv' + diff --git a/setup.py b/setup.py index dd18aeb..63ac174 100644 --- a/setup.py +++ b/setup.py @@ -10,18 +10,23 @@ def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup( - name = "taskwarrior-grocy", + name = "taskwarrior-services", version = "0.0.1", - author = "Aer=ex", + author = "Aerex", author_email = "aerex@aerex.me", - description = ("A plugin to create, delete, and modify tasks from and to grocy"), + description = ("A plugin to create, delete, and modify tasks across various services "), keywords = "taskwarrior, grocy", url = "http://packages.python.org/an_example_pypi_project", - packages=['requests', 'taskw', 'pytz'], + packages=['requests', 'pyyaml', 'taskw', 'pytz', 'click'], + install_requires=['Click'], long_description=read('README'), classifiers=[ "Development Status :: 3 - Alpha", "Topic :: Utilities", "License :: OSI Approved :: BSD License", ], + entry_points=" + [console_scripts] + twservices = cli:main + )