Skip to content

Commit

Permalink
If the user tries to remove their email from the waiting list after b…
Browse files Browse the repository at this point in the history
…eing invited then ship them to the settings/account page.
  • Loading branch information
MelissaAutumn committed Aug 16, 2024
1 parent 69a2753 commit a8780c0
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 9 deletions.
24 changes: 23 additions & 1 deletion backend/src/appointment/routes/waiting_list.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -55,13 +57,24 @@ 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()

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()
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down
17 changes: 17 additions & 0 deletions backend/test/integration/test_waiting_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '[email protected]'

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):
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/SettingsAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ const actuallyDeleteAccount = async () => {
<template>
<div class="flex flex-col gap-8">
<div class="text-3xl font-thin text-gray-500 dark:text-gray-200">{{ t('heading.accountSettings') }}</div>
<div class="flex max-w-3xl flex-col pl-6">
<div class="flex max-w-3xl flex-col pl-6" id="profile">
<div class="text-xl">{{ t('heading.profile') }}</div>
<label class="mt-4 flex items-center pl-4">
<div class="w-full max-w-2xs">{{ t('label.username') }}</div>
Expand Down Expand Up @@ -262,7 +262,7 @@ const actuallyDeleteAccount = async () => {
/>
</div>
</div>
<div class="pl-6">
<div class="pl-6" id="download-your-data">
<div class="text-xl">{{ t('heading.accountData') }}</div>
<div class="mt-4 pl-4">
<primary-button
Expand All @@ -273,7 +273,7 @@ const actuallyDeleteAccount = async () => {
/>
</div>
</div>
<div class="pl-6">
<div class="pl-6" id="delete-your-account">
<div class="text-xl">{{ t('heading.accountDeletion') }}</div>
<div class="mt-4 pl-4">
<caution-button
Expand Down
1 change: 1 addition & 0 deletions frontend/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ export type WaitingListEntry = {
export type WaitingListStatus = {
action: WaitingListAction;
success: boolean;
redirectToSettings?: boolean;
}

export type Signature = {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ router.beforeEach((to, from) => {
const toMeta: ApmtRouteMeta = to?.meta ?? {};
const fromMeta: ApmtRouteMeta = from?.meta ?? {};

if (!toMeta?.isPublic && !['setup', 'contact', 'undefined'].includes(String(to.name))) {
if (!toMeta?.isPublic && !['setup', 'contact', 'settings', 'undefined'].includes(String(to.name))) {
const user = useUserStore();
if (user && user.data?.email && !user.data.isSetup) {
return { ...to, name: 'setup' };
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/views/WaitingListActionView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ onMounted(async () => {
action.value = data?.value?.action;
// They're already a user, and they need to go to settings to delete their account!
if (data?.value?.redirectToSettings) {
await router.replace('/settings/account#delete-your-account');
return;
}
if (usePosthog) {
if (action.value === WaitingListAction.Confirm) {
posthog.capture(MetricEvents.WaitingListEmailConfirmed, {});
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/views/admin/WaitingListPanelView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ const amIAdmin = async () => {
};
const sendInvites = async () => {
console.log("Send!");
loading.value = true;
const idList = selectedFields.value.map((row) => row.id.value);
Expand All @@ -202,13 +201,13 @@ const sendInvites = async () => {
const { data, error } = response;
if (error.value) {
pageError.value = data?.value?.detail?.message ?? t('error.somethingWentWrong');
loading.value = false;
return;
}
const { accepted, errors } = data.value;
console.log(data.value);
pageNotification.value = t('label.sentCountInvitesSuccessfully', {count: accepted.length})
if (errors.length) {
Expand Down

0 comments on commit a8780c0

Please sign in to comment.