TandoorRecipes/cookbook/views/data.py
2021-04-16 09:02:04 -05:00

217 lines
7.6 KiB
Python

import json
import uuid
from datetime import datetime
from io import BytesIO
import requests
from django.contrib import messages
from django.core.files import File
from django.db.transaction import atomic
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils.translation import gettext as _
from django.utils.translation import ngettext
from django_tables2 import RequestConfig
from PIL import Image, UnidentifiedImageError
from cookbook.forms import BatchEditForm, SyncForm
from cookbook.helper.permission_helper import group_required, has_group_permission
from cookbook.helper.recipe_url_import import parse_cooktime
from cookbook.models import (Comment, Food, Ingredient, Keyword, Recipe,
RecipeImport, Step, Sync, Unit)
from cookbook.tables import SyncTable
@group_required('user')
def sync(request):
if request.method == "POST":
if not has_group_permission(request.user, ['admin']):
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
return HttpResponseRedirect(reverse('data_sync'))
form = SyncForm(request.POST, space=request.space)
if form.is_valid():
new_path = Sync()
new_path.path = form.cleaned_data['path']
new_path.storage = form.cleaned_data['storage']
new_path.last_checked = datetime.now()
new_path.space = request.space
new_path.save()
return redirect('data_sync')
else:
form = SyncForm(space=request.space)
monitored_paths = SyncTable(Sync.objects.filter(space=request.space).all())
RequestConfig(request, paginate={'per_page': 25}).configure(monitored_paths)
return render(request, 'batch/monitor.html', {'form': form, 'monitored_paths': monitored_paths})
@group_required('user')
def sync_wait(request):
return render(request, 'batch/waiting.html')
@group_required('user')
def batch_import(request):
imports = RecipeImport.objects.filter(space=request.space).all()
for new_recipe in imports:
recipe = Recipe(
name=new_recipe.name,
file_path=new_recipe.file_path,
storage=new_recipe.storage,
file_uid=new_recipe.file_uid,
created_by=request.user,
space=request.space
)
recipe.save()
new_recipe.delete()
return redirect('list_recipe_import')
@group_required('user')
def batch_edit(request):
if request.method == "POST":
form = BatchEditForm(request.POST, space=request.space)
if form.is_valid():
word = form.cleaned_data['search']
keywords = form.cleaned_data['keywords']
recipes = Recipe.objects.filter(name__icontains=word, space=request.space)
count = 0
for recipe in recipes:
edit = False
if keywords.__sizeof__() > 0:
recipe.keywords.add(*list(keywords))
edit = True
if edit:
count = count + 1
recipe.save()
msg = ngettext(
'Batch edit done. %(count)d recipe was updated.',
'Batch edit done. %(count)d Recipes where updated.',
count) % {'count': count, }
messages.add_message(request, messages.SUCCESS, msg)
return redirect('data_batch_edit')
else:
form = BatchEditForm(space=request.space)
return render(request, 'batch/edit.html', {'form': form})
@group_required('user')
@atomic
def import_url(request):
if request.method == 'POST':
data = json.loads(request.body)
data['cookTime'] = parse_cooktime(data.get('cookTime', ''))
data['prepTime'] = parse_cooktime(data.get('prepTime', ''))
recipe = Recipe.objects.create(
name=data['name'],
description=data['description'],
waiting_time=data['cookTime'],
working_time=data['prepTime'],
servings=data['servings'],
internal=True,
created_by=request.user,
space=request.space,
)
step = Step.objects.create(
instruction=data['recipeInstructions'],
)
recipe.steps.add(step)
for kw in data['keywords']:
if k := Keyword.objects.filter(name=kw['text'], space=request.space).first():
recipe.keywords.add(k)
elif data['all_keywords']:
k = Keyword.objects.create(name=kw['text'], space=request.space)
recipe.keywords.add(k)
for ing in data['recipeIngredient']:
ingredient = Ingredient()
if ing['ingredient']['text'] != '':
ingredient.food, f_created = Food.objects.get_or_create(
name=ing['ingredient']['text'], space=request.space
)
if ing['unit'] and ing['unit']['text'] != '':
ingredient.unit, u_created = Unit.objects.get_or_create(
name=ing['unit']['text'], space=request.space
)
# TODO properly handle no_amount recipes
if isinstance(ing['amount'], str):
try:
ingredient.amount = float(ing['amount'].replace(',', '.'))
except ValueError:
ingredient.no_amount = True
pass
elif isinstance(ing['amount'], float) \
or isinstance(ing['amount'], int):
ingredient.amount = ing['amount']
ingredient.note = ing['note'] if 'note' in ing else ''
ingredient.save()
step.ingredients.add(ingredient)
print(ingredient)
if 'image' in data and data['image'] != '':
try:
response = requests.get(data['image'])
img = Image.open(BytesIO(response.content))
# todo move image processing to dedicated function
basewidth = 720
wpercent = (basewidth / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
img = img.resize((basewidth, hsize), Image.ANTIALIAS)
im_io = BytesIO()
img.save(im_io, 'PNG', quality=70)
recipe.image = File(
im_io, name=f'{uuid.uuid4()}_{recipe.pk}.png'
)
recipe.save()
except UnidentifiedImageError:
pass
return HttpResponse(reverse('view_recipe', args=[recipe.pk]))
elif 'id' in request.GET:
context = {'bookmarklet': request.GET.get('id')}
else:
context = {}
return render(request, 'url_import.html', context)
class Object(object):
pass
@group_required('user')
def statistics(request):
counts = Object()
counts.recipes = Recipe.objects.filter(space=request.space).count()
counts.keywords = Keyword.objects.filter(space=request.space).count()
counts.recipe_import = RecipeImport.objects.filter(space=request.space).count()
counts.units = Unit.objects.filter(space=request.space).count()
counts.ingredients = Food.objects.filter(space=request.space).count()
counts.comments = Comment.objects.filter(recipe__space=request.space).count()
counts.recipes_internal = Recipe.objects.filter(internal=True, space=request.space).count()
counts.recipes_external = counts.recipes - counts.recipes_internal
counts.recipes_no_keyword = Recipe.objects.filter(keywords=None, space=request.space).count()
return render(request, 'stats.html', {'counts': counts})