1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
24 from osv import osv, fields
25 from osv.orm import except_orm
28 from tools.safe_eval import safe_eval
34 # An object that represent an uri
35 # path: the uri of the object
36 # content: the Content it belongs to (_print.pdf)
37 # type: content or collection
38 # content: objct = res.partner
39 # collection: object = directory, object2 = res.partner
40 # file: objct = ir.attachement
41 # root: if we are at the first directory of a ressource
44 def get_node_context(cr, uid, context):
45 return node_context(cr,uid,context)
47 class node_context(object):
48 """ This is the root node, representing access to some particular
52 def __init__(self, cr, uid, context=None):
53 self.dbname = cr.dbname
55 self.context = context
56 self._dirobj = pooler.get_pool(cr.dbname).get('document.directory')
58 self.rootdir = False #self._dirobj._get_root_directory(cr,uid,context)
60 def get_uri(self, cr, uri):
61 """ Although this fn passes back to doc.dir, it is needed since
62 it is a potential caching point """
63 (ndir, duri) = self._dirobj._locate_child(cr,self.uid, self.rootdir,uri, None, self)
65 ndir = ndir.child(cr, duri[0])
74 class node_class(object):
75 """ this is a superclass for our inodes
76 It is an API for all code that wants to access the document files.
77 Nodes have attributes which contain usual file properties
79 our_type = 'baseclass'
80 def __init__(self, path, parent, context):
81 assert isinstance(context,node_context)
82 assert (not parent ) or isinstance(parent,node_class)
84 self.context = context
85 self.type=self.our_type
87 self.mimetype = 'application/octet-stream'
88 self.create_date = None
89 self.write_date = None
90 self.content_length = 0
94 self.dctx = parent.dctx.copy()
95 self.displayname = 'Object'
98 """ Return the components of the full path for some
100 The returned list only contains the names of nodes.
103 s = self.parent.full_path()
106 if isinstance(self.path,list):
110 return s #map(lambda x: '/' +x, s)
112 def children(self, cr):
113 print "node_class.children()"
116 def child(self,cr, name):
117 print "node_class.child()"
121 print "node_class.path_get()"
124 def get_data(self,cr):
125 raise TypeError('no data for %s'% self.type)
127 def _get_storage(self,cr):
128 raise RuntimeError("no storage for base class")
130 def get_etag(self,cr):
131 """ Get a tag, unique per object + modification.
133 see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
134 return self._get_ttag(cr) + ':' + self._get_wtag(cr)
136 def _get_wtag(self,cr):
137 """ Return the modification time as a unique, compact string """
139 wtime = time.mktime(time.strptime(self.write_date,'%Y-%m-%d %H:%M:%S'))
140 else: wtime = time.time()
143 def _get_ttag(self,cr):
144 """ Get a unique tag for this type/id of object.
145 Must be overriden, so that each node is uniquely identified.
147 print "node_class.get_ttag()",self
148 raise RuntimeError("get_etag stub()")
150 def get_dav_props(self, cr):
151 """ If this class has special behaviour for GroupDAV etc, export
155 def get_dav_eprop(self,cr,ns,prop):
158 class node_database(node_class):
159 """ A node representing the database directory
162 our_type = 'database'
163 def __init__(self, path=[], parent=False, context=None):
164 super(node_database,self).__init__(path, parent, context)
166 def children(self,cr):
167 res = self._child_get(cr) + self._file_get(cr)
170 def child(self, cr, name):
171 res = self._child_get(cr,name)
174 res = self._file_get(cr,name)
179 def _child_get(self, cr, name=False, parent_id=False, domain=None):
180 dirobj = self.context._dirobj
181 uid = self.context.uid
182 ctx = self.context.context.copy()
183 ctx.update(self.dctx)
184 where = [('parent_id','=',parent_id)]
186 where.append(('name','=',name))
190 where2 = where + domain + [('type', '=', 'directory')]
191 ids = dirobj.search(cr, uid, where2, context=ctx)
193 for dirr in dirobj.browse(cr,uid,ids,context=ctx):
194 res.append(node_dir(dirr.name,self,self.context,dirr))
196 where2 = where + domain + [('type', '=', 'ressource'), ('ressource_parent_type_id','=',False)]
197 ids = dirobj.search(cr, uid, where2, context=ctx)
198 for dirr in dirobj.browse(cr,uid,ids,context=ctx):
199 res.append(node_res_dir(dirr.name,self,self.context,dirr))
201 fil_obj = dirobj.pool.get('ir.attachment')
202 ids = fil_obj.search(cr,uid,where,context=ctx)
204 for fil in fil_obj.browse(cr,uid,ids,context=ctx):
205 res.append(node_file(fil.name,self,self.context,fil))
208 def _file_get(self,cr, nodename=False, directory_id=False):
210 cntobj = self.context._dirobj.pool.get('document.directory.content')
211 uid = self.context.uid
212 ctx = self.context.context.copy()
213 ctx.update(self.dctx)
214 where = [('directory_id','=',directory_id) ]
215 ids = cntobj.search(cr, uid, where, context=ctx)
216 for content in cntobj.browse(cr, uid, ids, context=ctx):
217 res3 = cntobj._file_get(cr, self, nodename, content)
223 def _get_ttag(self,cr):
224 return 'db-%s' % cr.dbname
227 class node_dir(node_database):
228 our_type = 'collection'
229 def __init__(self,path, parent, context, dirr, dctx=None):
230 super(node_dir,self).__init__(path, parent,context)
231 self.dir_id = dirr and dirr.id or False
232 #todo: more info from dirr
233 self.mimetype = 'application/x-directory'
234 # 'httpd/unix-directory'
235 self.create_date = dirr and dirr.create_date or False
236 self.domain = dirr and dirr.domain or []
237 self.res_model = dirr and dirr.ressource_type_id and dirr.ressource_type_id.model or False
238 # TODO: the write date should be MAX(file.write)..
239 self.write_date = dirr and (dirr.write_date or dirr.create_date) or False
240 self.content_length = 0
242 self.dctx.update(dctx)
243 dc2 = self.context.context
244 dc2.update(self.dctx)
245 dc2['dir_id'] = self.dir_id
246 self.displayname = dirr and dirr.name or False
247 if dirr and dirr.dctx_ids:
248 for dfld in dirr.dctx_ids:
250 self.dctx['dctx_' + dfld.field] = safe_eval(dfld.expr,dc2)
252 print "Cannot eval %s" % dfld.expr
257 #def get_data(self,cr):
262 def _file_get(self,cr, nodename=False):
263 return super(node_dir,self)._file_get(cr, nodename, self.dir_id)
267 def _child_get(self, cr, name = None):
268 return super(node_dir,self)._child_get(cr, name, self.dir_id)
270 def create_child_collection(self, cr, objname):
272 dirobj = self.context._dirobj
273 uid = self.context.uid
274 ctx = self.context.context.copy()
275 ctx.update(self.dctx)
276 obj = dirobj.browse(cr, uid, self.dir_id)
277 if obj and (obj.type == 'ressource') and not object2:
278 raise OSError(1, 'Operation not permited.')
283 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False,
284 'ressource_id': object2 and object2.id or False,
285 'parent_id' : obj and obj.id or False
288 return dirobj.create(cr, uid, val)
291 def create_child(self,cr,path,data):
292 """ API function to create a child file object and node
293 Return the node_* created
295 dirobj = self.context._dirobj
296 uid = self.context.uid
297 ctx = self.context.context.copy()
298 ctx.update(self.dctx)
299 fil_obj=dirobj.pool.get('ir.attachment')
303 'parent_id': self.dir_id,
304 # Datas are not set here
307 fil_id = fil_obj.create(cr,uid, val, context=ctx)
308 fil = fil_obj.browse(cr,uid,fil_id,context=ctx)
309 fnode = node_file(path,self,self.context,fil)
310 fnode.set_data(cr,data,fil)
313 def get_etag(self, cr):
314 """ Get a tag, unique per object + modification.
316 see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
317 return self._get_ttag(cr) + ':' + self._get_wtag(cr)
319 def _get_wtag(self, cr):
320 """ Return the modification time as a unique, compact string """
322 wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
323 else: wtime = time.time()
326 def _get_ttag(self,cr):
327 return 'dir-%d' % self.dir_id
329 class node_res_dir(node_class):
330 """ A special sibling to node_dir, which does only contain dynamically
331 created folders foreach resource in the foreign model.
332 All folders should be of type node_res_obj and merely behave like
333 node_dirs (with limited domain).
335 our_type = 'collection'
336 def __init__(self,path, parent, context, dirr, dctx=None ):
337 super(node_res_dir,self).__init__(path, parent,context)
338 self.dir_id = dirr.id
339 #todo: more info from dirr
340 self.mimetype = 'application/x-directory'
341 # 'httpd/unix-directory'
342 self.create_date = dirr.create_date
343 # TODO: the write date should be MAX(file.write)..
344 self.write_date = dirr.write_date or dirr.create_date
345 self.content_length = 0
346 self.res_model = dirr.ressource_type_id and dirr.ressource_type_id.model or False
347 self.resm_id = dirr.ressource_id
348 self.namefield = dirr.resource_field or 'name'
349 self.displayname = dirr.name
350 # Important: the domain is evaluated using the *parent* dctx!
351 self.domain = dirr.domain
352 self.ressource_tree = dirr.ressource_tree
353 # and then, we add our own vars in the dctx:
355 self.dctx.update(dctx)
357 # and then, we prepare a dctx dict, for deferred evaluation:
359 for dfld in dirr.dctx_ids:
360 self.dctx_dict['dctx_' + dfld.field] = dfld.expr
362 def children(self,cr):
363 return self._child_get(cr)
365 def child(self,cr, name):
366 res = self._child_get(cr,name)
371 def _child_get(self,cr,name = None):
372 """ return virtual children of resource, based on the
375 Note that many objects use NULL for a name, so we should
376 better call the name_search(),name_get() set of methods
378 obj = self.context._dirobj.pool.get(self.res_model)
380 print "couldn't find model", self.res_model
382 dirobj = self.context._dirobj
383 uid = self.context.uid
384 ctx = self.context.context.copy()
385 ctx.update(self.dctx)
388 where += safe_eval(self.domain, self.dctx)
390 where.append(('id','=',self.resm_id))
393 where.append((self.namefield,'=',name))
395 # print "Where clause for %s" % self.res_model, where
396 if self.ressource_tree:
399 object2 = dirobj.pool.get(self.res_model).browse(cr, uid, self.resm_id) or False
400 if obj._parent_name in obj.fields_get(cr, uid):
401 where.append((obj._parent_name,'=',object2 and object2.id or False))
403 resids = obj.search(cr,uid, where, context=ctx)
405 for bo in obj.browse(cr,uid,resids,context=ctx):
408 name = getattr(bo,self.namefield)
411 # Yes! we can't do better but skip nameless records.
413 res.append(node_res_obj(name, self.dir_id, self, self.context, self.res_model, bo))
416 def _get_ttag(self,cr):
417 return 'rdir-%d' % self.dir_id
419 class node_res_obj(node_class):
420 """ A special sibling to node_dir, which does only contain dynamically
421 created folders foreach resource in the foreign model.
422 All folders should be of type node_res_obj and merely behave like
423 node_dirs (with limited domain).
425 our_type = 'collection'
426 def __init__(self, path, dir_id, parent, context, res_model, res_bo, res_id = None):
427 super(node_res_obj,self).__init__(path, parent,context)
429 #todo: more info from dirr
431 self.mimetype = 'application/x-directory'
432 # 'httpd/unix-directory'
433 self.create_date = parent.create_date
434 # TODO: the write date should be MAX(file.write)..
435 self.write_date = parent.write_date
436 self.content_length = 0
437 self.res_model = res_model
438 self.domain = parent.domain
439 self.displayname = path
440 self.dctx_dict = parent.dctx_dict
442 self.res_id = res_bo.id
443 dc2 = self.context.context
444 dc2.update(self.dctx)
445 dc2['res_model'] = res_model
446 dc2['res_id'] = res_bo.id
448 for fld,expr in self.dctx_dict.items():
450 self.dctx[fld] = safe_eval(expr,dc2)
452 print "Cannot eval %s for %s" % (expr, fld)
458 def children(self,cr):
459 return self._child_get(cr) + self._file_get(cr)
461 def child(self,cr, name):
462 res = self._child_get(cr,name)
465 res = self._file_get(cr,name)
470 def _file_get(self,cr, nodename=False):
472 cntobj = self.context._dirobj.pool.get('document.directory.content')
473 uid = self.context.uid
474 ctx = self.context.context.copy()
475 ctx.update(self.dctx)
476 where = [('directory_id','=',self.dir_id) ]
478 # where.extend(self.domain)
479 # print "res_obj file_get clause", where
480 ids = cntobj.search(cr,uid,where,context=ctx)
481 for content in cntobj.browse(cr,uid,ids,context=ctx):
482 res3 = cntobj._file_get(cr,self,nodename,content, context=ctx)
488 def get_dav_props(self, cr):
490 cntobj = self.context._dirobj.pool.get('document.directory.content')
491 uid = self.context.uid
492 ctx = self.context.context.copy()
493 ctx.update(self.dctx)
494 where = [('directory_id','=',self.dir_id) ]
495 ids = cntobj.search(cr,uid,where,context=ctx)
496 for content in cntobj.browse(cr,uid,ids,context=ctx):
497 if content.extension == '.ics': # FIXME: call the content class!
498 res['http://groupdav.org/'] = ('resourcetype',)
501 def get_dav_eprop(self,cr,ns,prop):
502 if ns != 'http://groupdav.org/' or prop != 'resourcetype':
503 print "Who asked for %s:%s?" % (ns,prop)
506 cntobj = self.context._dirobj.pool.get('document.directory.content')
507 uid = self.context.uid
508 ctx = self.context.context.copy()
509 ctx.update(self.dctx)
510 where = [('directory_id','=',self.dir_id) ]
511 ids = cntobj.search(cr,uid,where,context=ctx)
512 for content in cntobj.browse(cr,uid,ids,context=ctx):
513 if content.extension == '.ics': # FIXME: call the content class!
514 return ('vevent-collection','http://groupdav.org/')
517 def _child_get(self,cr,name = None):
518 dirobj = self.context._dirobj
519 uid = self.context.uid
520 ctx = self.context.context.copy()
521 ctx.update(self.dctx)
522 directory = dirobj.browse(cr, uid, self.dir_id)
523 obj = dirobj.pool.get(self.res_model)
527 where.append(('name','=',name))
529 # Directory Structure display in tree structure
530 if self.res_id and directory.ressource_tree:
532 if obj._parent_name in obj.fields_get(cr, uid):
533 where1 = where + [(obj._parent_name, '=', self.res_id)]
534 resids = obj.search(cr,uid, where1, context=ctx)
535 for bo in obj.browse(cr,uid,resids,context=ctx):
536 namefield = directory.resource_field or 'name'
539 res_name = getattr(bo, namefield)
542 res.append(node_res_obj(res_name, self.dir_id, self, self.context, self.res_model, res_bo = bo))
545 where2 = where + [('parent_id','=',self.dir_id) ]
546 ids = dirobj.search(cr, uid, where2, context=ctx)
547 for dirr in dirobj.browse(cr, uid, ids, context=ctx):
548 if dirr.type == 'directory':
549 res.append(node_res_obj(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = None, res_id = self.res_id))
550 elif dirr.type == 'ressource':
551 # child resources can be controlled by properly set dctx
552 res.append(node_res_dir(dirr.name,self,self.context, dirr, {'active_id': self.res_id}))
557 fil_obj = dirobj.pool.get('ir.attachment')
558 where3 = where2 + [('res_model', '=', self.res_model), ('res_id','=',self.res_id)]
559 # print "where clause for dir_obj", where2
560 ids = fil_obj.search(cr, uid, where3, context=ctx)
562 for fil in fil_obj.browse(cr, uid, ids, context=ctx):
563 res.append(node_file(fil.name, self, self.context, fil))
566 # Get Child Ressource Directories
567 if directory.ressource_type_id and directory.ressource_type_id.id:
568 where4 = where + [('ressource_parent_type_id','=',directory.ressource_type_id.id)]
569 where5 = where4 + [('ressource_id','=',0)]
570 dirids = dirobj.search(cr,uid, where5)
571 where5 = where4 + [('ressource_id','=',self.res_id)]
572 dirids = dirids + dirobj.search(cr,uid, where5)
573 for dirr in dirobj.browse(cr, uid, dirids, context=ctx):
574 if dirr.type == 'directory' and not dirr.parent_id:
575 res.append(node_res_obj(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = None, res_id = self.res_id))
576 if dirr.type == 'ressource':
577 res.append(node_res_dir(dirr.name, self, self.context, dirr, {'active_id': self.res_id}))
580 def create_child_collection(self, cr, objname):
581 dirobj = self.context._dirobj
582 uid = self.context.uid
583 ctx = self.context.context.copy()
584 ctx.update(self.dctx)
585 res_obj = dirobj.pool.get(self.context.context['res_model'])
587 object2 = res_obj.browse(cr, uid, self.context.context['res_id']) or False
589 obj = dirobj.browse(cr, uid, self.dir_id)
590 if obj and (obj.type == 'ressource') and not object2:
591 raise OSError(1, 'Operation not permited.')
596 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False,
597 'ressource_id': object2 and object2.id or False,
600 if (obj and (obj.type in ('directory'))) or not object2:
601 val['parent_id'] = obj and obj.id or False
603 return dirobj.create(cr, uid, val)
605 def create_child(self,cr,path,data):
606 """ API function to create a child file object and node
607 Return the node_* created
609 dirobj = self.context._dirobj
610 uid = self.context.uid
611 ctx = self.context.context.copy()
612 ctx.update(self.dctx)
613 fil_obj=dirobj.pool.get('ir.attachment')
617 'parent_id': self.dir_id,
618 'res_model': self.res_model,
619 'res_id': self.res_id,
620 # Datas are not set here
623 fil_id = fil_obj.create(cr,uid, val, context=ctx)
624 fil = fil_obj.browse(cr,uid,fil_id,context=ctx)
625 fnode = node_file(path,self,self.context,fil)
626 fnode.set_data(cr,data,fil)
629 def _get_ttag(self,cr):
630 return 'rodir-%d-%d' % (self.dir_id,self.res_id)
632 class node_file(node_class):
634 def __init__(self,path, parent, context, fil):
635 super(node_file,self).__init__(path, parent,context)
636 self.file_id = fil.id
637 #todo: more info from ir_attachment
638 if fil.file_type and '/' in fil.file_type:
639 self.mimetype = fil.file_type
640 self.create_date = fil.create_date
641 self.write_date = fil.write_date or fil.create_date
642 self.content_length = fil.file_size
643 self.displayname = fil.name
645 # This only propagates the problem to get_data. Better
646 # fix those files to point to the root dir.
648 self.storage_id = fil.parent_id.storage_id.id
650 self.storage_id = None
652 def open(self, cr, mode=False):
653 uid = self.context.uid
654 if self.type in ('collection','database'):
656 fobj = self.context._dirobj.pool.get('ir.attachment').browse(cr, uid, self.file_id, context=self.context.context)
657 if fobj.store_method and fobj.store_method== 'fs' :
658 s = StringIO.StringIO(self.get_data(cr, fobj))
660 s = StringIO.StringIO(base64.decodestring(fobj.db_datas or ''))
664 def fix_ppath(self, cr, fbro):
665 """Sometimes we may init this w/o path, parent.
666 This function fills the missing path from the file browse object
668 Note: this may be an expensive operation, do on demand. However,
669 once caching is in, we might want to do that at init time and keep
672 if self.path or self.parent:
675 uid = self.context.uid
679 dirobj = self.context._dirobj.pool.get('document.directory')
680 dirpath = dirobj.get_full_path(cr, uid, fbro.parent_id.id, context=self.context.context)
682 dirpath.append(fbro.datas_fname)
684 dirpath.append(fbro.name)
689 self.path = dirpath[0]
691 def get_data(self, cr, fil_obj = None):
692 """ Retrieve the data for some file.
693 fil_obj may optionally be specified, and should be a browse object
694 for the file. This is useful when the caller has already initiated
695 the browse object. """
696 # this is where storage kicks in..
697 stor = self.storage_id
699 data_obj = self.context._dirobj.pool.get('ir.model.data')
700 data_id = data_obj._get_id(cr, self.context.uid, 'document', 'storage_db')
702 stor = data_obj.browse(cr, self.context.uid, data_id, context=self.context.context).res_id
704 stobj = self.context._dirobj.pool.get('document.storage')
705 return stobj.get_data(cr,self.context.uid,stor, self,self.context.context, fil_obj)
707 def get_data_len(self, cr, fil_obj = None):
708 # TODO: verify with the storage object!
709 bin_size = self.context.context.get('bin_size', False)
710 if bin_size and not self.content_length:
711 self.content_length = fil_obj.db_datas
712 return self.content_length
714 def set_data(self, cr, data, fil_obj = None):
715 """ Store data at some file.
716 fil_obj may optionally be specified, and should be a browse object
717 for the file. This is useful when the caller has already initiated
718 the browse object. """
719 # this is where storage kicks in..
720 stor = self.storage_id
722 data_obj = self.context._dirobj.pool.get('ir.model.data')
723 data_id = data_obj._get_id(cr, self.context.uid, 'document', 'storage_db')
725 stor = data_obj.browse(cr, self.context.uid, data_id, context=self.context.context).res_id
727 stobj = self.context._dirobj.pool.get('document.storage')
728 return stobj.set_data(cr,self.context.uid,stor, self, data, self.context.context, fil_obj)
730 def _get_ttag(self,cr):
731 return 'file-%d' % self.file_id
733 class node_content(node_class):
735 def __init__(self,path, parent, context, cnt, dctx = None, act_id=None):
736 super(node_content,self).__init__(path, parent,context)
738 self.create_date = False
739 self.write_date = False
740 self.content_length = False
741 self.extension = cnt.extension
742 self.report_id = cnt.report_id and cnt.report_id.id
743 #self.mimetype = cnt.extension.
744 self.displayname = path
746 self.dctx.update(dctx)
749 def open(self, cr, mode=False):
750 uid = self.context.uid
751 if self.type in ('collection','database'):
753 pool = self.context._dirobj.pool
754 res = getattr(pool.get('document.directory.content'), 'process_read')(cr, uid, self)
755 res = StringIO.StringIO(res)
759 def fill_fields(self,cr,dctx = None):
760 """ Try to read the object and fill missing fields, like mimetype,
762 This function must be different from the constructor, because
763 it uses the db cursor.
766 cr.execute('SELECT DISTINCT mimetype FROM document_directory_content_type WHERE active AND code = %s;',
769 if res and res[0][0]:
770 self.mimetype = res[0][0]
773 def get_data(self, cr, fil_obj = None):
774 cntobj = self.context._dirobj.pool.get('document.directory.content')
775 ctx = self.context.context.copy()
776 ctx.update(self.dctx)
777 data = cntobj.process_read(cr,self.context.uid,self,ctx)
779 self.content_length = len(data)
782 def get_data_len(self, cr, fil_obj = None):
783 if not self.content_length:
784 self.get_data(cr,fil_obj)
785 return self.content_length
787 def set_data(self, cr, data, fil_obj = None):
788 cntobj = self.context._dirobj.pool.get('document.directory.content')
789 ctx = self.context.context.copy()
790 ctx.update(self.dctx)
791 return cntobj.process_write(cr,self.context.uid,self, data,ctx)
793 def _get_ttag(self,cr):
794 return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '')
797 # the old code, remove..
798 def __init__(self, cr, uid, path, object, object2=False, context={}, content=False, type='collection', root=False):
800 def _file_get(self, nodename=False):
803 pool = pooler.get_pool(self.cr.dbname)
804 fobj = pool.get('ir.attachment')
808 where.append( ('res_model','=',self.object2._name) )
809 where.append( ('res_id','=',self.object2.id) )
811 where.append( ('parent_id','=',self.object.id) )
812 where.append( ('res_id','=',False) )
814 where.append( (fobj._rec_name,'=',nodename) )
815 for content in self.object.content_ids:
816 res3 = content._table._file_get(self,nodename,content)
820 ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ])
821 if self.object and self.root and (self.object.type=='ressource'):
822 ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ])
823 res = fobj.browse(self.cr, self.uid, ids, context=self.context)
824 return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=False), res) + res2
826 def get_translation(self,value,lang):
827 # Must go, it works on arbitrary models and could be ambiguous.
829 pool = pooler.get_pool(self.cr.dbname)
830 translation_ids = pool.get('ir.translation').search(self.cr, self.uid, [('value','=',value),('lang','=',lang),('type','=','model')])
831 if len(translation_ids):
832 tran_id = translation_ids[0]
833 translation = pool.get('ir.translation').read(self.cr, self.uid, tran_id, ['res_id','name'])
834 res_model,field_name = tuple(translation['name'].split(','))
835 res_id = translation['res_id']
836 res = pool.get(res_model).read(self.cr, self.uid, res_id, [field_name])
838 result = res[field_name]
841 def directory_list_for_child(self,nodename,parent=False):
842 pool = pooler.get_pool(self.cr.dbname)
845 nodename = self.get_translation(nodename, self.context['lang'])
846 where.append(('name','=',nodename))
847 if (self.object and self.object.type=='directory') or not self.object2:
848 where.append(('parent_id','=',self.object and self.object.id or False))
850 where.append(('parent_id','=',False))
852 where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
854 where.append(('ressource_parent_type_id','=',False))
856 ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)])
858 ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)])
859 res = pool.get('document.directory').browse(self.cr, self.uid, ids, self.context)
862 def _child_get(self, nodename=False):
863 if self.type not in ('collection','database'):
865 res = self.directory_list_for_child(nodename)
866 result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, context=self.context, root=self.root), res)
867 if self.type=='database':
868 pool = pooler.get_pool(self.cr.dbname)
869 fobj = pool.get('ir.attachment')
870 vargs = [('parent_id','=',False),('res_id','=',False)]
872 vargs.append((fobj._rec_name,'=',nodename))
873 file_ids=fobj.search(self.cr,self.uid,vargs)
875 res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
876 result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=self.root), res)
877 if self.type=='collection' and self.object.type=="ressource":
878 where = self.object.domain and eval(self.object.domain, {'active_id':self.root, 'uid':self.uid}) or []
879 pool = pooler.get_pool(self.cr.dbname)
880 obj = pool.get(self.object.ressource_type_id.model)
881 _dirname_field = obj._rec_name
882 if len(obj.fields_get(self.cr, self.uid, ['dirname'])):
883 _dirname_field = 'dirname'
885 name_for = obj._name.split('.')[-1]
886 if nodename and nodename.find(name_for) == 0 :
887 id = int(nodename.replace(name_for,''))
888 where.append(('id','=',id))
890 if nodename.find('__') :
891 nodename=nodename.replace('__','/')
892 for invalid in INVALID_CHARS:
893 if nodename.find(INVALID_CHARS[invalid]) :
894 nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
895 nodename = self.get_translation(nodename, self.context['lang'])
896 where.append((_dirname_field,'=',nodename))
898 if self.object.ressource_tree:
899 if obj._parent_name in obj.fields_get(self.cr,self.uid):
900 where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
901 ids = obj.search(self.cr, self.uid, where)
902 res = obj.browse(self.cr, self.uid, ids,self.context)
903 result+= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
913 ids = obj.search(self.cr, self.uid, where)
914 res = obj.browse(self.cr, self.uid, ids,self.context)
916 if len(obj.fields_get(self.cr, self.uid, [_dirname_field])):
917 r.name = eval('r.'+_dirname_field)
921 r.name = name_for + '%d'%r.id
922 for invalid in INVALID_CHARS:
923 if r.name.find(invalid) :
924 r.name = r.name.replace(invalid,INVALID_CHARS[invalid])
925 result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
927 if self.object.ressource_tree:
936 if self.path[0]=='/':