diff --git a/.gitignore b/.gitignore index 2839fc9..f29261b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ venv grocy_cli.egg-info/ +grocy/**/__pycache__/ +*.sqlite +*.pyc diff --git a/grocy/__init__.py b/grocy/__init__.py index c90afa9..f7fd106 100644 --- a/grocy/__init__.py +++ b/grocy/__init__.py @@ -1,5 +1,8 @@ import requests +import requests_cache import json + +requests_cache.install_cache('grocy', allowable_methods=('GET',), expire_after=180) class RestService(object): API_KEY_HEADER = 'GROCY-API-KEY' def __init__(self, api_url, json=False): diff --git a/grocy/__pycache__/__init__.cpython-37.pyc b/grocy/__pycache__/__init__.cpython-37.pyc deleted file mode 100644 index e096245..0000000 Binary files a/grocy/__pycache__/__init__.cpython-37.pyc and /dev/null differ diff --git a/grocy/__pycache__/cli.cpython-37.pyc b/grocy/__pycache__/cli.cpython-37.pyc deleted file mode 100644 index 34e2ce5..0000000 Binary files a/grocy/__pycache__/cli.cpython-37.pyc and /dev/null differ diff --git a/grocy/__pycache__/rest.cpython-37.pyc b/grocy/__pycache__/rest.cpython-37.pyc deleted file mode 100644 index 26c1ded..0000000 Binary files a/grocy/__pycache__/rest.cpython-37.pyc and /dev/null differ diff --git a/grocy/cli.py b/grocy/cli.py index 919128e..003c19b 100644 --- a/grocy/cli.py +++ b/grocy/cli.py @@ -1,6 +1,6 @@ import click from grocy import RestService -from grocy.commands import Stock +from grocy.commands import * from pkg_resources import iter_entry_points import yaml from sys import exit @@ -17,6 +17,12 @@ CONFIG_FILE = 'config.yml' CONFIG_DIR = click.get_app_dir(APP_NAME) PROJ_DIR = path.join(path.dirname(path.realpath(__file__))) +def __validate_token(cfg): + # Validate token + if hasattr(cfg, 'token') or cfg['token'] is None: + click.echo('No token was found. Please add your token to the config file', err=True) + logger.error('No token was found. Please add your token') + exit(1) def __create_config_file(): user_cfg_file = path.join(CONFIG_DIR, CONFIG_FILE) @@ -32,8 +38,21 @@ def __create_config_file(): @click.group() -def main(): - pass +@click.pass_context +def main(ctx): + cfg = get_config_file() + # Get logger + if 'logger' in cfg: + log_cfg = cfg['logger'] + else: + log_cfg = path.join(click.get_app_dir(APP_NAME), 'grocy.log') + log_level = 'DEBUG' if 'level' not in log_cfg else log_cfg['level'] + log_filename = 'log' if 'file_location' not in log_cfg else log_cfg['file_location'] + logging.basicConfig(level=log_level, filename=log_filename) + + __validate_token(cfg) + ctx.ensure_object(dict) + ctx.obj['cfg'] = cfg def get_config_file(): @@ -48,28 +67,33 @@ def get_config_file(): exit(0) fd = open(cfg_file) parse_cfg_file = yaml.safe_load(fd) + return parse_cfg_file @main.command() -def stock(): - cfg = get_config_file() - - # Get logger - if 'logger' in cfg: - log_cfg = cfg['logger'] - else: - log_cfg = path.join(click.get_app_dir(APP_NAME), 'grocy.log') - log_level = 'DEBUG' if 'level' not in log_cfg else log_cfg['level'] - log_filename = 'log' if 'file_location' not in log_cfg else log_cfg['file_location'] - logging.basicConfig(level=log_level, filename=log_filename) - - # Validate token - if hasattr(cfg, 'token') or cfg['token'] is None: - click.echo('No token was found. Please add your token to the config file', err=True) - logger.error('No token was found. Please add your token') - exit(1) +@click.pass_context +def stock(ctx): + cfg = ctx.obj['cfg'] stock = Stock(**cfg) stock_entries = stock.get_entries() click.echo(stock_entries) + +@main.command() +@click.pass_context +def shopping(ctx): + cfg = ctx.obj['cfg'] + + shopping = Shopping(**cfg) + shopping_list = shopping.get_list() + click.echo(shopping_list) + +@main.command() +@click.pass_context +def recipe(ctx): + cfg = ctx.obj['cfg'] + + receipe = Recipe(**cfg) + recipes = receipe.get_list() + click.echo(recipes) diff --git a/grocy/commands/__init__.py b/grocy/commands/__init__.py index 20d7d07..87e99da 100644 --- a/grocy/commands/__init__.py +++ b/grocy/commands/__init__.py @@ -1 +1,3 @@ from grocy.commands.stock import Stock +from grocy.commands.recipe import Recipe +from grocy.commands.shopping import Shopping diff --git a/grocy/commands/__pycache__/__init__.cpython-37.pyc b/grocy/commands/__pycache__/__init__.cpython-37.pyc deleted file mode 100644 index 4263d1c..0000000 Binary files a/grocy/commands/__pycache__/__init__.cpython-37.pyc and /dev/null differ diff --git a/grocy/commands/__pycache__/stock.cpython-37.pyc b/grocy/commands/__pycache__/stock.cpython-37.pyc deleted file mode 100644 index 794d80c..0000000 Binary files a/grocy/commands/__pycache__/stock.cpython-37.pyc and /dev/null differ diff --git a/grocy/commands/recipe.py b/grocy/commands/recipe.py new file mode 100644 index 0000000..3bc1698 --- /dev/null +++ b/grocy/commands/recipe.py @@ -0,0 +1,52 @@ +from grocy import RestService +from tabulate import tabulate +from os import path + +class Recipe(object): + GET_RECIPES = '/get-objects/recipes' + GET_PRODUCT_BY_ID = '/get-object/products/{0}' + def __init__(self, **entries): + self.__dict__.update(entries) + self._init_rest_service() + #self._set_default_table_formats() + #if not hasattr('tablefmt', self): + # self.tablefmt = None + #if not hasattr('colalign', self): + # self.colalign = None + + + + def _set_default_table_formats(self): + if not hasattr('formats', self): + self.tablefmt = None + self.colalign = None + elif not hasattr('table', self.formats): + self.tableformat = None + elif not hasattr('col', self.formats): + self.colalign = None + + + + def _init_rest_service(self): + if self.api.startswith == '/': + self.api = self.api[1:] + if self.api.endswith == '/': + self.api = self.api[1:-1] + self.rest_service = RestService(self.api, json=True) + self.rest_service.addHeader('Content-Type', 'application/json') + self.rest_service.addToken(self.token) + + + def get_list(self): + try: + recipes = self.rest_service.get(Recipe.GET_RECIPES) + table_headers = ['#', 'Name'] + table_entries = [] + for recipe in recipes: + table_entry = [recipe.get('id'), recipe.get('name')] + table_entries.append(table_entry) + + except Exception as e: + raise e + # Generate stock overview table + return tabulate(table_entries, headers=table_headers) diff --git a/grocy/commands/shopping.py b/grocy/commands/shopping.py new file mode 100644 index 0000000..515aafa --- /dev/null +++ b/grocy/commands/shopping.py @@ -0,0 +1,72 @@ +from grocy import RestService +import json +from tabulate import tabulate +from os import path + +class Shopping(object): + GET_SHOPPING_LIST = '/get-objects/shopping_list' + GET_PRODUCT_BY_ID = '/get-object/products/{0}' + GET_QUANTITY_UNIIT_BY_ID = '/get-object/quantity_units/{0}' + GET_PRODUCT_GROUP_ID_BY_ID ='/get-object/product_groups/{0}' + + def __init__(self, **entries): + self.__dict__.update(entries) + self._init_rest_service() + # self.tablefmt = None + #if not hasattr('colalign', self): + # self.colalign = None + + + + def _set_default_table_formats(self): + if not hasattr('formats', self): + self.tablefmt = None + self.colalign = None + elif not hasattr('table', self.formats): + self.tableformat = None + elif not hasattr('col', self.formats): + self.colalign = None + + + + def _init_rest_service(self): + if self.api.startswith == '/': + self.api = self.api[1:] + if self.api.endswith == '/': + self.api = self.api[1:-1] + self.rest_service = RestService(self.api, json=True) + self.rest_service.addHeader('Content-Type', 'application/json') + self.rest_service.addToken(self.token) + + + def get_list(self): + try: + get_shopping_list = self.rest_service.get(Shopping.GET_SHOPPING_LIST) + table_headers = ['Group', 'Product', 'Amount'] + + # Get product names and location from ids and replace + product_ids = [entry['product_id'] for entry in get_shopping_list] + products = [] + location_ids = [] + table_entries = [] + for index in range(len(product_ids)): + product_id = product_ids[index] + path = Shopping.GET_PRODUCT_BY_ID.format(product_id) + product = self.rest_service.get(path) + + path = Shopping.GET_QUANTITY_UNIIT_BY_ID.format(product['qu_id_purchase']) + quantity_unit = self.rest_service.get(path) + min_amount = '{} {}'.format(product['min_stock_amount'], quantity_unit['name']) + if product['product_group_id'] == '': + product_group_name = 'Uncategorized' + else: + path = Shopping.GET_PRODUCT_GROUP_ID_BY_ID.format(product['product_group_id']) + product_group = self.rest_service.get(path) + product_group_name = product_group['name'] + current_shopping_item = [product_group_name, product['name'], min_amount] + table_entries.append(current_shopping_item) + except Exception as e: + raise e + + # Generate stock overview table + return tabulate(table_entries, headers=table_headers)