Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions drivers/place/auto_release_locker.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require "placeos-driver"
require "./booking_model"

class Place::AutoReleaseLocker < PlaceOS::Driver
descriptive_name "PlaceOS Auto Release Locker"
generic_name :AutoReleaseLocker
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
@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)
@booking_type = setting?(String, :booking_type).presence || "locker"
@time_window_hours = setting?(Int32, :time_window_hours) || 1

schedule.clear

if release = @release_schedule
schedule.cron(release, @timezone) { release_lockers }
end
end

# Finds the building ID for the current location services object
def get_building_id
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
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],
).get.to_json
results = bookings.select { |booking| booking.checked_in }

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

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

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)
released += 1
rescue error
logger.warn(exception: error) { "unable to release #{@booking_type} with booking id #{booking.id}" }
end
end
{total: bookings.size, released: released}
end
end
159 changes: 159 additions & 0 deletions drivers/place/auto_release_locker_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
require "placeos-driver/spec"

DriverSpecs.mock_driver "Place::BookingCheckInHelper" do
system({
StaffAPI: {StaffAPIMock},
})
resp = exec(:get_bookings).get
resp.should_not be_nil
resp.not_nil!.as_a.size.should eq 4
resp = exec(:release_lockers).get
resp.not_nil!.as_h["total"].should eq 4
resp.not_nil!.as_h["released"].should eq 4
end

# :nodoc:
class StaffAPIMock < DriverSpecs::MockDriver
BOOKINGS = [
{
id: 1,
user_id: "user-one",
user_email: "user_one@example.com",
user_name: "User One",
asset_id: "locker_001",
zones: ["zone-1234"],
booking_type: "locker",
booking_start: (Time.utc - 10.hour).to_unix,
booking_end: (Time.utc + 5.hours).to_unix,
timezone: "Australia/Darwin",
title: "ignore",
description: "",
checked_in: true,
rejected: false,
approved: true,
booked_by_id: "user-one",
booked_by_email: "user_one@example.com",
booked_by_name: "User One",
process_state: "approved",
last_changed: Time.utc.to_unix,
created: Time.utc.to_unix,
},
{
id: 2,
user_id: "user-one",
user_email: "user_one@example.com",
user_name: "User One",
asset_id: "locker_002",
zones: ["zone-1234"],
booking_type: "locker",
booking_start: (Time.utc - 5.minutes).to_unix,
booking_end: (Time.utc + 1.hour).to_unix,
timezone: "Australia/Darwin",
title: "notify",
description: "",
checked_in: true,
rejected: false,
approved: true,
booked_by_id: "user-one",
booked_by_email: "user_one@example.com",
booked_by_name: "User One",
process_state: "approved",
last_changed: Time.utc.to_unix,
created: Time.utc.to_unix,
},
{
id: 3,
user_id: "user-one",
user_email: "user_one@example.com",
user_name: "User One",
asset_id: "locker_003",
zones: ["zone-1234"],
booking_type: "locker",
booking_start: (Time.utc - 11.minutes).to_unix,
booking_end: (Time.utc + 1.hour).to_unix,
timezone: "Australia/Darwin",
title: "reject",
description: "",
checked_in: true,
rejected: false,
approved: true,
booked_by_id: "user-one",
booked_by_email: "user_one@example.com",
booked_by_name: "User One",
process_state: "approved",
last_changed: Time.utc.to_unix,
created: Time.utc.to_unix,
},
{
id: 4,
user_id: "user-one",
user_email: "user_one@example.com",
user_name: "User One",
asset_id: "locker_004",
zones: ["zone-1234"],
booking_type: "locker",
booking_start: (Time.utc - 5.hours).to_unix,
booking_end: (Time.utc + 1.hours).to_unix,
timezone: "Australia/Darwin",
title: "ignore_after_hours",
description: "",
checked_in: true,
rejected: false,
approved: true,
booked_by_id: "user-one",
booked_by_email: "user_one@example.com",
booked_by_name: "User One",
process_state: "approved",
last_changed: Time.utc.to_unix,
created: Time.utc.to_unix,
},
]

def query_bookings(
type : String,
period_start : Int64? = nil,
period_end : Int64? = nil,
zones : Array(String) = [] of String,
user : String? = nil,
email : String? = nil,
state : String? = nil,
created_before : Int64? = nil,
created_after : Int64? = nil,
approved : Bool? = nil,
rejected : Bool? = nil,
checked_in : Bool? = nil
)
JSON.parse(BOOKINGS.to_json)
end

def zones(q : String? = nil,
limit : Int32 = 1000,
offset : Int32 = 0,
parent : String? = nil,
tags : Array(String) | String? = nil)
zones = [
{
created_at: 1660537814,
updated_at: 1681800971,
id: "zone-1234",
name: "Test Zone",
display_name: "Test Zone",
location: "",
description: "",
code: "",
type: "",
count: 0,
capacity: 0,
map_id: "",
tags: [
"building",
],
triggers: [] of String,
parent_id: "zone-0000",
timezone: "Australia/Sydney",
},
]

JSON.parse(zones.to_json)
end
end