[REM] document directories
Keeping the attachments widget on form views and document indexation (currently limited to pdf/odt).
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
@@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
@@ -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)
|
||||
)
|
||||
""")
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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')])
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import document_configuration
|
||||
@@ -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
|
||||
})
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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')
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user