[IMP] base: make group "Technical Features" effective in debug mode only

In method `user_has_groups`, make "Technical Features" effective in debug mode.
Make the group "Employees" inherit "Technical Features".
Make the group "Technical Features" invisible in the user form view.
Remove useless `ir.rule` attached on group "Technical Features".
Fix `test_acl` by avoiding the tricks around the group "Technical Features".
This commit is contained in:
Ajay Javiya
2015-08-28 14:51:09 +02:00
committed by Raphael Collet
parent de5366ac33
commit 31518bc09b
9 changed files with 54 additions and 44 deletions
+1 -1
View File
@@ -149,7 +149,7 @@ class ir_import(orm.TransientModel):
elif field['type'] == 'one2many' and depth:
f['fields'] = self.get_fields(
cr, uid, field['relation'], context=context, depth=depth-1)
if self.pool['res.users'].has_group(cr, uid, 'base.group_no_one'):
if self.user_has_groups(cr, uid, 'base.group_no_one'):
f['fields'].append({'id' : '.id', 'name': '.id', 'string': _("Database ID"), 'required': False, 'fields': []})
fields.append(f)
-11
View File
@@ -23,17 +23,6 @@
<field name="perm_read" eval="False"/>
</record>
<!-- If technical rights then read and write others subscriptions -->
<record id="mail_followers_rule_write_admin" model="ir.rule">
<field name="name">mail.followers: read and write others entries</field>
<field name="model_id" ref="model_mail_followers"/>
<field name="groups" eval="[(4, ref('base.group_no_one'))]"/>
<field name="domain_force">[]</field>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="perm_read" eval="False"/>
</record>
<record id="mail_message_subtype_rule_public" model="ir.rule">
<field name="name">mail.message.subtype: portal/public: read public subtypes</field>
<field name="model_id" ref="model_mail_message_subtype"/>
+1 -1
View File
@@ -528,7 +528,7 @@ class Home(http.Controller):
return werkzeug.utils.redirect(kw.get('redirect'), 303)
request.uid = request.session.uid
menu_data = request.registry['ir.ui.menu'].load_menus(request.cr, request.uid, context=request.context)
menu_data = request.registry['ir.ui.menu'].load_menus(request.cr, request.uid, request.debug, context=request.context)
return request.render('web.webclient_bootstrap', qcontext={'menu_data': menu_data})
@http.route('/web/dbredirect', type='http', auth="none")
+7 -6
View File
@@ -9,6 +9,7 @@ import threading
import openerp.modules
from openerp.osv import fields, osv
from openerp import api, tools
from openerp.http import request
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
@@ -23,15 +24,15 @@ class ir_ui_menu(osv.osv):
self.pool['ir.model.access'].register_cache_clearing_method(self._name, 'clear_caches')
@api.model
@tools.ormcache('frozenset(self.env.user.groups_id.ids)')
def _visible_menu_ids(self):
@tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'debug')
def _visible_menu_ids(self, debug=False):
""" Return the ids of the menu items visible to the user. """
# retrieve all menus, and determine which ones are visible
context = {'ir.ui.menu.full_list': True}
menus = self.with_context(context).search([])
groups = self.env.user.groups_id if debug else self.env.user.groups_id - self.env.ref('base.group_no_one')
# first discard all menus with groups the user does not have
groups = self.env.user.groups_id
menus = menus.filtered(
lambda menu: not menu.groups_id or menu.groups_id & groups)
@@ -68,7 +69,7 @@ class ir_ui_menu(osv.osv):
the menu hierarchy of the current user.
Uses a cache for speeding up the computation.
"""
visible_ids = self._visible_menu_ids()
visible_ids = self._visible_menu_ids(request.debug if request else False)
return self.filtered(lambda menu: menu.id in visible_ids)
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
@@ -271,8 +272,8 @@ class ir_ui_menu(osv.osv):
}
@api.cr_uid_context
@tools.ormcache_context('uid', keys=('lang',))
def load_menus(self, cr, uid, context=None):
@tools.ormcache_context('uid', 'debug', keys=('lang',))
def load_menus(self, cr, uid, debug, context=None):
""" Loads all menu items (all applications and their sub-menus).
:return: the menu root
+6 -1
View File
@@ -780,6 +780,7 @@ class groups_view(osv.osv):
user_context.update(self.pool['res.users'].context_get(cr, uid))
view = self.pool['ir.model.data'].xmlid_to_object(cr, SUPERUSER_ID, 'base.user_groups_view', context=user_context)
if view and view.exists() and view._name == 'ir.ui.view':
group_no_one = view.env.ref('base.group_no_one')
xml1, xml2 = [], []
xml1.append(E.separator(string=_('Application'), colspan="2"))
for app, kind, gs in self.get_groups_by_application(cr, uid, user_context):
@@ -796,7 +797,11 @@ class groups_view(osv.osv):
xml2.append(E.separator(string=app_name, colspan="4", **attrs))
for g in gs:
field_name = name_boolean_group(g.id)
xml2.append(E.field(name=field_name, **attrs))
if g == group_no_one:
# make the group_no_one invisible in the form view
xml2.append(E.field(name=field_name, invisible="1", **attrs))
else:
xml2.append(E.field(name=field_name, **attrs))
xml2.append({'class': "o_label_nowrap"})
xml = E.field(E.group(*(xml1), col="2"), E.group(*(xml2), col="4"), name="groups_id", position="replace")
@@ -42,6 +42,9 @@
<record model="res.groups" id="group_no_one">
<field name="name">Technical Features</field>
</record>
<record model="res.groups" id="group_user">
<field name="implied_ids" eval="[(4, ref('group_no_one'))]"/>
</record>
<record id="group_sale_salesman" model="res.groups">
<field name="name">User</field>
+21 -21
View File
@@ -6,7 +6,8 @@ from openerp.tools.misc import mute_logger
from openerp.tests import common
# test group that demo user should not have
GROUP_TECHNICAL_FEATURES = 'base.group_no_one'
GROUP_SYSTEM = 'base.group_system'
GROUP_ERP_MANAGER = 'base.group_erp_manager'
class TestACL(common.TransactionCase):
@@ -17,17 +18,16 @@ class TestACL(common.TransactionCase):
self.res_partner = self.registry('res.partner')
self.res_users = self.registry('res.users')
self.res_company = self.registry('res.company')
self.demo_uid = self.registry('ir.model.data').xmlid_to_res_id(self.cr, self.uid, 'base.user_demo')
self.tech_group = self.registry('ir.model.data').xmlid_to_object(self.cr, self.uid, GROUP_TECHNICAL_FEATURES)
self.erp_manager_group = self.registry('ir.model.data').xmlid_to_object(self.cr, self.uid, 'base.group_erp_manager')
self.erp_system_group = self.registry('ir.model.data').xmlid_to_object(self.cr, self.uid, 'base.group_system')
self.demo_uid = self.env.ref('base.user_demo').id
self.erp_system_group = self.env.ref(GROUP_SYSTEM)
self.erp_manager_group = self.env.ref(GROUP_ERP_MANAGER)
def _set_field_groups(self, model, field_name, groups):
field = model._fields[field_name]
column = model._columns[field_name]
old_groups = field.groups
old_prefetch = column._prefetch
field.groups = groups
column.groups = groups
column._prefetch = False
@@ -45,14 +45,14 @@ class TestACL(common.TransactionCase):
original_fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
view_arch = etree.fromstring(form_view.get('arch'))
has_tech_feat = self.res_users.has_group(self.cr, self.demo_uid, GROUP_TECHNICAL_FEATURES)
self.assertFalse(has_tech_feat, "`demo` user should not belong to the restricted group before the test")
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group before the test")
self.assertTrue('decimal_places' in original_fields, "'decimal_places' field must be properly visible before the test")
self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [],
"Field 'decimal_places' must be found in view definition before the test")
# restrict access to the field and check it's gone
self._set_field_groups(self.res_currency, 'decimal_places', GROUP_TECHNICAL_FEATURES)
self._set_field_groups(self.res_currency, 'decimal_places', GROUP_SYSTEM)
fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
@@ -62,31 +62,31 @@ class TestACL(common.TransactionCase):
"Field 'decimal_places' must not be found in view definition")
# Make demo user a member of the restricted group and check that the field is back
self.tech_group.write({'users': [(4, self.demo_uid)]})
has_tech_feat = self.res_users.has_group(self.cr, self.demo_uid, GROUP_TECHNICAL_FEATURES)
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
view_arch = etree.fromstring(form_view.get('arch'))
#import pprint; pprint.pprint(fields); pprint.pprint(form_view)
self.assertTrue(has_tech_feat, "`demo` user should now belong to the restricted group")
self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group")
self.assertTrue('decimal_places' in fields, "'decimal_places' field must be properly visible again")
self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [],
"Field 'decimal_places' must be found in view definition again")
#cleanup
self.tech_group.write({'users': [(3, self.demo_uid)]})
self.erp_system_group.write({'users': [(3, self.demo_uid)]})
@mute_logger('openerp.models')
def test_field_crud_restriction(self):
"Read/Write RPC access to restricted field should be forbidden"
# Verify the test environment first
has_tech_feat = self.res_users.has_group(self.cr, self.demo_uid, GROUP_TECHNICAL_FEATURES)
self.assertFalse(has_tech_feat, "`demo` user should not belong to the restricted group")
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group")
self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids']))
self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []}))
# Now restrict access to the field and check it's forbidden
self._set_field_groups(self.res_partner, 'bank_ids', GROUP_TECHNICAL_FEATURES)
self._set_field_groups(self.res_partner, 'bank_ids', GROUP_SYSTEM)
with self.assertRaises(AccessError):
self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])
@@ -94,19 +94,19 @@ class TestACL(common.TransactionCase):
self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})
# Add the restricted group, and check that it works again
self.tech_group.write({'users': [(4, self.demo_uid)]})
has_tech_feat = self.res_users.has_group(self.cr, self.demo_uid, GROUP_TECHNICAL_FEATURES)
self.assertTrue(has_tech_feat, "`demo` user should now belong to the restricted group")
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group")
self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids']))
self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []}))
#cleanup
self.tech_group.write({'users': [(3, self.demo_uid)]})
self.erp_system_group.write({'users': [(3, self.demo_uid)]})
@mute_logger('openerp.models')
def test_fields_browse_restriction(self):
"""Test access to records having restricted fields"""
self._set_field_groups(self.res_partner, 'email', GROUP_TECHNICAL_FEATURES)
self._set_field_groups(self.res_partner, 'email', GROUP_SYSTEM)
pid = self.res_partner.search(self.cr, self.demo_uid, [], limit=1)[0]
part = self.res_partner.browse(self.cr, self.demo_uid, pid)
+4 -1
View File
@@ -314,7 +314,10 @@ class WebRequest(object):
def debug(self):
""" Indicates whether the current request is in "debug" mode
"""
return 'debug' in self.httprequest.args
debug = 'debug' in self.httprequest.args
if not debug and self.httprequest.referrer:
debug = bool(urlparse.parse_qs(urlparse.urlparse(self.httprequest.referrer).query, keep_blank_values=True).get('debug'))
return debug
@contextlib.contextmanager
def registry_cr(self):
+11 -2
View File
@@ -1339,8 +1339,17 @@ class BaseModel(object):
:return: True if the current user is a member of one of the
given groups
"""
return any(self.pool['res.users'].has_group(cr, uid, group_ext_id)
for group_ext_id in groups.split(','))
from openerp.http import request
Users = self.pool['res.users']
for group_ext_id in groups.split(','):
if group_ext_id == 'base.group_no_one':
# check: the group_no_one is effective in debug mode only
if Users.has_group(cr, uid, group_ext_id) and request and request.debug:
return True
else:
if Users.has_group(cr, uid, group_ext_id):
return True
return False
def _get_default_form_view(self, cr, user, context=None):
""" Generates a default single-line form view using all fields