[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. See sub commits for more details. Task-3285601 closes odoo/odoo#133921 Related: odoo/enterprise#46688 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -14,10 +14,13 @@ class Meeting(models.Model):
|
||||
_name = 'calendar.event'
|
||||
_inherit = ['calendar.event', 'google.calendar.sync']
|
||||
|
||||
MEET_ROUTE = 'meet.google.com'
|
||||
|
||||
google_id = fields.Char(
|
||||
'Google Calendar Event Id', compute='_compute_google_id', store=True, readonly=False)
|
||||
guests_readonly = fields.Boolean(
|
||||
'Guests Event Modification Permission', default=False)
|
||||
videocall_source = fields.Selection(selection_add=[('google_meet', 'Google Meet')], ondelete={'google_meet': 'set discuss'})
|
||||
|
||||
@api.depends('recurrence_id.google_id')
|
||||
def _compute_google_id(self):
|
||||
@@ -32,6 +35,12 @@ class Meeting(models.Model):
|
||||
elif not event.google_id:
|
||||
event.google_id = False
|
||||
|
||||
@api.depends('videocall_location')
|
||||
def _compute_videocall_source(self):
|
||||
events_with_google_url = self.filtered(lambda event: self.MEET_ROUTE in (event.videocall_location or ''))
|
||||
events_with_google_url.videocall_source = 'google_meet'
|
||||
super(Meeting, self - events_with_google_url)._compute_videocall_source()
|
||||
|
||||
@api.model
|
||||
def _get_google_synced_fields(self):
|
||||
return {'name', 'description', 'allday', 'start', 'date_end', 'stop',
|
||||
|
||||
@@ -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 """
|
||||
@@ -103,6 +133,12 @@ class User(models.Model):
|
||||
_logger.exception("[%s] Calendar Synchro - Exception : %s!", user, exception_to_unicode(e))
|
||||
self.env.cr.rollback()
|
||||
|
||||
def is_google_calendar_synced(self):
|
||||
""" True if Google Calendar settings are filled (Client ID / Secret) and user calendar is synced
|
||||
meaning we can make API calls, false otherwise."""
|
||||
self.ensure_one()
|
||||
return self.google_calendar_token and self._get_google_sync_status() == 'sync_active'
|
||||
|
||||
def stop_google_synchronization(self):
|
||||
self.ensure_one()
|
||||
self.google_synchronization_stopped = True
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user