diff --git a/cookbook/helper/scope_middleware.py b/cookbook/helper/scope_middleware.py new file mode 100644 index 000000000..595a5f916 --- /dev/null +++ b/cookbook/helper/scope_middleware.py @@ -0,0 +1,15 @@ +from django_scopes import scope + + +class ScopeMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + if request.user.is_authenticated: + request.space = request.user.userpreference.space + + with scope(space=request.space): + return self.get_response(request) + else: + return self.get_response(request) diff --git a/cookbook/migrations/0108_auto_20210219_1410.py b/cookbook/migrations/0108_auto_20210219_1410.py new file mode 100644 index 000000000..b71d3fc68 --- /dev/null +++ b/cookbook/migrations/0108_auto_20210219_1410.py @@ -0,0 +1,146 @@ +# Generated by Django 3.1.6 on 2021-02-19 13:10 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0107_auto_20210128_1535'), + ] + + operations = [ + migrations.AddField( + model_name='cooklog', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='food', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='invitelink', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='keyword', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='mealplan', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='mealtype', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='recipe', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='recipebook', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='recipebookentry', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='recipeimport', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='sharelink', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='shoppinglist', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='shoppinglistentry', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='shoppinglistrecipe', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='storage', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='supermarket', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='supermarketcategory', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='sync', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='synclog', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='unit', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='userpreference', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + migrations.AddField( + model_name='viewlog', + name='space', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'), + preserve_default=False, + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index bedc619ae..fd6ca6cea 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -108,7 +108,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -132,7 +132,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -147,7 +147,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -158,7 +158,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -170,7 +170,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -194,7 +194,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -208,7 +208,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -222,7 +222,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -236,7 +236,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -333,7 +333,7 @@ class Recipe(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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -360,7 +360,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -376,7 +376,7 @@ class RecipeBook(models.Model): ) created_by = models.ForeignKey(User, on_delete=models.CASCADE) - space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -387,8 +387,7 @@ 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') + objects = ScopedManager(space='book__space') def __str__(self): return self.recipe.name @@ -408,7 +407,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -429,7 +428,7 @@ class MealPlan(models.Model): note = models.TextField(blank=True) date = models.DateField() - space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def get_label(self): @@ -450,7 +449,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -471,7 +470,7 @@ class ShoppingListEntry(models.Model): order = models.IntegerField(default=0) checked = models.BooleanField(default=False) - space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -495,7 +494,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -508,7 +507,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -530,7 +529,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -544,7 +543,7 @@ class CookLog(models.Model): rating = models.IntegerField(null=True) servings = models.IntegerField(default=0) - space = models.ForeignKey(Space, blank=True, on_delete=models.CASCADE) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): @@ -556,7 +555,7 @@ 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) + space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') def __str__(self): diff --git a/cookbook/templates/system.html b/cookbook/templates/system.html index 8bf1b2b77..442e44ae1 100644 --- a/cookbook/templates/system.html +++ b/cookbook/templates/system.html @@ -22,23 +22,6 @@ {% trans 'Show Links' %} -
diff --git a/cookbook/views/lists.py b/cookbook/views/lists.py index 14198379d..7cfcb229b 100644 --- a/cookbook/views/lists.py +++ b/cookbook/views/lists.py @@ -17,7 +17,7 @@ from cookbook.tables import (ImportLogTable, IngredientTable, InviteLinkTable, @group_required('user') def keyword(request): - table = KeywordTable(Keyword.objects.all()) + table = KeywordTable(Keyword.objects.filter(space=request.space).all()) RequestConfig(request, paginate={'per_page': 25}).configure(table) return render( @@ -30,7 +30,7 @@ def keyword(request): @group_required('admin') def sync_log(request): table = ImportLogTable( - SyncLog.objects.all().order_by('-created_at') + SyncLog.objects.filter(space=request.space).all().order_by('-created_at') ) RequestConfig(request, paginate={'per_page': 25}).configure(table) @@ -43,7 +43,7 @@ def sync_log(request): @group_required('user') def recipe_import(request): - table = RecipeImportTable(RecipeImport.objects.all()) + table = RecipeImportTable(RecipeImport.objects.filter(space=request.space).all()) RequestConfig(request, paginate={'per_page': 25}).configure(table) @@ -56,10 +56,7 @@ def recipe_import(request): @group_required('user') def food(request): - f = IngredientFilter( - request.GET, - queryset=Food.objects.all().order_by('pk') - ) + f = IngredientFilter(request.GET, queryset=Food.objects.filter(space=request.space).all().order_by('pk')) table = IngredientTable(f.qs) RequestConfig(request, paginate={'per_page': 25}).configure(table) @@ -73,12 +70,10 @@ def food(request): @group_required('user') def shopping_list(request): - f = ShoppingListFilter( - request.GET, - queryset=ShoppingList.objects.filter( - Q(created_by=request.user) | - Q(shared=request.user) - ).all().order_by('finished', 'created_at')) + f = ShoppingListFilter(request.GET, queryset=ShoppingList.objects.filter( + Q(created_by=request.user) | + Q(shared=request.user), space=request.space + ).all().order_by('finished', 'created_at')) table = ShoppingListTable(f.qs) RequestConfig(request, paginate={'per_page': 25}).configure(table) @@ -97,7 +92,7 @@ def shopping_list(request): @group_required('admin') def storage(request): - table = StorageTable(Storage.objects.all()) + table = StorageTable(Storage.objects.filter(space=request.space).all()) RequestConfig(request, paginate={'per_page': 25}).configure(table) return render( @@ -113,18 +108,11 @@ def storage(request): @group_required('admin') def invite_link(request): - table = InviteLinkTable( - InviteLink.objects.filter( - valid_until__gte=datetime.today(), used_by=None - ).all()) + table = InviteLinkTable(InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, space=request.space).all()) RequestConfig(request, paginate={'per_page': 25}).configure(table) - return render( - request, - 'generic/list_template.html', - { - 'title': _("Invite Links"), - 'table': table, - 'create_url': 'new_invite_link' - } - ) + return render(request, 'generic/list_template.html', { + 'title': _("Invite Links"), + 'table': table, + 'create_url': 'new_invite_link' + }) diff --git a/cookbook/views/new.py b/cookbook/views/new.py index 877c26021..bdc2bac76 100644 --- a/cookbook/views/new.py +++ b/cookbook/views/new.py @@ -25,12 +25,11 @@ class RecipeCreate(GroupRequiredMixin, CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.created_by = self.request.user + obj.space = self.request.space obj.internal = True obj.save() obj.steps.add(Step.objects.create()) - return HttpResponseRedirect( - reverse('edit_recipe', kwargs={'pk': obj.pk}) - ) + return HttpResponseRedirect(reverse('edit_recipe', kwargs={'pk': obj.pk})) def get_success_url(self): return reverse('edit_recipe', kwargs={'pk': self.object.pk}) @@ -43,11 +42,9 @@ class RecipeCreate(GroupRequiredMixin, CreateView): @group_required('user') def share_link(request, pk): - recipe = get_object_or_404(Recipe, pk=pk) - link = ShareLink.objects.create(recipe=recipe, created_by=request.user) - return HttpResponseRedirect( - reverse('view_recipe', kwargs={'pk': pk, 'share': link.uuid}) - ) + recipe = get_object_or_404(Recipe, pk=pk, space=request.space) + link = ShareLink.objects.create(recipe=recipe, created_by=request.user, space=request.space) + return HttpResponseRedirect(reverse('view_recipe', kwargs={'pk': pk, 'share': link.uuid})) class KeywordCreate(GroupRequiredMixin, CreateView): @@ -57,6 +54,12 @@ class KeywordCreate(GroupRequiredMixin, CreateView): form_class = KeywordForm success_url = reverse_lazy('list_keyword') + def form_valid(self, form): + obj = form.save(commit=False) + obj.space = self.request.space + obj.save() + return HttpResponseRedirect(reverse('edit_keyword', kwargs={'pk': obj.pk})) + def get_context_data(self, **kwargs): context = super(KeywordCreate, self).get_context_data(**kwargs) context['title'] = _("Keyword") @@ -73,10 +76,9 @@ class StorageCreate(GroupRequiredMixin, CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.created_by = self.request.user + obj.space = self.request.space obj.save() - return HttpResponseRedirect( - reverse('edit_storage', kwargs={'pk': obj.pk}) - ) + return HttpResponseRedirect(reverse('edit_storage', kwargs={'pk': obj.pk})) def get_context_data(self, **kwargs): context = super(StorageCreate, self).get_context_data(**kwargs) @@ -89,8 +91,9 @@ def create_new_external_recipe(request, import_id): if request.method == "POST": form = ImportRecipeForm(request.POST) if form.is_valid(): - new_recipe = RecipeImport.objects.get(id=import_id) + new_recipe = get_object_or_404(RecipeImport, pk=import_id, space=request.space) recipe = Recipe() + recipe.space = request.space recipe.storage = new_recipe.storage recipe.name = form.cleaned_data['name'] recipe.file_path = form.cleaned_data['file_path'] @@ -101,20 +104,14 @@ def create_new_external_recipe(request, import_id): recipe.keywords.set(form.cleaned_data['keywords']) - RecipeImport.objects.get(id=import_id).delete() + new_recipe.delete() - messages.add_message( - request, messages.SUCCESS, _('Imported new recipe!') - ) + messages.add_message(request, messages.SUCCESS, _('Imported new recipe!')) return redirect('list_recipe_import') else: - messages.add_message( - request, - messages.ERROR, - _('There was an error importing this recipe!') - ) + messages.add_message(request, messages.ERROR, _('There was an error importing this recipe!')) else: - new_recipe = RecipeImport.objects.get(id=import_id) + new_recipe = get_object_or_404(RecipeImport, pk=import_id, space=request.space) form = ImportRecipeForm( initial={ 'file_path': new_recipe.file_path, @@ -136,6 +133,7 @@ class RecipeBookCreate(GroupRequiredMixin, CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.created_by = self.request.user + obj.space = self.request.space obj.save() return HttpResponseRedirect(reverse('view_books')) @@ -154,9 +152,7 @@ class MealPlanCreate(GroupRequiredMixin, CreateView): def get_form(self, form_class=None): form = self.form_class(**self.get_form_kwargs()) - form.fields['meal_type'].queryset = MealType.objects.filter( - created_by=self.request.user - ).all() + form.fields['meal_type'].queryset = MealType.objects.filter(created_by=self.request.user, space=self.request.space).all() return form def get_initial(self): @@ -181,6 +177,7 @@ class MealPlanCreate(GroupRequiredMixin, CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.created_by = self.request.user + obj.space = self.request.space obj.save() return HttpResponseRedirect(reverse('view_plan')) @@ -191,8 +188,8 @@ class MealPlanCreate(GroupRequiredMixin, CreateView): recipe = self.request.GET.get('recipe') if recipe: if re.match(r'^([0-9])+$', recipe): - if Recipe.objects.filter(pk=int(recipe)).exists(): - context['default_recipe'] = Recipe.objects.get(pk=int(recipe)) # noqa: E501 + if Recipe.objects.filter(pk=int(recipe), space=self.request.space).exists(): + context['default_recipe'] = Recipe.objects.get(pk=int(recipe), space=self.request.space) return context @@ -206,6 +203,7 @@ class InviteLinkCreate(GroupRequiredMixin, CreateView): def form_valid(self, form): obj = form.save(commit=False) obj.created_by = self.request.user + obj.space = self.request.space obj.save() return HttpResponseRedirect(reverse('list_invite_link')) diff --git a/cookbook/views/views.py b/cookbook/views/views.py index bb122d70d..a20da69ca 100644 --- a/cookbook/views/views.py +++ b/cookbook/views/views.py @@ -16,6 +16,7 @@ from django.shortcuts import get_object_or_404, render, redirect from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.translation import gettext as _ +from django_scopes import scopes_disabled, scope from django_tables2 import RequestConfig from rest_framework.authtoken.models import Token @@ -33,10 +34,12 @@ from recipes.version import BUILD_REF, VERSION_NUMBER def index(request): - if not request.user.is_authenticated: - if User.objects.count() < 1 and 'django.contrib.auth.backends.RemoteUserBackend' not in settings.AUTHENTICATION_BACKENDS: - return HttpResponseRedirect(reverse_lazy('view_setup')) - return HttpResponseRedirect(reverse_lazy('view_search')) + with scopes_disabled(): + if not request.user.is_authenticated: + if User.objects.count() < 1 and 'django.contrib.auth.backends.RemoteUserBackend' not in settings.AUTHENTICATION_BACKENDS: + return HttpResponseRedirect(reverse_lazy('view_setup')) + return HttpResponseRedirect(reverse_lazy('view_search')) + try: page_map = { UserPreference.SEARCH: reverse_lazy('view_search'), @@ -53,7 +56,7 @@ def search(request): if has_group_permission(request.user, ('guest',)): f = RecipeFilter( request.GET, - queryset=Recipe.objects.all().order_by('name') + queryset=Recipe.objects.filter(space=request.user.userpreference.space).all().order_by('name') ) if request.user.userpreference.search_style == UserPreference.LARGE: @@ -63,10 +66,7 @@ def search(request): RequestConfig(request, paginate={'per_page': 25}).configure(table) if request.GET == {} and request.user.userpreference.show_recent: - qs = Recipe.objects \ - .filter(viewlog__created_by=request.user) \ - .order_by('-viewlog__created_at') \ - .all() + qs = Recipe.objects.filter(viewlog__created_by=request.user).filter(space=request.user.userpreference.space).order_by('-viewlog__created_at').all() recent_list = [] for r in qs: @@ -79,11 +79,7 @@ def search(request): else: last_viewed = None - return render( - request, - 'index.html', - {'recipes': table, 'filter': f, 'last_viewed': last_viewed} - ) + return render(request, 'index.html', {'recipes': table, 'filter': f, 'last_viewed': last_viewed}) else: return HttpResponseRedirect(reverse('view_no_group') + '?next=' + request.path) @@ -97,17 +93,14 @@ def no_groups(request): def recipe_view(request, pk, share=None): - recipe = get_object_or_404(Recipe, pk=pk) + with scopes_disabled(): + recipe = get_object_or_404(Recipe, pk=pk) - if not has_group_permission(request.user, ('guest',)) and not share_link_valid(recipe, share): - messages.add_message( - request, - messages.ERROR, - _('You do not have the required permissions to view this page!') - ) + if not (has_group_permission(request.user, ('guest',)) and recipe.space == request.space) and not share_link_valid(recipe, share): + messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!')) return HttpResponseRedirect(reverse('view_no_group') + '?next=' + request.path) - comments = Comment.objects.filter(recipe=recipe) + comments = Comment.objects.filter(recipe__space=request.space, recipe=recipe) if request.method == "POST": if not request.user.is_authenticated: @@ -146,17 +139,9 @@ def recipe_view(request, pk, share=None): bookmark.save() except IntegrityError as e: if 'UNIQUE constraint' in str(e.args): - messages.add_message( - request, - messages.ERROR, - _('This recipe is already linked to the book!') - ) + messages.add_message(request, messages.ERROR, _('This recipe is already linked to the book!')) else: - messages.add_message( - request, - messages.SUCCESS, - _('Bookmark saved!') - ) + messages.add_message(request, messages.SUCCESS, _('Bookmark saved!')) comment_form = CommentForm() @@ -165,20 +150,16 @@ def recipe_view(request, pk, share=None): user_servings = CookLog.objects.filter( recipe=recipe, created_by=request.user, - servings__gt=0 + servings__gt=0, + space=request.space, ).all().aggregate(Avg('servings'))['servings__avg'] if not user_servings: user_servings = 0 if request.user.is_authenticated: - if not ViewLog.objects \ - .filter(recipe=recipe) \ - .filter(created_by=request.user) \ - .filter(created_at__gt=( - timezone.now() - timezone.timedelta(minutes=5))) \ - .exists(): - ViewLog.objects.create(recipe=recipe, created_by=request.user) + if not ViewLog.objects.filter(recipe=recipe, created_by=request.user, created_at__gt=(timezone.now() - timezone.timedelta(minutes=5)), space=request.space).exists(): + ViewLog.objects.create(recipe=recipe, created_by=request.user, space=request.space) return render(request, 'recipe_view.html', {'recipe': recipe, 'comments': comments, 'comment_form': comment_form, 'share': share, 'user_servings': user_servings}) @@ -187,11 +168,9 @@ def recipe_view(request, pk, share=None): def books(request): book_list = [] - books = RecipeBook.objects.filter( - Q(created_by=request.user) | Q(shared=request.user) - ).distinct().all() + recipe_books = RecipeBook.objects.filter(Q(created_by=request.user) | Q(shared=request.user), space=request.space).distinct().all() - for b in books: + for b in recipe_books: book_list.append( { 'book': b, @@ -209,32 +188,24 @@ def meal_plan(request): @group_required('user') def meal_plan_entry(request, pk): - plan = MealPlan.objects.get(pk=pk) + plan = MealPlan.objects.filter(space=request.space).get(pk=pk) if plan.created_by != request.user and plan.shared != request.user: - messages.add_message( - request, - messages.ERROR, - _('You do not have the required permissions to view this page!') - ) + messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!')) return HttpResponseRedirect(reverse_lazy('index')) same_day_plan = MealPlan.objects \ - .filter(date=plan.date) \ + .filter(date=plan.date, space=request.space) \ .exclude(pk=plan.pk) \ .filter(Q(created_by=request.user) | Q(shared=request.user)) \ .order_by('meal_type').all() - return render( - request, - 'meal_plan_entry.html', - {'plan': plan, 'same_day_plan': same_day_plan} - ) + return render(request, 'meal_plan_entry.html', {'plan': plan, 'same_day_plan': same_day_plan}) @group_required('user') def latest_shopping_list(request): - sl = ShoppingList.objects.filter(Q(created_by=request.user) | Q(shared=request.user)).filter(finished=False).order_by('-created_at').first() + sl = ShoppingList.objects.filter(Q(created_by=request.user) | Q(shared=request.user)).filter(finished=False, space=request.space).order_by('-created_at').first() if sl: return HttpResponseRedirect(reverse('view_shopping', kwargs={'pk': sl.pk}) + '?edit=true') @@ -251,7 +222,7 @@ def shopping_list(request, pk=None): r = r.replace('[', '').replace(']', '') if re.match(r'^([0-9])+,([0-9])+[.]*([0-9])*$', r): rid, multiplier = r.split(',') - if recipe := Recipe.objects.filter(pk=int(rid)).first(): + if recipe := Recipe.objects.filter(pk=int(rid), space=request.space).first(): recipes.append({'recipe': recipe.id, 'multiplier': multiplier}) edit = True if 'edit' in request.GET and request.GET['edit'] == 'true' else False @@ -317,23 +288,19 @@ def user_settings(request): if (api_token := Token.objects.filter(user=request.user).first()) is None: api_token = Token.objects.create(user=request.user) - return render( - request, - 'settings.html', - { - 'preference_form': preference_form, - 'user_name_form': user_name_form, - 'password_form': password_form, - 'api_token': api_token - } - ) + return render(request, 'settings.html', { + 'preference_form': preference_form, + 'user_name_form': user_name_form, + 'password_form': password_form, + 'api_token': api_token + }) @group_required('guest') def history(request): view_log = ViewLogTable( ViewLog.objects.filter( - created_by=request.user + created_by=request.user, space=request.space ).order_by('-created_at').all() ) cook_log = CookLogTable( @@ -341,11 +308,7 @@ def history(request): created_by=request.user ).order_by('-created_at').all() ) - return render( - request, - 'history.html', - {'view_log': view_log, 'cook_log': cook_log} - ) + return render(request, 'history.html', {'view_log': view_log, 'cook_log': cook_log}) @group_required('admin') @@ -357,28 +320,22 @@ def system(request): secret_key = False if os.getenv('SECRET_KEY') else True - return render( - request, - 'system.html', - { - 'gunicorn_media': settings.GUNICORN_MEDIA, - 'debug': settings.DEBUG, - 'postgres': postgres, - 'version': VERSION_NUMBER, - 'ref': BUILD_REF, - 'secret_key': secret_key - } - ) + return render(request, 'system.html', { + 'gunicorn_media': settings.GUNICORN_MEDIA, + 'debug': settings.DEBUG, + 'postgres': postgres, + 'version': VERSION_NUMBER, + 'ref': BUILD_REF, + 'secret_key': secret_key + }) def setup(request): if (User.objects.count() > 0 or 'django.contrib.auth.backends.RemoteUserBackend' in settings.AUTHENTICATION_BACKENDS): # noqa: E501 - messages.add_message( - request, - messages.ERROR, - _('The setup page can only be used to create the first user! If you have forgotten your superuser credentials please consult the django documentation on how to reset passwords.') # noqa: E501 - ) + messages.add_message(request, messages.ERROR, + _('The setup page can only be used to create the first user! If you have forgotten your superuser credentials please consult the django documentation on how to reset passwords.') # noqa: E501 + ) return HttpResponseRedirect(reverse('account_login')) if request.method == 'POST': @@ -415,14 +372,10 @@ def signup(request, token): try: token = UUID(token, version=4) except ValueError: - messages.add_message( - request, messages.ERROR, _('Malformed Invite Link supplied!') - ) + messages.add_message(request, messages.ERROR, _('Malformed Invite Link supplied!')) return HttpResponseRedirect(reverse('index')) - if link := InviteLink.objects.filter( - valid_until__gte=datetime.today(), used_by=None, uuid=token) \ - .first(): + if link := InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, uuid=token).first(): if request.method == 'POST': updated_request = request.POST.copy() if link.username != '': diff --git a/recipes/settings.py b/recipes/settings.py index 3105c67f1..f942e4511 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -101,6 +101,7 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'cookbook.helper.scope_middleware.ScopeMiddleware', ] # Auth related settings