Skip to content

Commit

Permalink
Update from main (#391)
Browse files Browse the repository at this point in the history
* Fix migration

* Error out the invite routes for now.

We need to add proper access control for these.

* Fix dropdown when nav is in mobile mode.

* Fix name case for unix systems.

* 🔨 Fix unreadable colored placeholder text (#368)

* Timezone information in booking confirmation email (#367)

* 🔨 fix case sensitive filename calls 🙈

* ➕ show timezone for attendee in confirmation email

* 🔨 extend schedule test with attendee timezone

* 🔨 Make attendee timezone mandatory

* 🔨 Fix appointment tests

* Completely disable 'pretty exceptions'.

* Rename Tooltip.vue to ToolTip.vue.

* Provide a default value for existing attendees.

* Fix schedule calendar being tooooo big

* Fix my default value fix

* General Availability Redesign (#374)

* Dark mode fixes for GA Redesign

* One last tweak

* Some final dark mode changes

* Homepage typo fix

* Fix sickening sticky movement on schedule settings, and try to make event day component behave.

* Remove chrome time icon that makes the time input overflow.

* Replace Confetti SVG with 🎉.

* Remove some old illustrations

* Implemented design review feedback:
* Required field (Name) now shows a red asterisk indicating its required
* Made error messages less round.

* New user experience fixes for Schedule Settings:
* Require a connected calendar in order to create a schedule
* Prompt the user to save to create a schedule if they have a calendar connected but no schedule.
* Consolidate component in <snackish-bar/>

* If we don't have a schedule just say it's not active.

* Add a touch function to mdoels.Base. This updates the time_updated (does not save.) And force a touch update after schedule creation

* Revert last commit

* Let's just try some defaults

* Update lang strings (#376)

* Legal and privacy should be public routes

* Move repository functions to own modules (#370)

* 🔨 Move repository functions to own modules

* 🧪 Test repo module init

* Hide unimplemented search

* Reduce sampling and profiling rate to 25% on stage/prod and ignore health check route

* Capture every error on prod for now

* Adjusted calendar settings flow (#381)

* Adjusted calendar settings flow:
* You can now disconnect connected calendars without nuking them.
* You can now remove (delete) calendars that are unconnected.
* Sync still brings them back if they're from a google account.
* Schedule Settings will become inactive if the connected calendar is disconnected.
* Schedule Settings will be deleted if an unconnected calendar that is associated is deleted. (Cascade all from models.Calendar)
* Schedule Settings becomes active if a previously unconnected calendar becomes connected again.

* 🌐 Update lang strings

---------

Co-authored-by: Andreas Müller <[email protected]>

* Ensure the incoming fxa uid matches all existing ones (there should only be one!) (#382)

* Fix 404 flashes (#383)

* 🔨 Handle lazy loaded routes with async components

* 🔨 Fix wrong route name

* 💚 Fix content x-padding for legal pages

* Add prototype notice to README.md

* Add production env for frontend

* update readme with topicbox (#386)

Co-authored-by: Malini Das <[email protected]>

* Constantify some more app environments

* Replace python-jose with PyJWT

* Convert the pem object to the key

* Adjust pem logic

Add leeway

* Add Google API Services disclosure.

* Watch dayBoundary and forward updates to Qalendar. (#389)

---------

Co-authored-by: Melissa Autumn <[email protected]>
Co-authored-by: Mel <[email protected]>
Co-authored-by: Malini Das <[email protected]>
Co-authored-by: Malini Das <[email protected]>
  • Loading branch information
5 people authored May 7, 2024
1 parent ced8f1e commit 62a1aa5
Show file tree
Hide file tree
Showing 76 changed files with 1,617 additions and 1,341 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Thunderbird Appointment

**Note: Thunderbird Appointment is a prototype still in active development, and is not production ready.**

Invite others to grab times on your calendar. Choose a date. Make appointments as easy as it gets.


## Feedback and Support

If you'd like to give feedback or need support, please see our [Topicbox](https://thunderbird.topicbox.com/groups/services).

## Get started

You can either build preconfigured docker containers (database, backend and frontend) or manually set up the application. A more detailed documentation can be found in the [docs folder](./docs/README.md).
Expand Down
2 changes: 1 addition & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ markdown==3.6
MarkupSafe==2.1.2
nh3==0.2.17
python-dotenv==1.0.0
python-jose==3.3.0
python-multipart==0.0.7
PyJWT==2.6.0
pydantic==2.5.2
sentry-sdk==1.26.0
starlette-context==0.3.6
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/commands/create_invite_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def run(n: int):
_, session = get_engine_and_session()
db = session()

codes = repo.generate_invite_codes(db, n)
codes = repo.invite.generate_codes(db, n)

db.close()

Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/controller/apis/fxa_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def token_saver(self, token):
if self.subscriber_id is None:
return

repo.update_subscriber_external_connection_token(next(get_db()), json.dumps(token), self.subscriber_id, models.ExternalConnectionType.fxa)
repo.external_connection.update_token(next(get_db()), json.dumps(token), self.subscriber_id, models.ExternalConnectionType.fxa)

def get_profile(self):
"""Retrieve the user's profile information"""
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/controller/apis/google_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def sync_calendars(self, db, subscriber_id: int, token):

# add calendar
try:
repo.update_or_create_subscriber_calendar(
repo.calendar.update_or_create(
db=db,
calendar=cal,
calendar_url=calendar.get("id"),
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/controller/apis/zoom_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def token_saver(self, token):
return

# get_db is a generator function, retrieve the only yield
repo.update_subscriber_external_connection_token(next(get_db()), json.dumps(token), self.subscriber_id, models.ExternalConnectionType.zoom)
repo.external_connection.update_token(next(get_db()), json.dumps(token), self.subscriber_id, models.ExternalConnectionType.zoom)

def get_me(self):
return self.client.get(f'{self.OAUTH_REQUEST_URL}/users/me').json()
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/controller/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ def existing_events_for_schedule(
# handle calendar events
for calendar in calendars:
if calendar.provider == CalendarProvider.google:
external_connection = utils.list_first(repo.get_external_connections_by_type(db, subscriber.id, schemas.ExternalConnectionType.google))
external_connection = utils.list_first(repo.external_connection.get_by_type(db, subscriber.id, schemas.ExternalConnectionType.google))

if external_connection is None or external_connection.token is None:
raise RemoteCalendarConnectionError()
Expand Down
26 changes: 13 additions & 13 deletions backend/src/appointment/controller/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ def model_to_csv_buffer(models):

def download(db, subscriber: Subscriber):
"""Generate a zip file of csvs that contain a copy of the subscriber's information."""
attendees = repo.get_attendees_by_subscriber(db, subscriber_id=subscriber.id)
appointments = repo.get_appointments_by_subscriber(db, subscriber_id=subscriber.id)
calendars = repo.get_calendars_by_subscriber(db, subscriber_id=subscriber.id)
attendees = repo.attendee.get_by_subscriber(db, subscriber_id=subscriber.id)
appointments = repo.appointment.get_by_subscriber(db, subscriber_id=subscriber.id)
calendars = repo.calendar.get_by_subscriber(db, subscriber_id=subscriber.id)
subscribers = [subscriber]
slots = repo.get_slots_by_subscriber(db, subscriber_id=subscriber.id)
slots = repo.slot.get_by_subscriber(db, subscriber_id=subscriber.id)
external_connections = subscriber.external_connections
schedules = repo.get_schedules_by_subscriber(db, subscriber.id)
availability = [repo.get_availability_by_schedule(db, schedule.id) for schedule in schedules]
schedules = repo.schedule.get_by_subscriber(db, subscriber.id)
availability = [repo.schedule.get_availability(db, schedule.id) for schedule in schedules]

# Convert models to csv
attendee_buffer = model_to_csv_buffer(attendees)
Expand Down Expand Up @@ -79,21 +79,21 @@ def download(db, subscriber: Subscriber):

def delete_account(db, subscriber: Subscriber):
# Ok nuke everything (thanks cascade=all,delete)
repo.delete_subscriber(db, subscriber)
repo.subscriber.delete(db, subscriber)

# Make sure we actually nuked the subscriber
if repo.get_subscriber(db, subscriber.id) is not None:
if repo.subscriber.get(db, subscriber.id) is not None:
raise AccountDeletionSubscriberFail(
subscriber.id,
"There was a problem deleting your data. This incident has been logged and your data will manually be removed.",
)

empty_check = [
len(repo.get_attendees_by_subscriber(db, subscriber.id)),
len(repo.get_slots_by_subscriber(db, subscriber.id)),
len(repo.get_appointments_by_subscriber(db, subscriber.id)),
len(repo.get_calendars_by_subscriber(db, subscriber.id)),
len(repo.get_schedules_by_subscriber(db, subscriber.id))
len(repo.attendee.get_by_subscriber(db, subscriber.id)),
len(repo.slot.get_by_subscriber(db, subscriber.id)),
len(repo.appointment.get_by_subscriber(db, subscriber.id)),
len(repo.calendar.get_by_subscriber(db, subscriber.id)),
len(repo.schedule.get_by_subscriber(db, subscriber.id))
]

# Check if we have any left-over subscriber data
Expand Down
9 changes: 7 additions & 2 deletions backend/src/appointment/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ class Base:
def __tablename__(cls):
return cls.__name__.lower()

time_created = Column(DateTime, server_default=func.now(), index=True)
time_updated = Column(DateTime, server_default=func.now(), onupdate=func.now(), index=True)
def touch(self):
"""Updates the time_updated field with the current datetime. This function does not save the model!"""
self.time_updated = datetime.datetime.now()

time_created = Column(DateTime, server_default=func.now(), default=func.now(), index=True)
time_updated = Column(DateTime, server_default=func.now(), default=func.now(), onupdate=func.now(), index=True)


class Subscriber(Base):
Expand Down Expand Up @@ -170,6 +174,7 @@ class Attendee(Base):
id = Column(Integer, primary_key=True, index=True)
email = Column(StringEncryptedType(String, secret, AesEngine, "pkcs5", length=255), index=True)
name = Column(StringEncryptedType(String, secret, AesEngine, "pkcs5", length=255), index=True)
timezone = Column(String(255), index=True)

slots = relationship("Slot", cascade="all,delete", back_populates="attendee")

Expand Down
Loading

0 comments on commit 62a1aa5

Please sign in to comment.