updated edit and added space find methods
This commit is contained in:
parent
fb58d35029
commit
ad163509b4
@ -1,6 +1,9 @@
|
||||
"""
|
||||
Source: https://djangosnippets.org/snippets/1703/
|
||||
"""
|
||||
from django.views.generic.detail import SingleObjectTemplateResponseMixin
|
||||
from django.views.generic.edit import ModelFormMixin
|
||||
|
||||
from cookbook.models import ShareLink
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
@ -131,11 +134,11 @@ class GroupRequiredMixin(object):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not has_group_permission(request.user, self.groups_required):
|
||||
messages.add_message(
|
||||
request,
|
||||
messages.ERROR,
|
||||
_('You do not have the required permissions to view this page!') # noqa: E501
|
||||
)
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
|
||||
if self.get_object().get_space() != request.space:
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
|
||||
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
@ -162,8 +165,11 @@ class OwnerRequiredMixin(object):
|
||||
)
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
return super(OwnerRequiredMixin, self) \
|
||||
.dispatch(request, *args, **kwargs)
|
||||
if self.get_object().get_space() != request.space:
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
|
||||
return super(OwnerRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
# Django Rest Framework Permission classes
|
||||
|
@ -1,4 +1,4 @@
|
||||
from django_scopes import scope
|
||||
from django_scopes import scope, scopes_disabled
|
||||
|
||||
|
||||
class ScopeMiddleware:
|
||||
@ -9,6 +9,7 @@ class ScopeMiddleware:
|
||||
if request.user.is_authenticated:
|
||||
request.space = request.user.userpreference.space
|
||||
|
||||
#with scopes_disabled():
|
||||
with scope(space=request.space):
|
||||
return self.get_response(request)
|
||||
else:
|
||||
|
@ -9,7 +9,6 @@ from django.core.validators import MinLengthValidator
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_random_queryset import RandomManager
|
||||
from django_scopes import ScopedManager
|
||||
|
||||
from recipes.settings import (COMMENT_PREF_DEFAULT, FRACTION_PREF_DEFAULT,
|
||||
@ -30,12 +29,26 @@ def get_model_name(model):
|
||||
return ('_'.join(re.findall('[A-Z][^A-Z]*', model.__name__))).lower()
|
||||
|
||||
|
||||
class PermissionModelMixin:
|
||||
def get_owner(self):
|
||||
if getattr(self, 'created_by', None):
|
||||
return self.created_by
|
||||
if getattr(self, 'user', None):
|
||||
return self.user
|
||||
return None
|
||||
|
||||
def get_space(self):
|
||||
if getattr(self, 'space', None):
|
||||
return self.space
|
||||
raise NotImplementedError('get space for method not implemented and standard fields not available')
|
||||
|
||||
|
||||
class Space(models.Model):
|
||||
name = models.CharField(max_length=128, default='Default')
|
||||
message = models.CharField(max_length=512, default='', blank=True)
|
||||
|
||||
|
||||
class UserPreference(models.Model):
|
||||
class UserPreference(models.Model, PermissionModelMixin):
|
||||
# Themes
|
||||
BOOTSTRAP = 'BOOTSTRAP'
|
||||
DARKLY = 'DARKLY'
|
||||
@ -115,7 +128,7 @@ class UserPreference(models.Model):
|
||||
return str(self.user)
|
||||
|
||||
|
||||
class Storage(models.Model):
|
||||
class Storage(models.Model, PermissionModelMixin):
|
||||
DROPBOX = 'DB'
|
||||
NEXTCLOUD = 'NEXTCLOUD'
|
||||
LOCAL = 'LOCAL'
|
||||
@ -139,7 +152,7 @@ class Storage(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class Sync(models.Model):
|
||||
class Sync(models.Model, PermissionModelMixin):
|
||||
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
|
||||
path = models.CharField(max_length=512, default="")
|
||||
active = models.BooleanField(default=True)
|
||||
@ -154,7 +167,7 @@ class Sync(models.Model):
|
||||
return self.path
|
||||
|
||||
|
||||
class SupermarketCategory(models.Model):
|
||||
class SupermarketCategory(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
description = models.TextField(blank=True, null=True)
|
||||
|
||||
@ -165,7 +178,7 @@ class SupermarketCategory(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class Supermarket(models.Model):
|
||||
class Supermarket(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
description = models.TextField(blank=True, null=True)
|
||||
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
||||
@ -177,18 +190,21 @@ class Supermarket(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class SupermarketCategoryRelation(models.Model):
|
||||
class SupermarketCategoryRelation(models.Model, PermissionModelMixin):
|
||||
supermarket = models.ForeignKey(Supermarket, on_delete=models.CASCADE, related_name='category_to_supermarket')
|
||||
category = models.ForeignKey(SupermarketCategory, on_delete=models.CASCADE, related_name='category_to_supermarket')
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
objects = ScopedManager(space='supermarket__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.supermarket.space
|
||||
|
||||
class Meta:
|
||||
ordering = ('order',)
|
||||
|
||||
|
||||
class SyncLog(models.Model):
|
||||
class SyncLog(models.Model, PermissionModelMixin):
|
||||
sync = models.ForeignKey(Sync, on_delete=models.CASCADE)
|
||||
status = models.CharField(max_length=32)
|
||||
msg = models.TextField(default="")
|
||||
@ -201,7 +217,7 @@ class SyncLog(models.Model):
|
||||
return f"{self.created_at}:{self.sync} - {self.status}"
|
||||
|
||||
|
||||
class Keyword(models.Model):
|
||||
class Keyword(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(max_length=64, unique=True)
|
||||
icon = models.CharField(max_length=16, blank=True, null=True)
|
||||
description = models.TextField(default="", blank=True)
|
||||
@ -218,7 +234,7 @@ class Keyword(models.Model):
|
||||
return f"{self.name}"
|
||||
|
||||
|
||||
class Unit(models.Model):
|
||||
class Unit(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
description = models.TextField(blank=True, null=True)
|
||||
|
||||
@ -229,7 +245,7 @@ class Unit(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class Food(models.Model):
|
||||
class Food(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
recipe = models.ForeignKey('Recipe', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
supermarket_category = models.ForeignKey(SupermarketCategory, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
@ -243,13 +259,9 @@ class Food(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class Ingredient(models.Model):
|
||||
food = models.ForeignKey(
|
||||
Food, on_delete=models.PROTECT, null=True, blank=True
|
||||
)
|
||||
unit = models.ForeignKey(
|
||||
Unit, on_delete=models.PROTECT, null=True, blank=True
|
||||
)
|
||||
class Ingredient(models.Model, PermissionModelMixin):
|
||||
food = models.ForeignKey(Food, on_delete=models.PROTECT, null=True, blank=True)
|
||||
unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True, blank=True)
|
||||
amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||
note = models.CharField(max_length=256, null=True, blank=True)
|
||||
is_header = models.BooleanField(default=False)
|
||||
@ -258,6 +270,9 @@ class Ingredient(models.Model):
|
||||
|
||||
objects = ScopedManager(space='step__recipe__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.step_set.first().recipe_set.first().space
|
||||
|
||||
def __str__(self):
|
||||
return str(self.amount) + ' ' + str(self.unit) + ' ' + str(self.food)
|
||||
|
||||
@ -265,7 +280,7 @@ class Ingredient(models.Model):
|
||||
ordering = ['order', 'pk']
|
||||
|
||||
|
||||
class Step(models.Model):
|
||||
class Step(models.Model, PermissionModelMixin):
|
||||
TEXT = 'TEXT'
|
||||
TIME = 'TIME'
|
||||
|
||||
@ -283,6 +298,9 @@ class Step(models.Model):
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.recipe_set.first().space
|
||||
|
||||
def get_instruction_render(self):
|
||||
from cookbook.helper.template_helper import render_instructions
|
||||
return render_instructions(self)
|
||||
@ -291,7 +309,7 @@ class Step(models.Model):
|
||||
ordering = ['order', 'pk']
|
||||
|
||||
|
||||
class NutritionInformation(models.Model):
|
||||
class NutritionInformation(models.Model, PermissionModelMixin):
|
||||
fats = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||
carbohydrates = models.DecimalField(
|
||||
default=0, decimal_places=16, max_digits=32
|
||||
@ -304,11 +322,14 @@ class NutritionInformation(models.Model):
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.recipe_set.first().space
|
||||
|
||||
def __str__(self):
|
||||
return 'Nutrition'
|
||||
|
||||
|
||||
class Recipe(models.Model):
|
||||
class Recipe(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(max_length=128)
|
||||
description = models.CharField(max_length=512, blank=True, null=True)
|
||||
servings = models.IntegerField(default=1)
|
||||
@ -340,7 +361,7 @@ class Recipe(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
class Comment(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
text = models.TextField()
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
@ -349,11 +370,14 @@ class Comment(models.Model):
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.recipe.space
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
class RecipeImport(models.Model):
|
||||
class RecipeImport(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(max_length=128)
|
||||
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
|
||||
file_uid = models.CharField(max_length=256, default="")
|
||||
@ -367,13 +391,11 @@ class RecipeImport(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class RecipeBook(models.Model):
|
||||
class RecipeBook(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(max_length=128)
|
||||
description = models.TextField(blank=True)
|
||||
icon = models.CharField(max_length=16, blank=True, null=True)
|
||||
shared = models.ManyToManyField(
|
||||
User, blank=True, related_name='shared_with'
|
||||
)
|
||||
shared = models.ManyToManyField(User, blank=True, related_name='shared_with')
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
@ -383,12 +405,15 @@ class RecipeBook(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class RecipeBookEntry(models.Model):
|
||||
class RecipeBookEntry(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
book = models.ForeignKey(RecipeBook, on_delete=models.CASCADE)
|
||||
|
||||
objects = ScopedManager(space='book__space')
|
||||
|
||||
def get_space(self):
|
||||
return self.book.space
|
||||
|
||||
def __str__(self):
|
||||
return self.recipe.name
|
||||
|
||||
@ -402,7 +427,7 @@ class RecipeBookEntry(models.Model):
|
||||
unique_together = (('recipe', 'book'),)
|
||||
|
||||
|
||||
class MealType(models.Model):
|
||||
class MealType(models.Model, PermissionModelMixin):
|
||||
name = models.CharField(max_length=128)
|
||||
order = models.IntegerField(default=0)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
@ -414,7 +439,7 @@ class MealType(models.Model):
|
||||
return self.name
|
||||
|
||||
|
||||
class MealPlan(models.Model):
|
||||
class MealPlan(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(
|
||||
Recipe, on_delete=models.CASCADE, blank=True, null=True
|
||||
)
|
||||
@ -443,10 +468,8 @@ class MealPlan(models.Model):
|
||||
return f'{self.get_label()} - {self.date} - {self.meal_type.name}'
|
||||
|
||||
|
||||
class ShoppingListRecipe(models.Model):
|
||||
recipe = models.ForeignKey(
|
||||
Recipe, on_delete=models.CASCADE, null=True, blank=True
|
||||
)
|
||||
class ShoppingListRecipe(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, null=True, blank=True)
|
||||
servings = models.DecimalField(default=1, max_digits=8, decimal_places=4)
|
||||
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
@ -462,7 +485,7 @@ class ShoppingListRecipe(models.Model):
|
||||
return None
|
||||
|
||||
|
||||
class ShoppingListEntry(models.Model):
|
||||
class ShoppingListEntry(models.Model, PermissionModelMixin):
|
||||
list_recipe = models.ForeignKey(ShoppingListRecipe, on_delete=models.CASCADE, null=True, blank=True)
|
||||
food = models.ForeignKey(Food, on_delete=models.CASCADE)
|
||||
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, null=True, blank=True)
|
||||
@ -483,7 +506,7 @@ class ShoppingListEntry(models.Model):
|
||||
return None
|
||||
|
||||
|
||||
class ShoppingList(models.Model):
|
||||
class ShoppingList(models.Model, PermissionModelMixin):
|
||||
uuid = models.UUIDField(default=uuid.uuid4)
|
||||
note = models.TextField(blank=True, null=True)
|
||||
recipes = models.ManyToManyField(ShoppingListRecipe, blank=True)
|
||||
@ -501,7 +524,7 @@ class ShoppingList(models.Model):
|
||||
return f'Shopping list {self.id}'
|
||||
|
||||
|
||||
class ShareLink(models.Model):
|
||||
class ShareLink(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
uuid = models.UUIDField(default=uuid.uuid4)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
@ -518,7 +541,7 @@ def default_valid_until():
|
||||
return date.today() + timedelta(days=14)
|
||||
|
||||
|
||||
class InviteLink(models.Model):
|
||||
class InviteLink(models.Model, PermissionModelMixin):
|
||||
uuid = models.UUIDField(default=uuid.uuid4)
|
||||
username = models.CharField(blank=True, max_length=64)
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
@ -536,7 +559,7 @@ class InviteLink(models.Model):
|
||||
return f'{self.uuid}'
|
||||
|
||||
|
||||
class CookLog(models.Model):
|
||||
class CookLog(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
@ -550,7 +573,7 @@ class CookLog(models.Model):
|
||||
return self.recipe.name
|
||||
|
||||
|
||||
class ViewLog(models.Model):
|
||||
class ViewLog(models.Model, PermissionModelMixin):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
@ -3,9 +3,10 @@ import os
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.urls import reverse
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import UpdateView
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.forms import (CommentForm, ExternalRecipeForm, FoodForm,
|
||||
FoodMergeForm, KeywordForm, MealPlanForm,
|
||||
@ -24,7 +25,7 @@ from cookbook.provider.nextcloud import Nextcloud
|
||||
|
||||
@group_required('guest')
|
||||
def switch_recipe(request, pk):
|
||||
recipe = get_object_or_404(Recipe, pk=pk)
|
||||
recipe = get_object_or_404(Recipe, pk=pk, space=request.space)
|
||||
if recipe.internal:
|
||||
return HttpResponseRedirect(reverse('edit_internal_recipe', args=[pk]))
|
||||
else:
|
||||
@ -33,7 +34,7 @@ def switch_recipe(request, pk):
|
||||
|
||||
@group_required('user')
|
||||
def convert_recipe(request, pk):
|
||||
recipe = get_object_or_404(Recipe, pk=pk)
|
||||
recipe = get_object_or_404(Recipe, pk=pk, space=request.space)
|
||||
if not recipe.internal:
|
||||
recipe.internal = True
|
||||
recipe.save()
|
||||
@ -43,7 +44,7 @@ def convert_recipe(request, pk):
|
||||
|
||||
@group_required('user')
|
||||
def internal_recipe_update(request, pk):
|
||||
recipe_instance = get_object_or_404(Recipe, pk=pk)
|
||||
recipe_instance = get_object_or_404(Recipe, pk=pk, space=request.space)
|
||||
|
||||
return render(
|
||||
request, 'forms/edit_internal_recipe.html', {'recipe': recipe_instance}
|
||||
@ -62,7 +63,7 @@ class SyncUpdate(GroupRequiredMixin, UpdateView):
|
||||
return reverse('edit_sync', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(SyncUpdate, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['title'] = _("Sync")
|
||||
return context
|
||||
|
||||
@ -79,7 +80,7 @@ class KeywordUpdate(GroupRequiredMixin, UpdateView):
|
||||
return reverse('edit_keyword', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(KeywordUpdate, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['title'] = _("Keyword")
|
||||
return context
|
||||
|
||||
@ -103,12 +104,10 @@ class FoodUpdate(GroupRequiredMixin, UpdateView):
|
||||
|
||||
@group_required('admin')
|
||||
def edit_storage(request, pk):
|
||||
instance = get_object_or_404(Storage, pk=pk)
|
||||
instance = get_object_or_404(Storage, pk=pk, space=request.space)
|
||||
|
||||
if not (instance.created_by == request.user or request.user.is_superuser):
|
||||
messages.add_message(
|
||||
request, messages.ERROR, _('You cannot edit this storage!')
|
||||
)
|
||||
messages.add_message(request, messages.ERROR, _('You cannot edit this storage!'))
|
||||
return HttpResponseRedirect(reverse('list_storage'))
|
||||
|
||||
if request.method == "POST":
|
||||
@ -225,7 +224,7 @@ class ExternalRecipeUpdate(GroupRequiredMixin, UpdateView):
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object = form.save(commit=False)
|
||||
old_recipe = Recipe.objects.get(pk=self.object.pk)
|
||||
old_recipe = Recipe.objects.get(pk=self.object.pk, space=self.request.space)
|
||||
if not old_recipe.name == self.object.name:
|
||||
if self.object.storage.method == Storage.DROPBOX:
|
||||
# TODO central location to handle storage type switches
|
||||
@ -277,45 +276,32 @@ def edit_ingredients(request):
|
||||
new_unit = units_form.cleaned_data['new_unit']
|
||||
old_unit = units_form.cleaned_data['old_unit']
|
||||
if new_unit != old_unit:
|
||||
recipe_ingredients = Ingredient.objects \
|
||||
.filter(unit=old_unit).all()
|
||||
recipe_ingredients = Ingredient.objects.filter(unit=old_unit, space=request.space).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!')
|
||||
)
|
||||
messages.add_message(request, messages.SUCCESS, _('Units merged!'))
|
||||
else:
|
||||
messages.add_message(
|
||||
request,
|
||||
messages.ERROR,
|
||||
_('Cannot merge with the same object!')
|
||||
)
|
||||
messages.add_message(request, messages.ERROR, _('Cannot merge with the same object!'))
|
||||
|
||||
food_form = FoodMergeForm(request.POST, prefix=FoodMergeForm.prefix)
|
||||
if food_form.is_valid():
|
||||
new_food = food_form.cleaned_data['new_food']
|
||||
old_food = food_form.cleaned_data['old_food']
|
||||
if new_food != old_food:
|
||||
ingredients = Ingredient.objects.filter(food=old_food).all()
|
||||
ingredients = Ingredient.objects.filter(food=old_food, space=request.space).all()
|
||||
for i in ingredients:
|
||||
i.food = new_food
|
||||
i.save()
|
||||
|
||||
old_food.delete()
|
||||
success = True
|
||||
messages.add_message(
|
||||
request, messages.SUCCESS, _('Foods merged!')
|
||||
)
|
||||
messages.add_message(request, messages.SUCCESS, _('Foods merged!'))
|
||||
else:
|
||||
messages.add_message(
|
||||
request,
|
||||
messages.ERROR,
|
||||
_('Cannot merge with the same object!')
|
||||
)
|
||||
messages.add_message(request, messages.ERROR, _('Cannot merge with the same object!'))
|
||||
|
||||
if success:
|
||||
units_form = UnitMergeForm()
|
||||
@ -324,8 +310,4 @@ def edit_ingredients(request):
|
||||
units_form = UnitMergeForm()
|
||||
food_form = FoodMergeForm()
|
||||
|
||||
return render(
|
||||
request,
|
||||
'forms/ingredients.html',
|
||||
{'units_form': units_form, 'food_form': food_form}
|
||||
)
|
||||
return render(request, 'forms/ingredients.html', {'units_form': units_form, 'food_form': food_form})
|
||||
|
@ -62,7 +62,7 @@ def export_recipe(request):
|
||||
recipe = request.GET.get('r')
|
||||
if recipe:
|
||||
if re.match(r'^([0-9])+$', recipe):
|
||||
if recipe := Recipe.objects.filter(pk=int(recipe)).first():
|
||||
if recipe := Recipe.objects.filter(pk=int(recipe), space=request.space).first():
|
||||
form = ExportForm(initial={'recipes': recipe}, user=request.user)
|
||||
|
||||
return render(request, 'export.html', {'form': form})
|
||||
|
Loading…
Reference in New Issue
Block a user