[IMP][WIP]Odoo storage plugin : other implementations, tests and failures...
This commit is contained in:
parent
f23010827e
commit
94f6e12601
@ -17,12 +17,23 @@
|
|||||||
|
|
||||||
""" Odoo Radicale Storage Plugin """
|
""" Odoo Radicale Storage Plugin """
|
||||||
|
|
||||||
from json import dumps
|
# # PLAN
|
||||||
import threading
|
# 1. Implement readonly from Odoo only
|
||||||
|
# 2. Implement contacts first (and so vcf)
|
||||||
|
# 3. Implement unique events (.ics)
|
||||||
|
# 4. Implement recurrent events
|
||||||
|
# 5. Begin write (two way) for contacts
|
||||||
|
# 5. Begin write (two way) for calendar
|
||||||
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from time import strftime, strptime
|
||||||
|
import vobject
|
||||||
from odoorpc import ODOO
|
from odoorpc import ODOO
|
||||||
from odoorpc.error import RPCError
|
from odoorpc.error import RPCError
|
||||||
from radicale.storage import BaseCollection
|
from radicale import xmlutils
|
||||||
|
from radicale.storage import BaseCollection, Item, get_etag, get_uid_from_object
|
||||||
|
from radicale_odoo_auth import Auth
|
||||||
|
|
||||||
|
|
||||||
class Collection(BaseCollection):
|
class Collection(BaseCollection):
|
||||||
@ -32,7 +43,10 @@ class Collection(BaseCollection):
|
|||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
""" Init function """
|
""" Init function """
|
||||||
if not self.odoo:
|
self.__class__.odoo = Auth.odoo
|
||||||
|
if not self.__class__.odoo:
|
||||||
|
self.logger.error('No auth Odoo found...')
|
||||||
|
raise RuntimeError('No auth Odoo found')
|
||||||
self.__class__.odoo_connect()
|
self.__class__.odoo_connect()
|
||||||
# self.odoo_init()
|
# self.odoo_init()
|
||||||
|
|
||||||
@ -41,12 +55,14 @@ class Collection(BaseCollection):
|
|||||||
self.props = {}
|
self.props = {}
|
||||||
if 'odoo-contact' in attributes:
|
if 'odoo-contact' in attributes:
|
||||||
self.tag = 'VADDRESSBOOK'
|
self.tag = 'VADDRESSBOOK'
|
||||||
|
self.odoo_model = 'res.partner'
|
||||||
self.content_suffix = '.vcf'
|
self.content_suffix = '.vcf'
|
||||||
self.props.update({'tag': 'VADDRESSBOOK',
|
self.props.update({'tag': 'VADDRESSBOOK',
|
||||||
'D:displayname': 'Odoo contacts',
|
'D:displayname': 'Odoo contacts',
|
||||||
'CR:addressbook-description': 'Contacts form your Odoo account'})
|
'CR:addressbook-description': 'Contacts form your Odoo account'})
|
||||||
elif 'odoo-calendar' in attributes:
|
elif 'odoo-calendar' in attributes:
|
||||||
self.tag = 'VCALENDAR'
|
self.tag = 'VCALENDAR'
|
||||||
|
self.odoo_model = 'calendar.event'
|
||||||
self.content_suffix = '.ics'
|
self.content_suffix = '.ics'
|
||||||
self.props.update({'tag': 'VCALENDAR',
|
self.props.update({'tag': 'VCALENDAR',
|
||||||
'D:displayname': 'Odoo calendar',
|
'D:displayname': 'Odoo calendar',
|
||||||
@ -132,18 +148,116 @@ class Collection(BaseCollection):
|
|||||||
cls.logger.warning('Discover : %s (path), %s (depth), %s (cls.user), %s (attributes)' %
|
cls.logger.warning('Discover : %s (path), %s (depth), %s (cls.user), %s (attributes)' %
|
||||||
(path, depth, cls.user, attributes))
|
(path, depth, cls.user, attributes))
|
||||||
yield cls(path)
|
yield cls(path)
|
||||||
contact_path = '%s/odoo-contact' % path
|
if len(attributes) == 1: # Got all if root is needed
|
||||||
calendar_path = '%s/odoo-calendar' % path
|
contact_path = '%s/odoo-contact' % path
|
||||||
yield cls(contact_path)
|
calendar_path = '%s/odoo-calendar' % path
|
||||||
yield cls(calendar_path)
|
yield cls(contact_path)
|
||||||
|
yield cls(calendar_path)
|
||||||
|
|
||||||
def get_meta(self, key=None):
|
def get_meta(self, key=None):
|
||||||
"""Get metadata value for collection """
|
"""Get metadata value for collection """
|
||||||
if key == 'tag':
|
if key:
|
||||||
return self.tag
|
return self.props.get(key)
|
||||||
return self.props.get(key)
|
else:
|
||||||
|
return self.props
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_collection(cls, href, collection=None, props=None):
|
def create_collection(cls, href, collection=None, props=None):
|
||||||
""" Create collection implementation : only warns ATM """
|
""" Create collection implementation : only warns ATM """
|
||||||
cls.logger.error('Attemmpt to create a new collection for %s' % href)
|
cls.logger.error('Attemmpt to create a new collection for %s' % href)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_contacts_from_odoo(cls, login):
|
||||||
|
""" Gets all contacts available from one Odoo login """
|
||||||
|
cls.logger.info('Get contacts for Odoo user %s' % login)
|
||||||
|
partner_ids = cls.odoo.env['res.partner'].search([])
|
||||||
|
cls.logger.debug(partner_ids)
|
||||||
|
return ['res.partner:%s' % pid for pid in partner_ids]
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
"""List collection items."""
|
||||||
|
# TODO : get all ICS from Odoo...
|
||||||
|
self.logger.warning('List collection %s' % self.path)
|
||||||
|
self.logger.warning('Collection tag %s' % self.tag)
|
||||||
|
if self.tag:
|
||||||
|
if self.tag == 'VADDRESSBOOK':
|
||||||
|
for oid in self.__class__.get_contacts_from_odoo(self.owner):
|
||||||
|
yield oid
|
||||||
|
# for item in self.collection.list():
|
||||||
|
# yield item.uid + self.content_suffix
|
||||||
|
|
||||||
|
def _get_with_metadata(self, href):
|
||||||
|
"""Fetch a single item from Odoo database"""
|
||||||
|
model, database_id = href.split(':')
|
||||||
|
fields = ['name', 'write_date', 'comment']
|
||||||
|
data = self.odoo.execute(model, 'read', [int(database_id)], fields)[0]
|
||||||
|
self.logger.warning(data)
|
||||||
|
if model == 'res.partner':
|
||||||
|
# last_modified = strftime("%a, %d %b %Y %H:%M:%S GMT",
|
||||||
|
# strptime(data.get('write_date'), '%Y-%m-%d %H:%M:%S'))
|
||||||
|
last_modified = strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||||
|
strptime(data.get('write_date'), '%Y-%m-%d %H:%M:%S'))
|
||||||
|
self.logger.warning(last_modified)
|
||||||
|
vobject_item = vobject.vCard()
|
||||||
|
vobject_item.add('n')
|
||||||
|
vobject_item.n.value = vobject.vcard.Name(family=data.get('name'))
|
||||||
|
vobject_item.add('fn')
|
||||||
|
vobject_item.fn.value = data.get('name')
|
||||||
|
vobject_item.add('uid').value = database_id
|
||||||
|
vobject_item.add('rev').value = last_modified
|
||||||
|
self.logger.warning(vobject_item.name)
|
||||||
|
self.logger.warning([c for c in vobject_item.components()])
|
||||||
|
tag, start, end = xmlutils.find_tag_and_time_range(vobject_item)
|
||||||
|
self.logger.warning('Tag, start, end : %s %s %s' % (tag, start, end))
|
||||||
|
text = vobject_item.serialize()
|
||||||
|
etag = get_etag(text)
|
||||||
|
uid = get_uid_from_object(vobject_item)
|
||||||
|
self.logger.warning('Text, ETAG, UID : %s %s %s' % (text, etag, uid))
|
||||||
|
return Item(
|
||||||
|
self, href=href, last_modified=last_modified, etag=etag,
|
||||||
|
text=text, item=vobject_item, uid=href,
|
||||||
|
name=vobject_item.name, component_name=tag), (tag, start, end)
|
||||||
|
elif model == 'calendar.event':
|
||||||
|
raise NotImplementedError
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get(self, href, verify_href=True):
|
||||||
|
item, metadata = self._get_with_metadata(href)
|
||||||
|
self.logger.warning(item)
|
||||||
|
self.logger.warning(item.serialize())
|
||||||
|
self.logger.warning(item.name)
|
||||||
|
self.logger.warning(item.last_modified)
|
||||||
|
self.logger.warning([c for c in item.components()])
|
||||||
|
self.logger.warning(metadata)
|
||||||
|
return item
|
||||||
|
|
||||||
|
def delete(self, href=None):
|
||||||
|
""" Can not delete collection but item, yes """
|
||||||
|
self.logger.warning(href)
|
||||||
|
if href is None:
|
||||||
|
# Delete the collection
|
||||||
|
self.logger.error('Attempt to delete collection %s' % self.path)
|
||||||
|
raise ValueError('Can not delete collection')
|
||||||
|
else:
|
||||||
|
# Delete an item
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
# def serialize(self):
|
||||||
|
# """ Get the whole collection unicode """
|
||||||
|
# # TODO: CALENDAR
|
||||||
|
# self.logger.warning('From serialize : %s' % self.tag)
|
||||||
|
# if self.tag == "VADDRESSBOOK":
|
||||||
|
# self.logger.warning('HERE')
|
||||||
|
# self.logger.warning([item.serialize() for item in self.get_all()])
|
||||||
|
# return ''.join((item.serialize() for item in self.get_all()))
|
||||||
|
# return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_modified(self):
|
||||||
|
""" Return last modified """
|
||||||
|
last = self.odoo.env[self.odoo_model].search([], limit=1, order='write_date desc')
|
||||||
|
last_fields = self.odoo.execute(self.odoo_model, 'read', last, ['write_date'])[0]
|
||||||
|
self.logger.info(last_fields)
|
||||||
|
return strftime("%a, %d %b %Y %H:%M:%S GMT",
|
||||||
|
strptime(last_fields.get('write_date'), '%Y-%m-%d %H:%M:%S'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user