[REM] document directories

Keeping the attachments widget on form views and document indexation (currently
limited to pdf/odt).
This commit is contained in:
Antony Lesuisse
2015-07-12 13:52:08 +02:00
parent 81bf724c24
commit 3ced0ff61b
29 changed files with 76 additions and 3694 deletions
+1 -5
View File
@@ -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
+6 -21
View File
@@ -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,
}
-177
View File
@@ -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
-82
View File
@@ -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>
-8
View File
@@ -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>
-283
View File
@@ -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
+60
View File
@@ -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)
-33
View File
@@ -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')
-70
View File
@@ -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), '&amp;', ('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), '&amp;', ('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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_document_directory_all document.directory all model_document_directory 1 0 0 0
3 access_document_directory_group_document_manager document.directory document manager model_document_directory base.group_system 1 1 1 1
4 access_document_directory_group_knowledge document.directory modify model_document_directory base.group_document_user 1 1 1 1
5 access_document_directory_content_all document.directory.content all model_document_directory_content 1 0 0 0
6 access_document_directory_content_group_document_manager document.directory.content document manager model_document_directory_content base.group_system 1 1 1 1
7 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
8 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
9 access_ir_attachment_group_user ir.attachment user base.model_ir_attachment base.group_document_user 1 1 1 1
10 access_ir_attachment_group_system ir.attachment system base.model_ir_attachment base.group_system 1 0 0 0
11 access_res_partner_group_user res.partner user base.model_res_partner base.group_document_user 1 1 1 0
12 access_document_directory_dctx_all document.directory.dctx all model_document_directory_dctx 1 0 0 0
13 access_document_directory_dctx_group_document_manager document.directory.dctx document manager model_document_directory_dctx base.group_system 1 1 1 1
14 access_report_document_user_group_document_manager report.document.user document manager model_report_document_user base.group_system 1 0 0 0
15 access_report_document_file_group_document_manager report.document.file document manager model_report_document_file base.group_system 1 0 0 0
16 access_report_document_file_group_document report.document.file document manager model_report_document_file base.group_document_user 1 0 0 0
17 access_report_document_user_knowledgeuser report.document.user knowledgeuser document.model_report_document_user base.group_document_user 1 0 0 0
18 access_document_storage access_document_storage model_document_storage base.group_system 1 1 1 1
-206
View File
@@ -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
-50
View File
@@ -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)
-88
View File
@@ -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')])
-118
View File
@@ -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
-53
View File
@@ -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
-3
View File
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 blog_blog_all blog.blog model_blog_blog 1 0 0 0
3 blog_blog blog.blog model_blog_blog base.group_document_user base.group_website_designer 1 1 1 1
4 blog_post_all blog.post model_blog_post 1 0 0 0
5 blog_post blog.post model_blog_post base.group_document_user base.group_website_designer 1 1 1 1
6 blog_tag blog.tag model_blog_tag 1 0 0 0
7 blog_tag_edition blog.tag model_blog_tag base.group_document_user base.group_website_designer 1 1 1 1
+1 -1
View File
@@ -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>