Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(survey): triggers #249

Merged
merged 9 commits into from
Jan 19, 2023
23 changes: 22 additions & 1 deletion OPENAPI_DOC.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4641,7 +4641,23 @@ paths:
tags:
- Surveys
operationId: Surveys#index
parameters: []
parameters:
- name: zone_id
in: query
description: filters surveys by zone_id
example: zone1234
required: false
schema:
type: string
nullable: true
- name: building_id
in: query
description: filters surveys by building_id
example: building1234
required: false
schema:
type: string
nullable: true
responses:
200:
description: OK
Expand Down Expand Up @@ -9736,10 +9752,15 @@ components:
nullable: true
trigger:
type: object
description: 'Triggers on booking states: RESERVED, CHECKEDIN, CHECKEDOUT,
REJECTED, CANCELLED'
nullable: true
zone_id:
type: string
nullable: true
building_id:
type: string
nullable: true
pages:
type: array
items:
Expand Down
99 changes: 1 addition & 98 deletions spec/controllers/bookings_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "../spec_helper"
require "./helpers/spec_clean_up"
require "./helpers/booking_helper"

describe Bookings do
Spec.before_each { Booking.query.each(&.delete) }
Expand Down Expand Up @@ -1139,101 +1140,3 @@ describe Bookings do
end

BOOKINGS_BASE = Bookings.base_route

module BookingsHelper
extend self

def create_booking(tenant_id, user_email)
user_name = Faker::Internet.user_name
zones = ["zone-#{Random.new.rand(500)}", "zone-#{Random.new.rand(500)}", "zone-#{Random.new.rand(500)}"]
Booking.create!(
tenant_id: tenant_id,
user_id: user_email,
user_email: PlaceOS::Model::Email.new(user_email),
user_name: user_name,
asset_id: "asset-#{Random.new.rand(500)}",
zones: zones,
booking_type: "desk",
booking_start: Random.new.rand(5..19).minutes.from_now.to_unix,
booking_end: Random.new.rand(25..79).minutes.from_now.to_unix,
checked_in: false,
approved: false,
rejected: false,
booked_by_email: PlaceOS::Model::Email.new(user_email),
booked_by_id: user_email,
booked_by_name: user_name,
utm_source: "desktop",
history: [] of Booking::History,
)
end

def create_booking(tenant_id, booking_start, booking_end)
booking = create_booking(tenant_id)
booking.booking_start = booking_start
booking.booking_end = booking_end
booking.save!
end

def create_booking(tenant_id, booking_start, booking_end, asset_id)
booking = create_booking(tenant_id)
booking.booking_start = booking_start
booking.booking_end = booking_end
booking.asset_id = asset_id
booking.save!
end

def create_booking(tenant_id)
user_email = Faker::Internet.email
create_booking(tenant_id: tenant_id, user_email: user_email)
end

def http_create_booking(
user_id = "jon@example.com",
user_email = "jon@example.com",
user_name = "Jon Smith",
asset_id = "asset-1",
zones = ["zone-1234", "zone-4567", "zone-890"],
booking_type = "desk",
booking_start = 5.minutes.from_now.to_unix,
booking_end = 1.hour.from_now.to_unix,
booked_by_email = "jon@example.com",
booked_by_id = "jon@example.com",
booked_by_name = "Jon Smith",
history = nil,
utm_source = nil,
department = nil,
limit_override = nil
)
body = {
user_id: user_id,
user_email: user_email ? PlaceOS::Model::Email.new(user_email) : nil,
user_name: user_name,
asset_id: asset_id,
zones: zones,
booking_type: booking_type,
booking_start: booking_start,
booking_end: booking_end,
booked_by_email: booked_by_email ? PlaceOS::Model::Email.new(booked_by_email) : nil,
booked_by_id: booked_by_id,
booked_by_name: booked_by_name,
history: history,
department: department,
}.to_h.compact!.to_json

client = AC::SpecHelper.client

param = URI::Params.new
param.add("utm_source", utm_source) if utm_source
param.add("limit_override", limit_override) if limit_override
uri = URI.new(path: BOOKINGS_BASE, query: param)
response = client.post(uri.to_s,
body: body,
headers: Mock::Headers.office365_guest
)
if response.success?
{response.status_code, JSON.parse(response.body).as_h}
else
{response.status_code, {} of String => JSON::Any}
end
end
end
1 change: 1 addition & 0 deletions spec/controllers/guests_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "../spec_helper"
require "./helpers/spec_clean_up"
require "./helpers/booking_helper"
require "../../src/constants"

describe Guests do
Expand Down
100 changes: 100 additions & 0 deletions spec/controllers/helpers/booking_helper.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
module BookingsHelper
extend self

def random_zones : Array(String)
["zone-#{Random.new.rand(500)}", "zone-#{Random.new.rand(500)}", "zone-#{Random.new.rand(500)}"]
end

def create_booking(tenant_id : Int64, user_email : String, zones : Array(String) = random_zones)
user_name = Faker::Internet.user_name
Booking.create!(
tenant_id: tenant_id,
user_id: user_email,
user_email: PlaceOS::Model::Email.new(user_email),
user_name: user_name,
asset_id: "asset-#{Random.new.rand(500)}",
zones: zones,
booking_type: "desk",
booking_start: Random.new.rand(5..19).minutes.from_now.to_unix,
booking_end: Random.new.rand(25..79).minutes.from_now.to_unix,
checked_in: false,
approved: false,
rejected: false,
booked_by_email: PlaceOS::Model::Email.new(user_email),
booked_by_id: user_email,
booked_by_name: user_name,
utm_source: "desktop",
history: [] of Booking::History,
)
end

def create_booking(tenant_id : Int64, booking_start : Int64, booking_end : Int64)
booking = create_booking(tenant_id)
booking.booking_start = booking_start
booking.booking_end = booking_end
booking.save!
end

def create_booking(tenant_id : Int64, booking_start : Int64, booking_end : Int64, asset_id : String)
booking = create_booking(tenant_id)
booking.booking_start = booking_start
booking.booking_end = booking_end
booking.asset_id = asset_id
booking.save!
end

def create_booking(tenant_id)
user_email = Faker::Internet.email
create_booking(tenant_id: tenant_id, user_email: user_email)
end

def http_create_booking(
user_id = "jon@example.com",
user_email = "jon@example.com",
user_name = "Jon Smith",
asset_id = "asset-1",
zones = ["zone-1234", "zone-4567", "zone-890"],
booking_type = "desk",
booking_start = 5.minutes.from_now.to_unix,
booking_end = 1.hour.from_now.to_unix,
booked_by_email = "jon@example.com",
booked_by_id = "jon@example.com",
booked_by_name = "Jon Smith",
history = nil,
utm_source = nil,
department = nil,
limit_override = nil
)
body = {
user_id: user_id,
user_email: user_email ? PlaceOS::Model::Email.new(user_email) : nil,
user_name: user_name,
asset_id: asset_id,
zones: zones,
booking_type: booking_type,
booking_start: booking_start,
booking_end: booking_end,
booked_by_email: booked_by_email ? PlaceOS::Model::Email.new(booked_by_email) : nil,
booked_by_id: booked_by_id,
booked_by_name: booked_by_name,
history: history,
department: department,
}.to_h.compact!.to_json

client = AC::SpecHelper.client

param = URI::Params.new
param.add("utm_source", utm_source) if utm_source
param.add("limit_override", limit_override) if limit_override
uri = URI.new(path: BOOKINGS_BASE, query: param)
response = client.post(uri.to_s,
body: body,
headers: Mock::Headers.office365_guest
)
if response.success?
{response.status_code, JSON.parse(response.body).as_h}
else
{response.status_code, {} of String => JSON::Any}
end
end
end
9 changes: 6 additions & 3 deletions spec/controllers/helpers/survey_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ module SurveyHelper
question_responders.map { |q| q.to_question.save! }
end

def survey_responder(question_order = [] of Int64)
def survey_responder(question_order = [] of Int64, zone_id = nil, building_id = nil, trigger = nil)
Survey::Responder.from_json({
title: "New Survey",
description: "This is a new survey",
zone_id: zone_id,
building_id: building_id,
trigger: trigger,
pages: [{
title: "Page 1",
description: "This is page 1",
Expand All @@ -50,7 +53,7 @@ module SurveyHelper
}.to_json)
end

def create_survey(question_order = [] of Int64)
survey_responder(question_order).to_survey.save!
def create_survey(question_order = [] of Int64, zone_id = nil, building_id = nil, trigger = nil)
survey_responder(question_order, zone_id, building_id, trigger).to_survey.save!
end
end
18 changes: 18 additions & 0 deletions spec/controllers/surveys_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ describe Surveys do
response.status_code.should eq(200)
response.body.should eq([survey.as_json].to_json)
end

it "should return a list of surveys filtered by zone_id" do
survey1 = SurveyHelper.create_survey(zone_id: "1")
survey2 = SurveyHelper.create_survey(zone_id: "2")

response = client.get("#{SURVEY_BASE}?zone_id=2", headers: headers)
response.status_code.should eq(200)
response.body.should eq([survey2.as_json].to_json)
end

it "should return a list of surveys filtered by building_id" do
survey1 = SurveyHelper.create_survey(building_id: "1")
survey2 = SurveyHelper.create_survey(building_id: "2")

response = client.get("#{SURVEY_BASE}?building_id=1", headers: headers)
response.status_code.should eq(200)
response.body.should eq([survey1.as_json].to_json)
end
end

describe "#create" do
Expand Down
16 changes: 13 additions & 3 deletions src/controllers/surveys.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ class Surveys < Application

# returns a list of surveys
@[AC::Route::GET("/")]
def index : Array(Survey::Responder)
Survey.query.select("id, title, description, trigger, zone_id, pages").to_a.map(&.as_json)
def index(
@[AC::Param::Info(name: "zone_id", description: "filters surveys by zone_id", example: "zone1234")]
zone_id : String? = nil,
@[AC::Param::Info(name: "building_id", description: "filters surveys by building_id", example: "building1234")]
building_id : String? = nil
) : Array(Survey::Responder)
query = Survey.query.select("id, title, description, trigger, zone_id, building_id, pages")

query = query.where(zone_id: zone_id) if zone_id
query = query.where(building_id: building_id) if building_id

query.to_a.map(&.as_json)
end

# creates a new survey
Expand All @@ -36,7 +46,7 @@ class Surveys < Application
def update(survey_body : Survey::Responder) : Survey::Responder
changes = survey_body.to_survey(update: true)

{% for key in [:title, :description, :trigger, :zone_id, :pages] %}
{% for key in [:title, :description, :trigger, :zone_id, :building_id, :pages] %}
begin
survey.{{key.id}} = changes.{{key.id}} if changes.{{key.id}}_column.defined?
rescue NilAssertionError
Expand Down
6 changes: 5 additions & 1 deletion src/migrations/0026_change_survey_tables.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ class ChangeSurveyTables
execute("ALTER TABLE questions ADD COLUMN max_rating integer")
execute("ALTER TABLE questions ADD COLUMN tags text[] DEFAULT '{}'")

create_enum(:survey_trigger_type, TriggerType)
# create_enum(:survey_trigger_type, TriggerType)
# changed to explicitly define enum values to avoid future issues
# that may arise from changing the TriggerType enum but not the database,
# if using the TriggerType enum directly then those issues would not be caught in dev/test
create_enum(:survey_trigger_type, %w(NONE RESERVED CHECKEDIN CHECKEDOUT NOSHOW REJECTED CANCELLED ENDED))
execute("ALTER TABLE surveys ADD COLUMN trigger survey_trigger_type DEFAULT 'NONE'")

execute("ALTER TABLE surveys ADD COLUMN zone_id text")
Expand Down
15 changes: 15 additions & 0 deletions src/migrations/0027_add_building_id_to_surveys.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class AddBuildingIdToSurveys
include Clear::Migration

def change(dir)
dir.up do
# Add the new columns
execute("ALTER TABLE surveys ADD COLUMN building_id text")
end

dir.down do
# remove the new columns
execute("ALTER TABLE surveys DROP COLUMN building_id")
end
end
end
19 changes: 19 additions & 0 deletions src/models/booking.cr
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,25 @@ class Booking
message: "History contains more than 3 events.",
id: booking_model.id,
} } if booking_model.history.size > 3
booking_model.survey_trigger
end

def survey_trigger
return unless history_column.changed?
state = history.last.state.to_s.upcase

query = Survey.query.select("id").where(trigger: state)
if (zone_list = zones) && !zone_list.empty?
query = query.where { var("zone_id").in?(zone_list) & var("building_id").in?(zone_list) }
end

surveys = query.to_a
surveys.each do |survey|
Survey::Invitation.create!(
survey_id: survey.id,
email: user_email.to_s,
)
end
end

def current_history : Array(History)
Expand Down
Loading