* Remove relation field actions:
- delete_all
- unlink_all
- set
* Rename relation field action unlink into remove
issue3457
review2271002
831 lines
32 KiB
Python
831 lines
32 KiB
Python
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
#this repository contains the full copyright notices and license terms.
|
|
import os
|
|
import time
|
|
import urllib
|
|
import urlparse
|
|
import socket
|
|
import encodings
|
|
import uuid
|
|
import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
from sql.functions import Extract
|
|
from sql.conditionals import Coalesce
|
|
|
|
from trytond.model import ModelView, ModelSQL, fields
|
|
from trytond.tools import reduce_ids, safe_eval
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool
|
|
from trytond.config import CONFIG
|
|
from trytond.pyson import Eval
|
|
|
|
__all__ = [
|
|
'Collection', 'Share', 'Attachment',
|
|
]
|
|
|
|
|
|
def get_webdav_url():
|
|
if CONFIG['ssl_webdav']:
|
|
protocol = 'https'
|
|
else:
|
|
protocol = 'http'
|
|
hostname = (CONFIG['hostname_webdav']
|
|
or unicode(socket.getfqdn(), 'utf8'))
|
|
hostname = '.'.join(encodings.idna.ToASCII(part) for part in
|
|
hostname.split('.'))
|
|
return urlparse.urlunsplit((protocol, hostname,
|
|
urllib.quote(
|
|
Transaction().cursor.database_name.encode('utf-8') + '/'),
|
|
None, None))
|
|
|
|
|
|
class Collection(ModelSQL, ModelView):
|
|
"Collection"
|
|
__name__ = "webdav.collection"
|
|
name = fields.Char('Name', required=True, select=True)
|
|
parent = fields.Many2One('webdav.collection', 'Parent',
|
|
ondelete='RESTRICT', domain=[('model', '=', None)])
|
|
childs = fields.One2Many('webdav.collection', 'parent', 'Children')
|
|
model = fields.Many2One('ir.model', 'Model')
|
|
domain = fields.Char('Domain')
|
|
complete_name = fields.Function(fields.Char('Complete Name'),
|
|
'get_rec_name')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Collection, cls).__setup__()
|
|
cls._sql_constraints += [
|
|
('name_parent_uniq', 'UNIQUE (name, parent)',
|
|
'The collection name must be unique inside a collection!'),
|
|
]
|
|
cls._error_messages.update({
|
|
'collection_file_name': ('You can not create a collection '
|
|
'named "%(parent)s" in collection "%(child)s" because '
|
|
'there is already a file with that name.'),
|
|
})
|
|
cls.ext2mime = {
|
|
'.png': 'image/png',
|
|
'.odt': 'application/vnd.oasis.opendocument.text',
|
|
'.pdf': 'application/pdf',
|
|
}
|
|
|
|
@classmethod
|
|
def order_complet_name(cls, tables):
|
|
return cls.name.convert_order('name', tables, cls)
|
|
|
|
@staticmethod
|
|
def default_domain():
|
|
return '[]'
|
|
|
|
def get_rec_name(self, name):
|
|
if self.parent:
|
|
return self.parent.rec_name + '/' + self.name
|
|
else:
|
|
return self.name
|
|
|
|
@classmethod
|
|
def validate(cls, collections):
|
|
super(Collection, cls).validate(collections)
|
|
cls.check_recursion(collections, rec_name='name')
|
|
cls.check_attachment(collections)
|
|
|
|
@classmethod
|
|
def check_attachment(cls, collections):
|
|
pool = Pool()
|
|
Attachment = pool.get('ir.attachment')
|
|
for collection in collections:
|
|
if collection.parent:
|
|
attachments = Attachment.search([
|
|
('resource', '=', '%s,%s' %
|
|
(cls.__name__, collection.parent.id)),
|
|
])
|
|
for attachment in attachments:
|
|
if attachment.name == collection.name:
|
|
cls.raise_user_error('collection_file_name', {
|
|
'parent': collection.parent.rec_name,
|
|
'child': collection.rec_name,
|
|
})
|
|
|
|
@classmethod
|
|
def _uri2object(cls, uri, object_name=__name__, object_id=None,
|
|
cache=None):
|
|
pool = Pool()
|
|
Attachment = pool.get('ir.attachment')
|
|
Report = pool.get('ir.action.report')
|
|
cache_uri = uri
|
|
|
|
if cache is not None:
|
|
cache.setdefault('_uri2object', {})
|
|
if cache_uri in cache['_uri2object']:
|
|
return cache['_uri2object'][cache_uri]
|
|
|
|
if not uri:
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (cls.__name__, None)
|
|
return cls.__name__, None
|
|
name, uri = (uri.split('/', 1) + [None])[0:2]
|
|
if object_name == cls.__name__:
|
|
collection_ids = None
|
|
if cache is not None:
|
|
cache.setdefault('_parent2collection_ids', {})
|
|
if object_id in cache['_parent2collection_ids']:
|
|
collection_ids = cache['_parent2collection_ids'][
|
|
object_id].get(name, [])
|
|
if collection_ids is None:
|
|
collections = cls.search([
|
|
('parent', '=', object_id),
|
|
])
|
|
collection_ids = []
|
|
if cache is not None:
|
|
cache['_parent2collection_ids'].setdefault(object_id, {})
|
|
for collection in collections:
|
|
if cache is not None:
|
|
cache['_parent2collection_ids'][object_id]\
|
|
.setdefault(collection.name, [])
|
|
cache['_parent2collection_ids'][object_id][
|
|
collection.name].append(collection.id)
|
|
cache.setdefault('_collection_name', {})
|
|
if collection.model and uri:
|
|
cache['_collection_name'][collection.id] = \
|
|
collection.model.model
|
|
else:
|
|
cache['_collection_name'][collection.id] = \
|
|
cls.__name__
|
|
if collection.name == name:
|
|
collection_ids.append(collection.id)
|
|
if collection_ids:
|
|
object_id = collection_ids[0]
|
|
object_name2 = None
|
|
if cache is not None:
|
|
cache.setdefault('_collection_name', {})
|
|
if object_id in cache['_collection_name']:
|
|
object_name2 = cache['_collection_name'][object_id]
|
|
if object_name2 is None:
|
|
collection = cls(object_id)
|
|
if collection.model and uri:
|
|
object_name = collection.model.model
|
|
if cache is not None:
|
|
cache['_collection_name'][object_id] = object_name
|
|
else:
|
|
object_name = object_name2
|
|
else:
|
|
if uri:
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (None, 0)
|
|
return None, 0
|
|
|
|
attachment_ids = None
|
|
if cache is not None:
|
|
cache.setdefault('_model&id2attachment_ids', {})
|
|
if (object_name, object_id) in \
|
|
cache['_model&id2attachment_ids']:
|
|
attachment_ids = cache['_model&id2attachment_ids'][
|
|
(object_name, object_id)].get(name, [])
|
|
attachment_id = None
|
|
if attachment_ids is None:
|
|
attachments = Attachment.search([
|
|
('resource', '=', '%s,%s' % (object_name, object_id)),
|
|
])
|
|
key = (object_name, object_id)
|
|
attachment_ids = []
|
|
if cache is not None:
|
|
cache['_model&id2attachment_ids'].setdefault(key, {})
|
|
for attachment in attachments:
|
|
if cache is not None:
|
|
cache.setdefault('_model&id&name2attachment_ids',
|
|
{})
|
|
cache['_model&id&name2attachment_ids'].setdefault(
|
|
key, {})
|
|
cache['_model&id&name2attachment_ids'][key]\
|
|
.setdefault(attachment.name, [])
|
|
cache['_model&id&name2attachment_ids'][key][
|
|
attachment.name].append(attachment.id)
|
|
if attachment.name == name:
|
|
attachment_id = attachment.id
|
|
else:
|
|
key = (object_name, object_id)
|
|
cache.setdefault('_model&id&name2attachment_ids', {})
|
|
cache['_model&id&name2attachment_ids'].setdefault(key, {})
|
|
attachment_id = cache['_model&id&name2attachment_ids'][
|
|
key].get(name, [None])[0]
|
|
if attachment_id:
|
|
object_name = 'ir.attachment'
|
|
object_id = attachment_id
|
|
else:
|
|
object_name = None
|
|
object_id = None
|
|
else:
|
|
splitted_name = name.rsplit('-', 1)
|
|
if len(splitted_name) != 2:
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (object_name, 0)
|
|
return object_name, 0
|
|
object_id = int(splitted_name[1].strip())
|
|
if uri:
|
|
if '/' in uri:
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (None, 0)
|
|
return None, 0
|
|
reports = Report.search([
|
|
('model', '=', object_name),
|
|
])
|
|
for report in reports:
|
|
report_name = (report.name + '-' + str(report.id)
|
|
+ '.' + report.extension)
|
|
if uri == report_name:
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = \
|
|
('ir.action.report', object_id)
|
|
return 'ir.action.report', object_id
|
|
name = uri
|
|
attachment_ids = None
|
|
if cache is not None:
|
|
cache.setdefault('_model&id2attachment_ids', {})
|
|
if (object_name, object_id) in \
|
|
cache['_model&id2attachment_ids']:
|
|
attachment_ids = cache['_model&id2attachment_ids'][
|
|
(object_name, object_id)].get(name, [])
|
|
if attachment_ids is None:
|
|
attachments = Attachment.search([
|
|
('resource', '=', '%s,%s' % (object_name, object_id)),
|
|
])
|
|
key = (object_name, object_id)
|
|
attachment_ids = []
|
|
if cache is not None:
|
|
cache['_model&id2attachment_ids'].setdefault(key, {})
|
|
for attachment in attachments:
|
|
if cache is not None:
|
|
cache['_model&id2attachment_ids'][key]\
|
|
.setdefault(attachment.name, [])
|
|
cache['_model&id2attachment_ids'][key][
|
|
attachment.name].append(attachment.id)
|
|
if attachment.name == name:
|
|
attachment_ids.append(attachment.id)
|
|
if attachment_ids:
|
|
object_name = 'ir.attachment'
|
|
object_id = attachment_ids[0]
|
|
else:
|
|
object_name = None
|
|
object_id = None
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (object_name, object_id)
|
|
return object_name, object_id
|
|
if uri:
|
|
res = cls._uri2object(uri, object_name, object_id, cache=cache)
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = res
|
|
return res
|
|
if cache is not None:
|
|
cache['_uri2object'][cache_uri] = (object_name, object_id)
|
|
return object_name, object_id
|
|
|
|
@classmethod
|
|
def get_childs(cls, uri, filter=None, cache=None):
|
|
pool = Pool()
|
|
Report = pool.get('ir.action.report')
|
|
res = []
|
|
if filter:
|
|
return []
|
|
if not uri:
|
|
collections = cls.search([
|
|
('parent', '=', None),
|
|
])
|
|
for collection in collections:
|
|
if '/' in collection.name:
|
|
continue
|
|
res.append(collection.name)
|
|
if cache is not None:
|
|
cache.setdefault(cls.__name__, {})
|
|
cache[cls.__name__][collection.id] = {}
|
|
return res
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name == cls.__name__ and object_id:
|
|
collection = cls(object_id)
|
|
if collection.model:
|
|
Model = pool.get(collection.model.model)
|
|
if not Model:
|
|
return res
|
|
models = Model.search(
|
|
safe_eval(collection.domain or "[]"))
|
|
for child in models:
|
|
if '/' in child.rec_name:
|
|
continue
|
|
res.append(child.rec_name + '-' + str(child.id))
|
|
if cache is not None:
|
|
cache.setdefault(Model.__name__, {})
|
|
cache[Model.__name__][child.id] = {}
|
|
return res
|
|
else:
|
|
for child in collection.childs:
|
|
if '/' in child.name:
|
|
continue
|
|
res.append(child.name)
|
|
if cache is not None:
|
|
cache.setdefault(cls.__name__, {})
|
|
cache[cls.__name__][child.id] = {}
|
|
if object_name not in ('ir.attachment', 'ir.action.report'):
|
|
reports = Report.search([
|
|
('model', '=', object_name),
|
|
])
|
|
for report in reports:
|
|
report_name = (report.name + '-' + str(report.id)
|
|
+ '.' + report.extension)
|
|
if '/' in report_name:
|
|
continue
|
|
res.append(report_name)
|
|
if cache is not None:
|
|
cache.setdefault(Report.__name__, {})
|
|
cache[Report.__name__][report.id] = {}
|
|
|
|
Attachment = pool.get('ir.attachment')
|
|
attachments = Attachment.search([
|
|
('resource', '=', '%s,%s' % (object_name, object_id)),
|
|
])
|
|
for attachment in attachments:
|
|
if attachment.name and not attachment.link:
|
|
if '/' in attachment.name:
|
|
continue
|
|
res.append(attachment.name)
|
|
if cache is not None:
|
|
cache.setdefault(Attachment.__name__, {})
|
|
cache[Attachment.__name__][attachment.id] = {}
|
|
return res
|
|
|
|
@classmethod
|
|
def get_resourcetype(cls, uri, cache=None):
|
|
from pywebdav.lib.constants import COLLECTION, OBJECT
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name in ('ir.attachment', 'ir.action.report'):
|
|
return OBJECT
|
|
return COLLECTION
|
|
|
|
@classmethod
|
|
def get_displayname(cls, uri, cache=None):
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
Model = Pool().get(object_name)
|
|
return Model(object_id).rec_name
|
|
|
|
@classmethod
|
|
def get_contentlength(cls, uri, cache=None):
|
|
pool = Pool()
|
|
Attachment = pool.get('ir.attachment')
|
|
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name == 'ir.attachment':
|
|
|
|
if cache is not None:
|
|
cache.setdefault('ir.attachment', {})
|
|
ids = cache['ir.attachment'].keys()
|
|
if object_id not in ids:
|
|
ids.append(object_id)
|
|
elif 'contentlength' in cache['ir.attachment'][object_id]:
|
|
return cache['ir.attachment'][object_id]['contentlength']
|
|
else:
|
|
ids = [object_id]
|
|
|
|
attachments = Attachment.browse(ids)
|
|
|
|
res = '0'
|
|
for attachment in attachments:
|
|
size = '0'
|
|
try:
|
|
if attachment.data_size:
|
|
size = str(attachment.data_size)
|
|
except Exception:
|
|
pass
|
|
if attachment.id == object_id:
|
|
res = size
|
|
if cache is not None:
|
|
cache['ir.attachment'].setdefault(attachment.id, {})
|
|
cache['ir.attachment'][attachment.id]['contentlength'] = \
|
|
size
|
|
return res
|
|
return '0'
|
|
|
|
@classmethod
|
|
def get_contenttype(cls, uri, cache=None):
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name in ('ir.attachment', 'ir.action.report'):
|
|
ext = os.path.splitext(uri)[1]
|
|
if not ext:
|
|
return "application/octet-stream"
|
|
return cls.ext2mime.get(ext, 'application/octet-stream')
|
|
return "application/octet-stream"
|
|
|
|
@classmethod
|
|
def get_creationdate(cls, uri, cache=None):
|
|
pool = Pool()
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name == 'ir.attachment':
|
|
Model = pool.get(object_name)
|
|
if object_id:
|
|
if cache is not None:
|
|
cache.setdefault(Model.__name__, {})
|
|
ids = cache[Model.__name__].keys()
|
|
if object_id not in ids:
|
|
ids.append(object_id)
|
|
elif 'creationdate' in cache[Model.__name__][object_id]:
|
|
return cache[Model.__name__][object_id][
|
|
'creationdate']
|
|
else:
|
|
ids = [object_id]
|
|
res = None
|
|
cursor = Transaction().cursor
|
|
table = Model.__table__()
|
|
for i in range(0, len(ids), cursor.IN_MAX):
|
|
sub_ids = ids[i:i + cursor.IN_MAX]
|
|
red_sql = reduce_ids(table.id, sub_ids)
|
|
cursor.execute(*table.select(table.id,
|
|
Extract('EPOCH', table.create_date),
|
|
where=red_sql))
|
|
for object_id2, date in cursor.fetchall():
|
|
if object_id2 == object_id:
|
|
res = date
|
|
if cache is not None:
|
|
cache[Model.__name__].setdefault(object_id2, {})
|
|
cache[Model.__name__][object_id2][
|
|
'creationdate'] = date
|
|
if res is not None:
|
|
return res
|
|
return time.time()
|
|
|
|
@classmethod
|
|
def get_lastmodified(cls, uri, cache=None):
|
|
pool = Pool()
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name == 'ir.attachment':
|
|
Model = pool.get(object_name)
|
|
if object_id:
|
|
if cache is not None:
|
|
cache.setdefault(Model.__name__, {})
|
|
ids = cache[Model.__name__].keys()
|
|
if object_id not in ids:
|
|
ids.append(object_id)
|
|
elif 'lastmodified' in cache[Model.__name__][object_id]:
|
|
return cache[Model.__name__][object_id][
|
|
'lastmodified']
|
|
else:
|
|
ids = [object_id]
|
|
res = None
|
|
cursor = Transaction().cursor
|
|
table = Model.__table__()
|
|
for i in range(0, len(ids), cursor.IN_MAX):
|
|
sub_ids = ids[i:i + cursor.IN_MAX]
|
|
red_sql = reduce_ids(table.id, sub_ids)
|
|
cursor.execute(*table.select(table.id,
|
|
Extract('EPOCH',
|
|
Coalesce(table.write_date, table.create_date)),
|
|
where=red_sql))
|
|
for object_id2, date in cursor.fetchall():
|
|
if object_id2 == object_id:
|
|
res = date
|
|
if cache is not None:
|
|
cache[Model.__name__].setdefault(object_id2, {})
|
|
cache[Model.__name__][object_id2][
|
|
'lastmodified'] = date
|
|
if res is not None:
|
|
return res
|
|
return time.time()
|
|
|
|
@classmethod
|
|
def get_data(cls, uri, cache=None):
|
|
from pywebdav.lib.errors import DAV_NotFound
|
|
pool = Pool()
|
|
Attachment = pool.get('ir.attachment')
|
|
Report = pool.get('ir.action.report')
|
|
|
|
if uri:
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
|
|
if object_name == 'ir.attachment' and object_id:
|
|
if cache is not None:
|
|
cache.setdefault('ir.attachment', {})
|
|
ids = cache['ir.attachment'].keys()
|
|
if object_id not in ids:
|
|
ids.append(object_id)
|
|
elif 'data' in cache['ir.attachment'][object_id]:
|
|
res = cache['ir.attachment'][object_id]['data']
|
|
if res == DAV_NotFound:
|
|
raise DAV_NotFound
|
|
return res
|
|
else:
|
|
ids = [object_id]
|
|
attachments = Attachment.browse(ids)
|
|
|
|
res = DAV_NotFound
|
|
for attachment in attachments:
|
|
data = DAV_NotFound
|
|
try:
|
|
if attachment.data is not None:
|
|
data = str(attachment.data)
|
|
except Exception:
|
|
pass
|
|
if attachment.id == object_id:
|
|
res = data
|
|
if cache is not None:
|
|
cache['ir.attachment'].setdefault(attachment.id, {})
|
|
cache['ir.attachment'][attachment.id]['data'] = data
|
|
if res == DAV_NotFound:
|
|
raise DAV_NotFound
|
|
return res
|
|
|
|
if object_name == 'ir.action.report' and object_id:
|
|
report_id = int(uri.rsplit('/', 1)[-1].rsplit('-',
|
|
1)[-1].rsplit('.', 1)[0])
|
|
report = Report(report_id)
|
|
if report.report_name:
|
|
Report = pool.get(report.report_name,
|
|
type='report')
|
|
val = Report.execute([object_id],
|
|
{'id': object_id, 'ids': [object_id]})
|
|
return val[1]
|
|
raise DAV_NotFound
|
|
|
|
@classmethod
|
|
def put(cls, uri, data, content_type, cache=None):
|
|
from pywebdav.lib.errors import DAV_Forbidden
|
|
from pywebdav.lib.utils import get_uriparentpath, get_urifilename
|
|
object_name, object_id = cls._uri2object(get_uriparentpath(uri),
|
|
cache=cache)
|
|
if not object_name \
|
|
or object_name == 'ir.attachment' \
|
|
or not object_id:
|
|
raise DAV_Forbidden
|
|
pool = Pool()
|
|
Attachment = pool.get('ir.attachment')
|
|
object_name2, object_id2 = cls._uri2object(uri, cache=cache)
|
|
if not object_id2:
|
|
name = get_urifilename(uri)
|
|
try:
|
|
Attachment.create([{
|
|
'name': name,
|
|
'data': data,
|
|
'resource': '%s,%s' % (object_name, object_id),
|
|
}])
|
|
except Exception:
|
|
raise DAV_Forbidden
|
|
else:
|
|
try:
|
|
Attachment.write(object_id2, {
|
|
'data': data,
|
|
})
|
|
except Exception:
|
|
raise DAV_Forbidden
|
|
return
|
|
|
|
@classmethod
|
|
def mkcol(cls, uri, cache=None):
|
|
from pywebdav.lib.errors import DAV_Forbidden
|
|
from pywebdav.lib.utils import get_uriparentpath, get_urifilename
|
|
if uri[-1:] == '/':
|
|
uri = uri[:-1]
|
|
object_name, object_id = cls._uri2object(get_uriparentpath(uri),
|
|
cache=cache)
|
|
if object_name != 'webdav.collection':
|
|
raise DAV_Forbidden
|
|
name = get_urifilename(uri)
|
|
try:
|
|
cls.create([{
|
|
'name': name,
|
|
'parent': object_id,
|
|
}])
|
|
except Exception:
|
|
raise DAV_Forbidden
|
|
return 201
|
|
|
|
@classmethod
|
|
def rmcol(cls, uri, cache=None):
|
|
from pywebdav.lib.errors import DAV_Forbidden
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name != 'webdav.collection' \
|
|
or not object_id:
|
|
raise DAV_Forbidden
|
|
try:
|
|
cls.delete([cls(object_id)])
|
|
except Exception:
|
|
raise DAV_Forbidden
|
|
return 200
|
|
|
|
@classmethod
|
|
def rm(cls, uri, cache=None):
|
|
from pywebdav.lib.errors import DAV_Forbidden
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if not object_name:
|
|
raise DAV_Forbidden
|
|
if object_name != 'ir.attachment' \
|
|
or not object_id:
|
|
raise DAV_Forbidden
|
|
pool = Pool()
|
|
Model = pool.get(object_name)
|
|
try:
|
|
Model.delete([Model(object_id)])
|
|
except Exception:
|
|
raise DAV_Forbidden
|
|
return 200
|
|
|
|
@classmethod
|
|
def exists(cls, uri, cache=None):
|
|
object_name, object_id = cls._uri2object(uri, cache=cache)
|
|
if object_name and object_id:
|
|
return 1
|
|
return None
|
|
|
|
@staticmethod
|
|
def current_user_privilege_set(uri, cache=None):
|
|
return ['create', 'read', 'write', 'delete']
|
|
|
|
|
|
class Share(ModelSQL, ModelView):
|
|
"Share"
|
|
__name__ = 'webdav.share'
|
|
_rec_name = 'key'
|
|
|
|
path = fields.Char('Path', required=True, select=True)
|
|
key = fields.Char('Key', required=True, select=True,
|
|
states={
|
|
'readonly': True,
|
|
})
|
|
user = fields.Many2One('res.user', 'User', required=True)
|
|
expiration_date = fields.Date('Expiration Date', required=True)
|
|
note = fields.Text('Note')
|
|
url = fields.Function(fields.Char('URL'), 'get_url')
|
|
|
|
@staticmethod
|
|
def default_key():
|
|
return uuid.uuid4().hex
|
|
|
|
@staticmethod
|
|
def default_user():
|
|
return Transaction().user
|
|
|
|
@staticmethod
|
|
def default_expiration_date():
|
|
return datetime.date.today() + relativedelta(months=1)
|
|
|
|
def get_url(self, name):
|
|
return urlparse.urljoin(get_webdav_url(),
|
|
urlparse.urlunsplit((None, None,
|
|
urllib.quote(self.path.encode('utf-8')),
|
|
urllib.urlencode([('key', self.key)]), None)))
|
|
|
|
@staticmethod
|
|
def match(share, command, path):
|
|
"Test if share match with command and path"
|
|
today = datetime.date.today()
|
|
return (path.startswith(share.path)
|
|
and share.expiration_date > today
|
|
and command == 'GET')
|
|
|
|
@classmethod
|
|
def get_login(cls, key, command, path):
|
|
"""Validate the key for the command and path
|
|
Return the user id if succeed or None
|
|
"""
|
|
shares = cls.search([
|
|
('key', '=', key),
|
|
])
|
|
if not shares:
|
|
return None
|
|
for share in shares:
|
|
if cls.match(share, command, path):
|
|
return share.user.id
|
|
return None
|
|
|
|
|
|
class Attachment(ModelSQL, ModelView):
|
|
__name__ = 'ir.attachment'
|
|
|
|
path = fields.Function(fields.Char('Path'), 'get_path')
|
|
url = fields.Function(fields.Char('URL'), 'get_url')
|
|
shares = fields.Function(fields.One2Many('webdav.share', None, 'Shares',
|
|
domain=[
|
|
('path', '=', Eval('path')),
|
|
],
|
|
depends=['path']), 'get_shares', 'set_shares')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Attachment, cls).__setup__()
|
|
cls._error_messages.update({
|
|
'collection_attachment_name': ('You can not create an '
|
|
'attachment named "%(attachment)s in collection '
|
|
'"%(collection)s" because there is already a collection '
|
|
'with that name.')
|
|
})
|
|
|
|
@classmethod
|
|
def validate(cls, attachments):
|
|
super(Attachment, cls).validate(attachments)
|
|
cls.check_collection(attachments)
|
|
|
|
@classmethod
|
|
def check_collection(cls, attachments):
|
|
pool = Pool()
|
|
Collection = pool.get('webdav.collection')
|
|
for attachment in attachments:
|
|
if attachment.resource:
|
|
model_name = attachment.resource.__name__
|
|
record_id = attachment.resource.id
|
|
if model_name == 'webdav.collection':
|
|
collection = Collection(int(record_id))
|
|
for child in collection.childs:
|
|
if child.name == attachment.name:
|
|
cls.raise_user_error(
|
|
'collection_attachment_name', {
|
|
'attachment': attachment.rec_name,
|
|
'collection': collection.rec_name,
|
|
})
|
|
|
|
@classmethod
|
|
def get_path(cls, attachments, name):
|
|
pool = Pool()
|
|
Collection = pool.get('webdav.collection')
|
|
paths = dict((a.id, None) for a in attachments)
|
|
|
|
resources = {}
|
|
resource2attachments = {}
|
|
for attachment in attachments:
|
|
if not attachment.resource:
|
|
paths[attachment.id] = None
|
|
continue
|
|
model_name = attachment.resource.__name__
|
|
record_id = attachment.resource.id
|
|
resources.setdefault(model_name, set()).add(record_id)
|
|
resource2attachments.setdefault((model_name, record_id),
|
|
[]).append(attachment)
|
|
collections = Collection.search([
|
|
('model.model', 'in', resources.keys()),
|
|
])
|
|
for collection in collections:
|
|
model_name = collection.model.model
|
|
Model = pool.get(model_name)
|
|
ids = list(resources[model_name])
|
|
domain = safe_eval(collection.domain or '[]')
|
|
domain = [domain, ('id', 'in', ids)]
|
|
records = Model.search(domain)
|
|
for record in records:
|
|
for attachment in resource2attachments[
|
|
(model_name, record.id)]:
|
|
paths[attachment.id] = '/'.join((collection.rec_name,
|
|
record.rec_name + '-' + str(record.id),
|
|
attachment.name))
|
|
if 'webdav.collection' in resources:
|
|
collection_ids = list(resources['webdav.collection'])
|
|
for collection in Collection.browse(collection_ids):
|
|
for attachment in resource2attachments[
|
|
('webdav.collection', collection.id)]:
|
|
paths[attachment.id] = '/'.join((collection.rec_name,
|
|
attachment.name))
|
|
return paths
|
|
|
|
def get_url(self, name):
|
|
if self.path:
|
|
return urlparse.urljoin(get_webdav_url(),
|
|
urllib.quote(self.path.encode('utf-8')))
|
|
|
|
@classmethod
|
|
def get_shares(cls, attachments, name):
|
|
Share = Pool().get('webdav.share')
|
|
result = dict((a.id, []) for a in attachments)
|
|
path2attachement = dict((a.path, a) for a in attachments)
|
|
shares = Share.search([
|
|
('path', 'in', path2attachement.keys()),
|
|
])
|
|
for share in shares:
|
|
attachment = path2attachement[share.path]
|
|
result[attachment.id].append(share.id)
|
|
return result
|
|
|
|
@classmethod
|
|
def set_shares(cls, attachments, name, values):
|
|
Share = Pool().get('webdav.share')
|
|
|
|
if not values:
|
|
return
|
|
|
|
def create(vlist):
|
|
to_create = []
|
|
for attachment in attachments:
|
|
for values in vlist:
|
|
values = values.copy()
|
|
values['path'] = attachment.path
|
|
to_create.append(values)
|
|
if to_create:
|
|
Share.create(to_create)
|
|
|
|
def write(ids, values):
|
|
Share.write(Share.browse(ids), values)
|
|
|
|
def delete(share_ids):
|
|
Share.delete(Share.browse(share_ids))
|
|
|
|
actions = {
|
|
'create': create,
|
|
'write': write,
|
|
'delete': delete,
|
|
}
|
|
for value in values:
|
|
action = value[0]
|
|
args = value[1:]
|
|
actions[action](*args)
|