grocy-cli/grocy/cli.py

246 lines
7.7 KiB
Python

import click
from markdown import markdown
from jinja2 import Environment, FileSystemLoader
from grocy.conf import Configuration
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
from os import path
import logging
APP_NAME = 'grocy-cli'
SAMPLE_CONFIG_FILE = 'sample.config.yml'
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__)))
TEMPLATE_LOADER = Environment(loader=FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True)
@click.group()
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)
user_cfg_options = {}
if create_config_app_dir:
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)
else:
cfg.load()
logging.basicConfig(level=cfg.logger_level, filename=cfg.logger_file_location)
@main.command()
@click.pass_context
def stock(ctx):
logger = logging.getLogger('cli.stock')
if ctx.invoked_subcommand is None:
try:
stock = Stock()
table = Table(stocks=stock.products)
click.echo(table.stock)
except Exception as e:
logger.error(e)
raise e
@main.group(invoke_without_command=True)
@click.pass_context
@click.argument('product_id', required=False)
def product(ctx, product_id):
logger = logging.getLogger('cli.product')
try:
if product_id:
stock = Stock()
product = stock.get_product(product_id)
# Need to get quantity_unit
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('list')
#@click.argument('query', required=False)
#def view(query, product_id):
# logger = logging.getLogger('cli.product.view')
# try:
# if product_id:
# entity = Entity(name='product')
# product = entity.get(id=product_id)
# table = Table(product=product)
# click.echo(table.product)
# else:
# except Exception as e:
# logger.error(e)
# 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.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
#@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)