You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

150 lines
4.5 KiB

# Copyright 2018 Therp BV <https://therp.nl>
# Copyright 2019-2020 initOS GmbH <https://initos.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import base64
import os
import time
from odoo.http import request
try:
from radicale.storage import BaseCollection, BaseStorage
from radicale.item import Item, get_etag
from radicale import types
except ImportError:
BaseCollection = None
Item = None
get_etag = None
class BytesPretendingToBeString(bytes):
# radicale expects a string as file content, so we provide the str
# functions needed
def encode(self, encoding):
return self
class FileItem(Item):
"""this item tricks radicalev into serving a plain file"""
@property
def name(self):
return 'VCARD'
def serialize(self):
return BytesPretendingToBeString(base64.b64decode(self.item.datas))
@property
def etag(self):
return get_etag(self.item.datas.decode('ascii'))
class Storage(BaseStorage):
@classmethod
@types.contextmanager
def acquire_lock(cls, mode, user=None):
"""We have a database for that"""
yield
@classmethod
def discover(cls, path, depth=None):
depth = int(depth or "0")
components = cls._split_path(path)
collection = Collection(path)
collection.logger = collection.collection.get_logger()
if len(components) > 2:
# TODO: this probably better should happen in some dav.collection
# function
if collection.collection.dav_type == 'files' and depth:
for href in collection.list():
yield collection.get(href)
return
yield collection.get(path)
return
yield collection
if depth and len(components) == 1:
for collection in request.env['dav.collection'].search([]):
yield cls('/'.join(components + ['/%d' % collection.id]))
if depth and len(components) == 2:
for href in collection.list():
yield collection.get(href)
@classmethod
def _split_path(cls, path):
return list(filter(
None, os.path.normpath(path or '').strip('/').split('/')
))
@classmethod
def create_collection(cls, href, collection=None, props=None):
return Collection(href)
class Collection(BaseCollection):
@classmethod
def _split_path(cls, path):
return list(filter(
None, os.path.normpath(path or '').strip('/').split('/')
))
@property
def env(self):
return request.env
@property
def last_modified(self):
return self._odoo_to_http_datetime(self.collection.create_date)
@property
def path(self):
return '/'.join(self.path_components) or '/'
def __init__(self, path):
self.path_components = self._split_path(path)
self._path = '/'.join(self.path_components) or '/'
self.collection = self.env['dav.collection']
if len(self.path_components) >= 2 and str(
self.path_components[1]
).isdigit():
self.collection = self.env['dav.collection'].browse(int(
self.path_components[1]
))
def _odoo_to_http_datetime(self, value):
return time.strftime(
'%a, %d %b %Y %H:%M:%S GMT',
value.timetuple(),
)
def get_meta(self, key=None):
if key is None:
return {}
elif key == 'tag':
return self.collection.tag
elif key == 'D:displayname':
return self.collection.display_name
elif key == 'C:supported-calendar-component-set':
return 'VTODO,VEVENT,VJOURNAL'
elif key == 'C:calendar-home-set':
return None
elif key == 'D:principal-URL':
return None
elif key == 'ICAL:calendar-color':
# TODO: set in dav.collection
return '#48c9f4'
elif key == 'C:calendar-description':
return self.collection.name
self.logger.warning('unsupported metadata %s', key)
def get_multi(self, hrefs):
return [self.collection.dav_get(self, href) for href in hrefs]
def upload(self, href, vobject_item):
return self.collection.dav_upload(self, href, vobject_item)
def delete(self, href):
return self.collection.dav_delete(self, self._split_path(href))
def get_all(self):
return self.collection.dav_list(self, self.path_components)