From 0d91e42aeefefcf3ceadc21afd338e45cba2023e Mon Sep 17 00:00:00 2001 From: Lasse Fredheim <lass@uio.no> Date: Tue, 14 Mar 2023 12:59:08 +0100 Subject: [PATCH] Add check for if email exists in validation --- frontend/public/locales/en/common.json | 1 + frontend/public/locales/nb/common.json | 1 + frontend/public/locales/nn/common.json | 1 + .../sponsor/register/stepPersonForm.tsx | 9 ------- frontend/src/utils/index.test.ts | 24 ++++++++++++++----- frontend/src/utils/index.ts | 13 ++++++++-- gregui/api/serializers/email.py | 0 gregui/api/urls.py | 7 +++++- gregui/api/views/email.py | 0 gregui/api/views/identity.py | 16 +++++++++++-- gregui/tests/api/views/test_identity.py | 13 ++++++++++ 11 files changed, 65 insertions(+), 20 deletions(-) delete mode 100644 gregui/api/serializers/email.py delete mode 100644 gregui/api/views/email.py diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index 40684e8e..1e0c48cd 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -133,6 +133,7 @@ "roleEndRequired": "Role end date is required", "invalidEndDate": "Chosen role must have an earlier end date", "emailRequired": "E-mail is required", + "existingEmail": "This e-mail address is already in use", "consentRequired": "This consent is required", "invalidMobilePhoneNumber": "Invalid phone number", "invalidEmail": "Invalid e-mail address", diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json index 38363b4a..782c45b0 100644 --- a/frontend/public/locales/nb/common.json +++ b/frontend/public/locales/nb/common.json @@ -133,6 +133,7 @@ "roleEndRequired": "Sluttdato for rolle er obligatorisk", "invalidEndDate": "Valgt rolle må ha en tidligere sluttdato", "emailRequired": "E-post er obligatorisk", + "existingEmail": "E-postadressen er allerede i bruk", "consentRequired": "Dette samtykket er obligatorisk", "invalidMobilePhoneNumber": "Ugyldig telefonnummer", "invalidEmail": "Ugyldig e-postadresse", diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json index e1669b95..fa51387b 100644 --- a/frontend/public/locales/nn/common.json +++ b/frontend/public/locales/nn/common.json @@ -133,6 +133,7 @@ "roleEndRequired": "Sluttdato for rolle er påkrevd", "invalidEndDate": "Vald rolle må ha ein tidlegare sluttdato", "emailRequired": "E-post er påkrevd", + "existingEmail": "E-postadressa er allereie i bruk", "consentRequired": "Dette samtykket er påkrevd", "invalidMobilePhoneNumber": "Ugyldig telefonnummer", "invalidEmail": "Ugyldig e-postadresse", diff --git a/frontend/src/routes/sponsor/register/stepPersonForm.tsx b/frontend/src/routes/sponsor/register/stepPersonForm.tsx index a07b9510..e9c8f5a1 100644 --- a/frontend/src/routes/sponsor/register/stepPersonForm.tsx +++ b/frontend/src/routes/sponsor/register/stepPersonForm.tsx @@ -131,15 +131,6 @@ const StepPersonForm = forwardRef( useImperativeHandle(ref, () => ({ doSubmit })) - // const checkDuplicateEmail = (email: String) => { - // fetch(url til api).then((res) => { - // if (res.toString() === email) { - // return true - // } - // return false - // }) - // } - const validateStartDateBeforeEndDate = (startDate: Date | undefined) => { if (!startDate) { return t('validation.startDateMustBeSet') diff --git a/frontend/src/utils/index.test.ts b/frontend/src/utils/index.test.ts index 0c6a66c6..5067541a 100644 --- a/frontend/src/utils/index.test.ts +++ b/frontend/src/utils/index.test.ts @@ -30,16 +30,28 @@ test('Valid phone number', async () => { }) test('Valid e-mail', async () => { - expect(isValidEmail('test@example.org')).toEqual(true) - expect(isValidEmail('Test.Tester@example.org')).toEqual(true) + isValidEmail('test@example.org').then((data) => { + expect(data).toEqual(true) + }) + isValidEmail('test.testerson@example.org').then((data) => { + expect(data).toEqual(true) + }) }) test('Invalid e-mail', async () => { - expect(isValidEmail('testexample.org')).not.toEqual(true) - expect(isValidEmail('test')).not.toEqual(true) + isValidEmail('testexample.org').then((data) => { + expect(data).toEqual('common:validation.invalidEmail') + }) + isValidEmail('test').then((data) => { + expect(data).toEqual('common:validation.invalidEmail') + }) // Treat special characters as invalid, some services allow them though - expect(isValidEmail('Øyvind.Åsen@example.org')).not.toEqual(true) - expect(isValidEmail('Test.Tester@åsen.org')).not.toEqual(true) + isValidEmail('Øyvind.Åsen@example.org').then((data) => { + expect(data).toEqual('common:validation.invalidEmail') + }) + isValidEmail('Test.Tester@åsen.org').then((data) => { + expect(data).toEqual('common:validation.invalidEmail') + }) }) test('Body has values', async () => { diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts index 681f6757..1ca62996 100644 --- a/frontend/src/utils/index.ts +++ b/frontend/src/utils/index.ts @@ -102,12 +102,21 @@ export function isValidMobilePhoneNumber( return i18n.t<string>('common:validation.invalidMobilePhoneNumber') } -export function isValidEmail(data: string | undefined): boolean | string { +export async function isValidEmail(data: string | undefined) { if (!data) { return i18n.t<string>('common:validation.emailRequired') } if (validEmailRegex.test(data)) { - return true + const message = await fetch( + `/api/ui/v1/email/${data}`, + fetchJsonOpts() + ).then((res) => { + if (res.ok) { + return i18n.t<string>('common:validation.existingEmail') + } + return true + }) + return message } return i18n.t<string>('common:validation.invalidEmail') } diff --git a/gregui/api/serializers/email.py b/gregui/api/serializers/email.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gregui/api/urls.py b/gregui/api/urls.py index cf2dd76c..122e11e8 100644 --- a/gregui/api/urls.py +++ b/gregui/api/urls.py @@ -1,6 +1,10 @@ from django.urls import re_path, path from rest_framework.routers import DefaultRouter -from gregui.api.views.identity import IdentityCheckView, IdentityViewSet +from gregui.api.views.identity import ( + IdentityCheckView, + IdentityViewSet, + EmailExistsView, +) from gregui.api.views.invitation import ( CheckInvitationView, @@ -43,4 +47,5 @@ urlpatterns += [ ), path("userinfo/", UserInfoView.as_view(), name="userinfo"), path("identitycheck/<int:id>", IdentityCheckView.as_view(), name="identitycheck"), + path("email/<str:value>", EmailExistsView.as_view(), name="email"), ] diff --git a/gregui/api/views/email.py b/gregui/api/views/email.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gregui/api/views/identity.py b/gregui/api/views/identity.py index e9593e82..d511db28 100644 --- a/gregui/api/views/identity.py +++ b/gregui/api/views/identity.py @@ -2,10 +2,10 @@ from django.conf import settings from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import GenericViewSet -from rest_framework import mixins +from rest_framework import mixins, status from rest_framework.views import APIView from rest_framework.response import Response -from rest_framework import status +from rest_framework.generics import RetrieveAPIView from greg.models import Identity from greg.permissions import IsSponsor @@ -52,3 +52,15 @@ class IdentityCheckView(APIView): ) match = client.extid_search(ident.type, ident.value) return Response({"match": match.dict() if match else None}) + + +class EmailExistsView(RetrieveAPIView): + """ + View used for checking if an email is already in use + """ + + authentication_classes = [SessionAuthentication, BasicAuthentication] + permission_classes = [IsAuthenticated, IsSponsor] + serializer_class = IdentitySerializer + queryset = Identity.objects.filter(type="private_email") + lookup_field = "value" diff --git a/gregui/tests/api/views/test_identity.py b/gregui/tests/api/views/test_identity.py index f7a1ac31..3c59514d 100644 --- a/gregui/tests/api/views/test_identity.py +++ b/gregui/tests/api/views/test_identity.py @@ -87,3 +87,16 @@ def test_identity_check_existing_fnr( url = reverse("gregui-v1:identitycheck", kwargs={"id": person_foo.fnr.id}) response = client.get(url) assert response.json() == {"match": {"first": "Ola", "last": "Nordmann"}} + + +@pytest.mark.django_db +def test_existing_email(client, log_in, user_sponsor, person_foo): + log_in(user_sponsor) + response = client.get( + reverse("gregui-v1:email", kwargs={"value": person_foo.private_email.value}) + ) + assert response.status_code == 200 + response = client.get( + reverse("gregui-v1:email", kwargs={"value": "nosuch@email.com"}) + ) + assert response.status_code == 404 -- GitLab