Skip to content

Commit

Permalink
Merge branch 'main' into cleanup-workflow-triggers
Browse files Browse the repository at this point in the history
  • Loading branch information
jdbass authored May 23, 2024
2 parents 9504977 + 501e543 commit d03c2ce
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
deploy-iac:
needs: detect-changes

if: needs.detect-changes.outputs.deploy-iac == 'true'
environment: staging
runs-on: ubuntu-latest
Expand Down Expand Up @@ -118,6 +119,7 @@ jobs:
needs:
- detect-changes
- deploy-iac

if: |
always() &&
(needs.deploy-iac.result == 'success' || needs.deploy-iac.result == 'skipped') &&
Expand Down Expand Up @@ -197,6 +199,7 @@ jobs:
needs:
- detect-changes
- deploy-iac

if: |
always() &&
(needs.deploy-iac.result == 'success' || needs.deploy-iac.result == 'skipped') &&
Expand Down Expand Up @@ -279,9 +282,11 @@ jobs:
- detect-changes
- deploy-backend
- deploy-frontend

if: |
needs.detect-changes.outputs.deploy-backend == 'true' &&
needs.detect-changes.outputs.deploy-frontend == 'true'
environment: staging
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 2 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ REDIS_DB=0
# No value = Python None
REDIS_PASSWORD
REDIS_USE_SSL=False
# Connect to a redis cluster instead of a single instance
REDIS_USE_CLUSTER=False

# In minutes, the time a cached remote event will expire at.
REDIS_EVENT_EXPIRE_TIME=15
Expand Down
7 changes: 3 additions & 4 deletions backend/src/appointment/controller/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
"""
import json
import logging
import uuid
import zoneinfo
import os

import caldav.lib.error
import requests
from redis import Redis
from redis import Redis, RedisCluster
from caldav import DAVClient
from fastapi import BackgroundTasks
from google.oauth2.credentials import Credentials
Expand All @@ -29,11 +28,11 @@


class BaseConnector:
redis_instance: Redis | None
redis_instance: Redis | RedisCluster | None
subscriber_id: int
calendar_id: int

def __init__(self, subscriber_id: int, calendar_id: int | None, redis_instance: Redis | None = None):
def __init__(self, subscriber_id: int, calendar_id: int | None, redis_instance: Redis | RedisCluster | None = None):
self.redis_instance = redis_instance
self.subscriber_id = subscriber_id
self.calendar_id = calendar_id
Expand Down
40 changes: 21 additions & 19 deletions backend/src/appointment/controller/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ def text(self):


class ConfirmationMail(Mailer):
def __init__(self, confirm_url, deny_url, attendee, date, *args, **kwargs):
def __init__(self, confirm_url, deny_url, attendee_name, attendee_email, date, *args, **kwargs):
"""init Mailer with confirmation specific defaults"""
self.attendee = attendee
self.attendee.name = self.attendee.name.title()
self.attendee_name = attendee_name
self.attendee_email = attendee_email
self.date = date
self.confirmUrl = confirm_url
self.denyUrl = deny_url
Expand All @@ -182,26 +182,27 @@ def __init__(self, confirm_url, deny_url, attendee, date, *args, **kwargs):

def text(self):
return l10n('confirm-mail-plain', {
'attendee_name': self.attendee.name,
'attendee_email': self.attendee.email,
'attendee_name': self.attendee_name,
'attendee_email': self.attendee_email,
'date': self.date,
'confirm_url': self.confirmUrl,
'deny_url': self.denyUrl,
})

def html(self):
return get_template("confirm.jinja2").render(
attendee=self.attendee,
attendee_name=self.attendee_name,
attendee_email=self.attendee_email,
date=self.date,
confirm=self.confirmUrl,
deny=self.denyUrl,
)


class RejectionMail(Mailer):
def __init__(self, owner, date, *args, **kwargs):
def __init__(self, owner_name, date, *args, **kwargs):
"""init Mailer with rejection specific defaults"""
self.owner = owner
self.owner_name = owner_name
self.date = date
default_kwargs = {
"subject": l10n('reject-mail-subject')
Expand All @@ -210,18 +211,18 @@ def __init__(self, owner, date, *args, **kwargs):

def text(self):
return l10n('reject-mail-plain', {
'owner_name': self.owner.name,
'owner_name': self.owner_name,
'date': self.date
})

def html(self):
return get_template("rejected.jinja2").render(owner=self.owner, date=self.date)
return get_template("rejected.jinja2").render(owner_name=self.owner_name, date=self.date)


class PendingRequestMail(Mailer):
def __init__(self, owner, date, *args, **kwargs):
def __init__(self, owner_name, date, *args, **kwargs):
"""init Mailer with pending specific defaults"""
self.owner = owner
self.owner_name = owner_name
self.date = date
default_kwargs = {
"subject": l10n('pending-mail-subject')
Expand All @@ -230,18 +231,19 @@ def __init__(self, owner, date, *args, **kwargs):

def text(self):
return l10n('pending-mail-plain', {
'owner_name': self.owner.name,
'owner_name': self.owner_name,
'date': self.date
})

def html(self):
return get_template("pending.jinja2").render(owner=self.owner, date=self.date)
return get_template("pending.jinja2").render(owner_name=self.owner_name, date=self.date)


class SupportRequestMail(Mailer):
def __init__(self, requestee, topic, details, *args, **kwargs):
def __init__(self, requestee_name, requestee_email, topic, details, *args, **kwargs):
"""init Mailer with support specific defaults"""
self.requestee = requestee
self.requestee_name = requestee_name
self.requestee_email = requestee_email
self.topic = topic
self.details = details
default_kwargs = {
Expand All @@ -251,14 +253,14 @@ def __init__(self, requestee, topic, details, *args, **kwargs):

def text(self):
return l10n('support-mail-plain', {
'requestee_name': self.requestee.name,
'requestee_email': self.requestee.email,
'requestee_name': self.requestee_name,
'requestee_email': self.requestee_email,
'topic': self.topic,
'details': self.details,
})

def html(self):
return get_template("support.jinja2").render(requestee=self.requestee, topic=self.topic, details=self.details)
return get_template("support.jinja2").render(requestee_name=self.requestee_name, requestee_email=self.requestee_email, topic=self.topic, details=self.details)


class InviteAccountMail(Mailer):
Expand Down
30 changes: 23 additions & 7 deletions backend/src/appointment/dependencies/database.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from redis import Redis
from redis import Redis, RedisCluster
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

Expand Down Expand Up @@ -29,17 +29,33 @@ def get_db():
db.close()


def get_redis() -> Redis | None:
def get_redis() -> Redis | RedisCluster | None:
"""Retrieves a redis instance or None if redis isn't available."""
# TODO: Create pool and simply grab instance?
if os.getenv('REDIS_URL') is None:
return None

host = os.getenv('REDIS_URL')
port = int(os.getenv('REDIS_PORT'))
db = os.getenv('REDIS_DB')
password = os.getenv('REDIS_PASSWORD')
ssl = os.getenv('REDIS_USE_SSL')

if os.getenv('REDIS_USE_CLUSTER'):
return RedisCluster(
host=host,
port=port,
db=db,
password=password,
ssl=ssl,
decode_responses=True,
)

return Redis(
host=os.getenv('REDIS_URL'),
port=os.getenv('REDIS_PORT'),
db=os.getenv('REDIS_DB'),
password=os.getenv('REDIS_PASSWORD'),
ssl=os.getenv('REDIS_USE_SSL'),
host=host,
port=port,
db=db,
password=password,
ssl=ssl,
decode_responses=True,
)
7 changes: 4 additions & 3 deletions backend/src/appointment/routes/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import requests.exceptions
import validators
from redis import Redis
from redis import Redis, RedisCluster
from requests import HTTPError
from sentry_sdk import capture_exception
from sqlalchemy.exc import SQLAlchemyError
Expand Down Expand Up @@ -316,7 +316,7 @@ def read_remote_events(
db: Session = Depends(get_db),
google_client: GoogleClient = Depends(get_google_client),
subscriber: Subscriber = Depends(get_subscriber),
redis_instance: Redis | None = Depends(get_redis),
redis_instance: Redis | RedisCluster | None = Depends(get_redis),
):
"""endpoint to get events in a given date range from a remote calendar"""
db_calendar = repo.calendar.get(db, calendar_id=id)
Expand Down Expand Up @@ -587,7 +587,8 @@ def send_feedback(

background_tasks.add_task(
send_support_email,
requestee=subscriber,
requestee_name=subscriber.name,
requestee_email=subscriber.email,
topic=form_data.topic,
details=form_data.details,
)
Expand Down
6 changes: 3 additions & 3 deletions backend/src/appointment/routes/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ def request_schedule_availability_slot(
db.commit()

# Sending confirmation email to owner
background_tasks.add_task(send_confirmation_email, url=url, attendee=attendee, date=date, to=subscriber.email)
background_tasks.add_task(send_confirmation_email, url=url, attendee_name=attendee.name, date=date, to=subscriber.email)

# Sending pending email to attendee
background_tasks.add_task(send_pending_email, owner=subscriber, date=attendee_date, to=slot.attendee.email)
background_tasks.add_task(send_pending_email, owner_name=subscriber.name, date=attendee_date, to=slot.attendee.email)

# Mini version of slot, so we can grab the newly created slot id for tests
return schemas.SlotOut(
Expand Down Expand Up @@ -321,7 +321,7 @@ def decide_on_schedule_availability_slot(
date = slot.start.replace(tzinfo=timezone.utc).astimezone(ZoneInfo(subscriber.timezone)).strftime("%c")
date = f"{date}, {slot.duration} minutes"
# send rejection information to bookee
background_tasks.add_task(send_rejection_email, owner=subscriber, date=date, to=slot.attendee.email)
background_tasks.add_task(send_rejection_email, owner_name=subscriber.name, date=date, to=slot.attendee.email)

if slot.appointment_id:
# delete the appointment, this will also delete the slot.
Expand Down
18 changes: 10 additions & 8 deletions backend/src/appointment/tasks/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,31 @@ def send_invite_email(to, attachment):
mail.send()


def send_confirmation_email(url, attendee, date, to):
def send_confirmation_email(url, attendee_name, attendee_email, date, to):
# send confirmation mail to owner
mail = ConfirmationMail(
f"{url}/1",
f"{url}/0",
attendee,
attendee_name,
attendee_email,
date,
to=to
)
mail.send()


def send_pending_email(owner, date, to):
def send_pending_email(owner_name, date, to):
mail = PendingRequestMail(
owner=owner,
owner_name=owner_name,
date=date,
to=to
)
mail.send()


def send_rejection_email(owner, date, to):
def send_rejection_email(owner_name, date, to):
mail = RejectionMail(
owner=owner,
owner_name=owner_name,
date=date,
to=to
)
Expand All @@ -42,9 +43,10 @@ def send_zoom_meeting_failed_email(to, appointment_title):
mail.send()


def send_support_email(requestee, topic, details):
def send_support_email(requestee_name, requestee_email, topic, details):
mail = SupportRequestMail(
requestee=requestee,
requestee_name=requestee_name,
requestee_email=requestee_email,
topic=topic,
details=details,
)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/templates/email/confirm.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html lang="{{ l10n('locale') }}">
<body>
<p>
{{ l10n('confirm-mail-html-heading', {'attendee_name': attendee.name, 'attendee_email': attendee.email, 'date': date}) }}
{{ l10n('confirm-mail-html-heading', {'attendee_name': attendee_name, 'attendee_email': attendee_email, 'date': date}) }}
</p>
<p>
{{ l10n('confirm-mail-html-confirm-text') }}<br>
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/templates/email/pending.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html lang="{{ l10n('locale') }}">
<body>
<p>
{{ l10n('pending-mail-html-heading', {'owner_name': owner.name, 'date': date}) }}
{{ l10n('pending-mail-html-heading', {'owner_name': owner_name, 'date': date}) }}
</p>
{% include 'includes/footer.jinja2' %}
</body>
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/templates/email/rejected.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html lang="{{ l10n('locale') }}">
<body>
<p>
{{ l10n('reject-mail-html-heading', {'owner_name': owner.name, 'date': date}) }}
{{ l10n('reject-mail-html-heading', {'owner_name': owner_name, 'date': date}) }}
</p>
{% include 'includes/footer.jinja2' %}
</body>
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/templates/email/support.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html lang="{{ l10n('locale') }}">
<body>
<p>
{{ l10n('support-mail-html-heading', {'requestee_name': requestee.name, 'requestee_email': requestee.email}) }}
{{ l10n('support-mail-html-heading', {'requestee_name': requestee_name, 'requestee_email': requestee_email}) }}
</p>
<p>
<b>{{ l10n('support-mail-html-topic', {'topic': topic}) }}</b><br>
Expand Down
4 changes: 2 additions & 2 deletions backend/test/unit/test_mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_confirm(self, faker, with_l10n):
now = datetime.datetime.now()
attendee = schemas.AttendeeBase(email=faker.email(), name=faker.name(), timezone='Europe/Berlin')

mailer = ConfirmationMail(confirm_url, deny_url, attendee, now, to=fake_email)
mailer = ConfirmationMail(confirm_url, deny_url, attendee.name, attendee.email, now, to=fake_email)
assert mailer.html()
assert mailer.text()

Expand All @@ -35,7 +35,7 @@ def test_reject(self, faker, with_l10n, make_pro_subscriber):
now = datetime.datetime.now()
fake_email = '[email protected]'

mailer = RejectionMail(owner=subscriber, date=now, to=fake_email)
mailer = RejectionMail(owner_name=subscriber.name, date=now, to=fake_email)
assert mailer.html()
assert mailer.text()

Expand Down
Loading

0 comments on commit d03c2ce

Please sign in to comment.