TandoorRecipes/cookbook/views/edit.py
2020-06-25 21:24:03 +02:00

358 lines
13 KiB
Python

import os
import uuid
from io import BytesIO
import simplejson
import simplejson as json
from PIL import Image
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.files import File
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.generic import UpdateView
from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, \
MealPlanForm, UnitMergeForm, IngredientMergeForm, RecipeBookForm, FoodForm
from cookbook.helper.permission_helper import group_required, GroupRequiredMixin
from cookbook.helper.permission_helper import OwnerRequiredMixin
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeIngredient, RecipeBook, \
MealPlan, Unit, Food
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.nextcloud import Nextcloud
@group_required('guest')
def switch_recipe(request, pk):
recipe = get_object_or_404(Recipe, pk=pk)
if recipe.internal:
return HttpResponseRedirect(reverse('edit_internal_recipe', args=[pk]))
else:
return HttpResponseRedirect(reverse('edit_external_recipe', args=[pk]))
@group_required('user')
def convert_recipe(request, pk):
recipe = get_object_or_404(Recipe, pk=pk)
if not recipe.internal:
recipe.internal = True
recipe.save()
return HttpResponseRedirect(reverse('edit_internal_recipe', args=[pk]))
@group_required('user')
def internal_recipe_update(request, pk):
recipe_instance = get_object_or_404(Recipe, pk=pk)
status = 200
if request.method == "POST":
form = InternalRecipeForm(request.POST, request.FILES)
form.instance = recipe_instance
if form.is_valid():
recipe = recipe_instance
recipe.name = form.cleaned_data['name']
recipe.instructions = form.cleaned_data['instructions']
recipe.working_time = form.cleaned_data['working_time']
recipe.waiting_time = form.cleaned_data['waiting_time']
if form.cleaned_data['image']:
recipe.image = form.cleaned_data['image']
img = Image.open(recipe.image)
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')
elif 'image' in form.changed_data and form.cleaned_data['image'] is False:
recipe.image = None
recipe.save()
try:
form_ingredients = json.loads(form.cleaned_data['ingredients'])
except simplejson.errors.JSONDecodeError:
form_ingredients = []
RecipeIngredient.objects.filter(recipe=recipe_instance).delete()
for i in form_ingredients:
recipe_ingredient = RecipeIngredient()
recipe_ingredient.recipe = recipe_instance
if 'note' in i:
recipe_ingredient.note = i['note']
if Food.objects.filter(name=i['ingredient__name']).exists():
recipe_ingredient.ingredient = Food.objects.get(name=i['ingredient__name'])
else:
ingredient = Food()
ingredient.name = i['ingredient__name']
ingredient.save()
recipe_ingredient.ingredient = ingredient
if isinstance(i['amount'], str):
try:
recipe_ingredient.amount = float(i['amount'].replace(',', '.'))
except ValueError:
form.add_error("ingredients", _('There was an error converting your ingredients amount to a number: ') + i['unit__name'])
else:
recipe_ingredient.amount = i['amount']
if Unit.objects.filter(name=i['unit__name']).exists():
recipe_ingredient.unit = Unit.objects.get(name=i['unit__name'])
else:
unit = Unit()
unit.name = i['unit__name']
unit.save()
recipe_ingredient.unit = unit
recipe_ingredient.save()
recipe.keywords.set(form.cleaned_data['keywords'])
messages.add_message(request, messages.SUCCESS, _('Recipe saved!'))
else:
messages.add_message(request, messages.ERROR, _('There was an error saving this recipe!'))
status = 403
else:
form = InternalRecipeForm(instance=recipe_instance)
ingredients = RecipeIngredient.objects.select_related('unit__name', 'ingredient__name').filter(recipe=recipe_instance).values('ingredient__name', 'unit__name', 'amount', 'note').order_by('id')
return render(request, 'forms/edit_internal_recipe.html',
{'form': form, 'ingredients': json.dumps(list(ingredients)),
'view_url': reverse('view_recipe', args=[pk])}, status=status)
class SyncUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['admin']
template_name = "generic/edit_template.html"
model = Sync
form_class = SyncForm
# TODO add msg box
def get_success_url(self):
return reverse('edit_sync', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(SyncUpdate, self).get_context_data(**kwargs)
context['title'] = _("Sync")
return context
class KeywordUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['user']
template_name = "generic/edit_template.html"
model = Keyword
form_class = KeywordForm
# TODO add msg box
def get_success_url(self):
return reverse('edit_keyword', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(KeywordUpdate, self).get_context_data(**kwargs)
context['title'] = _("Keyword")
return context
class FoodUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['user']
template_name = "generic/edit_template.html"
model = Food
form_class = FoodForm
# TODO add msg box
def get_success_url(self):
return reverse('edit_food', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(FoodUpdate, self).get_context_data(**kwargs)
context['title'] = _("Ingredient")
return context
@group_required('admin')
def edit_storage(request, pk):
instance = get_object_or_404(Storage, pk=pk)
if not (instance.created_by == request.user or request.user.is_superuser):
messages.add_message(request, messages.ERROR, _('You cannot edit this storage!'))
return HttpResponseRedirect(reverse('list_storage'))
if request.method == "POST":
form = StorageForm(request.POST, instance=instance)
if form.is_valid():
instance.name = form.cleaned_data['name']
instance.method = form.cleaned_data['method']
instance.username = form.cleaned_data['username']
instance.url = form.cleaned_data['url']
if form.cleaned_data['password'] != '__NO__CHANGE__':
instance.password = form.cleaned_data['password']
if form.cleaned_data['token'] != '__NO__CHANGE__':
instance.token = form.cleaned_data['token']
instance.save()
messages.add_message(request, messages.SUCCESS, _('Storage saved!'))
else:
messages.add_message(request, messages.ERROR, _('There was an error updating this storage backend!'))
else:
pseudo_instance = instance
pseudo_instance.password = '__NO__CHANGE__'
pseudo_instance.token = '__NO__CHANGE__'
form = StorageForm(instance=pseudo_instance)
return render(request, 'generic/edit_template.html', {'form': form, 'title': _('Storage')})
class CommentUpdate(OwnerRequiredMixin, UpdateView):
template_name = "generic/edit_template.html"
model = Comment
form_class = CommentForm
def get_success_url(self):
return reverse('edit_comment', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(CommentUpdate, self).get_context_data(**kwargs)
context['title'] = _("Comment")
context['view_url'] = reverse('view_recipe', args=[self.object.recipe.pk])
return context
class ImportUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['user']
template_name = "generic/edit_template.html"
model = RecipeImport
fields = ['name', 'path']
# TODO add msg box
def get_success_url(self):
return reverse('edit_import', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(ImportUpdate, self).get_context_data(**kwargs)
context['title'] = _("Import")
return context
class RecipeBookUpdate(OwnerRequiredMixin, UpdateView):
template_name = "generic/edit_template.html"
model = RecipeBook
form_class = RecipeBookForm
def get_success_url(self):
return reverse('view_books')
def get_context_data(self, **kwargs):
context = super(RecipeBookUpdate, self).get_context_data(**kwargs)
context['title'] = _("Recipe Book")
return context
class MealPlanUpdate(OwnerRequiredMixin, UpdateView):
template_name = "generic/edit_template.html"
model = MealPlan
form_class = MealPlanForm
def get_success_url(self):
return reverse('view_plan_entry', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(MealPlanUpdate, self).get_context_data(**kwargs)
context['title'] = _("Meal-Plan")
return context
class ExternalRecipeUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['user']
model = Recipe
form_class = ExternalRecipeForm
template_name = "generic/edit_template.html"
def form_valid(self, form):
self.object = form.save(commit=False)
old_recipe = Recipe.objects.get(pk=self.object.pk)
if not old_recipe.name == self.object.name:
if self.object.storage.method == Storage.DROPBOX:
Dropbox.rename_file(old_recipe, self.object.name) # TODO central location to handle storage type switches
if self.object.storage.method == Storage.NEXTCLOUD:
Nextcloud.rename_file(old_recipe, self.object.name)
self.object.file_path = os.path.dirname(self.object.file_path) + '/' + self.object.name + os.path.splitext(self.object.file_path)[1]
messages.add_message(self.request, messages.SUCCESS, _('Changes saved!'))
return super(ExternalRecipeUpdate, self).form_valid(form)
def form_invalid(self, form):
messages.add_message(self.request, messages.ERROR, _('Error saving changes!'))
return super(ExternalRecipeUpdate, self).form_valid(form)
def get_success_url(self):
return reverse('edit_recipe', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(ExternalRecipeUpdate, self).get_context_data(**kwargs)
context['title'] = _("Recipe")
context['view_url'] = reverse('view_recipe', args=[self.object.pk])
if self.object.storage:
context['delete_external_url'] = reverse('delete_recipe_source', args=[self.object.pk])
return context
@group_required('user')
def edit_ingredients(request):
if request.method == "POST":
success = False
units_form = UnitMergeForm(request.POST, prefix=UnitMergeForm.prefix)
if units_form.is_valid():
new_unit = units_form.cleaned_data['new_unit']
old_unit = units_form.cleaned_data['old_unit']
recipe_ingredients = RecipeIngredient.objects.filter(unit=old_unit).all()
for i in recipe_ingredients:
i.unit = new_unit
i.save()
old_unit.delete()
success = True
messages.add_message(request, messages.SUCCESS, _('Units merged!'))
ingredients_form = IngredientMergeForm(request.POST, prefix=IngredientMergeForm.prefix)
if ingredients_form.is_valid():
new_ingredient = ingredients_form.cleaned_data['new_food']
old_ingredient = ingredients_form.cleaned_data['old_food']
recipe_ingredients = RecipeIngredient.objects.filter(ingredient=old_ingredient).all()
for i in recipe_ingredients:
i.ingredient = new_ingredient
i.save()
old_ingredient.delete()
success = True
messages.add_message(request, messages.SUCCESS, _('Ingredients merged!'))
if success:
units_form = UnitMergeForm()
ingredients_form = IngredientMergeForm()
else:
units_form = UnitMergeForm()
ingredients_form = IngredientMergeForm()
return render(request, 'forms/ingredients.html', {'units_form': units_form, 'ingredients_form': ingredients_form})