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
36 changes: 10 additions & 26 deletions OPENAPI_DOC.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6481,38 +6481,22 @@ paths:
will return a list of system_ids that are already booked during the specified
time range

if system_ids is set, then it will only return booked systems from that list'
if system_id is set on the event, then it will only return booked systems
from that list'
tags:
- Events
operationId: Events_clashing_assets
parameters:
- name: period_start
in: query
description: event period start as a unix epoch
example: "1661725146"
required: true
schema:
type: integer
format: Int64
- name: period_end
in: query
description: event period end as a unix epoch
example: "1661743123"
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlaceCalendar__Event'
required: true
schema:
type: integer
format: Int64
- name: system_ids
in: query
description: comma separated list of system_ids to check for clashes
example: sys-1234,sys-5678
schema:
type: string
nullable: true
parameters:
- name: return_available
in: query
description: return available systems, this requires system_ids be set to
the full list
description: return available systems, this requires system_id be set on the
event
example: "false"
schema:
type: boolean
Expand Down
72 changes: 58 additions & 14 deletions spec/controllers/events_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1348,9 +1348,18 @@ describe Events, tags: ["event"] do
EventMetadatasHelper.create_event(tenant.id, system_id: "sys-5678", event_start: event_start + 5, event_end: event_end + 5)
EventMetadatasHelper.create_event(tenant.id, system_id: "sys-9999", event_start: event_end + 100, event_end: event_end + 200)

clashing_event_body = {
event_start: event_start,
event_end: event_end,
attendees: [] of String,
private: false,
all_day: false,
}.to_json

response = client.post(
"#{EVENTS_BASE}/clashing-assets?period_start=#{event_start}&period_end=#{event_end}",
headers: headers
"#{EVENTS_BASE}/clashing-assets",
headers: headers,
body: clashing_event_body
)
response.status_code.should eq(200)

Expand All @@ -1361,17 +1370,27 @@ describe Events, tags: ["event"] do
clashing.should_not contain("sys-9999")
end

it "returns only clashing system_ids from provided list" do
it "returns only clashing system_ids from provided system_id" do
tenant = get_tenant
event_start = 10.minutes.from_now.to_unix
event_end = 30.minutes.from_now.to_unix

EventMetadatasHelper.create_event(tenant.id, system_id: "sys-1234", event_start: event_start, event_end: event_end)
EventMetadatasHelper.create_event(tenant.id, system_id: "sys-5678", event_start: event_start, event_end: event_end)

clashing_event_body = {
event_start: event_start,
event_end: event_end,
system_id: "sys-1234",
attendees: [] of String,
private: false,
all_day: false,
}.to_json

response = client.post(
"#{EVENTS_BASE}/clashing-assets?period_start=#{event_start}&period_end=#{event_end}&system_ids=sys-1234,sys-9999",
headers: headers
"#{EVENTS_BASE}/clashing-assets",
headers: headers,
body: clashing_event_body
)
response.status_code.should eq(200)

Expand All @@ -1388,16 +1407,23 @@ describe Events, tags: ["event"] do

EventMetadatasHelper.create_event(tenant.id, system_id: "sys-1234", event_start: event_start, event_end: event_end)

clashing_event_body = {
event_start: event_start,
event_end: event_end,
system_id: "sys-1234",
attendees: [] of String,
private: false,
all_day: false,
}.to_json

response = client.post(
"#{EVENTS_BASE}/clashing-assets?period_start=#{event_start}&period_end=#{event_end}&system_ids=sys-1234,sys-5678,sys-9999&return_available=true",
headers: headers
"#{EVENTS_BASE}/clashing-assets?return_available=true",
headers: headers,
body: clashing_event_body
)
response.status_code.should eq(200)

available = Array(String).from_json(response.body)
available.size.should eq(2)
available.should contain("sys-5678")
available.should contain("sys-9999")
available.should_not contain("sys-1234")
end

Expand All @@ -1408,9 +1434,18 @@ describe Events, tags: ["event"] do

EventMetadatasHelper.create_event(tenant.id, system_id: "sys-1234", event_start: event_start, event_end: event_end)

clashing_event_body = {
event_start: event_start,
event_end: event_end,
attendees: [] of String,
private: false,
all_day: false,
}.to_json

response = client.post(
"#{EVENTS_BASE}/clashing-assets?period_start=#{event_start}&period_end=#{event_end}&include_clash_time=true",
headers: headers
"#{EVENTS_BASE}/clashing-assets?include_clash_time=true",
headers: headers,
body: clashing_event_body
)
response.status_code.should eq(200)

Expand All @@ -1431,9 +1466,18 @@ describe Events, tags: ["event"] do
cancelled_event.cancelled = true
cancelled_event.save!

clashing_event_body = {
event_start: event_start,
event_end: event_end,
attendees: [] of String,
private: false,
all_day: false,
}.to_json

response = client.post(
"#{EVENTS_BASE}/clashing-assets?period_start=#{event_start}&period_end=#{event_end}",
headers: headers
"#{EVENTS_BASE}/clashing-assets",
headers: headers,
body: clashing_event_body
)
response.status_code.should eq(200)

Expand Down
40 changes: 20 additions & 20 deletions src/controllers/events.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1765,55 +1765,55 @@ class Events < Application

# lists conflicting system_ids based on event time range
# will return a list of system_ids that are already booked during the specified time range
# if system_ids is set, then it will only return booked systems from that list
@[AC::Route::POST("/clashing-assets")]
# if system_id is set on the event, then it will only return booked systems from that list
@[AC::Route::POST("/clashing-assets", body: :input_event)]
def clashing_assets(
@[AC::Param::Info(name: "period_start", description: "event period start as a unix epoch", example: "1661725146")]
starting : Int64,
@[AC::Param::Info(name: "period_end", description: "event period end as a unix epoch", example: "1661743123")]
ending : Int64,
@[AC::Param::Info(description: "comma separated list of system_ids to check for clashes", example: "sys-1234,sys-5678")]
system_ids : String? = nil,
@[AC::Param::Info(description: "return available systems, this requires system_ids be set to the full list", example: "false")]
input_event : PlaceCalendar::Event,
@[AC::Param::Info(description: "return available systems, this requires system_id be set on the event", example: "false")]
return_available : Bool = false,
@[AC::Param::Info(description: "include the clash times, this is not compatible with return_available", example: "false")]
include_clash_time : Bool = false,
) : Array(String) | Array(NamedTuple(system_id: String, event_start: Int64, event_end: Int64))
if return_available && system_ids.nil?
raise Error::ModelValidation.new([{field: "system_ids".as(String?), reason: "Missing system_ids"}], "error validating event data")
raise Error::BadRequest.new("event_start must be present") unless event_start = input_event.event_start
raise Error::BadRequest.new("event_end must be present") unless event_end = input_event.event_end

sys_id = input_event.system_id || input_event.system.try(&.id)

if return_available && sys_id.nil?
raise Error::ModelValidation.new([{field: nil.as(String?), reason: "Missing system_id"}], "error validating event data")
end

if return_available && include_clash_time
raise AC::Route::Param::Error.new("include_clash_time and return_available cannot be used together")
end

# Parse system_ids if provided
sys_ids = system_ids.try(&.split(',').map(&.strip).reject(&.empty?)) || [] of String
starting = event_start.to_unix
ending = event_end.to_unix

# Query for clashing events
query = EventMetadata
.by_tenant(tenant.id)
.where("event_end > ? AND event_start < ?", starting, ending)
.where("cancelled = ? OR cancelled IS NULL", false)

# Filter by system_ids if provided
query = query.where({:system_id => sys_ids}) unless sys_ids.empty?
# Filter by system_id if provided
query = query.where({:system_id => sys_id}) if sys_id.try(&.presence)

clashing_events = query.to_a

if include_clash_time
result = [] of NamedTuple(system_id: String, event_start: Int64, event_end: Int64)
clashing_events.each do |event|
if sys_id = event.system_id
result << {system_id: sys_id, event_start: event.event_start, event_end: event.event_end}
clashing_events.each do |evt|
if clashing_sys_id = evt.system_id
result << {system_id: clashing_sys_id, event_start: evt.event_start, event_end: evt.event_end}
end
end
result
else
clashing_system_ids = clashing_events.compact_map(&.system_id).uniq
clashing_system_ids = clashing_events.compact_map(&.system_id).uniq!

if return_available
clashing_system_ids = sys_ids - clashing_system_ids
clashing_system_ids = [sys_id].compact - clashing_system_ids
end

clashing_system_ids
Expand Down
Loading