From 7b82b4c2d405949603c2b366991f861d710c423a Mon Sep 17 00:00:00 2001 From: Fabien BOURGEOIS Date: Sun, 13 May 2018 09:01:01 +0200 Subject: [PATCH] [PERF]Radicale Odoo Storage : huge performance optimization for events too --- radicale_odoo_storage/__init__.py | 67 ++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/radicale_odoo_storage/__init__.py b/radicale_odoo_storage/__init__.py index d26a3ab..dfa2f84 100644 --- a/radicale_odoo_storage/__init__.py +++ b/radicale_odoo_storage/__init__.py @@ -32,7 +32,7 @@ from contextlib import contextmanager from time import strftime, strptime -from datetime import timedelta +from datetime import timedelta, datetime import pytz import vobject from odoorpc import ODOO @@ -88,8 +88,9 @@ class Collection(BaseCollection): self.is_principal = len(attributes) == 0 @classmethod - def odoo_date_to_utc(cls, date_obj): + def odoo_date_to_utc(cls, date_str): """ Transform naive Odoo date object to UTC TZ """ + date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') local_date = cls.server_timezone.localize(date_obj, is_dst=None) return local_date.astimezone(pytz.utc) @@ -155,6 +156,17 @@ class Collection(BaseCollection): def get_events_from_odoo(cls, login, path): """ Gets all events available from one Odoo login """ cls.logger.info('Get events for Odoo user %s' % login) + fields = ['allday', 'start_date', 'stop_date', 'start_datetime', + 'stop_datetime', 'write_date', 'name', 'location', + 'description', 'recurrency', 'rrule', 'categ_ids', 'alarm_ids'] + event_types = cls.odoo.execute_kw('calendar.event.type', 'search_read', + [[]], {'fields': ['name']}) + cls.event_types = {et['id']: et['name'] for et in event_types} + event_alarms = cls.odoo.execute_kw('calendar.alarm', 'search_read', + [[]], {'fields': ['type', + 'duration_minutes']}) + cls.event_alarms = {ea['id']: ea for ea in event_alarms} + cls.odoo.env.context.update({'virtual_id': False}) # Only real events if path.endswith('odoo-calendar-own'): domain = [('user_id', '=', cls.odoo.env.uid)] @@ -164,10 +176,12 @@ class Collection(BaseCollection): domain = [('partner_ids', '=', pid)] else: domain = [] - event_ids = cls.odoo.env['calendar.event'].search(domain) + events = cls.odoo.execute_kw('calendar.event', 'search_read', + [domain], {'fields': fields}) + cls.events = {e['id']: e for e in events} # WARNING: Odoo does not remove from database deleted recurrent events... # Should be fixed on Odoo side and will be fixed via 2way here too - return ['calendar.event:%s' % eid for eid in event_ids] + return ['calendar.event:%s' % eid for eid in cls.events.keys()] def sync(self, old_token=None): """ Debug purpose """ @@ -240,35 +254,41 @@ class Collection(BaseCollection): return vobject_item @classmethod - def _generate_ics_from_odoo(cls, href, event): + def _generate_ics_from_odoo(cls, href, database_id): """ Generate and return UCS object from Odoo calendar.event record """ # TODO/IMP : attendees management (not handled directly by vobject) - if event.allday: - utc_dtstart = event.start_date - utc_dtstop = event.stop_date + timedelta(days=1) + event = cls.events.get(database_id) + if event.get('allday'): + utc_dtstart = datetime.strptime(event.get('start_date'), + '%Y-%m-%d').date() + stop_date_obj = datetime.strptime(event.get('stop_date'), + '%Y-%m-%d').date() + utc_dtstop = stop_date_obj + timedelta(days=1) else: - utc_dtstart = cls.odoo_date_to_utc(event.start_datetime) - utc_dtstop = cls.odoo_date_to_utc(event.stop_datetime) - last_modified = str(cls.odoo_date_to_utc(event.write_date)) + utc_dtstart = cls.odoo_date_to_utc(event.get('start_datetime')) + utc_dtstop = cls.odoo_date_to_utc(event.get('stop_datetime')) + last_modified = str(cls.odoo_date_to_utc(event.get('write_date'))) cal = vobject.iCalendar() cal.add('vevent') - cal.vevent.add('summary').value = event.name - cal.vevent.add('location').value = event.location or '' - cal.vevent.add('description').value = event.description or '' + cal.vevent.add('summary').value = event.get('name') + cal.vevent.add('location').value = event.get('location') or '' + cal.vevent.add('description').value = event.get('description') or '' cal.vevent.add('dtstart').value = utc_dtstart cal.vevent.add('dtend').value = utc_dtstop # cal.vevent.add('duration').value = event.duration - if event.categ_ids: - categs = [categ.name for categ in event.categ_ids] + if event.get('categ_ids'): + categs = [cls.event_types.get(etid) for etid in event.get('categ_ids')] cal.vevent.add('categories').value = categs - if event.alarm_ids: - for alarm in event.alarm_ids: + if event.get('alarm_ids'): + for alarm_id in event.get('alarm_ids'): + alarm = cls.event_alarms.get(alarm_id) valarm = cal.vevent.add('valarm') - action = 'DISPLAY' if alarm.type == 'notification' else 'EMAIL' + action = 'DISPLAY' if alarm.get('type') == 'notification' else 'EMAIL' valarm.add('action').value = action - valarm.add('trigger').value = timedelta(minutes=-alarm.duration_minutes) - if event.recurrency: - cal.vevent.add('rrule').value = event.rrule + valarm.add('trigger').value = timedelta( + minutes=-alarm.get('duration_minutes')) + if event.get('recurrency'): + cal.vevent.add('rrule').value = event.get('rrule') cal.vevent.add('uid').value = href cal.vevent.add('rev').value = last_modified cal.add('rev').value = last_modified @@ -294,8 +314,7 @@ class Collection(BaseCollection): vobject_item = self._generate_vcard_from_odoo(database_id) return self._get_item_from_vobject(href, vobject_item) elif model == 'calendar.event': - record = self.odoo.env[model].browse([database_id]) - vobject_item = self._generate_ics_from_odoo(href, record) + vobject_item = self._generate_ics_from_odoo(href, database_id) return self._get_item_from_vobject(href, vobject_item) else: raise NotImplementedError