Skip to content

Commit

Permalink
add email verification (#874)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Apr 26, 2024
1 parent cf01e42 commit fc7913b
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 4 deletions.
83 changes: 81 additions & 2 deletions userprofile/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
from projectroles.views import MSG_FORM_INVALID
from projectroles.utils import build_secret

from userprofile.views import SETTING_UPDATE_MSG
from userprofile.views import (
SETTING_UPDATE_MSG,
EMAIL_NOT_FOUND_MSG,
EMAIL_ALREADY_VERIFIED_MSG,
EMAIL_VERIFIED_MSG,
)


app_settings = AppSettingAPI()
Expand Down Expand Up @@ -302,7 +307,10 @@ def test_post(self):
)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].recipients(), [ADD_EMAIL])
# TODO: Assert sent URL
verify_url = reverse(
'userprofile:email_verify', kwargs={'secret': email.secret}
)
self.assertIn(verify_url, mail.outbox[0].body)

def test_post_existing_primary(self):
"""Test POST with email used as primary email for user"""
Expand Down Expand Up @@ -352,3 +360,74 @@ def test_post_multiple(self):
self.assertEqual(response.status_code, 302)
self.assertEqual(SODARUserAdditionalEmail.objects.count(), 2)
self.assertEqual(len(mail.outbox), 1)


class TestUserEmailVerifyView(SODARUserAdditionalEmailMixin, UserViewTestBase):
"""Tests for UserEmailVerifyView"""

def setUp(self):
super().setUp()
self.url_redirect = reverse('userprofile:detail')
self.email = self.make_email(self.user, ADD_EMAIL, verified=False)
self.url = reverse(
'userprofile:email_verify', kwargs={'secret': self.email.secret}
)

def test_get(self):
"""Test UserEmailVerifyView GET"""
self.assertEqual(self.email.verified, False)
with self.login(self.user):
response = self.client.get(self.url)
self.assertRedirects(response, self.url_redirect)
self.email.refresh_from_db()
self.assertEqual(self.email.verified, True)
self.assertEqual(
list(get_messages(response.wsgi_request))[0].message,
EMAIL_VERIFIED_MSG.format(email=self.email.email),
)

def test_get_invalid_secret(self):
"""Test GET with invalid secret"""
self.assertEqual(self.email.verified, False)
with self.login(self.user):
response = self.client.get(
reverse(
'userprofile:email_verify',
kwargs={'secret': build_secret(32)},
)
)
self.assertEqual(response.status_code, 302)
self.email.refresh_from_db()
self.assertEqual(self.email.verified, False)
self.assertEqual(
list(get_messages(response.wsgi_request))[0].message,
EMAIL_NOT_FOUND_MSG,
)

def test_get_wrong_user(self):
"""Test GET with wrong user"""
user_new = self.make_user('user_new')
self.assertEqual(self.email.verified, False)
with self.login(user_new):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 302)
self.email.refresh_from_db()
self.assertEqual(self.email.verified, False)
self.assertEqual(
list(get_messages(response.wsgi_request))[0].message,
EMAIL_NOT_FOUND_MSG,
)

def test_get_verified(self):
"""Test GET with verified email"""
self.email.verified = True
self.email.save()
with self.login(self.user):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 302)
self.email.refresh_from_db()
self.assertEqual(self.email.verified, True)
self.assertEqual(
list(get_messages(response.wsgi_request))[0].message,
EMAIL_ALREADY_VERIFIED_MSG,
)
5 changes: 5 additions & 0 deletions userprofile/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@
view=views.UserEmailCreateView.as_view(),
name='email_create',
),
path(
route='profile/email/verify/<str:secret>',
view=views.UserEmailVerifyView.as_view(),
name='email_verify',
),
]
36 changes: 34 additions & 2 deletions userprofile/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
from django.urls import reverse, reverse_lazy
from django.views.generic import TemplateView, FormView, CreateView
from django.views.generic import TemplateView, FormView, CreateView, View

# Projectroles dependency
from projectroles.app_settings import AppSettingAPI
Expand Down Expand Up @@ -46,6 +46,9 @@
If this was not requested by you, this message can be ignored.
'''.lstrip()
EMAIL_NOT_FOUND_MSG = 'No email found.'
EMAIL_ALREADY_VERIFIED_MSG = 'Email already verified.'
EMAIL_VERIFIED_MSG = 'Email "{email}" verified.'


class UserDetailView(LoginRequiredMixin, LoggedInPermissionMixin, TemplateView):
Expand Down Expand Up @@ -138,7 +141,12 @@ def get_success_url(self):
body = VERIFY_EMAIL_BODY.format(
user=get_email_user(self.object.user),
site=settings.SITE_INSTANCE_TITLE,
url='#', # TODO
url=self.request.build_absolute_uri(
reverse(
'userprofile:email_verify',
kwargs={'secret': self.object.secret},
)
),
)
try:
send_generic_mail(subject, body, [self.object.email], self.request)
Expand Down Expand Up @@ -175,3 +183,27 @@ def get(self, *args, **kwargs):
)
return redirect(reverse('userprofile:detail'))
return super().get(*args, **kwargs)


class UserEmailVerifyView(LoginRequiredMixin, LoggedInPermissionMixin, View):
"""View for verifying a created additional email address"""

http_method_names = ['get']
permission_required = 'userprofile.add_email'

def get(self, request, *args, **kwargs):
secret = self.kwargs.get('secret')
email = SODARUserAdditionalEmail.objects.filter(
user=request.user, secret=secret
).first()
if not email:
messages.error(request, EMAIL_NOT_FOUND_MSG)
elif email.verified:
messages.info(request, EMAIL_ALREADY_VERIFIED_MSG)
else:
email.verified = True
email.save()
messages.success(
request, EMAIL_VERIFIED_MSG.format(email=email.email)
)
return redirect(reverse('userprofile:detail'))

0 comments on commit fc7913b

Please sign in to comment.