mirror of
https://github.com/OCA/server-backend.git
synced 2025-02-18 09:52:42 +02:00
[ADD] base_dav
This commit is contained in:
committed by
fkantelberg
parent
c1349bb4bc
commit
cb2ecfee46
5
base_dav/radicale/__init__.py
Normal file
5
base_dav/radicale/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Copyright 2018 Therp BV <https://therp.nl>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from . import auth
|
||||
from . import collection
|
||||
from . import rights
|
||||
18
base_dav/radicale/auth.py
Normal file
18
base_dav/radicale/auth.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# 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).
|
||||
from odoo.http import request
|
||||
|
||||
try:
|
||||
from radicale.auth import BaseAuth
|
||||
except ImportError:
|
||||
BaseAuth = None
|
||||
|
||||
|
||||
class Auth(BaseAuth):
|
||||
def is_authenticated2(self, login, user, password):
|
||||
env = request.env
|
||||
uid = env['res.users']._login(env.cr.dbname, user, password)
|
||||
if uid:
|
||||
request._env = env(user=uid)
|
||||
return bool(uid)
|
||||
132
base_dav/radicale/collection.py
Normal file
132
base_dav/radicale/collection.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# 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 contextlib import contextmanager
|
||||
|
||||
from odoo.http import request
|
||||
|
||||
try:
|
||||
from radicale.storage import BaseCollection, Item, get_etag
|
||||
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 Collection(BaseCollection):
|
||||
@classmethod
|
||||
def static_init(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def _split_path(cls, path):
|
||||
return list(filter(
|
||||
None, os.path.normpath(path or '').strip('/').split('/')
|
||||
))
|
||||
|
||||
@classmethod
|
||||
def discover(cls, path, depth=None):
|
||||
depth = int(depth or "0")
|
||||
components = cls._split_path(path)
|
||||
collection = cls(path)
|
||||
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
|
||||
@contextmanager
|
||||
def acquire_lock(cls, mode, user=None):
|
||||
"""We have a database for that"""
|
||||
yield
|
||||
|
||||
@property
|
||||
def env(self):
|
||||
return request.env
|
||||
|
||||
@property
|
||||
def last_modified(self):
|
||||
return self._odoo_to_http_datetime(self.collection.create_date)
|
||||
|
||||
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',
|
||||
time.strptime(value, '%Y-%m-%d %H:%M:%S'),
|
||||
)
|
||||
|
||||
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'
|
||||
self.logger.warning('unsupported metadata %s', key)
|
||||
|
||||
def get(self, href):
|
||||
return self.collection.dav_get(href)
|
||||
|
||||
def upload(self, href, vobject_item):
|
||||
return self.collection.dav_upload(href, vobject_item)
|
||||
|
||||
def delete(self, href):
|
||||
return self.collection.dav_delete(self._split_path(href))
|
||||
|
||||
def list(self):
|
||||
return self.collection.dav_list(self.path_components)
|
||||
31
base_dav/radicale/rights.py
Normal file
31
base_dav/radicale/rights.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copyright 2018 Therp BV <https://therp.nl>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from .collection import Collection
|
||||
|
||||
try:
|
||||
from radicale.rights import (
|
||||
AuthenticatedRights, OwnerWriteRights, OwnerOnlyRights,
|
||||
)
|
||||
except ImportError:
|
||||
AuthenticatedRights = OwnerOnlyRights = OwnerWriteRights = None
|
||||
|
||||
|
||||
class Rights(OwnerOnlyRights, OwnerWriteRights, AuthenticatedRights):
|
||||
def authorized(self, user, path, perm):
|
||||
if path == '/':
|
||||
return True
|
||||
|
||||
collection = Collection(path)
|
||||
if not collection.collection:
|
||||
return False
|
||||
|
||||
rights = collection.collection.sudo().rights
|
||||
cls = {
|
||||
"owner_only": OwnerOnlyRights,
|
||||
"owner_write_only": OwnerWriteRights,
|
||||
"authenticated": AuthenticatedRights,
|
||||
}.get(rights)
|
||||
if not cls:
|
||||
return False
|
||||
return cls.authorized(self, user, path, perm)
|
||||
Reference in New Issue
Block a user