diff --git a/passbook/core/forms/invitations.py b/passbook/core/forms/invitations.py index 8111cef6e..b6f990830 100644 --- a/passbook/core/forms/invitations.py +++ b/passbook/core/forms/invitations.py @@ -27,7 +27,7 @@ class InvitationForm(forms.ModelForm): class Meta: model = Invitation - fields = ['expires', 'fixed_username', 'fixed_email'] + fields = ['expires', 'fixed_username', 'fixed_email', 'needs_confirmation'] labels = { 'fixed_username': "Force user's username (optional)", 'fixed_email': "Force user's email (optional)", diff --git a/passbook/core/migrations/0013_invitation_needs_confirmation.py b/passbook/core/migrations/0013_invitation_needs_confirmation.py new file mode 100644 index 000000000..4b09597e1 --- /dev/null +++ b/passbook/core/migrations/0013_invitation_needs_confirmation.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.7 on 2019-02-25 19:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('passbook_core', '0012_nonce'), + ] + + operations = [ + migrations.AddField( + model_name='invitation', + name='needs_confirmation', + field=models.BooleanField(default=True), + ), + ] diff --git a/passbook/core/models.py b/passbook/core/models.py index e5fc6a6d9..31b0b6874 100644 --- a/passbook/core/models.py +++ b/passbook/core/models.py @@ -392,6 +392,7 @@ class Invitation(UUIDModel): expires = models.DateTimeField(default=None, blank=True, null=True) fixed_username = models.TextField(blank=True, default=None) fixed_email = models.TextField(blank=True, default=None) + needs_confirmation = models.BooleanField(default=True) @property def link(self): diff --git a/passbook/core/urls.py b/passbook/core/urls.py index a6a26b557..b08bb22b9 100644 --- a/passbook/core/urls.py +++ b/passbook/core/urls.py @@ -19,7 +19,8 @@ core_urls = [ path('auth/login/', authentication.LoginView.as_view(), name='auth-login'), path('auth/logout/', authentication.LogoutView.as_view(), name='auth-logout'), path('auth/sign_up/', authentication.SignUpView.as_view(), name='auth-sign-up'), - # path('auth/sign_up//confirm/', , name='auth-sign-up-confirm'), + path('auth/sign_up//confirm/', authentication.SignUpConfirmView.as_view(), + name='auth-sign-up-confirm'), path('auth/process/denied/', view.FactorPermissionDeniedView.as_view(), name='auth-denied'), path('auth/password/reset//', authentication.PasswordResetView.as_view(), name='auth-password-reset'), diff --git a/passbook/core/views/authentication.py b/passbook/core/views/authentication.py index ab5c653e0..2a463dd6f 100644 --- a/passbook/core/views/authentication.py +++ b/passbook/core/views/authentication.py @@ -139,6 +139,15 @@ class SignUpView(UserPassesTestMixin, FormView): def form_valid(self, form: SignUpForm) -> HttpResponse: """Create user""" self._user = SignUpView.create_user(form.cleaned_data, self.request) + needs_confirmation = True + if self._invitation and not self._invitation.needs_confirmation: + needs_confirmation = False + if needs_confirmation: + nonce = Nonce.objects.create(user=self._user) + LOGGER.debug(str(nonce.uuid)) + # TODO: Send E-Mail to user + self._user.is_active = False + self._user.save() self.consume_invitation() messages.success(self.request, _("Successfully signed up!")) LOGGER.debug("Successfully signed up %s", @@ -185,12 +194,24 @@ class SignUpView(UserPassesTestMixin, FormView): sender=SignUpView, user=new_user, request=request) - # TODO: Implement Verification, via email or others - # if needs_confirmation: - # Create Account Confirmation UUID - # AccountConfirmation.objects.create(user=new_user) return new_user +class SignUpConfirmView(View): + """Confirm registration from Nonce""" + + def get(self, request, nonce): + """Verify UUID and activate user""" + nonce = get_object_or_404(Nonce, uuid=nonce) + nonce.user.is_active = True + nonce.user.save() + # Workaround: hardcoded reference to ModelBackend, needs testing + nonce.user.backend = 'django.contrib.auth.backends.ModelBackend' + login(request, nonce.user) + nonce.delete() + messages.success(request, _('Successfully confirmed registration.')) + return redirect('passbook_core:overview') + + class PasswordResetView(View): """Temporarily authenticate User and allow them to reset their password"""