[IMP] google_calendar: add single event synchronization

Purpose
=======
Add the possibility to only synchronize one specific event of
a user calendar instead of syncing the whole calendar.

Specification
=============
In certain cases, we do not want to synchronize the whole user
calendar with all the events and recurrences but only a specific
event. For example, in appointment, to retrieve the generated
google meet url of a specified event.

To perform the single event synchronization a synchronization
token is needed, meaning we cannot do a single event
synchronization prior to a full calendar synchronization as it
is the full sync which generates the temporary sync token.

To prevent the need of doing a full sync before a single event sync,
the permanent synchronization token is been used instead of
the temporary one when performing a single event synchronization.

Task-3285601

Part-of: odoo/odoo#133921
This commit is contained in:
amdi-odoo
2023-09-22 11:55:51 +00:00
parent af0d1b565c
commit a3eed99161
2 changed files with 55 additions and 18 deletions
+47 -17
View File
@@ -53,24 +53,10 @@ class User(models.Model):
def _sync_google_calendar(self, calendar_service: GoogleCalendarService):
self.ensure_one()
if self._get_google_sync_status() != "sync_active":
results = self._sync_request(calendar_service)
if not results or not results.get('events'):
return False
# don't attempt to sync when another sync is already in progress, as we wouldn't be
# able to commit the transaction anyway (row is locked)
self.env.cr.execute("""SELECT id FROM res_users WHERE id = %s FOR NO KEY UPDATE SKIP LOCKED""", [self.id])
if not self.env.cr.rowcount:
_logger.info("skipping calendar sync, locked user %s", self.login)
return False
full_sync = not bool(self.google_calendar_sync_token)
with google_calendar_token(self) as token:
try:
events, next_sync_token, default_reminders = calendar_service.get_events(self.google_calendar_account_id.calendar_sync_token, token=token)
except InvalidSyncToken:
events, next_sync_token, default_reminders = calendar_service.get_events(token=token)
full_sync = True
self.google_calendar_account_id.calendar_sync_token = next_sync_token
events, default_reminders, full_sync = results.values()
# Google -> Odoo
send_updates = not full_sync
events.clear_type_ambiguity(self.env)
@@ -89,6 +75,50 @@ class User(models.Model):
return bool(events | synced_events) or bool(recurrences | synced_recurrences)
def _sync_single_event(self, calendar_service: GoogleCalendarService, odoo_event, event_id):
self.ensure_one()
results = self._sync_request(calendar_service, event_id)
if not results or not results.get('events'):
return False
event, default_reminders, full_sync = results.values()
# Google -> Odoo
send_updates = not full_sync
event.clear_type_ambiguity(self.env)
synced_events = self.env['calendar.event']._sync_google2odoo(event, default_reminders=default_reminders)
# Odoo -> Google
odoo_event.with_context(send_updates=send_updates)._sync_odoo2google(calendar_service)
return bool(odoo_event | synced_events)
def _sync_request(self, calendar_service, event_id=None):
if self._get_google_sync_status() != "sync_active":
return False
# don't attempt to sync when another sync is already in progress, as we wouldn't be
# able to commit the transaction anyway (row is locked)
self.env.cr.execute("""SELECT id FROM res_users WHERE id = %s FOR NO KEY UPDATE SKIP LOCKED""", [self.id])
if not self.env.cr.rowcount:
_logger.info("skipping calendar sync, locked user %s", self.login)
return False
full_sync = not bool(self.google_calendar_sync_token)
with google_calendar_token(self) as token:
try:
if not event_id:
events, next_sync_token, default_reminders = calendar_service.get_events(self.google_calendar_account_id.calendar_sync_token, token=token)
else:
# We force the sync_token parameter to avoid doing a full sync.
# Other events are fetched when the calendar view is displayed.
events, next_sync_token, default_reminders = calendar_service.get_events(sync_token=token, token=token, event_id=event_id)
except InvalidSyncToken:
events, next_sync_token, default_reminders = calendar_service.get_events(token=token)
full_sync = True
if next_sync_token:
self.google_calendar_account_id.calendar_sync_token = next_sync_token
return {
'events': events,
'default_reminders': default_reminders,
'full_sync': full_sync,
}
@api.model
def _sync_all_google_calendar(self):
""" Cron job """
@@ -29,8 +29,10 @@ class GoogleCalendarService():
self.google_service = google_service
@requires_auth_token
def get_events(self, sync_token=None, token=None, timeout=TIMEOUT):
def get_events(self, sync_token=None, token=None, event_id=None, timeout=TIMEOUT):
url = "/calendar/v3/calendars/primary/events"
if event_id:
url += f"/{event_id}"
headers = {'Content-type': 'application/json'}
params = {'access_token': token}
if sync_token:
@@ -51,6 +53,11 @@ class GoogleCalendarService():
raise InvalidSyncToken("Invalid sync token. Full sync required")
raise e
if event_id:
next_sync_token = None
default_reminders = ()
return GoogleEvent([data]), next_sync_token, default_reminders
events = data.get('items', [])
next_page_token = data.get('nextPageToken')
while next_page_token: