2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2007-05-18 12:29:43 +00:00
##############################################################################
2010-03-19 10:58:38 +00:00
#
2009-10-14 12:32:15 +00:00
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2008-06-16 11:00:21 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 12:32:15 +00:00
# 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.
2007-05-18 12:29:43 +00:00
#
2008-11-03 18:27:16 +00:00
# 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
2009-10-14 12:32:15 +00:00
# GNU Affero General Public License for more details.
2007-05-18 12:29:43 +00:00
#
2009-10-14 12:32:15 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-03-19 10:58:38 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2007-05-18 12:29:43 +00:00
#
##############################################################################
2011-03-24 11:17:57 +00:00
from osv import fields , osv , expression
2007-05-18 12:29:43 +00:00
import time
2010-06-10 14:57:22 +00:00
from operator import itemgetter
from functools import partial
2007-05-18 12:29:43 +00:00
import tools
2010-05-03 23:49:53 +00:00
from tools . safe_eval import safe_eval as eval
2011-04-08 14:02:41 +00:00
from tools . misc import unquote as unquote
2007-08-22 05:17:13 +00:00
2007-05-18 12:29:43 +00:00
class ir_rule ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = ' ir.rule '
2010-12-10 22:42:58 +00:00
_order = ' name '
2010-06-10 14:57:22 +00:00
_MODES = [ ' read ' , ' write ' , ' create ' , ' unlink ' ]
2008-07-22 14:24:36 +00:00
2011-04-08 14:02:41 +00:00
def _eval_context_for_combinations ( self ) :
""" Returns a dictionary to use as evaluation context for
ir . rule domains , when the goal is to obtain python lists
that are easier to parse and combine , but not to
actually execute them . """
return { ' user ' : unquote ( ' user ' ) ,
' time ' : unquote ( ' time ' ) }
def _eval_context ( self , cr , uid ) :
""" Returns a dictionary to use as evaluation context for
ir . rule domains . """
return { ' user ' : self . pool . get ( ' res.users ' ) . browse ( cr , 1 , uid ) ,
' time ' : time }
def domain_binary_operation ( self , cr , uid , str_domain_1 , str_domain_2 , operator ) :
""" Returns the string representation of the binary operation designated by
` ` operator ` ` ( should be ' | ' or ' & ' ) for the two string domains ` ` str_domain_1 ` `
and ` ` str_domain_2 ` ` """
eval_context = self . _eval_context_for_combinations ( )
canonical_domain_1 = expression . expression . normalize_domain ( eval ( str_domain_1 or ' [] ' , eval_context ) )
canonical_domain_2 = expression . expression . normalize_domain ( eval ( str_domain_2 or ' [] ' , eval_context ) )
return str ( [ operator ] + canonical_domain_1 + canonical_domain_1 )
def domain_conjunction ( self , cr , uid , str_domain_1 , str_domain_2 ) :
""" Returns the string representation of the conjunction (AND) of the
two string domains ` ` str_domain_1 ` ` and ` ` str_domain_2 ` ` """
return self . domain_binary_operation ( cr , uid , str_domain_1 , str_domain_2 , expression . AND_OPERATOR )
def domain_disjunction ( self , cr , uid , str_domain_1 , str_domain_2 ) :
""" Returns the string representation of the disjunction (OR) of the
two string domains ` ` str_domain_1 ` ` and ` ` str_domain_2 ` ` """
return self . domain_binary_operation ( cr , uid , str_domain_1 , str_domain_2 , expression . OR_OPERATOR )
2011-03-02 11:08:16 +00:00
def _domain_force_get ( self , cr , uid , ids , field_name , arg , context = None ) :
2008-07-22 14:24:36 +00:00
res = { }
2011-04-08 14:02:41 +00:00
eval_context = self . _eval_context ( cr , uid )
2008-07-22 14:24:36 +00:00
for rule in self . browse ( cr , uid , ids , context ) :
2011-02-28 11:44:20 +00:00
if rule . domain_force :
2011-04-08 14:02:41 +00:00
res [ rule . id ] = expression . expression . normalize_domain ( eval ( rule . domain_force , eval_context ) )
2011-02-28 11:44:20 +00:00
else :
res [ rule . id ] = [ ]
2010-04-29 12:01:58 +00:00
return res
2010-03-19 10:58:38 +00:00
2011-03-02 11:08:16 +00:00
def _get_value ( self , cr , uid , ids , field_name , arg , context = None ) :
2010-04-29 12:01:58 +00:00
res = { }
for rule in self . browse ( cr , uid , ids , context ) :
if not rule . groups :
res [ rule . id ] = True
2008-07-22 14:24:36 +00:00
else :
2010-04-29 12:01:58 +00:00
res [ rule . id ] = False
2008-07-22 14:24:36 +00:00
return res
2010-12-09 10:57:33 +00:00
def _check_model_obj ( self , cr , uid , ids , context = None ) :
2010-06-10 14:57:22 +00:00
return not any ( isinstance ( self . pool . get ( rule . model_id . model ) , osv . osv_memory ) for rule in self . browse ( cr , uid , ids , context ) )
2010-04-29 12:01:58 +00:00
2008-07-22 14:24:36 +00:00
_columns = {
2010-04-29 12:01:58 +00:00
' name ' : fields . char ( ' Name ' , size = 128 , select = 1 ) ,
' model_id ' : fields . many2one ( ' ir.model ' , ' Object ' , select = 1 , required = True ) ,
2010-04-29 15:35:12 +00:00
' global ' : fields . function ( _get_value , method = True , string = ' Global ' , type = ' boolean ' , store = True , help = " If no group is specified the rule is global and applied to everyone " ) ,
2010-04-29 12:01:58 +00:00
' groups ' : fields . many2many ( ' res.groups ' , ' rule_group_rel ' , ' rule_group_id ' , ' group_id ' , ' Groups ' ) ,
2010-08-05 13:46:26 +00:00
' domain_force ' : fields . text ( ' Domain ' ) ,
' domain ' : fields . function ( _domain_force_get , method = True , string = ' Domain ' , type = ' text ' ) ,
2010-04-29 12:01:58 +00:00
' perm_read ' : fields . boolean ( ' Apply For Read ' ) ,
' perm_write ' : fields . boolean ( ' Apply For Write ' ) ,
' perm_create ' : fields . boolean ( ' Apply For Create ' ) ,
' perm_unlink ' : fields . boolean ( ' Apply For Delete ' )
2010-03-19 10:58:38 +00:00
}
2010-04-29 12:01:58 +00:00
_order = ' model_id DESC '
2010-03-19 10:58:38 +00:00
_defaults = {
2010-04-29 12:01:58 +00:00
' perm_read ' : True ,
' perm_write ' : True ,
' perm_create ' : True ,
' perm_unlink ' : True ,
' global ' : True ,
2008-07-22 14:24:36 +00:00
}
2010-03-19 10:58:38 +00:00
_sql_constraints = [
2010-09-09 11:02:11 +00:00
( ' no_access_rights ' , ' CHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False) ' , ' Rule must have at least one checked access right ! ' ) ,
2010-03-19 10:58:38 +00:00
]
2010-04-29 12:01:58 +00:00
_constraints = [
( _check_model_obj , ' Rules are not supported for osv_memory objects ! ' , [ ' model_id ' ] )
]
2008-07-22 14:24:36 +00:00
2010-04-29 12:01:58 +00:00
def domain_create ( self , cr , uid , rule_ids ) :
2011-02-28 11:44:20 +00:00
count = 0
dom = [ ]
2010-04-29 12:01:58 +00:00
for rule in self . browse ( cr , uid , rule_ids ) :
2011-02-28 11:44:20 +00:00
if rule . domain :
dom + = rule . domain
count + = 1
if count :
2011-03-24 11:17:57 +00:00
return [ expression . AND_OPERATOR ] * ( count - 1 ) + dom
2011-02-28 11:44:20 +00:00
return [ ]
2008-07-22 14:24:36 +00:00
2010-04-29 15:35:12 +00:00
@tools.cache ( )
def _compute_domain ( self , cr , uid , model_name , mode = " read " ) :
2010-06-10 14:57:22 +00:00
if mode not in self . _MODES :
raise ValueError ( ' Invalid mode: %r ' % ( mode , ) )
2010-04-29 12:01:58 +00:00
group_rule = { }
global_rules = [ ]
2008-07-22 14:24:36 +00:00
if uid == 1 :
2010-04-29 15:35:12 +00:00
return None
2010-03-19 10:58:38 +00:00
cr . execute ( """ SELECT r.id
FROM ir_rule r
2010-04-29 12:01:58 +00:00
JOIN ir_model m ON ( r . model_id = m . id )
2008-07-22 14:24:36 +00:00
WHERE m . model = % s
2010-03-19 10:58:38 +00:00
AND r . perm_ """ + mode + """
2010-04-29 12:01:58 +00:00
AND ( r . id IN ( SELECT rule_group_id FROM rule_group_rel g_rel
2008-07-22 14:24:36 +00:00
JOIN res_groups_users_rel u_rel ON ( g_rel . group_id = u_rel . gid )
2010-04-29 12:01:58 +00:00
WHERE u_rel . uid = % s ) OR r . global ) """ , (model_name, uid))
2010-03-19 10:58:38 +00:00
ids = map ( lambda x : x [ 0 ] , cr . fetchall ( ) )
2010-08-17 18:35:50 +00:00
if ids :
for rule in self . browse ( cr , uid , ids ) :
for group in rule . groups :
group_rule . setdefault ( group . id , [ ] ) . append ( rule . id )
if not rule . groups :
global_rules . append ( rule . id )
2011-02-28 11:44:20 +00:00
global_domain = self . domain_create ( cr , uid , global_rules )
count = 0
group_domains = [ ]
2010-08-17 18:35:50 +00:00
for value in group_rule . values ( ) :
2011-02-28 11:44:20 +00:00
group_domain = self . domain_create ( cr , uid , value )
if group_domain :
group_domains + = group_domain
count + = 1
if count and global_domain :
2011-03-24 11:17:57 +00:00
return [ expression . AND_OPERATOR ] + global_domain + [ expression . OR_OPERATOR ] * ( count - 1 ) + group_domains
2011-02-28 11:44:20 +00:00
if count :
2011-03-24 11:17:57 +00:00
return [ expression . OR_OPERATOR ] * ( count - 1 ) + group_domains
2011-03-02 08:35:38 +00:00
return global_domain
2010-08-17 18:35:50 +00:00
return [ ]
2010-04-29 15:35:12 +00:00
2010-06-10 14:57:22 +00:00
def clear_cache ( self , cr , uid ) :
cr . execute ( """ SELECT DISTINCT m.model
FROM ir_rule r
JOIN ir_model m
ON r . model_id = m . id
WHERE r . global
OR EXISTS ( SELECT 1
FROM rule_group_rel g_rel
JOIN res_groups_users_rel u_rel
ON g_rel . group_id = u_rel . gid
WHERE g_rel . rule_group_id = r . id
AND u_rel . uid = % s )
""" , (uid,))
models = map ( itemgetter ( 0 ) , cr . fetchall ( ) )
clear = partial ( self . _compute_domain . clear_cache , cr . dbname , uid )
[ clear ( model , mode ) for model in models for mode in self . _MODES ]
2011-03-02 11:08:16 +00:00
def domain_get ( self , cr , uid , model_name , mode = ' read ' , context = None ) :
2010-04-29 15:35:12 +00:00
dom = self . _compute_domain ( cr , uid , model_name , mode = mode )
if dom :
2011-03-02 08:35:38 +00:00
# _where_calc is called as superuser. This means that rules can
# involve objects on which the real uid has no acces rights.
# This means also there is no implicit restriction (e.g. an object
# references another object the user can't see).
query = self . pool . get ( model_name ) . _where_calc ( cr , 1 , dom , active_test = False )
2010-09-30 13:24:03 +00:00
return query . where_clause , query . where_clause_params , query . tables
2010-04-29 15:35:12 +00:00
return [ ] , [ ] , [ ' " ' + self . pool . get ( model_name ) . _table + ' " ' ]
2008-07-22 14:24:36 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
res = super ( ir_rule , self ) . unlink ( cr , uid , ids , context = context )
2010-04-29 15:35:12 +00:00
# Restart the cache on the _compute_domain method of ir.rule
self . _compute_domain . clear_cache ( cr . dbname )
2008-07-22 14:24:36 +00:00
return res
def create ( self , cr , user , vals , context = None ) :
res = super ( ir_rule , self ) . create ( cr , user , vals , context = context )
2010-04-29 15:35:12 +00:00
# Restart the cache on the _compute_domain method of ir.rule
self . _compute_domain . clear_cache ( cr . dbname )
2008-07-22 14:24:36 +00:00
return res
def write ( self , cr , uid , ids , vals , context = None ) :
res = super ( ir_rule , self ) . write ( cr , uid , ids , vals , context = context )
2010-04-29 15:35:12 +00:00
# Restart the cache on the _compute_domain method
self . _compute_domain . clear_cache ( cr . dbname )
2008-07-22 14:24:36 +00:00
return res
2007-05-18 12:29:43 +00:00
ir_rule ( )
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: