Browse Source
[10.0] [ADD] user_immutable: Add Module (#830)
[10.0] [ADD] user_immutable: Add Module (#830)
* [ADD] user_immutable: Add Module * Add module to support users that are immutable * [IMP] user_immutable: Fixes per PR * Add missing test * Fix README * Add logging * [IMP] user_immutable: Fixes per PR * Lower code complexity * Fix README * Fix License * [IMP] user_immutable: Fixes per PR Review * Call `_check_immutable` on singleton * Simplify check for immutable grouppull/844/head
committed by
Dave Lasley
11 changed files with 299 additions and 0 deletions
-
68user_immutable/README.rst
-
5user_immutable/__init__.py
-
20user_immutable/__manifest__.py
-
13user_immutable/data/user_immutable_data.xml
-
11user_immutable/demo/user_immutable_demo.xml
-
6user_immutable/models/__init__.py
-
28user_immutable/models/res_groups.py
-
48user_immutable/models/res_users.py
-
6user_immutable/tests/__init__.py
-
28user_immutable/tests/test_res_groups.py
-
66user_immutable/tests/test_res_users.py
@ -0,0 +1,68 @@ |
|||
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html |
|||
:alt: License: LGPL-3 |
|||
|
|||
============== |
|||
User Immutable |
|||
============== |
|||
|
|||
This module adds a group named `Immutable` which cannot be altered by users |
|||
outside of that group. By default, the `Administrator` user is the only user |
|||
given access to this group on install. This module also adds protections |
|||
against non-members granting/revoking membership to this group. |
|||
|
|||
|
|||
|
|||
Installation |
|||
============ |
|||
|
|||
* Install module as normal |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
Simply add any user to the `Immutable` group, provided that your login user |
|||
is a member of that group already. |
|||
|
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/149/10.0 |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
`<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please |
|||
check there if your issue has already been reported. If you spotted it first, |
|||
help us smash it by providing detailed and welcomed feedback. |
|||
|
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Images |
|||
------ |
|||
|
|||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Ted Salmon <tsalmon@laslabs.com> |
|||
|
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: https://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: https://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
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. |
|||
|
|||
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from . import models |
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
{ |
|||
"name": "Immutable Users", |
|||
"summary": "Add Immutable User Support", |
|||
"version": "10.0.1.0.0", |
|||
"category": "Authentication", |
|||
"website": "https://www.laslabs.com", |
|||
"author": "LasLabs, Odoo Community Association (OCA)", |
|||
"license": "LGPL-3", |
|||
"application": False, |
|||
'installable': True, |
|||
"data": [ |
|||
'data/user_immutable_data.xml', |
|||
], |
|||
"demo": [ |
|||
'demo/user_immutable_demo.xml', |
|||
] |
|||
} |
@ -0,0 +1,13 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- Copyright 2017 LasLabs Inc. |
|||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> |
|||
|
|||
<odoo noupdate="1"> |
|||
|
|||
<record id="group_immutable" model="res.groups"> |
|||
<field name="name">Immutable</field> |
|||
<field name="category_id" ref="base.module_category_hidden"/> |
|||
<field name="users" eval="[(4, ref('base.user_root'))]"/> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,11 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- Copyright 2017 LasLabs Inc. |
|||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> |
|||
|
|||
<odoo> |
|||
|
|||
<record id="group_immutable" model="res.groups"> |
|||
<field name="users" eval="[(4, ref('base.user_demo'))]" /> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from . import res_groups |
|||
from . import res_users |
@ -0,0 +1,28 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import _, api, models |
|||
from odoo.exceptions import AccessError |
|||
|
|||
IMMUTABLE = 'user_immutable.group_immutable' |
|||
|
|||
|
|||
class ResGroups(models.Model): |
|||
|
|||
_inherit = 'res.groups' |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
""" Override write to verify that access to the `Immutable` group is |
|||
not given or removed by users without access |
|||
""" |
|||
if not vals.get('users') or self.env.user.has_group(IMMUTABLE): |
|||
return super(ResGroups, self).write(vals) |
|||
immutable = self.env.ref(IMMUTABLE, raise_if_not_found=False) |
|||
if immutable and immutable in self: |
|||
raise AccessError(_( |
|||
'You must be a member of the `Immutable` group to grant' |
|||
' access to it' |
|||
)) |
|||
return super(ResGroups, self).write(vals) |
@ -0,0 +1,48 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import _, api, models |
|||
from odoo.exceptions import AccessError |
|||
|
|||
from .res_groups import IMMUTABLE |
|||
|
|||
|
|||
class ResUsers(models.Model): |
|||
|
|||
_inherit = 'res.users' |
|||
|
|||
def _check_immutable(self): |
|||
""" Check to see if the user being edited is Immutable and if so, |
|||
make sure that the user performing the action has access |
|||
""" |
|||
if self.has_group(IMMUTABLE): |
|||
if not self.env.user.has_group(IMMUTABLE): |
|||
raise AccessError( |
|||
_('You do not have permission to alter an Immutable User') |
|||
) |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
""" Override write to verify that there are no alterations to users |
|||
whom are members of the `Immutable` group |
|||
""" |
|||
for rec in self: |
|||
rec._check_immutable() |
|||
immutable = self.env.ref(IMMUTABLE) |
|||
has_group = self.env.user.has_group(IMMUTABLE) |
|||
if vals.get('in_group_%s' % immutable.id) and not has_group: |
|||
raise AccessError( |
|||
_('You must be a member of the `Immutable` group to grant ' |
|||
'access to it') |
|||
) |
|||
return super(ResUsers, self).write(vals) |
|||
|
|||
@api.multi |
|||
def unlink(self): |
|||
""" Override unlink to verify that there are no deletions of users |
|||
whom are members of the `Immutable` group |
|||
""" |
|||
for rec in self: |
|||
rec._check_immutable() |
|||
return super(ResUsers, self).unlink() |
@ -0,0 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from . import test_res_groups |
|||
from . import test_res_users |
@ -0,0 +1,28 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html |
|||
|
|||
from odoo.exceptions import AccessError |
|||
from odoo.tests import TransactionCase |
|||
|
|||
|
|||
class TestResGroups(TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestResGroups, self).setUp() |
|||
self.immutable = self.env.ref('user_immutable.group_immutable') |
|||
self.user = self.env.ref('base.user_demo') |
|||
self.user.write({'in_group_%s' % self.immutable.id: False}) |
|||
|
|||
def test_can_add_immutable(self): |
|||
""" It should make sure that `Administrator` can add users to the |
|||
immutable group by default """ |
|||
self.immutable.write({'users': [(4, [self.user.id])]}) |
|||
self.assertTrue(self.user.has_group('user_immutable.group_immutable')) |
|||
|
|||
def test_non_immutable_cannot_add_immutable(self): |
|||
""" It should make sure that other users cannot add to the immutable |
|||
group """ |
|||
immutable = self.env.ref('user_immutable.group_immutable') |
|||
with self.assertRaises(AccessError): |
|||
immutable.sudo(self.user.id).write({'users': [self.user.id]}) |
@ -0,0 +1,66 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 LasLabs Inc. |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html |
|||
|
|||
from odoo.exceptions import AccessError |
|||
from odoo.tests import TransactionCase |
|||
|
|||
|
|||
class TestResUsers(TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestResUsers, self).setUp() |
|||
self.immutable = self.env.ref('user_immutable.group_immutable') |
|||
self.user = self.env.ref('base.user_demo') |
|||
self.user.write({'in_group_%s' % self.immutable.id: False}) |
|||
|
|||
def test_can_add_immutable(self): |
|||
""" It should verify that `Administrator` can add users to the |
|||
immutable group by default |
|||
""" |
|||
self.user.write({'in_group_%s' % self.immutable.id: True}) |
|||
self.assertTrue(self.user.has_group('user_immutable.group_immutable')) |
|||
|
|||
def test_non_immutable_cannot_add_immutable(self): |
|||
""" It should verify that other users cannot add to the immutable |
|||
group |
|||
""" |
|||
with self.assertRaises(AccessError): |
|||
self.user.sudo(self.user.id).write({ |
|||
'in_group_%s' % self.immutable.id: True |
|||
}) |
|||
|
|||
def test_immutable_can_alter_immutable(self): |
|||
""" It should verify that immutable users can alter users in the |
|||
immutable group |
|||
""" |
|||
self.user.write({'in_group_%s' % self.immutable.id: True}) |
|||
exp = 'Princess Peach' |
|||
self.user.write({'name': exp}) |
|||
self.assertEquals(self.user.name, exp) |
|||
|
|||
def test_immutable_cannot_be_unlinked(self): |
|||
""" It should make sure non `Immutable` members cannot unlink other |
|||
`Immutable` Members |
|||
""" |
|||
with self.assertRaises(AccessError): |
|||
self.env.ref('base.user_root').sudo( |
|||
self.user.id |
|||
).unlink() |
|||
|
|||
def test_immutable_can_be_unlinked_by_immutable(self): |
|||
""" It should make sure `Immutable` members can unlink other |
|||
`Immutable` Members |
|||
""" |
|||
user = self.user.copy() |
|||
user.write({'in_group_%s' % self.immutable.id: True}) |
|||
self.assertTrue(user.unlink()) |
|||
|
|||
def test_check_immutable(self): |
|||
""" It should raise `AccessError` when trying called by a user |
|||
outside the `Immutable` group on an `Immutable` user |
|||
""" |
|||
with self.assertRaises(AccessError): |
|||
self.env.ref('base.user_root').sudo( |
|||
self.user.id |
|||
)._check_immutable() |
Write
Preview
Loading…
Cancel
Save
Reference in new issue