diff --git a/backend/src/appointment/routes/waiting_list.py b/backend/src/appointment/routes/waiting_list.py index a39b86c07..adc62009b 100644 --- a/backend/src/appointment/routes/waiting_list.py +++ b/backend/src/appointment/routes/waiting_list.py @@ -1,12 +1,14 @@ import os import sentry_sdk +from posthog import Posthog from sqlalchemy.orm import Session from fastapi import APIRouter, Depends, BackgroundTasks from ..database import repo, schemas, models from ..dependencies.auth import get_admin_subscriber from ..dependencies.database import get_db +from ..dependencies.metrics import get_posthog from ..exceptions import validation from ..l10n import l10n from ..tasks.emails import send_confirm_email, send_invite_account_email @@ -55,6 +57,7 @@ def act_on_waiting_list(data: schemas.TokenForWaitingList, db: Session = Depends action = token_data.get('action') email = token_data.get('email') + print(email) if action is None or email is None: raise validation.InvalidLinkException() @@ -62,6 +65,16 @@ def act_on_waiting_list(data: schemas.TokenForWaitingList, db: Session = Depends if action == WaitingListAction.CONFIRM_EMAIL.value: success = repo.invite.confirm_waiting_list_email(db, email) elif action == WaitingListAction.LEAVE.value: + # If they're a user already then tell the frontend to ship them to the settings page. + waiting_list_entry = repo.invite.get_waiting_list_entry_by_email(db, email) + + if waiting_list_entry and waiting_list_entry.invite_id and waiting_list_entry.invite.subscriber_id: + return { + 'action': action, + 'success': False, + 'redirectToSettings': True + } + success = repo.invite.remove_waiting_list_email(db, email) else: raise validation.InvalidLinkException() @@ -98,7 +111,8 @@ def invite_waiting_list_users( data: schemas.WaitingListInviteAdminIn, background_tasks: BackgroundTasks, db: Session = Depends(get_db), - _: models.Subscriber = Depends(get_admin_subscriber), + posthog: Posthog | None = Depends(get_posthog), + admin: models.Subscriber = Depends(get_admin_subscriber), ): """Invites a list of ids to TBA For each waiting list id: @@ -153,6 +167,14 @@ def invite_waiting_list_users( background_tasks.add_task(send_invite_account_email, to=subscriber.email) accepted.append(waiting_list_user.id) + if posthog: + posthog.capture(distinct_id=admin.unique_hash, event='apmt.admin.invited', properties={ + 'from': 'waitingList', + 'waiting-list-ids': accepted, + 'errors-encountered': len(errors), + 'service': 'apmt' + }) + return schemas.WaitingListInviteAdminOut( accepted=accepted, errors=errors, diff --git a/backend/test/integration/test_waiting_list.py b/backend/test/integration/test_waiting_list.py index 6e0c54593..e0ccf08c4 100644 --- a/backend/test/integration/test_waiting_list.py +++ b/backend/test/integration/test_waiting_list.py @@ -194,6 +194,23 @@ def test_bad_token_data_email_not_in_list(self, with_db, with_client, make_waiti with with_db() as db: assert not db.query(models.WaitingList).filter(models.WaitingList.email == email).first() + def test_already_is_a_subscriber(self, with_db, with_client, make_waiting_list, make_basic_subscriber, make_invite): + """Someone is who already a subscriber should be notified to delete their accounts in the settings page!""" + email = 'hello@example.org' + + sub = make_basic_subscriber(email=email) + invite = make_invite(subscriber_id=sub.id) + _waiting_list = make_waiting_list(email=email, invite_id=invite.id) + + serializer = URLSafeSerializer(os.getenv('SIGNED_SECRET'), 'waiting-list') + confirm_token = serializer.dumps({'email': email, 'action': WaitingListAction.LEAVE.value}) + + response = with_client.post('/waiting-list/action', json={'token': confirm_token}) + + # Ensure the response was okay! + assert response.status_code == 200, response.json() + assert response.json() == { "action": WaitingListAction.LEAVE.value, "success": False, "redirectToSettings": True } + class TestWaitingListAdminView: def test_view_with_admin(self, with_client, with_db, with_l10n, make_waiting_list): diff --git a/frontend/src/components/SettingsAccount.vue b/frontend/src/components/SettingsAccount.vue index 70df0d4d6..8f4631227 100644 --- a/frontend/src/components/SettingsAccount.vue +++ b/frontend/src/components/SettingsAccount.vue @@ -181,7 +181,7 @@ const actuallyDeleteAccount = async () => {