From b6b3af52ca46b337f362fe4475572312128a3100 Mon Sep 17 00:00:00 2001 From: amandazhu Date: Fri, 17 Apr 2026 11:16:52 +1000 Subject: [PATCH 1/2] feat: add TSI bundle rejection email --- biocommons/emails.py | 45 +++++++++++++++++++++++++++++++++++ routers/admin.py | 30 ++++++++++++++++++++++- tests/admin_api/test_admin.py | 30 +++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/biocommons/emails.py b/biocommons/emails.py index 347f3020..b9cb5b9f 100644 --- a/biocommons/emails.py +++ b/biocommons/emails.py @@ -333,6 +333,51 @@ def compose_welcome_email( return subject, _wrap_email_html(subject, subject, body_content, portal_url) +def compose_group_membership_rejected_email( + *, + group_name: str, + group_short_name: str, + first_name: str, + settings: Settings, +) -> tuple[str, str]: + """ + Notify a user that their group/bundle access request was rejected. + For the TSI bundle, includes detailed information about open-access alternatives. + """ + portal_url = settings.aai_portal_url or "" + safe_group_name = html.escape(group_name or "") + safe_first_name = html.escape(first_name or "") + subject = f"Your {group_name} Service Bundle request" + + is_tsi = (group_short_name or "").upper() == "TSI" + if is_tsi: + extra_content = f""" +

The TSI Bundle available on the Australian BioCommons Access is only for members of the Threatened Species Initiative consortium.

+

Members are collaborators who have projects supported through our request for partnership rounds. They can access datasets that are under embargo for the first 12 months following their generation.

+

The Threatened Species Initiative is generating genomic resources that are made openly accessible to the community with the standard registration to the Bioplatforms Australia data portal (now Australian BioCommons Access). You do not need to apply to the TSI Bundle to obtain access to these open access genomics datasets. This is also the case for datasets of all other initiatives presented on the Bioplatforms Data Portal.

+

Similarly the access to various tools, including Fgenesh++, can be obtained through Galaxy Australia without the need of the TSI Bundle:

+ +

Please do not hesitate to reach out to us for any non registration related issues:

+ """ + else: + extra_content = "" + + body_content = f""" +

Dear {safe_first_name},

+

Thank you for your interest in the {safe_group_name} Bundle.

+ {extra_content} +

Thank you,

+

BioCommons Access team

+ """ + return subject, _wrap_email_html(subject, subject, body_content, portal_url) + + def compose_bundle_request_confirmation_email( *, first_name: str, diff --git a/routers/admin.py b/routers/admin.py index 8d88c6f5..09852222 100644 --- a/routers/admin.py +++ b/routers/admin.py @@ -30,6 +30,7 @@ from biocommons.emails import ( compose_email_change_notification, compose_group_membership_approved_email, + compose_group_membership_rejected_email, compose_username_change_notification, format_first_name, ) @@ -1246,8 +1247,11 @@ def approve_group_membership(user_id: Annotated[str, UserIdParam], def reject_group_membership(user_id: Annotated[str, UserIdParam], group_id: Annotated[str, ServiceIdParam], payload: RejectServiceRequest, + client: Annotated[Auth0Client, Depends(get_auth0_client)], admin_record: Annotated[BiocommonsUser, Depends(get_db_user)], - db_session: Annotated[Session, Depends(get_db_session)]): + db_session: Annotated[Session, Depends(get_db_session)], + settings: Annotated[Settings, Depends(get_settings)]): + group_record = BiocommonsGroup.get_by_id_or_404(group_id, db_session) membership = GroupMembership.get_by_user_id_and_group_id_or_404( user_id=user_id, group_id=group_id, @@ -1264,6 +1268,30 @@ def reject_group_membership(user_id: Annotated[str, UserIdParam], session=db_session, commit=False, ) + if membership.user and membership.user.email: + first_name = "there" + try: + auth0_user = client.get_user(membership.user.id) + first_name = format_first_name( + full_name=auth0_user.name, + given_name=auth0_user.given_name, + fallback="there", + ) + except Exception: + pass + subject, body_html = compose_group_membership_rejected_email( + group_name=group_record.name, + group_short_name=group_record.short_name, + first_name=first_name, + settings=settings, + ) + enqueue_email( + session=db_session, + to_address=membership.user.email, + subject=subject, + body_html=body_html, + settings=settings, + ) db_session.commit() logger.info( "Rejected group %s for user %s: %s", diff --git a/tests/admin_api/test_admin.py b/tests/admin_api/test_admin.py index 67644797..c44b1b85 100644 --- a/tests/admin_api/test_admin.py +++ b/tests/admin_api/test_admin.py @@ -1335,6 +1335,7 @@ def test_reject_group_membership_records_reason( test_db_session, as_admin_user, tsi_group, + mock_auth0_client, persistent_factories, ): user = BiocommonsUserFactory.create_sync(group_memberships=[]) @@ -1369,6 +1370,35 @@ def test_reject_group_membership_records_reason( assert history[-1].reason == reason +def test_reject_group_membership_sends_email( + test_client, + test_db_session, + as_admin_user, + tsi_group, + mock_auth0_client, + persistent_factories, +): + user = BiocommonsUserFactory.create_sync(group_memberships=[]) + GroupMembershipFactory.create_sync( + group=tsi_group, + user=user, + approval_status=ApprovalStatusEnum.PENDING.value, + ) + test_db_session.commit() + + group_url = quote(tsi_group.group_id, safe='') + resp = test_client.post( + f"/admin/users/{user.id}/groups/{group_url}/reject", + json={"reason": "Not a TSI consortium member"}, + ) + + assert resp.status_code == 200 + queued_emails = test_db_session.exec(select(EmailNotification)).all() + assert len(queued_emails) == 1 + assert queued_emails[0].to_address == user.email + assert queued_emails[0].status == EmailStatusEnum.PENDING + + def test_reject_group_membership_forbidden_without_group_role( test_client, test_db_session, From 0b511283873a69e71a57ab34bdba20cb2836bbfb Mon Sep 17 00:00:00 2001 From: amandazhu Date: Fri, 17 Apr 2026 11:54:06 +1000 Subject: [PATCH 2/2] fix: make the rejection email only for TSI bundles --- biocommons/emails.py | 16 ++++------------ routers/admin.py | 3 +-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/biocommons/emails.py b/biocommons/emails.py index b9cb5b9f..27970c87 100644 --- a/biocommons/emails.py +++ b/biocommons/emails.py @@ -336,7 +336,6 @@ def compose_welcome_email( def compose_group_membership_rejected_email( *, group_name: str, - group_short_name: str, first_name: str, settings: Settings, ) -> tuple[str, str]: @@ -349,9 +348,9 @@ def compose_group_membership_rejected_email( safe_first_name = html.escape(first_name or "") subject = f"Your {group_name} Service Bundle request" - is_tsi = (group_short_name or "").upper() == "TSI" - if is_tsi: - extra_content = f""" + body_content = f""" +

Dear {safe_first_name},

+

Thank you for your interest in the {safe_group_name} Bundle.

The TSI Bundle available on the Australian BioCommons Access is only for members of the Threatened Species Initiative consortium.

Members are collaborators who have projects supported through our request for partnership rounds. They can access datasets that are under embargo for the first 12 months following their generation.

The Threatened Species Initiative is generating genomic resources that are made openly accessible to the community with the standard registration to the Bioplatforms Australia data portal (now Australian BioCommons Access). You do not need to apply to the TSI Bundle to obtain access to these open access genomics datasets. This is also the case for datasets of all other initiatives presented on the Bioplatforms Data Portal.

@@ -364,14 +363,7 @@ def compose_group_membership_rejected_email(
  • Bioplatforms Australia Data Portal — help@bioplatforms.com
  • Galaxy Australia
  • TSI specific enquiries — smazard@bioplatforms.com
  • - """ - else: - extra_content = "" - - body_content = f""" -

    Dear {safe_first_name},

    -

    Thank you for your interest in the {safe_group_name} Bundle.

    - {extra_content} +

    Thank you,

    BioCommons Access team

    """ diff --git a/routers/admin.py b/routers/admin.py index 09852222..63da8db7 100644 --- a/routers/admin.py +++ b/routers/admin.py @@ -1268,7 +1268,7 @@ def reject_group_membership(user_id: Annotated[str, UserIdParam], session=db_session, commit=False, ) - if membership.user and membership.user.email: + if group_id == GroupEnum.TSI.value and membership.user and membership.user.email: first_name = "there" try: auth0_user = client.get_user(membership.user.id) @@ -1281,7 +1281,6 @@ def reject_group_membership(user_id: Annotated[str, UserIdParam], pass subject, body_html = compose_group_membership_rejected_email( group_name=group_record.name, - group_short_name=group_record.short_name, first_name=first_name, settings=settings, )