[IMP] ir_ui_view, view_form: add information about the user
being able to create and write on many2one and many2many records in a form view. Indeed before this commit users had always the possibility to create or edit records leading to a crash if no access rights were granted. Now the option is not displayed if the user has no rights to do it. Tests have been added for this feature.
This commit is contained in:
committed by
Thibault Delavallée
parent
420479658e
commit
dc3fbb17fa
@@ -3336,6 +3336,8 @@ instance.web.form.CompletionFieldMixin = {
|
||||
init: function() {
|
||||
this.limit = 7;
|
||||
this.orderer = new instance.web.DropMisordered();
|
||||
this.can_create = this.node.attrs.can_create || true;
|
||||
this.can_write = this.node.attrs.can_write || true;
|
||||
},
|
||||
/**
|
||||
* Call this method to search using a string.
|
||||
@@ -3382,7 +3384,7 @@ instance.web.form.CompletionFieldMixin = {
|
||||
var raw_result = _(data.result).map(function(x) {return x[1];});
|
||||
if (search_val.length > 0 && !_.include(raw_result, search_val) &&
|
||||
! (self.options && (self.options.no_create || self.options.no_quick_create))) {
|
||||
values.push({
|
||||
self.can_create && values.push({
|
||||
label: _.str.sprintf(_t('Create "<strong>%s</strong>"'),
|
||||
$('<span />').text(search_val).html()),
|
||||
action: function() {
|
||||
@@ -3392,7 +3394,7 @@ instance.web.form.CompletionFieldMixin = {
|
||||
});
|
||||
}
|
||||
// create...
|
||||
if (!(self.options && (self.options.no_create || self.options.no_create_edit))){
|
||||
if (!(self.options && (self.options.no_create || self.options.no_create_edit)) && self.can_create){
|
||||
values.push({
|
||||
label: _t("Create and Edit..."),
|
||||
action: function() {
|
||||
@@ -3402,11 +3404,11 @@ instance.web.form.CompletionFieldMixin = {
|
||||
});
|
||||
}
|
||||
else if (values.length == 0)
|
||||
values.push({
|
||||
label: _t("No results to show..."),
|
||||
action: function() {},
|
||||
classname: 'oe_m2o_dropdown_option'
|
||||
});
|
||||
values.push({
|
||||
label: _t("No results to show..."),
|
||||
action: function() {},
|
||||
classname: 'oe_m2o_dropdown_option'
|
||||
});
|
||||
|
||||
return values;
|
||||
});
|
||||
@@ -3600,7 +3602,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
|
||||
self.build_context(),
|
||||
{
|
||||
title: _t("Open: ") + self.string,
|
||||
view_id: view_id
|
||||
view_id: view_id,
|
||||
readonly: !self.can_write
|
||||
}
|
||||
);
|
||||
pop.on('write_completed', self, function(){
|
||||
@@ -3677,7 +3680,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
|
||||
self.uned_def.reject();
|
||||
self.ed_def = $.Deferred();
|
||||
self.ed_def.done(function() {
|
||||
self.show_error_displayer();
|
||||
self.can_create && self.show_error_displayer();
|
||||
ignore_blur = false;
|
||||
self.trigger('focused');
|
||||
});
|
||||
|
||||
@@ -722,6 +722,10 @@ class view(osv.osv):
|
||||
'fields': xfields
|
||||
}
|
||||
attrs = {'views': views}
|
||||
Relation = self.pool.get(field.comodel_name)
|
||||
if Relation and field.type in ('many2one', 'many2many'):
|
||||
node.set('can_create', 'true' if Relation.check_access_rights(cr, user, 'create', raise_exception=False) else 'false')
|
||||
node.set('can_write', 'true' if Relation.check_access_rights(cr, user, 'write', raise_exception=False) else 'false')
|
||||
fields[node.get('name')] = attrs
|
||||
|
||||
field = model_fields.get(node.get('name'))
|
||||
|
||||
@@ -562,6 +562,8 @@
|
||||
<rng:optional><rng:attribute name="filters"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="statusbar_visible"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="statusbar_colors"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="can_create" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="can_write" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="interval" /></rng:optional>
|
||||
<!-- Widget *static* options defined as an arbitrary JSON dict, with
|
||||
widget-dependent parameters. To be ignored if widget/client does
|
||||
|
||||
@@ -16,9 +16,11 @@ class TestACL(common.TransactionCase):
|
||||
self.res_currency = self.registry('res.currency')
|
||||
self.res_partner = self.registry('res.partner')
|
||||
self.res_users = self.registry('res.users')
|
||||
_, self.demo_uid = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, 'base', 'user_demo')
|
||||
self.tech_group = self.registry('ir.model.data').get_object(self.cr, self.uid,
|
||||
*(GROUP_TECHNICAL_FEATURES.split('.')))
|
||||
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')
|
||||
|
||||
def _set_field_groups(self, model, field_name, groups):
|
||||
field = model._fields[field_name]
|
||||
@@ -118,5 +120,49 @@ class TestACL(common.TransactionCase):
|
||||
#Useless because we get the title in the client side now in the chrome.js file(map_title)
|
||||
#self.assertEqual(cm.exception.args[0], 'Access Error')
|
||||
|
||||
def test_view_create_edit_button_invisibility(self):
|
||||
""" Test form view Create, Edit, Delete button visibility based on access right of model"""
|
||||
methods = ['create', 'edit', 'delete']
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
for method in methods:
|
||||
self.assertEqual(view_arch.get(method), 'false')
|
||||
|
||||
def test_view_create_edit_button_visibility(self):
|
||||
""" Test form view Create, Edit, Delete button visibility based on access right of model"""
|
||||
methods = ['create', 'edit', 'delete']
|
||||
self.erp_manager_group.write({'users': [(4, self.demo_uid)]})
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
for method in methods:
|
||||
self.assertIsNone(view_arch.get(method))
|
||||
# cleanup
|
||||
self.erp_manager_group.write({'users': [(3, self.demo_uid)]})
|
||||
|
||||
def test_m2o_field_create_edit_invisibility(self):
|
||||
""" Test many2one field Create and Edit option visibility based on access rights of relation field"""
|
||||
methods = ['create', 'write']
|
||||
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
field_node = view_arch.xpath("//field[@name='currency_id']")
|
||||
self.assertTrue(len(field_node), "currency_id field should be in company from view")
|
||||
for method in methods:
|
||||
self.assertEqual(field_node[0].get('can_' + method), 'false')
|
||||
|
||||
def test_m2o_field_create_edit_visibility(self):
|
||||
""" Test many2one field Create and Edit option visibility based on access rights of relation field"""
|
||||
methods = ['create', 'write']
|
||||
|
||||
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
field_node = view_arch.xpath("//field[@name='currency_id']")
|
||||
self.assertTrue(len(field_node), "currency_id field should be in company from view")
|
||||
for method in methods:
|
||||
self.assertEqual(field_node[0].get('can_' + method), 'true')
|
||||
# cleanup
|
||||
self.erp_manager_group.write({'users': [(3, self.demo_uid)]})
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
||||
Reference in New Issue
Block a user