From 90480ce2d16f49f1a6721cdd6d583dc9cfaff7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Baranx=20=28bar=29?= Date: Thu, 5 Aug 2021 13:44:05 +0000 Subject: [PATCH] [IMP] microsoft_calendar: get videocall URL from a Outlook event Basically, a Outlook event may contain a videocall URL in 2 different ways: 1) the event location may be a specific URL (such as `https://teams.microsoft.com/...`). In this case, we use it as `videocall_location` instead of classic `location`. We use a list of patterns to identify these specific URLs among classic locations. 2) the event may have an attribute `isOnlineMeeting` set to `True` and the attribute `onlineMeetingUrl` set with the URL. In this case, we use this `onlineMeetingUrl` as `videocall_location`. opw-2601669 closes odoo/odoo#74785 Signed-off-by: Arnaud Joset --- addons/microsoft_calendar/models/calendar.py | 14 +++++ .../tests/test_sync_microsoft2odoo.py | 62 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/addons/microsoft_calendar/models/calendar.py b/addons/microsoft_calendar/models/calendar.py index 29421e9dfc9..bb48a0dabce 100644 --- a/addons/microsoft_calendar/models/calendar.py +++ b/addons/microsoft_calendar/models/calendar.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import pytz +import re from dateutil.parser import parse from dateutil.relativedelta import relativedelta @@ -23,6 +24,9 @@ ATTENDEE_CONVERTER_M2O = { 'accepted': 'accepted', 'organizer': 'accepted', } +VIDEOCALL_URL_PATTERNS = ( + r'https://teams.microsoft.com', +) MAX_RECURRENT_EVENT = 720 class Meeting(models.Model): @@ -126,6 +130,16 @@ class Meeting(models.Model): # Propagate the follow_recurrence according to the google result values['follow_recurrence'] = not microsoft_event.is_recurrence_outlier() + # if a videocall URL is provided with the Outlook event, use it + if microsoft_event.isOnlineMeeting and microsoft_event.onlineMeeting.get("joinUrl"): + values['videocall_location'] = microsoft_event.onlineMeeting["joinUrl"] + else: + # if a location is a URL matching a specific pattern (i.e a URL to access to a videocall), + # copy it in the 'videocall_location' instead + if values['location'] and any(re.match(p, values['location']) for p in VIDEOCALL_URL_PATTERNS): + values['videocall_location'] = values['location'] + values['location'] = False + values['microsoft_id'] = microsoft_event.id if microsoft_event.is_recurrent(): values['microsoft_recurrence_master_id'] = microsoft_event.seriesMasterId diff --git a/addons/microsoft_calendar/tests/test_sync_microsoft2odoo.py b/addons/microsoft_calendar/tests/test_sync_microsoft2odoo.py index 72525d1e1d4..524864043c5 100644 --- a/addons/microsoft_calendar/tests/test_sync_microsoft2odoo.py +++ b/addons/microsoft_calendar/tests/test_sync_microsoft2odoo.py @@ -24,6 +24,25 @@ class TestSyncMicrosoft2Odoo(TransactionCase): {'@odata.type': '#microsoft.graph.event', '@odata.etag': 'W/"DwAAABYAAABlLa4RUBXJToExnebpwea2AAALKrjF"', 'seriesMasterId': 'AQ8PojGtrADQATM3ZmYAZS0yY2MAMC00MDg1LTAwAi0wMAoARgAAA0By7X03vaNKv1GnWYTbFYAHAGUtrhFQFclOgTGd5unB5rYAAAIBDQAAAGUtrhFQFclOgTGd5unB5rYAAAALLLTEAAAA', 'type': 'occurrence', 'id': 'AQ8PojGtrADQATM3ZmYAZS0yY2MAMC00MDg1LTAwAi0wMAoBUQAICADX774WtQAAAEYAAAJAcu19N72jSr9Rp1mE2xWABwBlLa4RUBXJToExnebpwea2AAACAQ0AAABlLa4RUBXJToExnebpwea2AAAACyy0xAAAABA=', 'start': {'dateTime': '2020-05-04T14:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2020-05-04T16:00:00.0000000', 'timeZone': 'UTC'}}, {'@odata.type': '#microsoft.graph.event', '@odata.etag': 'W/"DwAAABYAAABlLa4RUBXJToExnebpwea2AAALKrjF"', 'seriesMasterId': 'AQ8PojGtrADQATM3ZmYAZS0yY2MAMC00MDg1LTAwAi0wMAoARgAAA0By7X03vaNKv1GnWYTbFYAHAGUtrhFQFclOgTGd5unB5rYAAAIBDQAAAGUtrhFQFclOgTGd5unB5rYAAAALLLTEAAAA', 'type': 'occurrence', 'id': 'AQ8PojGtrADQATM3ZmYAZS0yY2MAMC00MDg1LTAwAi0wMAoBUQAICADX8IdBHsAARgAAAkBy7X03vaNKv1GnWYTbFYAHAGUtrhFQFclOgTGd5unB5rYAAAIBDQAAAGUtrhFQFclOgTGd5unB5rYAAAALLLTEAAAAEA==', 'start': {'dateTime': '2020-05-05T14:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2020-05-05T16:00:00.0000000', 'timeZone': 'UTC'}} ] + self.single_event = [ + { + '@odata.type': '#microsoft.graph.event', + '@odata.etag': 'W/"AAAAA"', + 'type': 'singleInstance', + 'id': "CCCCC", + 'start': { + 'dateTime': '2020-05-05T14:30:00.0000000', + 'timeZone': 'UTC' + }, + 'end': { + 'dateTime': '2020-05-05T16:00:00.0000000', + 'timeZone': 'UTC' + }, + 'location': { + 'displayName': "a meeting room at Odoo" + } + } + ] self.env['calendar.event']._sync_microsoft2odoo(MicrosoftEvent(values)) @@ -275,3 +294,46 @@ class TestSyncMicrosoft2Odoo(TransactionCase): self.assertEqual(recurrent_event.calendar_event_ids[0].stop, datetime(2021, 7, 15, 15, 30)) self.assertEqual(recurrent_event.calendar_event_ids[1].start, datetime(2021, 7, 17, 15, 00)) self.assertEqual(recurrent_event.calendar_event_ids[1].stop, datetime(2021, 7, 17, 15, 30)) + + def test_use_classic_location(self): + ms_event = self.single_event + + self.env['calendar.event']._sync_microsoft2odoo(MicrosoftEvent(ms_event)) + + event = self.env['calendar.event'].search([("microsoft_id", "=", ms_event[0]["id"])]) + self.assertEqual(event.location, ms_event[0]["location"]["displayName"]) + + def test_use_url_location(self): + ms_event = self.single_event + ms_event[0]["location"]["displayName"] = "https://mylocation.com/meeting-room" + + self.env['calendar.event']._sync_microsoft2odoo(MicrosoftEvent(ms_event)) + + event = self.env['calendar.event'].search([("microsoft_id", "=", ms_event[0]["id"])]) + self.assertEqual(event.location, ms_event[0]["location"]["displayName"]) + + def test_use_specific_virtual_location(self): + """ + If the location of the Outlook event is a specific virtual location (such as a video Teams meeting), + use it as videocall location. + """ + ms_event = self.single_event + ms_event[0]["location"]["displayName"] = "https://teams.microsoft.com/l/meeting/1234" + + self.env['calendar.event']._sync_microsoft2odoo(MicrosoftEvent(ms_event)) + + event = self.env['calendar.event'].search([("microsoft_id", "=", ms_event[0]["id"])]) + self.assertEqual(event.location, False) + self.assertEqual(event.videocall_location, ms_event[0]["location"]["displayName"]) + + def test_outlook_event_has_online_meeting_url(self): + ms_event = self.single_event + ms_event[0].update({ + 'isOnlineMeeting': True, + 'onlineMeeting': {'joinUrl': 'https://video-meeting.com/1234'} + }) + + self.env['calendar.event']._sync_microsoft2odoo(MicrosoftEvent(ms_event)) + + event = self.env['calendar.event'].search([("microsoft_id", "=", ms_event[0]["id"])]) + self.assertEqual(event.videocall_location, ms_event[0]["onlineMeeting"]["joinUrl"])