grocy-cli/grocy/cli.py

314 lines
10 KiB
Python
Raw Normal View History

import click
2019-04-28 16:12:05 -05:00
from markdown import markdown
2019-04-01 00:16:32 -05:00
from jinja2 import Environment, FileSystemLoader
2019-06-16 23:54:10 -05:00
from grocy.conf import Configuration
from grocy.util import Util
2019-06-16 23:54:10 -05:00
from grocy.recipe import Recipe
from grocy.table import Table
from grocy.entity import Entity
from grocy.stock import Stock
import yaml
from sys import exit
2019-06-16 23:54:10 -05:00
from os import path
import logging
APP_NAME = 'grocy-cli'
SAMPLE_CONFIG_FILE = 'sample.config.yml'
2019-04-01 00:16:32 -05:00
TMP_DIR = '/tmp/grocy'
CONFIG_FILE = 'config.yml'
CONFIG_DIR = click.get_app_dir(APP_NAME)
PROJ_DIR = path.join(path.dirname(path.realpath(__file__)))
2019-06-16 23:54:10 -05:00
TEMPLATE_LOADER = Environment(loader=FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True)
class GrocyGroup(click.Group):
def parse_args(self, ctx, args):
is_subcommand = True if args[0] in self.commands else False
if is_subcommand:
ctx.forward(self.commands[args[0]], args[1:])
super(GrocyGroup, self).parse_args(ctx, args)
@click.group()
2019-06-16 23:54:10 -05:00
def main():
cfg = Configuration()
if not cfg.exists:
no_config_msg = 'A config file was not found. A sample configuration file'
no_config_msg += ' will be created under {}. Is that Ok?'.format(cfg.CONFIG_DIR)
create_config_app_dir = click.confirm(no_config_msg)
2019-06-16 23:54:10 -05:00
user_cfg_options = {}
if create_config_app_dir:
2019-06-16 23:54:10 -05:00
user_cfg_options['logger_level'] = click.prompt('Enter logger level',
default='DEBUG')
user_cfg_options['logger_file_location'] = click.prompt('Enter location for logger',
default=path.expanduser('~/.config/grocy/log'))
user_cfg_options['api'] = click.prompt('Enter the grocy api url',
default='https://demo-en.grocy.info/api')
user_cfg_options['token'] = click.prompt('Enter the grocy token ',
default='')
user_cfg_options['col_format'] = click.prompt('Enter the col position for rendering tables',
default='col')
user_cfg_options['table_format'] = click.prompt('Enter the table format',
default='simple')
cfg.create(user_cfg_options)
else:
exit(0)
2019-06-16 23:54:10 -05:00
else:
cfg.load()
2019-03-09 19:02:42 -06:00
2019-06-16 23:54:10 -05:00
logging.basicConfig(level=cfg.logger_level, filename=cfg.logger_file_location)
@main.command()
2019-06-16 23:54:10 -05:00
@click.pass_context
2019-03-09 19:02:42 -06:00
def stock(ctx):
2019-06-16 23:54:10 -05:00
logger = logging.getLogger('cli.stock')
if ctx.invoked_subcommand is None:
try:
stock = Stock()
table = Table(stocks=stock.products)
2019-06-16 23:54:10 -05:00
click.echo(table.stock)
except Exception as e:
logger.error(e)
raise e
2019-03-09 19:02:42 -06:00
@main.group()
def product():
pass
@product.command()
@click.pass_context
@click.argument('product_id', required=False)
def view(ctx, product_id):
logger = logging.getLogger('cli.product')
try:
if product_id:
stock = Stock()
product = stock.get_product(product_id)
table = Table(entry=product)
click.echo(table.product)
else:
click.echo(ctx.get_help())
except Exception as e:
logger.error(e)
raise e
@product.command()
@click.option('--name', '-n', 'name')
@click.argument('product_id', required=False)
def edit(product_id, name):
logger = logging.getLogger('cli.product.edit')
2019-06-16 23:54:10 -05:00
try:
cfg = Configuration()
util = Util(cfg=cfg)
cfg.load()
loaded_template = cfg.templates('product_edit')
entity = Entity(name='products')
if product_id:
product = entity.get(id=product_id)
edited_product = click.edit(loaded_template.render(product))
edited_product.update()
elif name:
# Convert name args to a single string
string_name_arg = ' '.join(name) if type(name) == list else name
products = entity.find({'name': string_name_arg})
if products is None:
click.echo('Could not find product')
return
edited_products = click.edit(loaded_template.render(products=products), extension='.yml')
if edited_products is None:
return
parsed_edited_products = Util.load_yaml(edited_products)
schema = entity.schema
for index, edited_product in enumerate(parsed_edited_products):
edited_product['id'] = products[index]['id']
Util.verify_integrity(edited_product, schema)
entity.update(edited_product, id=products[index]['id'])
else:
raise click.BadParameter('Missing PRODUCT_ID or QUERY')
2019-06-16 23:54:10 -05:00
except Exception as e:
logger.error(e)
raise e
2019-03-09 19:50:42 -06:00
@product.command()
@click.option('--name', '-n', 'name')
def list(name):
logger = logging.getLogger('cli.product.list')
cfg = Configuration()
cfg.load()
product_entity = Entity(name='products')
qu_entity = Entity(name='quantity_units')
location_entity = Entity(name='locations')
product_group_entity = Entity(name='product_groups')
2019-04-01 00:16:32 -05:00
try:
if name:
# Convert name args to a single string
string_name_arg = ' '.join(name) if type(name) == list else name
products = product_entity.find({'name': string_name_arg})
else:
products = product_entity.get()
entries = {}
entries['quantity_units'] = qu_entity.get()
entries['product_groups'] = product_group_entity.get()
entries['locations'] = location_entity.get()
entries['products'] = products
table = Table(entries=entries)
click.echo(table.products)
2019-04-01 00:16:32 -05:00
except Exception as e:
logger.error(e)
2019-06-16 23:54:10 -05:00
raise e
#@main.command()
#def shopping():
# logger = logging.getLogger('cli.shopping')
# try:
# entity = Entity(name='shopping_list')
# shopping_list = entity.get()
# table = Table(shopping_list=shopping_list)
# click.echo(table.shopping_list)
# except Exception as e:
# logger.error(e)
# raise e
#
#
#@main.command()
#@main.group()
#def ingredient():
# pass
#
#
#@ingredient.command('add')
#@click.argument('query')
#@click.argument('recipe_id')
#@click.option('--amount', '-a', 'amount', default=1, type=int)
#@click.option('--group', '-g', type=str, default='')
#@click.option('--variable-amount', '--va', 'variable_amount', default=None, type=float)
#@click.option('--in-stock', '--is', 'in_stock', default=False)
#@click.option('--disable-fulfillment', '--df', 'disable_fulfillment', default=False)
#@click.option('--note', '-n', 'note', multiple=True, default='', type=str)
#@click.option('--no-edit', '--ne', 'no_edit', default=False)
#def add(query, recipe_id, amount, group, variable_amount, in_stock, disable_fulfillment, note, no_edit):
# logger = logging.getLogger('cli.ingredient.add')
#
# try:
# loaded_template = TEMPLATE_LOADER.get_template('ingredient_add.yml')
# new_ingredient = {}
#
# entity = Entity(name='recipes')
# recipe = entity.get(id=recipe_id)
#
# if not recipe:
# raise click.BadParameter(message='recipe {id} does not exist', param='recipe_id',
# param_hint='Use `grocy recipes ls` to get a list of recipes')
#
# entity = Entity(name='products')
# product = entity.findOne(query)
# new_ingredient['product_id'] = product['id']
#
# new_ingredient['amount'] = amount
# new_ingredient['group'] = group
# new_ingredient['variable_amount'] = variable_amount
# new_ingredient['only_check_single_unit_in_stock'] = "1" if in_stock else "0"
# new_ingredient['not_check_stock_fulfillment'] = "1" if disable_fulfillment else "0"
# new_ingredient['note'] = note
#
# if not no_edit:
# new_ingredient = click.edit(loaded_template.render(new_ingredient))
#
# parsed_new_ingredient = yaml.safe_load(new_ingredient)
# entity = Entity(name='recipes_pos')
# #entity.create(parsed_new_ingredient)
#
# except Exception as e:
# logger.error(e)
# raise e
#
#
#@main.group()
#@click.pass_context
#def recipe(ctx):
# pass
#
#
#@recipe.command('ls')
#def ls():
# logger = logging.getLogger('cli.recipe')
# try:
# entity = Entity(name='recipes')
# recipes = entity.get()
# recipe = Recipe()
# recipes_reqs = recipe.get_requirements()
# table = Table(recipes=recipes, recipes_reqs=recipes_reqs)
# click.echo(table.recipe)
# except Exception as e:
# logger.error(e)
# raise e
#
#
#@recipe.command('edit')
#@click.argument('recipe_id')
#def edit(recipe_id):
# logger = logging.getLogger('cli.recipe.edit')
# try:
# if recipe_id:
# entity = Entity(name='recipes')
# recipe = entity.get(id=recipe_id)
# loaded_template = TEMPLATE_LOADER.get_template('recipe_edit.yml')
# edited_recipe = click.edit(loaded_template.render(recipe))
# if edited_recipe is not None:
# parsed_edited_recipe = yaml.safe_load(edited_recipe)
# parsed_edited_recipe['description'] = markdown(parsed_edited_recipe['description'])
# recipe.__dict__.update(parsed_edited_recipe)
# recipe.update()
# except Exception as e:
# logger.error(e)
# logger.error('Could not edit recipe {}'.format(recipe_id))
# raise e
#
#
#@recipe.command('create')
#@click.pass_context
#def create(ctx):
# logger = logging.getLogger('cli.recipe.create')
#
# try:
# recipe = Entity(name='recipes')
# loaded_template = TEMPLATE_LOADER.get_template('recipe_add.yml')
# new_recipe = click.edit(loaded_template.render())
# if new_recipe is not None:
# parsed_new_recipe = yaml.safe_load(new_recipe)
# parsed_new_recipe['description'] = markdown(parsed_new_recipe['description'])
# recipe.__dict__.update(parsed_new_recipe)
# recipe.create()
# except Exception as e:
# logger.error(e)
# raise e
#
2019-05-05 16:06:33 -05:00
#@main.command()
#@click.pass_context
#def chore(ctx):
# cfg = ctx.obj['cfg']
#
# chore = Chore(**cfg)
# chores = chore.get_list()
# click.echo(chores)
#
#@main.command()
#@click.pass_context
#def task(ctx):
# cfg = ctx.obj['cfg']
#
# task = Task(**cfg)
# tasks = task.get_list()
# click.echo(tasks)
# click.echo(tasks)