Skip to content

Commit

Permalink
[EPICSYSTEM-79] Email verification token bug (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
tolkamps1 authored Jun 7, 2024
1 parent 86274f7 commit 179cae7
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 8 deletions.
11 changes: 5 additions & 6 deletions met-api/src/met_api/services/email_verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ def create(cls, email_verification: EmailVerificationSchema,

email_verification['created_by'] = email_verification.get(
'participant_id')
email_verification['verification_token'] = uuid.uuid4()
EmailVerification.create(email_verification, session)
verification_token = uuid.uuid4()
EmailVerification.create({ **email_verification, 'verification_token': verification_token}, session)

# TODO: remove this once email logic is brought over from submission service to here
if email_verification.get('type', None) != EmailVerificationType.RejectedComment:
cls._send_verification_email(email_verification, subscription_type)
cls._send_verification_email({ **email_verification, 'verification_token': verification_token}, subscription_type)

return email_verification

Expand Down Expand Up @@ -239,14 +239,13 @@ def _get_tenant_name(tenant_id):

@staticmethod
def _get_project_name(subscription_type, tenant_name, engagement):
metadata_model: EngagementMetadataModel = EngagementMetadataModel.find_by_id(engagement.id)
if subscription_type == SubscriptionTypes.TENANT.value:
return tenant_name

if subscription_type == SubscriptionTypes.PROJECT.value:
metadata_model: EngagementMetadataModel = EngagementMetadataModel.find_by_id(engagement.id)
project_name = metadata_model.project_metadata.get('project_name', None)
return project_name or engagement.name
project_name = metadata_model.project_metadata.get('project_name', None) if metadata_model else engagement.name
return project_name

if subscription_type == SubscriptionTypes.ENGAGEMENT.value:
return engagement.name
Expand Down
93 changes: 92 additions & 1 deletion met-api/tests/unit/api/test_email_verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@
"""
import json

from http import HTTPStatus
from faker import Faker
from unittest.mock import patch
import pytest

from met_api.constants.email_verification import EmailVerificationType
from met_api.constants.subscription_type import SubscriptionTypes
from met_api.services.email_verification_service import EmailVerificationService
from met_api.utils.enums import ContentType
from tests.utilities.factory_scenarios import TestJwtClaims
from tests.utilities.factory_utils import factory_auth_header, factory_survey_and_eng_model, set_global_tenant
from tests.utilities.factory_utils import factory_auth_header, factory_email_verification, factory_survey_and_eng_model, set_global_tenant

fake = Faker()

Expand All @@ -40,3 +47,87 @@ def test_email_verification(client, jwt, session, notify_mock, ): # pylint:disa
headers=headers, content_type=ContentType.JSON.value)

assert rv.status_code == 200


@pytest.mark.parametrize('side_effect, expected_status', [
(KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR),
(ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR),
])
def test_get_email_verification_by_token(client, jwt, session, side_effect,
expected_status): # pylint:disable=unused-argument
"""Assert that an email verification can be fetched."""
claims = TestJwtClaims.public_user_role
set_global_tenant()
survey, eng = factory_survey_and_eng_model()
email_verification = factory_email_verification(survey.id)
headers = factory_auth_header(jwt=jwt, claims=claims)
rv = client.get(f'/api/email_verification/{email_verification.verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == 200
assert rv.json.get('verification_token') == email_verification.verification_token
assert rv.json.get('is_active') is True
with patch.object(EmailVerificationService, 'get_active', side_effect=side_effect):
rv = client.get(f'/api/email_verification/{email_verification.verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == expected_status
# test email verification not found
email_verification_token = fake.text(max_nb_chars=20)
rv = client.get(f'/api/email_verification/{email_verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR


def test_patch_email_verification_by_token(client, jwt, session): # pylint:disable=unused-argument
"""Assert that an email verification can be fetched."""
claims = TestJwtClaims.public_user_role
set_global_tenant()
survey, eng = factory_survey_and_eng_model()
email_verification = factory_email_verification(survey.id, verification_type=EmailVerificationType.Subscribe)
headers = factory_auth_header(jwt=jwt, claims=claims)
rv = client.put(f'/api/email_verification/{email_verification.verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == 200
assert rv.json.get('verification_token') == email_verification.verification_token
assert rv.json.get('is_active') is False
with patch.object(EmailVerificationService, 'verify', side_effect=KeyError('Test error')):
rv = client.put(f'/api/email_verification/{email_verification.verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == HTTPStatus.NOT_FOUND
with patch.object(EmailVerificationService, 'verify', side_effect=ValueError('Test error')):
rv = client.put(f'/api/email_verification/{email_verification.verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
# test email verification not found to update the data
email_verification_token = fake.text(max_nb_chars=20)
rv = client.put(f'/api/email_verification/{email_verification_token}',
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR


@pytest.mark.parametrize('side_effect, expected_status', [
(KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR),
(ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR),
])
def test_post_subscription_email_verification(client, jwt, session, notify_mock,
side_effect, expected_status): # pylint:disable=unused-argument
"""Assert that an Subscription Email can be sent."""
claims = TestJwtClaims.public_user_role
set_global_tenant()
survey, eng = factory_survey_and_eng_model()
to_dict = {
'email_address': fake.email(),
'survey_id': survey.id,
'type': EmailVerificationType.Subscribe,
'language': 'en',
}
headers = factory_auth_header(jwt=jwt, claims=claims)
rv = client.post(f'/api/email_verification/{SubscriptionTypes.PROJECT.value}/subscribe',
data=json.dumps(to_dict),
headers=headers, content_type=ContentType.JSON.value)

assert rv.status_code == 200
with patch.object(EmailVerificationService, 'create', side_effect=side_effect):
rv = client.post(f'/api/email_verification/{SubscriptionTypes.PROJECT.value}/subscribe',
data=json.dumps(to_dict),
headers=headers, content_type=ContentType.JSON.value)
assert rv.status_code == expected_status
8 changes: 7 additions & 1 deletion met-api/tests/utilities/factory_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from met_api.config import get_named_config
from met_api.constants.engagement_status import Status
from met_api.constants.widget import WidgetType
from met_api.constants.email_verification import EmailVerificationType
from met_api.models import Tenant
from met_api.models.comment import Comment as CommentModel
from met_api.models.email_verification import EmailVerification as EmailVerificationModel
Expand Down Expand Up @@ -107,15 +108,20 @@ def factory_subscription_model():
return subscription


def factory_email_verification(survey_id):
def factory_email_verification(survey_id, verification_type=None, submission_id=None):
"""Produce a EmailVerification model."""
email_verification = EmailVerificationModel(
verification_token=fake.uuid4(),
is_active=True
)
email_verification.type = verification_type if verification_type else EmailVerificationType.Survey

if survey_id:
email_verification.survey_id = survey_id

if submission_id:
email_verification.submission_id = submission_id

email_verification.save()
return email_verification

Expand Down

0 comments on commit 179cae7

Please sign in to comment.