diff --git a/base_archive_manager/README.rst b/base_archive_manager/README.rst new file mode 100644 index 0000000..f9a361d --- /dev/null +++ b/base_archive_manager/README.rst @@ -0,0 +1,108 @@ +=============== +Archive Manager +=============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2346ac753b8e3940aa35c3ea94dbd53152c6d64b6cdb1f10d20d7af3edee9342 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--ux-lightgray.png?logo=github + :target: https://github.com/OCA/server-ux/tree/18.0/base_archive_manager + :alt: OCA/server-ux +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-ux-18-0/server-ux-18-0-base_archive_manager + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-ux&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows administrators to control who can archive and +unarchive records in Odoo. By default, Odoo only provides a ``write`` +permission, which implicitly allows any user with write access to +archive and unarchive records. This module introduces specific +``Archive Access`` and ``Unarchive Access`` permissions on the Access +Rights (``ir.model.access``) level. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to: + +1. Go to *Settings > Technical > Security > Access Rights*. +2. Open any access right record. +3. You will see two new checkboxes: **Archive Access** + (``perm_archive``) and **Unarchive Access** (``perm_unarchive``). +4. Check or uncheck these boxes to grant or deny archive/unarchive + permissions for the corresponding group and model. + +Usage +===== + +Once configured, the module automatically controls the visibility of the +Archive and Unarchive actions across the system: + +- In Form views, the ``Active`` stat button will be hidden if the user + lacks the required permission to toggle it (e.g., if a record is + active and the user lacks archive permission, the button is hidden). +- In List and Kanban views, the ``Archive`` and ``Unarchive`` action + menu items will be hidden depending on the user's permissions. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Solomon Prabu +* CIT Services + +Contributors +------------ + +- `CIT-Services `__ + + - Solomon Prabu s.prabu@cit-services.eu + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/server-ux `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_archive_manager/__init__.py b/base_archive_manager/__init__.py new file mode 100644 index 0000000..368196f --- /dev/null +++ b/base_archive_manager/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2026 CIT Services +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/base_archive_manager/__manifest__.py b/base_archive_manager/__manifest__.py new file mode 100644 index 0000000..772e3f4 --- /dev/null +++ b/base_archive_manager/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright CIT Services 2026-27 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Archive Manager", + "summary": "Manage model archive/unarchive accesses", + "category": "Personalization", + "version": "18.0.1.0.0", + "depends": ["web"], + "author": "Solomon Prabu, CIT Services, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/server-ux", + "assets": { + "web.assets_backend": [ + "base_archive_manager/static/src/js/listController.esm.js", + "base_archive_manager/static/src/js/formController.esm.js", + "base_archive_manager/static/src/js/kanbanController.esm.js", + ], + }, + "data": ["views/ir_model_access.xml", "views/res_groups.xml"], + "license": "AGPL-3", + "installable": True, +} diff --git a/base_archive_manager/models/__init__.py b/base_archive_manager/models/__init__.py new file mode 100644 index 0000000..e242576 --- /dev/null +++ b/base_archive_manager/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2026 CIT Services +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import ir_model_access +from . import ir_ui_view diff --git a/base_archive_manager/models/ir_model_access.py b/base_archive_manager/models/ir_model_access.py new file mode 100644 index 0000000..40669c9 --- /dev/null +++ b/base_archive_manager/models/ir_model_access.py @@ -0,0 +1,64 @@ +# Copyright 2026 CIT Services +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, tools +from odoo.exceptions import AccessError + + +class IrModelAccess(models.Model): + _inherit = "ir.model.access" + + perm_archive = fields.Boolean("Archive Access", default=True) + perm_unarchive = fields.Boolean("Unarchive Access", default=True) + + @api.model + @tools.ormcache("self.env.uid", "model_name") + def _check_archive_access_cached(self, model_name): + group_ids = self.env.user._get_group_ids() + domain = [ + ("model_id.model", "=", model_name), + ("perm_archive", "=", True), + "|", + ("group_id", "=", False), + ("group_id", "in", group_ids), + ] + return self.sudo().search_count(domain) + + @api.model + def _check_archive_access(self, model_name, raise_exception=True): + """Check if the current user has permission to archive records of model_name.""" + if self.env.su: + return True + has_archive = self._check_archive_access_cached(model_name) + if not has_archive and raise_exception: + raise AccessError( + self.env._("You are not allowed to archive records of model %s.") + % model_name + ) + return has_archive + + @api.model + @tools.ormcache("self.env.uid", "model_name") + def _check_unarchive_access_cached(self, model_name): + group_ids = self.env.user._get_group_ids() + domain = [ + ("model_id.model", "=", model_name), + ("perm_unarchive", "=", True), + "|", + ("group_id", "=", False), + ("group_id", "in", group_ids), + ] + return self.sudo().search_count(domain) + + @api.model + def _check_unarchive_access(self, model_name, raise_exception=True): + """Check if the current user has permission to unarchive records of model_name.""" + if self.env.su: + return True + has_unarchive = self._check_unarchive_access_cached(model_name) + if not has_unarchive and raise_exception: + raise AccessError( + self.env._("You are not allowed to unarchive records of model %s.") + % model_name + ) + return has_unarchive diff --git a/base_archive_manager/models/ir_ui_view.py b/base_archive_manager/models/ir_ui_view.py new file mode 100644 index 0000000..ced9279 --- /dev/null +++ b/base_archive_manager/models/ir_ui_view.py @@ -0,0 +1,31 @@ +# Copyright 2026 CIT Services +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models + + +class IrUiView(models.Model): + _inherit = "ir.ui.view" + + def _postprocess_access_rights(self, tree): + """Restrict the 'Archive/Unarchive' action based + on the user's model access rights.""" + target_model = tree.get("model_access_rights") + tree = super()._postprocess_access_rights(tree) + if ( + not target_model + or tree.tag not in ("list", "form", "kanban") + or self.env.su + ): + return tree + can_archive = self.env["ir.model.access"]._check_archive_access( + target_model, raise_exception=False + ) + can_unarchive = self.env["ir.model.access"]._check_unarchive_access( + target_model, raise_exception=False + ) + if not can_archive: + tree.set("archive", "0") + if not can_unarchive: + tree.set("unarchive", "0") + return tree diff --git a/base_archive_manager/pyproject.toml b/base_archive_manager/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/base_archive_manager/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/base_archive_manager/readme/CONFIGURE.md b/base_archive_manager/readme/CONFIGURE.md new file mode 100644 index 0000000..466e9ac --- /dev/null +++ b/base_archive_manager/readme/CONFIGURE.md @@ -0,0 +1,6 @@ +To configure this module, you need to: + +1. Go to *Settings > Technical > Security > Access Rights*. +2. Open any access right record. +3. You will see two new checkboxes: **Archive Access** (`perm_archive`) and **Unarchive Access** (`perm_unarchive`). +4. Check or uncheck these boxes to grant or deny archive/unarchive permissions for the corresponding group and model. diff --git a/base_archive_manager/readme/CONTRIBUTORS.md b/base_archive_manager/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..59b132f --- /dev/null +++ b/base_archive_manager/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [CIT-Services](cit-services.eu) + - Solomon Prabu diff --git a/base_archive_manager/readme/DESCRIPTION.md b/base_archive_manager/readme/DESCRIPTION.md new file mode 100644 index 0000000..7147f66 --- /dev/null +++ b/base_archive_manager/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module allows administrators to control who can archive and unarchive records in Odoo. By default, Odoo only provides a `write` permission, which implicitly allows any user with write access to archive and unarchive records. This module introduces specific `Archive Access` and `Unarchive Access` permissions on the Access Rights (`ir.model.access`) level. diff --git a/base_archive_manager/readme/USAGE.md b/base_archive_manager/readme/USAGE.md new file mode 100644 index 0000000..c638a3e --- /dev/null +++ b/base_archive_manager/readme/USAGE.md @@ -0,0 +1,4 @@ +Once configured, the module automatically controls the visibility of the Archive and Unarchive actions across the system: + +* In Form views, the `Active` stat button will be hidden if the user lacks the required permission to toggle it (e.g., if a record is active and the user lacks archive permission, the button is hidden). +* In List and Kanban views, the `Archive` and `Unarchive` action menu items will be hidden depending on the user's permissions. diff --git a/base_archive_manager/static/description/index.html b/base_archive_manager/static/description/index.html new file mode 100644 index 0000000..76c4bfb --- /dev/null +++ b/base_archive_manager/static/description/index.html @@ -0,0 +1,458 @@ + + + + + +Archive Manager + + + +
+

Archive Manager

+ + +

Beta License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runboat

+

This module allows administrators to control who can archive and +unarchive records in Odoo. By default, Odoo only provides a write +permission, which implicitly allows any user with write access to +archive and unarchive records. This module introduces specific +Archive Access and Unarchive Access permissions on the Access +Rights (ir.model.access) level.

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Settings > Technical > Security > Access Rights.
  2. +
  3. Open any access right record.
  4. +
  5. You will see two new checkboxes: Archive Access +(perm_archive) and Unarchive Access (perm_unarchive).
  6. +
  7. Check or uncheck these boxes to grant or deny archive/unarchive +permissions for the corresponding group and model.
  8. +
+
+
+

Usage

+

Once configured, the module automatically controls the visibility of the +Archive and Unarchive actions across the system:

+
    +
  • In Form views, the Active stat button will be hidden if the user +lacks the required permission to toggle it (e.g., if a record is +active and the user lacks archive permission, the button is hidden).
  • +
  • In List and Kanban views, the Archive and Unarchive action +menu items will be hidden depending on the user’s permissions.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Solomon Prabu
  • +
  • CIT Services
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-ux project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/base_archive_manager/static/src/js/formController.esm.js b/base_archive_manager/static/src/js/formController.esm.js new file mode 100644 index 0000000..a6b7e09 --- /dev/null +++ b/base_archive_manager/static/src/js/formController.esm.js @@ -0,0 +1,23 @@ +/** + * Copyright 2026 CIT Services + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + */ + +import {FormController} from "@web/views/form/form_controller"; +import {patch} from "@web/core/utils/patch"; + +patch(FormController.prototype, { + getStaticActionMenuItems() { + const items = super.getStaticActionMenuItems(); + const xmlDoc = this.props.archInfo.xmlDoc; + const canArchive = xmlDoc ? xmlDoc.getAttribute("archive") !== "0" : true; + const canUnarchive = xmlDoc ? xmlDoc.getAttribute("unarchive") !== "0" : true; + if (!canArchive) { + delete items.archive; + } + if (!canUnarchive) { + delete items.unarchive; + } + return items; + }, +}); diff --git a/base_archive_manager/static/src/js/kanbanController.esm.js b/base_archive_manager/static/src/js/kanbanController.esm.js new file mode 100644 index 0000000..9376c9b --- /dev/null +++ b/base_archive_manager/static/src/js/kanbanController.esm.js @@ -0,0 +1,70 @@ +/** + * Copyright 2026 CIT Services + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + */ + +import {KanbanCompiler} from "@web/views/kanban/kanban_compiler"; +import {KanbanController} from "@web/views/kanban/kanban_controller"; +import {KanbanHeader} from "@web/views/kanban/kanban_header"; +import {KanbanRecord} from "@web/views/kanban/kanban_record"; +import {patch} from "@web/core/utils/patch"; +import {useSubEnv} from "@odoo/owl"; + +patch(KanbanController.prototype, { + setup() { + super.setup(...arguments); + const xmlDoc = this.props.archInfo.xmlDoc; + const canArchive = xmlDoc ? xmlDoc.getAttribute("archive") !== "0" : true; + const canUnarchive = xmlDoc ? xmlDoc.getAttribute("unarchive") !== "0" : true; + useSubEnv({ + archivePermissions: {archive: canArchive, unarchive: canUnarchive}, + }); + }, +}); + +patch(KanbanRecord.prototype, { + createWidget(props) { + super.createWidget(props); + this.dataState.widget.hasArchiveAccess = this.env.archivePermissions + ? this.env.archivePermissions.archive + : true; + this.dataState.widget.hasUnarchiveAccess = this.env.archivePermissions + ? this.env.archivePermissions.unarchive + : true; + }, +}); + +patch(KanbanHeader.prototype, { + canArchiveGroup() { + const canArchive = super.canArchiveGroup(); + return ( + canArchive && + (this.env.archivePermissions ? this.env.archivePermissions.archive : true) + ); + }, +}); + +patch(KanbanCompiler.prototype, { + compileButton(el, params) { + const type = el.getAttribute("type"); + if (type === "archive") { + const existingIf = el.getAttribute("t-if"); + el.setAttribute( + "t-if", + existingIf + ? `(${existingIf}) and widget.hasArchiveAccess` + : "widget.hasArchiveAccess" + ); + } + if (type === "unarchive") { + const existingIf = el.getAttribute("t-if"); + el.setAttribute( + "t-if", + existingIf + ? `(${existingIf}) and widget.hasUnarchiveAccess` + : "widget.hasUnarchiveAccess" + ); + } + return super.compileButton(el, params); + }, +}); diff --git a/base_archive_manager/static/src/js/listController.esm.js b/base_archive_manager/static/src/js/listController.esm.js new file mode 100644 index 0000000..28ff91b --- /dev/null +++ b/base_archive_manager/static/src/js/listController.esm.js @@ -0,0 +1,23 @@ +/** + * Copyright 2026 CIT Services + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + */ + +import {ListController} from "@web/views/list/list_controller"; +import {patch} from "@web/core/utils/patch"; + +patch(ListController.prototype, { + getStaticActionMenuItems() { + const items = super.getStaticActionMenuItems(); + const xmlDoc = this.props.archInfo.xmlDoc; + const canArchive = xmlDoc ? xmlDoc.getAttribute("archive") !== "0" : true; + const canUnarchive = xmlDoc ? xmlDoc.getAttribute("unarchive") !== "0" : true; + if (!canArchive) { + delete items.archive; + } + if (!canUnarchive) { + delete items.unarchive; + } + return items; + }, +}); diff --git a/base_archive_manager/tests/__init__.py b/base_archive_manager/tests/__init__.py new file mode 100644 index 0000000..de43ddd --- /dev/null +++ b/base_archive_manager/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2026 CIT Services +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_base_archive_manager diff --git a/base_archive_manager/tests/test_base_archive_manager.py b/base_archive_manager/tests/test_base_archive_manager.py new file mode 100644 index 0000000..349d512 --- /dev/null +++ b/base_archive_manager/tests/test_base_archive_manager.py @@ -0,0 +1,224 @@ +# Copyright 2026 CIT Services +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from lxml import etree + +from odoo.exceptions import AccessError +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestArchiveUnarchiveAccess(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user_model = cls.env["res.users"] + cls.group_model = cls.env["res.groups"] + cls.access_model = cls.env["ir.model.access"] + + cls.group_user = cls.env.ref("base.group_user") + + cls.group_no_access = cls.group_model.create({"name": "No Archive Access"}) + cls.group_archive_only = cls.group_model.create({"name": "Archive Only Access"}) + cls.group_unarchive_only = cls.group_model.create( + {"name": "Unarchive Only Access"} + ) + cls.group_full_access = cls.group_model.create({"name": "Full Archive Access"}) + + cls.partner_model = cls.env["ir.model"].search( + [("model", "=", "res.partner")], limit=1 + ) + + existing_rules = cls.access_model.search( + [("model_id", "=", cls.partner_model.id)] + ) + existing_rules.write({"perm_archive": False, "perm_unarchive": False}) + cls.partner_no_access = cls.access_model.create( + { + "name": "No Access", + "model_id": cls.partner_model.id, + "group_id": cls.group_no_access.id, + "perm_read": True, + "perm_write": True, + "perm_archive": False, + "perm_unarchive": False, + } + ) + + cls.partner_archive_access = cls.access_model.create( + { + "name": "No Access", + "model_id": cls.partner_model.id, + "group_id": cls.group_archive_only.id, + "perm_read": True, + "perm_write": True, + "perm_archive": True, + "perm_unarchive": False, + } + ) + + cls.partner_unarchive_access = cls.access_model.create( + { + "name": "No Access", + "model_id": cls.partner_model.id, + "group_id": cls.group_unarchive_only.id, + "perm_read": True, + "perm_write": True, + "perm_archive": False, + "perm_unarchive": True, + } + ) + + cls.partner_full_access = cls.access_model.create( + { + "name": "No Access", + "model_id": cls.partner_model.id, + "group_id": cls.group_full_access.id, + "perm_read": True, + "perm_write": True, + "perm_archive": True, + "perm_unarchive": True, + } + ) + + cls.user_no_access = cls.env["res.users"].create( + { + "name": "User No Access", + "login": "user_no_access", + "groups_id": [ + (6, 0, [cls.group_user.id, cls.group_no_access.id]), + ], + } + ) + + cls.user_archive_only = cls.env["res.users"].create( + { + "name": "User Archive Access", + "login": "user_archive_access", + "groups_id": [ + (6, 0, [cls.group_user.id, cls.group_archive_only.id]), + ], + } + ) + + cls.user_unarchive_only = cls.env["res.users"].create( + { + "name": "User Unarchive Access", + "login": "user_unarchive_access", + "groups_id": [ + (6, 0, [cls.group_user.id, cls.group_unarchive_only.id]), + ], + } + ) + + cls.user_full_access = cls.env["res.users"].create( + { + "name": "User Full Access", + "login": "user_full_access", + "groups_id": [ + (6, 0, [cls.group_user.id, cls.group_full_access.id]), + ], + } + ) + + cls.Partner = cls.env["res.partner"] + + def test_check_archive_access_no_access(self): + access_model = self.access_model.with_user(self.user_no_access) + with self.assertRaises(AccessError): + access_model._check_archive_access("res.partner") + + def test_check_archive_access_no_access_no_raise(self): + access_model = self.access_model.with_user(self.user_no_access) + result = access_model._check_archive_access( + "res.partner", raise_exception=False + ) + self.assertFalse(result) + + def test_check_archive_access_archive_only(self): + access_model = self.access_model.with_user(self.user_archive_only) + result = access_model._check_archive_access( + "res.partner", raise_exception=False + ) + self.assertTrue(result) + + def test_check_archive_access_unarchive_only(self): + access_model = self.access_model.with_user(self.user_unarchive_only) + result = access_model._check_archive_access( + "res.partner", raise_exception=False + ) + self.assertFalse(result) + + def test_check_archive_access_full_access(self): + access_model = self.access_model.with_user(self.user_full_access) + result = access_model._check_archive_access( + "res.partner", raise_exception=False + ) + self.assertTrue(result) + + def test_check_unarchive_access_no_access(self): + access_model = self.access_model.with_user(self.user_no_access) + with self.assertRaises(AccessError): + access_model._check_unarchive_access("res.partner") + + def test_check_unarchive_access_no_access_no_raise(self): + access_model = self.access_model.with_user(self.user_no_access) + result = access_model._check_unarchive_access( + "res.partner", raise_exception=False + ) + self.assertFalse(result) + + def test_check_unarchive_access_archive_only(self): + access_model = self.access_model.with_user(self.user_archive_only) + result = access_model._check_unarchive_access( + "res.partner", raise_exception=False + ) + self.assertFalse(result) + + def test_check_unarchive_access_unarchive_only(self): + access_model = self.access_model.with_user(self.user_unarchive_only) + result = access_model._check_unarchive_access( + "res.partner", raise_exception=False + ) + self.assertTrue(result) + + def test_check_unarchive_access_full_access(self): + access_model = self.access_model.with_user(self.user_full_access) + result = access_model._check_unarchive_access( + "res.partner", raise_exception=False + ) + self.assertTrue(result) + + def test_superuser_bypasses_archive_check(self): + result = self.access_model.sudo()._check_archive_access("res.partner") + self.assertTrue(result) + + def test_superuser_bypasses_unarchive_check(self): + result = self.access_model.sudo()._check_unarchive_access("res.partner") + self.assertTrue(result) + + def _get_root_view_element(self, user, view_type="form"): + res = self.Partner.with_user(user).get_views(views=[[False, view_type]]) + arch = res["views"][view_type]["arch"] + return etree.fromstring(arch) + + def test_get_views_no_access_sets_archive_and_unarchive_zero(self): + root = self._get_root_view_element(self.user_no_access) + self.assertEqual(root.get("archive"), "0") + self.assertEqual(root.get("unarchive"), "0") + + def test_get_views_archive_only_sets_unarchive_zero(self): + root = self._get_root_view_element(self.user_archive_only) + self.assertNotEqual(root.get("archive"), "0") + self.assertEqual(root.get("unarchive"), "0") + + def test_get_views_unarchive_only_sets_archive_zero(self): + root = self._get_root_view_element(self.user_unarchive_only) + self.assertEqual(root.get("archive"), "0") + self.assertNotEqual(root.get("unarchive"), "0") + + def test_get_views_full_access_no_restrictions(self): + root = self._get_root_view_element(self.user_full_access) + self.assertNotEqual(root.get("archive"), "0") + self.assertNotEqual(root.get("unarchive"), "0") diff --git a/base_archive_manager/views/ir_model_access.xml b/base_archive_manager/views/ir_model_access.xml new file mode 100644 index 0000000..dde116a --- /dev/null +++ b/base_archive_manager/views/ir_model_access.xml @@ -0,0 +1,36 @@ + + + + ir.model.access.list.base_archive_manager + ir.model.access + + + + + + + + + + ir.model.access.list.edition.base_archive_manager + ir.model.access + + + + + + + + + + ir.model.access.form.base_archive_manager + ir.model.access + + + + + + + + + diff --git a/base_archive_manager/views/res_groups.xml b/base_archive_manager/views/res_groups.xml new file mode 100644 index 0000000..46ecdc8 --- /dev/null +++ b/base_archive_manager/views/res_groups.xml @@ -0,0 +1,17 @@ + + + + res.groups.form.base_archive_manager + res.groups + + + + + + + + +