From ee65b66719b8022163da0d59f4cb73e73d4b9a6f Mon Sep 17 00:00:00 2001 From: Mel <97147377+MelissaAutumn@users.noreply.github.com> Date: Wed, 31 Jul 2024 09:07:56 -0700 Subject: [PATCH] Various ics/google event improvements (Fixes #586, #588, and #584) (#595) * Various ics/google event improvements (Fixes #586, #588, and #584) * Include meeting link url in the location field * Auto confirm/accept booked meetings * Update the confirm email subject to include the name of the person who requested the booking * Add test for meeting url in ics file --- backend/src/appointment/controller/calendar.py | 12 +++++++----- backend/src/appointment/controller/mailer.py | 2 +- backend/src/appointment/l10n/en/email.ftl | 4 +++- backend/src/appointment/routes/schedule.py | 5 ++--- backend/src/appointment/tasks/emails.py | 3 ++- backend/test/factory/appointment_factory.py | 2 +- backend/test/unit/test_calendar_tools.py | 14 ++++++++++++++ 7 files changed, 30 insertions(+), 12 deletions(-) diff --git a/backend/src/appointment/controller/calendar.py b/backend/src/appointment/controller/calendar.py index a130d99f4..13f2c5495 100644 --- a/backend/src/appointment/controller/calendar.py +++ b/backend/src/appointment/controller/calendar.py @@ -228,13 +228,13 @@ def create_event( body = { 'iCalUID': event.uuid.hex, 'summary': event.title, - 'location': event.location.name, + 'location': event.location.url if event.location.url else None, 'description': '\n'.join(description), 'start': {'dateTime': event.start.isoformat()}, 'end': {'dateTime': event.end.isoformat()}, 'attendees': [ - {'displayName': organizer.name, 'email': organizer_email}, - {'displayName': attendee.name, 'email': attendee.email}, + {'displayName': organizer.name, 'email': organizer_email, 'responseStatus': 'accepted'}, + {'displayName': attendee.name, 'email': attendee.email, 'responseStatus': 'accepted'}, ], 'organizer': { 'displayName': organizer.name, @@ -414,13 +414,14 @@ def create_vevent( slot.start.replace(tzinfo=timezone.utc) + timedelta(minutes=slot.duration), ) event.add('dtstamp', datetime.now(UTC)) + event.add('status', 'CONFIRMED') event['description'] = appointment.details event['organizer'] = org # Prefer the slot meeting link url over the appointment location url location_url = slot.meeting_link_url if slot.meeting_link_url is not None else appointment.location_url - if location_url != '' or location_url is not None: + if location_url: event.add('location', location_url) cal.add_component(event) @@ -435,10 +436,11 @@ def send_vevent( attendee: schemas.AttendeeBase, ): """send a booking confirmation email to attendee with .ics file attached""" + ics = self.create_vevent(appointment, slot, organizer) invite = Attachment( mime=('text', 'calendar'), filename='AppointmentInvite.ics', - data=self.create_vevent(appointment, slot, organizer), + data=ics, ) background_tasks.add_task(send_invite_email, to=attendee.email, attachment=invite) diff --git a/backend/src/appointment/controller/mailer.py b/backend/src/appointment/controller/mailer.py index d97d29931..27e635fdb 100644 --- a/backend/src/appointment/controller/mailer.py +++ b/backend/src/appointment/controller/mailer.py @@ -173,7 +173,7 @@ def __init__(self, confirm_url, deny_url, attendee_name, attendee_email, date, * self.date = date self.confirmUrl = confirm_url self.denyUrl = deny_url - default_kwargs = {'subject': l10n('confirm-mail-subject')} + default_kwargs = {'subject': l10n('confirm-mail-subject', {'attendee_name': self.attendee_name})} super(ConfirmationMail, self).__init__(*args, **default_kwargs, **kwargs) def text(self): diff --git a/backend/src/appointment/l10n/en/email.ftl b/backend/src/appointment/l10n/en/email.ftl index 4ecb73759..36d9ad9ae 100644 --- a/backend/src/appointment/l10n/en/email.ftl +++ b/backend/src/appointment/l10n/en/email.ftl @@ -15,7 +15,9 @@ invite-mail-html = {-brand-footer} ## Confirm Appointment -confirm-mail-subject = Confirm booking request from {-brand-name} +# Variables +# $attendee_name (String) - Name of the person who requested the appointment +confirm-mail-subject = Action Required: Confirm booking request from { $attendee_name } # Variables: # $attendee_name (String) - Name of the person who requested the appointment # $appointment_email (String) - Email of the person who requested the appointment diff --git a/backend/src/appointment/routes/schedule.py b/backend/src/appointment/routes/schedule.py index 533f6a2cd..cbdb88f12 100644 --- a/backend/src/appointment/routes/schedule.py +++ b/backend/src/appointment/routes/schedule.py @@ -484,15 +484,14 @@ def handle_schedule_availability_decision( if os.getenv('SENTRY_DSN') != '': capture_exception(err) - event = schemas.Event( title=title, start=slot.start.replace(tzinfo=timezone.utc), end=slot.start.replace(tzinfo=timezone.utc) + timedelta(minutes=slot.duration), description=schedule.details or '', location=schemas.EventLocation( - type=schedule.location_type, - url=location_url, + type=models.LocationType.online, + url=slot.meeting_link_url if slot.meeting_link_url else location_url, name=None, ), uuid=slot.appointment.uuid if slot.appointment else None, diff --git a/backend/src/appointment/tasks/emails.py b/backend/src/appointment/tasks/emails.py index 125cc4b65..623182b3a 100644 --- a/backend/src/appointment/tasks/emails.py +++ b/backend/src/appointment/tasks/emails.py @@ -8,7 +8,8 @@ ZoomMeetingFailedMail, RejectionMail, SupportRequestMail, - InviteAccountMail, ConfirmYourEmailMail, + InviteAccountMail, + ConfirmYourEmailMail, ) diff --git a/backend/test/factory/appointment_factory.py b/backend/test/factory/appointment_factory.py index 7298875cc..7cc14e5a1 100644 --- a/backend/test/factory/appointment_factory.py +++ b/backend/test/factory/appointment_factory.py @@ -55,7 +55,7 @@ def _make_appointment( if not factory_has_value(slots): make_appointment_slot(appointment_id=appointment.id) - else: + elif slots is not None: repo.slot.add_for_appointment(db, slots, appointment.id) # Refresh our appointment now that is has slot data diff --git a/backend/test/unit/test_calendar_tools.py b/backend/test/unit/test_calendar_tools.py index 835904cfd..6ca991ac1 100644 --- a/backend/test/unit/test_calendar_tools.py +++ b/backend/test/unit/test_calendar_tools.py @@ -56,3 +56,17 @@ def test_events_roll_up_difference(self): assert rolled_up_slots[0].booking_status == models.BookingStatus.booked assert rolled_up_slots[1].booking_status == models.BookingStatus.requested assert rolled_up_slots[2].booking_status == models.BookingStatus.booked + + +class TestVCreate: + def test_meeting_url_in_location(self, with_db, make_google_calendar, make_appointment, make_appointment_slot, make_pro_subscriber): + subscriber = make_pro_subscriber() + calendar = make_google_calendar(subscriber_id=subscriber.id) + appointment = make_appointment(calendar_id=calendar.id) + slot = appointment.slots[0] + + slot.meeting_link_url = 'https://thunderbird.net' + + ics = Tools().create_vevent(appointment, slot, subscriber) + assert ics + assert ':'.join(['LOCATION', slot.meeting_link_url])