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
58 changes: 58 additions & 0 deletions spec/controllers/events_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1728,4 +1728,62 @@ describe Events, tags: ["event"] do
last["previous_event_start"].as_i64.should eq thu
end
end

# Metadata is stored per room, so an event that changes room used to start a
# fresh record and re-announce every visitor as newly invited (PPT-2375).
describe "room moves", tags: "PPT-2375" do
it "keeps the meeting's metadata and does not re-invite anyone" do
WebMock.reset
attending_bodies = [] of String
WebMock.stub(:post, "#{ENV["PLACE_URI"]}/api/engine/v2/signal?channel=staff/guest/attending")
.to_return do |request|
attending_bodies << (request.body.try(&.gets_to_end) || "")
HTTP::Client::Response.new(200, body: "")
end
changed_bodies = [] of String
WebMock.stub(:post, "#{ENV["PLACE_URI"]}/api/engine/v2/signal?channel=staff/event/changed")
.to_return do |request|
changed_bodies << (request.body.try(&.gets_to_end) || "")
HTTP::Client::Response.new(200, body: "")
end
EventsHelper.stub_event_tokens
EventsHelper.stub_update_endpoints

system_id = "sys-rJQQlR4Cn7"
EventsHelper.stub_permissions_check(system_id)
created = JSON.parse(client.post(EVENTS_BASE, headers: headers, body: EventsHelper.create_event_input).body).as_h
event_id = created["id"].to_s
EventsHelper.stub_room_event_query(event_id)

# the room the event moves to
systems = Array(JSON::Any).from_json(File.read("./spec/fixtures/placeos/systems.json")).map &.to_json
moved_system_id = "sys_id"
WebMock.stub(:get, ENV["PLACE_URI"].to_s + "/api/engine/v2/systems/#{moved_system_id}")
.to_return(body: systems[1])
EventsHelper.stub_permissions_check(moved_system_id)

before = EventMetadata.find_by(event_id: event_id)
before.system_id.should eq system_id
attending_bodies.clear
changed_bodies.clear

# the same guest list as the meeting was created with, moved to another room
body = EventsHelper.create_event_input.gsub(%("system_id": "#{system_id}"), %("system_id": "#{moved_system_id}"))
client.patch("#{EVENTS_BASE}/#{event_id}?system_id=#{system_id}", headers: headers, body: body).status_code.should eq(200)
sleep 100.milliseconds

# the same record, now against the new room, so the visitors and their
# check-in state come with it
after = EventMetadata.find!(before.id.not_nil!)
after.system_id.should eq moved_system_id
after.resource_calendar.should eq "room2@example.com"
after.attendees.to_a.size.should eq before.attendees.to_a.size

# the move is a change, not an invitation
payload = JSON.parse(changed_bodies.last)
payload["previous_system_id"].as_s.should eq system_id
payload["system_id"].as_s.should eq moved_system_id
attending_bodies.map { |signal| JSON.parse(signal)["attendee_email"].as_s }.should_not contain "jon@example.com"
end
end
end
19 changes: 19 additions & 0 deletions spec/controllers/helpers/event_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ module EventsHelper
.to_return(body: File.read("./spec/fixtures/calendars/o365/show.json"))
end

# Everything Graph needs stubbed to create an event and then PATCH it.
def stub_update_endpoints
stub_create_endpoints

WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users/room1%40example.com/calendar/events/AAMkADE3YmQxMGQ2LTRmZDgtNDljYy1hNDg1LWM0NzFmMGI0ZTQ3YgBGAAAAAADFYQb3DJ_xSJHh14kbXHWhBwB08dwEuoS_QYSBDzuv558sAAAAAAENAAB08dwEuoS_QYSBDzuv558sAACGVOwUAAA%3D")
.to_return(body: File.read("./spec/fixtures/events/o365/create.json"))
WebMock.stub(:patch, "https://graph.microsoft.com/v1.0/users/dev%40acaprojects.onmicrosoft.com/calendar/events/AAMkADE3YmQxMGQ2LTRmZDgtNDljYy1hNDg1LWM0NzFmMGI0ZTQ3YgBGAAAAAADFYQb3DJ_xSJHh14kbXHWhBwB08dwEuoS_QYSBDzuv558sAAAAAAENAAB08dwEuoS_QYSBDzuv558sAACGVOwUAAA%3D")
.to_return(body: File.read("./spec/fixtures/events/o365/update.json"))
# the host's copy of the event, looked up by ical uid
WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users/dev%40acaprojects.onmicrosoft.com/calendar/calendarView?startDateTime=2020-08-26T14%3A00%3A00-00%3A00&endDateTime=2020-08-27T13%3A59%3A59-00%3A00&%24filter=iCalUId+eq+%27040000008200E00074C5B7101A82E008000000006DE2E3761F8AD6010000000000000000100000009CCCDBB1F09DE74D8B157797D97F6A10%27&%24top=10000")
.to_return(body: File.read("./spec/fixtures/events/o365/events_query.json"))
end

# The room's copy of the event, looked up by ical uid once the id is known.
def stub_room_event_query(event_id)
WebMock.stub(:get, "https://graph.microsoft.com/v1.0/users/room1%40example.com/calendar/calendarView?startDateTime=2020-08-26T14:00:00-00:00&endDateTime=2020-08-27T13:59:59-00:00&%24filter=iCalUId+eq+%27040000008200E00074C5B7101A82E008000000006DE2E3761F8AD6010000000000000000100000009CCCDBB1F09DE74D8B157797D97F6A10%27&$top=10000")
.to_return(event_query_response(event_id))
end

def mock_event_id(id, ical = nil)
event = Office365::Event.new(**{
id: id,
Expand Down
40 changes: 14 additions & 26 deletions src/controllers/events.cr
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,14 @@ class Events < Application
if system
raise Error::BadRequest.new("system_id must be present") if system_id.nil?

meta = get_migrated_metadata(updated_event, system_id) || EventMetadata.new
# An event that moves takes its metadata with it: the attendee records,
# their check-in state and the extension data belong to the meeting, not
# to the room. Metadata is looked up per room, so a move would otherwise
# start a fresh record, orphaning all of that and making every visitor
# look newly invited (PPT-2375).
moved_meta = previous_meta_for_signal if changing_room
meta = moved_meta || get_migrated_metadata(updated_event, system_id) || EventMetadata.new

if extension_data = changes.extension_data
meta_ext_data = meta.ext_data
data = if (val = meta_ext_data) && val.as_h?
Expand Down Expand Up @@ -802,7 +809,12 @@ class Events < Application

next unless attend.visit_expected

if !previously_visiting || changing_room
# Only a visitor who wasn't already attending is being invited.
# Moving the event to another room used to re-announce everyone,
# which reads downstream as a fresh invitation for each of them --
# the room change is reported by staff/event/changed instead
# (PPT-2375).
if !previously_visiting
spawn do
sys = system
raise Error::BadUpstreamResponse.new("event_start must be present on updated event #{updated_event.id}") unless updated_event_start = updated_event.event_start
Expand All @@ -824,30 +836,6 @@ class Events < Application
end
end
end
elsif changing_room
existing.each do |attend|
next unless attend.visit_expected
spawn do
sys = system
raise Error::NotFound.new("guest not found for attendee #{attend.id}") unless guest = attend.guest
raise Error::BadUpstreamResponse.new("event_start must be present on updated event #{updated_event.id}") unless updated_event_start = updated_event.event_start

placeos_client.root.signal("staff/guest/attending", {
action: :meeting_update,
system_id: sys.id,
event_id: event_id,
event_ical_uid: updated_event.ical_uid,
host: host,
resource: sys.email,
event_title: updated_event.title,
event_summary: updated_event.title,
event_starting: updated_event_start.to_unix,
attendee_name: guest.name,
attendee_email: guest.email,
zones: sys.zones,
})
end
end
end
end

Expand Down
Loading