usr signup and more
This commit is contained in:
@ -1,4 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
||||||
from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
|
from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
|
||||||
MealPlan, MealType, NutritionInformation, Recipe,
|
MealPlan, MealType, NutritionInformation, Recipe,
|
||||||
@ -8,6 +10,17 @@ from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
|
|||||||
ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation)
|
ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomUserAdmin(UserAdmin):
|
||||||
|
def has_add_permission(self, request, obj=None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.unregister(User)
|
||||||
|
admin.site.register(User, CustomUserAdmin)
|
||||||
|
|
||||||
|
admin.site.unregister(Group)
|
||||||
|
|
||||||
|
|
||||||
class SpaceAdmin(admin.ModelAdmin):
|
class SpaceAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'message')
|
list_display = ('name', 'message')
|
||||||
|
|
||||||
@ -16,10 +29,7 @@ admin.site.register(Space, SpaceAdmin)
|
|||||||
|
|
||||||
|
|
||||||
class UserPreferenceAdmin(admin.ModelAdmin):
|
class UserPreferenceAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = ('name', 'space', 'theme', 'nav_color', 'default_page', 'search_style',)
|
||||||
'name', 'theme', 'nav_color',
|
|
||||||
'default_page', 'search_style', 'comments'
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def name(obj):
|
def name(obj):
|
||||||
|
@ -6,7 +6,7 @@ from emoji_picker.widgets import EmojiPickerTextInput
|
|||||||
|
|
||||||
from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe,
|
from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe,
|
||||||
RecipeBook, RecipeBookEntry, Storage, Sync, Unit, User,
|
RecipeBook, RecipeBookEntry, Storage, Sync, Unit, User,
|
||||||
UserPreference, SupermarketCategory, MealType)
|
UserPreference, SupermarketCategory, MealType, Space)
|
||||||
|
|
||||||
|
|
||||||
class SelectWidget(widgets.Select):
|
class SelectWidget(widgets.Select):
|
||||||
@ -371,12 +371,20 @@ class MealPlanForm(forms.ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class InviteLinkForm(forms.ModelForm):
|
class InviteLinkForm(forms.ModelForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
user = kwargs.pop('user')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['space'].queryset = Space.objects.filter(created_by=user).all()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InviteLink
|
model = InviteLink
|
||||||
fields = ('username', 'group', 'valid_until')
|
fields = ('username', 'group', 'valid_until', 'space')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'username': _('A username is not required, if left blank the new user can choose one.') # noqa: E501
|
'username': _('A username is not required, if left blank the new user can choose one.') # noqa: E501
|
||||||
}
|
}
|
||||||
|
field_classes = {
|
||||||
|
'space': SafeModelChoiceField,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class UserCreateForm(forms.Form):
|
class UserCreateForm(forms.Form):
|
||||||
|
@ -123,9 +123,13 @@ class GroupRequiredMixin(object):
|
|||||||
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'))
|
return HttpResponseRedirect(reverse_lazy('index'))
|
||||||
|
|
||||||
if self.get_object().get_space() != request.space:
|
try:
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.get_space() != request.space:
|
||||||
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'))
|
return HttpResponseRedirect(reverse_lazy('index'))
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
|
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
@ -141,9 +145,13 @@ class OwnerRequiredMixin(object):
|
|||||||
messages.add_message(request, messages.ERROR, _('You cannot interact with this object as it is not owned by you!'))
|
messages.add_message(request, messages.ERROR, _('You cannot interact with this object as it is not owned by you!'))
|
||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
|
|
||||||
if self.get_object().get_space() != request.space:
|
try:
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.get_space() != request.space:
|
||||||
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'))
|
return HttpResponseRedirect(reverse_lazy('index'))
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
return super(OwnerRequiredMixin, self).dispatch(request, *args, **kwargs)
|
return super(OwnerRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.urls import reverse
|
||||||
from django_scopes import scope, scopes_disabled
|
from django_scopes import scope, scopes_disabled
|
||||||
|
|
||||||
|
|
||||||
@ -7,10 +9,21 @@ class ScopeMiddleware:
|
|||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
request.space = request.user.userpreference.space
|
|
||||||
|
if request.user.groups.count() == 0:
|
||||||
|
return redirect('view_no_group')
|
||||||
|
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
#with scope(space=request.space):
|
if request.user.userpreference.space is None and not reverse('view_no_space') in request.path and not reverse('account_logout') in request.path:
|
||||||
|
return redirect(reverse('view_no_space'))
|
||||||
|
|
||||||
|
if request.path.startswith('/admin/'):
|
||||||
|
with scopes_disabled():
|
||||||
|
return self.get_response(request)
|
||||||
|
|
||||||
|
request.space = request.user.userpreference.space
|
||||||
|
# with scopes_disabled():
|
||||||
|
with scope(space=request.space):
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
else:
|
else:
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
@ -27,7 +27,8 @@ class Integration:
|
|||||||
self.keyword = Keyword.objects.create(
|
self.keyword = Keyword.objects.create(
|
||||||
name=f'Import {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}.{datetime.datetime.now().strftime("%S")}',
|
name=f'Import {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}.{datetime.datetime.now().strftime("%S")}',
|
||||||
description=f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}',
|
description=f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}',
|
||||||
icon='📥'
|
icon='📥',
|
||||||
|
space=request.space
|
||||||
)
|
)
|
||||||
|
|
||||||
def do_export(self, recipes):
|
def do_export(self, recipes):
|
||||||
|
63
cookbook/migrations/0109_auto_20210221_1204.py
Normal file
63
cookbook/migrations/0109_auto_20210221_1204.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Generated by Django 3.1.6 on 2021-02-21 11:04
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0108_auto_20210219_1410'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='recipebookentry',
|
||||||
|
name='space',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='food',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128, validators=[django.core.validators.MinLengthValidator(1)]),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='keyword',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=64),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supermarket',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128, validators=[django.core.validators.MinLengthValidator(1)]),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supermarketcategory',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128, validators=[django.core.validators.MinLengthValidator(1)]),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='unit',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=128, validators=[django.core.validators.MinLengthValidator(1)]),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='food',
|
||||||
|
unique_together={('space', 'name')},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='keyword',
|
||||||
|
unique_together={('space', 'name')},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='supermarket',
|
||||||
|
unique_together={('space', 'name')},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='supermarketcategory',
|
||||||
|
unique_together={('space', 'name')},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='unit',
|
||||||
|
unique_together={('space', 'name')},
|
||||||
|
),
|
||||||
|
]
|
19
cookbook/migrations/0110_auto_20210221_1406.py
Normal file
19
cookbook/migrations/0110_auto_20210221_1406.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.1.6 on 2021-02-21 13:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0109_auto_20210221_1204'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='userpreference',
|
||||||
|
name='space',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
|
),
|
||||||
|
]
|
32
cookbook/migrations/0111_space_created_by.py
Normal file
32
cookbook/migrations/0111_space_created_by.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 3.1.6 on 2021-02-21 13:19
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
|
||||||
|
def set_default_owner(apps, schema_editor):
|
||||||
|
Space = apps.get_model('cookbook', 'Space')
|
||||||
|
User = apps.get_model('auth', 'user')
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
for x in Space.objects.all():
|
||||||
|
x.created_by = User.objects.filter(is_superuser=True).first()
|
||||||
|
x.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('cookbook', '0110_auto_20210221_1406'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='space',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.RunPython(set_default_owner),
|
||||||
|
]
|
@ -45,8 +45,12 @@ class PermissionModelMixin:
|
|||||||
|
|
||||||
class Space(models.Model):
|
class Space(models.Model):
|
||||||
name = models.CharField(max_length=128, default='Default')
|
name = models.CharField(max_length=128, default='Default')
|
||||||
|
created_by = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
|
||||||
message = models.CharField(max_length=512, default='', blank=True)
|
message = models.CharField(max_length=512, default='', blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class UserPreference(models.Model, PermissionModelMixin):
|
class UserPreference(models.Model, PermissionModelMixin):
|
||||||
# Themes
|
# Themes
|
||||||
@ -121,7 +125,7 @@ class UserPreference(models.Model, PermissionModelMixin):
|
|||||||
shopping_auto_sync = models.IntegerField(default=5)
|
shopping_auto_sync = models.IntegerField(default=5)
|
||||||
sticky_navbar = models.BooleanField(default=STICKY_NAV_PREF_DEFAULT)
|
sticky_navbar = models.BooleanField(default=STICKY_NAV_PREF_DEFAULT)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE, null=True)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -168,7 +172,7 @@ class Sync(models.Model, PermissionModelMixin):
|
|||||||
|
|
||||||
|
|
||||||
class SupermarketCategory(models.Model, PermissionModelMixin):
|
class SupermarketCategory(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
@ -177,9 +181,12 @@ class SupermarketCategory(models.Model, PermissionModelMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('space', 'name'),)
|
||||||
|
|
||||||
|
|
||||||
class Supermarket(models.Model, PermissionModelMixin):
|
class Supermarket(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
||||||
|
|
||||||
@ -189,6 +196,9 @@ class Supermarket(models.Model, PermissionModelMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('space', 'name'),)
|
||||||
|
|
||||||
|
|
||||||
class SupermarketCategoryRelation(models.Model, PermissionModelMixin):
|
class SupermarketCategoryRelation(models.Model, PermissionModelMixin):
|
||||||
supermarket = models.ForeignKey(Supermarket, on_delete=models.CASCADE, related_name='category_to_supermarket')
|
supermarket = models.ForeignKey(Supermarket, on_delete=models.CASCADE, related_name='category_to_supermarket')
|
||||||
@ -218,7 +228,7 @@ class SyncLog(models.Model, PermissionModelMixin):
|
|||||||
|
|
||||||
|
|
||||||
class Keyword(models.Model, PermissionModelMixin):
|
class Keyword(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(max_length=64, unique=True)
|
name = models.CharField(max_length=64)
|
||||||
icon = models.CharField(max_length=16, blank=True, null=True)
|
icon = models.CharField(max_length=16, blank=True, null=True)
|
||||||
description = models.TextField(default="", blank=True)
|
description = models.TextField(default="", blank=True)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
@ -233,9 +243,12 @@ class Keyword(models.Model, PermissionModelMixin):
|
|||||||
else:
|
else:
|
||||||
return f"{self.name}"
|
return f"{self.name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('space', 'name'),)
|
||||||
|
|
||||||
|
|
||||||
class Unit(models.Model, PermissionModelMixin):
|
class Unit(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
@ -244,9 +257,12 @@ class Unit(models.Model, PermissionModelMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('space', 'name'),)
|
||||||
|
|
||||||
|
|
||||||
class Food(models.Model, PermissionModelMixin):
|
class Food(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(unique=True, max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
recipe = models.ForeignKey('Recipe', null=True, blank=True, on_delete=models.SET_NULL)
|
recipe = models.ForeignKey('Recipe', null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
supermarket_category = models.ForeignKey(SupermarketCategory, null=True, blank=True, on_delete=models.SET_NULL)
|
supermarket_category = models.ForeignKey(SupermarketCategory, null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
ignore_shopping = models.BooleanField(default=False)
|
ignore_shopping = models.BooleanField(default=False)
|
||||||
@ -258,6 +274,9 @@ class Food(models.Model, PermissionModelMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (('space', 'name'),)
|
||||||
|
|
||||||
|
|
||||||
class Ingredient(models.Model, PermissionModelMixin):
|
class Ingredient(models.Model, PermissionModelMixin):
|
||||||
food = models.ForeignKey(Food, on_delete=models.PROTECT, null=True, blank=True)
|
food = models.ForeignKey(Food, on_delete=models.PROTECT, null=True, blank=True)
|
||||||
|
@ -111,17 +111,12 @@ class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
|||||||
return str(obj)
|
return str(obj)
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
obj, created = Keyword.objects.get_or_create(name=validated_data['name'], space=self.context['request'].space)
|
||||||
# duplicate names might be routed to create
|
|
||||||
obj, created = Keyword.objects.get_or_create(name=validated_data['name'])
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Keyword
|
model = Keyword
|
||||||
fields = (
|
fields = ('id', 'name', 'icon', 'label', 'description', 'created_at', 'updated_at')
|
||||||
'id', 'name', 'icon', 'label', 'description',
|
|
||||||
'created_at', 'updated_at'
|
|
||||||
)
|
|
||||||
|
|
||||||
read_only_fields = ('id',)
|
read_only_fields = ('id',)
|
||||||
|
|
||||||
@ -129,9 +124,7 @@ class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
|||||||
class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
obj, created = Unit.objects.get_or_create(name=validated_data['name'], space=self.context['request'].space)
|
||||||
# duplicate names might be routed to create
|
|
||||||
obj, created = Unit.objects.get_or_create(name=validated_data['name'])
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -143,9 +136,7 @@ class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
|||||||
class SupermarketCategorySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
class SupermarketCategorySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
obj, created = SupermarketCategory.objects.get_or_create(name=validated_data['name'], space=self.context['request'].space)
|
||||||
# duplicate names might be routed to create
|
|
||||||
obj, created = SupermarketCategory.objects.get_or_create(name=validated_data['name'])
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
@ -176,9 +167,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
|||||||
supermarket_category = SupermarketCategorySerializer(allow_null=True, required=False)
|
supermarket_category = SupermarketCategorySerializer(allow_null=True, required=False)
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
obj, created = Food.objects.get_or_create(name=validated_data['name'], space=self.context['request'].space)
|
||||||
# duplicate names might be routed to create
|
|
||||||
obj, created = Food.objects.get_or_create(name=validated_data['name'])
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
@ -256,6 +245,7 @@ class RecipeSerializer(WritableNestedModelSerializer):
|
|||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['created_by'] = self.context['request'].user
|
validated_data['created_by'] = self.context['request'].user
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
|
||||||
@ -455,4 +445,5 @@ class RecipeExportSerializer(WritableNestedModelSerializer):
|
|||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['created_by'] = self.context['request'].user
|
validated_data['created_by'] = self.context['request'].user
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{% trans "Offline" %}{% endblock %}
|
{% block title %}{% trans "No Permissions" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
20
cookbook/templates/no_space_info.html
Normal file
20
cookbook/templates/no_space_info.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block title %}{% trans "No Space" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div style="text-align: center">
|
||||||
|
|
||||||
|
<h1 class="">{% trans 'No Space' %}</h1>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<span>{% trans 'You are not a member of any space. Please contact your administrator.' %}</span> <br/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -40,6 +40,7 @@ urlpatterns = [
|
|||||||
path('', views.index, name='index'),
|
path('', views.index, name='index'),
|
||||||
path('setup/', views.setup, name='view_setup'),
|
path('setup/', views.setup, name='view_setup'),
|
||||||
path('no-group', views.no_groups, name='view_no_group'),
|
path('no-group', views.no_groups, name='view_no_group'),
|
||||||
|
path('no-space', views.no_space, name='view_no_space'),
|
||||||
path('signup/<slug:token>', views.signup, name='view_signup'),
|
path('signup/<slug:token>', views.signup, name='view_signup'),
|
||||||
path('system/', views.system, name='view_system'),
|
path('system/', views.system, name='view_system'),
|
||||||
path('search/', views.search, name='view_search'),
|
path('search/', views.search, name='view_search'),
|
||||||
@ -105,7 +106,6 @@ urlpatterns = [
|
|||||||
|
|
||||||
path('offline/', views.offline, name='view_offline'),
|
path('offline/', views.offline, name='view_offline'),
|
||||||
|
|
||||||
|
|
||||||
path('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )), name='service_worker'),
|
path('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )), name='service_worker'),
|
||||||
path('manifest.json', (TemplateView.as_view(template_name="manifest.json", content_type='application/json', )), name='web_manifest'),
|
path('manifest.json', (TemplateView.as_view(template_name="manifest.json", content_type='application/json', )), name='web_manifest'),
|
||||||
]
|
]
|
||||||
|
@ -212,3 +212,8 @@ class InviteLinkCreate(GroupRequiredMixin, CreateView):
|
|||||||
context = super(InviteLinkCreate, self).get_context_data(**kwargs)
|
context = super(InviteLinkCreate, self).get_context_data(**kwargs)
|
||||||
context['title'] = _("Invite Link")
|
context['title'] = _("Invite Link")
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super().get_form_kwargs()
|
||||||
|
kwargs.update({'user': self.request.user})
|
||||||
|
return kwargs
|
||||||
|
@ -26,7 +26,7 @@ from cookbook.forms import (CommentForm, Recipe, RecipeBookEntryForm, User,
|
|||||||
UserPreferenceForm)
|
UserPreferenceForm)
|
||||||
from cookbook.helper.permission_helper import group_required, share_link_valid, has_group_permission
|
from cookbook.helper.permission_helper import group_required, share_link_valid, has_group_permission
|
||||||
from cookbook.models import (Comment, CookLog, InviteLink, MealPlan,
|
from cookbook.models import (Comment, CookLog, InviteLink, MealPlan,
|
||||||
RecipeBook, RecipeBookEntry, ViewLog, ShoppingList)
|
RecipeBook, RecipeBookEntry, ViewLog, ShoppingList, Space)
|
||||||
from cookbook.tables import (CookLogTable, RecipeTable, RecipeTableSmall,
|
from cookbook.tables import (CookLogTable, RecipeTable, RecipeTableSmall,
|
||||||
ViewLogTable)
|
ViewLogTable)
|
||||||
from recipes.settings import DEMO
|
from recipes.settings import DEMO
|
||||||
@ -92,6 +92,10 @@ def no_groups(request):
|
|||||||
return render(request, 'no_groups_info.html')
|
return render(request, 'no_groups_info.html')
|
||||||
|
|
||||||
|
|
||||||
|
def no_space(request):
|
||||||
|
return render(request, 'no_space_info.html')
|
||||||
|
|
||||||
|
|
||||||
def recipe_view(request, pk, share=None):
|
def recipe_view(request, pk, share=None):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
recipe = get_object_or_404(Recipe, pk=pk)
|
recipe = get_object_or_404(Recipe, pk=pk)
|
||||||
@ -331,11 +335,8 @@ def system(request):
|
|||||||
|
|
||||||
|
|
||||||
def setup(request):
|
def setup(request):
|
||||||
if (User.objects.count() > 0
|
if User.objects.count() > 0 or 'django.contrib.auth.backends.RemoteUserBackend' in settings.AUTHENTICATION_BACKENDS:
|
||||||
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.'))
|
||||||
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'))
|
return HttpResponseRedirect(reverse('account_login'))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -344,20 +345,19 @@ def setup(request):
|
|||||||
if form.cleaned_data['password'] != form.cleaned_data['password_confirm']: # noqa: E501
|
if form.cleaned_data['password'] != form.cleaned_data['password_confirm']: # noqa: E501
|
||||||
form.add_error('password', _('Passwords dont match!'))
|
form.add_error('password', _('Passwords dont match!'))
|
||||||
else:
|
else:
|
||||||
user = User(
|
user = User(username=form.cleaned_data['name'], is_superuser=True, is_staff=True)
|
||||||
username=form.cleaned_data['name'],
|
|
||||||
is_superuser=True,
|
|
||||||
is_staff=True
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
validate_password(form.cleaned_data['password'], user=user)
|
validate_password(form.cleaned_data['password'], user=user)
|
||||||
user.set_password(form.cleaned_data['password'])
|
user.set_password(form.cleaned_data['password'])
|
||||||
user.save()
|
user.save()
|
||||||
messages.add_message(
|
user.userpreference.space = Space.objects.first()
|
||||||
request,
|
user.userpreference.save()
|
||||||
messages.SUCCESS,
|
|
||||||
_('User has been created, please login!')
|
with scopes_disabled():
|
||||||
)
|
for x in Space.objects.all():
|
||||||
|
x.created_by = user
|
||||||
|
x.save()
|
||||||
|
messages.add_message(request, messages.SUCCESS, _('User has been created, please login!'))
|
||||||
return HttpResponseRedirect(reverse('account_login'))
|
return HttpResponseRedirect(reverse('account_login'))
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
for m in e:
|
for m in e:
|
||||||
@ -369,6 +369,7 @@ def setup(request):
|
|||||||
|
|
||||||
|
|
||||||
def signup(request, token):
|
def signup(request, token):
|
||||||
|
with scopes_disabled():
|
||||||
try:
|
try:
|
||||||
token = UUID(token, version=4)
|
token = UUID(token, version=4)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -387,24 +388,19 @@ def signup(request, token):
|
|||||||
if form.cleaned_data['password'] != form.cleaned_data['password_confirm']: # noqa: E501
|
if form.cleaned_data['password'] != form.cleaned_data['password_confirm']: # noqa: E501
|
||||||
form.add_error('password', _('Passwords dont match!'))
|
form.add_error('password', _('Passwords dont match!'))
|
||||||
else:
|
else:
|
||||||
user = User(
|
user = User(username=form.cleaned_data['name'], )
|
||||||
username=form.cleaned_data['name'],
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
validate_password(
|
validate_password(form.cleaned_data['password'], user=user)
|
||||||
form.cleaned_data['password'], user=user
|
|
||||||
)
|
|
||||||
user.set_password(form.cleaned_data['password'])
|
user.set_password(form.cleaned_data['password'])
|
||||||
user.save()
|
user.save()
|
||||||
messages.add_message(
|
messages.add_message(request, messages.SUCCESS, _('User has been created, please login!'))
|
||||||
request,
|
|
||||||
messages.SUCCESS,
|
|
||||||
_('User has been created, please login!')
|
|
||||||
)
|
|
||||||
|
|
||||||
link.used_by = user
|
link.used_by = user
|
||||||
link.save()
|
link.save()
|
||||||
user.groups.add(link.group)
|
user.groups.add(link.group)
|
||||||
|
|
||||||
|
user.userpreference.space = link.space
|
||||||
|
user.userpreference.save()
|
||||||
return HttpResponseRedirect(reverse('account_login'))
|
return HttpResponseRedirect(reverse('account_login'))
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
for m in e:
|
for m in e:
|
||||||
@ -415,13 +411,9 @@ def signup(request, token):
|
|||||||
if link.username != '':
|
if link.username != '':
|
||||||
form.fields['name'].initial = link.username
|
form.fields['name'].initial = link.username
|
||||||
form.fields['name'].disabled = True
|
form.fields['name'].disabled = True
|
||||||
return render(
|
return render(request, 'account/signup.html', {'form': form, 'link': link})
|
||||||
request, 'account/signup.html', {'form': form, 'link': link}
|
|
||||||
)
|
|
||||||
|
|
||||||
messages.add_message(
|
messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!'))
|
||||||
request, messages.ERROR, _('Invite Link not valid or already used!')
|
|
||||||
)
|
|
||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user