diff --git a/addons/document/__init__.py b/addons/document/__init__.py index 55caca1b701d2964e10003e9708298720f9c9e46..81fc81d29c953d6366524a4eb569e5cba130099a 100644 --- a/addons/document/__init__.py +++ b/addons/document/__init__.py @@ -1,8 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import content_index -import std_index -import document -import report -import wizard +import models diff --git a/addons/document/__openerp__.py b/addons/document/__openerp__.py index aafc17e86c7955b7b0ed125f15d59a2936a42fd3..32a7f45c10a42f16627904d9ad5c5645483b9bc1 100644 --- a/addons/document/__openerp__.py +++ b/addons/document/__openerp__.py @@ -1,36 +1,21 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - - { - 'name': 'Document Management System', + 'name': 'Attachments List and Document Indexation', 'version': '2.1', 'category': 'Knowledge Management', 'description': """ -This is a complete document management system. -============================================== - * User Authentication - * Document Indexation:- .pptx and .docx files are not supported in Windows platform. - * Dashboard for Document that includes: - * New Files (list) - * Files by Resource Type (graph) - * Files by Partner (graph) - * Files Size by Month (graph) +Attachments list and document indexation +======================================== +* Show attachment on the top of the forms +* Document Indexation: odt """, 'author': 'OpenERP SA', 'website': 'https://www.odoo.com', - 'depends': ['mail'], + 'depends': ['web'], 'data': [ - 'security/document_security.xml', - 'document_view.xml', - 'document_data.xml', - 'wizard/document_configuration_view.xml', - 'security/ir.model.access.csv', - 'report/document_report_view.xml', 'views/document.xml', ], - 'demo': [ 'document_demo.xml' ], - 'test': ['test/document_test2.yml'], 'installable': True, 'auto_install': False, } diff --git a/addons/document/content_index.py b/addons/document/content_index.py deleted file mode 100644 index fb26e26a6934c8ce7a1654bf458735934dcbb7a2..0000000000000000000000000000000000000000 --- a/addons/document/content_index.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. -import logging -import os -import tempfile -from subprocess import Popen, PIPE -_logger = logging.getLogger(__name__) - - -class indexer(object): - """ An indexer knows how to parse the content of some file. - - Typically, one indexer should be instantiated per file - type. - Override this class to add more functionality. Note that - you should only override the Content or the File methods - that give an optimal result. """ - - def _getMimeTypes(self): - """ Return supported mimetypes """ - return [] - - def _getExtensions(self): - return [] - - def _getDefMime(self, ext): - """ Return a mimetype for this document type, ideally the - closest to the extension ext. """ - mts = self._getMimeTypes(); - if len (mts): - return mts[0] - return None - - def indexContent(self, content, filename=None, realfile=None): - """ Use either content or the real file, to index. - Some parsers will work better with the actual - content, others parse a file easier. Try the - optimal. - """ - res = '' - try: - if content != None: - return self._doIndexContent(content) - except NotImplementedError: - pass - - if realfile != None: - try: - return self._doIndexFile(realfile) - except NotImplementedError: - pass - - fp = open(realfile,'rb') - try: - content2 = fp.read() - finally: - fp.close() - - # The not-handled exception may be raised here - return self._doIndexContent(content2) - - - # last try, with a tmp file - if content: - try: - fname,ext = filename and os.path.splitext(filename) or ('','') - fd, rfname = tempfile.mkstemp(suffix=ext) - os.write(fd, content) - os.close(fd) - res = self._doIndexFile(rfname) - os.unlink(rfname) - return res - except NotImplementedError: - pass - - raise ValueError('No appropriate method to index file.') - - def _doIndexContent(self, content): - raise NotImplementedError("Content cannot be handled here.") - - def _doIndexFile(self, fpath): - raise NotImplementedError("Content cannot be handled here.") - - def __repr__(self): - return "<indexer %s.%s>" %(self.__module__, self.__class__.__name__) - -def mime_match(mime, mdict): - if mdict.has_key(mime): - return (mime, mdict[mime]) - if '/' in mime: - mpat = mime.split('/')[0]+'/*' - if mdict.has_key(mpat): - return (mime, mdict[mpat]) - - return (None, None) - -class contentIndex(object): - - def __init__(self): - self.mimes = {} - self.exts = {} - - def register(self, obj): - f = False - for mime in obj._getMimeTypes(): - self.mimes[mime] = obj - f = True - - for ext in obj._getExtensions(): - self.exts[ext] = obj - f = True - - if not f: - raise ValueError("Your indexer should at least support a mimetype or extension.") - _logger.debug('Register content indexer: %r.', obj) - - def doIndex(self, content, filename=None, content_type=None, realfname=None, debug=False): - fobj = None - fname = None - mime = None - if content_type and self.mimes.has_key(content_type): - mime = content_type - fobj = self.mimes[content_type] - elif filename: - bname,ext = os.path.splitext(filename) - if self.exts.has_key(ext): - fobj = self.exts[ext] - mime = fobj._getDefMime(ext) - - if content_type and not fobj: - mime,fobj = mime_match(content_type, self.mimes) - - if not fobj: - try: - if realfname : - fname = realfname - else: - try: - bname,ext = os.path.splitext(filename or 'test.tmp') - except Exception: - bname, ext = filename, 'tmp' - fd, fname = tempfile.mkstemp(suffix=ext) - os.write(fd, content) - os.close(fd) - - pop = Popen(['file','-b','--mime',fname], shell=False, stdout=PIPE) - (result, _) = pop.communicate() - - mime2 = result.split(';')[0] - _logger.debug('File gives us: %s', mime2) - # Note that the temporary file still exists now. - mime,fobj = mime_match(mime2, self.mimes) - if not mime: - mime = mime2 - except Exception: - _logger.info('Cannot determine mime type.', exc_info=True) - - try: - if fobj: - res = (mime, fobj.indexContent(content,filename,fname or realfname) ) - else: - _logger.debug("Have no object, return (%s, None).", mime) - res = (mime, '') - except Exception: - _logger.info("Cannot index file %s (%s).", - filename, fname or realfname, exc_info=True) - res = (mime, '') - - # If we created a tmp file, unlink it now - if not realfname and fname: - try: - os.unlink(fname) - except Exception: - _logger.exception("Cannot unlink %s.", fname) - return res - -cntIndex = contentIndex() diff --git a/addons/document/doc/access_permissions.rst b/addons/document/doc/access_permissions.rst deleted file mode 100644 index 2cdc45dadabe06cc732fec5abc6b4470cbc22783..0000000000000000000000000000000000000000 --- a/addons/document/doc/access_permissions.rst +++ /dev/null @@ -1,65 +0,0 @@ -Access control in the Document Management system -================================================ - -The purpose is to let the DMS act as a real-life management system for -the file handling of some small business. -The key concept, there, is the separation of access according to users -and groups. - -Fact 1: Users, in general, must NOT see each other's documents, not even -their names (because they usually imply sensitive data, like eg. a doc: -"Acme Company's Patent 012356 about fooobars.odf" ) -Fact 2: Users, sometimes, fail to comprehend complex ACL schemes, so we -owe to keep things simple, a main principle applied all over the place. -Fact 3: our system has both statically placed files and directories, as -well as dynamic (aka "resources" in our terminology) nodes. - -We allow/limit the access based on 3 factors (fields): - - The "owner" field, which holds the user that created or "owns" the - file or directory. - - The "group_ids" field, on directories, which specifieds group-wise - access - - The "company_id" field, for multi-company access rules [1] - -[1] at multi-company setups, we may want the same file hierarchy to apply -to different companies, and also nodes to be company-specific in it. - -Principle of "owner" ----------------------- -Files or directories that have an empty "owner" field are public. All users -will be able to _read_ them. Only the OpenERP Administrator or specified -groups, however, will be able to modify them! -Files or directories that have an "owner" are private. Only their users will -be able to read or modify (including delete) them. -By default, all user's files are created with "owner" field set, thus private. - -Principle of "group_ids" -------------------------- -Directories that have any group ids set will only (apart from their owner) -allow members of these groups to read them. -Directories that are created into the above directories will initially inherit -(that is, copy) the group_ids of their parents, so that they also allow -access to the same users. - -Implementation note ---------------------- -Most of the principles are applied through record rules (see ir.rule object), -so an administrator can actually readjust them. -In order to have logical "areas" of folders, where different policies apply -(like group folders, personal areas), default values for directories' owners -and group_ids can be tuned (through the 'set default' functionality of -fields). - -Summary --------- - -Table of permissions and behavior - -|| Type | Owner set | Groups set | Description || -|| Public | - | - | Public-readable folders, admin can write || -|| Group | - | X | Group can read, write, delete in them || -|| Group-read | X | X | Group can read[2], owner can write/delete || -|| Private | X | - | Only owner can read, write, delete in. || - -[2] hint: using a wide group, like "Internal users" at this setup creates the - effect of public-readable folders, with write permission to a non-admin user. diff --git a/addons/document/document.py b/addons/document/document.py deleted file mode 100644 index 61d07feeeccb04280b777eb05233922838dc0784..0000000000000000000000000000000000000000 --- a/addons/document/document.py +++ /dev/null @@ -1,2092 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. -import base64 -import errno -import logging -import os -import random -import shutil -import string -import time -from StringIO import StringIO - -import psycopg2 - -import openerp -from openerp import tools -from openerp import SUPERUSER_ID -from openerp.osv import fields, osv -from openerp.exceptions import UserError, AccessError, ValidationError -import openerp.report.interface -from openerp.tools.misc import ustr -from openerp.tools.translate import _ -from openerp.tools.safe_eval import safe_eval - -from content_index import cntIndex - -_logger = logging.getLogger(__name__) - -class document_file(osv.osv): - _inherit = 'ir.attachment' - - def _index(self, cr, uid, bin_data, datas_fname, mimetype): - """ - Override the parent method to use the indexer of document module to find the index_content. - It is called from _set_data, when the data changed. - """ - mime, icont = cntIndex.doIndex(bin_data, datas_fname, mimetype or None, None) - icont_u = ustr(icont) - return icont_u - - _columns = { - # Columns from ir.attachment: - 'write_date': fields.datetime('Date Modified', readonly=True), - 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True), - # Fields of document: - 'user_id': fields.many2one('res.users', 'Owner', select=1), - 'parent_id': fields.many2one('document.directory', 'Directory', select=1, change_default=True), - 'partner_id':fields.many2one('res.partner', 'Partner', select=1), - } - _order = "id desc" - - _defaults = { - 'user_id': lambda self, cr, uid, ctx:uid, - } - - _sql_constraints = [ - ('filename_unique', 'unique (name,parent_id)', 'The filename must be unique in a directory !'), - ] - - def check(self, cr, uid, ids, mode, context=None, values=None): - """Overwrite check to verify access on directory to validate specifications of doc/access_permissions.rst""" - if not isinstance(ids, list): - ids = [ids] - - super(document_file, self).check(cr, uid, ids, mode, context=context, values=values) - - if ids: - self.pool.get('ir.model.access').check(cr, uid, 'document.directory', mode) - - # use SQL to avoid recursive loop on read - cr.execute('SELECT DISTINCT parent_id from ir_attachment WHERE id in %s AND parent_id is not NULL', (tuple(ids),)) - self.pool.get('document.directory').check_access_rule(cr, uid, [parent_id for (parent_id,) in cr.fetchall()], mode, context=context) - - def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): - # Grab ids, bypassing 'count' - ids = super(document_file, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=False) - if not ids: - return 0 if count else [] - # Filter out documents that are in directories that the user is not allowed to read. - # Must use pure SQL to avoid access rules exceptions (we want to remove the records, - # not fail), and the records have been filtered in parent's search() anyway. - cr.execute('SELECT id, parent_id from ir_attachment WHERE id in %s', (tuple(ids),)) - - # cont a dict of parent -> attach - parents = {} - for attach_id, attach_parent in cr.fetchall(): - parents.setdefault(attach_parent, []).append(attach_id) - parent_ids = parents.keys() - - # filter parents - visible_parent_ids = self.pool.get('document.directory').search(cr, uid, [('id', 'in', list(parent_ids))]) - - # null parents means allowed - orig_ids = ids # save the ids, to keep order - ids = parents.get(None,[]) - for parent_id in visible_parent_ids: - ids.extend(parents[parent_id]) - - # sort result according to the original sort ordering - if count: - return len(ids) - else: - set_ids = set(ids) - return [id for id in orig_ids if id in set_ids] - - def copy(self, cr, uid, id, default=None, context=None): - if not default: - default = {} - if 'name' not in default: - name = self.read(cr, uid, [id], ['name'])[0]['name'] - default.update(name=_("%s (copy)") % (name)) - return super(document_file, self).copy(cr, uid, id, default, context=context) - - def create(self, cr, uid, vals, context=None): - if context is None: - context = {} - vals['parent_id'] = context.get('parent_id', False) or vals.get('parent_id', False) - # take partner from uid - if vals.get('res_id', False) and vals.get('res_model', False) and not vals.get('partner_id', False): - vals['partner_id'] = self.__get_partner_id(cr, uid, vals['res_model'], vals['res_id'], context) - return super(document_file, self).create(cr, uid, vals, context) - - def write(self, cr, uid, ids, vals, context=None): - if context is None: - context = {} - return super(document_file, self).write(cr, uid, ids, vals, context) - - def __get_partner_id(self, cr, uid, res_model, res_id, context=None): - """ A helper to retrieve the associated partner from any res_model+id - It is a hack that will try to discover if the mentioned record is - clearly associated with a partner record. - """ - obj_model = self.pool[res_model] - if obj_model._name == 'res.partner': - return res_id - elif 'partner_id' in obj_model._columns and obj_model._columns['partner_id']._obj == 'res.partner': - bro = obj_model.browse(cr, uid, res_id, context=context) - return bro.partner_id.id - return False - -class document_directory(osv.osv): - _name = 'document.directory' - _description = 'Directory' - _order = 'name' - _columns = { - 'name': fields.char('Name', required=True, select=1), - 'write_date': fields.datetime('Date Modified', readonly=True), - 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True), - 'create_date': fields.datetime('Date Created', readonly=True), - 'create_uid': fields.many2one('res.users', 'Creator', readonly=True), - 'user_id': fields.many2one('res.users', 'Owner'), - 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'), - 'parent_id': fields.many2one('document.directory', 'Parent Directory', select=1, change_default=True), - 'child_ids': fields.one2many('document.directory', 'parent_id', 'Children'), - 'file_ids': fields.one2many('ir.attachment', 'parent_id', 'Files'), - 'content_ids': fields.one2many('document.directory.content', 'directory_id', 'Virtual Files'), - 'type': fields.selection([ ('directory','Static Directory'), ('ressource','Folders per resource'), ], - 'Type', required=True, select=1, change_default=True, - help="Each directory can either have the type Static or be linked to another resource. A static directory, as with Operating Systems, is the classic directory that can contain a set of files. The directories linked to systems resources automatically possess sub-directories for each of resource types defined in the parent directory."), - 'domain': fields.char('Domain', help="Use a domain if you want to apply an automatic filter on visible resources."), - 'ressource_type_id': fields.many2one('ir.model', 'Resource model', change_default=True, - 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', - 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', change_default=True, - help="If you put an object here, this directory template will appear bellow all of these objects. " \ - "Such directories are \"attached\" to the specific model or record, just like attachments. " \ - "Don't put a parent directory if you select a parent model."), - 'ressource_id': fields.integer('Resource ID', - help="Along with Parent Model, this ID attaches this folder to a specific record of Parent Model."), - 'ressource_tree': fields.boolean('Tree Structure', - help="Check this if you want to use the same tree structure as the object selected in the system."), - 'dctx_ids': fields.one2many('document.directory.dctx', 'dir_id', 'Context fields'), - 'company_id': fields.many2one('res.company', 'Company', change_default=True), - } - - _defaults = { - 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'document.directory', context=c), - 'user_id': lambda self,cr,uid,ctx: uid, - 'domain': '[]', - 'type': 'directory', - 'ressource_id': 0, - 'resource_find_all': True, - } - _sql_constraints = [ - ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !'), - ('no_selfparent', 'check(parent_id <> id)', 'Directory cannot be parent of itself!'), - ] - def name_get(self, cr, uid, ids, context=None): - res = [] - if not self.search(cr,uid,[('id','in',ids)]): - ids = [] - for d in self.browse(cr, uid, ids, context=context): - s = '' - d2 = d - while d2 and d2.parent_id: - s = d2.name + (s and ('/' + s) or '') - d2 = d2.parent_id - res.append((d.id, s or d.name)) - return res - - def get_full_path(self, cr, uid, dir_id, context=None): - """ Return the full path to this directory, in a list, root first - """ - if isinstance(dir_id, (tuple, list)): - assert len(dir_id) == 1 - dir_id = dir_id[0] - - def _parent(dir_id, path): - parent=self.browse(cr, uid, dir_id) - if parent.parent_id and not parent.ressource_parent_type_id: - _parent(parent.parent_id.id,path) - path.append(parent.name) - else: - path.append(parent.name) - return path - path = [] - _parent(dir_id, path) - return path - - _constraints = [ - (osv.osv._check_recursion, 'Error! You cannot create recursive directories.', ['parent_id']) - ] - - def onchange_content_id(self, cr, uid, ids, ressource_type_id): - return {} - - def get_object(self, cr, uid, uri, context=None): - """ Return a node object for the given uri. - This fn merely passes the call to node_context - """ - return get_node_context(cr, uid, context).get_uri(cr, uri) - - def get_node_class(self, cr, uid, ids, dbro=None, dynamic=False, context=None): - """Retrieve the class of nodes for this directory - - This function can be overriden by inherited classes ;) - @param dbro The browse object, if caller already has it - """ - if dbro is None: - dbro = self.browse(cr, uid, ids, context=context) - - if dynamic: - return node_res_obj - elif dbro.type == 'directory': - return node_dir - elif dbro.type == 'ressource': - return node_res_dir - else: - raise ValueError("dir node for %s type.", dbro.type) - - def _prepare_context(self, cr, uid, nctx, context=None): - """ Fill nctx with properties for this database - @param nctx instance of nodes.node_context, to be filled - @param context ORM context (dict) for us - - Note that this function is called *without* a list of ids, - it should behave the same for the whole database (based on the - ORM instance of document.directory). - - Some databases may override this and attach properties to the - node_context. See WebDAV, CalDAV. - """ - return - - def get_dir_permissions(self, cr, uid, ids, context=None): - """Check what permission user 'uid' has on directory 'id' - """ - assert len(ids) == 1 - - res = 0 - for pperms in [('read', 5), ('write', 2), ('unlink', 8)]: - try: - self.check_access_rule(cr, uid, ids, pperms[0], context=context) - res |= pperms[1] - except AccessError: - pass - return res - - def _locate_child(self, cr, uid, root_id, uri, nparent, ncontext): - """ try to locate the node in uri, - Return a tuple (node_dir, remaining_path) - """ - return (node_database(context=ncontext), uri) - - def copy(self, cr, uid, id, default=None, context=None): - if not default: - default ={} - name = self.read(cr, uid, [id])[0]['name'] - default.update(name=_("%s (copy)") % (name)) - return super(document_directory,self).copy(cr, uid, id, default, context=context) - - def _check_duplication(self, cr, uid, vals, ids=None, op='create'): - name=vals.get('name',False) - parent_id=vals.get('parent_id',False) - ressource_parent_type_id=vals.get('ressource_parent_type_id',False) - ressource_id=vals.get('ressource_id',0) - if op=='write': - for directory in self.browse(cr, SUPERUSER_ID, ids): - if not name: - name=directory.name - if not parent_id: - parent_id=directory.parent_id and directory.parent_id.id or False - # TODO fix algo - if not ressource_parent_type_id: - ressource_parent_type_id=directory.ressource_parent_type_id and directory.ressource_parent_type_id.id or False - if not ressource_id: - ressource_id=directory.ressource_id and directory.ressource_id or 0 - res=self.search(cr,uid,[('id','<>',directory.id),('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)]) - if len(res): - return False - if op=='create': - res = self.search(cr, SUPERUSER_ID, [('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)]) - if len(res): - return False - return True - - def write(self, cr, uid, ids, vals, context=None): - if not self._check_duplication(cr, uid, vals, ids, op='write'): - raise ValidationError(_('Directory name must be unique!')) - return super(document_directory,self).write(cr, uid, ids, vals, context=context) - - def create(self, cr, uid, vals, context=None): - if not self._check_duplication(cr, uid, vals): - raise ValidationError(_('Directory name must be unique!')) - newname = vals.get('name',False) - if newname: - for illeg in ('/', '@', '$', '#'): - if illeg in newname: - raise ValidationError(_('Directory name contains special characters!')) - return super(document_directory,self).create(cr, uid, vals, context) - -class document_directory_dctx(osv.osv): - """ In order to evaluate dynamic folders, child items could have a limiting - domain expression. For that, their parents will export a context where useful - information will be passed on. - If you define sth like "s_id" = "this.id" at a folder iterating over sales, its - children could have a domain like [('sale_id', = ,s_id )] - This system should be used recursively, that is, parent dynamic context will be - appended to all children down the tree. - """ - _name = 'document.directory.dctx' - _description = 'Directory Dynamic Context' - _columns = { - 'dir_id': fields.many2one('document.directory', 'Directory', required=True, ondelete="cascade"), - 'field': fields.char('Field', required=True, select=1, help="The name of the field."), - 'expr': fields.char('Expression', required=True, help="A python expression used to evaluate the field.\n" + \ - "You can use 'dir_id' for current dir, 'res_id', 'res_model' as a reference to the current record, in dynamic folders"), - } - -class document_directory_content_type(osv.osv): - _name = 'document.directory.content.type' - _description = 'Directory Content Type' - _columns = { - 'name': fields.char('Content Type', required=True), - 'code': fields.char('Extension', size=4), - 'active': fields.boolean('Active'), - 'mimetype': fields.char('Mime Type') - } - _defaults = { - 'active': lambda *args: 1 - } - -class document_directory_content(osv.osv): - _name = 'document.directory.content' - _description = 'Directory Content' - _order = "sequence" - - def _extension_get(self, cr, uid, context=None): - cr.execute('select code,name from document_directory_content_type where active') - res = cr.fetchall() - return res - - _columns = { - 'name': fields.char('Content Name', required=True), - 'sequence': fields.integer('Sequence', size=16), - 'prefix': fields.char('Prefix', size=16), - '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 to contain the record name." \ - "\nIf set, the directory will have to be a resource one."), - 'directory_id': fields.many2one('document.directory', 'Directory'), - } - _defaults = { - 'extension': lambda *args: '.pdf', - 'sequence': lambda *args: 1, - 'include_name': lambda *args: 1, - } - - def _file_get(self, cr, node, nodename, content, context=None): - """ return the nodes of a <node> parent having a <content> content - The return value MUST be false or a list of node_class objects. - """ - - # TODO: respect the context! - model = node.res_model - if content.include_name and not model: - return False - - res2 = [] - tname = '' - if content.include_name: - record_name = node.displayname or '' - if record_name: - tname = (content.prefix or '') + record_name + (content.suffix or '') + (content.extension or '') - else: - tname = (content.prefix or '') + (content.name 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['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 = node_content(tname, node, node.context,content, act_id=act_id) - res2.append( n) - else: - if nodename == tname: - n = node_content(tname, node, node.context,content, act_id=act_id) - n.fill_fields(cr) - res2.append(n) - return res2 - - def process_write(self, cr, uid, node, data, context=None): - if node.extension != '.pdf': - raise Exception("Invalid content: %s" % node.extension) - return True - - def process_read(self, cr, uid, node, context=None): - if node.extension != '.pdf': - raise Exception("Invalid content: %s" % node.extension) - report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.report_id, context=context) - srv = openerp.report.interface.report_int._reports['report.'+report.report_name] - ctx = node.context.context.copy() - ctx.update(node.dctx) - pdf,pdftype = srv.create(cr, uid, [node.act_id,], {}, context=ctx) - return pdf - -class ir_action_report_xml(osv.osv): - _name="ir.actions.report.xml" - _inherit ="ir.actions.report.xml" - - def _model_get(self, cr, uid, ids, name, arg, context=None): - res = {} - model_pool = self.pool.get('ir.model') - for data in self.read(cr, uid, ids, ['model']): - model = data.get('model',False) - if model: - model_id =model_pool.search(cr, uid, [('model','=',model)]) - if model_id: - res[data.get('id')] = model_id[0] - else: - res[data.get('id')] = False - return res - - def _model_search(self, cr, uid, obj, name, args, context=None): - if not len(args): - return [] - assert len(args) == 1 and args[0][1] == '=', 'expression is not what we expect: %r' % args - model_id= args[0][2] - if not model_id: - # a deviation from standard behavior: when searching model_id = False - # we return *all* reports, not just ones with empty model. - # One reason is that 'model' is a required field so far - return [] - model = self.pool.get('ir.model').read(cr, uid, [model_id])[0]['model'] - report_id = self.search(cr, uid, [('model','=',model)]) - if not report_id: - return [('id','=','0')] - return [('id','in',report_id)] - - _columns={ - 'model_id' : fields.function(_model_get, fnct_search=_model_search, string='Model Id'), - } - -class document_storage(osv.osv): - """ The primary object for data storage. Deprecated. """ - _name = 'document.storage' - _description = 'Storage Media' - - def get_data(self, cr, uid, id, file_node, context=None, fil_obj=None): - """ retrieve the contents of some file_node having storage_id = id - optionally, fil_obj could point to the browse object of the file - (ir.attachment) - """ - boo = self.browse(cr, uid, id, context=context) - if fil_obj: - ira = fil_obj - else: - ira = self.pool.get('ir.attachment').browse(cr, uid, file_node.file_id, context=context) - data = ira.datas - if data: - out = data.decode('base64') - else: - out = '' - return out - - def get_file(self, cr, uid, id, file_node, mode, context=None): - """ Return a file-like object for the contents of some node - """ - if context is None: - context = {} - boo = self.browse(cr, uid, id, context=context) - - ira = self.pool.get('ir.attachment').browse(cr, uid, file_node.file_id, context=context) - return nodefd_db(file_node, ira_browse=ira, mode=mode) - - def set_data(self, cr, uid, id, file_node, data, context=None, fil_obj=None): - """ store the data. - This function MUST be used from an ir.attachment. It wouldn't make sense - to store things persistently for other types (dynamic). - """ - boo = self.browse(cr, uid, id, context=context) - if fil_obj: - ira = fil_obj - else: - ira = self.pool.get('ir.attachment').browse(cr, uid, file_node.file_id, context=context) - - _logger.debug( "Store data for ir.attachment #%d." % ira.id) - store_fname = None - fname = None - filesize = len(data) - self.pool.get('ir.attachment').write(cr, uid, [file_node.file_id], {'datas': data.encode('base64')}, context=context) - # 2nd phase: store the metadata - try: - icont = '' - mime = ira.mimetype - if not mime: - mime = "" - try: - mime, icont = cntIndex.doIndex(data, ira.datas_fname, ira.mimetype or None, fname) - except Exception: - _logger.debug('Cannot index file.', exc_info=True) - pass - try: - icont_u = ustr(icont) - except UnicodeError: - icont_u = '' - # a hack: /assume/ that the calling write operation will not try - # to write the fname and size, and update them in the db concurrently. - # We cannot use a write() here, because we are already in one. - cr.execute('UPDATE ir_attachment SET file_size = %s, index_content = %s, mimetype = %s WHERE id = %s', (filesize, icont_u, mime, file_node.file_id)) - self.pool.get('ir.attachment').invalidate_cache(cr, uid, ['file_size', 'index_content', 'mimetype'], [file_node.file_id], context=context) - file_node.content_length = filesize - file_node.content_type = mime - return True - except Exception, e : - _logger.info("Cannot save data.", exc_info=True) - # should we really rollback once we have written the actual data? - # at the db case (only), that rollback would be safe - raise UserError(ustr(e)) - -def _str2time(cre): - """ Convert a string with time representation (from db) into time (float) - - Note: a place to fix if datetime is used in db. - """ - if not cre: - return time.time() - frac = 0.0 - if isinstance(cre, basestring) and '.' in cre: - fdot = cre.find('.') - frac = float(cre[fdot:]) - cre = cre[:fdot] - return time.mktime(time.strptime(cre,'%Y-%m-%d %H:%M:%S')) + frac - -def get_node_context(cr, uid, context): - return node_context(cr, uid, context) - -# -# An object that represent an uri -# path: the uri of the object -# content: the Content it belongs to (_print.pdf) -# type: content or collection -# content: objct = res.partner -# collection: object = directory, object2 = res.partner -# file: objct = ir.attachement -# root: if we are at the first directory of a ressource -# - -class node_context(object): - """ This is the root node, representing access to some particular context - - A context is a set of persistent data, which may influence the structure - of the nodes. All other transient information during a data query should - be passed down with function arguments. - """ - cached_roots = {} - node_file_class = None - - def __init__(self, cr, uid, context=None): - self.dbname = cr.dbname - self.uid = uid - self.context = context - if context is None: - context = {} - context['uid'] = uid - self._dirobj = openerp.registry(cr.dbname).get('document.directory') - self.node_file_class = node_file - self.extra_ctx = {} # Extra keys for context, that do _not_ trigger inequality - assert self._dirobj - self._dirobj._prepare_context(cr, uid, self, context=context) - self.rootdir = False #self._dirobj._get_root_directory(cr,uid,context) - - def __eq__(self, other): - if not type(other) == node_context: - return False - if self.dbname != other.dbname: - return False - if self.uid != other.uid: - return False - if self.context != other.context: - return False - if self.rootdir != other.rootdir: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def get(self, name, default=None): - return self.context.get(name, default) - - def get_uri(self, cr, uri): - """ Although this fn passes back to doc.dir, it is needed since - it is a potential caching point. - """ - (ndir, duri) = self._dirobj._locate_child(cr, self.uid, self.rootdir, uri, None, self) - while duri: - ndir = ndir.child(cr, duri[0]) - if not ndir: - return False - duri = duri[1:] - return ndir - - def get_dir_node(self, cr, dbro): - """Create (or locate) a node for a directory - @param dbro a browse object of document.directory - """ - - fullpath = dbro.get_full_path(context=self.context) - klass = dbro.get_node_class(dbro, context=self.context) - return klass(fullpath, None ,self, dbro) - - def get_file_node(self, cr, fbro): - """ Create or locate a node for a static file - @param fbro a browse object of an ir.attachment - """ - parent = None - if fbro.parent_id: - parent = self.get_dir_node(cr, fbro.parent_id) - - return self.node_file_class(fbro.name, parent, self, fbro) - -class node_class(object): - """ this is a superclass for our inodes - It is an API for all code that wants to access the document files. - Nodes have attributes which contain usual file properties - """ - our_type = 'baseclass' - DAV_PROPS = None - DAV_M_NS = None - - def __init__(self, path, parent, context): - assert isinstance(context,node_context) - assert (not parent ) or isinstance(parent,node_class) - self.path = path - self.context = context - self.type=self.our_type - self.parent = parent - self.uidperms = 5 # computed permissions for our uid, in unix bits - self.mimetype = 'application/octet-stream' - self.create_date = None - self.write_date = None - self.unixperms = 0660 - self.uuser = 'user' - self.ugroup = 'group' - self.content_length = 0 - # dynamic context: - self.dctx = {} - if parent: - self.dctx = parent.dctx.copy() - self.displayname = 'Object' - - def __eq__(self, other): - return NotImplemented - - def __ne__(self, other): - return not self.__eq__(other) - - def full_path(self): - """ Return the components of the full path for some - node. - The returned list only contains the names of nodes. - """ - if self.parent: - s = self.parent.full_path() - else: - s = [] - if isinstance(self.path,list): - s+=self.path - elif self.path is None: - s.append('') - else: - s.append(self.path) - return s #map(lambda x: '/' +x, s) - - def __repr__(self): - return "%s@/%s" % (self.our_type, '/'.join(self.full_path())) - - def children(self, cr, domain=None): - print "node_class.children()" - return [] #stub - - def child(self, cr, name, domain=None): - print "node_class.child()" - return None - - def get_uri(self, cr, uri): - duri = uri - ndir = self - while duri: - ndir = ndir.child(cr, duri[0]) - if not ndir: - return False - duri = duri[1:] - return ndir - - def path_get(self): - print "node_class.path_get()" - return False - - def get_data(self, cr): - raise TypeError('No data for %s.'% self.type) - - def open_data(self, cr, mode): - """ Open a node_descriptor object for this node. - - @param the mode of open, eg 'r', 'w', 'a', like file.open() - - This operation may lock the data for this node (and accross - other node hierarchies), until the descriptor is close()d. If - the node is locked, subsequent opens (depending on mode) may - immediately fail with an exception (which?). - For this class, there is no data, so no implementation. Each - child class that has data should override this. - """ - raise TypeError('No data for %s.' % self.type) - - def get_etag(self, cr): - """ Get a tag, unique per object + modification. - - see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """ - return '"%s-%s"' % (self._get_ttag(cr), self._get_wtag(cr)) - - def _get_wtag(self, cr): - """ Return the modification time as a unique, compact string """ - return str(_str2time(self.write_date)).replace('.','') - - def _get_ttag(self, cr): - """ Get a unique tag for this type/id of object. - Must be overriden, so that each node is uniquely identified. - """ - print "node_class.get_ttag()",self - raise NotImplementedError("get_ttag stub()") - - def get_dav_props(self, cr): - """ If this class has special behaviour for GroupDAV etc, export - its capabilities """ - # This fn is placed here rather than WebDAV, because we want the - # baseclass methods to apply to all node subclasses - return self.DAV_PROPS or {} - - def match_dav_eprop(self, cr, match, ns, prop): - res = self.get_dav_eprop(cr, ns, prop) - if res == match: - return True - return False - - def get_dav_eprop(self, cr, ns, prop): - if not self.DAV_M_NS: - return None - - if self.DAV_M_NS.has_key(ns): - prefix = self.DAV_M_NS[ns] - else: - _logger.debug('No namespace: %s ("%s").',ns, prop) - return None - - mname = prefix + "_" + prop.replace('-','_') - - if not hasattr(self, mname): - return None - - try: - m = getattr(self, mname) - r = m(cr) - return r - except AttributeError: - _logger.debug('The property %s is not supported.' % prop, exc_info=True) - return None - - def get_dav_resourcetype(self, cr): - """ Get the DAV resource type. - - Is here because some nodes may exhibit special behaviour, like - CalDAV/GroupDAV collections - """ - raise NotImplementedError - - def move_to(self, cr, ndir_node, new_name=False, fil_obj=None, ndir_obj=None, in_write=False): - """ Move this node to a new parent directory. - @param ndir_node the collection that this node should be moved under - @param new_name a name to rename this node to. If omitted, the old - name is preserved - @param fil_obj, can be None, is the browse object for the file, - if already available. - @param ndir_obj must be the browse object to the new doc.directory - location, where this node should be moved to. - in_write: When called by write(), we shouldn't attempt to write the - object, but instead return the dict of vals (avoid re-entrance). - If false, we should write all data to the object, here, as if the - caller won't do anything after calling move_to() - - Return value: - True: the node is moved, the caller can update other values, too. - False: the node is either removed or fully updated, the caller - must discard the fil_obj, not attempt to write any more to it. - dict: values to write back to the object. *May* contain a new id! - - Depending on src and target storage, implementations of this function - could do various things. - Should also consider node<->content, dir<->dir moves etc. - - Move operations, as instructed from APIs (e.g. request from DAV) could - use this function. - """ - raise NotImplementedError(repr(self)) - - def create_child(self, cr, path, data=None): - """ Create a regular file under this node - """ - _logger.info("Attempted to create a file under %r, not possible.", self) - raise IOError(errno.EPERM, "Not allowed to create file(s) here.") - - def create_child_collection(self, cr, objname): - """ Create a child collection (directory) under self - """ - _logger.info("Attempted to create a collection under %r, not possible.", self) - raise IOError(errno.EPERM, "Not allowed to create folder(s) here.") - - def rm(self, cr): - raise NotImplementedError(repr(self)) - - def rmcol(self, cr): - raise NotImplementedError(repr(self)) - - def get_domain(self, cr, filters): - # TODO Document - return [] - - def check_perms(self, perms): - """ Check the permissions of the current node. - - @param perms either an integers of the bits to check, or - a string with the permission letters - - Permissions of nodes are (in a unix way): - 1, x : allow descend into dir - 2, w : allow write into file, or modification to dir - 4, r : allow read of file, or listing of dir contents - 8, u : allow remove (unlink) - """ - - if isinstance(perms, str): - pe2 = 0 - chars = { 'x': 1, 'w': 2, 'r': 4, 'u': 8 } - for c in perms: - pe2 = pe2 | chars[c] - perms = pe2 - elif isinstance(perms, int): - if perms < 0 or perms > 15: - raise ValueError("Invalid permission bits.") - else: - raise ValueError("Invalid permission attribute.") - - return ((self.uidperms & perms) == perms) - -class node_database(node_class): - """ A node representing the database directory - - """ - our_type = 'database' - def __init__(self, path=None, parent=False, context=None): - if path is None: - path = [] - super(node_database,self).__init__(path, parent, context) - self.unixperms = 040750 - self.uidperms = 5 - - def children(self, cr, domain=None): - res = self._child_get(cr, domain=domain) + self._file_get(cr) - return res - - def child(self, cr, name, domain=None): - res = self._child_get(cr, name, domain=None) - if res: - return res[0] - res = self._file_get(cr,name) - if res: - return res[0] - return None - - def _child_get(self, cr, name=False, domain=None): - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('parent_id','=', False), ('ressource_parent_type_id','=',False)] - if name: - where.append(('name','=',name)) - is_allowed = self.check_perms(1) - else: - is_allowed = self.check_perms(5) - - if not is_allowed: - raise IOError(errno.EPERM, "Permission into directory denied.") - - if domain: - where = where + domain - ids = dirobj.search(cr, uid, where, context=ctx) - res = [] - for dirr in dirobj.browse(cr, uid, ids, context=ctx): - klass = dirr.get_node_class(dirr, context=ctx) - res.append(klass(dirr.name, self, self.context,dirr)) - - return res - - def _file_get(self, cr, nodename=False): - res = [] - return res - - def _get_ttag(self, cr): - return 'db-%s' % cr.dbname - -def mkdosname(company_name, default='noname'): - """ convert a string to a dos-like name""" - if not company_name: - return default - badchars = ' !@#$%^`~*()+={}[];:\'"/?.<>' - n = '' - for c in company_name[:8]: - n += (c in badchars and '_') or c - return n - -def _uid2unixperms(perms, has_owner): - """ Convert the uidperms and the owner flag to full unix bits - """ - res = 0 - if has_owner: - res |= (perms & 0x07) << 6 - res |= (perms & 0x05) << 3 - elif perms & 0x02: - res |= (perms & 0x07) << 6 - res |= (perms & 0x07) << 3 - else: - res |= (perms & 0x07) << 6 - res |= (perms & 0x05) << 3 - res |= 0x05 - return res - -class node_dir(node_database): - our_type = 'collection' - def __init__(self, path, parent, context, dirr, dctx=None): - super(node_dir,self).__init__(path, parent,context) - self.dir_id = dirr and dirr.id or False - #todo: more info from dirr - self.mimetype = 'application/x-directory' - # 'httpd/unix-directory' - self.create_date = dirr and dirr.create_date or False - self.domain = dirr and dirr.domain or [] - self.res_model = dirr and dirr.ressource_type_id and dirr.ressource_type_id.model or False - # TODO: the write date should be MAX(file.write).. - self.write_date = dirr and (dirr.write_date or dirr.create_date) or False - self.content_length = 0 - try: - self.uuser = (dirr.user_id and dirr.user_id.login) or 'nobody' - except Exception: - self.uuser = 'nobody' - self.ugroup = mkdosname(dirr.company_id and dirr.company_id.name, default='nogroup') - self.uidperms = dirr.get_dir_permissions() - self.unixperms = 040000 | _uid2unixperms(self.uidperms, dirr and dirr.user_id) - if dctx: - self.dctx.update(dctx) - dc2 = self.context.context - dc2.update(self.dctx) - dc2['dir_id'] = self.dir_id - self.displayname = dirr and dirr.name or False - if dirr and dirr.dctx_ids: - for dfld in dirr.dctx_ids: - try: - self.dctx[dfld.field] = safe_eval(dfld.expr,dc2) - except Exception,e: - print "Cannot eval %s." % dfld.expr - print e - pass - - def __eq__(self, other): - if type(self) != type(other): - return False - if not self.context == other.context: - return False - # Two directory nodes, for the same document.directory, may have a - # different context! (dynamic folders) - if self.dctx != other.dctx: - return False - return self.dir_id == other.dir_id - - def get_data(self, cr): - #res = '' - #for child in self.children(cr): - # res += child.get_data(cr) - return None - - def _file_get(self, cr, nodename=False): - res = super(node_dir,self)._file_get(cr, nodename) - - is_allowed = self.check_perms(nodename and 1 or 5) - if not is_allowed: - raise IOError(errno.EPERM, "Permission into directory denied.") - - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr, uid, where, context=ctx) - for content in cntobj.browse(cr, uid, ids, context=ctx): - res3 = cntobj._file_get(cr, self, nodename, content) - if res3: - res.extend(res3) - - return res - - def _child_get(self, cr, name=None, domain=None): - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('parent_id','=',self.dir_id)] - if name: - where.append(('name','=',name)) - is_allowed = self.check_perms(1) - else: - is_allowed = self.check_perms(5) - - if not is_allowed: - raise IOError(errno.EPERM, "Permission into directory denied.") - - if not domain: - domain = [] - - where2 = where + domain + [('ressource_parent_type_id','=',False)] - ids = dirobj.search(cr, uid, where2, context=ctx) - res = [] - for dirr in dirobj.browse(cr, uid, ids, context=ctx): - klass = dirr.get_node_class(dirr, context=ctx) - res.append(klass(dirr.name, self, self.context,dirr)) - - # Static directories should never return files with res_model/res_id - # because static dirs are /never/ related to a record. - # In fact, files related to some model and parented by the root dir - # (the default), will NOT be accessible in the node system unless - # a resource folder for that model exists (with resource_find_all=True). - # Having resource attachments in a common folder is bad practice, - # because they would be visible to all users, and their names may be - # the same, conflicting. - where += [('res_model', '=', False)] - fil_obj = dirobj.pool.get('ir.attachment') - ids = fil_obj.search(cr, uid, where, context=ctx) - if ids: - for fil in fil_obj.browse(cr, uid, ids, context=ctx): - klass = self.context.node_file_class - res.append(klass(fil.name, self, self.context, fil)) - return res - - def rmcol(self, cr): - uid = self.context.uid - directory = self.context._dirobj.browse(cr, uid, self.dir_id) - res = False - if not directory: - raise OSError(2, 'Not such file or directory.') - if not self.check_perms('u'): - raise IOError(errno.EPERM,"Permission denied.") - - if directory._name == 'document.directory': - if self.children(cr): - raise OSError(39, 'Directory not empty.') - res = self.context._dirobj.unlink(cr, uid, [directory.id]) - else: - raise OSError(1, 'Operation is not permitted.') - return res - - def create_child_collection(self, cr, objname): - object2 = False - if not self.check_perms(2): - raise IOError(errno.EPERM,"Permission denied.") - - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - obj = dirobj.browse(cr, uid, self.dir_id) - if obj and (obj.type == 'ressource') and not object2: - raise OSError(1, 'Operation is not permitted.') - - #objname = uri2[-1] - val = { - 'name': objname, - 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, - 'ressource_id': object2 and object2.id or False, - 'parent_id' : obj and obj.id or False - } - - return dirobj.create(cr, uid, val) - - def create_child(self, cr, path, data=None): - """ API function to create a child file object and node - Return the node_* created - """ - if not self.check_perms(2): - raise IOError(errno.EPERM,"Permission denied.") - - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - fil_obj=dirobj.pool.get('ir.attachment') - val = { - 'name': path, - 'datas_fname': path, - 'parent_id': self.dir_id, - # Datas are not set here - } - - fil_id = fil_obj.create(cr, uid, val, context=ctx) - fil = fil_obj.browse(cr, uid, fil_id, context=ctx) - fnode = node_file(path, self, self.context, fil) - if data is not None: - fnode.set_data(cr, data, fil) - return fnode - - def _get_ttag(self, cr): - return 'dir-%d' % self.dir_id - - def move_to(self, cr, ndir_node, new_name=False, fil_obj=None, ndir_obj=None, in_write=False): - """ Move directory. This operation is simple, since the present node is - only used for static, simple directories. - Note /may/ be called with ndir_node = None, to rename the document root. - """ - if ndir_node and (ndir_node.context != self.context): - raise NotImplementedError("Cannot move directories between contexts.") - - if (not self.check_perms('u')) or (not ndir_node.check_perms('w')): - raise IOError(errno.EPERM,"Permission denied.") - - dir_obj = self.context._dirobj - if not fil_obj: - dbro = dir_obj.browse(cr, self.context.uid, self.dir_id, context=self.context.context) - else: - dbro = dir_obj - assert dbro.id == self.dir_id - - if not dbro: - raise IndexError("Cannot locate dir %d", self.dir_id) - - if (not self.parent) and ndir_node: - if not dbro.parent_id: - raise IOError(errno.EPERM, "Cannot move the root directory!") - self.parent = self.context.get_dir_node(cr, dbro.parent_id) - assert self.parent - - if self.parent != ndir_node: - _logger.debug('Cannot move dir %r from %r to %r.', self, self.parent, ndir_node) - raise NotImplementedError('Cannot move dir to another dir.') - - ret = {} - if new_name and (new_name != dbro.name): - if ndir_node.child(cr, new_name): - raise IOError(errno.EEXIST, "Destination path already exists.") - ret['name'] = new_name - - del dbro - - if not in_write: - # We have to update the data ourselves - if ret: - ctx = self.context.context.copy() - ctx['__from_node'] = True - dir_obj.write(cr, self.context.uid, [self.dir_id,], ret, ctx) - ret = True - - return ret - -class node_res_dir(node_class): - """ A folder containing dynamic folders - A special sibling to node_dir, which does only contain dynamically - created folders foreach resource in the foreign model. - All folders should be of type node_res_obj and merely behave like - node_dirs (with limited domain). - """ - our_type = 'collection' - res_obj_class = None - def __init__(self, path, parent, context, dirr, dctx=None ): - super(node_res_dir,self).__init__(path, parent, context) - self.dir_id = dirr.id - #todo: more info from dirr - self.mimetype = 'application/x-directory' - # 'httpd/unix-directory' - self.create_date = dirr.create_date - # TODO: the write date should be MAX(file.write).. - self.write_date = dirr.write_date or dirr.create_date - self.content_length = 0 - try: - self.uuser = (dirr.user_id and dirr.user_id.login) or 'nobody' - except Exception: - self.uuser = 'nobody' - self.ugroup = mkdosname(dirr.company_id and dirr.company_id.name, default='nogroup') - self.uidperms = dirr.get_dir_permissions() - self.unixperms = 040000 | _uid2unixperms(self.uidperms, dirr and dirr.user_id) - 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! - self.domain = dirr.domain - self.ressource_tree = dirr.ressource_tree - # and then, we add our own vars in the dctx: - if dctx: - self.dctx.update(dctx) - - # and then, we prepare a dctx dict, for deferred evaluation: - self.dctx_dict = {} - for dfld in dirr.dctx_ids: - self.dctx_dict[dfld.field] = dfld.expr - - def __eq__(self, other): - if type(self) != type(other): - return False - if not self.context == other.context: - return False - # Two nodes, for the same document.directory, may have a - # different context! (dynamic folders) - if self.dctx != other.dctx: - return False - return self.dir_id == other.dir_id - - def children(self, cr, domain=None): - return self._child_get(cr, domain=domain) - - def child(self, cr, name, domain=None): - res = self._child_get(cr, name, domain=domain) - if res: - return res[0] - return None - - def _child_get(self, cr, name=None, domain=None): - """ return virtual children of resource, based on the - foreign object. - - Note that many objects use NULL for a name, so we should - better call the name_search(),name_get() set of methods - """ - if self.res_model not in self.context._dirobj.pool: - return [] - obj = self.context._dirobj.pool[self.res_model] - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - ctx.update(self.context.extra_ctx) - where = [] - if self.domain: - app = safe_eval(self.domain, ctx) - if not app: - pass - elif isinstance(app, list): - where.extend(app) - elif isinstance(app, tuple): - where.append(app) - else: - raise RuntimeError("Incorrect domain expr: %s." % self.domain) - if self.resm_id: - where.append(('id','=',self.resm_id)) - - if name: - # The =like character will match underscores against any characters - # including the special ones that couldn't exist in a FTP/DAV request - where.append((self.namefield,'=like',name.replace('\\','\\\\'))) - is_allowed = self.check_perms(1) - else: - is_allowed = self.check_perms(5) - - if not is_allowed: - raise IOError(errno.EPERM,"Permission denied.") - - # print "Where clause for %s" % self.res_model, where - if self.ressource_tree: - object2 = False - if self.resm_id: - object2 = dirobj.pool[self.res_model].browse(cr, uid, self.resm_id) or False - if obj._parent_name in obj.fields_get(cr, uid): - where.append((obj._parent_name,'=',object2 and object2.id or False)) - - resids = obj.search(cr, uid, where, context=ctx) - res = [] - for bo in obj.browse(cr, uid, resids, context=ctx): - if not bo: - continue - res_name = getattr(bo, self.namefield) - if not res_name: - continue - # Yes! we can't do better but skip nameless records. - - # Escape the name for characters not supported in filenames - res_name = res_name.replace('/','_') # any other weird char? - - if name and (res_name != ustr(name)): - # we have matched _ to any character, but we only meant to match - # the special ones. - # Eg. 'a_c' will find 'abc', 'a/c', 'a_c', may only - # return 'a/c' and 'a_c' - continue - - res.append(self.res_obj_class(res_name, self.dir_id, self, self.context, self.res_model, bo)) - return res - - def _get_ttag(self, cr): - return 'rdir-%d' % self.dir_id - -class node_res_obj(node_class): - """ A dynamically created folder. - A special sibling to node_dir, which does only contain dynamically - created folders foreach resource in the foreign model. - All folders should be of type node_res_obj and merely behave like - node_dirs (with limited domain). - """ - our_type = 'collection' - def __init__(self, path, dir_id, parent, context, res_model, res_bo, res_id=None): - super(node_res_obj,self).__init__(path, parent,context) - assert parent - #todo: more info from dirr - self.dir_id = dir_id - self.mimetype = 'application/x-directory' - # 'httpd/unix-directory' - self.create_date = parent.create_date - # TODO: the write date should be MAX(file.write).. - self.write_date = parent.write_date - self.content_length = 0 - self.uidperms = parent.uidperms & 15 - self.unixperms = 040000 | _uid2unixperms(self.uidperms, True) - 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 - if isinstance(parent, node_res_dir): - self.res_find_all = parent.res_find_all - else: - self.res_find_all = False - if res_bo: - self.res_id = res_bo.id - dc2 = self.context.context.copy() - dc2.update(self.dctx) - dc2['res_model'] = res_model - dc2['res_id'] = res_bo.id - dc2['this'] = res_bo - for fld,expr in self.dctx_dict.items(): - try: - self.dctx[fld] = safe_eval(expr, dc2) - except Exception,e: - print "Cannot eval %s for %s." % (expr, fld) - print e - pass - else: - self.res_id = res_id - - def __eq__(self, other): - if type(self) != type(other): - return False - if not self.context == other.context: - return False - if not self.res_model == other.res_model: - return False - if not self.res_id == other.res_id: - 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 - - def children(self, cr, domain=None): - return self._child_get(cr, domain=domain) + self._file_get(cr) - - def child(self, cr, name, domain=None): - res = self._child_get(cr, name, domain=domain) - if res: - return res[0] - res = self._file_get(cr, name) - if res: - return res[0] - return None - - def _file_get(self, cr, nodename=False): - res = [] - is_allowed = self.check_perms((nodename and 1) or 5) - if not is_allowed: - raise IOError(errno.EPERM,"Permission denied.") - - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - #if self.domain: - # where.extend(self.domain) - # print "res_obj file_get clause", where - ids = cntobj.search(cr, uid, where, context=ctx) - for content in cntobj.browse(cr, uid, ids, context=ctx): - res3 = cntobj._file_get(cr, self, nodename, content, context=ctx) - if res3: - res.extend(res3) - - return res - - def get_dav_props_DEPR(self, cr): - # Deprecated! (but document_ics must be cleaned, first) - res = {} - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr, uid, where, context=ctx) - for content in cntobj.browse(cr, uid, ids, context=ctx): - if content.extension == '.ics': # FIXME: call the content class! - res['http://groupdav.org/'] = ('resourcetype',) - return res - - def get_dav_eprop_DEPR(self, cr, ns, prop): - # Deprecated! - if ns != 'http://groupdav.org/' or prop != 'resourcetype': - _logger.info("Who asks for %s:%s?", ns, prop) - return None - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr,uid,where,context=ctx) - for content in cntobj.browse(cr, uid, ids, context=ctx): - # TODO: remove relic of GroupDAV - if content.extension == '.ics': # FIXME: call the content class! - return ('vevent-collection','http://groupdav.org/') - return None - - def _child_get(self, cr, name=None, domain=None): - dirobj = self.context._dirobj - - is_allowed = self.check_perms((name and 1) or 5) - if not is_allowed: - raise IOError(errno.EPERM,"Permission denied.") - - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - directory = dirobj.browse(cr, uid, self.dir_id) - obj = dirobj.pool[self.res_model] - where = [] - res = [] - if name: - where.append(('name','=',name)) - - # Directory Structure display in tree structure - if self.res_id and directory.ressource_tree: - where1 = [] - if name: - where1.append(('name','=like',name.replace('\\','\\\\'))) - if obj._parent_name in obj.fields_get(cr, uid): - where1.append((obj._parent_name, '=', self.res_id)) - namefield = directory.resource_field.name or 'name' - resids = obj.search(cr, uid, where1, context=ctx) - for bo in obj.browse(cr, uid, resids, context=ctx): - if not bo: - continue - res_name = getattr(bo, namefield) - if not res_name: - continue - res_name = res_name.replace('/', '_') - if name and (res_name != ustr(name)): - continue - # TODO Revise - klass = directory.get_node_class(directory, dynamic=True, context=ctx) - rnode = klass(res_name, dir_id=self.dir_id, parent=self, context=self.context, - res_model=self.res_model, res_bo=bo) - rnode.res_find_all = self.res_find_all - res.append(rnode) - - - where2 = where + [('parent_id','=',self.dir_id) ] - ids = dirobj.search(cr, uid, where2, context=ctx) - bo = obj.browse(cr, uid, self.res_id, context=ctx) - - for dirr in dirobj.browse(cr, uid, ids, context=ctx): - if name and (name != dirr.name): - continue - if dirr.type == 'directory': - klass = dirr.get_node_class(dirr, dynamic=True, context=ctx) - res.append(klass(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = bo, res_id = self.res_id)) - elif dirr.type == 'ressource': - # child resources can be controlled by properly set dctx - klass = dirr.get_node_class(dirr, context=ctx) - res.append(klass(dirr.name,self,self.context, dirr, {'active_id': self.res_id})) # bo? - - 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", where3 - ids = fil_obj.search(cr, uid, where3, context=ctx) - if ids: - for fil in fil_obj.browse(cr, uid, ids, context=ctx): - klass = self.context.node_file_class - res.append(klass(fil.name, self, self.context, fil)) - - - # Get Child Ressource Directories - if directory.ressource_type_id and directory.ressource_type_id.id: - where4 = where + [('ressource_parent_type_id','=',directory.ressource_type_id.id)] - where5 = where4 + ['|', ('ressource_id','=',0), ('ressource_id','=',self.res_id)] - dirids = dirobj.search(cr,uid, where5) - for dirr in dirobj.browse(cr, uid, dirids, context=ctx): - if dirr.type == 'directory' and not dirr.parent_id: - klass = dirr.get_node_class(dirr, dynamic=True, context=ctx) - rnode = klass(dirr.name, dirr.id, self, self.context, self.res_model, res_bo = bo, res_id = self.res_id) - rnode.res_find_all = dirr.resource_find_all - res.append(rnode) - if dirr.type == 'ressource': - klass = dirr.get_node_class(dirr, context=ctx) - rnode = klass(dirr.name, self, self.context, dirr, {'active_id': self.res_id}) - rnode.res_find_all = dirr.resource_find_all - res.append(rnode) - return res - - def create_child_collection(self, cr, objname): - dirobj = self.context._dirobj - is_allowed = self.check_perms(2) - if not is_allowed: - raise IOError(errno.EPERM,"Permission denied.") - - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - res_obj = dirobj.pool[self.res_model] - - object2 = res_obj.browse(cr, uid, self.res_id) or False - - obj = dirobj.browse(cr, uid, self.dir_id) - if obj and (obj.type == 'ressource') and not object2: - raise OSError(1, 'Operation is not permitted.') - - - val = { - 'name': objname, - 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, - 'ressource_id': object2 and object2.id or False, - 'parent_id' : False, - 'resource_find_all': False, - } - if (obj and (obj.type in ('directory'))) or not object2: - val['parent_id'] = obj and obj.id or False - - return dirobj.create(cr, uid, val) - - def create_child(self, cr, path, data=None): - """ API function to create a child file object and node - Return the node_* created - """ - is_allowed = self.check_perms(2) - if not is_allowed: - raise IOError(errno.EPERM,"Permission denied.") - - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - fil_obj=dirobj.pool.get('ir.attachment') - val = { - 'name': path, - 'datas_fname': path, - '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) - klass = self.context.node_file_class - fnode = klass(path, self, self.context, fil) - if data is not None: - fnode.set_data(cr, data, fil) - return fnode - - def _get_ttag(self, cr): - return 'rodir-%d-%d' % (self.dir_id, self.res_id) - -node_res_dir.res_obj_class = node_res_obj - -class node_file(node_class): - our_type = 'file' - def __init__(self, path, parent, context, fil): - super(node_file,self).__init__(path, parent,context) - self.file_id = fil.id - #todo: more info from ir_attachment - if fil.mimetype and '/' in fil.mimetype: - self.mimetype = str(fil.mimetype) - self.create_date = fil.create_date - self.write_date = fil.write_date or fil.create_date - self.content_length = fil.file_size - self.displayname = fil.name - - self.uidperms = 14 - if parent: - if not parent.check_perms('x'): - self.uidperms = 0 - elif not parent.check_perms('w'): - self.uidperms = 4 - - try: - self.uuser = (fil.user_id and fil.user_id.login) or 'nobody' - except Exception: - self.uuser = 'nobody' - self.ugroup = mkdosname(fil.company_id and fil.company_id.name, default='nogroup') - - def __eq__(self, other): - if type(self) != type(other): - return False - if not self.context == other.context: - return False - if self.dctx != other.dctx: - return False - return self.file_id == other.file_id - - def open_data(self, cr, mode): - if not self.check_perms(4): - raise IOError(errno.EPERM, "Permission denied.") - - stobj = self.context._dirobj.pool.get('document.storage') - return stobj.get_file(cr, self.context.uid, None, self, mode=mode, context=self.context.context) - - def rm(self, cr): - uid = self.context.uid - if not self.check_perms(8): - raise IOError(errno.EPERM, "Permission denied.") - document_obj = self.context._dirobj.pool.get('ir.attachment') - if self.type in ('collection','database'): - return False - document = document_obj.browse(cr, uid, self.file_id, context=self.context.context) - res = False - if document and document._name == 'ir.attachment': - res = document_obj.unlink(cr, uid, [document.id]) - return res - - def fix_ppath(self, cr, fbro): - """Sometimes we may init this w/o path, parent. - This function fills the missing path from the file browse object - - Note: this may be an expensive operation, do on demand. However, - once caching is in, we might want to do that at init time and keep - this object anyway - """ - if self.path or self.parent: - return - assert fbro - uid = self.context.uid - - dirpath = [] - if fbro.parent_id: - dirobj = self.context._dirobj.pool.get('document.directory') - dirpath = dirobj.get_full_path(cr, uid, fbro.parent_id.id, context=self.context.context) - if fbro.datas_fname: - dirpath.append(fbro.datas_fname) - else: - dirpath.append(fbro.name) - - if len(dirpath)>1: - self.path = dirpath - else: - self.path = dirpath[0] - - def get_data(self, cr, fil_obj=None): - """ Retrieve the data for some file. - fil_obj may optionally be specified, and should be a browse object - for the file. This is useful when the caller has already initiated - the browse object. """ - if not self.check_perms(4): - raise IOError(errno.EPERM, "Permission denied.") - - stobj = self.context._dirobj.pool.get('document.storage') - return stobj.get_data(cr, self.context.uid, None, self,self.context.context, fil_obj) - - def get_data_len(self, cr, fil_obj=None): - bin_size = self.context.context.get('bin_size', False) - if bin_size and not self.content_length: - self.content_length = fil_obj.db_datas - return self.content_length - - def set_data(self, cr, data, fil_obj=None): - """ Store data at some file. - fil_obj may optionally be specified, and should be a browse object - for the file. This is useful when the caller has already initiated - the browse object. """ - if not self.check_perms(2): - raise IOError(errno.EPERM, "Permission denied.") - - stobj = self.context._dirobj.pool.get('document.storage') - return stobj.set_data(cr, self.context.uid, None, self, data, self.context.context, fil_obj) - - def _get_ttag(self, cr): - return 'file-%d' % self.file_id - - def move_to(self, cr, ndir_node, new_name=False, fil_obj=None, ndir_obj=None, in_write=False): - if ndir_node and ndir_node.context != self.context: - raise NotImplementedError("Cannot move files between contexts.") - - if (not self.check_perms(8)) and ndir_node.check_perms(2): - raise IOError(errno.EPERM, "Permission denied.") - - doc_obj = self.context._dirobj.pool.get('ir.attachment') - if not fil_obj: - dbro = doc_obj.browse(cr, self.context.uid, self.file_id, context=self.context.context) - else: - dbro = fil_obj - assert dbro.id == self.file_id, "%s != %s for %r." % (dbro.id, self.file_id, self) - - if not dbro: - raise IndexError("Cannot locate doc %d.", self.file_id) - - if (not self.parent): - # there *must* be a parent node for this one - self.parent = self.context.get_dir_node(cr, dbro.parent_id) - assert self.parent - - ret = {} - if ndir_node and self.parent != ndir_node: - if not (isinstance(self.parent, node_dir) and isinstance(ndir_node, node_dir)): - _logger.debug('Cannot move file %r from %r to %r.', self, self.parent, ndir_node) - raise NotImplementedError('Cannot move files between dynamic folders.') - - if not ndir_obj: - ndir_obj = self.context._dirobj.browse(cr, self.context.uid, \ - ndir_node.dir_id, context=self.context.context) - - assert ndir_obj.id == ndir_node.dir_id - - r2 = { 'parent_id': ndir_obj.id } - ret.update(r2) - - if new_name and (new_name != dbro.name): - if len(ret): - raise NotImplementedError("Cannot rename and move.") # TODO - r2 = { 'name': new_name, 'datas_fname': new_name } - ret.update(r2) - - del dbro - - if not in_write: - # We have to update the data ourselves - if ret: - ctx = self.context.context.copy() - ctx['__from_node'] = True - doc_obj.write(cr, self.context.uid, [self.file_id,], ret, ctx ) - ret = True - - return ret - -class node_content(node_class): - our_type = 'content' - def __init__(self, path, parent, context, cnt, dctx=None, act_id=None): - super(node_content,self).__init__(path, parent,context) - self.cnt_id = cnt.id - self.create_date = False - self.write_date = False - self.content_length = False - self.unixperms = 0640 - if parent: - self.uidperms = parent.uidperms & 14 - self.uuser = parent.uuser - self.ugroup = parent.ugroup - - self.extension = cnt.extension - self.report_id = cnt.report_id and cnt.report_id.id - #self.mimetype = cnt.extension. - self.displayname = path - if dctx: - self.dctx.update(dctx) - self.act_id = act_id - - def fill_fields(self, cr, dctx=None): - """ Try to read the object and fill missing fields, like mimetype, - dates etc. - This function must be different from the constructor, because - it uses the db cursor. - """ - - cr.execute('SELECT DISTINCT mimetype FROM document_directory_content_type WHERE active AND code = %s;', - (self.extension,)) - res = cr.fetchall() - if res and res[0][0]: - self.mimetype = str(res[0][0]) - - def get_data(self, cr, fil_obj=None): - cntobj = self.context._dirobj.pool.get('document.directory.content') - if not self.check_perms(4): - raise IOError(errno.EPERM, "Permission denied.") - - ctx = self.context.context.copy() - ctx.update(self.dctx) - data = cntobj.process_read(cr, self.context.uid, self, ctx) - if data: - 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 - - def set_data(self, cr, data, fil_obj=None): - cntobj = self.context._dirobj.pool.get('document.directory.content') - if not self.check_perms(2): - raise IOError(errno.EPERM, "Permission denied.") - - ctx = self.context.context.copy() - ctx.update(self.dctx) - return cntobj.process_write(cr, self.context.uid, self, data, ctx) - - def _get_ttag(self, cr): - return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '') - - def get_dav_resourcetype(self, cr): - return '' - -class node_descriptor(object): - """A file-like interface to the data contents of a node. - - This class is NOT a node, but an /open descriptor/ for some - node. It can hold references to a cursor or a file object, - because the life of a node_descriptor will be the open period - of the data. - It should also take care of locking, with any native mechanism - or using the db. - For the implementation, it would be OK just to wrap around file, - StringIO or similar class. The node_descriptor is only needed to - provide the link to the parent /node/ object. - """ - - def __init__(self, parent): - assert isinstance(parent, node_class) - self.name = parent.displayname - self.__parent = parent - - def _get_parent(self): - return self.__parent - - def open(self, **kwargs): - raise NotImplementedError - - def close(self): - raise NotImplementedError - - def read(self, size=None): - raise NotImplementedError - - def seek(self, offset, whence=None): - raise NotImplementedError - - def tell(self): - raise NotImplementedError - - def write(self, str): - raise NotImplementedError - - def size(self): - raise NotImplementedError - - def __len__(self): - return self.size() - - def __nonzero__(self): - """ Ensure that a node_descriptor will never equal False - - Since we do define __len__ and __iter__ for us, we must avoid - being regarded as non-true objects. - """ - return True - - def next(self, str): - raise NotImplementedError - -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 - self._size = 0L - - 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: - self._size = len(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: - _logger.info("Incorrect mode %s is specified.", mode) - raise IOError(errno.EINVAL, "Invalid file mode.") - self.mode = mode - - def size(self): - return self._size - - 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 = openerp.registry(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, par, data, par.context.context) - elif self.mode == 'a': - raise NotImplementedError - cr.commit() - except Exception: - _logger.info('Cannot update db content #%d for close.', par.cnt_id) - raise - finally: - cr.close() - StringIO.close(self) - -class nodefd_static(StringIO, node_descriptor): - """ A descriptor to nodes with static data. - """ - def __init__(self, parent, cr, mode, ctx=None): - node_descriptor.__init__(self, parent) - self._context=ctx - self._size = 0L - - if mode in ('r', 'r+'): - data = parent.get_data(cr) - if data: - self._size = len(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: - _logger.info("Incorrect mode %s is specified.", mode) - raise IOError(errno.EINVAL, "Invalid file mode.") - self.mode = mode - - def size(self): - return self._size - - 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 = openerp.registry(par.context.dbname).cursor() - try: - if self.mode in ('w', 'w+', 'r+'): - data = self.getvalue() - par.set_data(cr, data) - elif self.mode == 'a': - raise NotImplementedError - cr.commit() - except Exception: - _logger.info('Cannot update db content #%d for close.', par.cnt_id) - raise - finally: - cr.close() - StringIO.close(self) - -class nodefd_db(StringIO, node_descriptor): - """ A descriptor to db data - """ - def __init__(self, parent, ira_browse, mode): - node_descriptor.__init__(self, parent) - self._size = 0L - if mode.endswith('b'): - mode = mode[:-1] - - if mode in ('r', 'r+'): - data = ira_browse.datas - if data: - data = data.decode('base64') - self._size = 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: - _logger.info("Incorrect mode %s is specified.", mode) - raise IOError(errno.EINVAL, "Invalid file mode.") - self.mode = mode - - def size(self): - return self._size - - def close(self): - # we now open a *separate* cursor, to update the data. - # FIXME: this may be improved, for concurrency handling - par = self._get_parent() - # uid = par.context.uid - registry = openerp.modules.registry.RegistryManager.get(par.context.dbname) - with registry.cursor() as cr: - data = self.getvalue().encode('base64') - if self.mode in ('w', 'w+', 'r+'): - registry.get('ir.attachment').write(cr, 1, par.file_id, {'datas': data}) - cr.commit() - StringIO.close(self) diff --git a/addons/document/document_data.xml b/addons/document/document_data.xml deleted file mode 100644 index bd73b11359b6d2de4d6260c3ac7f0c322e618219..0000000000000000000000000000000000000000 --- a/addons/document/document_data.xml +++ /dev/null @@ -1,82 +0,0 @@ -<?xml version="1.0"?> -<openerp> -<data noupdate="1"> - <record model="document.directory" id="dir_root"> - <field name="name">Documents</field> - <field name="user_id" eval="False"/> - <field name="ressource_id">0</field> - </record> - - <record model="document.directory" id="dir_my_folder"> - <field name="name">Admin Folder</field> - <field name="parent_id" ref="dir_root"/> - <field name="user_id" ref="base.user_root"/> - <field name="ressource_id">0</field> - </record> -</data> - -<data noupdate="1"> - <record model="document.directory.content.type" id="pdf"> - <field name="code">.pdf</field> - <field name="name">PDF Report</field> - <field name="mimetype">application/pdf</field> - </record> - - <record model="document.directory" id="dir_partner"> - <field name="name">Partners</field> - <field name="type">ressource</field> - <field name="ressource_type_id" search="[('model','=','res.partner')]" /> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_root"/> - <field name="ressource_id">0</field> - </record> - - <record model="document.directory" id="dir_personnal_folder"> - <field name="name">Personal Folders</field> - <field name="parent_id" ref="dir_root"/> - <field name="type">ressource</field> - <field name="user_id" eval="False"/> - <field name="ressource_type_id" ref="base.model_res_users" /> - <field name="ressource_id">0</field> - </record> - <record model="document.directory" id="dir_product"> - <field name="name">Products</field> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_root"/> - <field name="ressource_id">0</field> - - </record> - - <record model="document.directory" id="dir_sale_order"> - <field name="name">Sales Order</field> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_root"/> - <field name="ressource_id">0</field> - - </record> - - <record model="document.directory" id="dir_sale_order_all"> - <field name="name">All Sales Order</field> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_sale_order"/> - <field name="ressource_id">0</field> - - </record> - - <record model="document.directory" id="dir_sale_order_quote"> - <field name="name">Quotations</field> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_sale_order"/> - <field name="ressource_id">0</field> - - </record> - - <record model="document.directory" id="dir_project"> - <field name="name">Projects</field> - <field name="user_id" eval="False"/> - <field name="parent_id" ref="dir_root"/> - <field name="ressource_id">0</field> - </record> - -</data> -</openerp> diff --git a/addons/document/document_demo.xml b/addons/document/document_demo.xml deleted file mode 100644 index fda125afb95b74be288c28cefc527e90583571f6..0000000000000000000000000000000000000000 --- a/addons/document/document_demo.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<openerp> -<data noupdate="1"> - <record id="base.user_demo" model="res.users"> - <field eval="[(4, ref('base.group_document_user'))]" name="groups_id"/> - </record> -</data> -</openerp> diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml deleted file mode 100644 index 8dafdc37be43711fa54e5911d134bf79db65ccdc..0000000000000000000000000000000000000000 --- a/addons/document/document_view.xml +++ /dev/null @@ -1,283 +0,0 @@ -<?xml version="1.0"?> -<openerp> -<data> - <menuitem name="Knowledge" id="menu_document" groups="base.group_system,base.group_document_user" icon="fa-magic" sequence="300"/> - <menuitem name="Document Management" id="menu_document_management_configuration" parent="menu_document" sequence="1" groups="base.group_no_one"/> - - <record model="ir.ui.view" id="view_document_directory_form"> - <field name="name">document.directory</field> - <field name="model">document.directory</field> - <field name="arch" type="xml"> - <form string="Directories" col="4"> - <group col="4"> - <field name="name"/> - <field name="parent_id"/> - <field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/> - <field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/> - </group> - <notebook colspan="4"> - <page string="Definition"> - <group string="Directory Type" colspan="4"> - <field name="type"/> - </group> - <group col="4" attrs="{'invisible': [('type','!=','ressource')]}"> - <field name="ressource_type_id" on_change="onchange_content_id(ressource_type_id)" - attrs="{'required': [('type','=','ressource')] }"/> - <newline/> - <field name="resource_field" domain="[('model_id','=',ressource_type_id), ('ttype', 'in', ('char', 'selection', 'date', 'datetime'))]"/> - <field name="ressource_tree"/> - <newline/> - <field name="domain" attrs="{'required': [('type','=','ressource')], 'readonly': [('type','=','static')]}"/> - </group> - <group col="4"> - <field name="ressource_parent_type_id"/> - <field name="ressource_id" readonly="1"/> - </group> - <group col="2" attrs="{'invisible': [('type','!=','ressource'),('ressource_parent_type_id','=',False)]}"> - <field name="resource_find_all"/> - </group> - - </page> - <page string="Generated Files" groups="base.group_no_one"> - <label colspan="4" string="For each entry here, virtual files will appear in this folder." /> - <field name="content_ids" nolabel="1" colspan="4" > - <form string="Contents"> - <group col="4"> - <field name="name"/> - <field name="sequence"/> - <field name="prefix"/> - <field name="suffix"/> - <field name="extension"/> - <field name="include_name"/> - <separator string="PDF Report" colspan="4"/> - <field name="report_id" domain="[('model_id','=',parent.ressource_type_id)]"/> - </group> - </form> - <tree string="Contents"> - <field name="sequence" string="Seq."/> - <field name="name"/> - <field name="suffix"/> - <field name="extension"/> - </tree> - </field> - </page> - <page string="Dynamic context" groups="base.group_no_one"> - <label colspan="4" string="Define words in the context, for all child directories and files" /> - <field name="dctx_ids" nolabel="1" colspan="4"> - <tree string="Fields" editable="bottom"> - <field name="field"/> - <field name="expr"/> - </tree> - <form string="Fields"> - <group col="4"> - <field name="field"/> - <field name="expr"/> - </group> - </form> - </field> - </page> - <page string="Security"> - <label colspan="4" string="Only members of these groups will have access to this directory and its files." /> - <label colspan="4" string="These groups, however, do NOT apply to children directories, which must define their own groups." /> - <field name="group_ids" colspan="4" nolabel="1"/> - </page> - </notebook> - </form> - </field> - </record> - <record model="ir.ui.view" id="view_document_directory_tree"> - <field name="name">document.directory</field> - <field name="model">document.directory</field> - <field name="field_parent">child_ids</field> - <field name="arch" type="xml"> - <tree string="Directories" toolbar="1"> - <field name="name"/> - <field name="type"/> - <field name="user_id"/> - <field name="company_id" groups="base.group_multi_company"/> - <field name="create_date"/> - <field name="write_date"/> - </tree> - </field> - </record> - - <record id="view_document_directory_filter" model="ir.ui.view"> - <field name="name">Search View: Document Directory</field> - <field name="model">document.directory</field> - <field name="arch" type="xml"> - <search string="Search Document Directory"> - <field name="name" string="Document Directory"/> - <filter string="Static" domain="[('type','=','directory')]"/> - <filter string="Resources" icon="terp-personal" domain="[('type','=','ressource')]"/> - <field name="company_id" groups="base.group_multi_company"/> - <field name="user_id" /> - <group expand="0" string="Group By"> - <filter string="Owner" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/> - <filter string="Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'type'}"/> - <filter string="Company" domain="[]" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> - </group> - </search> - </field> - </record> - - <record model="ir.actions.act_window" id="action_document_directory_form"> - <field name="name">Directories</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">document.directory</field> - <field name="view_type">form</field> - <field name="view_mode">tree,form</field> - <field name="search_view_id" ref="view_document_directory_filter"/> - </record> - - <record id="action_dir_view1" model="ir.actions.act_window.view"> - <field eval="10" name="sequence"/> - <field name="view_mode">tree</field> - <field name="view_id" ref="view_document_directory_tree"/> - <field name="act_window_id" ref="action_document_directory_form"/> - </record> - <record id="action_dir_view2" model="ir.actions.act_window.view"> - <field eval="20" name="sequence"/> - <field name="view_mode">form</field> - <field name="view_id" ref="view_document_directory_form"/> - <field name="act_window_id" ref="action_document_directory_form"/> - </record> - - <menuitem - action="action_document_directory_form" - id="menu_document_directories" - parent="menu_document_management_configuration"/> - - - <record model="ir.actions.act_window" id="action_document_directory_tree"> - <field name="type">ir.actions.act_window</field> - <field name="name">Directories' Structure</field> - <field name="res_model">document.directory</field> - <field name="view_type">tree</field> - <field name="view_id" ref="document.view_document_directory_tree"/> - <field name="domain">[('ressource_parent_type_id','=',False),('parent_id','=',False)]</field> - </record> - <menuitem - action="action_document_directory_tree" - id="menu_document_directories_tree" - parent="menu_document_management_configuration" sequence="5"/> - - <record model="ir.ui.view" id="view_document_file_form"> - <field name="name">ir.attachment</field> - <field name="model">ir.attachment</field> - <field name="priority" eval="1"/> - <field name="inherit_id" ref="base.view_attachment_form"/> - <field name="arch" type="xml"> - <xpath expr="//field[@name='datas_fname']" position="replace"> - <field name="datas_fname" invisible="1"/> - </xpath> - <field name="url" position="after"> - <field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/> - </field> - <field name="company_id" position="before"> - <field name="parent_id"/> - <field name="partner_id"/> - </field> - <xpath expr="//div[@name='creation_div']" position='after'> - <label for="write_uid" string="Modification"/> - <div> - <field name="write_uid" readonly="1" class="oe_inline"/> on - <field name="write_date" readonly="1" class="oe_inline"/> - </div> - </xpath> - </field> - </record> - - <record id="view_attach_filter_inherit0" model="ir.ui.view"> - <field name="name">IR Attachment0</field> - <field name="model">ir.attachment</field> - <field name="inherit_id" ref="base.view_attachment_search"/> - <field name="arch" type="xml"> - <xpath expr="//filter[@name='my_documents_filter']" position="replace"> - <filter name="my_documents_filter" string="My Document(s)" icon="terp-personal" domain="[('user_id','=',uid)]" help="Filter on my documents"/> - </xpath> - <xpath expr="//field[@name='create_uid']" position="replace"> - <field name="user_id"/> - <field name="parent_id" /> - <field name="index_content"/> - </xpath> - </field> - </record> - <record id="view_attach_filter_inherit2" model="ir.ui.view"> - <field name="name">IR Attachment2</field> - <field name="model">ir.attachment</field> - <field name="inherit_id" ref="base.view_attachment_search"/> - <field name="arch" type="xml"> - <filter name="owner" position="replace"> - <filter string="Owner" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/> - <filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/> - <filter string="Directory" icon="terp-folder-green" domain="[]" context="{'group_by':'parent_id'}"/> - </filter> - </field> - </record> - - - <record model="ir.ui.view" id="view_document_file_tree"> - <field name="name">ir.attachment</field> - <field name="model">ir.attachment</field> - <field name="priority" eval="1"/> - <field name="arch" type="xml"> - <tree decoration-info="type in ('url',)" string="Attachments"> - <field name="name"/> - <field name="parent_id" /> - <field name="user_id"/> - <field name="company_id"/> - <field name="create_date" groups="base.group_no_one"/> - <field name="write_date" groups="base.group_no_one"/> - <field name="partner_id"/> - <field name="type"/> - </tree> - </field> - </record> - - <record model="ir.actions.act_window" id="action_document_file_form"> - <field name="name">Documents</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">ir.attachment</field> - <field name="view_type">form</field> - <field name="view_mode">kanban,tree,form</field> - <field name="help" type="html"> - <p class="oe_view_nocontent_create"> - Click to create a new document. - </p><p> - The Documents repository gives you access to all attachments, such - as mails, project documents, invoices etc. - </p> - </field> - </record> - - <record model="ir.actions.act_window" id="action_document_file_directory_form"> - <field name="type">ir.actions.act_window</field> - <field name="res_model">ir.attachment</field> - <field name="name">Directory</field> - <field name="view_type">form</field> - <field name="domain">[('parent_id','child_of',active_id)]</field> - <field name="context">{'parent_id':active_id}</field> - </record> - - <record model="ir.values" id="ir_action_document_file_directory_form"> - <field name="key2" eval="'tree_but_open'"/> - <field name="model" eval="'document.directory'"/> - <field name="name">Browse Files</field> - <field name="value" eval="'ir.actions.act_window,%d'%action_document_file_directory_form"/> - </record> - - - <act_window domain="[('partner_id', '=', active_id)]" - context="{'default_partner_id': active_id}" - id="act_res_partner_document" name="Related Documents" - res_model="ir.attachment" - src_model="res.partner"/> - - <act_window - domain="[('parent_id', '=', active_id)]" - context="{'default_parent_id': active_id}" - id="zoom_directory" name="Related Documents" - res_model="ir.attachment" - src_model="document.directory"/> -</data> -</openerp> diff --git a/addons/document/report/__init__.py b/addons/document/models/__init__.py similarity index 81% rename from addons/document/report/__init__.py rename to addons/document/models/__init__.py index aff512744ed8a5db8a0fa9e50c5d224af9d2fd90..33a378b9e7ab61f8eec3d8faf1d5133e718fd1b6 100644 --- a/addons/document/report/__init__.py +++ b/addons/document/models/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import document_report + +import ir_attachment diff --git a/addons/document/models/ir_attachment.py b/addons/document/models/ir_attachment.py new file mode 100644 index 0000000000000000000000000000000000000000..c10f5b1013e89c7bd2fe4023f64998580da3aa89 --- /dev/null +++ b/addons/document/models/ir_attachment.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +import logging +import zipfile +import xml.dom.minidom +from StringIO import StringIO + +import pyPdf + +import openerp +from openerp.osv import fields, osv + +_logger = logging.getLogger(__name__) + +class IrAttachment(osv.osv): + _inherit = 'ir.attachment' + + def _index_odt(self, bin_data): + buf = u"" + f = StringIO(bin_data) + if zipfile.is_zipfile(f): + try: + zf = zipfile.ZipFile(f) + self.content = xml.dom.minidom.parseString(zf.read("content.xml")) + for val in ["text:p", "text:h", "text:list"]: + for element in self.content.getElementsByTagName(val) : + for node in element.childNodes : + if node.nodeType == xml.dom.Node.TEXT_NODE : + buf += node.nodeValue + elif node.nodeType == xml.dom.Node.ELEMENT_NODE : + buf += self.textToString(node) + buf += "\n" + except Exception: + pass + return buf + + def _index_pdf(self, bin_data): + buf = u"" + if bin_data.startswith('%PDF-'): + f = StringIO(bin_data) + try: + pdf = pyPdf.PdfFileReader(f) + for page in pdf.pages: + buf += page.extractText() + except Exception: + pass + return buf + + def _index(self, cr, uid, bin_data, datas_fname, mimetype): + # try to index odt content + buf = self._index_odt(bin_data) + if buf: + return buf + # try to index pdf content + buf = self._index_pdf(bin_data) + if buf: + return buf + + return super(IrAttachment, self)._index(cr, uid, bin_data, datas_fname, mimetype) + diff --git a/addons/document/odt2txt.py b/addons/document/odt2txt.py deleted file mode 100755 index e9a6d2daf5b94053a05a8f0c393e3bbe2d3e3dfe..0000000000000000000000000000000000000000 --- a/addons/document/odt2txt.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -import sys, zipfile, xml.dom.minidom -import StringIO - -class OpenDocumentTextFile : - def __init__ (self, filepath): - zip = zipfile.ZipFile(filepath) - self.content = xml.dom.minidom.parseString(zip.read("content.xml")) - - def toString (self): - """ Converts the document to a string. """ - buffer = u"" - for val in ["text:p", "text:h", "text:list"]: - for paragraph in self.content.getElementsByTagName(val) : - buffer += self.textToString(paragraph) + "\n" - return buffer - - def textToString(self, element): - buffer = u"" - for node in element.childNodes : - if node.nodeType == xml.dom.Node.TEXT_NODE : - buffer += node.nodeValue - elif node.nodeType == xml.dom.Node.ELEMENT_NODE : - buffer += self.textToString(node) - return buffer - -if __name__ == "__main__" : - s =StringIO.StringIO(file(sys.argv[1]).read()) - odt = OpenDocumentTextFile(s) - print odt.toString().encode('ascii','replace') diff --git a/addons/document/report/document_report.py b/addons/document/report/document_report.py deleted file mode 100644 index cf832784be949261722843165de90527ddbc5f3e..0000000000000000000000000000000000000000 --- a/addons/document/report/document_report.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - - -from openerp.osv import fields,osv -from openerp import tools - -class report_document_user(osv.osv): - _name = "report.document.user" - _description = "Files details by Users" - _auto = False - _columns = { - 'name': fields.char('Year', size=64,readonly=True), - 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), - ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month',readonly=True), - 'user_id': fields.many2one('res.users', 'Owner', readonly=True), - 'user': fields.related('user_id', 'name', type='char', size=64, readonly=True), - 'directory': fields.char('Directory',size=64,readonly=True), - 'datas_fname': fields.char('File Name',size=64,readonly=True), - 'create_date': fields.datetime('Date Created', readonly=True), - 'change_date': fields.datetime('Modified Date', readonly=True), - 'file_size': fields.integer('File Size', readonly=True), - 'nbr':fields.integer('# of Files', readonly=True), - 'type':fields.char('Directory Type',size=64,readonly=True), - } - def init(self, cr): - tools.drop_view_if_exists(cr, 'report_document_user') - cr.execute(""" - CREATE OR REPLACE VIEW report_document_user as ( - SELECT - min(f.id) as id, - to_char(f.create_date, 'YYYY') as name, - to_char(f.create_date, 'MM') as month, - f.user_id as user_id, - count(*) as nbr, - d.name as directory, - f.datas_fname as datas_fname, - f.create_date as create_date, - f.file_size as file_size, - min(d.type) as type, - f.write_date as change_date - FROM ir_attachment f - left join document_directory d on (f.parent_id=d.id and d.name<>'') - group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,d.type,f.write_date,f.datas_fname - ) - """) - - -class report_document_file(osv.osv): - _name = "report.document.file" - _description = "Files details by Directory" - _auto = False - _columns = { - 'file_size': fields.integer('File Size', readonly=True), - 'nbr':fields.integer('# of Files', readonly=True), - 'month': fields.char('Month', size=24, readonly=True), - } - _order = "month" - def init(self, cr): - tools.drop_view_if_exists(cr, 'report_document_file') - cr.execute(""" - create or replace view report_document_file as ( - select min(f.id) as id, - count(*) as nbr, - min(EXTRACT(MONTH FROM f.create_date)||'-'||to_char(f.create_date,'Month')) as month, - sum(f.file_size) as file_size - from ir_attachment f - group by EXTRACT(MONTH FROM f.create_date) - ) - """) diff --git a/addons/document/report/document_report_view.xml b/addons/document/report/document_report_view.xml deleted file mode 100644 index f6af9ad199afd5d7ca865df62df5113a12e1ddb4..0000000000000000000000000000000000000000 --- a/addons/document/report/document_report_view.xml +++ /dev/null @@ -1,142 +0,0 @@ -<?xml version="1.0"?> -<openerp> - <data> - <record model="ir.ui.view" id="view_document_user_form"> - <field name="name">report.document.user.form</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <form string="Files"> - <group col="4"> - <field name="name"/> - <field name="user"/> - <field name="directory"/> - <field name="datas_fname"/> - <field name="file_size"/> - <field name="create_date"/> - </group> - </form> - </field> - </record> - - - <record model="ir.ui.view" id="view_document_user_tree"> - <field name="name">report.document.user.tree</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <tree string="Files"> - <field name="name"/> - <field name="month"/> - <field name="user" invisible="1"/> - <field name="directory" invisible="1"/> - <field name="file_size" invisible="1"/> - <field name="create_date" invisible="1"/> - <field name="nbr"/> - </tree> - </field> - </record> - - <record id="view_report_document_user_search" model="ir.ui.view"> - <field name="name">report.document.user.search</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <search string="All users files"> - <field name="name" filter_domain="['|', '|',('name','ilike',self), ('user','ilike',self), ('directory','ilike',self)]" string="Users File"/> - <field name="month"/> - </search> - </field> - </record> - - - <record model="ir.actions.act_window" id="action_view_all_document_tree1"> - <field name="name">All Users files</field> - <field name="res_model">report.document.user</field> - <field name="view_type">form</field> - <field name="view_mode">tree,form</field> - <field name="context">{'group_by': ['name','month']}</field> - <field name="search_view_id" ref="view_report_document_user_search"/> - </record> - - - <record model="ir.ui.view" id="view_size_month"> - <field name="name">report.document.user.graph</field> - <field name="model">report.document.file</field> - <field name="arch" type="xml"> - <graph string="File Size by Month" type="line"> - <field name="month"/> - <field name="file_size" operator="+"/> - </graph> - </field> - </record> - - <record model="ir.ui.view" id="view_size_month_tree"> - <field name="name">report.document.user.tree</field> - <field name="model">report.document.file</field> - <field name="arch" type="xml"> - <tree string="File Size by Month"> - <field name="month" /> - <field name="file_size"/> - </tree> - </field> - </record> - - <record model="ir.actions.act_window" id="action_view_size_month"> - <field name="name">File Size by Month</field> - <field name="res_model">report.document.file</field> - <field name="view_id" ref="view_size_month"></field> - <field name="view_type">form</field> - <field name="view_mode">tree</field> - </record> - - - <record model="ir.ui.view" id="view_files_by_month_graph"> - <field name="name">report.file.month.graph</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <graph string="Files by Month" type="pie"> - <field name="month" /> - <field name="nbr" operator="+"/> - </graph> - </field> - </record> - - <record model="ir.ui.view" id="view_files_by_month_tree"> - <field name="name">report.file.month.tree</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <tree string="Files by Month"> - <field name="name"/> - <field name="month"/> - <field name="nbr"/> - </tree> - </field> - </record> - - <record model="ir.ui.view" id="view_files_by_user_graph"> - <field name="name">report.file.user.graph</field> - <field name="model">report.document.user</field> - <field name="arch" type="xml"> - <graph string="Files by User" type="pie"> - <field name="user_id" /> - <field name="nbr" operator="+"/> - </graph> - </field> - </record> - - <record model="ir.actions.act_window" id="action_view_files_by_user_graph"> - <field name="name">Files by User</field> - <field name="res_model">report.document.user</field> - <field name="view_id" ref="view_files_by_user_graph"></field> - <field name="view_type">form</field> - <field name="view_mode">tree</field> - </record> - - <record model="ir.actions.act_window" id="action_view_files_by_month_graph"> - <field name="name">Files by Month</field> - <field name="res_model">report.document.user</field> - <field name="view_id" ref="view_files_by_month_graph"></field> - <field name="view_type">form</field> - <field name="view_mode">tree</field> - </record> - - </data> -</openerp> diff --git a/addons/document/security/document_security.xml b/addons/document/security/document_security.xml deleted file mode 100644 index a7ec76eafac1b316dc0cc6fee0e23fc90e4014c5..0000000000000000000000000000000000000000 --- a/addons/document/security/document_security.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> -<data noupdate="0"> - - <record id="base.group_document_user" model="res.groups"> - <field name="name">User</field> - <field name="category_id" ref="base.module_category_knowledge_management"/> - <field name="users" eval="[(4, ref('base.user_root'))]"/> - </record> - -<!-- <record id="group_document_manager" model="res.groups">--> -<!-- <field name="name">Document / Manager</field>--> -<!-- </record>--> -</data> -<data noupdate="1"> - - <record id="ir_rule_readpublicdirectories0" model="ir.rule"> - <field name="model_id" ref="document.model_document_directory"/> - <field name="domain_force">['|','|',('group_ids','in',[g.id for g in user.groups_id]), ('user_id', '=', user.id), '&', ('user_id', '=', False), ('group_ids','=',False), '|','|', ('company_id','=',False), ('company_id','child_of',[user.company_id.id]),('company_id.child_ids','child_of',[user.company_id.id])]</field> - <field name="name">Read public directories</field> - <field eval="0" name="global"/> - <field eval="[(6,0,[ref('base.group_user')])]" name="groups"/> - <field eval="0" name="perm_unlink"/> - <field eval="0" name="perm_write"/> - <field eval="1" name="perm_read"/> - <field eval="0" name="perm_create"/> - </record> - - <record id="ir_rule_documentmodifyowndirectories0" model="ir.rule"> - <field name="model_id" ref="document.model_document_directory"/> - <field name="domain_force">[ '|', ('user_id', '=', user.id), '&', ('group_ids','in',[g.id for g in user.groups_id]), ('user_id','=',False), '|','|', ('company_id','=',False), ('company_id','child_of',[user.company_id.id]),('company_id.child_ids','child_of',[user.company_id.id])]</field> - <field name="name">Document modify own directories</field> - <field eval="0" name="global"/> - <field eval="[(6,0,[ref('base.group_document_user')])]" name="groups"/> - <field eval="1" name="perm_unlink"/> - <field eval="1" name="perm_write"/> - <field eval="0" name="perm_read"/> - <field eval="1" name="perm_create"/> - </record> -</data> -</openerp> diff --git a/addons/document/security/ir.model.access.csv b/addons/document/security/ir.model.access.csv deleted file mode 100644 index 8c5e43238318f08fcf4a93dd673e6f3ddc9c0a4c..0000000000000000000000000000000000000000 --- a/addons/document/security/ir.model.access.csv +++ /dev/null @@ -1,18 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_document_directory_all,document.directory all,model_document_directory,,1,0,0,0 -access_document_directory_group_document_manager,document.directory document manager,model_document_directory,base.group_system,1,1,1,1 -access_document_directory_group_knowledge,document.directory modify,model_document_directory,base.group_document_user,1,1,1,1 -access_document_directory_content_all,document.directory.content all,model_document_directory_content,,1,0,0,0 -access_document_directory_content_group_document_manager,document.directory.content document manager,model_document_directory_content,base.group_system,1,1,1,1 -access_document_directory_content_type_group_document_manager,document.directory.content.type document manager,model_document_directory_content_type,base.group_system,1,1,1,1 -access_document_directory_content_type_group_system,document.directory.content.type group system,model_document_directory_content_type,base.group_user,1,0,0,0 -access_ir_attachment_group_user,ir.attachment user,base.model_ir_attachment,base.group_document_user,1,1,1,1 -access_ir_attachment_group_system,ir.attachment system,base.model_ir_attachment,base.group_system,1,0,0,0 -access_res_partner_group_user,res.partner user,base.model_res_partner,base.group_document_user,1,1,1,0 -access_document_directory_dctx_all,document.directory.dctx all,model_document_directory_dctx,,1,0,0,0 -access_document_directory_dctx_group_document_manager,document.directory.dctx document manager,model_document_directory_dctx,base.group_system,1,1,1,1 -access_report_document_user_group_document_manager,report.document.user document manager,model_report_document_user,base.group_system,1,0,0,0 -access_report_document_file_group_document_manager,report.document.file document manager,model_report_document_file,base.group_system,1,0,0,0 -access_report_document_file_group_document,report.document.file document manager,model_report_document_file,base.group_document_user,1,0,0,0 -access_report_document_user_knowledgeuser,report.document.user knowledgeuser,document.model_report_document_user,base.group_document_user,1,0,0,0 -access_document_storage,access_document_storage,model_document_storage,base.group_system,1,1,1,1 diff --git a/addons/document/std_index.py b/addons/document/std_index.py deleted file mode 100644 index 9f05b86835b2245e0108b408eec9b6afea152a19..0000000000000000000000000000000000000000 --- a/addons/document/std_index.py +++ /dev/null @@ -1,206 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from content_index import indexer, cntIndex -from subprocess import Popen, PIPE -import StringIO -import odt2txt -import sys, zipfile, xml.dom.minidom -import logging -_logger = logging.getLogger(__name__) - -def _to_unicode(s): - try: - return s.decode('utf-8') - except UnicodeError: - try: - return s.decode('latin') - except UnicodeError: - try: - return s.encode('ascii') - except UnicodeError: - return s - -def textToString(element): - buffer = u"" - for node in element.childNodes : - if node.nodeType == xml.dom.Node.TEXT_NODE : - buffer += node.nodeValue - elif node.nodeType == xml.dom.Node.ELEMENT_NODE : - buffer += textToString(node) - return buffer - -class TxtIndex(indexer): - def _getMimeTypes(self): - return ['text/plain','text/html','text/diff','text/xml', 'text/*', - 'application/xml'] - - def _getExtensions(self): - return ['.txt', '.py'] - - def _doIndexContent(self, content): - return content - -cntIndex.register(TxtIndex()) - -class PptxIndex(indexer): - def _getMimeTypes(self): - return [ 'application/vnd.openxmlformats-officedocument.presentationml.presentation'] - - def _getExtensions(self): - return ['.pptx'] - - def _doIndexFile(self, fname): - def toString () : - """ Converts the document to a string. """ - buffer = u"" - for val in ["a:t"]: - for paragraph in content.getElementsByTagName(val) : - buffer += textToString(paragraph) + "\n" - return buffer - - data = [] - zip = zipfile.ZipFile(fname) - files = filter(lambda x: x.startswith('ppt/slides/slide'), zip.namelist()) - for i in range(1, len(files) + 1): - content = xml.dom.minidom.parseString(zip.read('ppt/slides/slide%s.xml' % str(i))) - res = toString().encode('ascii','replace') - data.append(res) - - return _to_unicode('\n'.join(data)) - -cntIndex.register(PptxIndex()) - -class DocIndex(indexer): - def _getMimeTypes(self): - return [ 'application/ms-word'] - - def _getExtensions(self): - return ['.doc'] - - def _doIndexFile(self, fname): - try: - pop = Popen(['antiword', fname], shell=False, stdout=PIPE) - (data, _) = pop.communicate() - return _to_unicode(data) - except OSError: - - _logger.warning("Failed attempt to execute antiword (MS Word reader). Antiword is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0]) - _logger.debug("Trace of the failed file indexing attempt.", exc_info=True) - return u'' - -cntIndex.register(DocIndex()) - -class DocxIndex(indexer): - def _getMimeTypes(self): - return [ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'] - - def _getExtensions(self): - return ['.docx'] - - def _doIndexFile(self, fname): - zip = zipfile.ZipFile(fname) - content = xml.dom.minidom.parseString(zip.read("word/document.xml")) - def toString () : - """ Converts the document to a string. """ - buffer = u"" - for val in ["w:p", "w:h", "text:list"]: - for paragraph in content.getElementsByTagName(val) : - buffer += textToString(paragraph) + "\n" - return buffer - - res = toString().encode('ascii','replace') - - return _to_unicode(res) - -cntIndex.register(DocxIndex()) - - -class XlsxIndex(indexer): - def _getMimeTypes(self): - return [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] - - def _getExtensions(self): - return ['.xlsx'] - - def _doIndexFile(self, fname): - zip = zipfile.ZipFile(fname) - content = xml.dom.minidom.parseString(zip.read("xl/sharedStrings.xml")) - def toString () : - """ Converts the document to a string. """ - buffer = u"" - for val in ["t"]: - for paragraph in content.getElementsByTagName(val) : - buffer += textToString(paragraph) + "\n" - return buffer - - res = toString().encode('ascii','replace') - - return _to_unicode(res) - -cntIndex.register(XlsxIndex()) - -class PdfIndex(indexer): - def _getMimeTypes(self): - return [ 'application/pdf'] - - def _getExtensions(self): - return ['.pdf'] - - def _doIndexFile(self, fname): - try: - pop = Popen(['pdftotext', '-enc', 'UTF-8', '-nopgbrk', fname, '-'], shell=False, stdout=PIPE) - (data, _) = pop.communicate() - return _to_unicode(data) - except OSError: - _logger.warning("Failed attempt to execute pdftotext. This program is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0]) - _logger.debug("Trace of the failed file indexing attempt.", exc_info=True) - return u'' - -cntIndex.register(PdfIndex()) - -class ImageNoIndex(indexer): - def _getMimeTypes(self): - return [ 'image/*'] - - def _getExtensions(self): - #better return no extension, and let 'file' do its magic - return [] - #return ['.png','.jpg','.gif','.jpeg','.bmp','.tiff'] - - def _doIndexContent(self, content): - return 'image' - - -cntIndex.register(ImageNoIndex()) - -# other opendocument formats: -# chart-template chart database -# formula-template formula graphics-template graphics -# image -# presentation-template presentation spreadsheet-template spreadsheet - -class OpenDoc(indexer): - """ Index OpenDocument files. - - Q: is it really worth it to index spreadsheets, or do we only get a - meaningless list of numbers (cell contents) ? - """ - def _getMimeTypes(self): - otypes = [ 'text', 'text-web', 'text-template', 'text-master' ] - return map(lambda a: 'application/vnd.oasis.opendocument.'+a, otypes) - - def _getExtensions(self): - return ['.odt', '.ott', ] # '.ods' - - def _doIndexContent(self, content): - s = StringIO.StringIO(content) - o = odt2txt.OpenDocumentTextFile(s) - result = _to_unicode(o.toString()) - s.close() - return result - -cntIndex.register(OpenDoc()) - - -#eof diff --git a/addons/document/test/document_test.yml b/addons/document/test/document_test.yml deleted file mode 100644 index 75fa74548d097eb76af16c2fc9613ba1cd7b8a74..0000000000000000000000000000000000000000 --- a/addons/document/test/document_test.yml +++ /dev/null @@ -1,50 +0,0 @@ -- | - In order to test the Document Management System In OpenERP. -- - In order to test behaviour of resource Directory I will make one resource Directory "Partner Labels" in OpenERP having type "Other Resources" and Directory mapped to object "Partner" -- - !record {model: 'document.directory', id: dir_partner_label}: - name : "Partner Labels" - type : ressource - content_ids: - - name: "Label" - report_id : base.res_partner_address_report -- - Assign "res.partner" object to ressource_type_id. -- - !python {model: document.directory}: | - ids = self.pool.get('ir.model').search(cr, uid, [('model','=','res.partner')]) - id = self.write(cr, uid, [ref("dir_partner_label")], {'ressource_type_id' : ids[0]}, context) -- - In order to check static directory in OpenERP which is the real directory just like system's local folders, - First I create a directory in OpenERP named "Directory 1" with type as "Static Directory" -- - !record {model: 'document.directory', id: directory_1}: - name : "Directory 1" - type : directory -- - In order to make a directory hierarchy in OpenERP I will make other static directory "Directory 2" and I put its Parent Item as "Directory 1", - So I can see the directory hierarchy in OpenERP's client like :- Directory1 -> Directory2 -- - !record {model: 'document.directory', id: directory_2}: - name : "Directory 2" - type : directory - parent_id : directory_1 -- - I am create a one Document Attachment name "My document" and select "Directory 2" as its Directory, - And in order to put a File content. -- - When I am creating the document then "Resource Title" is filled automatic with "My document". -- - !record {model: 'ir.attachment', id: document_1}: - name : "My document" - parent_id : directory_2 -- - Attach a pdf file in "My document" -- - !python {model: 'ir.attachment'}: | - import tools - import base64 - pdf_file = open(tools.config['addons_path'] + '/document/test/partner.pdf') - self.write(cr, uid, [ref("document_1")], {'datas_fname': 'partner.pdf', 'datas' : base64.encodestring(pdf_file.read())}, context) - diff --git a/addons/document/test/document_test2.yml b/addons/document/test/document_test2.yml deleted file mode 100644 index 1eed98aa9011d71efaddc6e4b5dc6081b7e326ad..0000000000000000000000000000000000000000 --- a/addons/document/test/document_test2.yml +++ /dev/null @@ -1,88 +0,0 @@ -- - I create a "Testing" folder where all the test data will go. -- - !record {model: document.directory, id: dir_tests }: - name: 'Testing (will be deleted!)' - parent_id: dir_root -- - I create an attachment into the root folder (w. empty fields, test that - defaults work) -- - !record {model: ir.attachment, id: file_test1 }: - name: Test file.txt -- - I delete the attachment from the root folder -- - !python {model: ir.attachment}: | - self.unlink(cr, uid, [ref('file_test1')]) -- - I create an attachment into the Testing folder. -- - !record {model: ir.attachment, id: file_test2 }: - name: Test file 2 - parent_id: dir_tests -- - I update the attachment with data, namely "abcd" -- - !record {model: ir.attachment, id: file_test2 }: - datas: "YWJjZA==\n" -- - I test that the datas of the attachment are correct -- - !assert {model: ir.attachment, id: file_test2 }: - - datas == "YWJjZA==\n" - - file_size == 4 -- - I rename the attachment. -- - !record {model: ir.attachment, id: file_test2 }: - name: Test renamed 2 -- - I search the testing folder for attachments. -- - !python {model: ir.attachment}: | - ids = self.search(cr, uid, [('parent_id.name','=', 'Testing (will be deleted!)'), ('name','=','Test renamed 2')]) - assert ids == [ ref("file_test2") ], ids -- - I create an attachment to a 3rd resource, eg. a res.country -- - !record {model: ir.attachment, id: attach_3rd }: - name: 'Country attachment.txt' - parent_id: dir_tests - datas: "Q291bnRyeSBhdHRhY2htZW50IGNvbnRlbnQ=\n" - res_model: res.country - res_id: !eval ref("base.za") -- - I search for the res.country attachment -- - !python {model: ir.attachment}: | - ids = self.search(cr, uid, [('res_model', '=', 'res.country'), ('res_id', '=', ref("base.za"))]) - assert ids == [ ref("attach_3rd")], ids -- - I test that I can't create duplicate directories (even when duplicates are hidden by a record rule) -- - !python {model: document.directory}: | - duplicate_detected = False - from openerp.osv.osv import except_osv - try: - demo_uid = ref('base.user_demo') - dir_vals = { - 'name': 'Testing (will be deleted!)', - 'parent_id': ref('document.dir_root') - } - new_dir_id = self.create(cr, demo_uid, dir_vals, context=None) - self.unlink(cr, uid, [new_dir_id], context=None) - except except_osv, e: - duplicate_detected = e.name == u'Directory name must be unique!' - assert duplicate_detected is True, 'Failed to detect duplicate directory' -- - I delete the attachments -- - !python {model: ir.attachment}: | - self.unlink(cr, uid, [ref('file_test2')]) - self.unlink(cr, uid, [ref('attach_3rd')]) -- - I delete the tests folder -- - !python {model: document.directory}: | - self.unlink(cr, uid, [ref('dir_tests')]) diff --git a/addons/document/test/partner.pdf b/addons/document/test/partner.pdf deleted file mode 100644 index 1b1c7f0daac89fade2597ad6079ef7c8b15a78a4..0000000000000000000000000000000000000000 --- a/addons/document/test/partner.pdf +++ /dev/null @@ -1,118 +0,0 @@ -%PDF-1.3 -%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com -% 'BasicFonts': class PDFDictionary -1 0 obj -% The standard fonts dictionary -<< /F1 2 0 R - /F2 3 0 R - /F3 4 0 R >> -endobj -% 'F1': class PDFType1Font -2 0 obj -% Font Helvetica -<< /BaseFont /Helvetica - /Encoding /WinAnsiEncoding - /Name /F1 - /Subtype /Type1 - /Type /Font >> -endobj -% 'F2': class PDFType1Font -3 0 obj -% Font Helvetica-Bold -<< /BaseFont /Helvetica-Bold - /Encoding /WinAnsiEncoding - /Name /F2 - /Subtype /Type1 - /Type /Font >> -endobj -% 'F3': class PDFType1Font -4 0 obj -% Font Times-Roman -<< /BaseFont /Times-Roman - /Encoding /WinAnsiEncoding - /Name /F3 - /Subtype /Type1 - /Type /Font >> -endobj -% 'Page1': class PDFPage -5 0 obj -% Page dictionary -<< /Contents 9 0 R - /MediaBox [ 0 - 0 - 841.8898 - 595.2756 ] - /Parent 8 0 R - /Resources << /Font 1 0 R - /ProcSet [ /PDF - /Text - /ImageB - /ImageC - /ImageI ] >> - /Rotate 0 - /Trans << >> - /Type /Page >> -endobj -% 'R6': class PDFCatalog -6 0 obj -% Document Root -<< /Outlines 10 0 R - /PageMode /UseNone - /Pages 8 0 R - /Type /Catalog >> -endobj -% 'R7': class PDFInfo -7 0 obj -<< /Author (Generated by OpenERP, Fabien Pinckaers) - /CreationDate (20100421145542) - /Keywords () - /Producer (ReportLab http://www.reportlab.com) - /Subject (\(unspecified\)) - /Title (Partner) >> -endobj -% 'R8': class PDFPages -8 0 obj -% page tree -<< /Count 1 - /Kids [ 5 0 R ] - /Type /Pages >> -endobj -% 'R9': class PDFStream -9 0 obj -% page stream -<< /Filter [ /ASCII85Decode - /FlateDecode ] - /Length 524 >> -stream -Gat=(?#P<K'R_@f5MSc<`6.HPV2s@dQRlarfjrE>3i<Y4(hW<qY=/IHPo2nd;U2u=SpPc46=:icfCoF922oN\83q_*El(+<i)0C.\*qSa'orY`+p(cC^oTpn8t,B-+=I?_Q1#SGXQbKWJ5-M7"aXRSQCBTu'NHJF046Jno-.K&2kW+&Ddh9bXc1q%)-e?DSC(5(4%=lk+ql;XaX3m]F#7K:"]hph/QW?(0_J4kXQiP</;'9K=]Wd,jeGe.Ma6pqJ&iD]r%qkNclhVq5Q/gSmK+r&6mr`*Z[m8(n)Usu)MZo%TNta^h'I^g6m5Vp92+>e[>S,B2ME\)S7:@oo6@nF8`I+h##OY3a-n#Qm!>5jiD.9pQ@E1#Xj$=)27)F3RmD%fbqZh,T`gJd0/,?A3`0:_VVm`"l`>oOf9p&HGF7>WCGVJoD2&_+c#BDb)/&0>>rL5@]KY$9YOA<rrt#g)1a61mS([/:0_[`)!ctOhSA/p@bq]>qZHTJq8k]!o+?4a5\-KbB#NYJC'`~>endstream - -endobj -% 'R10': class PDFOutlines -10 0 obj -<< /Count 0 - /Type /Outlines >> -endobj -xref -0 11 -0000000000 65535 f -0000000113 00000 n -0000000233 00000 n -0000000398 00000 n -0000000573 00000 n -0000000740 00000 n -0000001017 00000 n -0000001152 00000 n -0000001395 00000 n -0000001500 00000 n -0000002169 00000 n -trailer -<< /ID - % ReportLab generated PDF document -- digest (http://www.reportlab.com) - [(\210\344\006bE\230CUUi\010[\)Qif) (\210\344\006bE\230CUUi\010[\)Qif)] - - /Info 7 0 R - /Root 6 0 R - /Size 11 >> -startxref -2221 -%%EOF diff --git a/addons/document/test_cindex.py b/addons/document/test_cindex.py deleted file mode 100755 index 05101a7a4911ac42ac1857e13973a2d211a09e3b..0000000000000000000000000000000000000000 --- a/addons/document/test_cindex.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python - -import sys -import os -import glob -import time -import logging - -from optparse import OptionParser - -logging.basicConfig(level=logging.DEBUG) - -parser = OptionParser() -parser.add_option("-q", "--quiet", - action="store_false", dest="verbose", default=True, - help="don't print status messages to stdout") - -parser.add_option("-C", "--content", - action="store_true", dest="docontent", default=False, - help="Disect content, rather than the file.") - -parser.add_option("--delay", - action="store_true", dest="delay", default=False, - help="delay after the operation, to inspect child processes") - -(options, args) = parser.parse_args() - -import content_index, std_index - -from content_index import cntIndex - -for fname in args: - try: - if options.docontent: - fp = open(fname,'rb') - content = fp.read() - fp.close() - res = cntIndex.doIndex(content, fname, None, None, True) - else: - res = cntIndex.doIndex(None, fname, None, fname,True) - - if options.verbose: - for line in res[:5]: - print line - if options.delay: - time.sleep(30) - except Exception,e: - import traceback - tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback)) - except KeyboardInterrupt: - print "Keyboard interrupt" - -#eof diff --git a/addons/document/wizard/__init__.py b/addons/document/wizard/__init__.py deleted file mode 100644 index 10d4e5efb6b5ce256ca07d4eea86e013163764b6..0000000000000000000000000000000000000000 --- a/addons/document/wizard/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. -import document_configuration diff --git a/addons/document/wizard/document_configuration.py b/addons/document/wizard/document_configuration.py deleted file mode 100644 index 916222284d3183414c4ef4e27111d742a5601daf..0000000000000000000000000000000000000000 --- a/addons/document/wizard/document_configuration.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from openerp.osv import fields, osv - -class document_configuration(osv.osv_memory): - _name='document.configuration' - _description = 'Directory Configuration' - _inherit = 'res.config' - - def execute(self, cr, uid, ids, context=None): - dir_pool = self.pool.get('document.directory') - data_pool = self.pool.get('ir.model.data') - model_pool = self.pool.get('ir.model') - content_pool = self.pool.get('document.directory.content') - if self.pool.get('sale.order'): - # Sale order - dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_sale_order_all') - if dir_data_id: - sale_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id - else: - sale_dir_id = data_pool.create(cr, uid, {'name': 'Sale Orders'}) - mid = model_pool.search(cr, uid, [('model','=','sale.order')]) - dir_pool.write(cr, uid, [sale_dir_id], { - 'type':'ressource', - 'ressource_type_id': mid[0], - 'domain': '[]', - }) - # Qutation - dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_sale_order_quote') - if dir_data_id: - quta_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id - else: - quta_dir_id = data_pool.create(cr, uid, {'name': 'Sale Quotations'}) - - dir_pool.write(cr, uid, [quta_dir_id], { - 'type':'ressource', - 'ressource_type_id': mid[0], - 'domain': "[('state','=','draft')]", - }) - # Sale Order Report - order_report_data_id = data_pool._get_id(cr, uid, 'sale', 'report_sale_order') - if order_report_data_id: - order_report_id = data_pool.browse(cr, uid, order_report_data_id, context=context).res_id - - content_pool.create(cr, uid, { - 'name': "Print Order", - 'suffix': "_print", - 'report_id': order_report_id, - 'extension': '.pdf', - 'include_name': 1, - 'directory_id': sale_dir_id, - }) - - content_pool.create(cr, uid, { - 'name': "Print Quotation", - 'suffix': "_print", - 'report_id': order_report_id, - 'extension': '.pdf', - 'include_name': 1, - 'directory_id': quta_dir_id, - }) - - - if self.pool.get('product.product'): - # Product - dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_product') - if dir_data_id: - product_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id - else: - product_dir_id = data_pool.create(cr, uid, {'name': 'Products'}) - - mid = model_pool.search(cr, uid, [('model','=','product.product')]) - dir_pool.write(cr, uid, [product_dir_id], { - 'type':'ressource', - 'ressource_type_id': mid[0], - }) - - if self.pool.get('account.analytic.account'): - # Project - dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_project') - if dir_data_id: - project_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id - else: - project_dir_id = data_pool.create(cr, uid, {'name': 'Projects'}) - - mid = model_pool.search(cr, uid, [('model','=','account.analytic.account')]) - dir_pool.write(cr, uid, [project_dir_id], { - 'type':'ressource', - 'ressource_type_id': mid[0], - 'domain': '[]', - 'ressource_tree': 1 - }) diff --git a/addons/document/wizard/document_configuration_view.xml b/addons/document/wizard/document_configuration_view.xml deleted file mode 100644 index 049c3a0097470bde627aa09c7623d4a049c70253..0000000000000000000000000000000000000000 --- a/addons/document/wizard/document_configuration_view.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> - <data> - <record id="view_auto_config_form" model="ir.ui.view"> - <field name="name">Auto Configure Directories</field> - <field name="model">document.configuration</field> - <field name="inherit_id" ref="base.res_config_view_base"/> - <field name="arch" type="xml"> - <data> - <form position="attributes"> - <attribute name="string">Knowledge Application Configuration</attribute> - </form> - <group name="res_config_contents" position="replace"> - <separator string="Configure Directories"/> - <p>Odoo's Document Management System supports mapping virtual folders with documents. The virtual folder of a document can be used to manage the files attached to the document, or to print and download any report. This tool will create directories automatically according to modules installed.</p> - <p>When executing this wizard, it will configure your directories automatically according to modules installed.</p> - </group> - </data> - </field> - </record> - - <record id="action_config_auto_directory" model="ir.actions.act_window"> - <field name="name">Configure Directories</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">document.configuration</field> - <field name="view_id" ref="view_auto_config_form"/> - <field name="view_type">form</field> - <field name="view_mode">form</field> - <field name="target">new</field> - </record> - - </data> -</openerp> diff --git a/addons/marketing_campaign/marketing_campaign.py b/addons/marketing_campaign/marketing_campaign.py index f96afda10340b1723e4292aa30bccebc1ce476db..2f4d11243b7cd9ea41a3d5d12693482133b1f173 100644 --- a/addons/marketing_campaign/marketing_campaign.py +++ b/addons/marketing_campaign/marketing_campaign.py @@ -383,8 +383,6 @@ class marketing_campaign_activity(osv.osv): """), 'email_template_id': fields.many2one('mail.template', "Email Template", help='The email to send when this activity is activated'), 'report_id': fields.many2one('ir.actions.report.xml', "Report", help='The report to generate when this activity is activated', ), - 'report_directory_id': fields.many2one('document.directory','Directory', - help="This folder is used to store the generated reports"), 'server_action_id': fields.many2one('ir.actions.server', string='Action', help= "The action to perform when this activity is activated"), 'to_ids': fields.one2many('marketing.campaign.transition', @@ -428,9 +426,7 @@ class marketing_campaign_activity(osv.osv): activity.name,workitem.partner_id.name), 'datas_fname': '%s.%s'%(activity.report_id.report_name, activity.report_id.report_type), - 'parent_id': activity.report_directory_id.id, 'datas': base64.encodestring(report_data), - 'file_type': format } self.pool.get('ir.attachment').create(cr, uid, attach_vals) return True diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml index f41051b3537ccbd0c7544d1cf9a394d3ee41cb13..1254b11df6bc816f36cbcc05255df785a6a2512e 100644 --- a/addons/marketing_campaign/marketing_campaign_view.xml +++ b/addons/marketing_campaign/marketing_campaign_view.xml @@ -316,7 +316,6 @@ context="{'default_model_id':object_id}"/> <field name="server_action_id" attrs="{'required':[('type','=','action')],'invisible':[('type','!=','action')]}" domain="[('model_id','=',object_id)]"/> <field name="report_id" attrs="{'required':[('type','=','report')],'invisible':[('type','!=','report')]}" context="{'object_id':object_id}"/> - <field name="report_directory_id" attrs="{'required':[('type','=','report')],'invisible':[('type','!=','report')]}"/> </group> </group> <separator string="Previous Activities"/> diff --git a/addons/website_blog/security/ir.model.access.csv b/addons/website_blog/security/ir.model.access.csv index 68fdcaf0374cb4214905dbb8f3d4bbe9f4140070..df9abd86b33d53b84755012ea92de04554e5285e 100644 --- a/addons/website_blog/security/ir.model.access.csv +++ b/addons/website_blog/security/ir.model.access.csv @@ -1,7 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink blog_blog_all,blog.blog,model_blog_blog,,1,0,0,0 -blog_blog,blog.blog,model_blog_blog,base.group_document_user,1,1,1,1 +blog_blog,blog.blog,model_blog_blog,base.group_website_designer,1,1,1,1 blog_post_all,blog.post,model_blog_post,,1,0,0,0 -blog_post,blog.post,model_blog_post,base.group_document_user,1,1,1,1 +blog_post,blog.post,model_blog_post,base.group_website_designer,1,1,1,1 blog_tag,blog.tag,model_blog_tag,,1,0,0,0 -blog_tag_edition,blog.tag,model_blog_tag,base.group_document_user,1,1,1,1 +blog_tag_edition,blog.tag,model_blog_tag,base.group_website_designer,1,1,1,1 diff --git a/addons/website_blog/tests/common.py b/addons/website_blog/tests/common.py index 9147d2a37398cfdba06427361bd929d19bd883ef..5dff9af2278afa66c9c2a8d4a76de3868153b07d 100644 --- a/addons/website_blog/tests/common.py +++ b/addons/website_blog/tests/common.py @@ -8,7 +8,7 @@ class TestWebsiteBlogCommon(common.TransactionCase): Users = self.env['res.users'] - group_blog_manager_id = self.ref('base.group_document_user') + group_blog_manager_id = self.ref('base.group_website_designer') group_employee_id = self.ref('base.group_user') group_public_id = self.ref('base.group_public') diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml index 0bfe17ee0b0579b6b8972a4cbea73889f94f4dee..2d6d97a65644a5e387b00d5e23074b9dae8c6f25 100644 --- a/addons/website_blog/views/website_blog_templates.xml +++ b/addons/website_blog/views/website_blog_templates.xml @@ -127,7 +127,7 @@ <p class="css_editable_hidden"> <h1>No blog post yet.</h1> </p> - <p groups="base.group_document_user"> + <p groups="base.group_website_designer"> Click on "Content" on the top menu to write your first blog post. </p> </div> @@ -482,7 +482,7 @@ </template> <!-- User Navbar --> -<template id="content_new_blogpost" inherit_id="website.user_navbar" groups="base.group_document_user"> +<template id="content_new_blogpost" inherit_id="website.user_navbar" groups="base.group_website_designer"> <xpath expr="//ul[@id='oe_systray']/li/ul[@class='dropdown-menu oe_content_menu']" position="inside"> <li><a href="#" data-action="new_blog_post">New Blog Post</a></li> </xpath> diff --git a/addons/website_blog/views/website_blog_views.xml b/addons/website_blog/views/website_blog_views.xml index 2b37369e77181adaf54a0211536722945ed36c54..755d610b70837caf2ee8a29e12ccc73b4f5eb7e4 100644 --- a/addons/website_blog/views/website_blog_views.xml +++ b/addons/website_blog/views/website_blog_views.xml @@ -71,7 +71,7 @@ <field name="ranking" invisible="1"/> </group> <group string="Technical" groups="base.group_no_one"> - <field name="write_uid" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/> + <field name="write_uid" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_website_designer']}"/> <field name="write_date"/> </group> </sheet>