diff --git a/backend/src/appointment/controller/mailer.py b/backend/src/appointment/controller/mailer.py index 5364d45c7..a0b07419d 100644 --- a/backend/src/appointment/controller/mailer.py +++ b/backend/src/appointment/controller/mailer.py @@ -259,3 +259,19 @@ def text(self): def html(self): return get_template("support.jinja2").render(requestee=self.requestee, topic=self.topic, details=self.details) + + +class InviteAccountMail(Mailer): + def __init__(self, *args, **kwargs): + default_kwargs = { + "subject": l10n('new-account-mail-subject') + } + super(InviteAccountMail, self).__init__(*args, **default_kwargs, **kwargs) + + def text(self): + return l10n('new-account-mail-plain', { + 'homepage_url': os.getenv('FRONTEND_URL'), + }) + + def html(self): + return get_template("new_account.jinja2").render(homepage_url=os.getenv('FRONTEND_URL')) diff --git a/backend/src/appointment/dependencies/auth.py b/backend/src/appointment/dependencies/auth.py index fc18e9791..b1d3b99c9 100644 --- a/backend/src/appointment/dependencies/auth.py +++ b/backend/src/appointment/dependencies/auth.py @@ -57,11 +57,8 @@ def get_subscriber( def get_admin_subscriber( user: models.Subscriber = Depends(get_subscriber), - db: Session = Depends(get_db), ): - if user is None: - raise InvalidTokenException() - + """Retrieve the subscriber and check if they're an admin""" # check admin allow list admin_emails = os.getenv("APP_ADMIN_ALLOW_LIST", '').split(',') if not any([user.email.endswith(allowed_email) for allowed_email in admin_emails]): diff --git a/backend/src/appointment/l10n/en/email.ftl b/backend/src/appointment/l10n/en/email.ftl index f25844fb7..4f2e0ccf0 100644 --- a/backend/src/appointment/l10n/en/email.ftl +++ b/backend/src/appointment/l10n/en/email.ftl @@ -103,3 +103,14 @@ support-mail-plain = { $requestee_name } ({ $requestee_email }) sent the followi Topic: { $topic } Details: { $details } {-brand-footer} + +## New/Invited Account Email +new-account-mail-subject = You've been invited to Thunderbird Appointment +new-account-mail-action = Continue to Thunderbird Appointment +new-account-mail-html-heading = You've been invited to Thunderbird Appointment. Login with this email address to continue. +# Variables: +# $homepage_url (String) - URL to Thunderbird Appointment +new-account-mail-plain = You've been invited to Thunderbird Appointment. + Login with this email address to continue. + { $homepage_url } + {-brand-footer} diff --git a/backend/src/appointment/routes/invite.py b/backend/src/appointment/routes/invite.py index 01eb7e402..dfa097071 100644 --- a/backend/src/appointment/routes/invite.py +++ b/backend/src/appointment/routes/invite.py @@ -1,5 +1,4 @@ - -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, BackgroundTasks from sqlalchemy.orm import Session @@ -9,6 +8,7 @@ from ..dependencies.database import get_db from ..exceptions import validation +from ..tasks.emails import send_invite_account_email router = APIRouter() @@ -48,3 +48,30 @@ def revoke_invite_code(code: str, db: Session = Depends(get_db), admin: Subscrib if not repo.invite.code_is_available(db, code): raise validation.InviteCodeNotAvailableException() return repo.invite.revoke_code(db, code) + + +@router.post("/send", response_model=schemas.Invite) +def send_invite_email( + background_tasks: BackgroundTasks, + email: str, + db: Session = Depends(get_db), + # Note admin must be here to for permission reasons + _admin: Subscriber = Depends(get_admin_subscriber) +): + """With a given email address, generate a subscriber and email them, welcoming them to Thunderbird Appointment.""" + invite_code = repo.invite.generate_codes(db, 1)[0] + subscriber = repo.subscriber.create(db, schemas.SubscriberBase( + email=email, + username=email, + )) + + if not subscriber: + raise RuntimeError + + invite_code.subscriber_id = subscriber.id + db.add(invite_code) + db.commit() + + background_tasks.add_task(send_invite_account_email, to=email) + + return invite_code diff --git a/backend/src/appointment/tasks/emails.py b/backend/src/appointment/tasks/emails.py index 4f5eb1fc4..326119fc9 100644 --- a/backend/src/appointment/tasks/emails.py +++ b/backend/src/appointment/tasks/emails.py @@ -1,5 +1,5 @@ from appointment.controller.mailer import PendingRequestMail, ConfirmationMail, InvitationMail, ZoomMeetingFailedMail, \ - RejectionMail, SupportRequestMail + RejectionMail, SupportRequestMail, InviteAccountMail def send_invite_email(to, attachment): @@ -49,3 +49,8 @@ def send_support_email(requestee, topic, details): details=details, ) mail.send() + + +def send_invite_account_email(to): + mail = InviteAccountMail(to=to) + mail.send() diff --git a/backend/src/appointment/templates/email/new_account.jinja2 b/backend/src/appointment/templates/email/new_account.jinja2 new file mode 100644 index 000000000..8d8aacfc5 --- /dev/null +++ b/backend/src/appointment/templates/email/new_account.jinja2 @@ -0,0 +1,21 @@ + +
++ {{ l10n('new-account-html-heading') }} +
+ + {% include 'includes/footer.jinja2' %} + +