From faec99ceb5d8a07fd90f10a44530d30ba666bddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 9 Dec 2016 18:06:42 +0100 Subject: [PATCH] 8.0 - New module 'base_user_role' to manage user roles efficiently (#608) * [ADD] New module 'base_user_role' * [FIX] base_user_role - Review * [FIX] base_user_role - Review s/is_active/is_enabled/ * [FIX] base_user_role - Review s/is_active/is_enabled/ * [IMP] base_user_role - Translations updated (template + FR) * [FIX] base_user_role - Lint --- base_user_role/README.rst | 82 ++++++++ base_user_role/__init__.py | 3 + base_user_role/__openerp__.py | 24 +++ base_user_role/data/ir_cron.xml | 20 ++ base_user_role/i18n/base_user_role.pot | 189 ++++++++++++++++++ base_user_role/i18n/fr.po | 189 ++++++++++++++++++ .../migrations/8.0.1.1.0/post-migration.py | 25 +++ base_user_role/models/__init__.py | 4 + base_user_role/models/role.py | 83 ++++++++ base_user_role/models/user.py | 54 +++++ base_user_role/security/ir.model.access.csv | 3 + base_user_role/static/description/icon.png | Bin 0 -> 18048 bytes .../static/description/role_groups.png | Bin 0 -> 12323 bytes .../static/description/role_users.png | Bin 0 -> 12493 bytes base_user_role/static/description/roles.png | Bin 0 -> 20446 bytes base_user_role/tests/__init__.py | 3 + base_user_role/tests/test_user_role.py | 107 ++++++++++ base_user_role/views/role.xml | 73 +++++++ base_user_role/views/user.xml | 39 ++++ 19 files changed, 898 insertions(+) create mode 100644 base_user_role/README.rst create mode 100644 base_user_role/__init__.py create mode 100644 base_user_role/__openerp__.py create mode 100644 base_user_role/data/ir_cron.xml create mode 100644 base_user_role/i18n/base_user_role.pot create mode 100644 base_user_role/i18n/fr.po create mode 100644 base_user_role/migrations/8.0.1.1.0/post-migration.py create mode 100644 base_user_role/models/__init__.py create mode 100644 base_user_role/models/role.py create mode 100644 base_user_role/models/user.py create mode 100644 base_user_role/security/ir.model.access.csv create mode 100644 base_user_role/static/description/icon.png create mode 100644 base_user_role/static/description/role_groups.png create mode 100644 base_user_role/static/description/role_users.png create mode 100644 base_user_role/static/description/roles.png create mode 100644 base_user_role/tests/__init__.py create mode 100644 base_user_role/tests/test_user_role.py create mode 100644 base_user_role/views/role.xml create mode 100644 base_user_role/views/user.xml diff --git a/base_user_role/README.rst b/base_user_role/README.rst new file mode 100644 index 000000000..4b38fab53 --- /dev/null +++ b/base_user_role/README.rst @@ -0,0 +1,82 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +========== +User roles +========== + +This module was written to extend the standard functionality regarding users +and groups management. +It helps creating well-defined user roles and associating them to users. + +It can become very hard to maintain a large number of user profiles over time, +juggling with many technical groups. For this purpose, this module will help +you to: + + * define functional roles by aggregating low-level groups, + * set user accounts with the predefined roles (roles are cumulative), + * update groups of all relevant user accounts (all at once), + * ensure that user accounts will have the groups defined in their roles + (nothing more, nothing less). In other words, you can not set groups + manually on a user as long as there is roles configured on it, + * activate/deactivate roles depending on the date (useful to plan holidays, etc) + * get a quick overview of roles and the related user accounts. + +That way you make clear the different responsabilities within a company, and +are able to add and update user accounts in a scalable and reliable way. + +Configuration +============= + +To configure this module, you need to go to *Configuration / Users / Roles*, +and create a new role. From there, you can add groups to compose your role, +and then associate users to it. + +Roles: + +.. image:: /base_user_role/static/description/roles.png + +Add groups: + +.. image:: /base_user_role/static/description/role_groups.png + +Add users (with dates or not): + +.. image:: /base_user_role/static/description/role_users.png + +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 smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Oxygen Team: `Icon `_ (LGPL) + +Contributors +------------ + +* Sébastien Alix + +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. diff --git a/base_user_role/__init__.py b/base_user_role/__init__.py new file mode 100644 index 000000000..cde864bae --- /dev/null +++ b/base_user_role/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/base_user_role/__openerp__.py b/base_user_role/__openerp__.py new file mode 100644 index 000000000..59c525fc8 --- /dev/null +++ b/base_user_role/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 ABF OSIELL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'User roles', + 'version': '8.0.1.1.0', + 'category': 'Tools', + 'author': 'ABF OSIELL, Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'maintainer': 'ABF OSIELL', + 'website': 'http://www.osiell.com', + 'depends': [ + 'base', + ], + 'data': [ + 'security/ir.model.access.csv', + 'data/ir_cron.xml', + 'views/role.xml', + 'views/user.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/base_user_role/data/ir_cron.xml b/base_user_role/data/ir_cron.xml new file mode 100644 index 000000000..a92276a90 --- /dev/null +++ b/base_user_role/data/ir_cron.xml @@ -0,0 +1,20 @@ + + + + + + + Update user roles + 3 + hours + -1 + True + + res.users.role + cron_update_users + () + + + + diff --git a/base_user_role/i18n/base_user_role.pot b/base_user_role/i18n/base_user_role.pot new file mode 100644 index 000000000..a62c4664d --- /dev/null +++ b/base_user_role/i18n/base_user_role.pot @@ -0,0 +1,189 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_user_role +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-18 11:58+0000\n" +"PO-Revision-Date: 2016-11-18 11:58+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_user_role +#: field:res.users.role,model_access:0 +msgid "Access Controls" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,menu_access:0 +msgid "Access Menu" +msgstr "" + +#. module: base_user_role +#: field:res.users.role.line,is_enabled:0 +msgid "Enabled" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,category_id:0 +msgid "Application" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,group_id:0 +msgid "Associated group" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,comment:0 +msgid "Comment" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,create_uid:0 +#: field:res.users.role.line,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,create_date:0 +#: field:res.users.role.line,create_date:0 +msgid "Created on" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,display_name:0 +#: field:res.users.role.line,display_name:0 +msgid "Display Name" +msgstr "" + +#. module: base_user_role +#: field:res.users.role.line,date_from:0 +msgid "From" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,full_name:0 +msgid "Group Name" +msgstr "" + +#. module: base_user_role +#: view:res.users.role:base_user_role.view_res_users_role_form +msgid "Groups" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,id:0 +#: field:res.users.role.line,id:0 +msgid "ID" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,implied_ids:0 +msgid "Inherits" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,__last_update:0 +#: field:res.users.role.line,__last_update:0 +msgid "Last Modified on" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,write_uid:0 +#: field:res.users.role.line,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,write_date:0 +#: field:res.users.role.line,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,name:0 +msgid "Name" +msgstr "" + +#. module: base_user_role +#: view:res.users.role:base_user_role.view_res_users_role_form +#: view:res.users.role:base_user_role.view_res_users_role_tree +#: field:res.users.role.line,role_id:0 +msgid "Role" +msgstr "" + +#. module: base_user_role +#: field:res.users,role_line_ids:0 +msgid "Role lines" +msgstr "" + +#. module: base_user_role +#: model:ir.actions.act_window,name:base_user_role.action_res_users_role_tree +#: model:ir.ui.menu,name:base_user_role.menu_action_res_users_role_tree +#: view:res.users:base_user_role.view_res_users_form_inherit +#: field:res.users,role_ids:0 +#: view:res.users.role:base_user_role.view_res_users_role_search +msgid "Roles" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,rule_groups:0 +msgid "Rules" +msgstr "" + +#. module: base_user_role +#: field:res.users,scoring:0 +msgid "Scoring (%)" +msgstr "" + +#. module: base_user_role +#: field:res.users.role.line,date_to:0 +msgid "To" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,trans_implied_ids:0 +msgid "Transitively inherits" +msgstr "" + +#. module: base_user_role +#: field:res.users.role.line,user_id:0 +msgid "User" +msgstr "" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users_role +msgid "User role" +msgstr "" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users +#: view:res.users.role:base_user_role.view_res_users_role_form +#: field:res.users.role,line_ids:0 +#: field:res.users.role,user_ids:0 +#: field:res.users.role,users:0 +msgid "Users" +msgstr "" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users_role_line +msgid "Users associated to a role" +msgstr "" + +#. module: base_user_role +#: help:res.users.role,implied_ids:0 +msgid "Users of this group automatically inherit those groups" +msgstr "" + +#. module: base_user_role +#: field:res.users.role,view_access:0 +msgid "Views" +msgstr "" + diff --git a/base_user_role/i18n/fr.po b/base_user_role/i18n/fr.po new file mode 100644 index 000000000..809fc24cd --- /dev/null +++ b/base_user_role/i18n/fr.po @@ -0,0 +1,189 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_user_role +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-18 12:03+0000\n" +"PO-Revision-Date: 2016-11-18 12:03+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_user_role +#: field:res.users.role,model_access:0 +msgid "Access Controls" +msgstr "Access Controls" + +#. module: base_user_role +#: field:res.users.role,menu_access:0 +msgid "Access Menu" +msgstr "Access Menu" + +#. module: base_user_role +#: field:res.users.role.line,is_enabled:0 +msgid "Enabled" +msgstr "Activé" + +#. module: base_user_role +#: field:res.users.role,category_id:0 +msgid "Application" +msgstr "Application" + +#. module: base_user_role +#: field:res.users.role,group_id:0 +msgid "Associated group" +msgstr "Groupe associé" + +#. module: base_user_role +#: field:res.users.role,comment:0 +msgid "Comment" +msgstr "Comment" + +#. module: base_user_role +#: field:res.users.role,create_uid:0 +#: field:res.users.role.line,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: base_user_role +#: field:res.users.role,create_date:0 +#: field:res.users.role.line,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: base_user_role +#: field:res.users.role,display_name:0 +#: field:res.users.role.line,display_name:0 +msgid "Display Name" +msgstr "Display Name" + +#. module: base_user_role +#: field:res.users.role.line,date_from:0 +msgid "From" +msgstr "À partir du" + +#. module: base_user_role +#: field:res.users.role,full_name:0 +msgid "Group Name" +msgstr "Group Name" + +#. module: base_user_role +#: view:res.users.role:base_user_role.view_res_users_role_form +msgid "Groups" +msgstr "Groupes" + +#. module: base_user_role +#: field:res.users.role,id:0 +#: field:res.users.role.line,id:0 +msgid "ID" +msgstr "ID" + +#. module: base_user_role +#: field:res.users.role,implied_ids:0 +msgid "Inherits" +msgstr "Inherits" + +#. module: base_user_role +#: field:res.users.role,__last_update:0 +#: field:res.users.role.line,__last_update:0 +msgid "Last Modified on" +msgstr "Last Modified on" + +#. module: base_user_role +#: field:res.users.role,write_uid:0 +#: field:res.users.role.line,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: base_user_role +#: field:res.users.role,write_date:0 +#: field:res.users.role.line,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: base_user_role +#: field:res.users.role,name:0 +msgid "Name" +msgstr "Nom" + +#. module: base_user_role +#: view:res.users.role:base_user_role.view_res_users_role_form +#: view:res.users.role:base_user_role.view_res_users_role_tree +#: field:res.users.role.line,role_id:0 +msgid "Role" +msgstr "Rôle" + +#. module: base_user_role +#: field:res.users,role_line_ids:0 +msgid "Role lines" +msgstr "Role lines" + +#. module: base_user_role +#: model:ir.actions.act_window,name:base_user_role.action_res_users_role_tree +#: model:ir.ui.menu,name:base_user_role.menu_action_res_users_role_tree +#: view:res.users:base_user_role.view_res_users_form_inherit +#: field:res.users,role_ids:0 +#: view:res.users.role:base_user_role.view_res_users_role_search +msgid "Roles" +msgstr "Rôles" + +#. module: base_user_role +#: field:res.users.role,rule_groups:0 +msgid "Rules" +msgstr "Rules" + +#. module: base_user_role +#: field:res.users,scoring:0 +msgid "Scoring (%)" +msgstr "Scoring (%)" + +#. module: base_user_role +#: field:res.users.role.line,date_to:0 +msgid "To" +msgstr "Jusqu'au" + +#. module: base_user_role +#: field:res.users.role,trans_implied_ids:0 +msgid "Transitively inherits" +msgstr "Transitively inherits" + +#. module: base_user_role +#: field:res.users.role.line,user_id:0 +msgid "User" +msgstr "Utilisateur" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users_role +msgid "User role" +msgstr "Rôle utilisateur" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users +#: view:res.users.role:base_user_role.view_res_users_role_form +#: field:res.users.role,line_ids:0 +#: field:res.users.role,user_ids:0 +#: field:res.users.role,users:0 +msgid "Users" +msgstr "Utilisateurs" + +#. module: base_user_role +#: model:ir.model,name:base_user_role.model_res_users_role_line +msgid "Users associated to a role" +msgstr "Utilisateurs associés à un rôle" + +#. module: base_user_role +#: help:res.users.role,implied_ids:0 +msgid "Users of this group automatically inherit those groups" +msgstr "Users of this group automatically inherit those groups" + +#. module: base_user_role +#: field:res.users.role,view_access:0 +msgid "Views" +msgstr "Views" + diff --git a/base_user_role/migrations/8.0.1.1.0/post-migration.py b/base_user_role/migrations/8.0.1.1.0/post-migration.py new file mode 100644 index 000000000..074389c7b --- /dev/null +++ b/base_user_role/migrations/8.0.1.1.0/post-migration.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 ABF OSIELL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from openerp import api, SUPERUSER_ID + + +def migrate_res_users_role(env): + """Migrate user roles database schema. + ('res_users_role_user_rel' many2many table to 'res.users.role.line' model. + """ + role_line_model = env['res.users.role.line'] + query = "SELECT role_id, user_id FROM res_users_role_user_rel;" + env.cr.execute(query) + rows = env.cr.fetchall() + for row in rows: + vals = { + 'role_id': row[0], + 'user_id': row[1], + } + role_line_model.create(vals) + + +def migrate(cr, version): + env = api.Environment(cr, SUPERUSER_ID, {}) + migrate_res_users_role(env) diff --git a/base_user_role/models/__init__.py b/base_user_role/models/__init__.py new file mode 100644 index 000000000..db691145c --- /dev/null +++ b/base_user_role/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import role +from . import user diff --git a/base_user_role/models/role.py b/base_user_role/models/role.py new file mode 100644 index 000000000..6cbf42b97 --- /dev/null +++ b/base_user_role/models/role.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 ABF OSIELL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import datetime +import logging + +from openerp import api, fields, models + + +_logger = logging.getLogger(__name__) + + +class ResUsersRole(models.Model): + _name = 'res.users.role' + _inherits = {'res.groups': 'group_id'} + _description = "User role" + + group_id = fields.Many2one( + 'res.groups', required=True, ondelete='cascade', + readonly=True, string=u"Associated group") + line_ids = fields.One2many( + 'res.users.role.line', 'role_id', string=u"Users") + user_ids = fields.One2many( + 'res.users', string=u"Users", compute='_compute_user_ids') + + @api.multi + @api.depends('line_ids.user_id') + def _compute_user_ids(self): + for role in self: + role.user_ids = role.line_ids.mapped('user_id') + + @api.model + def create(self, vals): + new_record = super(ResUsersRole, self).create(vals) + new_record.update_users() + return new_record + + @api.multi + def write(self, vals): + res = super(ResUsersRole, self).write(vals) + self.update_users() + return res + + @api.multi + def update_users(self): + """Update all the users concerned by the roles identified by `ids`.""" + users = self.mapped('user_ids') + users.set_groups_from_roles() + return True + + @api.model + def cron_update_users(self): + logging.info(u"Update user roles") + self.search([]).update_users() + + +class ResUsersRoleLine(models.Model): + _name = 'res.users.role.line' + _description = 'Users associated to a role' + + role_id = fields.Many2one( + 'res.users.role', string=u"Role", ondelete='cascade') + user_id = fields.Many2one( + 'res.users', string=u"User") + date_from = fields.Date(u"From") + date_to = fields.Date(u"To") + is_enabled = fields.Boolean(u"Enabled", compute='_compute_is_enabled') + + @api.multi + @api.depends('date_from', 'date_to') + def _compute_is_enabled(self): + today = datetime.date.today() + for role_line in self: + role_line.is_enabled = True + if role_line.date_from: + date_from = fields.Date.from_string(role_line.date_from) + if date_from > today: + role_line.is_enabled = False + if role_line.date_to: + date_to = fields.Date.from_string(role_line.date_to) + if today > date_to: + role_line.is_enabled = False diff --git a/base_user_role/models/user.py b/base_user_role/models/user.py new file mode 100644 index 000000000..a15849ced --- /dev/null +++ b/base_user_role/models/user.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 ABF OSIELL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + + +class ResUsers(models.Model): + _inherit = 'res.users' + + role_line_ids = fields.One2many( + 'res.users.role.line', 'user_id', string=u"Role lines") + role_ids = fields.One2many( + 'res.users.role', string=u"Roles", compute='_compute_role_ids') + + @api.multi + @api.depends('role_line_ids.role_id') + def _compute_role_ids(self): + for user in self: + user.role_ids = user.role_line_ids.mapped('role_id') + + @api.model + def create(self, vals): + new_record = super(ResUsers, self).create(vals) + new_record.set_groups_from_roles() + return new_record + + @api.multi + def write(self, vals): + res = super(ResUsers, self).write(vals) + self.sudo().set_groups_from_roles() + return res + + @api.multi + def set_groups_from_roles(self): + """Set (replace) the groups following the roles defined on users. + If no role is defined on the user, its groups are let untouched. + """ + for user in self: + if not user.role_line_ids: + continue + group_ids = [] + role_lines = user.role_line_ids.filtered( + lambda rec: rec.is_enabled) + for role_line in role_lines: + role = role_line.role_id + group_ids.append(role.group_id.id) + group_ids.extend(role.implied_ids.ids) + group_ids = list(set(group_ids)) # Remove duplicates IDs + vals = { + 'groups_id': [(6, 0, group_ids)], + } + super(ResUsers, user).write(vals) + return True diff --git a/base_user_role/security/ir.model.access.csv b/base_user_role/security/ir.model.access.csv new file mode 100644 index 000000000..04790a3d5 --- /dev/null +++ b/base_user_role/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_res_users_role,access_res_users_role,model_res_users_role,"base.group_erp_manager",1,1,1,1 +access_res_users_role_line,access_res_users_role_line,model_res_users_role_line,"base.group_erp_manager",1,1,1,1 diff --git a/base_user_role/static/description/icon.png b/base_user_role/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8a6d74ee31c70efd2540873b14293f2f95acf9 GIT binary patch literal 18048 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 literal 0 HcmV?d00001 diff --git a/base_user_role/static/description/role_groups.png b/base_user_role/static/description/role_groups.png new file mode 100644 index 0000000000000000000000000000000000000000..ee31ef971b88a7fa4125eb60b4663f00b423cf3f GIT binary patch literal 12323 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 MU>eYZ$1h(0FF5-KHvj+t literal 0 HcmV?d00001 diff --git a/base_user_role/static/description/role_users.png b/base_user_role/static/description/role_users.png new file mode 100644 index 0000000000000000000000000000000000000000..ceb7f6ea905865e90d073a6811f429e30ede73b3 GIT binary patch literal 12493 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 Wo{i2$=?=sx0Tg6Zz{SsBz5hRe|8=$i literal 0 HcmV?d00001 diff --git a/base_user_role/static/description/roles.png b/base_user_role/static/description/roles.png new file mode 100644 index 0000000000000000000000000000000000000000..e3f0d4a6af915bd795149e6cac833fd9f8285403 GIT binary patch literal 20446 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

771pAt}n&;6kUq{l%90ZI`DO8bhh?~5elpX1_ zA>I;0V!>e_D$On;d$N1Trtj}+spb!!&yZ2rFioq>G|u4TOZ!z*-pDJboNNaD;s4xD zm7*M~MCeP*eUEZn=%|5 z8>9X8dN^JTu(9pk#6`@3E{zog&Q$x^fclv#L2Ay;eW~i)TP;sRe`qRUz|MZ7GKUWL zR5>!ERi^XF8mZ=$4w9d$07)WF2PwiDb#^t+d%Z{uf0g?d7DLh{?$ndT>jJqNjW6`v z!II&U26K(>F9Taz!{0iUPIMxJCeM1*XJ#v*pOooBEV5>k?Kge$*NKXX2~OBdqvINY zR}B>e`zjs_rAqfDYLJIpfDjc3cc|#WEpg!t3_~tt@P2RB>w%$R5tpIJQ99WRimv>OBEpeiTk<345Ytm?KA&V+3_G zQg{qR<53wsfb%zuoeC$w-9ooIei+1Bl2VI)cT=E!_e-L;Yz zDC>8LKS=Fv+nlaBv{Pj5u;+p26NcOPqakWp81tgi(i30YUG?L|bSGKg>2(W>c+m*8 z7&yZjfCjy9Otwp|9hx6i{COtx1{h2hJtikpxWs&*t9fqggap|^E+4-k+cnEkv+ph< z2e0;s&ItBzmjAXqA%*a=KORmOUptKKjkBLyAy((DpPc>KlwPHlMF;9|j&Y)wfcX57`fpesYk8}IsTmT;GHIa@LLPFiOP%) z&H~ionkSJ4ZH;J31LHTs<8pj#?D#D=Z8t8t8qgUn+$)@~zDcBb`dfmBn1=Vt{z!a& zm3Q_H!1q^LSnQE+JZ@o|O%kdkP0pHbQX>+dP)`A#6GUA^-pbjhK1r}dMt3*}fvnmU z%Lp<_D_jQ{Le?=Cwn5y!kK#vHJvzAkPk?JGiqpp`|8n~FsGY*w4GSPKd&C-UcbQJP zFH@F^jk@Z0lJqo;m(M`}qjq1bD0Q;3Lcg-YE1$XfKU;q#%`a-~@&?jaZ}8KG?(`AX zn1b$(dG@X6-Pfj%ehMGn>bG4(4?BKQWgaHPhRQp7$<556BJP)P`&Sa<5$dya1X*Tl}O%csadcd?0qjOTcL!F2>8$E47M) zz{4Hu90*D_eZ!*1ywsld9eFT=J~e#E3V6}?cZ{&e(@LzwR+eOrdKzi)W+gBg@**{V zz}df0Urfh~eea{od9x-tA_9^^OS6@fYS{i4D8k z93NF(uQoPHZ%T!o$-6Wh!-9~Wd~QU&FDFq_L*Kmi`N=lKu^1$ z7^a5_Y6@Ep|7Js#*m&*}zMR_)8_+lQI2gs21$dQ2`26A_`k>AAhJR2&-98HZnP znSHnD*W|68O~jh9cHevD6IZ)TAh&}j{5FDz{LBrAvy1om#NVf9T?2HN8p|D-WFBXz>1?5)eN0MwWHL{Q2S-@Q+r%`<;Z#n+(GpU^@ z?5~;R=*C~Z1KO$RvZl6_xv(*7bNq#8u3vj*Q5*u>Lu4^GL7rklLa)(I&fh;?4I$Lx zt4znxY-rpK8e;-eFh-@vRDe3wye>f?tz+wB)J<4;#i{jG{XaR2X#6`iX3#X%)VLAV zdn7Z`%1NsMQe(a_XFmQ(+o%K%4d}x`t$xd9wR>4EtV9}1rmO(J+d_5|SC&Tt?uQ~5 zgCFmeetBXGeSdTQ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import datetime + +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from openerp.tests.common import TransactionCase + + +class TestUserRole(TransactionCase): + + def setUp(self): + super(TestUserRole, self).setUp() + self.imd_model = self.registry('ir.model.data') + self.user_model = self.registry('res.users') + self.role_model = self.registry('res.users.role') + + self.user_id = self.user_model.create( + self.cr, self.uid, + {'name': u"USER TEST (ROLES)", 'login': 'user_test_roles'}) + + # ROLE_1 + self.group_user_id = self.imd_model.get_object_reference( + self.cr, self.uid, 'base', 'group_user')[1] + self.group_no_one_id = self.imd_model.get_object_reference( + self.cr, self.uid, 'base', 'group_no_one')[1] + vals = { + 'name': u"ROLE_1", + 'implied_ids': [6, 0, [self.group_user_id, self.group_no_one_id]], + } + self.role1_id = self.role_model.create(self.cr, self.uid, vals) + + # ROLE_2 + self.group_multi_currency_id = self.imd_model.get_object_reference( + self.cr, self.uid, 'base', 'group_multi_currency')[1] + self.group_sale_manager_id = self.imd_model.get_object_reference( + self.cr, self.uid, 'base', 'group_sale_manager')[1] + vals = { + 'name': u"ROLE_2", + 'implied_ids': [6, 0, [self.group_multi_currency_id, + self.group_sale_manager_id]], + } + self.role2_id = self.role_model.create(self.cr, self.uid, vals) + + def test_role_1(self): + role1 = self.role_model.browse(self.cr, self.uid, self.role1_id) + self.user_model.write( + self.cr, self.uid, [self.user_id], + {'role_line_ids': [(0, 0, {'role_id': self.role1_id})]}) + user = self.user_model.browse(self.cr, self.uid, self.user_id) + user_group_ids = sorted(set([group.id for group in user.groups_id])) + role_group_ids = role1.implied_ids.ids + role_group_ids.append(role1.group_id.id) + role_group_ids = sorted(set(role_group_ids)) + self.assertEqual(user_group_ids, role_group_ids) + + def test_role_2(self): + role2 = self.role_model.browse(self.cr, self.uid, self.role2_id) + self.user_model.write( + self.cr, self.uid, [self.user_id], + {'role_line_ids': [(0, 0, {'role_id': self.role2_id})]}) + user = self.user_model.browse(self.cr, self.uid, self.user_id) + user_group_ids = sorted(set([group.id for group in user.groups_id])) + role_group_ids = role2.implied_ids.ids + role_group_ids.append(role2.group_id.id) + role_group_ids = sorted(set(role_group_ids)) + self.assertEqual(user_group_ids, role_group_ids) + + def test_role_1_2(self): + role1 = self.role_model.browse(self.cr, self.uid, self.role1_id) + role2 = self.role_model.browse(self.cr, self.uid, self.role2_id) + self.user_model.write( + self.cr, self.uid, [self.user_id], + {'role_line_ids': [ + (0, 0, {'role_id': self.role1_id}), + (0, 0, {'role_id': self.role2_id}), + ]}) + user = self.user_model.browse(self.cr, self.uid, self.user_id) + user_group_ids = sorted(set([group.id for group in user.groups_id])) + role1_group_ids = role1.implied_ids.ids + role1_group_ids.append(role1.group_id.id) + role2_group_ids = role2.implied_ids.ids + role2_group_ids.append(role2.group_id.id) + role_group_ids = sorted(set(role1_group_ids + role2_group_ids)) + self.assertEqual(user_group_ids, role_group_ids) + + def test_role_1_2_with_dates(self): + role1 = self.role_model.browse(self.cr, self.uid, self.role1_id) + today = datetime.date.today() + today_str = today.strftime(DEFAULT_SERVER_DATE_FORMAT) + yesterday = today - datetime.timedelta(days=1) + yesterday_str = yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT) + self.user_model.write( + self.cr, self.uid, [self.user_id], + {'role_line_ids': [ + # Role 1 should be enabled + (0, 0, {'role_id': self.role1_id, 'date_from': today_str}), + # Role 2 should be disabled + (0, 0, {'role_id': self.role2_id, 'date_to': yesterday_str}), + ]}) + user = self.user_model.browse(self.cr, self.uid, self.user_id) + user_group_ids = sorted(set([group.id for group in user.groups_id])) + role1_group_ids = role1.implied_ids.ids + role1_group_ids.append(role1.group_id.id) + role_group_ids = sorted(set(role1_group_ids)) + self.assertEqual(user_group_ids, role_group_ids) diff --git a/base_user_role/views/role.xml b/base_user_role/views/role.xml new file mode 100644 index 000000000..ea1cab525 --- /dev/null +++ b/base_user_role/views/role.xml @@ -0,0 +1,73 @@ + + + + + + + res.users.role.form + res.users.role + +

+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + res.users.role.tree + res.users.role + + + + + + + + + + res.users.role.search + res.users.role + + + + + + + + + + + Roles + ir.actions.act_window + res.users.role + form + + + + + + + diff --git a/base_user_role/views/user.xml b/base_user_role/views/user.xml new file mode 100644 index 000000000..bae3ba500 --- /dev/null +++ b/base_user_role/views/user.xml @@ -0,0 +1,39 @@ + + + + + + + res.users.form.inherit + res.users + + + + + + + + + + + + + + + + + + + res.users.search.inherit + res.users + + + + + + + + + +