Skip to content

Commit

Permalink
feat(auto_release_locker): simplify deployment requirements
Browse files Browse the repository at this point in the history
ensure cron is configured
improve security
  • Loading branch information
stakach committed Feb 10, 2025
1 parent f973eb7 commit 6ad6cd7
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 24 deletions.
49 changes: 28 additions & 21 deletions drivers/place/auto_release_locker.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,80 @@ class Place::AutoReleaseLocker < PlaceOS::Driver
description %(automatic release locker on specified interval)

default_settings({
timezone: "Australia/Sydney",
booking_type: "locker",
release_schedule: "0 23 * * 5",
time_window_hours: 1,
})

accessor staff_api : StaffAPI_1

@timezone : Time::Location = Time::Location.load("Australia/Sydney")
@booking_type : String = "locker"
@release_schedule : String? = nil
@release_schedule : String = "0 23 * * 5"
@time_window_hours : Int32 = 1

def on_update
@release_schedule = setting?(String, :release_schedule).presence
timezone = setting?(String, :timezone).presence || "Australia/Sydney"
@timezone = Time::Location.load(timezone)
@timezone = nil
@building_id = nil
@booking_type = setting?(String, :booking_type).presence || "locker"
@time_window_hours = setting?(Int32, :time_window_hours) || 1
@release_schedule = setting(String, :release_schedule)

schedule.clear
schedule_cron
end

if release = @release_schedule
schedule.cron(release, @timezone) { release_lockers }
end
protected def schedule_cron : Nil
schedule.cron(@release_schedule, timezone) { release_lockers }
rescue error
logger.warn(exception: error) { "failed to schedule cron job" }
schedule.in(1.minute) { schedule_cron }
end

# Finds the building ID for the current location services object
def get_building_id
getter building_id : String do
zone_ids = staff_api.zones(tags: "building").get.as_a.map(&.[]("id").as_s)
(zone_ids & system.zones).first
rescue error
logger.warn(exception: error) { "unable to determine building zone id" }
nil
raise error
end

protected getter timezone : Time::Location do
tz = config.control_system.try(&.timezone) || staff_api.zone(building_id).get["timezone"].as_s
Time::Location.load(tz)
end

@[Security(Level::Support)]
def get_bookings : Array(Booking)
results = [] of Booking
bookings = Array(Booking).from_json staff_api.query_bookings(
type: @booking_type,
period_start: Time.utc.to_unix,
period_end: (Time.utc + @time_window_hours.hours).to_unix,
zones: [get_building_id],
zones: [building_id],
).get.to_json
results = bookings.select { |booking| booking.checked_in }

logger.debug { "found #{results.size} #{@booking_type} bookings" }
logger.debug { "found #{bookings.size} #{@booking_type} bookings" }

results
bookings
rescue error
logger.warn(exception: error) { "unable to obtain list of #{@booking_type} bookings" }
[] of Booking
end

@[Security(Level::Support)]
def release_lockers
bookings = get_bookings
released = 0
bookings.each do |booking|
logger.debug { "releasing booking #{booking.id} as it is within the time_after window" }
begin
staff_api.update_booking(booking_id: booking.id, booking_end: Time.utc.to_unix, checked_in: false).get
staff_api.update_booking(booking.id, recurrence_end: booking.booking_end).get if booking.instance
staff_api.booking_check_in(booking.id, false, "auto-release", instance: booking.instance).get
released += 1
rescue error
logger.warn(exception: error) { "unable to release #{@booking_type} with booking id #{booking.id}" }
logger.warn(exception: error) { "unable to release #{@booking_type} with booking id #{booking.id} (inst: #{booking.instance})" }
end
end
{total: bookings.size, released: released}
results = {total: bookings.size, released: released}
logger.debug { results.inspect }
results
end
end
24 changes: 21 additions & 3 deletions drivers/place/auto_release_locker_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class StaffAPIMock < DriverSpecs::MockDriver
rejected : Bool? = nil,
checked_in : Bool? = nil
)
JSON.parse(BOOKINGS.to_json)
BOOKINGS
end

def zones(q : String? = nil,
Expand Down Expand Up @@ -154,10 +154,28 @@ class StaffAPIMock < DriverSpecs::MockDriver
},
]

JSON.parse(zones.to_json)
zones
end

def update_booking(booking_id : String | Int64, booking_end : Int64, checked_in : Bool)
def update_booking(
booking_id : String | Int64,
booking_start : Int64? = nil,
booking_end : Int64? = nil,
asset_id : String? = nil,
title : String? = nil,
description : String? = nil,
timezone : String? = nil,
extension_data : JSON::Any? = nil,
approved : Bool? = nil,
checked_in : Bool? = nil,
limit_override : Int64? = nil,
instance : Int64? = nil,
recurrence_end : Int64? = nil,
)
true
end

def booking_check_in(booking_id : String | Int64, state : Bool = true, utm_source : String? = nil, instance : Int64? = nil)
true
end
end

0 comments on commit 6ad6cd7

Please sign in to comment.