From 2a37a3d06fca721350e67b3709d17ed3fee65bdc Mon Sep 17 00:00:00 2001 From: "Julien Carion (juca)" Date: Thu, 23 Mar 2023 09:38:57 +0000 Subject: [PATCH] [REF] web, base, mail: move res.users.settings from mail to base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit moves and adapt the res.users.settings model from mail to base and and allows to access and modify its content with web's user service. This allows to access user settings without needing the mail module. closes odoo/odoo#116005 Related: odoo/enterprise#38360 Signed-off-by: Michaƫl Mattiello (mcm) --- addons/mail/models/res_users.py | 12 ----- addons/mail/models/res_users_settings.py | 34 +++----------- addons/mail/security/ir.model.access.csv | 2 - addons/web/models/ir_http.py | 1 + addons/web/static/src/core/user_service.js | 18 ++++++- .../src/webclient/menus/menu_helpers.js | 23 +++++++++ odoo/addons/base/models/__init__.py | 1 + odoo/addons/base/models/res_users.py | 12 +++++ odoo/addons/base/models/res_users_settings.py | 47 +++++++++++++++++++ odoo/addons/base/security/ir.model.access.csv | 2 + 10 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 odoo/addons/base/models/res_users_settings.py diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py index 00914aa494c..4e4a6ab890b 100644 --- a/addons/mail/models/res_users.py +++ b/addons/mail/models/res_users.py @@ -24,9 +24,6 @@ class Users(models.Model): help="Policy on how to handle Chatter notifications:\n" "- Handle by Emails: notifications are sent to your email address\n" "- Handle in Odoo: notifications appear in your Odoo Inbox") - res_users_settings_ids = fields.One2many('res.users.settings', 'user_id') - # Provide a target for relateds that is not a x2Many field. - res_users_settings_id = fields.Many2one('res.users.settings', string="Settings", compute='_compute_res_users_settings_id', search='_search_res_users_settings_id') _sql_constraints = [( "notification_type", @@ -62,15 +59,6 @@ class Users(models.Model): else: user.groups_id -= inbox_group - @api.depends('res_users_settings_ids') - def _compute_res_users_settings_id(self): - for user in self: - user.res_users_settings_id = user.res_users_settings_ids and user.res_users_settings_ids[0] - - @api.model - def _search_res_users_settings_id(self, operator, operand): - return [('res_users_settings_ids', operator, operand)] - # ------------------------------------------------------------ # CRUD # ------------------------------------------------------------ diff --git a/addons/mail/models/res_users_settings.py b/addons/mail/models/res_users_settings.py index 5fd719bee3a..7eb92b0c66d 100644 --- a/addons/mail/models/res_users_settings.py +++ b/addons/mail/models/res_users_settings.py @@ -5,11 +5,8 @@ from odoo import api, fields, models class ResUsersSettings(models.Model): - _name = 'res.users.settings' - _description = 'User Settings' - _rec_name = 'user_id' + _inherit = 'res.users.settings' - user_id = fields.Many2one('res.users', string="User", required=True, readonly=True, ondelete='cascade') is_discuss_sidebar_category_channel_open = fields.Boolean(string="Is discuss sidebar category channel open?", default=True) is_discuss_sidebar_category_chat_open = fields.Boolean(string="Is discuss sidebar category chat open?", default=True) @@ -19,37 +16,18 @@ class ResUsersSettings(models.Model): voice_active_duration = fields.Integer(string="Duration of voice activity in ms", help="How long the audio broadcast will remain active after passing the volume threshold") volume_settings_ids = fields.One2many('res.users.settings.volumes', 'user_setting_id', string="Volumes of other partners") - _sql_constraints = [ - ('unique_user_id', 'UNIQUE(user_id)', 'One user should only have one mail user settings.') - ] - @api.model - def _find_or_create_for_user(self, user): - settings = user.sudo().res_users_settings_ids - if not settings: - settings = self.sudo().create({'user_id': user.id}) - return settings - - def _res_users_settings_format(self, fields_to_format=None): - self.ensure_one() - if not fields_to_format: - fields_to_format = [name for name, field in self._fields.items() if name == 'id' or not field.automatic] - res = self._read_format(fnames=fields_to_format)[0] - if 'user_id' in fields_to_format: - res['user_id'] = {'id': self.user_id.id} + def _format_settings(self, fields_to_format): + res = super()._format_settings(fields_to_format) if 'volume_settings_ids' in fields_to_format: volume_settings = self.volume_settings_ids._discuss_users_settings_volume_format() res['volume_settings_ids'] = [('insert', volume_settings)] return res def set_res_users_settings(self, new_settings): - self.ensure_one() - changed_settings = {} - for setting in new_settings.keys(): - if setting in self._fields and new_settings[setting] != self[setting]: - changed_settings[setting] = new_settings[setting] - self.write(changed_settings) - self.env['bus.bus']._sendone(self.user_id.partner_id, 'mail.record/insert', {'res.users.settings': self._res_users_settings_format([*changed_settings.keys(), 'id'])}) + formated = super().set_res_users_settings(new_settings) + self.env['bus.bus']._sendone(self.user_id.partner_id, 'mail.record/insert', {'res.users.settings': formated}) + return formated def set_volume_setting(self, partner_id, volume, guest_id=None): """ diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 29c55416c9d..3123352f48f 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -59,8 +59,6 @@ access_mail_guest_user,mail.guest,model_mail_guest,base.group_user,1,0,0,0 access_mail_guest_system,mail.guest,model_mail_guest,base.group_system,1,1,1,1 access_mail_ice_server_all,mail.ice.server.all,model_mail_ice_server,,0,0,0,0 access_mail_ice_server_system,mail.ice.server.system,model_mail_ice_server,base.group_system,1,1,1,1 -access_res_users_settings_all,res.users.settings,model_res_users_settings,,0,0,0,0 -access_res_users_settings_user,res.users.settings,model_res_users_settings,base.group_user,1,1,1,1 access_res_users_settings_volumes_all,res.users.settings.volumes,model_res_users_settings_volumes,,0,0,0,0 access_res_users_settings_volumes_user,res.users.settings.volumes,model_res_users_settings_volumes,base.group_user,1,1,1,1 access_mail_template_reset,access.mail.template.reset,model_mail_template_reset,mail.group_mail_template_editor,1,1,1,1 diff --git a/addons/web/models/ir_http.py b/addons/web/models/ir_http.py index 373d4817b57..8ffee516815 100644 --- a/addons/web/models/ir_http.py +++ b/addons/web/models/ir_http.py @@ -95,6 +95,7 @@ class Http(models.AbstractModel): "is_admin": user._is_admin() if session_uid else False, "user_context": user_context, "db": self.env.cr.dbname, + "user_settings": self.env['res.users.settings']._find_or_create_for_user(user)._res_users_settings_format(), "server_version": version_info.get('server_version'), "server_version_info": version_info.get('server_version_info'), "support_url": "https://www.odoo.com/buy", diff --git a/addons/web/static/src/core/user_service.js b/addons/web/static/src/core/user_service.js index 82f4ef3026f..08f175d1117 100644 --- a/addons/web/static/src/core/user_service.js +++ b/addons/web/static/src/core/user_service.js @@ -33,6 +33,8 @@ export const userService = { ...session.user_context, uid: session.uid, }; + let settings = session.user_settings; + delete session.user_settings; return { get context() { return Object.assign({}, context); @@ -49,7 +51,21 @@ export const userService = { async checkAccessRight(model, operation) { return accessRightCache.read(model, operation); }, - + get settings() { + return settings; + }, + async setUserSettings(key, value) { + settings = await env.services.orm.call( + "res.users.settings", + "set_res_users_settings", + [[this.settings.id]], + { + new_settings: { + [key]: value, + }, + } + ); + }, name: session.name, userName: session.username, isAdmin: session.is_admin, diff --git a/addons/web/static/src/webclient/menus/menu_helpers.js b/addons/web/static/src/webclient/menus/menu_helpers.js index a73a311c5b8..e086dcb3aa8 100644 --- a/addons/web/static/src/webclient/menus/menu_helpers.js +++ b/addons/web/static/src/webclient/menus/menu_helpers.js @@ -61,3 +61,26 @@ export function computeAppsAndMenuItems(menuTree) { }); return { apps, menuItems }; } + +/** + * @param {Array} order + * Sorts the apps in the homescreen menu according to the given order as an array of xmlid strings + */ +export function reorderApps(apps, order) { + apps.sort((a, b) => { + const aIndex = order.indexOf(a.xmlid); + const bIndex = order.indexOf(b.xmlid); + if (aIndex === -1 && bIndex === -1) { + // if both items are not present, sort by original order + return apps.indexOf(a) - apps.indexOf(b); + } + // not found items always before found ones + if (aIndex === -1) { + return -1; + } + if (bIndex === -1) { + return 1; + } + return aIndex - bIndex; // sort by order array + }); +} diff --git a/odoo/addons/base/models/__init__.py b/odoo/addons/base/models/__init__.py index 86fe94b5ba0..673a8fa0643 100644 --- a/odoo/addons/base/models/__init__.py +++ b/odoo/addons/base/models/__init__.py @@ -43,6 +43,7 @@ from . import res_config from . import res_currency from . import res_company from . import res_users +from . import res_users_settings from . import res_users_deletion from . import decimal_precision diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index c4e71badf71..5c78215311c 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -326,6 +326,9 @@ class Users(models.Model): help="External user with limited access, created only for the purpose of sharing data.") companies_count = fields.Integer(compute='_compute_companies_count', string="Number of Companies") tz_offset = fields.Char(compute='_compute_tz_offset', string='Timezone offset', invisible=True) + res_users_settings_ids = fields.One2many('res.users.settings', 'user_id') + # Provide a target for relateds that is not a x2Many field. + res_users_settings_id = fields.Many2one('res.users.settings', string="Settings", compute='_compute_res_users_settings_id', search='_search_res_users_settings_id') # Special behavior for this field: res.company.search() will only return the companies # available to the current user (should be the user's companies?), when the user_preference @@ -459,6 +462,15 @@ class Users(models.Model): user.rules_count = len(groups.rule_groups) user.groups_count = len(groups) + @api.depends('res_users_settings_ids') + def _compute_res_users_settings_id(self): + for user in self: + user.res_users_settings_id = user.res_users_settings_ids and user.res_users_settings_ids[0] + + @api.model + def _search_res_users_settings_id(self, operator, operand): + return [('res_users_settings_ids', operator, operand)] + @api.onchange('login') def on_change_login(self): if self.login and tools.single_email_re.match(self.login): diff --git a/odoo/addons/base/models/res_users_settings.py b/odoo/addons/base/models/res_users_settings.py new file mode 100644 index 00000000000..0e40edbbed6 --- /dev/null +++ b/odoo/addons/base/models/res_users_settings.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class ResUsersSettings(models.Model): + _name = 'res.users.settings' + _description = 'User Settings' + _rec_name = 'user_id' + + user_id = fields.Many2one('res.users', string="User", required=True, readonly=True, ondelete='cascade') + + _sql_constraints = [ + ('unique_user_id', 'UNIQUE(user_id)', 'One user should only have one user settings.') + ] + + @api.model + def _find_or_create_for_user(self, user): + settings = user.sudo().res_users_settings_ids + if not settings: + settings = self.sudo().create({'user_id': user.id}) + return settings + + def _res_users_settings_format(self, fields_to_format=None): + self.ensure_one() + if not fields_to_format: + fields_to_format = [name for name, field in self._fields.items() if name == 'id' or not field.automatic] + res = self._format_settings(fields_to_format) + return res + + def _format_settings(self, fields_to_format): + res = self._read_format(fnames=fields_to_format)[0] + if 'user_id' in fields_to_format: + res = self._read_format(fnames=fields_to_format)[0] + res['user_id'] = {'id': self.user_id.id} + return res + + def set_res_users_settings(self, new_settings): + self.ensure_one() + changed_settings = {} + for setting in new_settings.keys(): + if setting in self._fields and new_settings[setting] != self[setting]: + changed_settings[setting] = new_settings[setting] + self.write(changed_settings) + formated = self._res_users_settings_format([*changed_settings.keys(), 'id']) + return formated diff --git a/odoo/addons/base/security/ir.model.access.csv b/odoo/addons/base/security/ir.model.access.csv index 5ef2ab83234..a0662bcb692 100644 --- a/odoo/addons/base/security/ir.model.access.csv +++ b/odoo/addons/base/security/ir.model.access.csv @@ -78,6 +78,8 @@ "access_res_users_apikeys_description_employee","API key wizard employees","model_res_users_apikeys_description","group_user",1,0,1,0 "access_res_users_apikeys_description_portal","API key wizard","model_res_users_apikeys_description","group_portal",1,0,1,0 "access_res_users_apikeys_show_employee","API key result employees","model_res_users_apikeys_show","group_user",1,0,1,0 +access_res_users_settings_all,res.users.settings,model_res_users_settings,,0,0,0,0 +access_res_users_settings_user,res.users.settings,model_res_users_settings,group_user,1,1,1,1 "access_ir_asset_group_system","ir_asset_group_system","model_ir_asset","group_system",1,1,1,1 "access_ir_actions_group_system","ir_actions_group_system","model_ir_actions_actions","group_system",1,1,1,1 "access_ir_actions_act_window_system","ir_actions_act_window_system","model_ir_actions_act_window","group_system",1,1,1,1