Skip to content

Commit

Permalink
Incorporate 2nd factor recreation notification with test
Browse files Browse the repository at this point in the history
  • Loading branch information
TheByronHimes committed May 15, 2024
1 parent 84c357d commit d3afbc0
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/nos/core/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,26 @@ async def delete_user_data(self, resource_id: str) -> None:
except ResourceNotFoundError:
# do not raise an error if the user is not found, just log it.
log.warning("User not found for deletion", extra={"user_id": resource_id})

async def process_second_factor_recreated(self, *, user_id: str) -> None:
"""Send a notification to the user that their second factor has been recreated."""
try:
user = await self._user_dao.get_by_id(user_id)
except ResourceNotFoundError as err:
error = self.MissingUserError(
user_id=user_id, notification_name="Second Factor Recreated"
)
log.error(
error,
extra={
"user_id": user_id,
"notification_name": "Second Factor Recreated",
},
)
raise error from err

await self._notification_emitter.notify(
email=user.email,
full_name=user.name,
notification=notifications.SECOND_FACTOR_RECREATED_TO_USER,
)
4 changes: 4 additions & 0 deletions src/nos/ports/inbound/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ async def delete_user_data(self, resource_id: str) -> None:
In the case that the user ID does not exist in the database, this method will
log the fact but not raise an error.
"""

@abstractmethod
async def process_second_factor_recreated(self, *, user_id: str) -> None:
"""Send a notification to the user that their second factor has been recreated."""
9 changes: 9 additions & 0 deletions src/nos/translators/inbound/event_sub.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ def __init__(
config.access_request_events_topic,
config.file_registered_event_topic,
config.iva_state_changed_event_topic,
config.second_factor_recreated_event_topic,
]
self.types_of_interest = [
config.access_request_created_event_type,
config.access_request_allowed_event_type,
config.access_request_denied_event_type,
config.file_registered_event_type,
config.iva_state_changed_event_type,
config.second_factor_recreated_event_type,
]
self._config = config
self._orchestrator = orchestrator
Expand Down Expand Up @@ -134,6 +136,13 @@ async def _handle_all_ivas_reset(self, payload: JsonObject) -> None:
user_id=validated_payload.user_id
)

async def _handle_second_factor_recreated(self, payload: JsonObject) -> None:
"""Send notifications for second factor recreation."""
validated_payload = get_validated_payload(payload, event_schemas.UserID)
await self._orchestrator.process_second_factor_recreated(
user_id=validated_payload.user_id
)

async def _consume_validated(
self, *, payload: JsonObject, type_: Ascii, topic: Ascii, key: Ascii
) -> None:
Expand Down
42 changes: 42 additions & 0 deletions tests/test_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,45 @@ async def test_all_ivas_reset(joint_fixture: JointFixture):
in_topic=joint_fixture.config.notification_event_topic,
):
await joint_fixture.event_subscriber.run(forever=False)


async def test_second_factor_recreated_notification(joint_fixture: JointFixture):
"""Test that the second factor recreated event is translated into a notification."""
# Prepare triggering event (the second factor recreated event).
payload = event_schemas.UserID(
user_id=TEST_USER.user_id,
)

# Publish the trigger event
await joint_fixture.kafka.publish_event(
payload=payload.model_dump(),
type_=joint_fixture.config.second_factor_recreated_event_type,
topic=joint_fixture.config.second_factor_recreated_event_topic,
key=TEST_USER.user_id,
)

# Define the event that should be published by the NOS when the trigger is consumed
expected_notification_content = (
notifications.SECOND_FACTOR_RECREATED_TO_USER.formatted(
support_email=joint_fixture.config.central_data_stewardship_email
)
)

expected_notification = event_schemas.Notification(
recipient_email=TEST_USER.email,
recipient_name=TEST_USER.name,
subject=expected_notification_content.subject,
plaintext_body=expected_notification_content.text,
)

expected_event = ExpectedEvent(
payload=expected_notification.model_dump(),
type_=joint_fixture.config.notification_event_type,
)

# consume the event and verify that the expected event is published
async with joint_fixture.kafka.expect_events(
events=[expected_event],
in_topic=joint_fixture.config.notification_event_topic,
):
await joint_fixture.event_subscriber.run(forever=False)

0 comments on commit d3afbc0

Please sign in to comment.