added basic group permission system
This commit is contained in:
parent
c7046bc705
commit
ad467fae28
53
cookbook/helper/group_helper.py
Normal file
53
cookbook/helper/group_helper.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
Source: https://djangosnippets.org/snippets/1703/
|
||||||
|
"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
|
|
||||||
|
def get_allowed_groups(groups_required):
|
||||||
|
groups_allowed = tuple(groups_required)
|
||||||
|
if 'guest' in groups_required:
|
||||||
|
groups_allowed = groups_allowed + ('user', 'admin')
|
||||||
|
if 'user' in groups_required:
|
||||||
|
groups_allowed = groups_allowed + ('admin',)
|
||||||
|
return groups_allowed
|
||||||
|
|
||||||
|
|
||||||
|
def group_required(*groups_required):
|
||||||
|
"""Requires user membership in at least one of the groups passed in."""
|
||||||
|
|
||||||
|
def in_groups(u):
|
||||||
|
groups_allowed = get_allowed_groups(groups_required)
|
||||||
|
if u.is_authenticated:
|
||||||
|
if u.is_superuser | bool(u.groups.filter(name__in=groups_allowed)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
return user_passes_test(in_groups, login_url='index')
|
||||||
|
|
||||||
|
|
||||||
|
class GroupRequiredMixin(object):
|
||||||
|
"""
|
||||||
|
groups_required - list of strings, required param
|
||||||
|
"""
|
||||||
|
|
||||||
|
groups_required = None
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
if not request.user.is_authenticated:
|
||||||
|
messages.add_message(request, messages.ERROR, _('You are not logged in and therefore cannot view this page!'))
|
||||||
|
return HttpResponseRedirect(reverse_lazy('login'))
|
||||||
|
else:
|
||||||
|
if not request.user.is_superuser:
|
||||||
|
group_allowed = get_allowed_groups(self.groups_required)
|
||||||
|
user_groups = []
|
||||||
|
for group in request.user.groups.values_list('name', flat=True):
|
||||||
|
user_groups.append(group)
|
||||||
|
if len(set(user_groups).intersection(group_allowed)) <= 0:
|
||||||
|
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||||
|
return HttpResponseRedirect(reverse_lazy('index'))
|
||||||
|
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
|
22
cookbook/migrations/0034_auto_20200426_1614.py
Normal file
22
cookbook/migrations/0034_auto_20200426_1614.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 3.0.5 on 2020-04-26 14:14
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def apply_migration(apps, schema_editor):
|
||||||
|
Group = apps.get_model('auth', 'Group')
|
||||||
|
Group.objects.bulk_create([
|
||||||
|
Group(name=u'guest'),
|
||||||
|
Group(name=u'user'),
|
||||||
|
Group(name=u'admin'),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0033_userpreference_default_page'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(apply_migration)
|
||||||
|
]
|
@ -1,5 +1,5 @@
|
|||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User, Group
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
|
||||||
@ -11,14 +11,17 @@ class TestBase(TestCase):
|
|||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.client.force_login(User.objects.get_or_create(username='client')[0])
|
self.client.force_login(User.objects.get_or_create(username='client')[0])
|
||||||
user = auth.get_user(self.client)
|
user = auth.get_user(self.client)
|
||||||
|
user.groups.add(Group.objects.get(name='admin'))
|
||||||
self.assertTrue(user.is_authenticated)
|
self.assertTrue(user.is_authenticated)
|
||||||
|
|
||||||
self.another_client = Client()
|
self.another_client = Client()
|
||||||
self.another_client.force_login(User.objects.get_or_create(username='another_client')[0])
|
self.another_client.force_login(User.objects.get_or_create(username='another_client')[0])
|
||||||
user = auth.get_user(self.another_client)
|
user = auth.get_user(self.another_client)
|
||||||
|
user.groups.add(Group.objects.get(name='admin'))
|
||||||
self.assertTrue(user.is_authenticated)
|
self.assertTrue(user.is_authenticated)
|
||||||
|
|
||||||
self.superuser_client = Client()
|
self.superuser_client = Client()
|
||||||
self.superuser_client.force_login(User.objects.get_or_create(username='superuser_client', is_superuser=True)[0])
|
self.superuser_client.force_login(User.objects.get_or_create(username='superuser_client', is_superuser=True)[0])
|
||||||
user = auth.get_user(self.superuser_client)
|
user = auth.get_user(self.superuser_client)
|
||||||
|
user.groups.add(Group.objects.get(name='admin'))
|
||||||
self.assertTrue(user.is_authenticated)
|
self.assertTrue(user.is_authenticated)
|
||||||
|
@ -5,6 +5,7 @@ from django.utils.translation import gettext as _
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
|
from cookbook.helper.group_helper import group_required
|
||||||
from cookbook.models import Recipe, Sync, Storage
|
from cookbook.models import Recipe, Sync, Storage
|
||||||
from cookbook.provider.dropbox import Dropbox
|
from cookbook.provider.dropbox import Dropbox
|
||||||
from cookbook.provider.nextcloud import Nextcloud
|
from cookbook.provider.nextcloud import Nextcloud
|
||||||
@ -26,7 +27,7 @@ def update_recipe_links(recipe):
|
|||||||
recipe.save()
|
recipe.save()
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def get_external_file_link(request, recipe_id):
|
def get_external_file_link(request, recipe_id):
|
||||||
recipe = Recipe.objects.get(id=recipe_id)
|
recipe = Recipe.objects.get(id=recipe_id)
|
||||||
if not recipe.link:
|
if not recipe.link:
|
||||||
@ -35,7 +36,7 @@ def get_external_file_link(request, recipe_id):
|
|||||||
return HttpResponse(recipe.link)
|
return HttpResponse(recipe.link)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def get_recipe_file(request, recipe_id):
|
def get_recipe_file(request, recipe_id):
|
||||||
recipe = Recipe.objects.get(id=recipe_id)
|
recipe = Recipe.objects.get(id=recipe_id)
|
||||||
if not recipe.cors_link:
|
if not recipe.cors_link:
|
||||||
@ -44,7 +45,7 @@ def get_recipe_file(request, recipe_id):
|
|||||||
return HttpResponse(get_recipe_provider(recipe).get_base64_file(recipe))
|
return HttpResponse(get_recipe_provider(recipe).get_base64_file(recipe))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def sync_all(request):
|
def sync_all(request):
|
||||||
monitors = Sync.objects.filter(active=True)
|
monitors = Sync.objects.filter(active=True)
|
||||||
|
|
||||||
|
@ -7,11 +7,12 @@ from django.utils.translation import ngettext
|
|||||||
from django_tables2 import RequestConfig
|
from django_tables2 import RequestConfig
|
||||||
|
|
||||||
from cookbook.forms import SyncForm, BatchEditForm
|
from cookbook.forms import SyncForm, BatchEditForm
|
||||||
|
from cookbook.helper.group_helper import group_required
|
||||||
from cookbook.models import *
|
from cookbook.models import *
|
||||||
from cookbook.tables import SyncTable
|
from cookbook.tables import SyncTable
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def sync(request):
|
def sync(request):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = SyncForm(request.POST)
|
form = SyncForm(request.POST)
|
||||||
@ -31,12 +32,12 @@ def sync(request):
|
|||||||
return render(request, 'batch/monitor.html', {'form': form, 'monitored_paths': monitored_paths})
|
return render(request, 'batch/monitor.html', {'form': form, 'monitored_paths': monitored_paths})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def sync_wait(request):
|
def sync_wait(request):
|
||||||
return render(request, 'batch/waiting.html')
|
return render(request, 'batch/waiting.html')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def batch_import(request):
|
def batch_import(request):
|
||||||
imports = RecipeImport.objects.all()
|
imports = RecipeImport.objects.all()
|
||||||
for new_recipe in imports:
|
for new_recipe in imports:
|
||||||
@ -47,7 +48,7 @@ def batch_import(request):
|
|||||||
return redirect('list_recipe_import')
|
return redirect('list_recipe_import')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def batch_edit(request):
|
def batch_edit(request):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = BatchEditForm(request.POST)
|
form = BatchEditForm(request.POST)
|
||||||
@ -86,7 +87,7 @@ class Object(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def statistics(request):
|
def statistics(request):
|
||||||
counts = Object()
|
counts = Object()
|
||||||
counts.recipes = Recipe.objects.count()
|
counts.recipes = Recipe.objects.count()
|
||||||
|
@ -5,13 +5,15 @@ from django.urls import reverse_lazy, reverse
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.generic import DeleteView
|
from django.views.generic import DeleteView
|
||||||
|
|
||||||
|
from cookbook.helper.group_helper import GroupRequiredMixin
|
||||||
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeBook, \
|
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeBook, \
|
||||||
RecipeBookEntry, MealPlan, Ingredient
|
RecipeBookEntry, MealPlan, Ingredient
|
||||||
from cookbook.provider.dropbox import Dropbox
|
from cookbook.provider.dropbox import Dropbox
|
||||||
from cookbook.provider.nextcloud import Nextcloud
|
from cookbook.provider.nextcloud import Nextcloud
|
||||||
|
|
||||||
|
|
||||||
class RecipeDelete(LoginRequiredMixin, DeleteView):
|
class RecipeDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = Recipe
|
model = Recipe
|
||||||
success_url = reverse_lazy('index')
|
success_url = reverse_lazy('index')
|
||||||
@ -23,6 +25,7 @@ class RecipeDelete(LoginRequiredMixin, DeleteView):
|
|||||||
|
|
||||||
|
|
||||||
def delete_recipe_source(request, pk):
|
def delete_recipe_source(request, pk):
|
||||||
|
group_required = ['user']
|
||||||
recipe = get_object_or_404(Recipe, pk=pk)
|
recipe = get_object_or_404(Recipe, pk=pk)
|
||||||
|
|
||||||
if recipe.storage.method == Storage.DROPBOX:
|
if recipe.storage.method == Storage.DROPBOX:
|
||||||
@ -38,7 +41,8 @@ def delete_recipe_source(request, pk):
|
|||||||
return HttpResponseRedirect(reverse('edit_recipe', args=[recipe.pk]))
|
return HttpResponseRedirect(reverse('edit_recipe', args=[recipe.pk]))
|
||||||
|
|
||||||
|
|
||||||
class RecipeImportDelete(LoginRequiredMixin, DeleteView):
|
class RecipeImportDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = RecipeImport
|
model = RecipeImport
|
||||||
success_url = reverse_lazy('list_recipe_import')
|
success_url = reverse_lazy('list_recipe_import')
|
||||||
@ -49,7 +53,8 @@ class RecipeImportDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class SyncDelete(LoginRequiredMixin, DeleteView):
|
class SyncDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['admin']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = Sync
|
model = Sync
|
||||||
success_url = reverse_lazy('data_sync')
|
success_url = reverse_lazy('data_sync')
|
||||||
@ -60,7 +65,8 @@ class SyncDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class KeywordDelete(LoginRequiredMixin, DeleteView):
|
class KeywordDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = Keyword
|
model = Keyword
|
||||||
success_url = reverse_lazy('list_keyword')
|
success_url = reverse_lazy('list_keyword')
|
||||||
@ -71,7 +77,8 @@ class KeywordDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class IngredientDelete(LoginRequiredMixin, DeleteView):
|
class IngredientDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = Ingredient
|
model = Ingredient
|
||||||
success_url = reverse_lazy('list_ingredient')
|
success_url = reverse_lazy('list_ingredient')
|
||||||
@ -82,7 +89,8 @@ class IngredientDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StorageDelete(LoginRequiredMixin, DeleteView):
|
class StorageDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['admin']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = Storage
|
model = Storage
|
||||||
success_url = reverse_lazy('list_storage')
|
success_url = reverse_lazy('list_storage')
|
||||||
@ -104,7 +112,8 @@ class CommentDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class RecipeBookDelete(LoginRequiredMixin, DeleteView):
|
class RecipeBookDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = RecipeBook
|
model = RecipeBook
|
||||||
success_url = reverse_lazy('view_books')
|
success_url = reverse_lazy('view_books')
|
||||||
@ -115,7 +124,8 @@ class RecipeBookDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class RecipeBookEntryDelete(LoginRequiredMixin, DeleteView):
|
class RecipeBookEntryDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = RecipeBookEntry
|
model = RecipeBookEntry
|
||||||
success_url = reverse_lazy('view_books')
|
success_url = reverse_lazy('view_books')
|
||||||
@ -126,7 +136,8 @@ class RecipeBookEntryDelete(LoginRequiredMixin, DeleteView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MealPlanDelete(LoginRequiredMixin, DeleteView):
|
class MealPlanDelete(GroupRequiredMixin, DeleteView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/delete_template.html"
|
template_name = "generic/delete_template.html"
|
||||||
model = MealPlan
|
model = MealPlan
|
||||||
success_url = reverse_lazy('view_plan')
|
success_url = reverse_lazy('view_plan')
|
||||||
|
@ -5,7 +5,6 @@ import simplejson
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
@ -16,13 +15,14 @@ from django.views.generic import UpdateView
|
|||||||
|
|
||||||
from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, \
|
from cookbook.forms import ExternalRecipeForm, KeywordForm, StorageForm, SyncForm, InternalRecipeForm, CommentForm, \
|
||||||
MealPlanForm, UnitMergeForm, IngredientMergeForm, IngredientForm
|
MealPlanForm, UnitMergeForm, IngredientMergeForm, IngredientForm
|
||||||
|
from cookbook.helper.group_helper import group_required, GroupRequiredMixin
|
||||||
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeIngredient, RecipeBook, \
|
from cookbook.models import Recipe, Sync, Keyword, RecipeImport, Storage, Comment, RecipeIngredient, RecipeBook, \
|
||||||
MealPlan, Unit, Ingredient
|
MealPlan, Unit, Ingredient
|
||||||
from cookbook.provider.dropbox import Dropbox
|
from cookbook.provider.dropbox import Dropbox
|
||||||
from cookbook.provider.nextcloud import Nextcloud
|
from cookbook.provider.nextcloud import Nextcloud
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@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)
|
||||||
if recipe.internal:
|
if recipe.internal:
|
||||||
@ -31,7 +31,7 @@ def switch_recipe(request, pk):
|
|||||||
return HttpResponseRedirect(reverse('edit_external_recipe', args=[pk]))
|
return HttpResponseRedirect(reverse('edit_external_recipe', args=[pk]))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@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)
|
||||||
if not recipe.internal:
|
if not recipe.internal:
|
||||||
@ -41,7 +41,7 @@ def convert_recipe(request, pk):
|
|||||||
return HttpResponseRedirect(reverse('edit_internal_recipe', args=[pk]))
|
return HttpResponseRedirect(reverse('edit_internal_recipe', args=[pk]))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@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)
|
||||||
status = 200
|
status = 200
|
||||||
@ -131,7 +131,8 @@ def internal_recipe_update(request, pk):
|
|||||||
'view_url': reverse('view_recipe', args=[pk])}, status=status)
|
'view_url': reverse('view_recipe', args=[pk])}, status=status)
|
||||||
|
|
||||||
|
|
||||||
class SyncUpdate(LoginRequiredMixin, UpdateView):
|
class SyncUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['admin']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = Sync
|
model = Sync
|
||||||
form_class = SyncForm
|
form_class = SyncForm
|
||||||
@ -147,7 +148,8 @@ class SyncUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class KeywordUpdate(LoginRequiredMixin, UpdateView):
|
class KeywordUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = Keyword
|
model = Keyword
|
||||||
form_class = KeywordForm
|
form_class = KeywordForm
|
||||||
@ -163,7 +165,8 @@ class KeywordUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class IngredientUpdate(LoginRequiredMixin, UpdateView):
|
class IngredientUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = Ingredient
|
model = Ingredient
|
||||||
form_class = IngredientForm
|
form_class = IngredientForm
|
||||||
@ -179,7 +182,7 @@ class IngredientUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@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)
|
||||||
|
|
||||||
@ -239,7 +242,8 @@ class CommentUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ImportUpdate(LoginRequiredMixin, UpdateView):
|
class ImportUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = RecipeImport
|
model = RecipeImport
|
||||||
fields = ['name', 'path']
|
fields = ['name', 'path']
|
||||||
@ -255,7 +259,8 @@ class ImportUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class RecipeBookUpdate(LoginRequiredMixin, UpdateView):
|
class RecipeBookUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = RecipeBook
|
model = RecipeBook
|
||||||
fields = ['name']
|
fields = ['name']
|
||||||
@ -271,7 +276,8 @@ class RecipeBookUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MealPlanUpdate(LoginRequiredMixin, UpdateView):
|
class MealPlanUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
model = MealPlan
|
model = MealPlan
|
||||||
form_class = MealPlanForm
|
form_class = MealPlanForm
|
||||||
@ -287,7 +293,8 @@ class MealPlanUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ExternalRecipeUpdate(LoginRequiredMixin, UpdateView):
|
class ExternalRecipeUpdate(GroupRequiredMixin, UpdateView):
|
||||||
|
groups_required = ['user']
|
||||||
model = Recipe
|
model = Recipe
|
||||||
form_class = ExternalRecipeForm
|
form_class = ExternalRecipeForm
|
||||||
template_name = "generic/edit_template.html"
|
template_name = "generic/edit_template.html"
|
||||||
@ -322,7 +329,7 @@ class ExternalRecipeUpdate(LoginRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def edit_ingredients(request):
|
def edit_ingredients(request):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
success = False
|
success = False
|
||||||
|
@ -11,9 +11,11 @@ from django.urls import reverse_lazy
|
|||||||
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from cookbook.forms import ExportForm, ImportForm
|
from cookbook.forms import ExportForm, ImportForm
|
||||||
|
from cookbook.helper.group_helper import group_required
|
||||||
from cookbook.models import RecipeIngredient, Recipe, Unit, Ingredient, Keyword
|
from cookbook.models import RecipeIngredient, Recipe, Unit, Ingredient, Keyword
|
||||||
|
|
||||||
|
|
||||||
|
@group_required('user')
|
||||||
def import_recipe(request):
|
def import_recipe(request):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ImportForm(request.POST)
|
form = ImportForm(request.POST)
|
||||||
@ -62,6 +64,7 @@ def import_recipe(request):
|
|||||||
return render(request, 'import.html', {'form': form})
|
return render(request, 'import.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
|
@group_required('user')
|
||||||
def export_recipe(request):
|
def export_recipe(request):
|
||||||
context = {}
|
context = {}
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models.functions import Lower
|
from django.db.models.functions import Lower
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django_tables2 import RequestConfig
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from django_tables2 import RequestConfig
|
||||||
|
|
||||||
from cookbook.filters import IngredientFilter
|
from cookbook.filters import IngredientFilter
|
||||||
|
from cookbook.helper.group_helper import group_required
|
||||||
from cookbook.models import Keyword, SyncLog, RecipeImport, Storage, Ingredient
|
from cookbook.models import Keyword, SyncLog, RecipeImport, Storage, Ingredient
|
||||||
from cookbook.tables import KeywordTable, ImportLogTable, RecipeImportTable, StorageTable, IngredientTable
|
from cookbook.tables import KeywordTable, ImportLogTable, RecipeImportTable, StorageTable, IngredientTable
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def keyword(request):
|
def keyword(request):
|
||||||
table = KeywordTable(Keyword.objects.all())
|
table = KeywordTable(Keyword.objects.all())
|
||||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||||
@ -18,7 +18,7 @@ def keyword(request):
|
|||||||
return render(request, 'generic/list_template.html', {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'})
|
return render(request, 'generic/list_template.html', {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('admin')
|
||||||
def sync_log(request):
|
def sync_log(request):
|
||||||
table = ImportLogTable(SyncLog.objects.all().order_by(Lower('created_at').desc()))
|
table = ImportLogTable(SyncLog.objects.all().order_by(Lower('created_at').desc()))
|
||||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||||
@ -26,7 +26,7 @@ def sync_log(request):
|
|||||||
return render(request, 'generic/list_template.html', {'title': _("Import Log"), 'table': table})
|
return render(request, 'generic/list_template.html', {'title': _("Import Log"), 'table': table})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def recipe_import(request):
|
def recipe_import(request):
|
||||||
table = RecipeImportTable(RecipeImport.objects.all())
|
table = RecipeImportTable(RecipeImport.objects.all())
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ def recipe_import(request):
|
|||||||
return render(request, 'generic/list_template.html', {'title': _("Discovery"), 'table': table, 'import_btn': True})
|
return render(request, 'generic/list_template.html', {'title': _("Discovery"), 'table': table, 'import_btn': True})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def ingredient(request):
|
def ingredient(request):
|
||||||
f = IngredientFilter(request.GET, queryset=Ingredient.objects.all().order_by('pk'))
|
f = IngredientFilter(request.GET, queryset=Ingredient.objects.all().order_by('pk'))
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ def ingredient(request):
|
|||||||
return render(request, 'generic/list_template.html', {'title': _("Ingredients"), 'table': table, 'filter': f})
|
return render(request, 'generic/list_template.html', {'title': _("Ingredients"), 'table': table, 'filter': f})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('admin')
|
||||||
def storage(request):
|
def storage(request):
|
||||||
table = StorageTable(Storage.objects.all())
|
table = StorageTable(Storage.objects.all())
|
||||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||||
|
@ -2,8 +2,6 @@ import re
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
@ -12,10 +10,12 @@ from django.views.generic import CreateView
|
|||||||
|
|
||||||
from cookbook.forms import ImportRecipeForm, RecipeImport, KeywordForm, Storage, StorageForm, InternalRecipeForm, \
|
from cookbook.forms import ImportRecipeForm, RecipeImport, KeywordForm, Storage, StorageForm, InternalRecipeForm, \
|
||||||
RecipeBookForm, MealPlanForm
|
RecipeBookForm, MealPlanForm
|
||||||
|
from cookbook.helper.group_helper import GroupRequiredMixin, group_required
|
||||||
from cookbook.models import Keyword, Recipe, RecipeBook, MealPlan
|
from cookbook.models import Keyword, Recipe, RecipeBook, MealPlan
|
||||||
|
|
||||||
|
|
||||||
class RecipeCreate(LoginRequiredMixin, CreateView):
|
class RecipeCreate(GroupRequiredMixin, CreateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/new_template.html"
|
template_name = "generic/new_template.html"
|
||||||
model = Recipe
|
model = Recipe
|
||||||
fields = ('name',)
|
fields = ('name',)
|
||||||
@ -36,7 +36,8 @@ class RecipeCreate(LoginRequiredMixin, CreateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class KeywordCreate(LoginRequiredMixin, CreateView):
|
class KeywordCreate(GroupRequiredMixin, CreateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/new_template.html"
|
template_name = "generic/new_template.html"
|
||||||
model = Keyword
|
model = Keyword
|
||||||
form_class = KeywordForm
|
form_class = KeywordForm
|
||||||
@ -48,7 +49,8 @@ class KeywordCreate(LoginRequiredMixin, CreateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StorageCreate(LoginRequiredMixin, CreateView):
|
class StorageCreate(GroupRequiredMixin, CreateView):
|
||||||
|
groups_required = ['admin']
|
||||||
template_name = "generic/new_template.html"
|
template_name = "generic/new_template.html"
|
||||||
model = Storage
|
model = Storage
|
||||||
form_class = StorageForm
|
form_class = StorageForm
|
||||||
@ -66,7 +68,7 @@ class StorageCreate(LoginRequiredMixin, CreateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def create_new_external_recipe(request, import_id):
|
def create_new_external_recipe(request, import_id):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ImportRecipeForm(request.POST)
|
form = ImportRecipeForm(request.POST)
|
||||||
@ -97,7 +99,8 @@ def create_new_external_recipe(request, import_id):
|
|||||||
return render(request, 'forms/edit_import_recipe.html', {'form': form})
|
return render(request, 'forms/edit_import_recipe.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
class RecipeBookCreate(LoginRequiredMixin, CreateView):
|
class RecipeBookCreate(GroupRequiredMixin, CreateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/new_template.html"
|
template_name = "generic/new_template.html"
|
||||||
model = RecipeBook
|
model = RecipeBook
|
||||||
form_class = RecipeBookForm
|
form_class = RecipeBookForm
|
||||||
@ -115,7 +118,8 @@ class RecipeBookCreate(LoginRequiredMixin, CreateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MealPlanCreate(LoginRequiredMixin, CreateView):
|
class MealPlanCreate(GroupRequiredMixin, CreateView):
|
||||||
|
groups_required = ['user']
|
||||||
template_name = "generic/new_template.html"
|
template_name = "generic/new_template.html"
|
||||||
model = MealPlan
|
model = MealPlan
|
||||||
form_class = MealPlanForm
|
form_class = MealPlanForm
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import copy
|
import copy
|
||||||
import re
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import update_session_auth_hash
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
from django.contrib.auth.forms import PasswordChangeForm
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
@ -14,6 +12,7 @@ from django.utils.translation import gettext as _
|
|||||||
|
|
||||||
from cookbook.filters import RecipeFilter
|
from cookbook.filters import RecipeFilter
|
||||||
from cookbook.forms import *
|
from cookbook.forms import *
|
||||||
|
from cookbook.helper.group_helper import group_required
|
||||||
from cookbook.tables import RecipeTable
|
from cookbook.tables import RecipeTable
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ def search(request):
|
|||||||
return render(request, 'index.html')
|
return render(request, 'index.html')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('guest')
|
||||||
def recipe_view(request, pk):
|
def recipe_view(request, pk):
|
||||||
recipe = get_object_or_404(Recipe, pk=pk)
|
recipe = get_object_or_404(Recipe, pk=pk)
|
||||||
ingredients = RecipeIngredient.objects.filter(recipe=recipe)
|
ingredients = RecipeIngredient.objects.filter(recipe=recipe)
|
||||||
@ -80,7 +79,7 @@ def recipe_view(request, pk):
|
|||||||
'bookmark_form': bookmark_form})
|
'bookmark_form': bookmark_form})
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
@group_required('user')
|
||||||
def books(request):
|
def books(request):
|
||||||
book_list = []
|
book_list = []
|
||||||
|
|
||||||
@ -106,7 +105,7 @@ def get_days_from_week(start, end):
|
|||||||
return days
|
return days
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
@group_required('user')
|
||||||
def meal_plan(request):
|
def meal_plan(request):
|
||||||
js_week = datetime.now().strftime("%Y-W%V")
|
js_week = datetime.now().strftime("%Y-W%V")
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
@ -134,7 +133,7 @@ def meal_plan(request):
|
|||||||
return render(request, 'meal_plan.html', {'js_week': js_week, 'plan': plan, 'days': days, 'surrounding_weeks': surrounding_weeks})
|
return render(request, 'meal_plan.html', {'js_week': js_week, 'plan': plan, 'days': days, 'surrounding_weeks': surrounding_weeks})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('user')
|
||||||
def shopping_list(request):
|
def shopping_list(request):
|
||||||
markdown_format = True
|
markdown_format = True
|
||||||
|
|
||||||
@ -174,7 +173,7 @@ def shopping_list(request):
|
|||||||
return render(request, 'shopping_list.html', {'ingredients': ingredients, 'recipes': recipes, 'form': form, 'markdown_format': markdown_format})
|
return render(request, 'shopping_list.html', {'ingredients': ingredients, 'recipes': recipes, 'form': form, 'markdown_format': markdown_format})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@group_required('guest')
|
||||||
def settings(request):
|
def settings(request):
|
||||||
try:
|
try:
|
||||||
up = request.user.userpreference
|
up = request.user.userpreference
|
||||||
|
Loading…
Reference in New Issue
Block a user