basic space stuff
This commit is contained in:
@ -3,11 +3,12 @@ from django.conf import settings
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.forms import MultiSelectWidget
|
||||
from cookbook.models import Food, Keyword, Recipe, ShoppingList
|
||||
|
||||
|
||||
with scopes_disabled():
|
||||
class RecipeFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(method='filter_name')
|
||||
keywords = django_filters.ModelMultipleChoiceFilter(
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django import forms
|
||||
from django.forms import widgets
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes.forms import SafeModelChoiceField, SafeModelMultipleChoiceField
|
||||
from emoji_picker.widgets import EmojiPickerTextInput
|
||||
|
||||
from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe,
|
||||
@ -74,18 +75,13 @@ class UserNameForm(forms.ModelForm):
|
||||
|
||||
class ExternalRecipeForm(forms.ModelForm):
|
||||
file_path = forms.CharField(disabled=True, required=False)
|
||||
storage = forms.ModelChoiceField(
|
||||
queryset=Storage.objects.all(),
|
||||
disabled=True,
|
||||
required=False
|
||||
)
|
||||
file_uid = forms.CharField(disabled=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
fields = (
|
||||
'name', 'keywords', 'description', 'servings', 'working_time', 'waiting_time',
|
||||
'file_path', 'storage', 'file_uid'
|
||||
'name', 'description', 'servings', 'working_time', 'waiting_time',
|
||||
'file_path', 'file_uid'
|
||||
)
|
||||
|
||||
labels = {
|
||||
@ -96,39 +92,7 @@ class ExternalRecipeForm(forms.ModelForm):
|
||||
'file_path': _('Path'),
|
||||
'file_uid': _('Storage UID'),
|
||||
}
|
||||
widgets = {'keywords': MultiSelectWidget}
|
||||
|
||||
|
||||
class InternalRecipeForm(forms.ModelForm):
|
||||
ingredients = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
fields = (
|
||||
'name', 'image', 'working_time',
|
||||
'waiting_time', 'servings', 'keywords'
|
||||
)
|
||||
|
||||
labels = {
|
||||
'name': _('Name'),
|
||||
'keywords': _('Keywords'),
|
||||
'working_time': _('Preparation time in minutes'),
|
||||
'waiting_time': _('Waiting time (cooking/baking) in minutes'),
|
||||
'servings': _('Number of servings'),
|
||||
}
|
||||
widgets = {'keywords': MultiSelectWidget}
|
||||
|
||||
|
||||
class ShoppingForm(forms.Form):
|
||||
recipe = forms.ModelMultipleChoiceField(
|
||||
queryset=Recipe.objects.filter(internal=True).all(),
|
||||
widget=MultiSelectWidget
|
||||
)
|
||||
markdown_format = forms.BooleanField(
|
||||
help_text=_('Include <code>- [ ]</code> in list for easier usage in markdown based documents.'), # noqa: E501
|
||||
required=False,
|
||||
initial=False
|
||||
)
|
||||
# widgets = {'keywords': MultiSelectWidget}
|
||||
|
||||
|
||||
class ImportExportBase(forms.Form):
|
||||
@ -150,37 +114,44 @@ class ImportForm(ImportExportBase):
|
||||
|
||||
|
||||
class ExportForm(ImportExportBase):
|
||||
recipes = forms.ModelMultipleChoiceField(queryset=Recipe.objects.filter(internal=True).all(), widget=MultiSelectWidget)
|
||||
recipes = forms.ModelMultipleChoiceField(widget=MultiSelectWidget, queryset=None)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__()
|
||||
user = kwargs.pop('user')
|
||||
self.fields['recipes'].queryset = Recipe.objects.filter(internal=True).filter(space=user.userpreference.space).all()
|
||||
|
||||
|
||||
class UnitMergeForm(forms.Form):
|
||||
prefix = 'unit'
|
||||
|
||||
new_unit = forms.ModelChoiceField(
|
||||
queryset=Unit.objects.all(),
|
||||
new_unit = SafeModelChoiceField(
|
||||
queryset=Unit.objects.none(),
|
||||
widget=SelectWidget,
|
||||
label=_('New Unit'),
|
||||
help_text=_('New unit that other gets replaced by.'),
|
||||
)
|
||||
old_unit = forms.ModelChoiceField(
|
||||
queryset=Unit.objects.all(),
|
||||
old_unit = SafeModelChoiceField(
|
||||
queryset=Unit.objects.none(),
|
||||
widget=SelectWidget,
|
||||
label=_('Old Unit'),
|
||||
help_text=_('Unit that should be replaced.'),
|
||||
)
|
||||
|
||||
|
||||
# todo spaces form here on
|
||||
|
||||
class FoodMergeForm(forms.Form):
|
||||
prefix = 'food'
|
||||
|
||||
new_food = forms.ModelChoiceField(
|
||||
queryset=Food.objects.all(),
|
||||
new_food = SafeModelChoiceField(
|
||||
queryset=Food.objects.none(),
|
||||
widget=SelectWidget,
|
||||
label=_('New Food'),
|
||||
help_text=_('New food that other gets replaced by.'),
|
||||
)
|
||||
old_food = forms.ModelChoiceField(
|
||||
queryset=Food.objects.all(),
|
||||
old_food = SafeModelChoiceField(
|
||||
queryset=Food.objects.none(),
|
||||
widget=SelectWidget,
|
||||
label=_('Old Food'),
|
||||
help_text=_('Food that should be replaced.'),
|
||||
@ -215,6 +186,11 @@ class FoodForm(forms.ModelForm):
|
||||
fields = ('name', 'description', 'ignore_shopping', 'recipe', 'supermarket_category')
|
||||
widgets = {'recipe': SelectWidget}
|
||||
|
||||
field_classes = {
|
||||
'recipe': SafeModelChoiceField,
|
||||
'supermarket_category': SafeModelChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class StorageForm(forms.ModelForm):
|
||||
username = forms.CharField(
|
||||
@ -252,17 +228,25 @@ class RecipeBookEntryForm(forms.ModelForm):
|
||||
model = RecipeBookEntry
|
||||
fields = ('book',)
|
||||
|
||||
field_classes = {
|
||||
'book': SafeModelChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class SyncForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Sync
|
||||
fields = ('storage', 'path', 'active')
|
||||
|
||||
field_classes = {
|
||||
'storage': SafeModelChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class BatchEditForm(forms.Form):
|
||||
search = forms.CharField(label=_('Search String'))
|
||||
keywords = forms.ModelMultipleChoiceField(
|
||||
queryset=Keyword.objects.all().order_by('id'),
|
||||
queryset=Keyword.objects.none().order_by('id'),
|
||||
required=False,
|
||||
widget=MultiSelectWidget
|
||||
)
|
||||
@ -280,6 +264,9 @@ class ImportRecipeForm(forms.ModelForm):
|
||||
'file_uid': _('File ID'),
|
||||
}
|
||||
widgets = {'keywords': MultiSelectWidget}
|
||||
field_classes = {
|
||||
'keywords': SafeModelChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class RecipeBookForm(forms.ModelForm):
|
||||
@ -287,6 +274,9 @@ class RecipeBookForm(forms.ModelForm):
|
||||
model = RecipeBook
|
||||
fields = ('name', 'icon', 'description', 'shared')
|
||||
widgets = {'icon': EmojiPickerTextInput, 'shared': MultiSelectWidget}
|
||||
field_classes = {
|
||||
'shared': SafeModelMultipleChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class MealPlanForm(forms.ModelForm):
|
||||
@ -318,6 +308,11 @@ class MealPlanForm(forms.ModelForm):
|
||||
'date': DateWidget,
|
||||
'shared': MultiSelectWidget
|
||||
}
|
||||
field_classes = {
|
||||
'recipe': SafeModelChoiceField,
|
||||
'meal_type': SafeModelChoiceField,
|
||||
'shared': SafeModelMultipleChoiceField,
|
||||
}
|
||||
|
||||
|
||||
class InviteLinkForm(forms.ModelForm):
|
||||
|
@ -10,6 +10,7 @@ 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,
|
||||
STICKY_NAV_PREF_DEFAULT)
|
||||
@ -107,6 +108,9 @@ class UserPreference(models.Model):
|
||||
shopping_auto_sync = models.IntegerField(default=5)
|
||||
sticky_navbar = models.BooleanField(default=STICKY_NAV_PREF_DEFAULT)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user)
|
||||
|
||||
@ -128,6 +132,9 @@ class Storage(models.Model):
|
||||
path = models.CharField(blank=True, default='', max_length=256)
|
||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -140,6 +147,9 @@ class Sync(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.path
|
||||
|
||||
@ -148,6 +158,9 @@ class SupermarketCategory(models.Model):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
description = models.TextField(blank=True, null=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -157,6 +170,9 @@ class Supermarket(models.Model):
|
||||
description = models.TextField(blank=True, null=True)
|
||||
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -166,6 +182,8 @@ class SupermarketCategoryRelation(models.Model):
|
||||
category = models.ForeignKey(SupermarketCategory, on_delete=models.CASCADE, related_name='category_to_supermarket')
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
objects = ScopedManager(space='supermarket__space')
|
||||
|
||||
class Meta:
|
||||
ordering = ('order',)
|
||||
|
||||
@ -176,6 +194,9 @@ class SyncLog(models.Model):
|
||||
msg = models.TextField(default="")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.created_at}:{self.sync} - {self.status}"
|
||||
|
||||
@ -187,6 +208,9 @@ class Keyword(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
if self.icon:
|
||||
return f"{self.icon} {self.name}"
|
||||
@ -198,6 +222,9 @@ class Unit(models.Model):
|
||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
||||
description = models.TextField(blank=True, null=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -209,6 +236,9 @@ class Food(models.Model):
|
||||
ignore_shopping = models.BooleanField(default=False)
|
||||
description = models.TextField(default='', blank=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -226,6 +256,8 @@ class Ingredient(models.Model):
|
||||
no_amount = models.BooleanField(default=False)
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
objects = ScopedManager(space='step__recipe__space')
|
||||
|
||||
def __str__(self):
|
||||
return str(self.amount) + ' ' + str(self.unit) + ' ' + str(self.food)
|
||||
|
||||
@ -249,6 +281,8 @@ class Step(models.Model):
|
||||
order = models.IntegerField(default=0)
|
||||
show_as_header = models.BooleanField(default=True)
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def get_instruction_render(self):
|
||||
from cookbook.helper.template_helper import render_instructions
|
||||
return render_instructions(self)
|
||||
@ -268,6 +302,8 @@ class NutritionInformation(models.Model):
|
||||
max_length=512, default="", null=True, blank=True
|
||||
)
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def __str__(self):
|
||||
return 'Nutrition'
|
||||
|
||||
@ -297,7 +333,8 @@ class Recipe(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = RandomManager()
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@ -310,6 +347,8 @@ class Comment(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = ScopedManager(space='recipe__space')
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
@ -321,6 +360,9 @@ class RecipeImport(models.Model):
|
||||
file_path = models.CharField(max_length=512, default="")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -334,6 +376,9 @@ class RecipeBook(models.Model):
|
||||
)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -342,6 +387,9 @@ class RecipeBookEntry(models.Model):
|
||||
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
|
||||
book = models.ForeignKey(RecipeBook, on_delete=models.CASCADE)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.recipe.name
|
||||
|
||||
@ -360,6 +408,9 @@ class MealType(models.Model):
|
||||
order = models.IntegerField(default=0)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -378,6 +429,9 @@ class MealPlan(models.Model):
|
||||
note = models.TextField(blank=True)
|
||||
date = models.DateField()
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def get_label(self):
|
||||
if self.title:
|
||||
return self.title
|
||||
@ -396,6 +450,9 @@ class ShoppingListRecipe(models.Model):
|
||||
)
|
||||
servings = models.DecimalField(default=1, max_digits=8, decimal_places=4)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f'Shopping list recipe {self.id} - {self.recipe}'
|
||||
|
||||
@ -414,6 +471,9 @@ class ShoppingListEntry(models.Model):
|
||||
order = models.IntegerField(default=0)
|
||||
checked = models.BooleanField(default=False)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f'Shopping list entry {self.id}'
|
||||
|
||||
@ -435,6 +495,9 @@ class ShoppingList(models.Model):
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f'Shopping list {self.id}'
|
||||
|
||||
@ -445,6 +508,9 @@ class ShareLink(models.Model):
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.recipe} - {self.uuid}'
|
||||
|
||||
@ -464,6 +530,9 @@ class InviteLink(models.Model):
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.uuid}'
|
||||
|
||||
@ -475,6 +544,9 @@ class CookLog(models.Model):
|
||||
rating = models.IntegerField(null=True)
|
||||
servings = models.IntegerField(default=0)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.recipe.name
|
||||
|
||||
@ -484,5 +556,8 @@ class ViewLog(models.Model):
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
def __str__(self):
|
||||
return self.recipe.name
|
||||
|
@ -89,7 +89,6 @@ urlpatterns = [
|
||||
path('api/log_cooking/<int:recipe_id>/', api.log_cooking, name='api_log_cooking'),
|
||||
path('api/plan-ical/<slug:from_date>/<slug:to_date>/', api.get_plan_ical, name='api_get_plan_ical'),
|
||||
path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'),
|
||||
path('api/backup/', api.get_backup, name='api_backup'),
|
||||
path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'),
|
||||
|
||||
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
||||
|
@ -59,7 +59,7 @@ from recipes.settings import DEMO
|
||||
class StandardFilterMixin(ViewSetMixin):
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset
|
||||
queryset = self.queryset.filter(userpreference__space=self.request.user.userpreference.space)
|
||||
query = self.request.query_params.get('query', None)
|
||||
if query is not None:
|
||||
queryset = queryset.filter(name__icontains=query)
|
||||
@ -90,13 +90,13 @@ class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
- **filter_list**: array of user id's to get names for
|
||||
"""
|
||||
queryset = User.objects.all()
|
||||
queryset = User.objects
|
||||
serializer_class = UserNameSerializer
|
||||
permission_classes = [CustomIsGuest]
|
||||
http_method_names = ['get']
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset
|
||||
queryset = self.queryset.filter(userpreference__space=self.request.user.userpreference.space)
|
||||
try:
|
||||
filter_list = self.request.query_params.get('filter_list', None)
|
||||
if filter_list is not None:
|
||||
@ -110,7 +110,7 @@ class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
||||
|
||||
class UserPreferenceViewSet(viewsets.ModelViewSet):
|
||||
queryset = UserPreference.objects.all()
|
||||
queryset = UserPreference.objects
|
||||
serializer_class = UserPreferenceSerializer
|
||||
permission_classes = [CustomIsOwner, ]
|
||||
|
||||
@ -120,35 +120,45 @@ class UserPreferenceViewSet(viewsets.ModelViewSet):
|
||||
serializer.save(user=self.request.user)
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_superuser:
|
||||
return self.queryset
|
||||
return self.queryset.filter(user=self.request.user)
|
||||
|
||||
|
||||
class StorageViewSet(viewsets.ModelViewSet):
|
||||
# TODO handle delete protect error and adjust test
|
||||
queryset = Storage.objects.all()
|
||||
queryset = Storage.objects
|
||||
serializer_class = StorageSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class SyncViewSet(viewsets.ModelViewSet):
|
||||
queryset = Sync.objects.all()
|
||||
queryset = Sync.objects
|
||||
serializer_class = SyncSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class SyncLogViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SyncLog.objects.all()
|
||||
queryset = SyncLog.objects
|
||||
serializer_class = SyncLogSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class SupermarketViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = Supermarket.objects.all()
|
||||
queryset = Supermarket.objects
|
||||
serializer_class = SupermarketSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class KeywordViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
"""
|
||||
@ -159,44 +169,48 @@ class KeywordViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
in the keyword name (case in-sensitive)
|
||||
- **limit**: limits the amount of returned results
|
||||
"""
|
||||
queryset = Keyword.objects.all()
|
||||
queryset = Keyword.objects
|
||||
serializer_class = KeywordSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class UnitViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = Unit.objects.all()
|
||||
queryset = Unit.objects
|
||||
serializer_class = UnitSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class FoodViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = Food.objects.all()
|
||||
queryset = Food.objects
|
||||
serializer_class = FoodSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class RecipeBookViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = RecipeBook.objects.all()
|
||||
queryset = RecipeBook.objects
|
||||
serializer_class = RecipeBookSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = super(RecipeBookViewSet, self).get_queryset()
|
||||
if self.request.user.is_superuser:
|
||||
return self.queryset
|
||||
return self.queryset.filter(created_by=self.request.user)
|
||||
return self.queryset.filter(created_by=self.request.user).filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class RecipeBookEntryViewSet(viewsets.ModelViewSet, viewsets.GenericViewSet):
|
||||
queryset = RecipeBookEntry.objects.all()
|
||||
queryset = RecipeBookEntry.objects
|
||||
serializer_class = RecipeBookEntrySerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_superuser:
|
||||
return self.queryset
|
||||
return self.queryset.filter(created_by=self.request.user)
|
||||
return self.queryset.filter(created_by=self.request.user).filter(space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class MealPlanViewSet(viewsets.ModelViewSet):
|
||||
@ -208,15 +222,15 @@ class MealPlanViewSet(viewsets.ModelViewSet):
|
||||
- **to_date**: filter upward to (inclusive) certain date
|
||||
|
||||
"""
|
||||
queryset = MealPlan.objects.all()
|
||||
queryset = MealPlan.objects
|
||||
serializer_class = MealPlanSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = MealPlan.objects.filter(
|
||||
queryset = self.queryset.filter(
|
||||
Q(created_by=self.request.user) |
|
||||
Q(shared=self.request.user)
|
||||
).distinct().all()
|
||||
).filter(space=self.request.user.userpreference.space).distinct().all()
|
||||
|
||||
from_date = self.request.query_params.get('from_date', None)
|
||||
if from_date is not None:
|
||||
@ -233,26 +247,32 @@ class MealTypeViewSet(viewsets.ModelViewSet):
|
||||
returns list of meal types created by the
|
||||
requesting user ordered by the order field.
|
||||
"""
|
||||
queryset = MealType.objects.order_by('order').all()
|
||||
queryset = MealType.objects
|
||||
serializer_class = MealTypeSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = MealType.objects.order_by('order', 'id').filter(created_by=self.request.user).all()
|
||||
queryset = self.queryset.order_by('order', 'id').filter(created_by=self.request.user).filter(space=self.request.user.userpreference.space).all()
|
||||
return queryset
|
||||
|
||||
|
||||
class IngredientViewSet(viewsets.ModelViewSet):
|
||||
queryset = Ingredient.objects.all()
|
||||
queryset = Ingredient.objects
|
||||
serializer_class = IngredientSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(step__recipe__space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class StepViewSet(viewsets.ModelViewSet):
|
||||
queryset = Step.objects.all()
|
||||
queryset = Step.objects
|
||||
serializer_class = StepSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(recipe__space=self.request.user.userpreference.space)
|
||||
|
||||
|
||||
class RecipeViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
"""
|
||||
@ -263,18 +283,19 @@ class RecipeViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
in the recipe name (case in-sensitive)
|
||||
- **limit**: limits the amount of returned results
|
||||
"""
|
||||
queryset = Recipe.objects.all()
|
||||
queryset = Recipe.objects
|
||||
serializer_class = RecipeSerializer
|
||||
# TODO split read and write permission for meal plan guest
|
||||
permission_classes = [CustomIsShare | CustomIsGuest]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(space=self.request.user.userpreference.space)
|
||||
|
||||
internal = self.request.query_params.get('internal', None)
|
||||
if internal:
|
||||
self.queryset = self.queryset.filter(internal=True)
|
||||
queryset = queryset.filter(internal=True)
|
||||
|
||||
return super().get_queryset()
|
||||
return queryset
|
||||
|
||||
# TODO write extensive tests for permissions
|
||||
|
||||
@ -317,34 +338,32 @@ class RecipeViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
|
||||
|
||||
class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingListRecipe.objects.all()
|
||||
queryset = ShoppingListRecipe.objects
|
||||
serializer_class = ShoppingListRecipeSerializer
|
||||
permission_classes = [CustomIsOwner, ]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(shoppinglist__created_by=self.request.user).all()
|
||||
return self.queryset.filter(shoppinglist__created_by=self.request.user).filter(space=self.request.user.userpreference.space).all()
|
||||
|
||||
|
||||
class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingListEntry.objects.all()
|
||||
queryset = ShoppingListEntry.objects
|
||||
serializer_class = ShoppingListEntrySerializer
|
||||
permission_classes = [CustomIsOwner, ]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(shoppinglist__created_by=self.request.user).all()
|
||||
return self.queryset.filter(shoppinglist__created_by=self.request.user).filter(space=self.request.user.userpreference.space).all()
|
||||
|
||||
|
||||
class ShoppingListViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingList.objects.all()
|
||||
queryset = ShoppingList.objects
|
||||
serializer_class = ShoppingListSerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_superuser:
|
||||
return self.queryset
|
||||
return self.queryset.filter(
|
||||
Q(created_by=self.request.user) | Q(shared=self.request.user)
|
||||
).all()
|
||||
).filter(space=self.request.user.userpreference.space).all()
|
||||
|
||||
def get_serializer_class(self):
|
||||
autosync = self.request.query_params.get('autosync', None)
|
||||
@ -354,21 +373,21 @@ class ShoppingListViewSet(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class ViewLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = ViewLog.objects.all()
|
||||
queryset = ViewLog.objects
|
||||
serializer_class = ViewLogSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
return CookLog.objects.filter(created_by=self.request.user).all()[:5]
|
||||
return CookLog.objects.filter(created_by=self.request.user).filter(space=self.request.user.userpreference.space).all()[:5]
|
||||
|
||||
|
||||
class CookLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = CookLog.objects.all()
|
||||
queryset = CookLog.objects
|
||||
serializer_class = CookLogSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = CookLog.objects.filter(created_by=self.request.user).all()[:5]
|
||||
queryset = CookLog.objects.filter(created_by=self.request.user).filter(space=self.request.user.userpreference.space).all()[:5]
|
||||
return queryset
|
||||
|
||||
|
||||
@ -395,7 +414,7 @@ def update_recipe_links(recipe):
|
||||
|
||||
@group_required('user')
|
||||
def get_external_file_link(request, recipe_id):
|
||||
recipe = Recipe.objects.get(id=recipe_id)
|
||||
recipe = Recipe.objects.filter(space=request.user.userpreference.space).get(id=recipe_id)
|
||||
if not recipe.link:
|
||||
update_recipe_links(recipe)
|
||||
|
||||
@ -404,7 +423,7 @@ def get_external_file_link(request, recipe_id):
|
||||
|
||||
@group_required('guest')
|
||||
def get_recipe_file(request, recipe_id):
|
||||
recipe = Recipe.objects.get(id=recipe_id)
|
||||
recipe = Recipe.objects.filter(space=request.user.userpreference.space).get(id=recipe_id)
|
||||
if recipe.storage:
|
||||
return FileResponse(get_recipe_provider(recipe).get_file(recipe))
|
||||
else:
|
||||
@ -419,7 +438,7 @@ def sync_all(request):
|
||||
)
|
||||
return redirect('index')
|
||||
|
||||
monitors = Sync.objects.filter(active=True)
|
||||
monitors = Sync.objects.filter(active=True).filter(space=request.user.userpreference.space)
|
||||
|
||||
error = False
|
||||
for monitor in monitors:
|
||||
@ -471,7 +490,7 @@ def log_cooking(request, recipe_id):
|
||||
def get_plan_ical(request, from_date, to_date):
|
||||
queryset = MealPlan.objects.filter(
|
||||
Q(created_by=request.user) | Q(shared=request.user)
|
||||
).distinct().all()
|
||||
).filter(space=request.user.userpreference.space).distinct().all()
|
||||
|
||||
if from_date is not None:
|
||||
queryset = queryset.filter(date__gte=from_date)
|
||||
@ -525,22 +544,6 @@ def recipe_from_url(request):
|
||||
return get_from_html(response.text, url)
|
||||
|
||||
|
||||
@group_required('admin')
|
||||
def get_backup(request):
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponse('', status=403)
|
||||
|
||||
buf = io.StringIO()
|
||||
management.call_command(
|
||||
'dumpdata', exclude=['contenttypes', 'auth'], stdout=buf
|
||||
)
|
||||
|
||||
response = FileResponse(buf.getvalue())
|
||||
response["Content-Disposition"] = f'attachment; filename=backup{date_format(timezone.now(), format="SHORT_DATETIME_FORMAT", use_l10n=True)}.json' # noqa: E501
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def ingredient_from_string(request):
|
||||
text = request.POST['text']
|
||||
|
@ -49,7 +49,7 @@ def import_recipe(request):
|
||||
@group_required('user')
|
||||
def export_recipe(request):
|
||||
if request.method == "POST":
|
||||
form = ExportForm(request.POST)
|
||||
form = ExportForm(request.POST, user=request.user)
|
||||
if form.is_valid():
|
||||
try:
|
||||
integration = get_integration(request, form.cleaned_data['type'])
|
||||
@ -58,11 +58,11 @@ def export_recipe(request):
|
||||
messages.add_message(request, messages.ERROR, _('Exporting is not implemented for this provider'))
|
||||
|
||||
else:
|
||||
form = ExportForm()
|
||||
form = ExportForm(user=request.user)
|
||||
recipe = request.GET.get('r')
|
||||
if recipe:
|
||||
if re.match(r'^([0-9])+$', recipe):
|
||||
if recipe := Recipe.objects.filter(pk=int(recipe)).first():
|
||||
form = ExportForm(initial={'recipes': recipe})
|
||||
form = ExportForm(initial={'recipes': recipe}, user=request.user)
|
||||
|
||||
return render(request, 'export.html', {'form': form})
|
||||
|
@ -31,3 +31,4 @@ Jinja2==2.11.3
|
||||
django-webpack-loader==0.7.0
|
||||
django-js-reverse==0.9.1
|
||||
django-allauth==0.44.0
|
||||
django-scopes==1.2.0
|
Reference in New Issue
Block a user