Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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).get
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
163 changes: 163 additions & 0 deletions drivers/place/auto_release_locker_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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: "[email protected]",
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

def update_booking(booking_id : String | Int64, booking_end : Int64, checked_in : Bool)
true
end
end