Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,22 @@ def get_for_admin_roles(cls, role_names: list[str], session: Session) -> list[Se
.where(Auth0Role.name.in_(role_names))
).all()

def get_admins(self, auth0_client: Auth0Client) -> set[str]:
"""
Get all admin emails for this platform from the Auth0 API, returning a set of emails.
"""
admins = set()
for role in self.admin_roles:
role_admins = auth0_client.get_all_role_users(role_id=role.id)
for admin in role_admins:
email = admin.email
if email is None:
full_admin = auth0_client.get_user(admin.user_id)
email = full_admin.email
if email:
admins.add(email)
return admins

@classmethod
def get_approved_by_user_id(cls, user_id: str, session: Session) -> list[Self] | None:
return session.exec(
Expand Down
43 changes: 34 additions & 9 deletions routers/sbp_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from auth0.client import Auth0Client, get_auth0_client
from config import Settings, get_settings
from db.models import BiocommonsUser, PlatformEnum
from db.models import BiocommonsUser, Platform, PlatformEnum
from db.setup import get_db_session
from routers.errors import RegistrationRoute
from routers.utils import check_existing_user
Expand Down Expand Up @@ -55,6 +55,33 @@ def compose_sbp_registration_email(registration: SBPRegistrationRequest, setting
return subject, body_html


def queue_sbp_admin_notifications(
registration: SBPRegistrationRequest,
db_session: Session,
auth0_client: Auth0Client,
settings: Settings,
) -> None:
"""Queue approval emails for SBP platform admins."""
sbp_platform = Platform.get_by_id(PlatformEnum.SBP, db_session)
if sbp_platform is None:
logger.warning("SBP platform not found; skipping admin notification email")
return

admin_emails = sbp_platform.get_admins(auth0_client=auth0_client)
if not admin_emails:
logger.info("No SBP platform admins found; skipping notification email")
return

subject, body_html = compose_sbp_registration_email(registration, settings)
for email in admin_emails:
enqueue_email(
db_session,
to_address=email,
subject=subject,
body_html=body_html,
)


@router.post(
"/register",
responses={
Expand Down Expand Up @@ -94,14 +121,12 @@ async def register_sbp_user(
logger.info("Adding user to DB")
_create_sbp_user_record(auth0_user_data, auth0_client=auth0_client, session=db_session)

# Queue approval email for admins
subject, body_html = compose_sbp_registration_email(registration, settings)
enqueue_email(
db_session,
# TODO: update to send email to SBP admin instead
to_address="aai-dev@biocommons.org.au",
subject=subject,
body_html=body_html,
# Queue approval email for SBP platform admins
queue_sbp_admin_notifications(
registration=registration,
db_session=db_session,
auth0_client=auth0_client,
settings=settings,
)
db_session.commit()

Expand Down
31 changes: 31 additions & 0 deletions tests/db/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,37 @@ def _get_all_role_users(*, role_id):
]


def test_platform_get_admins_collects_emails(test_db_session, mocker, persistent_factories):
primary_role = Auth0RoleFactory.create_sync(id="platform-role-primary")
secondary_role = Auth0RoleFactory.create_sync(id="platform-role-secondary")
platform = PlatformFactory.create_sync(id=PlatformEnum.SBP, admin_roles=[primary_role, secondary_role])
mock_client = mocker.Mock()
mock_user_1 = Auth0UserDataFactory.build()
mock_user_2 = Auth0UserDataFactory.build()
mock_user_3 = Auth0UserDataFactory.build()
stub_1 = RoleUserDataFactory.build(user_id=mock_user_1.user_id, email=mock_user_1.email)
stub_2 = RoleUserDataFactory.build(user_id=mock_user_2.user_id, email=None)
stub_3 = RoleUserDataFactory.build(user_id=mock_user_3.user_id, email=None)

def _get_all_role_users(*, role_id):
if role_id == primary_role.id:
return [stub_1, stub_2]
if role_id == secondary_role.id:
return [stub_3]
raise AssertionError(f"Unexpected role id {role_id}")

mock_client.get_all_role_users.side_effect = _get_all_role_users
mock_client.get_user.side_effect = [mock_user_2, mock_user_3]

admins = platform.get_admins(mock_client)

assert admins == {mock_user_1.email, mock_user_2.email, mock_user_3.email}
assert mock_client.get_all_role_users.call_args_list == [
call(role_id=primary_role.id),
call(role_id=secondary_role.id),
]


@respx.mock
def test_group_membership_grant_auth0_role(test_auth0_client, persistent_factories):
group = BiocommonsGroupFactory.create_sync(group_id="biocommons/group/tsi", admin_roles=[])
Expand Down
13 changes: 12 additions & 1 deletion tests/test_sbp_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from schemas.biocommons import BiocommonsRegisterData
from tests.datagen import (
Auth0UserDataFactory,
RoleUserDataFactory,
SBPRegistrationDataFactory,
random_auth0_id,
)
Expand All @@ -39,10 +40,12 @@ def sbp_platform(persistent_factories):
Set up a SBP platform with the associated platform role
"""
platform_role = Auth0RoleFactory.create_sync(name="biocommons/platform/sbp")
admin_role = Auth0RoleFactory.create_sync(name="biocommons/role/sbp/admin")
return PlatformFactory.create_sync(
id=PlatformEnum.SBP,
role_id=platform_role.id,
name="Structural Biology Platform",
admin_roles=[admin_role],
)


Expand Down Expand Up @@ -91,6 +94,14 @@ def test_successful_registration(
email=valid_registration_data["email"],
username=valid_registration_data["username"]
)
admin_user = RoleUserDataFactory.build(email="sbp.admin@example.com")

def _get_all_role_users(*, role_id):
if role_id == sbp_platform.admin_roles[0].id:
return [admin_user]
raise AssertionError(f"Unexpected role id {role_id}")

mock_auth0_client.get_all_role_users.side_effect = _get_all_role_users

response = test_client.post("/sbp/register", json=valid_registration_data)

Expand Down Expand Up @@ -125,7 +136,7 @@ def test_successful_registration(
assert called_data.app_metadata.registration_from == "sbp"
queued_emails = test_db_session.exec(select(EmailNotification)).all()
assert len(queued_emails) == 1
assert queued_emails[0].to_address == "aai-dev@biocommons.org.au"
assert queued_emails[0].to_address == admin_user.email
assert queued_emails[0].status == EmailStatusEnum.PENDING


Expand Down