[REM] base, workflow: removed res.roles object, replaced by dedicated res.groups

bzr revid: odo@openerp.com-20101013215340-jaiihef9chsym48z
This commit is contained in:
Olivier Dony 2010-10-13 23:53:40 +02:00
parent a79d0ee8e3
commit 88117959b5
10 changed files with 35 additions and 157 deletions

View File

@ -159,20 +159,6 @@ CREATE TABLE res_groups (
primary key(id)
);
create table res_roles (
id serial NOT NULL,
parent_id int references res_roles on delete set null,
name varchar(64) NOT NULL,
primary key(id)
);
CREATE TABLE res_roles_users_rel (
uid integer NOT NULL references res_users on delete cascade,
rid integer NOT NULL references res_roles on delete cascade
);
create index res_roles_users_rel_uid_idx on res_roles_users_rel (uid);
create index res_roles_users_rel_rid_idx on res_roles_users_rel (rid);
CREATE TABLE res_groups_users_rel (
uid integer NOT NULL references res_users on delete cascade,
gid integer NOT NULL references res_groups on delete cascade
@ -222,7 +208,7 @@ create table wkf_transition
trigger_expr_id varchar(128) default NULL,
signal varchar(64) default null,
role_id int references res_roles on delete set null,
group_id int references res_groups on delete set null,
primary key(id)
);

View File

@ -144,13 +144,10 @@
<field colspan="2" name="signature" nolabel="1"/>
</group>
<group colspan="2" col="2" expand="1">
<separator string="Access Rights (groups)" colspan="2"/>
<separator string="Groups" colspan="2"/>
<field colspan="2" nolabel="1" name="groups_id"/>
</group>
</page>
<page string="Roles">
<field colspan="4" nolabel="1" name="roles_id"/>
</page>
<page string="Companies" groups="base.group_multi_company">
<field colspan="4" nolabel="1" name="company_ids" select="1"/>
</page>

View File

@ -708,7 +708,7 @@
</record>
<menuitem action="action_res_company_form" id="menu_action_res_company_form" parent="base.menu_res_company_global"/>
<!-- User Roles -->
<!-- Users -->
<record id="action_res_users" model="ir.actions.act_window">
<field name="name">Users</field>
<field name="type">ir.actions.act_window</field>
@ -761,68 +761,6 @@
<menuitem action="action_res_groups" id="menu_action_res_groups" parent="base.menu_users"
groups="base.group_extended"/>
<record id="view_roles_form" model="ir.ui.view">
<field name="name">res.roles.form</field>
<field name="model">res.roles</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Role">
<field name="name"/>
<field name="parent_id"/>
<separator string="Description" colspan="4"/>
<field name="description" nolabel="1" colspan="4"/>
<separator string="Workflow transitions" colspan="4"/>
<field name="workflow_transition_ids" nolabel="1" colspan="4">
<tree string="Workflow transitions">
<field name="wkf_id"/>
<field name="act_from"/>
<field name="act_to"/>
<field name="signal"/>
<field name="condition"/>
</tree>
</field>
</form>
</field>
</record>
<record id="view_roles_tree" model="ir.ui.view">
<field name="name">res.roles.tree</field>
<field name="model">res.roles</field>
<field name="type">tree</field>
<field name="field_parent">child_id</field>
<field name="arch" type="xml">
<tree string="Roles">
<field name="name"/>
<field name="parent_id"/>
<field name="description"/>
</tree>
</field>
</record>
<record id="view_roles_search" model="ir.ui.view">
<field name="name">res.roles.search</field>
<field name="model">res.roles</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Role">
<field name="name"/>
<field name="parent_id"/>
<field name="description"/>
<newline/>
<group expand="0" string="Group By..." colspan="11" col="11" groups="base.group_extended">
<filter string="Parent" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'parent_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_res_roles_form" model="ir.actions.act_window">
<field name="name">Roles</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.roles</field>
<field name="view_type">form</field>
<field name="search_view_id" ref="view_roles_search"/>
</record>
<menuitem action="action_res_roles_form" id="menu_action_res_roles_form" parent="base.menu_users"/>
<!-- View -->
<record id="view_view_form" model="ir.ui.view">
<field name="name">ir.ui.view</field>

View File

@ -554,7 +554,7 @@ class ir_model_data(osv.osv):
if model=='workflow.activity':
cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
wkf_todo.extend(cr.fetchall())
cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
cr.execute("update wkf_transition set condition='True', group_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
cr.execute("delete from wkf_transition where act_to=%s", (res_id,))
for model,id in wkf_todo:

View File

@ -149,8 +149,8 @@ class wkf_transition(osv.osv):
'signal': fields.char('Signal (button Name)', size=64,
help="When the operation of transition comes from a button pressed in the client form, "\
"signal tests the name of the pressed button. If signal is NULL, no button is necessary to validate this transition."),
'role_id': fields.many2one('res.roles', 'Role Required',
help="The role that a user must have to validate this transition."),
'group_id': fields.many2one('res.groups', 'Group Required',
help="The group that a user must have to be authorized to validate this transition."),
'condition': fields.char('Condition', required=True, size=128,
help="Expression to be satisfied if we want the transition done."),
'act_from': fields.many2one('workflow.activity', 'Source Activity', required=True, select=True, ondelete='cascade',

View File

@ -217,7 +217,7 @@
<field name="condition"/>
<field name="trigger_model"/>
<field name="trigger_expr_id"/>
<field name="role_id"/>
<field name="group_id"/>
</group>
</form>
</field>

View File

@ -82,32 +82,6 @@ class groups(osv.osv):
groups()
class roles(osv.osv):
_name = "res.roles"
_columns = {
'name': fields.char('Role Name', size=64, required=True),
'parent_id': fields.many2one('res.roles', 'Parent', select=True,
help="The parent role can be used to construct a hierarchy of roles. Parent roles inherit from the roles of their descendants."),
'child_id': fields.one2many('res.roles', 'parent_id', 'Children'),
'users': fields.many2many('res.users', 'res_roles_users_rel', 'rid', 'uid', 'Users'),
'description': fields.text('Description', help="Description of this role and where it is relevant in workflows and processes"),
'workflow_transition_ids': fields.one2many('workflow.transition', 'role_id', 'Workflow Transitions',
help="The workflow transitions associated with this role"),
}
def check(self, cr, uid, ids, role_id):
"""Verifies that the role with id ``role_id`` is granted directly or indirectly to a
user that possesses the roles with ids ``ids``. Indirectly means that one of the
roles with id in ``ids`` is an ancestor role of the role with id ``role_id``.
"""
if role_id in ids:
return True
cr.execute('select parent_id from res_roles where id=%s', (role_id,))
roles = cr.fetchone()[0]
if roles:
return self.check(cr, uid, ids, roles)
return False
roles()
def _lang_get(self, cr, uid, context={}):
obj = self.pool.get('res.lang')
ids = obj.search(cr, uid, [('translatable','=',True)])
@ -236,7 +210,6 @@ class users(osv.osv):
'action_id': fields.many2one('ir.actions.actions', 'Home Action', help="If specified, this action will be opened at logon for this user, in addition to the standard menu."),
'menu_id': fields.many2one('ir.actions.actions', 'Menu Action', help="If specified, the action will replace the standard menu for this user."),
'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
# Special behavior for this field: res.company.search() will only return the companies
# available to the current user (should be the user's companies?), when the user_preference

View File

@ -108,8 +108,6 @@
"access_ir_actions_server_group_system","ir_actions_server_group_system","model_ir_actions_server","group_system",1,1,1,1
"access_res_bank_group_system","res_bank_group_system","model_res_bank","group_system",1,1,1,1
"access_res_payterm_group_system","res_payterm_group_system","model_res_payterm","group_system",1,1,1,1
"access_res_roles_group_erpmanager","res_roles_group_erp_manager","model_res_roles","group_erp_manager",1,1,1,1
"access_res_roles_all","res_roles_all","model_res_roles",,1,0,0,0
"access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_system",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
108 access_ir_actions_server_group_system ir_actions_server_group_system model_ir_actions_server group_system 1 1 1 1
109 access_res_bank_group_system res_bank_group_system model_res_bank group_system 1 1 1 1
110 access_res_payterm_group_system res_payterm_group_system model_res_payterm group_system 1 1 1 1
access_res_roles_group_erpmanager res_roles_group_erp_manager model_res_roles group_erp_manager 1 1 1 1
access_res_roles_all res_roles_all model_res_roles 1 0 0 0
111 access_res_bank_group_partner_manager res_bank_group_partner_manager model_res_bank group_partner_manager 1 1 1 1
112 access_res_bank_user res_bank user model_res_bank group_user 1 0 0 0
113 access_maintenance_group_user maintenance_contract group_user model_maintenance_contract group_system 1 1 1 1

View File

@ -1365,47 +1365,33 @@ class orm_template(object):
return fields
def __view_look_dom_arch(self, cr, user, node, view_id, context=None):
fields_def = self.__view_look_dom(cr, user, node, view_id, context=context)
def _disable_workflow_buttons(self, cr, user, node):
if user == 1:
# admin user can always activate workflow buttons
return node
rolesobj = self.pool.get('res.roles')
# TODO handle the case of more than one workflow for a model or multiple
# transitions with different groups and same signal
usersobj = self.pool.get('res.users')
buttons = (n for n in node.getiterator('button') if n.get('type') != 'object')
for button in buttons:
can_click = True
if user != 1: # admin user has all roles
user_roles = usersobj.read(cr, user, [user], ['roles_id'])[0]['roles_id']
# TODO handle the case of more than one workflow for a model
cr.execute("""SELECT DISTINCT t.role_id
FROM wkf
INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
INNER JOIN wkf_transition t ON (t.act_to = a.id)
WHERE wkf.osv = %s
AND t.signal = %s
""", (self._name, button.get('name'),))
roles = cr.fetchall()
# draft -> valid = signal_next (role X)
# draft -> cancel = signal_cancel (no role)
#
# valid -> running = signal_next (role Y)
# valid -> cancel = signal_cancel (role Z)
#
# running -> done = signal_next (role Z)
# running -> cancel = signal_cancel (role Z)
# As we don't know the object state, in this scenario,
# the button "signal_cancel" will be always shown as there is no restriction to cancel in draft
# the button "signal_next" will be show if the user has any of the roles (X Y or Z)
# The verification will be made later in workflow process...
if roles:
can_click = any((not role) or rolesobj.check(cr, user, user_roles, role) for (role,) in roles)
user_groups = usersobj.read(cr, user, [user], ['groups_id'])[0]['groups_id']
cr.execute("""SELECT DISTINCT t.group_id
FROM wkf
INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
INNER JOIN wkf_transition t ON (t.act_to = a.id)
WHERE wkf.osv = %s
AND t.signal = %s
""", (self._name, button.get('name')))
group_ids = [x[0] for x in cr.fetchall()]
can_click = not group_ids or bool(set(user_groups).intersection(group_ids))
button.set('readonly', str(int(not can_click)))
return node
def __view_look_dom_arch(self, cr, user, node, view_id, context=None):
fields_def = self.__view_look_dom(cr, user, node, view_id, context=context)
node = self._disable_workflow_buttons(cr, user, node)
arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
fields = {}
if node.tag == 'diagram':
if node.getchildren()[0].tag == 'node':

View File

@ -68,17 +68,17 @@ def execute(cr, ident, workitem, activity):
return _eval_expr(cr, ident, workitem, activity['action'])
def check(cr, workitem, ident, transition, signal):
ok = True
if transition['signal']:
ok = (signal==transition['signal'])
if transition['signal'] and signal != transition['signal']:
return False
uid = ident[0]
if transition['role_id'] and uid != 1:
if transition['group_id'] and uid != 1:
pool = pooler.get_pool(cr.dbname)
user_roles = pool.get('res.users').read(cr, uid, [uid], ['roles_id'])[0]['roles_id']
ok = ok and pool.get('res.roles').check(cr, uid, user_roles, transition['role_id'])
ok = ok and _eval_expr(cr, ident, workitem, transition['condition'])
return ok
user_groups = pool.get('res.users').read(cr, uid, [uid], ['groups_id'])[0]['groups_id']
if not transition['group_id'] in user_groups:
return False
return _eval_expr(cr, ident, workitem, transition['condition'])
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: