diff --git a/shard.lock b/shard.lock index 4b93e0c..25f3d65 100644 --- a/shard.lock +++ b/shard.lock @@ -175,7 +175,7 @@ shards: placeos-models: git: https://github.com/placeos/models.git - version: 9.51.1 + version: 9.52.1 pool: git: https://github.com/ysbaddaden/pool.git diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 56b8d75..c25f2cc 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -43,6 +43,7 @@ describe Bookings do tenant = get_tenant booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + sleep 1 booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) starting = 5.minutes.from_now.to_unix @@ -58,7 +59,7 @@ describe Bookings do route = "#{BOOKINGS_BASE}/booked?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}" body = JSON.parse(client.get(route, headers: headers).body).as_a - body.map(&.as_s).sort!.should eq booking1.asset_ids.concat(booking2.asset_ids).uniq! + body.map(&.as_s).should eq booking1.asset_ids.concat(booking2.asset_ids).uniq! # More filters by zones route = "#{BOOKINGS_BASE}/booked?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones1.first}" @@ -83,20 +84,20 @@ describe Bookings do result.success?.should be_true result.headers["X-Total-Count"].should eq "3" - result.headers["Content-Range"].should eq "bookings 0-2/3" + result.headers["Content-Range"].should eq "bookings 0-1/3" body = JSON.parse(result.body).as_a body.size.should eq(2) link = URI.decode(result.headers["Link"]) - link.should eq(%(<#{route}&offset=3>; rel="next")) + link.should eq(%(<#{route}&offset=2>; rel="next")) next_link = link.split(">;")[0][1..] result = client.get(next_link, headers: headers) result.success?.should be_true result.headers["X-Total-Count"].should eq "3" - result.headers["Content-Range"].should eq "bookings 3-3/3" + result.headers["Content-Range"].should eq "bookings 2-2/3" result.headers["Link"]?.should be_nil body = JSON.parse(result.body).as_a diff --git a/spec/controllers/recurring_bookings_spec.cr b/spec/controllers/recurring_bookings_spec.cr new file mode 100644 index 0000000..b2b8dfa --- /dev/null +++ b/spec/controllers/recurring_bookings_spec.cr @@ -0,0 +1,133 @@ +require "../spec_helper" +require "./helpers/booking_helper" +require "./helpers/guest_helper" + +describe Bookings do + Spec.before_each { + Booking.clear + Attendee.truncate + Guest.truncate + } + + client = AC::SpecHelper.client + headers = Mock::Headers.office365_guest + + describe "recurring bookings" do + it "should support pagination" do + tenant = get_tenant + + booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + sleep 1 + booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) + sleep 1 + booking3 = BookingsHelper.create_booking(tenant.id.not_nil!) + + booking1.recurrence_type = :daily + booking1.recurrence_days = 0b1111111 + booking1.timezone = "Europe/Berlin" + booking1.save! + + starting = 5.minutes.from_now.to_unix + ending = 4.days.from_now.to_unix + + # make initial request + zones1 = booking1.zones.not_nil! + zones_string = "#{zones1.first},#{booking2.zones.not_nil!.last},,#{booking3.zones.not_nil!.last}" + route = "#{BOOKINGS_BASE}?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}&limit=2" + result = client.get(route, headers: headers) + + result.success?.should be_true + result.headers["X-Total-Count"].should eq "3" + result.headers["Content-Range"].should eq "bookings 0-1/3" + + body = JSON.parse(result.body).as_a + body.size.should eq(2) + + # make second request + link = URI.decode(result.headers["Link"]) + link.should eq(%(<#{route}&offset=2>; rel="next")) + next_link = link.split(">;")[0][1..] + + result = client.get(next_link, headers: headers) + result.success?.should be_true + + body = JSON.parse(result.body).as_a + body.size.should eq(2) + result.headers["X-Total-Count"]?.should be_nil + result.headers["Content-Range"]?.should be_nil + + # make final request + link = URI.decode(result.headers["Link"]) + link.should eq(%(<#{route}&offset=2&recurrence=2>; rel="next")) + next_link = link.split(">;")[0][1..] + + result = client.get(next_link, headers: headers) + + result.success?.should be_true + body = JSON.parse(result.body).as_a + body.size.should eq(2) + + result.headers["Link"]?.should be_nil + end + + it "booking deleted before booking_start" do + tenant = get_tenant + + booking = BookingsHelper.create_booking(tenant.id.not_nil!, + booking_start: 1.minutes.from_now.to_unix, + booking_end: 9.minutes.from_now.to_unix) + + booking.recurrence_type = :daily + booking.recurrence_days = 0b1111111 + booking.timezone = "Europe/Berlin" + booking.save! + + booking.deleted.should be_false + + instances = booking.calculate_daily(2.days.from_now, 5.days.from_now).instances + instance = instances.first.to_unix + + client.delete("#{BOOKINGS_BASE}/#{booking.id}/instance/#{instance}", headers: headers) + body = JSON.parse(client.get("#{BOOKINGS_BASE}/#{booking.id}/instance/#{instance}", headers: headers).body).as_h + body["current_state"].should eq("cancelled") + + booking.reload! + booking.deleted.should be_false + + other = instances.last.to_unix + other.should_not eq instance + body = JSON.parse(client.get("#{BOOKINGS_BASE}/#{booking.id}/instance/#{other}", headers: headers).body).as_h + body["current_state"].should_not eq("cancelled") + end + + it "check-in recurrence" do + tenant = get_tenant + + booking = BookingsHelper.create_booking(tenant.id.not_nil!, + booking_start: 1.minutes.from_now.to_unix, + booking_end: 9.minutes.from_now.to_unix) + + booking.recurrence_type = :daily + booking.recurrence_days = 0b1111111 + booking.timezone = "Europe/Berlin" + booking.save! + + booking.checked_in.should be_false + + instances = booking.calculate_daily(2.days.from_now, 5.days.from_now).instances + instance = instances.first.to_unix + + client.post("#{BOOKINGS_BASE}/#{booking.id}/check_in/#{instance}", headers: headers) + body = JSON.parse(client.get("#{BOOKINGS_BASE}/#{booking.id}/instance/#{instance}", headers: headers).body).as_h + body["checked_in"].should be_true + + booking.reload! + booking.checked_in.should be_false + + other = instances.last.to_unix + other.should_not eq instance + body = JSON.parse(client.get("#{BOOKINGS_BASE}/#{booking.id}/instance/#{other}", headers: headers).body).as_h + body["checked_in"].should be_false + end + end +end diff --git a/spec/controllers/staff_spec.cr b/spec/controllers/staff_spec.cr index aef665e..9c0f369 100644 --- a/spec/controllers/staff_spec.cr +++ b/spec/controllers/staff_spec.cr @@ -8,7 +8,7 @@ describe Staff do it "should return a list of users" do WebMock.stub(:post, "https://login.microsoftonline.com/bb89674a-238b-4b7d-91ec-6bebad83553a/oauth2/v2.0/token") .to_return(body: File.read("./spec/fixtures/tokens/o365_token.json")) - WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users?%24filter=accountEnabled+eq+true") + WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users?%24select=id%2CuserPrincipalName%2Csurname%2CpreferredLanguage%2CofficeLocation%2CmobilePhone%2Cmail%2CjobTitle%2CgivenName%2CdisplayName%2CbusinessPhones%2CaccountEnabled%2CmailNickname&%24filter=accountEnabled+eq+true") .to_return(body: File.read("./spec/fixtures/staff/index.json")) body = JSON.parse(client.get(STAFF_BASE, headers: headers).body).as_a @@ -18,7 +18,7 @@ describe Staff do it "should return a queryable list of users" do WebMock.stub(:post, "https://login.microsoftonline.com/bb89674a-238b-4b7d-91ec-6bebad83553a/oauth2/v2.0/token") .to_return(body: File.read("./spec/fixtures/tokens/o365_token.json")) - WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users?%24filter=%28accountEnabled+eq+true%29+and+%28startswith%28displayName%2C%27john%27%29+or+startswith%28givenName%2C%27john%27%29+or+startswith%28surname%2C%27john%27%29+or+startswith%28mail%2C%27john%27%29%29") + WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users?%24select=id%2CuserPrincipalName%2Csurname%2CpreferredLanguage%2CofficeLocation%2CmobilePhone%2Cmail%2CjobTitle%2CgivenName%2CdisplayName%2CbusinessPhones%2CaccountEnabled%2CmailNickname&%24filter=%28accountEnabled+eq+true%29+and+%28startswith%28displayName%2C%27john%27%29+or+startswith%28givenName%2C%27john%27%29+or+startswith%28surname%2C%27john%27%29+or+startswith%28mail%2C%27john%27%29%29") .to_return(body: File.read("./spec/fixtures/staff/index_filtered.json")) body = JSON.parse(client.get("#{STAFF_BASE}?q=john", headers: headers).body).as_a diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 07f02ec..40af7ed 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -260,7 +260,7 @@ class Bookings < Application else range_end = result.size + offset response.headers["X-Total-Count"] = total.to_s - response.headers["Content-Range"] = "bookings #{offset}-#{range_end}/#{total}" + response.headers["Content-Range"] = "bookings #{offset}-#{range_end - 1}/#{total}" # Set link if range_end < total @@ -513,7 +513,7 @@ class Bookings < Application original_start = existing_booking.booking_start original_end = existing_booking.booking_end original_assets = existing_booking.asset_ids - existing_booking.instance = instance if instance + existing_booking.instance = instance {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :title, :description, :images] %} begin @@ -681,7 +681,7 @@ class Bookings < Application @[AC::Param::Info(description: "a recurring instance id", example: "1234567")] instance : Int64? = nil ) : Nil - booking.instance = instance if instance + booking.instance = instance booking.update!( deleted: true, deleted_at: Time.local.to_unix, @@ -760,7 +760,7 @@ class Bookings < Application @[AC::Param::Info(description: "a recurring instance id", example: "1234567")] instance : Int64? = nil ) : Booking - booking.instance = instance if instance + booking.instance = instance booking.checked_in = state if booking.checked_in