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