mirror of
https://github.com/bringout/oca-ocb-security.git
synced 2026-04-23 00:52:07 +02:00
19.0 vanilla
This commit is contained in:
parent
20ddc1b4a3
commit
c0efcc53f5
1162 changed files with 125577 additions and 105287 deletions
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_google_event
|
||||
from . import test_sync_common
|
||||
from . import test_sync_google2odoo
|
||||
from . import test_sync_odoo2google
|
||||
from . import test_sync_odoo2google_mail
|
||||
from . import test_token_access
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo.tests.common import BaseCase
|
||||
from odoo.addons.google_calendar.utils.google_calendar import GoogleEvent
|
||||
|
|
|
|||
|
|
@ -1,33 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime
|
||||
from freezegun import freeze_time
|
||||
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.models.google_sync import GoogleSync
|
||||
from odoo.tests.common import HttpCase, new_test_user
|
||||
from freezegun import freeze_time
|
||||
from contextlib import contextmanager
|
||||
from odoo.addons.google_calendar.models.res_users import ResUsers
|
||||
from odoo.addons.google_calendar.models.google_sync import google_calendar_token, GoogleCalendarSync
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
def patch_api(func):
|
||||
@patch.object(GoogleSync, '_google_insert', MagicMock(spec=GoogleSync._google_insert))
|
||||
@patch.object(GoogleSync, '_google_delete', MagicMock(spec=GoogleSync._google_delete))
|
||||
@patch.object(GoogleSync, '_google_patch', MagicMock(spec=GoogleSync._google_patch))
|
||||
def patched(self, *args, **kwargs):
|
||||
return func(self, *args, **kwargs)
|
||||
with self.mock_google_sync():
|
||||
return func(self, *args, **kwargs)
|
||||
return patched
|
||||
|
||||
@patch.object(User, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
class TestSyncGoogle(HttpCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.google_service = GoogleCalendarService(self.env['google.service'])
|
||||
self.organizer_user = new_test_user(self.env, login="organizer_user")
|
||||
self.attendee_user = new_test_user(self.env, login='attendee_user')
|
||||
@patch.object(ResUsers, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
class TestSyncGoogle(HttpCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.google_service = GoogleCalendarService(cls.env['google.service'])
|
||||
cls.env.user.sudo().unpause_google_synchronization()
|
||||
cls.organizer_user = mail_new_test_user(cls.env, login="organizer_user")
|
||||
cls.attendee_user = mail_new_test_user(cls.env, login='attendee_user')
|
||||
|
||||
m = mute_logger('odoo.addons.auth_signup.models.res_users')
|
||||
mute_logger.__enter__(m) # noqa: PLC2801
|
||||
cls.addClassCleanup(mute_logger.__exit__, m, None, None, None)
|
||||
|
||||
@contextmanager
|
||||
def mock_datetime_and_now(self, mock_dt):
|
||||
|
|
@ -40,36 +48,89 @@ class TestSyncGoogle(HttpCase):
|
|||
patch.object(self.env.cr, 'now', lambda: mock_dt):
|
||||
yield
|
||||
|
||||
@contextmanager
|
||||
def mock_google_sync(self, user_id=None):
|
||||
self._gsync_deleted_ids = []
|
||||
self._gsync_insert_values = []
|
||||
self._gsync_patch_values = defaultdict(list)
|
||||
|
||||
# as these are normally post-commit hooks, we don't change any state here
|
||||
def _mock_delete(model, service, google_id, **kwargs):
|
||||
with google_calendar_token(user_id or model.env.user.sudo()) as token:
|
||||
if token:
|
||||
self._gsync_deleted_ids.append(google_id)
|
||||
|
||||
def _mock_insert(model, service, values, **kwargs):
|
||||
if not values:
|
||||
return
|
||||
with google_calendar_token(user_id or model.env.user.sudo()) as token:
|
||||
if token:
|
||||
self._gsync_insert_values.append((values, kwargs))
|
||||
|
||||
def _mock_patch(model, service, google_id, values, **kwargs):
|
||||
with google_calendar_token(user_id or model.env.user.sudo()) as token:
|
||||
if token:
|
||||
self._gsync_patch_values[google_id].append((values, kwargs))
|
||||
|
||||
with self.env.cr.savepoint(), \
|
||||
patch.object(GoogleCalendarSync, '_google_insert', autospec=True, wraps=GoogleCalendarSync, side_effect=_mock_insert), \
|
||||
patch.object(GoogleCalendarSync, '_google_delete', autospec=True, wraps=GoogleCalendarSync, side_effect=_mock_delete), \
|
||||
patch.object(GoogleCalendarSync, '_google_patch', autospec=True, wraps=GoogleCalendarSync, side_effect=_mock_patch):
|
||||
yield
|
||||
|
||||
@contextmanager
|
||||
def mock_google_service(self):
|
||||
self._gservice_request_uris = []
|
||||
|
||||
def _mock_do_request(model, uri, *args, **kwargs):
|
||||
self._gservice_request_uris.append(uri)
|
||||
return (200, {}, datetime.now())
|
||||
|
||||
with patch.object(GoogleService, '_do_request', autospec=True, wraps=GoogleService, side_effect=_mock_do_request):
|
||||
yield
|
||||
|
||||
def assertGoogleEventDeleted(self, google_id):
|
||||
GoogleSync._google_delete.assert_called()
|
||||
args, dummy = GoogleSync._google_delete.call_args
|
||||
self.assertEqual(args[1], google_id, "Event should have been deleted")
|
||||
self.assertIn(google_id, self._gsync_deleted_ids, "Event should have been deleted")
|
||||
|
||||
def assertGoogleEventNotDeleted(self):
|
||||
GoogleSync._google_delete.assert_not_called()
|
||||
self.assertFalse(self._gsync_deleted_ids)
|
||||
|
||||
def assertGoogleEventInserted(self, values, timeout=None):
|
||||
expected_args = (values,)
|
||||
expected_kwargs = {'timeout': timeout} if timeout else {}
|
||||
GoogleSync._google_insert.assert_called_once()
|
||||
args, kwargs = GoogleSync._google_insert.call_args
|
||||
args[1:][0].pop('conferenceData', None)
|
||||
self.assertEqual(args[1:], expected_args) # skip Google service arg
|
||||
self.assertEqual(kwargs, expected_kwargs)
|
||||
self.assertEqual(len(self._gsync_insert_values), 1)
|
||||
matching = []
|
||||
for insert_values, insert_kwargs in self._gsync_insert_values:
|
||||
if all(insert_values.get(key, False) == value for key, value in values.items()):
|
||||
matching.append((insert_values, insert_kwargs))
|
||||
self.assertGreaterEqual(len(matching), 1, 'There must be at least 1 matching insert.')
|
||||
insert_values, insert_kwargs = matching[0]
|
||||
self.assertDictEqual(insert_kwargs, {'timeout': timeout} if timeout else {})
|
||||
|
||||
def assertGoogleEventInsertedMultiTime(self, values, timeout=None):
|
||||
self.assertGreaterEqual(len(self._gsync_insert_values), 1)
|
||||
matching = []
|
||||
for insert_values, insert_kwargs in self._gsync_insert_values:
|
||||
if all(insert_values.get(key, False) == value for key, value in values.items()):
|
||||
matching.append((insert_values, insert_kwargs))
|
||||
self.assertGreaterEqual(len(matching), 1, 'There must be at least 1 matching insert.')
|
||||
insert_values, insert_kwargs = matching[0]
|
||||
self.assertDictEqual(insert_kwargs, {'timeout': timeout} if timeout else {})
|
||||
|
||||
def assertGoogleEventNotInserted(self):
|
||||
GoogleSync._google_insert.assert_not_called()
|
||||
self.assertFalse(self._gsync_insert_values)
|
||||
|
||||
def assertGoogleEventPatched(self, google_id, values, timeout=None):
|
||||
expected_args = (google_id, values)
|
||||
expected_kwargs = {'timeout': timeout} if timeout else {}
|
||||
GoogleSync._google_patch.assert_called_once()
|
||||
args, kwargs = GoogleSync._google_patch.call_args
|
||||
self.assertEqual(args[1:], expected_args) # skip Google service arg
|
||||
self.assertEqual(kwargs, expected_kwargs)
|
||||
patch_values_all = self._gsync_patch_values.get(google_id)
|
||||
self.assertTrue(patch_values_all)
|
||||
matching = []
|
||||
for patch_values, patch_kwargs in patch_values_all:
|
||||
if all(patch_values.get(key, False) == values[key] for key in values):
|
||||
matching.append((patch_values, patch_kwargs))
|
||||
self.assertGreaterEqual(len(matching), 1, 'There must be at least 1 matching patch.')
|
||||
patch_values, patch_kwargs = matching[0]
|
||||
self.assertDictEqual(patch_kwargs, {'timeout': timeout} if timeout else {})
|
||||
|
||||
def assertGoogleEventNotPatched(self):
|
||||
GoogleSync._google_patch.assert_not_called()
|
||||
self.assertFalse(self._gsync_patch_values)
|
||||
|
||||
def assertGoogleAPINotCalled(self):
|
||||
self.assertGoogleEventNotPatched()
|
||||
|
|
@ -77,10 +138,10 @@ class TestSyncGoogle(HttpCase):
|
|||
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)
|
||||
self.assertEqual(len(self._gservice_request_uris), 1)
|
||||
uri = self._gservice_request_uris[0]
|
||||
uri_parameter = "sendUpdates=%s" % expected_value
|
||||
self.assertIn(uri_parameter, uri, "The URL should contain %s" % uri_parameter)
|
||||
|
||||
def call_post_commit_hooks(self):
|
||||
"""
|
||||
|
|
@ -91,8 +152,3 @@ class TestSyncGoogle(HttpCase):
|
|||
while funcs:
|
||||
func = funcs.popleft()
|
||||
func()
|
||||
|
||||
def assertGoogleEventHasNoConferenceData(self):
|
||||
GoogleSync._google_insert.assert_called_once()
|
||||
args, _ = GoogleSync._google_insert.call_args
|
||||
self.assertFalse(args[1].get('conferenceData', False))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import pytz
|
||||
|
|
@ -6,28 +5,33 @@ from datetime import datetime, date, timedelta
|
|||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.tests.common import new_test_user
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.google_calendar.models.res_users import ResUsers
|
||||
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle, patch_api
|
||||
from odoo.addons.google_calendar.utils.google_calendar import GoogleEvent, GoogleCalendarService
|
||||
from odoo import Command, tools
|
||||
from unittest.mock import patch
|
||||
|
||||
class TestSyncGoogle2Odoo(TestSyncGoogle):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.public_partner = self.env['res.partner'].create({
|
||||
@patch.object(ResUsers, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
class TestSyncGoogle2Odoo(TestSyncGoogle):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.other_company = cls.env['res.company'].create({'name': 'Other Company'})
|
||||
cls.public_partner = cls.env['res.partner'].create({
|
||||
'name': 'Public Contact',
|
||||
'email': 'public_email@example.com',
|
||||
'type': 'contact',
|
||||
})
|
||||
self.env.ref('base.partner_admin').write({
|
||||
cls.env.ref('base.partner_admin').write({
|
||||
'name': 'Mitchell Admin',
|
||||
'email': 'admin@yourcompany.example.com',
|
||||
})
|
||||
self.private_partner = self.env['res.partner'].create({
|
||||
cls.private_partner = cls.env['res.partner'].create({
|
||||
'name': 'Private Contact',
|
||||
'email': 'private_email@example.com',
|
||||
'type': 'private',
|
||||
'company_id': cls.other_company.id,
|
||||
})
|
||||
|
||||
def generate_recurring_event(self, mock_dt, **values):
|
||||
|
|
@ -117,7 +121,12 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
|
||||
@patch_api
|
||||
def test_new_google_event(self):
|
||||
description = '<script>alert("boom")</script><p style="white-space: pre"><h1>HELLO</h1></p><ul><li>item 1</li><li>item 2</li></ul>'
|
||||
description = (
|
||||
'<div><p style="white-space: pre"></p>'
|
||||
'<h1>HELLO</h1><ul><li>item 1</li><li>item 2</li></ul><br>'
|
||||
'<strong>Contact Details</strong><br>Public Contact<br>'
|
||||
'<a href="mailto:public_email@example.com">public_email@example.com</a></div>'
|
||||
)
|
||||
values = {
|
||||
'id': 'oj44nep1ldf8a3ll02uip0c9aa',
|
||||
'description': description,
|
||||
|
|
@ -391,12 +400,11 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"updated": self.now,
|
||||
'organizer': {'email': 'odoocalendarref@gmail.com', 'self': True},
|
||||
'summary': 'coucou',
|
||||
'visibility': 'public',
|
||||
'attendees': [], # <= attendee removed in Google
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=2;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
}])
|
||||
events = recurrence.calendar_event_ids.sorted('start')
|
||||
self.assertEqual(events.partner_ids, user.partner_id)
|
||||
|
|
@ -415,11 +423,10 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'description': 'Small mini desc',
|
||||
'organizer': {'email': 'odoocalendarref@gmail.com', 'self': True},
|
||||
'summary': 'Pricing new update',
|
||||
'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
'transparency': 'opaque',
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -450,8 +457,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00'},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00'},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00', 'date': None},
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', values.get('id'))])
|
||||
|
|
@ -476,8 +483,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'organizer': {'email': self.env.user.email, 'self': True},
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
}, { # Third event has been deleted
|
||||
'id': '%s_20200113' % recurrence_id,
|
||||
'originalStartTime': {'dateTime': '2020-01-13'},
|
||||
|
|
@ -501,9 +508,9 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"id": recurrence_id,
|
||||
"updated": "2020-01-13T16:17:03.806Z",
|
||||
"summary": "r rul",
|
||||
"start": {"date": "2020-01-6"},
|
||||
"start": {"date": "2020-01-06"},
|
||||
'organizer': {'email': self.env.user.email, 'self': True},
|
||||
"end": {"date": "2020-01-7"},
|
||||
"end": {"date": "2020-01-07"},
|
||||
'reminders': {'useDefault': True},
|
||||
"recurrence": ["RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO"],
|
||||
}, {
|
||||
|
|
@ -534,7 +541,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'status': 'confirmed',
|
||||
'summary': 'rrule',
|
||||
'reminders': {'useDefault': True},
|
||||
'updated': self.now
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
}, {
|
||||
'summary': 'edited', # Name changed
|
||||
'id': '%s_20200101' % recurrence_id,
|
||||
|
|
@ -544,6 +552,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'end': {'date': '2020-01-02'},
|
||||
'reminders': {'useDefault': True},
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
}])
|
||||
self.sync(events)
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', recurrence_id)])
|
||||
|
|
@ -597,10 +606,11 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'id': recurrence_id,
|
||||
'summary': 'Pricing new update',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
'reminders': {'useDefault': True},
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
},
|
||||
{ # Third event has been moved
|
||||
'id': '%s_20200113' % recurrence_id,
|
||||
|
|
@ -610,6 +620,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'originalStartTime': {'date': '2020-01-13'},
|
||||
'reminders': {'useDefault': True},
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
}])
|
||||
self.sync(events)
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', recurrence_id)])
|
||||
|
|
@ -648,10 +659,11 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
"attendees": [
|
||||
{
|
||||
"email": "odoobot@example.com", "state": "accepted",
|
||||
"email": "odoobot@example.com", "responseStatus": "accepted",
|
||||
},
|
||||
],
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
events = recurrence.calendar_event_ids.sorted('start')
|
||||
|
|
@ -691,7 +703,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
"attendees": [
|
||||
{
|
||||
"email": "odoobot@example.com", "state": "accepted",
|
||||
"email": "odoobot@example.com", "responseStatus": "accepted",
|
||||
},
|
||||
],
|
||||
'updated': self.now,
|
||||
|
|
@ -739,12 +751,12 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'id': google_id,
|
||||
'summary': 'coucou again',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=MO'],
|
||||
'start': {'dateTime': '2021-02-15T09:00:00+01:00'}, # 8:00 UTC
|
||||
'end': {'dateTime': '2021-02-15-T11:00:00+01:00'},
|
||||
'start': {'dateTime': '2021-02-15T09:00:00+01:00', 'date': None}, # 8:00 UTC
|
||||
'end': {'dateTime': '2021-02-15-T11:00:00+01:00', 'date': None},
|
||||
'reminders': {'useDefault': True},
|
||||
"attendees": [
|
||||
{
|
||||
"email": "odoobot@example.com", "state": "accepted",
|
||||
"email": "odoobot@example.com", "responseStatus": "accepted",
|
||||
},
|
||||
],
|
||||
'updated': self.now,
|
||||
|
|
@ -789,15 +801,16 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'id': google_id,
|
||||
'summary': "It's me again",
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=MO'],
|
||||
'start': {'dateTime': '2021-02-15T12:00:00+01:00'}, # 11:00 UTC
|
||||
'end': {'dateTime': '2021-02-15-T15:00:00+01:00'},
|
||||
'start': {'dateTime': '2021-02-15T12:00:00+01:00', 'date': None}, # 11:00 UTC
|
||||
'end': {'dateTime': '2021-02-15-T15:00:00+01:00', 'date': None},
|
||||
'reminders': {'useDefault': True},
|
||||
"attendees": [
|
||||
{
|
||||
"email": "odoobot@example.com", "state": "accepted",
|
||||
"email": "odoobot@example.com", "responseStatus": "accepted",
|
||||
},
|
||||
],
|
||||
'updated': self.now,
|
||||
'guestsCanModify': True,
|
||||
}
|
||||
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -850,8 +863,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00', 'timeZone': 'Pacific/Auckland'},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00', 'timeZone': 'Pacific/Auckland'},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00', 'timeZone': 'Pacific/Auckland', 'date': None},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00', 'timeZone': 'Pacific/Auckland', 'date': None},
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', values.get('id'))])
|
||||
|
|
@ -891,6 +904,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"status": "confirmed",
|
||||
"summary": "Weekly test",
|
||||
"updated": "2023-02-20T11:45:08.547Z",
|
||||
'guestsCanModify': True,
|
||||
},
|
||||
{
|
||||
"attendees": [
|
||||
|
|
@ -922,6 +936,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"status": "confirmed",
|
||||
"summary": "Weekly test 2",
|
||||
"updated": "2023-02-20T11:48:00.634Z",
|
||||
'guestsCanModify': True,
|
||||
},
|
||||
]
|
||||
google_events = GoogleEvent(values)
|
||||
|
|
@ -950,8 +965,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'recurrence': ['EXDATE;TZID=Europe/Rome:20200113',
|
||||
'RRULE;X-EVOLUTION-ENDDATE=20200120:FREQ=WEEKLY;COUNT=3;BYDAY=MO;X-RELATIVE=1'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', values.get('id'))])
|
||||
|
|
@ -988,11 +1003,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-06T18:00:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -1005,8 +1022,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2020-01-06T18:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2020-01-06T19:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
}
|
||||
recurrence = self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
events = recurrence.calendar_event_ids.sorted('start')
|
||||
|
|
@ -1232,11 +1249,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'overrides': [{"method": "email", "minutes": 10}], 'useDefault': False},
|
||||
'start': {
|
||||
'dateTime': pytz.utc.localize(start).isoformat(),
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
'end': {
|
||||
'dateTime': pytz.utc.localize(end).isoformat(),
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
}
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -1261,11 +1280,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'overrides': [{"method": "email", "minutes": 10}], 'useDefault': False},
|
||||
'start': {
|
||||
'dateTime': pytz.utc.localize(start).isoformat(),
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': pytz.utc.localize(end).isoformat(),
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -1338,7 +1359,6 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"updated": self.now,
|
||||
'organizer': {'email': 'odoocalendarref@gmail.com', 'self': True},
|
||||
'summary': """I don't want to be with me anymore""",
|
||||
'visibility': 'public',
|
||||
'attendees': [{
|
||||
'displayName': 'calendar-user (base.group_user)',
|
||||
'email': 'c.c@example.com',
|
||||
|
|
@ -1347,13 +1367,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
'timeZone': 'Europe/Brussels'
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'date': None,
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
'transparency': 'opaque',
|
||||
}
|
||||
|
|
@ -1383,7 +1403,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'start': {'date': str(event.start_date), 'dateTime': None},
|
||||
'end': {'date': str(event.stop_date + relativedelta(days=1)), 'dateTime': None},
|
||||
'summary': 'coucou',
|
||||
'description': '',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'organizer': {'email': 'c.c@example.com', 'self': False},
|
||||
|
|
@ -1392,7 +1412,6 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id,
|
||||
'%s_owner_id' % self.env.cr.dbname: other_user.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
||||
|
|
@ -1427,8 +1446,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
# 'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'dateTime': '2021-02-15T8:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2021-02-15T10:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2021-02-15T8:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2021-02-15T10:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
attendee = recurrence.calendar_event_ids.attendee_ids.mapped('state')
|
||||
|
|
@ -1448,8 +1467,9 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
# 'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'dateTime': '2021-02-15T8:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2021-02-15T10:00:00+01:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2021-02-15T8:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2021-02-15T10:00:00+01:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'guestsCanModify': True,
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', google_id)])
|
||||
|
|
@ -1515,11 +1535,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'recurrence': ['RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=MO'],
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:00:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T20:00:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
}])
|
||||
self.sync(gevent)
|
||||
|
|
@ -1547,11 +1569,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:00:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T20:00:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
event = self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -1574,11 +1598,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
'conferenceData': {
|
||||
'entryPoints': [{
|
||||
|
|
@ -1670,11 +1696,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'transparency': 'transparent'
|
||||
}
|
||||
|
|
@ -1704,19 +1732,20 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
event = self.env['calendar.event'].search([('google_id', '=', values.get('id'))])
|
||||
private_attendee = event.attendee_ids.filtered(lambda e: e.email == self.private_partner.email)
|
||||
self.assertNotEqual(self.private_partner.id, private_attendee.partner_id.id)
|
||||
self.assertNotEqual(private_attendee.partner_id.type, 'private')
|
||||
self.assertEqual(self.private_partner.id, private_attendee.partner_id.id)
|
||||
self.assertGoogleAPINotCalled()
|
||||
|
||||
@patch_api
|
||||
|
|
@ -1735,23 +1764,21 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
}, ],
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=3;BYDAY=MO'],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {'date': '2020-01-6'},
|
||||
'end': {'date': '2020-01-7'},
|
||||
'start': {'date': '2020-01-06'},
|
||||
'end': {'date': '2020-01-07'},
|
||||
}
|
||||
self.env['calendar.recurrence']._sync_google2odoo(GoogleEvent([values]))
|
||||
recurrence = self.env['calendar.recurrence'].search([('google_id', '=', values.get('id'))])
|
||||
events = recurrence.calendar_event_ids
|
||||
private_attendees = events.mapped('attendee_ids').filtered(lambda e: e.email == self.private_partner.email)
|
||||
self.assertTrue(all([a.partner_id.id != self.private_partner.id for a in private_attendees]))
|
||||
self.assertTrue(all([a.partner_id == self.private_partner for a in private_attendees]))
|
||||
self.assertTrue(all([a.partner_id.type != 'private' for a in private_attendees]))
|
||||
self.assertGoogleAPINotCalled()
|
||||
|
||||
@patch_api
|
||||
def test_alias_email_sync_recurrence(self):
|
||||
catchall_domain = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.domain")
|
||||
alias_model = self.env['ir.model'].search([('model', '=', 'calendar.event')])
|
||||
self.env['mail.alias'].create({'alias_name': 'sale', 'alias_model_id': alias_model.id})
|
||||
alias_email = 'sale@%s' % catchall_domain if catchall_domain else 'sale@'
|
||||
mail_alias = self.env['mail.alias'].create({'alias_name': 'sale', 'alias_model_id': alias_model.id})
|
||||
|
||||
google_id = 'oj44nep1ldf8a3ll02uip0c9aa'
|
||||
base_event = self.env['calendar.event'].create({
|
||||
|
|
@ -1779,7 +1806,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
"attendees": [
|
||||
{
|
||||
"email": alias_email, "state": "accepted",
|
||||
"email": mail_alias.display_name,
|
||||
"responseStatus": "accepted",
|
||||
},
|
||||
],
|
||||
'updated': self.now,
|
||||
|
|
@ -1804,11 +1832,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([values]))
|
||||
|
|
@ -1847,11 +1877,13 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2020-01-13T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2020-01-13T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels'
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1882,6 +1914,7 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
"recurrence": [f"RRULE:FREQ={frequency};COUNT={count}"],
|
||||
"reminders": {"useDefault": True},
|
||||
"updated": "2023-03-27T11:45:08.547Z",
|
||||
'guestsCanModify': True,
|
||||
}]
|
||||
google_event = GoogleEvent(google_value)
|
||||
self.env['calendar.recurrence']._sync_google2odoo(google_event)
|
||||
|
|
@ -1913,8 +1946,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'First title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-12T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-12T10:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-12T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-12T10:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20230518T215959Z;BYDAY=FR'],
|
||||
'iCalUID': '59orfkiunbn2vlp6c2tndq6ui0@google.com',
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -1929,8 +1962,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'Second title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-19T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-19T10:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-19T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-19T10:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=FR'],
|
||||
'iCalUID': '59orfkiunbn2vlp6c2tndq6ui0_R20230519T070000@google.com',
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -1945,8 +1978,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'Second title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-26T08:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-26T08:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurringEventId': '59orfkiunbn2vlp6c2tndq6ui0_R20230519T070000',
|
||||
'originalStartTime': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -2021,8 +2054,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'First title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-12T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-12T10:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-12T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-12T10:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20230518T215959Z;BYDAY=FR'],
|
||||
'iCalUID': '59orfkiunbn2vlp6c2tndq6ui0@google.com',
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -2037,8 +2070,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'Second title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-19T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-19T10:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-19T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-19T10:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=FR'],
|
||||
'iCalUID': '59orfkiunbn2vlp6c2tndq6ui0_R20230519T070000@google.com',
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -2053,8 +2086,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'Second title',
|
||||
'creator': {'email': 'john.doe@example.com', 'self': True},
|
||||
'organizer': {'email': 'john.doe@example.com', 'self': True},
|
||||
'start': {'dateTime': '2023-05-26T08:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'end': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'start': {'dateTime': '2023-05-26T08:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'end': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels', 'date': None},
|
||||
'recurringEventId': '59orfkiunbn2vlp6c2tndq6ui0', # Range removed
|
||||
'originalStartTime': {'dateTime': '2023-05-26T09:00:00+02:00', 'timeZone': 'Europe/Brussels'},
|
||||
'reminders': {'useDefault': True},
|
||||
|
|
@ -2094,6 +2127,95 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
# Not call API
|
||||
self.assertGoogleAPINotCalled()
|
||||
|
||||
@patch_api
|
||||
def test_event_guest_modify_permission(self):
|
||||
"""
|
||||
'guestsCanModify' is a permission set on Google side to allow or forbid guests editing the event.
|
||||
This test states that Odoo Calendar:
|
||||
1. forbids the updates of non-editable events by guests.
|
||||
2. allows editable events being updated by guests.
|
||||
3. allows guests to stop and restart their synchronizations with Google Calendars.
|
||||
"""
|
||||
guest_user = new_test_user(self.env, login='calendar-user')
|
||||
|
||||
# Create an event editable only by the organizer. Guests can't modify it.
|
||||
not_editable_event_values = {
|
||||
'id': 'notEditableEventGoogleId',
|
||||
'guestsCanModify': False,
|
||||
'description': 'Editable only by organizer',
|
||||
'organizer': {'email': self.env.user.email, 'self': True},
|
||||
'summary': 'Editable only by organizer',
|
||||
'visibility': 'public',
|
||||
'attendees': [{
|
||||
'displayName': 'Guest User',
|
||||
'email': guest_user.email,
|
||||
'responseStatus': 'accepted'
|
||||
}],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2023-07-05T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2023-07-05T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None
|
||||
},
|
||||
}
|
||||
# Create an event editable by guests and organizer.
|
||||
editable_event_values = {
|
||||
'id': 'editableEventGoogleId',
|
||||
'guestsCanModify': True,
|
||||
'description': 'Editable by everyone',
|
||||
'organizer': {'email': self.env.user.email, 'self': True},
|
||||
'summary': 'Editable by everyone',
|
||||
'visibility': 'public',
|
||||
'attendees': [{
|
||||
'displayName': 'Guest User',
|
||||
'email': guest_user.email,
|
||||
'responseStatus': 'accepted'
|
||||
}],
|
||||
'reminders': {'useDefault': True},
|
||||
'start': {
|
||||
'dateTime': '2023-07-05T16:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2023-07-05T19:55:00+01:00',
|
||||
'timeZone': 'Europe/Brussels',
|
||||
'date': None,
|
||||
},
|
||||
}
|
||||
# Sync events from Google to Odoo and get them after sync.
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([not_editable_event_values, editable_event_values]))
|
||||
not_editable_event = self.env['calendar.event'].search([('google_id', '=', not_editable_event_values.get('id'))])
|
||||
editable_event = self.env['calendar.event'].search([('google_id', '=', editable_event_values.get('id'))])
|
||||
|
||||
# Assert that event is created in Odoo with proper values for guests_readonly variable.
|
||||
self.assertFalse(editable_event.guests_readonly, "Value 'guestCanModify' received from Google must be True.")
|
||||
self.assertTrue(not_editable_event.guests_readonly, "Value 'guestCanModify' received from Google must be False.")
|
||||
|
||||
# Assert that organizer can edit both events.
|
||||
self.assertTrue(editable_event.with_user(editable_event.user_id).write({'name': 'Edited by organizer!'}))
|
||||
self.assertTrue(not_editable_event.with_user(not_editable_event.user_id).write({'name': 'Edited by organizer!'}))
|
||||
|
||||
# Assert that a validation error is raised when guest updates the not editable event.
|
||||
with self.assertRaises(ValidationError):
|
||||
self.assertTrue(not_editable_event.with_user(guest_user).write({'name': 'Edited by attendee!'}),
|
||||
"Attendee shouldn't be able to modify event with 'guests_readonly' variable as 'True'.")
|
||||
|
||||
# Assert that normal event can be edited by guest.
|
||||
self.assertTrue(editable_event.with_user(guest_user).write({'name': 'Edited by attendee!'}),
|
||||
"Attendee should be able to modify event with 'guests_readonly' variable as 'False'.")
|
||||
|
||||
# Assert that guest user can restart the synchronization of its calendar (containing non-editable events).
|
||||
guest_user.sudo().stop_google_synchronization()
|
||||
self.assertTrue(guest_user.google_synchronization_stopped)
|
||||
guest_user.sudo().restart_google_synchronization()
|
||||
self.assertFalse(guest_user.google_synchronization_stopped)
|
||||
|
||||
@patch_api
|
||||
def test_attendee_status_is_not_updated_when_syncing_and_time_data_is_not_changed(self):
|
||||
recurrence_id = "aaaaaaaa"
|
||||
|
|
@ -2121,8 +2243,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
'summary': 'coucou',
|
||||
'id': recurrence_id,
|
||||
'recurrence': ['RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3'],
|
||||
'start': {'dateTime': '2020-01-06T10:00:00+01:00'},
|
||||
'end': {'dateTime': '2020-01-06T11:00:00+01:00'},
|
||||
'start': {'dateTime': '2020-01-06T10:00:00+01:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-06T11:00:00+01:00', 'date': None},
|
||||
'reminders': {'useDefault': True},
|
||||
'organizer': {'email': organizer.partner_id.email},
|
||||
'attendees': [{'email': organizer.partner_id.email, 'responseStatus': 'accepted'}, {'email': other_user.partner_id.email, 'responseStatus': 'accepted'}],
|
||||
|
|
@ -2134,100 +2256,28 @@ class TestSyncGoogle2Odoo(TestSyncGoogle):
|
|||
self.assertEqual(events[0].attendee_ids[0].state, 'accepted', 'after google sync, organizer should have accepted status still')
|
||||
self.assertGoogleAPINotCalled()
|
||||
|
||||
@patch.object(GoogleCalendarService, "get_events")
|
||||
def test_recurring_event_moved_to_future(self, mock_get_events):
|
||||
# There's a daily recurring event from 2024-07-01 to 2024-07-02
|
||||
recurrence_id = "abcd1"
|
||||
recurrence = self.generate_recurring_event(
|
||||
mock_dt="2024-07-01",
|
||||
google_id=recurrence_id,
|
||||
rrule="FREQ=DAILY;INTERVAL=1;COUNT=2",
|
||||
start=datetime(2024, 7, 1, 9),
|
||||
stop=datetime(2024, 7, 1, 10),
|
||||
partner_ids=[
|
||||
Command.set(
|
||||
[
|
||||
self.organizer_user.partner_id.id,
|
||||
self.attendee_user.partner_id.id,
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
self.assertRecordValues(
|
||||
recurrence.calendar_event_ids.sorted("start"),
|
||||
[
|
||||
{
|
||||
"start": datetime(2024, 7, 1, 9),
|
||||
"stop": datetime(2024, 7, 1, 10),
|
||||
"google_id": f"{recurrence_id}_20240701T090000Z",
|
||||
},
|
||||
{
|
||||
"start": datetime(2024, 7, 2, 9),
|
||||
"stop": datetime(2024, 7, 2, 10),
|
||||
"google_id": f"{recurrence_id}_20240702T090000Z",
|
||||
},
|
||||
],
|
||||
)
|
||||
# User moves batch to next week
|
||||
common = {
|
||||
"attendees": [
|
||||
{
|
||||
"email": self.attendee_user.partner_id.email,
|
||||
"responseStatus": "needsAction",
|
||||
},
|
||||
{
|
||||
"email": self.organizer_user.partner_id.email,
|
||||
"responseStatus": "needsAction",
|
||||
},
|
||||
],
|
||||
"organizer": {"email": self.organizer_user.partner_id.email},
|
||||
"reminders": {"useDefault": True},
|
||||
"summary": "coucou",
|
||||
"updated": "2024-07-02T08:00:00Z",
|
||||
@patch_api
|
||||
def test_create_event_with_default_and_undefined_privacy(self):
|
||||
""" Check if google events are created in Odoo when 'default' privacy setting is defined and also when it is not. """
|
||||
# Sync events from Google to Odoo after adding the privacy property.
|
||||
sample_event_values = {
|
||||
'summary': 'Test',
|
||||
'start': {'dateTime': '2020-01-06T10:00:00+01:00'},
|
||||
'end': {'dateTime': '2020-01-06T11:00:00+01:00'},
|
||||
'reminders': {'useDefault': True},
|
||||
'organizer': {'email': self.env.user.email},
|
||||
'attendees': [{'email': self.env.user.email, 'responseStatus': 'accepted'}],
|
||||
'updated': self.now,
|
||||
}
|
||||
google_events = [
|
||||
# Recurrence event
|
||||
dict(
|
||||
common,
|
||||
id=recurrence_id,
|
||||
start={"dateTime": "2024-07-08T09:00:00+00:00"},
|
||||
end={"dateTime": "2024-07-08T10:00:00+00:00"},
|
||||
recurrence=["RRULE:FREQ=DAILY;INTERVAL=1;COUNT=2"],
|
||||
),
|
||||
# Cancelled instances
|
||||
{"id": f"{recurrence_id}_20240701T090000Z", "status": "cancelled"},
|
||||
{"id": f"{recurrence_id}_20240702T090000Z", "status": "cancelled"},
|
||||
# New base event
|
||||
dict(
|
||||
common,
|
||||
id=f"{recurrence_id}_20240708T090000Z",
|
||||
start={"dateTime": "2024-07-08T09:00:00+00:00"},
|
||||
end={"dateTime": "2024-07-08T10:00:00+00:00"},
|
||||
recurringEventId=recurrence_id,
|
||||
),
|
||||
]
|
||||
mock_get_events.return_value = (
|
||||
GoogleEvent(google_events),
|
||||
None,
|
||||
[{"method": "popup", "minutes": 30}],
|
||||
)
|
||||
with self.mock_datetime_and_now("2024-04-03"):
|
||||
self.organizer_user.sudo()._sync_google_calendar(self.google_service)
|
||||
self.assertRecordValues(
|
||||
recurrence.calendar_event_ids.sorted("start"),
|
||||
[
|
||||
{
|
||||
"start": datetime(2024, 7, 8, 9),
|
||||
"stop": datetime(2024, 7, 8, 10),
|
||||
"google_id": f"{recurrence_id}_20240708T090000Z",
|
||||
},
|
||||
{
|
||||
"start": datetime(2024, 7, 9, 9),
|
||||
"stop": datetime(2024, 7, 9, 10),
|
||||
"google_id": f"{recurrence_id}_20240709T090000Z",
|
||||
},
|
||||
],
|
||||
)
|
||||
undefined_privacy_event = {'id': 100, **sample_event_values}
|
||||
default_privacy_event = {'id': 200, 'privacy': 'default', **sample_event_values}
|
||||
self.env['calendar.event']._sync_google2odoo(GoogleEvent([undefined_privacy_event, default_privacy_event]))
|
||||
|
||||
# Ensure that synced events have the correct privacy field in Odoo.
|
||||
undefined_privacy_odoo_event = self.env['calendar.event'].search([('google_id', '=', 1)])
|
||||
default_privacy_odoo_event = self.env['calendar.event'].search([('google_id', '=', 2)])
|
||||
self.assertFalse(undefined_privacy_odoo_event.privacy, "Event with undefined privacy must have False value in privacy field.")
|
||||
self.assertFalse(default_privacy_odoo_event.privacy, "Event with default privacy must have False value in privacy field.")
|
||||
|
||||
@patch.object(GoogleCalendarService, 'get_events')
|
||||
def test_accepting_recurrent_event_with_this_event_option_synced_by_attendee(self, mock_get_events):
|
||||
|
|
|
|||
|
|
@ -1,29 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo.addons.google_calendar.utils.google_event import GoogleEvent
|
||||
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.res_users import ResUsers
|
||||
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle, patch_api
|
||||
from odoo.tests.common import users, warmup
|
||||
from odoo.tests import tagged
|
||||
from odoo import tools
|
||||
|
||||
|
||||
@tagged('odoo2google', 'is_query_count')
|
||||
@patch.object(User, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
@tagged('odoo2google', 'calendar_performance', 'is_query_count')
|
||||
@patch.object(ResUsers, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
class TestSyncOdoo2Google(TestSyncGoogle):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.env.user.partner_id.tz = "Europe/Brussels"
|
||||
self.google_service = GoogleCalendarService(self.env['google.service'])
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.user.partner_id.tz = "Europe/Brussels"
|
||||
cls.google_service = GoogleCalendarService(cls.env['google.service'])
|
||||
# Make sure this test will work for the next 30 years
|
||||
self.env['ir.config_parameter'].set_param('google_calendar.sync.range_days', 10000)
|
||||
cls.env['ir.config_parameter'].set_param('google_calendar.sync.range_days', 10000)
|
||||
|
||||
@patch_api
|
||||
def test_event_creation(self):
|
||||
|
|
@ -51,7 +50,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'description': tools.html_sanitize(description),
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'visibility': 'private',
|
||||
'guestsCanModify': True,
|
||||
|
|
@ -77,7 +76,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
})
|
||||
partner_model = self.env.ref('base.model_res_partner')
|
||||
partner = self.env['res.partner'].search([], limit=1)
|
||||
with self.assertQueryCount(__system__=616):
|
||||
with self.assertQueryCount(__system__=526):
|
||||
events = self.env['calendar.event'].create([{
|
||||
'name': "Event %s" % (i),
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
|
|
@ -92,10 +91,9 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
|
||||
events._sync_odoo2google(self.google_service)
|
||||
|
||||
with self.assertQueryCount(__system__=130):
|
||||
with self.assertQueryCount(__system__=24):
|
||||
events.unlink()
|
||||
|
||||
|
||||
@patch_api
|
||||
@users('__system__')
|
||||
@warmup
|
||||
|
|
@ -108,8 +106,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'duration': 18,
|
||||
})
|
||||
partner_model = self.env.ref('base.model_res_partner')
|
||||
partner = self.env['res.partner'].search([], limit=1)
|
||||
with self.assertQueryCount(__system__=72):
|
||||
with self.assertQueryCount(__system__=105):
|
||||
event = self.env['calendar.event'].create({
|
||||
'name': "Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
|
|
@ -126,7 +123,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'res_id': partner.id,
|
||||
})
|
||||
|
||||
with self.assertQueryCount(__system__=35):
|
||||
with self.assertQueryCount(__system__=29):
|
||||
event.unlink()
|
||||
|
||||
def test_event_without_user(self):
|
||||
|
|
@ -164,7 +161,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'description': '',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'visibility': 'private',
|
||||
'guestsCanModify': True,
|
||||
|
|
@ -193,7 +190,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'summary': 'Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
|
|
@ -255,7 +251,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'summary': 'Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
|
|
@ -291,7 +286,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'summary': 'Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
|
|
@ -345,7 +339,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'attendees': [{'email': 'odoobot@example.com', 'responseStatus': 'accepted'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.recurrence_id.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=1;BYDAY=WE'],
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
|
@ -390,9 +383,8 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'description': '',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'jean-luc@opoo.com', 'self': True},
|
||||
|
|
@ -436,7 +428,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=WE'],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: new_recurrence.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
||||
|
|
@ -559,14 +550,13 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'start': {'date': str(event.start_date), 'dateTime': None},
|
||||
'end': {'date': str(event.stop_date + relativedelta(days=1)), 'dateTime': None},
|
||||
'summary': 'Event with attendees',
|
||||
'description': '',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
'attendees': [{'email': 'jean-luc@opoo.com', 'responseStatus': 'declined'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
})
|
||||
|
||||
|
|
@ -605,39 +595,9 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=WE'],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: new_recurrence.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
}, 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')
|
||||
|
||||
@patch_api
|
||||
def test_recurrence_delete_single_events(self):
|
||||
"""
|
||||
|
|
@ -678,7 +638,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'attendees': [{'email': 'odoobot@example.com', 'responseStatus': 'accepted'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event_1.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'status': 'cancelled',
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
|
@ -691,6 +650,92 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
self.assertFalse(event_2.active)
|
||||
self.assertFalse(recurrence.active)
|
||||
|
||||
@patch_api
|
||||
def test_create_event_with_sync_config_paused(self):
|
||||
"""
|
||||
Creates an event with the synchronization paused, its field 'need_sync'
|
||||
must be True for later synchronizing it with Google Calendar.
|
||||
"""
|
||||
# Set synchronization as active and unpause the synchronization.
|
||||
self.env.user.google_synchronization_stopped = False
|
||||
self.env.user.sudo().pause_google_synchronization()
|
||||
|
||||
# Create record and call synchronization method.
|
||||
record = self.env['calendar.event'].create({
|
||||
'name': "Event",
|
||||
'start': datetime(2023, 6, 29, 8, 0),
|
||||
'stop': datetime(2023, 6, 29, 18, 0),
|
||||
'need_sync': True
|
||||
})
|
||||
record._sync_odoo2google(self.google_service)
|
||||
|
||||
# Assert that synchronization is paused, insert wasn't called and record is waiting to be synced.
|
||||
self.assertFalse(self.env.user.google_synchronization_stopped)
|
||||
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
|
||||
self.assertTrue(record.need_sync, "Sync variable must be true for updating event when sync re-activates")
|
||||
self.assertGoogleEventNotInserted()
|
||||
|
||||
@patch_api
|
||||
def test_update_synced_event_with_sync_config_paused(self):
|
||||
"""
|
||||
Updates a synced event with synchronization paused, event must be modified and have its
|
||||
field 'need_sync' as True for later synchronizing it with Google Calendar.
|
||||
"""
|
||||
# Set synchronization as active and unpause it.
|
||||
self.env.user.google_synchronization_stopped = False
|
||||
self.env.user.sudo().unpause_google_synchronization()
|
||||
|
||||
# Setup synced record in Calendar.
|
||||
record = self.env['calendar.event'].create({
|
||||
'google_id': 'aaaaaaaaa',
|
||||
'name': "Event",
|
||||
'start': datetime(2023, 6, 29, 8, 0),
|
||||
'stop': datetime(2023, 6, 29, 18, 0),
|
||||
'need_sync': False
|
||||
})
|
||||
|
||||
# Pause synchronization and update synced event. It will only update it locally.
|
||||
self.env.user.sudo().pause_google_synchronization()
|
||||
record.write({'name': "Updated Event"})
|
||||
record._sync_odoo2google(self.google_service)
|
||||
|
||||
# Assert that synchronization is paused, patch wasn't called and record is waiting to be synced.
|
||||
self.assertFalse(self.env.user.google_synchronization_stopped)
|
||||
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
|
||||
self.assertEqual(record.name, "Updated Event", "Assert that event name was updated in Odoo Calendar")
|
||||
self.assertTrue(record.need_sync, "Sync variable must be true for updating event when sync re-activates")
|
||||
self.assertGoogleEventNotPatched()
|
||||
|
||||
@patch_api
|
||||
def test_delete_synced_event_with_sync_config_paused(self):
|
||||
"""
|
||||
Deletes a synced event with synchronization paused, event must be archived in Odoo and
|
||||
have its field 'need_sync' as True for later synchronizing it with Google Calendar.
|
||||
"""
|
||||
# Set synchronization as active and then pause synchronization.
|
||||
self.env.user.google_synchronization_stopped = False
|
||||
self.env.user.sudo().unpause_google_synchronization()
|
||||
|
||||
# Setup synced record in Calendar.
|
||||
record = self.env['calendar.event'].create({
|
||||
'google_id': 'aaaaaaaaa',
|
||||
'name': "Event",
|
||||
'start': datetime(2023, 6, 29, 8, 0),
|
||||
'stop': datetime(2023, 6, 29, 18, 0),
|
||||
'need_sync': False
|
||||
})
|
||||
|
||||
# Pause synchronization and delete synced event.
|
||||
self.env.user.sudo().pause_google_synchronization()
|
||||
record.unlink()
|
||||
|
||||
# Assert that synchronization is paused, delete wasn't called and record was archived in Odoo.
|
||||
self.assertFalse(self.env.user.google_synchronization_stopped)
|
||||
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
|
||||
self.assertFalse(record.active, "Event must be archived in Odoo after unlinking it")
|
||||
self.assertTrue(record.need_sync, "Sync variable must be true for updating event in Google when sync re-activates")
|
||||
self.assertGoogleEventNotDeleted()
|
||||
|
||||
@patch_api
|
||||
def test_videocall_location_on_location_set(self):
|
||||
partner = self.env['res.partner'].create({'name': 'Jean-Luc', 'email': 'jean-luc@opoo.com'})
|
||||
|
|
@ -703,7 +748,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'location' : 'Event Location'
|
||||
})
|
||||
event._sync_odoo2google(self.google_service)
|
||||
self.assertGoogleEventHasNoConferenceData()
|
||||
self.assertGoogleEventInserted({'conferenceData': False})
|
||||
|
||||
@patch_api
|
||||
def test_event_available_privacy(self):
|
||||
|
|
@ -723,7 +768,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'summary': 'Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
|
|
@ -750,7 +794,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'summary': 'Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'odoobot@example.com', 'self': True},
|
||||
|
|
@ -759,6 +802,55 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'transparency': 'opaque',
|
||||
})
|
||||
|
||||
@patch_api
|
||||
@patch.object(ResUsers, '_sync_request')
|
||||
def test_event_sync_after_pause_period(self, mock_sync_request):
|
||||
""" Ensure that an event created during the paused synchronization period gets synchronized after resuming it. """
|
||||
# Pause the synchronization and creates the local event.
|
||||
self.organizer_user.google_synchronization_stopped = False
|
||||
self.organizer_user.sudo().pause_google_synchronization()
|
||||
record = self.env['calendar.event'].with_user(self.organizer_user).create({
|
||||
'name': "Event",
|
||||
'start': datetime(2023, 1, 15, 8, 0),
|
||||
'stop': datetime(2023, 1, 15, 18, 0),
|
||||
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)]
|
||||
})
|
||||
|
||||
# Define mock return values for the '_sync_request' method.
|
||||
mock_sync_request.return_value = {
|
||||
'events': GoogleEvent([]),
|
||||
'default_reminders': (),
|
||||
'full_sync': False,
|
||||
}
|
||||
|
||||
# With the synchronization paused, manually call the synchronization to simulate the page refresh.
|
||||
self.organizer_user.sudo()._sync_google_calendar(self.google_service)
|
||||
self.assertFalse(self.organizer_user.google_synchronization_stopped, "Synchronization should not be stopped, only paused.")
|
||||
self.assertEqual(self.organizer_user._get_google_sync_status(), "sync_paused", "Synchronization must be paused since it wasn't resumed yet.")
|
||||
self.assertTrue(record.need_sync, "Record must have its 'need_sync' variable as true for it to be synchronized when the synchronization is resumed.")
|
||||
self.assertGoogleEventNotInserted()
|
||||
|
||||
# Unpause the synchronization and call the calendar synchronization. Ensure the event was inserted in Google side.
|
||||
self.organizer_user.sudo().unpause_google_synchronization()
|
||||
self.organizer_user.with_user(self.organizer_user).sudo()._sync_google_calendar(self.google_service)
|
||||
self.assertGoogleEventInserted({
|
||||
'id': False,
|
||||
'start': {'dateTime': '2023-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2023-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'description': record.description,
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'transparency': 'opaque',
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': self.organizer_user.email, 'self': True},
|
||||
'attendees': [
|
||||
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
|
||||
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
|
||||
],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: record.id}},
|
||||
})
|
||||
|
||||
@patch_api
|
||||
def test_allday_duplicated_first_event_in_recurrence(self):
|
||||
""" Ensure that when creating recurrence with 'all day' events the first event won't get duplicated in Google. """
|
||||
|
|
@ -788,9 +880,8 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
'start': {'date': '2024-01-17', 'dateTime': None},
|
||||
'end': {'date': '2024-01-18', 'dateTime': None},
|
||||
'summary': 'All Day Recurrent Event',
|
||||
'description': '',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'visibility': 'public',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': self.organizer_user.email, 'self': True},
|
||||
|
|
@ -801,118 +892,227 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
|||
}, timeout=3)
|
||||
|
||||
@patch_api
|
||||
def test_partner_type_change(self):
|
||||
"""Test syncing an event with a private address attendee using
|
||||
a user without access to private addresses.
|
||||
@patch.object(ResUsers, '_sync_request')
|
||||
def test_skip_google_sync_for_non_synchronized_users_new_events(self, mock_sync_request):
|
||||
"""
|
||||
user = self.env['res.users'].create({
|
||||
'name': 'user1',
|
||||
'login': 'user1',
|
||||
'email': 'user1@odoo.com',
|
||||
})
|
||||
private_partner = self.env['res.partner'].create({
|
||||
'name': 'Private Contact',
|
||||
'email': 'private_email@example.com',
|
||||
'type': 'private',
|
||||
})
|
||||
event = self.env['calendar.event'].create({
|
||||
'name': "Private Event",
|
||||
'user_id': user.id,
|
||||
'start': datetime(2020, 1, 13, 16, 55),
|
||||
'stop': datetime(2020, 1, 13, 19, 55),
|
||||
'partner_ids': [(4, private_partner.id)],
|
||||
'privacy': 'private',
|
||||
Skip the synchro of new events by attendees when the organizer is not synchronized with Google.
|
||||
Otherwise, the event ownership will be lost to the attendee and it could generate duplicates in
|
||||
Odoo, as well cause problems in the future the synchronization of that event for the original owner.
|
||||
"""
|
||||
with self.mock_datetime_and_now("2023-01-10"):
|
||||
# Stop the synchronization for the organizer and leave the attendee synchronized.
|
||||
# Then, create an event with the organizer and attendee. Assert that it was not inserted.
|
||||
self.organizer_user.google_synchronization_stopped = True
|
||||
self.attendee_user.google_synchronization_stopped = False
|
||||
record = self.env['calendar.event'].with_user(self.organizer_user).create({
|
||||
'name': "Event",
|
||||
'start': datetime(2023, 1, 15, 8, 0),
|
||||
'stop': datetime(2023, 1, 15, 18, 0),
|
||||
'need_sync': True,
|
||||
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)]
|
||||
})
|
||||
self.assertGoogleEventNotInserted()
|
||||
|
||||
# Define mock return values for the '_sync_request' method.
|
||||
mock_sync_request.return_value = {
|
||||
'events': GoogleEvent([]),
|
||||
'default_reminders': (),
|
||||
'full_sync': False,
|
||||
}
|
||||
|
||||
# Synchronize the attendee, and ensure that the event was not inserted after it.
|
||||
self.attendee_user.with_user(self.attendee_user).sudo()._sync_google_calendar(self.google_service)
|
||||
self.assertGoogleAPINotCalled()
|
||||
|
||||
# Now, we synchronize the organizer and make sure the event got inserted by him.
|
||||
self.organizer_user.with_user(self.organizer_user).restart_google_synchronization()
|
||||
self.organizer_user.with_user(self.organizer_user).sudo()._sync_google_calendar(self.google_service)
|
||||
self.assertGoogleEventInserted({
|
||||
'id': False,
|
||||
'start': {'dateTime': '2023-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2023-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'description': ('<div><strong>Organized by</strong><br>'
|
||||
'organizer_user (base.group_user)<br><a href="mailto:o.o@example.com">o.o@example.com</a><br><br>'
|
||||
'<strong>Contact Details</strong><br>'
|
||||
'attendee_user (base.group_user)<br><a href="mailto:a.a@example.com">a.a@example.com</a></div>'),
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'transparency': 'opaque',
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': self.organizer_user.email, 'self': True},
|
||||
'attendees': [
|
||||
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
|
||||
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
|
||||
],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: record.id}},
|
||||
})
|
||||
|
||||
@patch_api
|
||||
def test_event_duplication_allday_google_calendar(self):
|
||||
event = self.env['calendar.event'].with_user(self.organizer_user).create({
|
||||
'name': "Event",
|
||||
'allday': True,
|
||||
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)],
|
||||
'start': datetime(2020, 1, 15),
|
||||
'stop': datetime(2020, 1, 15),
|
||||
'need_sync': False,
|
||||
})
|
||||
event = event.with_user(user)
|
||||
event.env.invalidate_all()
|
||||
event._sync_odoo2google(self.google_service)
|
||||
event_response_data = {
|
||||
'id': False,
|
||||
'start': {'date': '2020-01-15', 'dateTime': None},
|
||||
'end': {'date': '2020-01-16', 'dateTime': None},
|
||||
'summary': 'Event',
|
||||
'description': event.description,
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'organizer': {'email': self.organizer_user.email, 'self': True},
|
||||
'attendees': [
|
||||
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
|
||||
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
|
||||
],
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'transparency': 'opaque',
|
||||
}
|
||||
self.assertGoogleEventInsertedMultiTime({
|
||||
**event_response_data,
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
|
||||
})
|
||||
|
||||
event2 = event.copy()
|
||||
event2._sync_odoo2google(self.google_service)
|
||||
event_response_data['description'] = event2.description
|
||||
self.assertGoogleEventInsertedMultiTime({
|
||||
**event_response_data,
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event2.id}},
|
||||
})
|
||||
|
||||
def test_event_over_send_updates(self):
|
||||
"""Test that events that are over don't sent updates to attendees."""
|
||||
with self.mock_datetime_and_now("2023-01-10"):
|
||||
self.env.cr.postcommit.clear()
|
||||
with self.mock_google_service():
|
||||
past_event = self.env['calendar.event'].create({
|
||||
'name': "Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 9, 0),
|
||||
'need_sync': False,
|
||||
})
|
||||
past_event._sync_odoo2google(self.google_service)
|
||||
self.call_post_commit_hooks()
|
||||
self.assertTrue(past_event._is_event_over(), "Event should be considered over")
|
||||
self.assertGoogleEventSendUpdates('none')
|
||||
|
||||
def test_event_not_over_send_updates(self):
|
||||
"""Test that events that are not over send updates to attendees."""
|
||||
with self.mock_datetime_and_now("2023-01-10"):
|
||||
self.env.cr.postcommit.clear()
|
||||
with self.mock_google_service():
|
||||
future_date = datetime(2023, 1, 20, 8, 0) # Fixed date instead of datetime.now()
|
||||
future_event = self.env['calendar.event'].create({
|
||||
'name': "Future Event",
|
||||
'start': future_date,
|
||||
'stop': future_date + relativedelta(hours=1),
|
||||
'need_sync': False,
|
||||
})
|
||||
# Sync the event and verify send_updates is set to 'all'
|
||||
future_event._sync_odoo2google(self.google_service)
|
||||
self.call_post_commit_hooks()
|
||||
self.assertFalse(future_event._is_event_over(), "Future event should not be considered over")
|
||||
self.assertGoogleEventSendUpdates('all')
|
||||
|
||||
def test_recurrence_over_send_updates(self):
|
||||
"""Test that recurrences that are over don't send updates to attendees."""
|
||||
with self.mock_datetime_and_now("2023-01-10"):
|
||||
self.env.cr.postcommit.clear()
|
||||
with self.mock_google_service():
|
||||
past_event = self.env['calendar.event'].create({
|
||||
'name': "Past Recurring Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 9, 0),
|
||||
'need_sync': False,
|
||||
})
|
||||
past_recurrence = self.env['calendar.recurrence'].create({
|
||||
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
|
||||
'base_event_id': past_event.id,
|
||||
'need_sync': False,
|
||||
})
|
||||
past_recurrence._apply_recurrence()
|
||||
# Sync the recurrence and verify send_updates is set to 'none'
|
||||
past_recurrence._sync_odoo2google(self.google_service)
|
||||
self.call_post_commit_hooks()
|
||||
self.assertTrue(past_recurrence._is_event_over(), "Past recurrence should be considered over")
|
||||
self.assertGoogleEventSendUpdates('none')
|
||||
|
||||
def test_recurrence_not_over_send_updates(self):
|
||||
"""Test that recurrences that are not over send updates to attendees."""
|
||||
with self.mock_datetime_and_now("2023-01-10"):
|
||||
self.env.cr.postcommit.clear()
|
||||
with self.mock_google_service():
|
||||
future_date = datetime(2023, 1, 20, 8, 0)
|
||||
future_event = self.env['calendar.event'].create({
|
||||
'name': "Future Recurring Event",
|
||||
'start': future_date,
|
||||
'stop': future_date + relativedelta(hours=1),
|
||||
'need_sync': False,
|
||||
})
|
||||
future_recurrence = self.env['calendar.recurrence'].create(
|
||||
{
|
||||
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
|
||||
'base_event_id': future_event.id,
|
||||
'need_sync': False,
|
||||
}
|
||||
)
|
||||
future_recurrence._apply_recurrence()
|
||||
# Sync the recurrence and verify send_updates is set to 'all'
|
||||
future_recurrence._sync_odoo2google(self.google_service)
|
||||
self.call_post_commit_hooks()
|
||||
self.assertFalse(future_recurrence._is_event_over(), "Future recurrence should not be considered over")
|
||||
self.assertGoogleEventSendUpdates('all')
|
||||
|
||||
@patch_api
|
||||
def test_eliminate_remote_meet_link_when_removed_locally(self):
|
||||
partner = self.env['res.partner'].create({'name': 'Name', 'email': 'email@emailprovider.com'})
|
||||
google_id = 'nicegoogleid'
|
||||
event = self.env['calendar.event'].create({
|
||||
'google_id': google_id,
|
||||
'name': "Awesome event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 18, 0),
|
||||
'partner_ids': [(4, partner.id)],
|
||||
'need_sync': False,
|
||||
})
|
||||
event.write({'videocall_location': False})
|
||||
event._sync_odoo2google(self.google_service)
|
||||
self.assertGoogleEventPatched(google_id, {'conferenceData': None}, timeout=3)
|
||||
|
||||
@patch_api
|
||||
def test_event_creation_for_different_user(self):
|
||||
"""
|
||||
Test event is synchronized for organizer with active google synchronization if it is
|
||||
created by a user with google synchronization stopped.
|
||||
"""
|
||||
self.attendee_user.google_synchronization_stopped = True
|
||||
self.organizer_user.google_calendar_token = 'dummy-token'
|
||||
event = self.env['calendar.event'].with_user(self.attendee_user).create({
|
||||
'name': "Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 18, 0),
|
||||
'user_id': self.organizer_user.id,
|
||||
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)],
|
||||
})
|
||||
|
||||
event._sync_odoo2google(self.google_service)
|
||||
self.assertGoogleEventInserted({
|
||||
'id': False,
|
||||
'start': {'dateTime': '2020-01-13T16:55:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-13T19:55:00+00:00', 'date': None},
|
||||
'summary': 'Private Event',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'visibility': 'private',
|
||||
'guestsCanModify': True,
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'organizer': {'email': 'user1@odoo.com', 'self': True},
|
||||
'attendees': [{'email': 'private_email@example.com', 'responseStatus': 'needsAction'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
|
||||
'transparency': 'opaque',
|
||||
})
|
||||
|
||||
@patch_api
|
||||
def test_update_allday_to_timed_event(self):
|
||||
""" Ensure that updating in Odoo all-day events to timed events is reflected in Google. """
|
||||
# Create an 'all-day' event synchronized with Google.
|
||||
self.organizer_user.stop_google_synchronization()
|
||||
event = self.env['calendar.event'].with_user(self.organizer_user).create({
|
||||
'name': "AllDay",
|
||||
'google_id': 'allDayEv',
|
||||
'user_id': self.organizer_user.id,
|
||||
'start': datetime(2024, 1, 17),
|
||||
'stop': datetime(2024, 1, 17),
|
||||
'allday': True,
|
||||
'need_sync': False,
|
||||
'recurrency': True,
|
||||
'recurrence_id': False,
|
||||
})
|
||||
|
||||
# In Odoo, update the event from 'all-day' to timed event.
|
||||
# Ensure that it got successfully patched in Google side.
|
||||
self.organizer_user.restart_google_synchronization()
|
||||
event.with_user(self.organizer_user.id).write({"allday": False})
|
||||
self.assertGoogleEventPatched(event.google_id, {
|
||||
'id': event.google_id,
|
||||
'start': {'date': None, 'dateTime': '2024-01-17T00:00:00+00:00'},
|
||||
'end': {'date': None, 'dateTime': '2024-01-17T00:00:00+00:00'},
|
||||
'summary': 'AllDay',
|
||||
'description': '',
|
||||
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
|
||||
'summary': 'Event',
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'organizer': {'email': 'o.o@example.com', 'self': True},
|
||||
'attendees': [{'email': 'o.o@example.com', 'responseStatus': 'accepted'}],
|
||||
'organizer': {'email': 'o.o@example.com', 'self': False},
|
||||
'attendees': [{'email': 'a.a@example.com', 'responseStatus': 'accepted'}, {'email': 'o.o@example.com', 'responseStatus': 'needsAction'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
||||
@patch_api
|
||||
def test_update_timed_to_allday_event(self):
|
||||
""" Ensure that updating in Odoo timed events to all-day events is reflected in Google. """
|
||||
# Create a timed event synchronized with Google.
|
||||
self.organizer_user.stop_google_synchronization()
|
||||
event = self.env['calendar.event'].with_user(self.organizer_user).create({
|
||||
'name': "TimedEvent",
|
||||
'google_id': 'timedEvId',
|
||||
'user_id': self.organizer_user.id,
|
||||
'start': datetime(2024, 1, 17, 10, 00),
|
||||
'stop': datetime(2024, 1, 17, 11, 00),
|
||||
'allday': False,
|
||||
'need_sync': False,
|
||||
'recurrency': True,
|
||||
'recurrence_id': False,
|
||||
})
|
||||
|
||||
# In Odoo, update the event from timed to 'all-day'.
|
||||
# Ensure that it got successfully patched in Google side.
|
||||
self.organizer_user.restart_google_synchronization()
|
||||
event.with_user(self.organizer_user.id).write({"allday": True})
|
||||
self.assertGoogleEventPatched(event.google_id, {
|
||||
'id': event.google_id,
|
||||
'start': {'date': '2024-01-17', 'dateTime': None},
|
||||
'end': {'date': '2024-01-18', 'dateTime': None},
|
||||
'summary': 'TimedEvent',
|
||||
'description': '',
|
||||
'location': '',
|
||||
'guestsCanModify': True,
|
||||
'organizer': {'email': 'o.o@example.com', 'self': True},
|
||||
'attendees': [{'email': 'o.o@example.com', 'responseStatus': 'accepted'}],
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
|
||||
'reminders': {'overrides': [], 'useDefault': False},
|
||||
'visibility': 'public',
|
||||
'transparency': 'opaque',
|
||||
}, timeout=3)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from freezegun import freeze_time
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo.addons.google_calendar.models.res_users import ResUsers
|
||||
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle
|
||||
from odoo.addons.mail.tests.common import MailCommon
|
||||
from odoo.tests import tagged
|
||||
|
||||
from .test_token_access import TestTokenAccess
|
||||
|
||||
|
||||
@tagged('odoo2google')
|
||||
class TestSyncOdoo2GoogleMail(TestTokenAccess, TestSyncGoogle, MailCommon):
|
||||
|
||||
@patch.object(ResUsers, '_get_google_calendar_token', lambda user: user.google_calendar_token)
|
||||
@freeze_time("2020-01-01")
|
||||
def test_event_creation_for_user(self):
|
||||
organizer1 = self.users[0]
|
||||
organizer2 = self.users[1]
|
||||
user_root = self.env.ref('base.user_root')
|
||||
organizer1.google_calendar_token = 'abc'
|
||||
organizer2.google_calendar_token = False
|
||||
event_values = {
|
||||
'name': "Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 18, 0),
|
||||
}
|
||||
partner = self.env['res.partner'].create({'name': 'Jean-Luc', 'email': 'jean-luc@opoo.com'})
|
||||
for create_user, organizer, responsible, expect_mail, is_public in [
|
||||
(user_root, organizer1, organizer1, False, True), (user_root, None, user_root, True, True),
|
||||
(organizer1, None, organizer1, False, False), (organizer1, organizer2, organizer1, False, True)]:
|
||||
with self.subTest(create_uid=create_user.name if create_user else None, user_id=organizer.name if organizer else None):
|
||||
with self.mock_mail_gateway(), self.mock_google_sync(user_id=responsible):
|
||||
self.env['calendar.event'].with_user(create_user).create({
|
||||
**event_values,
|
||||
'partner_ids': [(4, partner.id)],
|
||||
'user_id': organizer.id if organizer else False,
|
||||
})
|
||||
if not expect_mail:
|
||||
self.assertNotSentEmail()
|
||||
self.assertGoogleEventInserted({
|
||||
'attendees': [{'email': 'jean-luc@opoo.com', 'responseStatus': 'needsAction'}],
|
||||
'id': False,
|
||||
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
|
||||
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
|
||||
'guestsCanModify': is_public,
|
||||
'organizer': {'email': organizer.email, 'self': False} if organizer else False,
|
||||
'summary': 'Event',
|
||||
'reminders': {'useDefault': False, 'overrides': []},
|
||||
}, timeout=3)
|
||||
else:
|
||||
self.assertGoogleEventNotInserted()
|
||||
self.assertMailMail(partner, 'sent', author=user_root.partner_id)
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, Command
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
|
@ -10,17 +12,16 @@ class TestTokenAccess(TransactionCase):
|
|||
|
||||
cls.users = []
|
||||
for u in ('user1', 'user2'):
|
||||
credentials = cls.env['google.calendar.credentials'].create({
|
||||
'calendar_rtoken': f'{u}_rtoken',
|
||||
'calendar_token': f'{u}_token',
|
||||
'calendar_token_validity': fields.Datetime.today(),
|
||||
'calendar_sync_token': f'{u}_sync_token',
|
||||
})
|
||||
user = cls.env['res.users'].create({
|
||||
'name': f'{u}',
|
||||
'login': f'{u}',
|
||||
'email': f'{u}@odoo.com',
|
||||
'google_calendar_account_id': credentials.id,
|
||||
})
|
||||
user.res_users_settings_id.write({
|
||||
'google_calendar_rtoken': f'{u}_rtoken',
|
||||
'google_calendar_token': f'{u}_token',
|
||||
'google_calendar_token_validity': fields.Datetime.today(),
|
||||
'google_calendar_sync_token': f'{u}_sync_token',
|
||||
})
|
||||
cls.users += [user]
|
||||
|
||||
|
|
@ -28,39 +29,39 @@ class TestTokenAccess(TransactionCase):
|
|||
'name': 'system_user',
|
||||
'login': 'system_user',
|
||||
'email': 'system_user@odoo.com',
|
||||
'groups_id': [Command.link(cls.env.ref('base.group_system').id)],
|
||||
'group_ids': [Command.link(cls.env.ref('base.group_system').id)],
|
||||
})
|
||||
|
||||
def test_normal_user_should_be_able_to_reset_his_own_token(self):
|
||||
user = self.users[0]
|
||||
old_validity = user.google_calendar_account_id.calendar_token_validity
|
||||
old_validity = user.res_users_settings_id.google_calendar_token_validity
|
||||
|
||||
user.with_user(user).google_calendar_account_id._set_auth_tokens('my_new_token', 'my_new_rtoken', 3600)
|
||||
user.with_user(user).res_users_settings_id._set_google_auth_tokens('my_new_token', 'my_new_rtoken', 3600)
|
||||
|
||||
self.assertEqual(user.google_calendar_account_id.calendar_rtoken, 'my_new_rtoken')
|
||||
self.assertEqual(user.google_calendar_account_id.calendar_token, 'my_new_token')
|
||||
self.assertEqual(user.res_users_settings_id.google_calendar_rtoken, 'my_new_rtoken')
|
||||
self.assertEqual(user.res_users_settings_id.google_calendar_token, 'my_new_token')
|
||||
self.assertNotEqual(
|
||||
user.google_calendar_account_id.calendar_token_validity,
|
||||
user.res_users_settings_id.google_calendar_token_validity,
|
||||
old_validity
|
||||
)
|
||||
|
||||
def test_normal_user_should_not_be_able_to_reset_other_user_tokens(self):
|
||||
user1, user2 = self.users
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
user2.with_user(user1).google_calendar_account_id._set_auth_tokens(False, False, 0)
|
||||
# Skip test: the access error will not be raised anymore since the access rules were deleted.
|
||||
# with self.assertRaises(AccessError):
|
||||
# user2.with_user(user1).res_users_settings_id._set_auth_tokens(False, False, 0)
|
||||
|
||||
def test_system_user_should_be_able_to_reset_any_tokens(self):
|
||||
user = self.users[0]
|
||||
old_validity = user.google_calendar_account_id.calendar_token_validity
|
||||
old_validity = user.res_users_settings_id.google_calendar_token_validity
|
||||
|
||||
user.with_user(self.system_user).google_calendar_account_id._set_auth_tokens(
|
||||
user.with_user(self.system_user).res_users_settings_id._set_google_auth_tokens(
|
||||
'my_new_token', 'my_new_rtoken', 3600
|
||||
)
|
||||
|
||||
self.assertEqual(user.google_calendar_account_id.calendar_rtoken, 'my_new_rtoken')
|
||||
self.assertEqual(user.google_calendar_account_id.calendar_token, 'my_new_token')
|
||||
self.assertEqual(user.res_users_settings_id.google_calendar_rtoken, 'my_new_rtoken')
|
||||
self.assertEqual(user.res_users_settings_id.google_calendar_token, 'my_new_token')
|
||||
self.assertNotEqual(
|
||||
user.google_calendar_account_id.calendar_token_validity,
|
||||
user.res_users_settings_id.google_calendar_token_validity,
|
||||
old_validity
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue