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
13 changes: 12 additions & 1 deletion vc_zoom/indico_vc_zoom/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from flask_pluginengine import current_plugin
from marshmallow import EXCLUDE
from sqlalchemy.orm.attributes import flag_modified
from sqlalchemy.orm.exc import StaleDataError
from webargs import fields
from webargs.flaskparser import use_kwargs
from werkzeug.exceptions import Forbidden, ServiceUnavailable
Expand Down Expand Up @@ -85,6 +86,16 @@ def _handle_validation(self, payload):
'encryptedToken': signed_token
})

def _mark_room_deleted(self, vc_room):
vc_room.status = VCRoomStatus.deleted
try:
db.session.flush()
except StaleDataError:
# The VC room was already removed in Indico (the deletion that triggered this
# webhook), so the row is gone and there is nothing left to update.
db.session.rollback()
current_plugin.logger.info('VC room for the deleted Zoom meeting was already removed in Indico')

def _handle_zoom_event(self, event, payload):
# XXX Some Zoom events receive the ID as a string, others as a number
meeting_id = int(payload['object']['id'])
Expand All @@ -99,7 +110,7 @@ def _handle_zoom_event(self, event, payload):
current_plugin.refresh_room(vc_room, None)
elif event in ('meeting.deleted', 'webinar.deleted'):
current_plugin.logger.info('Zoom meeting deleted: %s', meeting_id)
vc_room.status = VCRoomStatus.deleted
self._mark_room_deleted(vc_room)
elif event in ('meeting.participant_joined', 'webinar.participant_joined'):
if not vc_room.data.get('auto_register') or not vc_room.data.get('auto_checkin'):
return
Expand Down
29 changes: 29 additions & 0 deletions vc_zoom/tests/webhook_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,32 @@ def test_webinar_participant_joined_checks_in_registration(db, zoom_plugin, reg_
assert resp.status_code == 200
db.session.refresh(reg)
assert reg.checked_in


# ── meeting.deleted tests ─────────────────────────────────────────────────────

@pytest.mark.usefixtures('request_context')
def test_meeting_deleted_marks_room_deleted(db, zoom_user, reg_form, webhook_client, create_vc_room_with_assoc):
vc_room, _assoc = create_vc_room_with_assoc(reg_form.event, zoom_user)
payload = {'event': 'meeting.deleted', 'payload': {'object': {'id': str(vc_room.data['zoom_id'])}}}

resp = webhook_client(payload)

assert resp.status_code == 200
db.session.refresh(vc_room)
assert vc_room.status == VCRoomStatus.deleted


def test_meeting_deleted_tolerates_already_removed_room(db, zoom_plugin, zoom_user):
from indico_vc_zoom.controllers import RHWebhook

vc_room = VCRoom(name='Gone', type='zoom', status=VCRoomStatus.created, created_by_user=zoom_user)
vc_room.data = {'zoom_id': 99999}
db.session.add(vc_room)
db.session.flush()
# Simulate Indico having hard-deleted the row in the transaction that triggered this webhook.
db.session.execute(VCRoom.__table__.delete().where(VCRoom.__table__.c.id == vc_room.id))

with zoom_plugin.plugin_context():
# Must not raise StaleDataError even though the row is gone.
RHWebhook()._mark_room_deleted(vc_room)