From 85f803c4a2ea1b1e2e9585213e29d6a9d423685e Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 13 Aug 2024 14:24:23 +0930 Subject: [PATCH 01/10] test(bookings): visitor-kiosk visitor checkin flow --- spec/controllers/bookings_spec.cr | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 321e473..7ebd6aa 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -2234,4 +2234,44 @@ describe Bookings do booking.deleted.should be_true booking.children.not_nil!.all? { |b| b.deleted == true }.should be_true end + + context "[visitor-kiosk]", tags: ["visitor-kiosk"] do + it "checks in a visitor" do + tenant = get_tenant + + starting = Random.new.rand(5..19).minutes.from_now.to_unix + ending = Random.new.rand(25..39).minutes.from_now.to_unix + + visitor_email = Faker::Internet.email + + # Create booking with attendee + create_booking_response = client.post(BOOKINGS_BASE, headers: headers, + body: %({"asset_id":"room_one","booking_start":#{starting},"booking_end":#{ending},"booking_type":"room","attendees": [ + { + "name": "#{Faker::Name.first_name}", + "email": "#{visitor_email}", + "checked_in": false, + "visit_expected": true + }]}) + ) + create_booking_response.status_code.should eq(201) + booking = Booking.from_json(create_booking_response.body) + + # Find guest by email + guest_response = client.get("#{GUESTS_BASE}/#{visitor_email}", headers: headers) + guest_response.status_code.should eq(200) + guest_id = JSON.parse(guest_response.body)["id"] + + # update induction state on booking + update_state_response = client.post("#{BOOKINGS_BASE}/#{booking.id}/update_state?state=inducted", headers: headers) + update_state_response.status_code.should eq(200) + booking = Booking.from_json(update_state_response.body) + booking.induction.should be_true + + # change booking guests to attendees + booking.attendees = booking.guests + booking.guests = nil + update_response = client.patch("#{BOOKINGS_BASE}/#{booking.id}", headers: headers, body: booking.to_json) + end + end end From 300dbf09a96ab900eca08c246137ab111f12e6ef Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 13 Aug 2024 15:13:25 +0930 Subject: [PATCH 02/10] test(bookings): match observed flow --- spec/controllers/bookings_spec.cr | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 7ebd6aa..e3029f9 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -2271,6 +2271,7 @@ describe Bookings do # change booking guests to attendees booking.attendees = booking.guests booking.guests = nil + booking.induction = true update_response = client.patch("#{BOOKINGS_BASE}/#{booking.id}", headers: headers, body: booking.to_json) end end From 712f70252fa29a16ba93692072ba8dac07b175e8 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Mon, 19 Aug 2024 14:35:56 +0930 Subject: [PATCH 03/10] chore(shards): update shards --- shard.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shard.lock b/shard.lock index 0f3f499..c19cd61 100644 --- a/shard.lock +++ b/shard.lock @@ -31,7 +31,7 @@ shards: connect-proxy: git: https://github.com/spider-gazelle/connect-proxy.git - version: 2.0.1 + version: 2.0.2 cron_parser: git: https://github.com/kostya/cron_parser.git @@ -167,7 +167,7 @@ shards: placeos-models: git: https://github.com/placeos/models.git - version: 9.56.4 + version: 9.57.3 pool: git: https://github.com/ysbaddaden/pool.git From 7e79cea651df23300fad5f13fd27a4f4090e5dc2 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Mon, 19 Aug 2024 14:36:35 +0930 Subject: [PATCH 04/10] test(induction): test update_induction endpoint --- spec/controllers/bookings_spec.cr | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index e3029f9..8fa501b 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -2263,16 +2263,10 @@ describe Bookings do guest_id = JSON.parse(guest_response.body)["id"] # update induction state on booking - update_state_response = client.post("#{BOOKINGS_BASE}/#{booking.id}/update_state?state=inducted", headers: headers) - update_state_response.status_code.should eq(200) - booking = Booking.from_json(update_state_response.body) - booking.induction.should be_true - - # change booking guests to attendees - booking.attendees = booking.guests - booking.guests = nil - booking.induction = true - update_response = client.patch("#{BOOKINGS_BASE}/#{booking.id}", headers: headers, body: booking.to_json) + update_induction_response = client.post("#{BOOKINGS_BASE}/#{booking.id}/update_induction?induction=ACCEPTED", headers: headers) + update_induction_response.status_code.should eq(200) + booking = Booking.from_json(update_induction_response.body) + booking.induction.should eq(PlaceOS::Model::Induction::ACCEPTED) end end end From f635fd1718da85a30bb6b338a108cd03a1ae3cb9 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Mon, 19 Aug 2024 14:37:06 +0930 Subject: [PATCH 05/10] feat(bookings): add update_induction endpoint --- src/controllers/bookings.cr | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 40d15b3..511edcb 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -56,7 +56,7 @@ class Bookings < Application .limit(1).to_a.first { raise Error::NotFound.new("could not find booking with id: #{id}") } end - @[AC::Route::Filter(:before_action, only: [:update, :update_alt, :destroy, :update_state])] + @[AC::Route::Filter(:before_action, only: [:update, :update_alt, :destroy, :update_state, :update_induction])] private def confirm_access return if is_support? if user = current_user @@ -515,7 +515,7 @@ class Bookings < Application original_assets = existing_booking.asset_ids existing_booking.instance = instance - {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :title, :description, :images] %} + {% for key in [:asset_id, :asset_ids, :zones, :booking_start, :booking_end, :title, :description, :images, :induction] %} begin existing_booking.{{key.id}} = changes.{{key.id}} if changes.{{key.id}}_present? rescue NilAssertionError @@ -807,6 +807,19 @@ class Bookings < Application update_booking(booking, "process_state") end + # update the induction status + @[AC::Route::POST("/:id/update_induction")] + def update_induction( + @[AC::Param::Info(description: "the induction status of the booking", example: "TENTATIVE")] + induction : PlaceOS::Model::Induction, + @[AC::Param::Info(description: "provided for use with analytics", example: "mobile")] + utm_source : String? = nil + ) : Booking + booking.induction = induction + booking.utm_source = utm_source + update_booking(booking, "induction") + end + # returns a list of guests associated with a booking @[AC::Route::GET("/:id/guests")] def guest_list : Array(Guest) From 1a8767e764f178cc4bbcfa362b31e64f08226299 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Mon, 19 Aug 2024 14:40:33 +0930 Subject: [PATCH 06/10] fix(bookings): enum name --- spec/controllers/bookings_spec.cr | 2 +- src/controllers/bookings.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 8fa501b..36b52be 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -2266,7 +2266,7 @@ describe Bookings do update_induction_response = client.post("#{BOOKINGS_BASE}/#{booking.id}/update_induction?induction=ACCEPTED", headers: headers) update_induction_response.status_code.should eq(200) booking = Booking.from_json(update_induction_response.body) - booking.induction.should eq(PlaceOS::Model::Induction::ACCEPTED) + booking.induction.should eq(PlaceOS::Model::Booking::Induction::ACCEPTED) end end end diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 511edcb..7abc0d6 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -811,7 +811,7 @@ class Bookings < Application @[AC::Route::POST("/:id/update_induction")] def update_induction( @[AC::Param::Info(description: "the induction status of the booking", example: "TENTATIVE")] - induction : PlaceOS::Model::Induction, + induction : PlaceOS::Model::Booking::Induction, @[AC::Param::Info(description: "provided for use with analytics", example: "mobile")] utm_source : String? = nil ) : Booking From 5a78af9aa2f8205a81db1cd43f1fbf41510169d0 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Mon, 19 Aug 2024 14:42:34 +0930 Subject: [PATCH 07/10] doc(openapi): doc gen --- OPENAPI_DOC.yml | 127 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/OPENAPI_DOC.yml b/OPENAPI_DOC.yml index 1022fa5..10d0f81 100644 --- a/OPENAPI_DOC.yml +++ b/OPENAPI_DOC.yml @@ -2375,6 +2375,119 @@ paths: application/json: schema: $ref: '#/components/schemas/Bookings__BookingError' + /api/staff/v1/bookings/{id}/update_induction: + post: + summary: update the induction status + tags: + - Bookings + operationId: Bookings_update_induction + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: Int64 + - name: induction + in: query + description: the induction status of the booking + example: TENTATIVE + required: true + schema: + type: string + enum: + - tentative + - accepted + - declined + - name: utm_source + in: query + description: provided for use with analytics + example: mobile + required: false + schema: + type: string + nullable: true + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PlaceOS__Model__Booking' + 429: + description: Too Many Requests + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 400: + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 401: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 403: + description: Forbidden + 404: + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 511: + description: Network Authentication Required + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 406: + description: Not Acceptable + content: + application/json: + schema: + $ref: '#/components/schemas/Application__ContentError' + 415: + description: Unsupported Media Type + content: + application/json: + schema: + $ref: '#/components/schemas/Application__ContentError' + 422: + description: Unprocessable Entity + content: + application/json: + schema: + $ref: '#/components/schemas/Application__ValidationError' + 500: + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 405: + description: Method Not Allowed + content: + application/json: + schema: + $ref: '#/components/schemas/Application__CommonError' + 409: + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/Bookings__BookingError' + 410: + description: Gone + content: + application/json: + schema: + $ref: '#/components/schemas/Bookings__BookingError' /api/staff/v1/bookings/{id}/guests: get: summary: returns a list of guests associated with a booking @@ -9651,7 +9764,12 @@ components: type: string nullable: true induction: - type: boolean + type: string + enum: + - tentative + - accepted + - declined + description: The induction status of the booking. Defaults to TENTATIVE. nullable: true permission: type: string @@ -12073,7 +12191,12 @@ components: type: string nullable: true induction: - type: boolean + type: string + enum: + - tentative + - accepted + - declined + description: The induction status of the booking. Defaults to TENTATIVE. nullable: true permission: type: string From 2dc4522b714d21a4d8efcbb74ef6a156a22c84e1 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 20 Aug 2024 10:01:13 +0930 Subject: [PATCH 08/10] test(bookings): test visitor checking flow --- spec/controllers/bookings_spec.cr | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 36b52be..20b55ad 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -2237,6 +2237,13 @@ describe Bookings do context "[visitor-kiosk]", tags: ["visitor-kiosk"] do it "checks in a visitor" do + WebMock.stub(:post, "#{ENV["PLACE_URI"]}/auth/oauth/token") + .to_return(body: File.read("./spec/fixtures/tokens/placeos_token.json")) + WebMock.stub(:post, "#{ENV["PLACE_URI"]}/api/engine/v2/signal?channel=staff/booking/changed") + .to_return(body: "") + WebMock.stub(:post, "#{ENV["PLACE_URI"]}/api/engine/v2/signal?channel=staff/guest/attending") + .to_return(body: "") + tenant = get_tenant starting = Random.new.rand(5..19).minutes.from_now.to_unix @@ -2255,7 +2262,7 @@ describe Bookings do }]}) ) create_booking_response.status_code.should eq(201) - booking = Booking.from_json(create_booking_response.body) + booking_id = JSON.parse(create_booking_response.body)["id"] # Find guest by email guest_response = client.get("#{GUESTS_BASE}/#{visitor_email}", headers: headers) @@ -2263,7 +2270,7 @@ describe Bookings do guest_id = JSON.parse(guest_response.body)["id"] # update induction state on booking - update_induction_response = client.post("#{BOOKINGS_BASE}/#{booking.id}/update_induction?induction=ACCEPTED", headers: headers) + update_induction_response = client.post("#{BOOKINGS_BASE}/#{booking_id}/update_induction?induction=accepted", headers: headers) update_induction_response.status_code.should eq(200) booking = Booking.from_json(update_induction_response.body) booking.induction.should eq(PlaceOS::Model::Booking::Induction::ACCEPTED) From e2134f20619f93ff6ee8b35889ae897ae04bf83c Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 20 Aug 2024 10:13:13 +0930 Subject: [PATCH 09/10] chore(ameba): update ameba config --- .ameba.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.ameba.yml b/.ameba.yml index 1a6e988..d41f668 100644 --- a/.ameba.yml +++ b/.ameba.yml @@ -36,4 +36,25 @@ Style/PredicateName: Enabled: false Lint/LiteralsComparison: - Enabled: false \ No newline at end of file + Enabled: false + +Naming/BlockParameterName: + Enabled: false + +Naming/AccessorMethodName: + Enabled: false + +Naming/PredicateName: + Enabled: false + +Documentation/DocumentationAdmonition: + Enabled: false + +Lint/SpecFilename: + Excluded: + - spec/controllers/helpers/* + - spec/migration/**/* + +Lint/UselessAssign: + Excluded: + - spec/**/* From 8595425c0f62dfffc56faa276246386588233f2d Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Tue, 20 Aug 2024 11:34:26 +0930 Subject: [PATCH 10/10] doc(bookings): lowercase example --- OPENAPI_DOC.yml | 2 +- src/controllers/bookings.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OPENAPI_DOC.yml b/OPENAPI_DOC.yml index 10d0f81..3894141 100644 --- a/OPENAPI_DOC.yml +++ b/OPENAPI_DOC.yml @@ -2391,7 +2391,7 @@ paths: - name: induction in: query description: the induction status of the booking - example: TENTATIVE + example: accepted required: true schema: type: string diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index 7abc0d6..8c96025 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -810,7 +810,7 @@ class Bookings < Application # update the induction status @[AC::Route::POST("/:id/update_induction")] def update_induction( - @[AC::Param::Info(description: "the induction status of the booking", example: "TENTATIVE")] + @[AC::Param::Info(description: "the induction status of the booking", example: "accepted")] induction : PlaceOS::Model::Booking::Induction, @[AC::Param::Info(description: "provided for use with analytics", example: "mobile")] utm_source : String? = nil