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