From 3074d916dc2d9c49554ce57cdb81db701cdc4e5b Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 7 Jun 2021 16:46:28 +0200 Subject: [PATCH] many signup and space management fixes --- cookbook/admin.py | 2 +- cookbook/forms.py | 12 +---- cookbook/helper/scope_middleware.py | 5 +- .../0127_remove_invitelink_username.py | 17 +++++++ cookbook/models.py | 1 - cookbook/tables.py | 2 +- cookbook/templates/account/signup.html | 3 ++ cookbook/templates/space.html | 8 +-- cookbook/urls.py | 3 +- cookbook/views/new.py | 2 +- cookbook/views/views.py | 50 ++++--------------- recipes/settings.py | 5 ++ 12 files changed, 49 insertions(+), 61 deletions(-) create mode 100644 cookbook/migrations/0127_remove_invitelink_username.py diff --git a/cookbook/admin.py b/cookbook/admin.py index e9613ec0..3d52ac2b 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -166,7 +166,7 @@ admin.site.register(ViewLog, ViewLogAdmin) class InviteLinkAdmin(admin.ModelAdmin): list_display = ( - 'username', 'group', 'valid_until', + 'group', 'valid_until', 'created_by', 'created_at', 'used_by' ) diff --git a/cookbook/forms.py b/cookbook/forms.py index 71d664e7..d96ba164 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -413,19 +413,11 @@ class InviteLinkForm(forms.ModelForm): return email - def clean_username(self): - username = self.cleaned_data['username'] - with scopes_disabled(): - if username != '' and (User.objects.filter(username=username).exists() or InviteLink.objects.filter(username=username).exists()): - raise ValidationError(_('Username already taken!')) - return username - class Meta: model = InviteLink - fields = ('username', 'email', 'group', 'valid_until', 'space') + fields = ('email', 'group', 'valid_until', 'space') help_texts = { - 'username': _('A username is not required, if left blank the new user can choose one.'), - 'email': _('An email address is not required but if present the invite link will be send to the user.') + 'email': _('An email address is not required but if present the invite link will be send to the user.'), } field_classes = { 'space': SafeModelChoiceField, diff --git a/cookbook/helper/scope_middleware.py b/cookbook/helper/scope_middleware.py index c7de19dd..809a7eb1 100644 --- a/cookbook/helper/scope_middleware.py +++ b/cookbook/helper/scope_middleware.py @@ -16,7 +16,10 @@ class ScopeMiddleware: with scopes_disabled(): return self.get_response(request) - if request.path.startswith('/signup/'): + if request.path.startswith('/signup/') or request.path.startswith('/invite/'): + return self.get_response(request) + + if request.path.startswith('/accounts/'): return self.get_response(request) with scopes_disabled(): diff --git a/cookbook/migrations/0127_remove_invitelink_username.py b/cookbook/migrations/0127_remove_invitelink_username.py new file mode 100644 index 00000000..ffb25260 --- /dev/null +++ b/cookbook/migrations/0127_remove_invitelink_username.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.3 on 2021-06-07 14:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0126_alter_userpreference_theme'), + ] + + operations = [ + migrations.RemoveField( + model_name='invitelink', + name='username', + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 3a7997e8..3f198e64 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -612,7 +612,6 @@ def default_valid_until(): class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, PermissionModelMixin): uuid = models.UUIDField(default=uuid.uuid4) - username = models.CharField(blank=True, max_length=64) email = models.EmailField(blank=True) group = models.ForeignKey(Group, on_delete=models.CASCADE) valid_until = models.DateField(default=default_valid_until) diff --git a/cookbook/tables.py b/cookbook/tables.py index 3872ea13..2adf47a7 100644 --- a/cookbook/tables.py +++ b/cookbook/tables.py @@ -141,7 +141,7 @@ class ShoppingListTable(tables.Table): class InviteLinkTable(tables.Table): link = tables.TemplateColumn( - "" + "" ) delete_link = tables.TemplateColumn( "" + _('Delete') + "", verbose_name=_('Delete') diff --git a/cookbook/templates/account/signup.html b/cookbook/templates/account/signup.html index f124621b..e6785b7d 100644 --- a/cookbook/templates/account/signup.html +++ b/cookbook/templates/account/signup.html @@ -25,6 +25,9 @@
{{ form.email |as_crispy_field }}
+
+ {{ form.email2 |as_crispy_field }} +
{{ form.password1 |as_crispy_field }}
diff --git a/cookbook/templates/space.html b/cookbook/templates/space.html index 86a20283..7cf19369 100644 --- a/cookbook/templates/space.html +++ b/cookbook/templates/space.html @@ -96,10 +96,10 @@
', views.signup, name='view_signup'), + path('signup/', views.signup, name='view_signup'), # TODO deprecated with 0.16.2 remove at some point + path('invite/', views.invite_link, name='view_invite'), path('system/', views.system, name='view_system'), path('search/', views.search, name='view_search'), path('search/v2/', views.search_v2, name='view_search_v2'), diff --git a/cookbook/views/new.py b/cookbook/views/new.py index 6edc95bd..46aa8b32 100644 --- a/cookbook/views/new.py +++ b/cookbook/views/new.py @@ -225,7 +225,7 @@ class InviteLinkCreate(GroupRequiredMixin, CreateView): if InviteLink.objects.filter(space=self.request.space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20: message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.request.user.username) message += _(' to join their Tandoor Recipes space ') + escape(self.request.space.name) + '.\n\n' - message += _('Click the following link to activate your account: ') + self.request.build_absolute_uri(reverse('view_signup', args=[str(obj.uuid)])) + '\n\n' + message += _('Click the following link to activate your account: ') + self.request.build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n' message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n' message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n' message += _('Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/' diff --git a/cookbook/views/views.py b/cookbook/views/views.py index 2d4b4fa2..b7cc5746 100644 --- a/cookbook/views/views.py +++ b/cookbook/views/views.py @@ -126,7 +126,7 @@ def no_space(request): return HttpResponseRedirect(reverse('index')) if join_form.is_valid(): - return HttpResponseRedirect(reverse('view_signup', args=[join_form.cleaned_data['token']])) + return HttpResponseRedirect(reverse('view_invite', args=[join_form.cleaned_data['token']])) else: if settings.SOCIAL_DEFAULT_ACCESS: request.user.userpreference.space = Space.objects.first() @@ -134,7 +134,7 @@ def no_space(request): request.user.groups.add(Group.objects.get(name=settings.SOCIAL_DEFAULT_GROUP)) return HttpResponseRedirect(reverse('index')) if 'signup_token' in request.session: - return HttpResponseRedirect(reverse('view_signup', args=[request.session.pop('signup_token', '')])) + return HttpResponseRedirect(reverse('view_invite', args=[request.session.pop('signup_token', '')])) create_form = SpaceCreateForm() join_form = SpaceJoinForm() @@ -420,7 +420,7 @@ def setup(request): return render(request, 'setup.html', {'form': form}) -def signup(request, token): +def invite_link(request, token): with scopes_disabled(): try: token = UUID(token, version=4) @@ -446,47 +446,15 @@ def signup(request, token): return HttpResponseRedirect(reverse('index')) else: request.session['signup_token'] = str(token) + return HttpResponseRedirect(reverse('account_signup')) - if request.method == 'POST': - updated_request = request.POST.copy() - if link.username != '': - updated_request.update({'username': link.username}) + messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!')) + return HttpResponseRedirect(reverse('index')) - form = SignupForm(data=updated_request) - if form.is_valid(): - if form.cleaned_data['password1'] != form.cleaned_data['password_confirm']: # noqa: E501 - form.add_error('password1', _('Passwords dont match!')) - else: - user = User(username=form.cleaned_data['username'], ) - try: - validate_password(form.cleaned_data['password1'], user=user) - user.set_password(form.cleaned_data['password1']) - user.save() - messages.add_message(request, messages.SUCCESS, _('User has been created, please login!')) - - link.used_by = user - link.save() - - request.user.groups.clear() - user.groups.add(link.group) - - user.userpreference.space = link.space - user.userpreference.save() - return HttpResponseRedirect(reverse('account_login')) - except ValidationError as e: - for m in e: - form.add_error('password', m) - else: - form = SignupForm() - - if link.username != '': - form.fields['name'].initial = link.username - form.fields['name'].disabled = True - return render(request, 'account/signup.html', {'form': form, 'link': link}) - - messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!')) - return HttpResponseRedirect(reverse('index')) +# TODO deprecated with 0.16.2 remove at some point +def signup(request, token): + return HttpResponseRedirect(reverse('view_invite', args=[token])) @group_required('admin') diff --git a/recipes/settings.py b/recipes/settings.py index 175fc781..6d86fa11 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -113,6 +113,11 @@ INSTALLED_APPS = [ SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else [] INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS +ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = True +ACCOUNT_MAX_EMAIL_ADDRESSES = 3 +ACCOUNT_EMAIL_REQUIRED = True +ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 90 + SOCIALACCOUNT_PROVIDERS = ast.literal_eval( os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}')