Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TA#72088 [16.0][MIG] base_view_mode_restricted #223

Merged
merged 4 commits into from
Feb 12, 2025
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
1 change: 1 addition & 0 deletions .docker_files/main/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"admin_light_filters",
"attachment_minio",
"base_extended_security",
"base_view_mode_restricted",
"crm", # module added for test purpose
"currency_rate_update_boc",
"database_bi_user",
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ COPY admin_light_user /mnt/extra-addons/admin_light_user
COPY admin_light_web /mnt/extra-addons/admin_light_web
COPY attachment_minio /mnt/extra-addons/attachment_minio
COPY base_extended_security /mnt/extra-addons/base_extended_security
COPY base_view_mode_restricted /mnt/extra-addons/base_view_mode_restricted
COPY currency_rate_update_boc /mnt/extra-addons/currency_rate_update_boc
COPY database_bi_user /mnt/extra-addons/database_bi_user
COPY lang_fr_activated /mnt/extra-addons/lang_fr_activated
Expand Down
54 changes: 54 additions & 0 deletions base_view_mode_restricted/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Base View Mode Restricted
=========================
This module allows to restrict the view modes of a given action to a specific group.

.. contents:: Table of Contents

Configuration
-------------
I go to the list of ``Window Actions``.

.. image:: static/description/window_action_list.png

I select the action view ``All Timesheets``.

.. image:: static/description/window_action_list_filtered.png

In the form view of the action, I notice a new section ``View Restrictions``.

.. image:: static/description/window_action_restrictions_empty.png

I define a new rule so that only Administrators can see the graph and pivot view types.

.. image:: static/description/window_action_restrictions_filled.png

..

The column View Modes must contain the technical names of the view modes to restrict,
separated by commas.

If no user group is specified, then the view modes are disabled for everyone.

Usage
-----
Connected as a non-administrator, I go to ``Timesheets > Timesheet > All Timesheets``.

I notice that the pivot and graph views are not available.

.. image:: static/description/timesheet_view_no_pivot.png

Connected as an administrator, I go to ``Timesheets > Timesheet > All Timesheets``.

I notice that the pivot and graph views are available.

.. image:: static/description/timesheet_view_with_pivot.png

Security
--------
This module does not add any real security.

Users without the access to a view mode can find a workaround to access the data.

Contributors
------------
* Numigi (tm) and all its contributors (https://bit.ly/numigiens)
4 changes: 4 additions & 0 deletions base_view_mode_restricted/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from . import models

Check notice on line 4 in base_view_mode_restricted/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

base_view_mode_restricted/__init__.py#L4

'.models' imported but unused (F401)
20 changes: 20 additions & 0 deletions base_view_mode_restricted/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

{

Check warning on line 4 in base_view_mode_restricted/__manifest__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

base_view_mode_restricted/__manifest__.py#L4

Statement seems to have no effect
"name": "Base View Mode Restricted",
"version": "16.0.1.0.0",
"author": "Numigi",
"maintainer": "Numigi",
"license": "LGPL-3",
"category": "Other",
"summary": "Add view mode restrictions on window actions",
"depends": [
"base",
],
"data": [
"security/ir.model.access.csv",
"views/ir_actions_act_window.xml",
],
"installable": True,
}
86 changes: 86 additions & 0 deletions base_view_mode_restricted/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_view_mode_restricted
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-23 13:13+0000\n"
"PO-Revision-Date: 2021-06-23 13:13+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__action_id
msgid "Action"
msgstr "Action"

#. module: base_view_mode_restricted
#: model:ir.model,name:base_view_mode_restricted.model_ir_actions_act_window
msgid "Action Window"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__create_uid
msgid "Created by"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__create_date
msgid "Created on"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__display_name
msgid "Display Name"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__group_ids
msgid "Group"
msgstr "Groupe"

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__id
msgid "ID"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model,name:base_view_mode_restricted.model_ir_actions_view_mode_restriction
msgid "Ir Action View Mode Restriction"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction____last_update
msgid "Last Modified on"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__write_uid
msgid "Last Updated by"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__write_date
msgid "Last Updated on"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_act_window__view_mode_restriction_ids
msgid "View Mode Restriction"
msgstr ""

#. module: base_view_mode_restricted
#: model:ir.model.fields,field_description:base_view_mode_restricted.field_ir_actions_view_mode_restriction__view_modes
msgid "View Modes"
msgstr "Modes de vue"

#. module: base_view_mode_restricted
#: model_terms:ir.ui.view,arch_db:base_view_mode_restricted.ir_actions_act_window_form
msgid "View Restrictions"
msgstr "Restrictions de vue"
7 changes: 7 additions & 0 deletions base_view_mode_restricted/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from . import (

Check notice on line 4 in base_view_mode_restricted/models/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

base_view_mode_restricted/models/__init__.py#L4

'.ir_actions_act_window' imported but unused (F401)
ir_actions_act_window,
ir_actions_view_mode_restriction,
)
36 changes: 36 additions & 0 deletions base_view_mode_restricted/models/ir_actions_act_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from itertools import chain
from odoo import api, fields, models


class IrActionsActWindow(models.Model):

_inherit = "ir.actions.act_window"

view_mode_restriction_ids = fields.One2many(
"ir.actions.view.mode.restriction",
"action_id",
)

@api.depends("view_ids.view_mode", "view_mode", "view_id.type")
def _compute_views(self):
lanto-razafindrabe marked this conversation as resolved.
Show resolved Hide resolved
super()._compute_views()
for action in self:
action.views = action._get_authorized_views()

def _get_authorized_views(self):
forbiden_modes = self._get_forbiden_view_modes()
return [
(view_id, mode)
for view_id, mode in self.views
if mode not in forbiden_modes
]

def _get_forbiden_view_modes(self):
user_groups = self.env.user.groups_id
restrictions = self.view_mode_restriction_ids.filtered(
lambda r: not (r.group_ids & user_groups)
)
return set(chain.from_iterable(r._get_view_mode_list() for r in restrictions))
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo import fields, models


class IrActionsViewModeRestriction(models.Model):

_name = "ir.actions.view.mode.restriction"
_description = "Ir Action View Mode Restriction"

action_id = fields.Many2one(
"ir.actions.act_window",
required=True,
ondelete="cascade",
index=True,
lanto-razafindrabe marked this conversation as resolved.
Show resolved Hide resolved
)
view_modes = fields.Char(required=True)
group_ids = fields.Many2many(
"res.groups",
"ir_actions_view_mode_restriction_group_rel",
"restriction_id",
"group_id",
required=True,
)

def _get_view_mode_list(self):
return [mode.strip() for mode in self.view_modes.split(",")]
3 changes: 3 additions & 0 deletions base_view_mode_restricted/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_ir_actions_view_mode_restriction_manager,ir_actions_view_mode_restriction_manager,model_ir_actions_view_mode_restriction,base.group_erp_manager,1,1,1,1
access_ir_actions_view_mode_restriction_user,ir_actions_view_mode_restriction_user,model_ir_actions_view_mode_restriction,,1,0,0,0
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions base_view_mode_restricted/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
58 changes: 58 additions & 0 deletions base_view_mode_restricted/tests/test_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2021 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo.tests import common


class TestViewModeRestrictions(common.TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user = cls.env.ref("base.user_admin")
cls.group_1 = cls.env["res.groups"].create({"name": "Group 1"})
cls.action = cls.env.ref("base.action_partner_form")

def test_user_without_group(self):
self.user.groups_id -= self.group_1
self._setup_restriction("kanban", self.group_1)
modes = self._get_authorized_view_modes()
assert "kanban" not in modes

def test_user_with_group(self):
self.user.groups_id |= self.group_1
self._setup_restriction("kanban", self.group_1)
modes = self._get_authorized_view_modes()
assert "kanban" in modes

def test_multiple_restrictions(self):
self.user.groups_id -= self.group_1
self._setup_restriction("kanban,list", self.group_1)
modes = self._get_authorized_view_modes()
assert "kanban" not in modes
assert "list" not in modes
assert "form" in modes

def test_view_mode_with_extra_spaces(self):
self.user.groups_id -= self.group_1
self._setup_restriction(" kanban ", self.group_1)
modes = self._get_authorized_view_modes()
assert "kanban" not in modes

def _setup_restriction(self, view_modes, groups):
self.action.write(
{
"view_mode_restriction_ids": [
(
0,
0,
{
"view_modes": view_modes,
"group_ids": [(6, 0, groups.ids)],
},
)
]
}
)

def _get_authorized_view_modes(self):
return {v[1] for v in self.action.with_user(self.user).views}
22 changes: 22 additions & 0 deletions base_view_mode_restricted/views/ir_actions_act_window.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<record id="ir_actions_act_window_form" model="ir.ui.view">
<field name="name">Ir Actions Act Window: add restrictions on view modes</field>
<field name="model">ir.actions.act_window</field>
<field name="inherit_id" ref="base.view_window_action_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='view_ids']/.." position="after">
<group name="view_mode_restrictions" string="View Restrictions">
<field colspan="2" name="view_mode_restriction_ids" nolabel="1">
<tree editable="bottom">
<field name="view_modes" />
<field name="group_ids" widget="many2many_tags" />
</tree>
</field>
</group>
</xpath>
</field>
</record>

</odoo>
Loading