# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from uuid import uuid4 import requests import json import logging from odoo import api, _ from odoo.tools import exception_to_unicode from odoo.addons.google_calendar.utils.google_event import GoogleEvent from odoo.addons.google_account.models.google_service import TIMEOUT _logger = logging.getLogger(__name__) def requires_auth_token(func): def wrapped(self, *args, **kwargs): if not kwargs.get('token'): raise AttributeError("An authentication token is required") return func(self, *args, **kwargs) return wrapped class InvalidSyncToken(Exception): pass class GoogleCalendarService(): def __init__(self, google_service): self.google_service = google_service @requires_auth_token def get_events(self, sync_token=None, token=None, timeout=TIMEOUT): url = "/calendar/v3/calendars/primary/events" headers = {'Content-type': 'application/json'} params = {'access_token': token} if sync_token: params['syncToken'] = sync_token try: status, data, time = self.google_service._do_request(url, params, headers, method='GET', timeout=timeout) except requests.HTTPError as e: if e.response.status_code == 410 and 'fullSyncRequired' in str(e.response.content): raise InvalidSyncToken("Invalid sync token. Full sync required") raise e events = data.get('items', []) next_page_token = data.get('nextPageToken') while next_page_token: params = {'access_token': token, 'pageToken': next_page_token} status, data, time = self.google_service._do_request(url, params, headers, method='GET', timeout=timeout) next_page_token = data.get('nextPageToken') events += data.get('items', []) next_sync_token = data.get('nextSyncToken') default_reminders = data.get('defaultReminders') return GoogleEvent(events), next_sync_token, default_reminders @requires_auth_token def insert(self, values, token=None, timeout=TIMEOUT): url = "/calendar/v3/calendars/primary/events?sendUpdates=all" headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token} if not values.get('id'): values['id'] = uuid4().hex self.google_service._do_request(url, json.dumps(values), headers, method='POST', timeout=timeout) return values['id'] @requires_auth_token def patch(self, event_id, values, token=None, timeout=TIMEOUT): url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=all" % event_id headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token} self.google_service._do_request(url, json.dumps(values), headers, method='PUT', timeout=timeout) @requires_auth_token def delete(self, event_id, token=None, timeout=TIMEOUT): url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=all" % event_id headers = {'Content-type': 'application/json'} params = {'access_token': token} try: self.google_service._do_request(url, params, headers=headers, method='DELETE', timeout=timeout) except requests.HTTPError as e: # For some unknown reason Google can also return a 403 response when the event is already cancelled. if e.response.status_code not in (410, 403): raise e _logger.info("Google event %s was already deleted" % event_id) ################################# ## MANAGE CONNEXION TO GMAIL ## ################################# def is_authorized(self, user): return bool(user.sudo().google_calendar_rtoken) def _get_calendar_scope(self, RO=False): readonly = '.readonly' if RO else '' return 'https://www.googleapis.com/auth/calendar%s' % (readonly) def _google_authentication_url(self, from_url='http://www.odoo.com'): return self.google_service._get_authorize_uri(from_url, service='calendar', scope=self._get_calendar_scope()) def _can_authorize_google(self, user): return user.has_group('base.group_erp_manager')