diff --git a/drivers/place/at_capacity_mailer.cr b/drivers/place/at_capacity_mailer.cr index 0ffd2f2192..aa9beb135a 100644 --- a/drivers/place/at_capacity_mailer.cr +++ b/drivers/place/at_capacity_mailer.cr @@ -8,7 +8,7 @@ class Place::AtCapacityMailer < PlaceOS::Driver descriptive_name "PlaceOS At Capacity Mailer" generic_name :AtCapacityMailer - description %() + description %(sends a notification when the specified type is at capacity) default_settings({ timezone: "Australia/Sydney", @@ -62,6 +62,7 @@ class Place::AtCapacityMailer < PlaceOS::Driver @time_window_hours = setting?(Int32, :time_window_hours) || 1 @debounce_time_minutes = setting?(Int32, :debounce_time_minutes) || 60 + @email_template = setting?(String, :email_template) || "at_capacity" @unique_templates = setting?(Bool, :unique_templates) || false @template_suffix = @unique_templates ? "_#{@booking_type}" : "" @template_fields_suffix = @unique_templates ? " (#{@booking_type})" : "" diff --git a/drivers/place/room_at_capacity_mailer.cr b/drivers/place/room_at_capacity_mailer.cr new file mode 100644 index 0000000000..ac8f0b6de3 --- /dev/null +++ b/drivers/place/room_at_capacity_mailer.cr @@ -0,0 +1,148 @@ +require "placeos-driver" +require "placeos-driver/interface/mailer" +require "placeos-driver/interface/mailer_templates" + +class Place::RoomAtCapacityMailer < PlaceOS::Driver + include PlaceOS::Driver::Interface::MailerTemplates + + descriptive_name "PlaceOS Room at capacity mailer" + generic_name :RoomAtCapacityMailer + description %(notifies when a room is at capacity) + + default_settings({ + notify_email: ["concierge@place.com"], + email_template: "room_at_capacity", + debounce_time_minutes: 60, # the time to wait before sending another email + check_every_minutes: 5, # the frequency to check rooms + over_capactity_detected_count: 2, # the number of times over capacity before sending an email + }) + + accessor staff_api : StaffAPI_1 + accessor locations : LocationServices_1 + + def mailer + system.implementing(Interface::Mailer)[0] + end + + getter building_id : String do + locations.building_id.get.as_s + end + + # Grabs the list of systems in the building + getter systems : Hash(String, Array(String)) do + staff_api.systems_in_building(building_id).get.as_h.transform_values(&.as_a.map(&.as_s)) + end + + def on_load + on_update + end + + @notify_email : Array(String) = [] of String + @email_template : String = "room_at_capacity" + @debounce_time_minutes : Int32 = 60 + @over_capactity_detected_count : Int32 = 2 + + @last_email_sent : Hash(String, Time) = {} of String => Time + @over_capacity : Hash(String, Int32) = Hash(String, Int32).new { |hash, sys_id| hash[sys_id] = 0 } + + def on_update + @building_id = nil + @systems = nil + + @notify_email = setting?(Array(String), :notify_email) || [] of String + @email_template = setting?(String, :email_template) || "room_at_capacity" + @debounce_time_minutes = setting?(Int32, :debounce_time_minutes) || 60 + @over_capactity_detected_count = setting?(Int32, :over_capactity_detected_count) || 2 + + period = setting?(Int32, :check_every_minutes) || 5 + schedule.clear + schedule.every(period.minutes) { check_capacity } + end + + def check_capacity + systems.each do |level_id, system_ids| + system_ids.each do |system_id| + sys = system(system_id) + next unless sys.exists?("Bookings", 1) + next unless sys.capacity > 0 + + if people_count = sys.get("Bookings", 1).status?(Int32, "people_count") + logger.debug { "people count for #{system_id}: #{people_count}" } + + if people_count >= sys.capacity + @over_capacity[system_id] += 1 + else + @over_capacity[system_id] = 0 + end + + if (over = @over_capacity[system_id]?) && over == @over_capactity_detected_count + send_email( + sys.capacity, + people_count, + system_id, + sys.name, + sys.display_name, + sys.description, + sys.email, + ) + end + end + end + end + end + + @[Security(Level::Support)] + def send_email( + capacity : Int32, + people_count : Int32, + system_id : String, + name : String? = nil, + display_name : String? = nil, + description : String? = nil, + system_email : String? = nil, + ) + if (last = @last_email_sent[system_id]?) && Time.utc - last < @debounce_time_minutes.minutes + logger.debug { "skipping email for #{system_id} due to debounce timer" } + return + end + + args = { + system_id: system_id, + name: name, + display_name: display_name, + description: description, + system_email: system_email, + capacity: capacity, + people_count: people_count, + } + + begin + mailer.send_template( + to: @notify_email, + template: {"room_at_capacity", @email_template}, + args: args) + @last_email_sent[system_id] = Time.utc + rescue error + logger.warn(exception: error) { "failed to send at capacity email for zone #{system_id}" } + end + end + + def template_fields : Array(TemplateFields) + [ + TemplateFields.new( + trigger: {"room_at_capacity", @email_template}, + name: "Room at capacity", + description: "Notification when a room is at capacity", + fields: [ + {name: "system_id", description: "Identifier of the room/system"}, + {name: "name", description: "Room name"}, + {name: "display_name", description: "Room display name"}, + {name: "description", description: "Room description"}, + {name: "system_email", description: "System/room email address"}, + {name: "capacity", description: "Capacity of the room"}, + {name: "people_count", description: "Number of people in the room"}, + ] + ), + ] + end +end