From 62d7814f73227966bfe8b333079c2ecfae8de864 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 17 Mar 2026 11:50:47 +0930 Subject: [PATCH 1/5] feat(bookings): [PPT-2375] Email notification to the original host - if the host changes --- src/controllers/bookings.cr | 39 +++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 28268a54..4ab31aa2 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -578,17 +578,29 @@ class Bookings < Application changes.instance = booking.instance existing_booking = booking + original_host_email = existing_booking.user_email original_start = existing_booking.booking_start original_end = existing_booking.booking_end original_assets = existing_booking.asset_ids - {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :all_day, :title, :description, :images, :induction, :recurrence_end, :recurrence_interval, :recurrence_nth_of_month, :recurrence_days, :recurrence_type, :permission] %} + {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :all_day, :title, :description, :images, :induction, :recurrence_end, :recurrence_interval, :recurrence_nth_of_month, :recurrence_days, :recurrence_type, :permission, :user_email] %} begin existing_booking.{{key.id}} = changes.{{key.id}} if changes.{{key.id}}_present? rescue NilAssertionError end {% end %} + # When the host (user_email) changes, resolve the new user's id and name + # from the directory rather than trusting client-supplied values. + if existing_booking.user_email_changed? + if new_user_email = existing_booking.user_email.to_s.presence + new_user = client.get_user_by_email(new_user_email) + raise Error::NotFound.new("user #{new_user_email} not found") unless new_user + existing_booking.user_id = new_user.id.presence || new_user_email + existing_booking.user_name = new_user.name.presence || new_user_email + end + end + extension_data = changes.extension_data unless changes.extension_data.nil? if extension_data booking_ext_data = existing_booking.extension_data @@ -716,7 +728,30 @@ class Bookings < Application end end - update_booking(existing_booking, reset_state ? "changed" : "metadata_changed") + result = update_booking(existing_booking, reset_state ? "changed" : "metadata_changed") + + if original_host_email.to_s.downcase != existing_booking.user_email.to_s.downcase + spawn do + begin + get_placeos_client.root.signal("staff/booking/host_changed", { + action: :host_changed, + booking_id: existing_booking.id, + resource_id: existing_booking.asset_id, + resource_ids: existing_booking.asset_ids, + event_title: existing_booking.title, + event_summary: existing_booking.description.presence || existing_booking.title, + event_starting: existing_booking.booking_start, + previous_host_email: original_host_email, + new_host_email: existing_booking.user_email, + zones: existing_booking.zones, + }) + rescue error + Log.error(exception: error) { "while signaling booking host changed" } + end + end + end + + result end # patches an existing booking extension data with the changes provided From 4ec73ce85daa369bf73767eabb281b630f9bdcb0 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 17 Mar 2026 13:41:41 +0930 Subject: [PATCH 2/5] feat(bookings): [PPT-2375] Email notification to all visitors if the date changes --- src/controllers/bookings.cr | 39 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 4ab31aa2..1ef24abe 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -579,9 +579,10 @@ class Bookings < Application existing_booking = booking original_host_email = existing_booking.user_email - original_start = existing_booking.booking_start - original_end = existing_booking.booking_end - original_assets = existing_booking.asset_ids + original_start = existing_booking.booking_start + original_end = existing_booking.booking_end + original_asset_id = existing_booking.asset_id + original_assets = existing_booking.asset_ids {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :all_day, :title, :description, :images, :induction, :recurrence_end, :recurrence_interval, :recurrence_nth_of_month, :recurrence_days, :recurrence_type, :permission, :user_email] %} begin @@ -728,7 +729,14 @@ class Bookings < Application end end - result = update_booking(existing_booking, reset_state ? "changed" : "metadata_changed") + result = update_booking( + existing_booking, + reset_state ? "changed" : "metadata_changed", + previous_booking_start: original_start, + previous_booking_end: original_end, + previous_resource_id: original_asset_id, + previous_resource_ids: original_assets, + ) if original_host_email.to_s.downcase != existing_booking.user_email.to_s.downcase spawn do @@ -1151,7 +1159,14 @@ class Bookings < Application end end - private def update_booking(booking, signal = "changed") + private def update_booking( + booking, + signal = "changed", + previous_booking_start : Int64? = nil, + previous_booking_end : Int64? = nil, + previous_resource_id : String? = nil, + previous_resource_ids : Array(String)? = nil, + ) booking.save! rescue raise Error::ModelValidation.new(booking.errors.map { |error| {field: error.field.to_s, reason: error.message}.as({field: String?, reason: String}) }, "error validating booking data") spawn do @@ -1161,11 +1176,15 @@ class Bookings < Application id: booking.id, instance: booking.instance, booking_type: booking.booking_type, - booking_start: booking.booking_start, - booking_end: booking.booking_end, - timezone: booking.timezone, - resource_id: booking.asset_id, - resource_ids: booking.asset_ids, + booking_start: booking.booking_start, + booking_end: booking.booking_end, + timezone: booking.timezone, + resource_id: booking.asset_id, + resource_ids: booking.asset_ids, + previous_booking_start: previous_booking_start, + previous_booking_end: previous_booking_end, + previous_resource_id: previous_resource_id, + previous_resource_ids: previous_resource_ids, user_id: booking.user_id, user_email: booking.user_email, user_name: booking.user_name, From 41f7b7c5e00317905cb962196eafe493a8765454 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 17 Mar 2026 13:58:53 +0930 Subject: [PATCH 3/5] feat(bookings): [PPT-2375] Email notification to all visitors if the location changes --- src/controllers/bookings.cr | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 1ef24abe..d9b58cfb 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -579,10 +579,10 @@ class Bookings < Application existing_booking = booking original_host_email = existing_booking.user_email - original_start = existing_booking.booking_start - original_end = existing_booking.booking_end - original_asset_id = existing_booking.asset_id - original_assets = existing_booking.asset_ids + original_start = existing_booking.booking_start + original_end = existing_booking.booking_end + original_assets = existing_booking.asset_ids + original_zones = existing_booking.zones.dup {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :all_day, :title, :description, :images, :induction, :recurrence_end, :recurrence_interval, :recurrence_nth_of_month, :recurrence_days, :recurrence_type, :permission, :user_email] %} begin @@ -734,8 +734,7 @@ class Bookings < Application reset_state ? "changed" : "metadata_changed", previous_booking_start: original_start, previous_booking_end: original_end, - previous_resource_id: original_asset_id, - previous_resource_ids: original_assets, + previous_zones: original_zones, ) if original_host_email.to_s.downcase != existing_booking.user_email.to_s.downcase @@ -1164,8 +1163,7 @@ class Bookings < Application signal = "changed", previous_booking_start : Int64? = nil, previous_booking_end : Int64? = nil, - previous_resource_id : String? = nil, - previous_resource_ids : Array(String)? = nil, + previous_zones : Array(String)? = nil, ) booking.save! rescue raise Error::ModelValidation.new(booking.errors.map { |error| {field: error.field.to_s, reason: error.message}.as({field: String?, reason: String}) }, "error validating booking data") @@ -1183,8 +1181,7 @@ class Bookings < Application resource_ids: booking.asset_ids, previous_booking_start: previous_booking_start, previous_booking_end: previous_booking_end, - previous_resource_id: previous_resource_id, - previous_resource_ids: previous_resource_ids, + previous_zones: previous_zones, user_id: booking.user_id, user_email: booking.user_email, user_name: booking.user_name, From eef262fd3079e51913408c5201bd3529fb42d68c Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 17 Mar 2026 14:00:03 +0930 Subject: [PATCH 4/5] style(bookings): [PPT-2375] crystal tool format --- src/controllers/bookings.cr | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index d9b58cfb..b7561bbf 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -579,10 +579,10 @@ class Bookings < Application existing_booking = booking original_host_email = existing_booking.user_email - original_start = existing_booking.booking_start - original_end = existing_booking.booking_end + original_start = existing_booking.booking_start + original_end = existing_booking.booking_end original_assets = existing_booking.asset_ids - original_zones = existing_booking.zones.dup + original_zones = existing_booking.zones.dup {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :all_day, :title, :description, :images, :induction, :recurrence_end, :recurrence_interval, :recurrence_nth_of_month, :recurrence_days, :recurrence_type, :permission, :user_email] %} begin @@ -1170,10 +1170,10 @@ class Bookings < Application spawn do begin get_placeos_client.root.signal("staff/booking/changed", { - action: signal, - id: booking.id, - instance: booking.instance, - booking_type: booking.booking_type, + action: signal, + id: booking.id, + instance: booking.instance, + booking_type: booking.booking_type, booking_start: booking.booking_start, booking_end: booking.booking_end, timezone: booking.timezone, @@ -1182,21 +1182,21 @@ class Bookings < Application previous_booking_start: previous_booking_start, previous_booking_end: previous_booking_end, previous_zones: previous_zones, - user_id: booking.user_id, - user_email: booking.user_email, - user_name: booking.user_name, - zones: booking.zones, - process_state: booking.process_state, - last_changed: booking.last_changed, - approver_name: booking.approver_name, - approver_email: booking.approver_email, - title: booking.title, - checked_in: booking.checked_in, - description: booking.description, - extension_data: booking.extension_data, - booked_by_email: booking.booked_by_email, - booked_by_name: booking.booked_by_name, - induction: booking.induction, + user_id: booking.user_id, + user_email: booking.user_email, + user_name: booking.user_name, + zones: booking.zones, + process_state: booking.process_state, + last_changed: booking.last_changed, + approver_name: booking.approver_name, + approver_email: booking.approver_email, + title: booking.title, + checked_in: booking.checked_in, + description: booking.description, + extension_data: booking.extension_data, + booked_by_email: booking.booked_by_email, + booked_by_name: booking.booked_by_name, + induction: booking.induction, }) rescue error Log.error(exception: error) { "while signaling booking #{signal}" } From e6fc7cd12d164113494eedd0cf9cb66db2788f50 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 17 Mar 2026 14:10:30 +0930 Subject: [PATCH 5/5] refactor(bookings): --- src/controllers/bookings.cr | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index b7561bbf..e415b2f1 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -591,10 +591,9 @@ class Bookings < Application end {% end %} - # When the host (user_email) changes, resolve the new user's id and name - # from the directory rather than trusting client-supplied values. + # When the host changes, resolve the new user's id and name from the user_email if existing_booking.user_email_changed? - if new_user_email = existing_booking.user_email.to_s.presence + if new_user_email = existing_booking.user_email.presence new_user = client.get_user_by_email(new_user_email) raise Error::NotFound.new("user #{new_user_email} not found") unless new_user existing_booking.user_id = new_user.id.presence || new_user_email