[ADD][WIP]Radicale Odoo Storage : add calendar unique events display

This commit is contained in:
Fabien BOURGEOIS 2018-05-10 17:31:04 +02:00
parent b61be41911
commit 3350d83d94

View File

@ -18,16 +18,18 @@
""" Odoo Radicale Storage Plugin """ """ Odoo Radicale Storage Plugin """
# # PLAN # # PLAN
# 1. Implement readonly from Odoo only # 1. OK : Implement readonly from Odoo only
# 2. Implement contacts first (and so vcf) # 2. OK : Implement contacts first (and so vcf)
# 3. Implement unique events (.ics) # 3. OK : Implement unique events (.ics) and timezone
# 4. Implement recurrent events # 4. Implement notifications for events
# 5. Begin write (two way) for contacts # 5. Implement recurrent events
# 5. Begin write (two way) for calendar # 6. Begin write (two way) for contacts
# 7. Begin write (two way) for calendar
from contextlib import contextmanager from contextlib import contextmanager
from time import strftime, strptime from time import strftime, strptime
import pytz
import vobject import vobject
from odoorpc import ODOO from odoorpc import ODOO
from odoorpc.error import RPCError from odoorpc.error import RPCError
@ -47,8 +49,10 @@ class Collection(BaseCollection):
if not self.__class__.odoo: if not self.__class__.odoo:
self.logger.error('No auth Odoo found...') self.logger.error('No auth Odoo found...')
raise RuntimeError('No auth Odoo found') raise RuntimeError('No auth Odoo found')
self.__class__.odoo_connect() # self.__class__.odoo_connect()
# self.odoo_init() # self.odoo_init()
odoo_timezone = self.configuration.get('storage', 'odoo_timezone')
self.__class__.server_timezone = pytz.timezone(odoo_timezone)
attributes = path.strip('/').split('/') attributes = path.strip('/').split('/')
self.tag = None self.tag = None
@ -118,6 +122,11 @@ class Collection(BaseCollection):
self.create_collection(calendar_path, props=props) self.create_collection(calendar_path, props=props)
self.logger.info('Collection creation for Odoo Sync : %s' % calendar_path) self.logger.info('Collection creation for Odoo Sync : %s' % calendar_path)
@classmethod
def odoo_date_to_utc(cls, date_obj):
""" Transform naive Odoo date object to UTC TZ """
local_date = cls.server_timezone.localize(date_obj, is_dst=None)
return local_date.astimezone(pytz.utc)
@classmethod @classmethod
@contextmanager @contextmanager
@ -176,6 +185,13 @@ class Collection(BaseCollection):
partner_ids = cls.odoo.env['res.partner'].search([]) partner_ids = cls.odoo.env['res.partner'].search([])
return ['res.partner:%s' % pid for pid in partner_ids] return ['res.partner:%s' % pid for pid in partner_ids]
@classmethod
def get_events_from_odoo(cls, login):
""" Gets all events available from one Odoo login """
cls.logger.info('Get events for Odoo user %s' % login)
event_ids = cls.odoo.env['calendar.event'].search([])
return ['calendar.event:%s' % eid for eid in event_ids]
def sync(self, old_token=None): def sync(self, old_token=None):
""" Debug purpose """ """ Debug purpose """
token, ilist = super(Collection, self).sync(old_token) token, ilist = super(Collection, self).sync(old_token)
@ -185,13 +201,17 @@ class Collection(BaseCollection):
def list(self): def list(self):
"""List collection items.""" """List collection items."""
# TODO : get all ICS from Odoo...
self.logger.debug('List collection %s' % self.path) self.logger.debug('List collection %s' % self.path)
self.logger.debug('Collection tag %s' % self.tag) self.logger.debug('Collection tag %s' % self.tag)
if self.tag: if self.tag:
if self.tag == 'VADDRESSBOOK': if self.tag == 'VADDRESSBOOK':
for oid in self.__class__.get_contacts_from_odoo(self.owner): for oid in self.get_contacts_from_odoo(self.owner):
yield oid + self.content_suffix yield oid + self.content_suffix
elif self.tag == 'VCALENDAR':
for oid in self.get_events_from_odoo(self.owner):
yield oid + self.content_suffix
else:
raise NotImplementedError
@classmethod @classmethod
def _generate_vcard_from_odoo(cls, partner): def _generate_vcard_from_odoo(cls, partner):
@ -230,6 +250,40 @@ class Collection(BaseCollection):
vobject_item.add('rev').value = last_modified vobject_item.add('rev').value = last_modified
return vobject_item return vobject_item
@classmethod
def _generate_ics_from_odoo(cls, href, event):
""" Generate and return UCS object from Odoo calendar.event record """
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))
cal = vobject.iCalendar()
cal.add('vevent')
cal.vevent.add('summary').value = event.name
cal.vevent.add('location').value = event.location
cal.vevent.add('description').value = event.description
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]
cal.vevent.add('categories').value = categs
cal.vevent.add('uid').value = href
cal.vevent.add('rev').value = last_modified
cal.add('rev').value = last_modified
return cal
def _get_item_from_vobject(self, href, vobject_item):
""" Return Item from Vobject and HREF """
vobject_item.add('uid').value = href
tag, start, end = xmlutils.find_tag_and_time_range(vobject_item)
text = vobject_item.serialize()
etag = get_etag(text)
# uid = get_uid_from_object(vobject_item)
return Item(
self, href=href, last_modified=vobject_item.rev.value, etag=etag,
text=text, item=vobject_item, uid=href,
name=vobject_item.name, component_name=tag), (tag, start, end)
def _get_with_metadata(self, href): def _get_with_metadata(self, href):
"""Fetch a single item from Odoo database""" """Fetch a single item from Odoo database"""
model, database_id = href.split(':') model, database_id = href.split(':')
@ -240,17 +294,10 @@ class Collection(BaseCollection):
record = self.odoo.env[model].browse([database_id]) record = self.odoo.env[model].browse([database_id])
if model == 'res.partner': if model == 'res.partner':
vobject_item = self._generate_vcard_from_odoo(record) vobject_item = self._generate_vcard_from_odoo(record)
vobject_item.add('uid').value = href return self._get_item_from_vobject(href, vobject_item)
tag, start, end = xmlutils.find_tag_and_time_range(vobject_item)
text = vobject_item.serialize()
etag = get_etag(text)
# uid = get_uid_from_object(vobject_item)
return Item(
self, href=href, last_modified=vobject_item.rev.value, etag=etag,
text=text, item=vobject_item, uid=href,
name=vobject_item.name, component_name=tag), (tag, start, end)
elif model == 'calendar.event': elif model == 'calendar.event':
raise NotImplementedError vobject_item = self._generate_ics_from_odoo(href, record)
return self._get_item_from_vobject(href, vobject_item)
else: else:
raise NotImplementedError raise NotImplementedError