summaryrefslogtreecommitdiff
path: root/addons/document
diff options
context:
space:
mode:
authorHarry (OpenERP) <hmo@tinyerp.com>2010-07-13 20:01:41 +0530
committerHarry (OpenERP) <hmo@tinyerp.com>2010-07-13 20:01:41 +0530
commit72c068a75e0811fc0aaaeb8622afab2b1f1c3ede (patch)
tree1741d7aad768d613d970a30d54a4c0af2cc87ed7 /addons/document
parent506b249a0fc32f5c6dad50ae85c39c45b0a4f9c2 (diff)
parentbbbf42c6ba0f5aa05a53c5b31f909432cbd5f708 (diff)
[MERGE]
bzr revid: hmo@tinyerp.com-20100713143141-wozs7fnurj8ckblw
Diffstat (limited to 'addons/document')
-rw-r--r--addons/document/directory_content.py21
-rw-r--r--addons/document/document.py9
-rw-r--r--addons/document/document_directory.py4
-rw-r--r--addons/document/document_view.xml3
-rw-r--r--addons/document/nodes.py114
5 files changed, 130 insertions, 21 deletions
diff --git a/addons/document/directory_content.py b/addons/document/directory_content.py
index 2d434712f56..bec4f25e45d 100644
--- a/addons/document/directory_content.py
+++ b/addons/document/directory_content.py
@@ -58,7 +58,9 @@ class document_directory_content(osv.osv):
'suffix': fields.char('Suffix', size=16),
'report_id': fields.many2one('ir.actions.report.xml', 'Report'),
'extension': fields.selection(_extension_get, 'Document Type', required=True, size=4),
- 'include_name': fields.boolean('Include Record Name', help="Check this field if you want that the name of the file start by the record name."),
+ 'include_name': fields.boolean('Include Record Name',
+ help="Check this field if you want that the name of the file to contain the record name." \
+ "\nIf set, the directory will have to be a resource one."),
'directory_id': fields.many2one('document.directory', 'Directory'),
}
_defaults = {
@@ -88,12 +90,19 @@ class document_directory_content(osv.osv):
tname = (content.prefix or '') + (content.suffix or '') + (content.extension or '')
if tname.find('/'):
tname=tname.replace('/', '_')
+ act_id = False
+ if 'dctx_res_id' in node.dctx:
+ act_id = node.dctx['dctx_res_id']
+ elif hasattr(node, 'res_id'):
+ act_id = node.res_id
+ else:
+ act_id = node.context.context.get('res_id',False)
if not nodename:
- n = nodes.node_content(tname, node, node.context,content)
+ n = nodes.node_content(tname, node, node.context,content, act_id=act_id)
res2.append( n)
else:
if nodename == tname:
- n = nodes.node_content(tname, node, node.context,content)
+ n = nodes.node_content(tname, node, node.context,content, act_id=act_id)
n.fill_fields(cr)
res2.append(n)
return res2
@@ -108,6 +117,10 @@ class document_directory_content(osv.osv):
raise Exception("Invalid content: %s" % node.extension)
report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.report_id)
srv = netsvc.Service._services['report.'+report.report_name]
- pdf,pdftype = srv.create(cr, uid, [node.context.context['res_id']], {}, {})
+ ctx = node.context.context.copy()
+ ctx.update(node.dctx)
+ pdf,pdftype = srv.create(cr, uid, [node.act_id,], {}, context=ctx)
return pdf
document_directory_content()
+
+#eof \ No newline at end of file
diff --git a/addons/document/document.py b/addons/document/document.py
index 6ab6cae5281..ac3d7b9187d 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -47,7 +47,10 @@ class document_file(osv.osv):
def _data_get(self, cr, uid, ids, name, arg, context):
fbrl = self.browse(cr, uid, ids, context=context)
- nctx = nodes.get_node_context(cr, uid, context)
+ nctx = nodes.get_node_context(cr, uid, context={})
+ # nctx will /not/ inherit the caller's context. Most of
+ # it would be useless, anyway (like active_id, active_model,
+ # bin_size etc.)
result = {}
bin_size = context.get('bin_size', False)
for fbro in fbrl:
@@ -67,7 +70,7 @@ class document_file(osv.osv):
if not value:
return True
fbro = self.browse(cr, uid, id, context=context)
- nctx = nodes.get_node_context(cr, uid, context)
+ nctx = nodes.get_node_context(cr, uid, context={})
fnode = nodes.node_file(None, None, nctx, fbro)
res = fnode.set_data(cr, base64.decodestring(value), fbro)
return res
@@ -156,7 +159,7 @@ class document_file(osv.osv):
raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
if ('parent_id' in vals) or ('name' in vals):
# perhaps this file is renaming or changing directory
- nctx = nodes.get_node_context(cr,uid,context)
+ nctx = nodes.get_node_context(cr,uid,context={})
dirobj = self.pool.get('document.directory')
if 'parent_id' in vals:
dbro = dirobj.browse(cr, uid, vals['parent_id'], context=context)
diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py
index 0685f5c08ff..f5b9202fc8e 100644
--- a/addons/document/document_directory.py
+++ b/addons/document/document_directory.py
@@ -57,6 +57,9 @@ class document_directory(osv.osv):
'ressource_type_id': fields.many2one('ir.model', 'Resource model',
help="Select an object here and there will be one folder per record of that resource."),
'resource_field': fields.many2one('ir.model.fields', 'Name field', help='Field to be used as name on resource directories. If empty, the "name" will be used.'),
+ 'resource_find_all': fields.boolean('Find all resources', required=True,
+ help="If true, all attachments that match this resource will " \
+ " be located. If false, only ones that have this as parent." ),
'ressource_parent_type_id': fields.many2one('ir.model', 'Parent Model',
help="If you put an object here, this directory template will appear bellow all of these objects. " \
"Don't put a parent directory if you select a parent model."),
@@ -103,6 +106,7 @@ class document_directory(osv.osv):
'type': lambda *args: 'directory',
'ressource_id': lambda *a: 0,
'storage_id': _get_def_storage,
+ 'resource_find_all': True,
}
_sql_constraints = [
('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !'),
diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml
index 693d7370567..998d1e93188 100644
--- a/addons/document/document_view.xml
+++ b/addons/document/document_view.xml
@@ -82,6 +82,7 @@
<group colspan="4" col="4" attrs="{'invisible': [('type','!=','ressource')]}">
<field name="ressource_type_id" on_change="onchange_content_id(ressource_type_id)"
attrs="{'required': [('type','=','ressource')] }"/>
+ <field name="resource_find_all" groups="base.group_extended" />
<newline/>
<field name="resource_field" domain="[('model_id','=',ressource_type_id), ('ttype', 'in', ('char', 'selection', 'date', 'datetime'))]"/>
<field name="ressource_tree"/>
@@ -96,7 +97,7 @@
</page>
<page string="Generated Files" groups="base.group_extended">
<label colspan="4" string="For each entry here, virtual files will appear in this folder." />
- <field name="content_ids" nolabel="1" colspan="4" attrs="{'readonly': [('ressource_type_id','=',False)]}">
+ <field name="content_ids" nolabel="1" colspan="4" >
<form string="Contents">
<field name="name"/>
<field name="sequence"/>
diff --git a/addons/document/nodes.py b/addons/document/nodes.py
index d710db37c15..e368c6fc5a0 100644
--- a/addons/document/nodes.py
+++ b/addons/document/nodes.py
@@ -31,6 +31,8 @@ import errno
import os
import time
+from StringIO import StringIO
+
#
# An object that represent an uri
# path: the uri of the object
@@ -226,7 +228,7 @@ class node_class(object):
return False
def get_data(self,cr):
- raise IOError(errno.EINVAL, 'no data for %s' % self.type)
+ raise TypeError('no data for %s'% self.type)
def open_data(self, cr, mode):
""" Open a node_descriptor object for this node.
@@ -240,7 +242,7 @@ class node_class(object):
For this class, there is no data, so no implementation. Each
child class that has data should override this.
"""
- raise IOError(errno.EINVAL, 'no data for %s' % self.type)
+ raise TypeError('no data for %s' % self.type)
def _get_storage(self,cr):
raise RuntimeError("no storage for base class")
@@ -306,13 +308,23 @@ class node_class(object):
Move operations, as instructed from APIs (eg. request from DAV) could
use this function.
"""
- raise NotImplementedError
+ raise NotImplementedError(repr(self))
+
+ def create_child(self, cr, path, data=None):
+ """ Create a regular file under this node
+ """
+ raise NotImplementedError(repr(self))
+
+ def create_child_collection(self, cr, objname):
+ """ Create a child collection (directory) under self
+ """
+ raise NotImplementedError(repr(self))
def rm(self, cr):
- raise RuntimeError("Not Implemented")
+ raise NotImplementedError(repr(self))
def rmcol(self, cr):
- raise RuntimeError("Not Implemented")
+ raise NotImplementedError(repr(self))
def get_domain(self, cr, filters):
return []
@@ -535,7 +547,7 @@ class node_dir(node_database):
return dirobj.create(cr, uid, val)
- def create_child(self, cr, path, data):
+ def create_child(self, cr, path, data=None):
""" API function to create a child file object and node
Return the node_* created
"""
@@ -647,6 +659,7 @@ class node_res_dir(node_class):
self.uidperms = dirr.get_dir_permissions()
self.res_model = dirr.ressource_type_id and dirr.ressource_type_id.model or False
self.resm_id = dirr.ressource_id
+ self.res_find_all = dirr.resource_find_all
self.namefield = dirr.resource_field.name or 'name'
self.displayname = dirr.name
# Important: the domain is evaluated using the *parent* dctx!
@@ -761,16 +774,17 @@ class node_res_obj(node_class):
self.write_date = parent.write_date
self.content_length = 0
self.unixperms = 040750
- self.uidperms = parent.uidperms & 0x15
+ self.uidperms = parent.uidperms & 15
self.uuser = parent.uuser
self.ugroup = parent.ugroup
self.res_model = res_model
self.domain = parent.domain
self.displayname = path
self.dctx_dict = parent.dctx_dict
+ self.res_find_all = parent.res_find_all
if res_bo:
self.res_id = res_bo.id
- dc2 = self.context.context
+ dc2 = self.context.context.copy()
dc2.update(self.dctx)
dc2['res_model'] = res_model
dc2['res_id'] = res_bo.id
@@ -796,6 +810,8 @@ class node_res_obj(node_class):
return False
if self.domain != other.domain:
return False
+ if self.res_find_all != other.res_find_all:
+ return False
if self.dctx != other.dctx:
return False
return self.dir_id == other.dir_id
@@ -909,6 +925,8 @@ class node_res_obj(node_class):
fil_obj = dirobj.pool.get('ir.attachment')
+ if self.res_find_all:
+ where2 = where
where3 = where2 + [('res_model', '=', self.res_model), ('res_id','=',self.res_id)]
# print "where clause for dir_obj", where2
ids = fil_obj.search(cr, uid, where3, context=ctx)
@@ -960,7 +978,7 @@ class node_res_obj(node_class):
return dirobj.create(cr, uid, val)
- def create_child(self, cr, path, data):
+ def create_child(self, cr, path, data=None):
""" API function to create a child file object and node
Return the node_* created
"""
@@ -976,11 +994,12 @@ class node_res_obj(node_class):
val = {
'name': path,
'datas_fname': path,
- 'parent_id': self.dir_id,
'res_model': self.res_model,
'res_id': self.res_id,
# Datas are not set here
}
+ if not self.res_find_all:
+ val['parent_id'] = self.dir_id
fil_id = fil_obj.create(cr, uid, val, context=ctx)
fil = fil_obj.browse(cr, uid, fil_id, context=ctx)
@@ -1204,9 +1223,6 @@ class node_content(node_class):
self.dctx.update(dctx)
self.act_id = act_id
- def open(self, cr, mode=False):
- raise DeprecationWarning()
-
def fill_fields(self, cr, dctx = None):
""" Try to read the object and fill missing fields, like mimetype,
dates etc.
@@ -1233,7 +1249,29 @@ class node_content(node_class):
self.content_length = len(data)
return data
+ def open_data(self, cr, mode):
+ if mode.endswith('b'):
+ mode = mode[:-1]
+ if mode in ('r', 'w'):
+ cperms = mode[:1]
+ elif mode in ('r+', 'w+'):
+ cperms = 'rw'
+ else:
+ raise IOError(errno.EINVAL, "Cannot open at mode %s" % mode)
+
+ if not self.check_perms(cperms):
+ raise IOError(errno.EPERM, "Permission denied")
+
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+
+ return nodefd_content(self, cr, mode, ctx)
+
def get_data_len(self, cr, fil_obj = None):
+ # FIXME : here, we actually generate the content twice!!
+ # we should have cached the generated content, but it is
+ # not advisable to do keep it in memory, until we have a cache
+ # expiration logic.
if not self.content_length:
self.get_data(cr,fil_obj)
return self.content_length
@@ -1249,3 +1287,53 @@ class node_content(node_class):
def _get_ttag(self,cr):
return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '')
+
+
+class nodefd_content(StringIO, node_descriptor):
+ """ A descriptor to content nodes
+ """
+ def __init__(self, parent, cr, mode, ctx):
+ node_descriptor.__init__(self, parent)
+ self._context=ctx
+
+ if mode in ('r', 'r+'):
+ cntobj = parent.context._dirobj.pool.get('document.directory.content')
+ data = cntobj.process_read(cr, parent.context.uid, parent, ctx)
+ if data:
+ parent.content_length = len(data)
+ StringIO.__init__(self, data)
+ elif mode in ('w', 'w+'):
+ StringIO.__init__(self, None)
+ # at write, we start at 0 (= overwrite), but have the original
+ # data available, in case of a seek()
+ elif mode == 'a':
+ StringIO.__init__(self, None)
+ else:
+ logging.getLogger('document.content').error("Incorrect mode %s specified", mode)
+ raise IOError(errno.EINVAL, "Invalid file mode")
+ self.mode = mode
+
+ def close(self):
+ # we now open a *separate* cursor, to update the data.
+ # FIXME: this may be improved, for concurrency handling
+ if self.mode == 'r':
+ StringIO.close(self)
+ return
+
+ par = self._get_parent()
+ uid = par.context.uid
+ cr = pooler.get_db(par.context.dbname).cursor()
+ try:
+ if self.mode in ('w', 'w+', 'r+'):
+ data = self.getvalue()
+ cntobj = par.context._dirobj.pool.get('document.directory.content')
+ cntobj.process_write(cr, uid, parent, data, ctx)
+ elif self.mode == 'a':
+ raise NotImplementedError
+ cr.commit()
+ except Exception, e:
+ logging.getLogger('document.content').exception('Cannot update db content #%d for close:', par.cnt_id)
+ raise
+ finally:
+ cr.close()
+ StringIO.close(self)