From fe9e93d9e6e2fe851e443adbc0a015fdf7478a36 Mon Sep 17 00:00:00 2001 From: pedrambiria Date: Tue, 27 Sep 2022 10:08:14 +0000 Subject: [PATCH] [FIX] google_calendar: not sending emails to existing event attendees Before this commit: syncing with google led to sending emails to attendees of existing future events on Odoo. Steps to reproduce the first issue: Install 'google_calendar' module Integrate with Google Calendar in setting Add an event to the Odoo calendar for future date Add one external attendee to the event Sync with Google Invitation emails would be sent to the attendees of the events. Solution It's possible to not send emails to the attendees in api calls. So the solution is to not send emails to the attendees for the syncing time. opw-2819046 closes odoo/odoo#102870 X-original-commit: 5a56e37a5f54662b1f3593930738e51c010abab7 Signed-off-by: Arnaud Joset Signed-off-by: Pedram Bi Ria (pebr) --- addons/calendar/models/calendar_event.py | 2 ++ addons/calendar/tests/test_calendar.py | 6 ++++ addons/google_calendar/models/google_sync.py | 1 + addons/google_calendar/models/res_users.py | 5 ++-- .../google_calendar/tests/test_sync_common.py | 21 +++++++++++-- .../tests/test_sync_odoo2google.py | 30 +++++++++++++++++++ .../google_calendar/utils/google_calendar.py | 3 +- 7 files changed, 63 insertions(+), 5 deletions(-) diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index 5fbb3d7a181..43bb858577b 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -351,6 +351,7 @@ class Meeting(models.Model): recurrence_fields = self._get_recurrent_fields() false_values = {field: False for field in recurrence_fields} # computes need to set a value defaults = self.env['calendar.recurrence'].default_get(recurrence_fields) + default_rrule_values = self.recurrence_id.default_get(recurrence_fields) for event in self: if event.recurrency: event.update(defaults) # default recurrence values are needed to correctly compute the recurrence params @@ -360,6 +361,7 @@ class Meeting(models.Model): for field in recurrence_fields if event.recurrence_id[field] } + rrule_values = rrule_values or default_rrule_values event.update({**false_values, **defaults, **event_values, **rrule_values}) else: event.update(false_values) diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py index f3d81a42306..96134db2782 100644 --- a/addons/calendar/tests/test_calendar.py +++ b/addons/calendar/tests/test_calendar.py @@ -220,6 +220,12 @@ class TestCalendar(SavepointCaseWithUserDemo): f.start = '2022-07-07 01:00:00' # This is in UTC. In NY, it corresponds to the 6th of july at 9pm. f.recurrency = True self.assertEqual(f.weekday, 'WED') + self.assertEqual(f.event_tz, 'US/Eastern', "The value should correspond to the user tz") + self.assertEqual(f.count, 1, "The default value should be displayed") + self.assertEqual(f.interval, 1, "The default value should be displayed") + self.assertEqual(f.month_by, "date", "The default value should be displayed") + self.assertEqual(f.end_type, "count", "The default value should be displayed") + self.assertEqual(f.rrule_type, "weekly", "The default value should be displayed") def test_event_activity_timezone(self): activty_type = self.env['mail.activity.type'].create({ diff --git a/addons/google_calendar/models/google_sync.py b/addons/google_calendar/models/google_sync.py index bb7c7b5bb4b..92ffb849cc9 100644 --- a/addons/google_calendar/models/google_sync.py +++ b/addons/google_calendar/models/google_sync.py @@ -247,6 +247,7 @@ class GoogleSync(models.AbstractModel): if token: try: send_updates = self._context.get('send_updates', True) + google_service.google_service = google_service.google_service.with_context(send_updates=send_updates) google_id = google_service.insert(values, token=token, timeout=timeout) # Everything went smoothly self.with_context(dont_notify=True).write({ diff --git a/addons/google_calendar/models/res_users.py b/addons/google_calendar/models/res_users.py index f2d5361ff7f..ab4cf3c4c6b 100644 --- a/addons/google_calendar/models/res_users.py +++ b/addons/google_calendar/models/res_users.py @@ -63,6 +63,7 @@ class User(models.Model): self.google_calendar_account_id.calendar_sync_token = next_sync_token # Google -> Odoo + send_updates = not full_sync events.clear_type_ambiguity(self.env) recurrences = events.filter(lambda e: e.is_recurrence()) synced_recurrences = self.env['calendar.recurrence']._sync_google2odoo(recurrences) @@ -71,11 +72,11 @@ class User(models.Model): # Odoo -> Google recurrences = self.env['calendar.recurrence']._get_records_to_sync(full_sync=full_sync) recurrences -= synced_recurrences - recurrences._sync_odoo2google(calendar_service) + recurrences.with_context(send_updates=send_updates)._sync_odoo2google(calendar_service) synced_events |= recurrences.calendar_event_ids - recurrences._get_outliers() synced_events |= synced_recurrences.calendar_event_ids - synced_recurrences._get_outliers() events = self.env['calendar.event']._get_records_to_sync(full_sync=full_sync) - (events - synced_events)._sync_odoo2google(calendar_service) + (events - synced_events).with_context(send_updates=send_updates)._sync_odoo2google(calendar_service) return bool(events | synced_events) or bool(recurrences | synced_recurrences) diff --git a/addons/google_calendar/tests/test_sync_common.py b/addons/google_calendar/tests/test_sync_common.py index 9eed4be0f02..f5f99688e72 100644 --- a/addons/google_calendar/tests/test_sync_common.py +++ b/addons/google_calendar/tests/test_sync_common.py @@ -3,10 +3,11 @@ from unittest.mock import MagicMock, patch -from odoo.tests.common import TransactionCase from odoo.addons.google_calendar.utils.google_calendar import GoogleCalendarService +from odoo.addons.google_account.models.google_service import GoogleService from odoo.addons.google_calendar.models.res_users import User from odoo.addons.google_calendar.models.google_sync import GoogleSync +from odoo.tests.common import HttpCase def patch_api(func): @patch.object(GoogleSync, '_google_insert', MagicMock(spec=GoogleSync._google_insert)) @@ -17,7 +18,7 @@ def patch_api(func): return patched @patch.object(User, '_get_google_calendar_token', lambda user: 'dummy-token') -class TestSyncGoogle(TransactionCase): +class TestSyncGoogle(HttpCase): def setUp(self): super().setUp() @@ -57,3 +58,19 @@ class TestSyncGoogle(TransactionCase): self.assertGoogleEventNotPatched() self.assertGoogleEventNotInserted() self.assertGoogleEventNotDeleted() + + def assertGoogleEventSendUpdates(self, expected_value): + GoogleService._do_request.assert_called_once() + args, _ = GoogleService._do_request.call_args + val = "?sendUpdates=%s" % expected_value + self.assertTrue(val in args[0], "The URL should contain %s" % val) + + def call_post_commit_hooks(self): + """ + manually calls postcommit hooks defined with the decorator @after_commit + """ + + funcs = self.env.cr.postcommit._funcs.copy() + while funcs: + func = funcs.popleft() + func() diff --git a/addons/google_calendar/tests/test_sync_odoo2google.py b/addons/google_calendar/tests/test_sync_odoo2google.py index df39feefaad..f14de26f1f3 100644 --- a/addons/google_calendar/tests/test_sync_odoo2google.py +++ b/addons/google_calendar/tests/test_sync_odoo2google.py @@ -6,6 +6,7 @@ from dateutil.relativedelta import relativedelta from unittest.mock import patch from odoo.addons.google_calendar.utils.google_calendar import GoogleCalendarService +from odoo.addons.google_account.models.google_service import GoogleService from odoo.addons.google_calendar.models.res_users import User from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle, patch_api from odoo.tests.common import users, warmup @@ -589,3 +590,32 @@ class TestSyncOdoo2Google(TestSyncGoogle): 'reminders': {'overrides': [], 'useDefault': False}, 'visibility': 'public', }, timeout=3) + + @patch.object(GoogleService, '_do_request') + def test_send_update_do_request(self, mock_do_request): + self.env.cr.postcommit.clear() + event = self.env['calendar.event'].create({ + 'name': "Event", + 'allday': True, + 'start': datetime(2020, 1, 15), + 'stop': datetime(2020, 1, 15), + 'need_sync': False, + }) + + event.with_context(send_updates=True)._sync_odoo2google(self.google_service) + self.call_post_commit_hooks() + self.assertGoogleEventSendUpdates('all') + + @patch.object(GoogleService, '_do_request') + def test_not_send_update_do_request(self, mock_do_request): + event = self.env['calendar.event'].create({ + 'name': "Event", + 'allday': True, + 'start': datetime(2020, 1, 15), + 'stop': datetime(2020, 1, 15), + 'need_sync': False, + }) + + event.with_context(send_updates=False)._sync_odoo2google(self.google_service) + self.call_post_commit_hooks() + self.assertGoogleEventSendUpdates('none') diff --git a/addons/google_calendar/utils/google_calendar.py b/addons/google_calendar/utils/google_calendar.py index e1ce24049b3..4112c081a0e 100644 --- a/addons/google_calendar/utils/google_calendar.py +++ b/addons/google_calendar/utils/google_calendar.py @@ -66,7 +66,8 @@ class GoogleCalendarService(): @requires_auth_token def insert(self, values, token=None, timeout=TIMEOUT): - url = "/calendar/v3/calendars/primary/events?sendUpdates=all" + send_updates = self.google_service._context.get('send_updates', True) + url = "/calendar/v3/calendars/primary/events?sendUpdates=%s" % ("all" if send_updates else "none") headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token} if not values.get('id'): values['id'] = uuid4().hex