Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions base_extended_security/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

{
"name": "Base Extended Security",
"version": "16.0.1.1.0",
"version": "16.0.1.1.1",
"author": "Numigi",
"maintainer": "Numigi",
"license": "LGPL-3",
"category": "Other",
"summary": "Securize access to records",
"depends": ["web", "account"],
"depends": ["web"],
"data": [
"security/ir.model.access.csv",
"views/extended_security_rule.xml",
Expand Down
2 changes: 1 addition & 1 deletion base_extended_security/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from odoo import models, api


class BaseWithExtendedSecurity(models.AbstractModel):
class Base(models.AbstractModel):

_inherit = "base"

Expand Down
2 changes: 1 addition & 1 deletion base_extended_security/models/ir_ui_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from odoo import api, models


class ViewWithButtonsHiden(models.Model):
class IrUiView(models.Model):
_inherit = "ir.ui.view"

def _remove_write_access_buttons(self, env, model, tree):
Expand Down
114 changes: 70 additions & 44 deletions base_extended_security/tests/test_security_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,41 @@ def setUpClass(cls):
}
)

cls.product = cls.env["product.product"].create(
# PARTNER
cls.partner = cls.env["res.partner"].create(
{
"name": "Product 1",
"name": "Partner 1",
}
)

cls.rule = cls.env["extended.security.rule"].create(
{
"model_id": cls.env.ref("product.model_product_product").id,
"model_id": cls.env.ref("base.model_res_partner").id,
"group_ids": [(4, cls.group.id)],
"perm_read": False,
"perm_write": False,
"perm_create": False,
"perm_unlink": False,
}
)

# IR ACTIONS SERVER
cls.res_partner_model = cls.env["ir.model"].search(
[("model", "=", "res.partner")]
)
cls.comment_html = "<p>MyComment</p>"
cls.action_1 = cls.env["ir.actions.server"].create(
{
"name": "TestAction",
"model_id": cls.res_partner_model.id,
"model_name": "res.partner",
"state": "code",
"code": 'record.write({"comment": "%s"})' % cls.comment_html,
}
)
cls.rule_1 = cls.env["extended.security.rule"].create(
{
"model_id": cls.env.ref("base.model_ir_actions_server").id,
"group_ids": [(4, cls.group.id)],
"perm_read": False,
"perm_write": False,
Expand All @@ -51,87 +77,83 @@ def test_if_member_of_group__access_error_not_raised(self, access_type):
self.rule["perm_{}".format(access_type)] = True
self.user.groups_id |= self.group
method = "check_extended_security_{}".format(access_type)
getattr(self.product.with_user(self.user), method)()
getattr(self.partner.with_user(self.user), method)()

@data("read", "write", "create", "unlink")
def test_if_access_type_uncheked__access_error_raised(self, access_type):
method = "check_extended_security_{}".format(access_type)
getattr(self.product.with_user(self.user), method)()
getattr(self.partner.with_user(self.user), method)()

@data("read", "write", "create", "unlink")
def test_if_not_member_of_group__access_error_raised(self, access_type):
self.rule["perm_{}".format(access_type)] = True
method = "check_extended_security_{}".format(access_type)

with pytest.raises(AccessError):
getattr(self.product.with_user(self.user), method)()
getattr(self.partner.with_user(self.user), method)()

def test_after_rule_deleted__rule_not_applied(self):
self.rule.perm_read = True
with pytest.raises(AccessError):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

self.rule.unlink()
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

def test_after_rule_created__rule_applied(self):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()
self.rule.copy({"perm_read": True})

with pytest.raises(AccessError):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

def test_after_rule_unchecked__rule_not_applied(self):
self.rule.perm_read = True

with pytest.raises(AccessError):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

self.rule.perm_read = False
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

def test_after_rule_archived__rule_not_applied(self):
self.rule.perm_read = True

with pytest.raises(AccessError):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

self.rule.active = False
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

def test_after_rule_checked__rule_applied(self):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

self.rule.perm_read = True
with pytest.raises(AccessError):
self.product.with_user(self.user).check_extended_security_read()
self.partner.with_user(self.user).check_extended_security_read()

def test_on_search__if_not_authorized__domain_is_empty(self):
self.rule.perm_read = True
domain = (
self.env["product.product"]
.with_user(self.user)
.get_extended_security_domain()
self.env["res.partner"].with_user(self.user).get_extended_security_domain()
)
search_result = self.env["product.product"].search(domain)
assert self.product not in search_result
search_result = self.env["res.partner"].search(domain)
assert self.partner not in search_result

def test_on_search__if_authorized__domain_not_empty(self):
self.rule.perm_read = True
self.user.groups_id |= self.group

domain = (
self.env["product.product"]
.with_user(self.user)
.get_extended_security_domain()
self.env["res.partner"].with_user(self.user).get_extended_security_domain()
)
search_result = self.env["product.product"].search(domain)
search_result = self.env["res.partner"].search(domain)

assert self.product in search_result
assert self.partner in search_result

def _get_product_list_view_arch(self):
view = self.env.ref("product.product_product_tree_view")
arch = self.env["product.product"].get_view(view_id=view.id)["arch"]
def _get_partner_list_view_arch(self):
view = self.env.ref("base.view_partner_tree")
arch = self.env["res.partner"].get_view(view_id=view.id)["arch"]
return etree.fromstring(arch)

@data(
Expand All @@ -143,7 +165,7 @@ def _get_product_list_view_arch(self):
def test_if_authorized__view_property_not_disabled(
self, access_type, view_property
):
list_view = self._get_product_list_view_arch()
list_view = self._get_partner_list_view_arch()
assert view_property not in list_view.attrib

def _get_nested_ir_rule_many2many_arch(self):
Expand Down Expand Up @@ -177,6 +199,15 @@ def _get_nested_ir_model_access_one2many_arch(self):
tree_attrib = model_access_field["edition_view"]["tree"].attrib
return tree_attrib

def test_if_not_authorized__toggle_button_hidden(self):
self.rule_1.perm_write = True
form_view = self._get_ir_actions_server_form_view_arch()
assert not form_view.xpath("//header/button[@name='create_action']")

def test_if_authorized__toggle_button_not_hidden(self):
form_view = self._get_ir_actions_server_form_view_arch()
assert form_view.xpath("//header/button[@name='create_action']")

@data(
("write", "edit"),
("create", "create"),
Expand All @@ -197,11 +228,6 @@ def test_in_nested_one2many_list__view_property_disabled(
one2many_list = self._get_nested_ir_model_access_one2many_arch()
assert view_property in one2many_list

def test_if_not_authorized__toggle_button_hidden(self):
self.rule.perm_write = True
form_view = self._get_product_form_view_arch()
assert not form_view.xpath("//button[@name='action_update_quantity_on_hand']")

def test_read_access_action(self):
self.rule.model_id = self.env.ref("base.model_res_partner")
self.rule.perm_write = True
Expand All @@ -217,22 +243,22 @@ def test_read_access_action(self):
def test_if_unauthorized__view_property_disabled(self, access_type, view_property):
self.rule["perm_{}".format(access_type)] = True

list_view = self._get_product_list_view_arch()
list_view = self._get_partner_list_view_arch()
assert list_view.attrib[view_property] == "false"

def _get_product_form_view_arch(self):
return self._get_form_view_arch(
"product.product", "product.product_normal_form_view"
)

def _get_partner_form_view_arch(self):
return self._get_form_view_arch("res.partner", "base.view_partner_form")

def _get_ir_actions_server_form_view_arch(self):
return self._get_form_view_arch(
"ir.actions.server", "base.view_server_action_form"
)

def _get_form_view_arch(self, model, view_ref):
view = self.env.ref(view_ref)
arch = self.env[model].get_view(view_id=view.id)["arch"]
return etree.fromstring(arch)

def test_if_authorized__toggle_button_not_hidden(self):
form_view = self._get_product_form_view_arch()
assert form_view.xpath("//button[@name='action_open_label_layout']")
def test_if_authorized__field_not_hidden(self):
form_view = self._get_partner_form_view_arch()
assert form_view.xpath("//field[@name='name']")