2009-12-02 05:36:57 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2009-12-02 05:36:57 +00:00
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base64
from osv import osv , fields
from osv . orm import except_orm
import urlparse
import os
import nodes
2009-12-15 10:48:10 +00:00
from tools . translate import _
2009-12-02 05:36:57 +00:00
class document_directory ( osv . osv ) :
_name = ' document.directory '
2010-05-19 18:32:32 +00:00
_description = ' Directory '
2010-01-26 19:44:40 +00:00
_order = ' name desc '
2009-12-02 05:36:57 +00:00
_columns = {
' name ' : fields . char ( ' Name ' , size = 64 , required = True , select = 1 ) ,
' write_date ' : fields . datetime ( ' Date Modified ' , readonly = True ) ,
' write_uid ' : fields . many2one ( ' res.users ' , ' Last Modification User ' , readonly = True ) ,
' create_date ' : fields . datetime ( ' Date Created ' , readonly = True ) ,
' create_uid ' : fields . many2one ( ' res.users ' , ' Creator ' , readonly = True ) ,
' domain ' : fields . char ( ' Domain ' , size = 128 , help = " Use a domain if you want to apply an automatic filter on visible resources. " ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' Owner ' ) ,
2009-12-07 13:11:11 +00:00
' storage_id ' : fields . many2one ( ' document.storage ' , ' Storage ' ) ,
2009-12-02 05:36:57 +00:00
' group_ids ' : fields . many2many ( ' res.groups ' , ' document_directory_group_rel ' , ' item_id ' , ' group_id ' , ' Groups ' ) ,
2010-06-29 14:00:29 +00:00
' parent_id ' : fields . many2one ( ' document.directory ' , ' Parent Directory ' , select = 1 ) ,
2009-12-02 05:36:57 +00:00
' child_ids ' : fields . one2many ( ' document.directory ' , ' parent_id ' , ' Children ' ) ,
' file_ids ' : fields . one2many ( ' ir.attachment ' , ' parent_id ' , ' Files ' ) ,
' content_ids ' : fields . one2many ( ' document.directory.content ' , ' directory_id ' , ' Virtual Files ' ) ,
2010-06-27 20:18:18 +00:00
' type ' : fields . selection ( [
( ' directory ' , ' Static Directory ' ) ,
( ' ressource ' , ' Folders per resource ' ) ,
( ' at_record ' , ' Single folder under resource ' ) ] ,
' Type ' , required = True , select = 1 ,
help = " Defines directory ' s behaviour. " ) ,
2010-06-27 20:18:26 +00:00
' ressource_type_id ' : fields . many2one ( ' ir.model ' , ' Resource model ' ,
help = " Select an object here and there will be one folder per record of that resource. " ) ,
2010-04-08 06:23:16 +00:00
' resource_field ' : fields . many2one ( ' ir.model.fields ' , ' Name field ' , help = ' Field to be used as name on resource directories. If empty, the " name " will be used. ' ) ,
2009-12-02 05:36:57 +00:00
' ressource_parent_type_id ' : fields . many2one ( ' ir.model ' , ' Parent Model ' ,
help = " If you put an object here, this directory template will appear bellow all of these objects. " \
" Don ' t put a parent directory if you select a parent model. " ) ,
' ressource_id ' : fields . integer ( ' Resource ID ' ) ,
' ressource_tree ' : fields . boolean ( ' Tree Structure ' ,
help = " Check this if you want to use the same tree structure as the object selected in the system. " ) ,
' dctx_ids ' : fields . one2many ( ' document.directory.dctx ' , ' dir_id ' , ' Context fields ' ) ,
2010-06-27 20:18:18 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' ) ,
2009-12-02 05:36:57 +00:00
}
2010-04-08 06:23:16 +00:00
2009-12-02 05:36:57 +00:00
def _get_root_directory ( self , cr , uid , context = None ) :
objid = self . pool . get ( ' ir.model.data ' )
try :
2010-04-08 06:23:16 +00:00
mid = objid . _get_id ( cr , uid , ' document ' , ' dir_root ' )
2009-12-02 05:36:57 +00:00
if not mid :
2010-03-10 10:53:34 +00:00
return False
2010-03-16 08:53:40 +00:00
root_id = objid . read ( cr , uid , mid , [ ' res_id ' ] ) [ ' res_id ' ]
return root_id
2009-12-02 05:36:57 +00:00
except Exception , e :
import netsvc
logger = netsvc . Logger ( )
logger . notifyChannel ( " document " , netsvc . LOG_WARNING , ' Cannot set directory root: ' + str ( e ) )
2010-03-10 10:53:34 +00:00
return False
2009-12-02 05:36:57 +00:00
return objid . browse ( cr , uid , mid , context = context ) . res_id
2010-06-16 11:51:39 +00:00
def _get_def_storage ( self , cr , uid , context = None ) :
2009-12-02 05:36:57 +00:00
if context and context . has_key ( ' default_parent_id ' ) :
# Use the same storage as the parent..
2010-06-16 11:51:39 +00:00
diro = self . browse ( cr , uid , context [ ' default_parent_id ' ] )
2009-12-02 05:36:57 +00:00
if diro . storage_id :
return diro . storage_id . id
objid = self . pool . get ( ' ir.model.data ' )
try :
mid = objid . _get_id ( cr , uid , ' document ' , ' storage_default ' )
return objid . browse ( cr , uid , mid , context = context ) . res_id
except Exception :
return None
_defaults = {
2010-06-23 11:53:49 +00:00
' company_id ' : lambda s , cr , uid , c : s . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' document.directory ' , context = c ) ,
2009-12-02 05:36:57 +00:00
' user_id ' : lambda self , cr , uid , ctx : uid ,
' domain ' : lambda self , cr , uid , ctx : ' [] ' ,
' type ' : lambda * args : ' directory ' ,
2010-04-13 11:03:20 +00:00
' ressource_id ' : lambda * a : 0 ,
2009-12-02 05:36:57 +00:00
' storage_id ' : _get_def_storage ,
}
_sql_constraints = [
( ' dirname_uniq ' , ' unique (name,parent_id,ressource_id,ressource_parent_type_id) ' , ' The directory name must be unique ! ' ) ,
2010-06-27 20:18:18 +00:00
( ' no_selfparent ' , ' check(parent_id <> id) ' , ' Directory cannot be parent of itself! ' ) ,
( ' dir_parented ' , ' check(parent_id IS NOT NULL OR storage_id IS NOT NULL) ' , ' Directory must have a parent or a storage ' )
2009-12-02 05:36:57 +00:00
]
2010-01-26 19:44:40 +00:00
def name_get ( self , cr , uid , ids , context = { } ) :
2010-01-26 20:12:47 +00:00
res = [ ]
2010-04-27 12:20:42 +00:00
if not self . search ( cr , uid , [ ( ' id ' , ' in ' , ids ) ] ) :
ids = [ ]
2010-01-26 19:44:40 +00:00
for d in self . browse ( cr , uid , ids , context = context ) :
2010-01-26 20:12:47 +00:00
s = ' '
d2 = d
2010-01-27 00:33:18 +00:00
while d2 and d2 . parent_id :
2010-01-26 20:12:47 +00:00
s = d2 . name + ( s and ( ' / ' + s ) or ' ' )
d2 = d2 . parent_id
2010-06-24 09:48:27 +00:00
res . append ( ( d . id , s or d . name ) )
2010-01-26 19:44:40 +00:00
return res
2009-12-02 05:36:57 +00:00
2010-03-16 08:53:40 +00:00
def get_full_path ( self , cr , uid , dir_id , context = None ) :
""" Return the full path to this directory, in a list, root first
"""
def _parent ( dir_id , path ) :
2010-06-16 11:51:39 +00:00
parent = self . browse ( cr , uid , dir_id )
2010-03-16 08:53:40 +00:00
if parent . parent_id and not parent . ressource_parent_type_id :
_parent ( parent . parent_id . id , path )
path . append ( parent . name )
else :
path . append ( parent . name )
return path
path = [ ]
_parent ( dir_id , path )
return path
2010-06-16 11:51:39 +00:00
def ol_get_resource_path ( self , cr , uid , dir_id , res_model , res_id ) :
2009-12-02 05:36:57 +00:00
# this method will be used in process module
# to be need test and Improvement if resource dir has parent resource (link resource)
path = [ ]
def _parent ( dir_id , path ) :
2010-06-16 11:51:39 +00:00
parent = self . browse ( cr , uid , dir_id )
2009-12-02 05:36:57 +00:00
if parent . parent_id and not parent . ressource_parent_type_id :
_parent ( parent . parent_id . id , path )
path . append ( parent . name )
else :
path . append ( parent . name )
return path
directory = self . browse ( cr , uid , dir_id )
2010-06-16 11:51:39 +00:00
model_ids = self . pool . get ( ' ir.model ' ) . search ( cr , uid , [ ( ' model ' , ' = ' , res_model ) ] )
2009-12-02 05:36:57 +00:00
if directory :
_parent ( dir_id , path )
2010-06-16 11:51:39 +00:00
path . append ( self . pool . get ( directory . ressource_type_id . model ) . browse ( cr , uid , res_id ) . name )
2009-12-02 05:36:57 +00:00
#user=self.pool.get('res.users').browse(cr,uid,uid)
#return "ftp://%s:%s@localhost:%s/%s/%s"%(user.login,user.password,config.get('ftp_server_port',8021),cr.dbname,'/'.join(path))
2009-12-07 13:11:11 +00:00
# No way we will return the password!
return " ftp://user:pass@host:port/test/this "
2009-12-02 05:36:57 +00:00
return False
def _check_recursion ( self , cr , uid , ids ) :
level = 100
while len ( ids ) :
cr . execute ( ' select distinct parent_id from document_directory where id in ( ' + ' , ' . join ( map ( str , ids ) ) + ' ) ' )
ids = filter ( None , map ( lambda x : x [ 0 ] , cr . fetchall ( ) ) )
if not level :
return False
level - = 1
return True
_constraints = [
( _check_recursion , ' Error! You can not create recursive Directories. ' , [ ' parent_id ' ] )
]
def __init__ ( self , * args , * * kwargs ) :
res = super ( document_directory , self ) . __init__ ( * args , * * kwargs )
#self._cache = {}
def onchange_content_id ( self , cr , uid , ids , ressource_type_id ) :
return { }
"""
PRE :
uri : of the form " Sales Order/SO001 "
PORT :
uri
object : the object . directory or object . directory . content
object2 : the other object linked ( if object . directory . content )
"""
def get_object ( self , cr , uid , uri , context = None ) :
""" Return a node object for the given uri.
This fn merely passes the call to node_context
"""
if not context :
context = { }
lang = context . get ( ' lang ' , False )
if not lang :
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid )
lang = user . context_lang
context [ ' lang ' ] = lang
try : #just instrumentation
2010-06-16 11:51:39 +00:00
return nodes . get_node_context ( cr , uid , context ) . get_uri ( cr , uri )
2009-12-02 05:36:57 +00:00
except Exception , e :
print " exception: " , e
raise
2010-04-13 11:03:20 +00:00
def _locate_child ( self , cr , uid , root_id , uri , nparent , ncontext ) :
2009-12-02 05:36:57 +00:00
""" try to locate the node in uri,
Return a tuple ( node_dir , remaining_path )
"""
2010-04-13 11:03:20 +00:00
return ( nodes . node_database ( context = ncontext ) , uri )
2009-12-02 05:36:57 +00:00
def old_code ( ) :
if not uri :
return node_database ( cr , uid , context = context )
turi = tuple ( uri )
node = node_class ( cr , uid , ' / ' , False , context = context , type = ' database ' )
for path in uri [ : ] :
if path :
node = node . child ( path )
if not node :
return False
oo = node . object and ( node . object . _name , node . object . id ) or False
oo2 = node . object2 and ( node . object2 . _name , node . object2 . id ) or False
return node
def ol_get_childs ( self , cr , uid , uri , context = { } ) :
node = self . get_object ( cr , uid , uri , context )
if uri :
children = node . children ( )
else :
children = [ node ]
result = map ( lambda node : node . path_get ( ) , children )
return result
def copy ( self , cr , uid , id , default = None , context = None ) :
if not default :
default = { }
name = self . read ( cr , uid , [ id ] ) [ 0 ] [ ' name ' ]
default . update ( { ' name ' : name + " (copy) " } )
2010-06-16 11:51:39 +00:00
return super ( document_directory , self ) . copy ( cr , uid , id , default , context )
2009-12-02 05:36:57 +00:00
2010-06-16 11:51:39 +00:00
def _check_duplication ( self , cr , uid , vals , ids = [ ] , op = ' create ' ) :
2009-12-02 05:36:57 +00:00
name = vals . get ( ' name ' , False )
parent_id = vals . get ( ' parent_id ' , False )
ressource_parent_type_id = vals . get ( ' ressource_parent_type_id ' , False )
ressource_id = vals . get ( ' ressource_id ' , 0 )
if op == ' write ' :
2010-06-16 11:51:39 +00:00
for directory in self . browse ( cr , uid , ids ) :
2009-12-02 05:36:57 +00:00
if not name :
name = directory . name
if not parent_id :
parent_id = directory . parent_id and directory . parent_id . id or False
if not ressource_parent_type_id :
ressource_parent_type_id = directory . ressource_parent_type_id and directory . ressource_parent_type_id . id or False
if not ressource_id :
ressource_id = directory . ressource_id and directory . ressource_id or 0
res = self . search ( cr , uid , [ ( ' id ' , ' <> ' , directory . id ) , ( ' name ' , ' = ' , name ) , ( ' parent_id ' , ' = ' , parent_id ) , ( ' ressource_parent_type_id ' , ' = ' , ressource_parent_type_id ) , ( ' ressource_id ' , ' = ' , ressource_id ) ] )
if len ( res ) :
return False
if op == ' create ' :
res = self . search ( cr , uid , [ ( ' name ' , ' = ' , name ) , ( ' parent_id ' , ' = ' , parent_id ) , ( ' ressource_parent_type_id ' , ' = ' , ressource_parent_type_id ) , ( ' ressource_id ' , ' = ' , ressource_id ) ] )
if len ( res ) :
return False
return True
def write ( self , cr , uid , ids , vals , context = None ) :
2010-06-16 11:51:39 +00:00
if not self . _check_duplication ( cr , uid , vals , ids , op = ' write ' ) :
2009-12-02 05:36:57 +00:00
raise osv . except_osv ( _ ( ' ValidateError ' ) , _ ( ' Directory name must be unique! ' ) )
2010-06-16 11:51:39 +00:00
return super ( document_directory , self ) . write ( cr , uid , ids , vals , context = context )
2009-12-02 05:36:57 +00:00
def create ( self , cr , uid , vals , context = None ) :
2010-06-16 11:51:39 +00:00
if not self . _check_duplication ( cr , uid , vals ) :
2009-12-02 05:36:57 +00:00
raise osv . except_osv ( _ ( ' ValidateError ' ) , _ ( ' Directory name must be unique! ' ) )
if vals . get ( ' name ' , False ) and ( vals . get ( ' name ' ) . find ( ' / ' ) + 1 or vals . get ( ' name ' ) . find ( ' @ ' ) + 1 or vals . get ( ' name ' ) . find ( ' $ ' ) + 1 or vals . get ( ' name ' ) . find ( ' # ' ) + 1 ) :
raise osv . except_osv ( _ ( ' ValidateError ' ) , _ ( ' Directory name contains special characters! ' ) )
return super ( document_directory , self ) . create ( cr , uid , vals , context )
document_directory ( )
class document_directory_dctx ( osv . osv ) :
""" In order to evaluate dynamic folders, child items could have a limiting
domain expression . For that , their parents will export a context where useful
information will be passed on .
If you define sth like " s_id " = " this.id " at a folder iterating over sales , its
children could have a domain like [ ( ' sale_id ' , = , dctx_s_id ) ]
This system should be used recursively , that is , parent dynamic context will be
appended to all children down the tree .
"""
_name = ' document.directory.dctx '
2010-05-19 18:32:32 +00:00
_description = ' Directory Dynamic Context '
2009-12-02 05:36:57 +00:00
_columns = {
' dir_id ' : fields . many2one ( ' document.directory ' , ' Directory ' , required = True ) ,
' field ' : fields . char ( ' Field ' , size = 20 , required = True , select = 1 , help = " The name of the field. Note that the prefix \" dctx_ \" will be prepended to what is typed here. " ) ,
' expr ' : fields . char ( ' Expression ' , size = 64 , required = True , help = " A python expression used to evaluate the field. \n " + \
" You can use ' dir_id ' for current dir, ' res_id ' , ' res_model ' as a reference to the current record, in dynamic folders " ) ,
}
document_directory_dctx ( )
class document_directory_node ( osv . osv ) :
_inherit = ' process.node '
_columns = {
' directory_id ' : fields . many2one ( ' document.directory ' , ' Document directory ' , ondelete = " set null " ) ,
}
document_directory_node ( )