[MERGE][IMP] base, *: hide non-relevant fields for portal users

Purpose
=======

Hide non-relevant fields for a portal user. E.G. we want to hide the
notification type,  the menu customization... Because those fields
make no sense for a portal user.

In this PR we make onchange works on reified field to allow fields
depending on groups to be modified as regular onchange in form
view.

Force the non-internal user to receive notifications by emails since
they can not open Discuss.

Task-2508521

closes odoo/odoo#77766

Related: odoo/upgrade#2890
Related: odoo/enterprise#21420
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2021-11-09 15:45:50 +01:00
committed by GitHub
16 changed files with 109 additions and 22 deletions
+3 -5
View File
@@ -38,11 +38,9 @@
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="attributes">
<attribute name="decoration-info">state == 'new'</attribute>
</xpath>
<xpath expr="//field[@name='login_date']" position="after">
<field name="state" invisible="1"/>
<xpath expr="//field[@name='company_id']" position="after">
<field name="state" widget="badge"
decoration-info="state == 'new'" decoration-success="state == 'active'"/>
</xpath>
</field>
</record>
@@ -8,7 +8,6 @@
<xpath expr="//search" position="inside">
<separator/>
<filter name="totp_enabled" string="Two-factor authentication Enabled" domain="[('totp_secret','!=',False)]"/>
<separator/>
<filter name="totp_disabled" string="Two-factor authentication Disabled" domain="[('totp_secret','=',False)]"/>
</xpath>
</field>
+2 -1
View File
@@ -346,7 +346,8 @@
<field name="arch" type="xml">
<notebook colspan="4" position="inside">
<!-- Placeholder container to hold information about external accounts (Google calendar, Microsoft calendar, ...) -->
<page string="Calendar" name="calendar" invisible="1" groups="base.group_system">
<page string="Calendar" name="calendar" invisible="1" groups="base.group_system"
attrs="{'invisible': [('share', '=', True)]}">
<group name="calendar_accounts"/>
</page>
</notebook>
+2 -2
View File
@@ -16,14 +16,14 @@ class TestLivechatLead(TestCrmCommon):
cls.env, login='user_anonymous',
name='Anonymous Website', email=False,
company_id=cls.company_main.id,
notification_type='inbox',
notification_type='email',
groups='base.group_public',
)
cls.user_portal = mail_new_test_user(
cls.env, login='user_portal',
name='Paulette Portal', email='user_portal@test.example.com',
company_id=cls.company_main.id,
notification_type='inbox',
notification_type='email',
groups='base.group_portal',
)
+4 -2
View File
@@ -9,7 +9,8 @@
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='tz']" position="after">
<field name="livechat_username" string="Online Chat Name" readonly="0"/>
<field name="livechat_username" string="Online Chat Name" readonly="0"
attrs="{'invisible': [('share', '=', True)]}"/>
</xpath>
</field>
</record>
@@ -21,7 +22,8 @@
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='messaging']" position="after">
<group name="livechat" string="Livechat">
<group name="livechat" string="Livechat"
attrs="{'invisible': [('share', '=', True)]}">
<field name="livechat_username"/>
</group>
</xpath>
+14
View File
@@ -22,11 +22,25 @@ class Users(models.Model):
('email', 'Handle by Emails'),
('inbox', 'Handle in Odoo')],
'Notification', required=True, default='email',
compute='_compute_notification_type', store=True, readonly=False,
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')
_sql_constraints = [(
"notification_type",
"CHECK (notification_type = 'email' OR NOT share)",
"Only internal user can receive notifications in Odoo",
)]
@api.depends('share')
def _compute_notification_type(self):
for user in self:
# Only the internal users can receive notifications in Odoo
if user.share or not user.notification_type:
user.notification_type = 'email'
# ------------------------------------------------------------
# CRUD
# ------------------------------------------------------------
+1
View File
@@ -9,6 +9,7 @@ from . import test_mail_render
from . import test_mail_template
from . import test_mail_tools
from . import test_res_partner
from . import test_res_users
from . import test_res_users_settings
from . import test_rtc
from . import test_update_notification
+22
View File
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from psycopg2 import IntegrityError
from odoo.addons.mail.tests.common import MailCommon, mail_new_test_user
from odoo.tools import mute_logger
class TestUser(MailCommon):
@mute_logger('odoo.sql_db')
def test_notification_type_constraint(self):
with self.assertRaises(IntegrityError, msg='Portal user can not receive notification in Odoo'):
mail_new_test_user(
self.env,
login='user_test_constraint_2',
name='Test User 2',
email='user_test_constraint_2@test.example.com',
notification_type='inbox',
groups='base.group_portal',
)
+2 -1
View File
@@ -27,7 +27,8 @@
<field name="arch" type="xml">
<data>
<field name="signature" position="before">
<field name="notification_type" widget="radio"/>
<field name="notification_type" widget="radio"
attrs="{'invisible': [('share', '=', True)]}"/>
</field>
</data>
</field>
+4 -2
View File
@@ -8,7 +8,8 @@
<field name="arch" type="xml">
<data>
<field name="notification_type" position="after">
<field name="odoobot_state" readonly="0" groups="base.group_no_one"/>
<field name="odoobot_state" readonly="0" groups="base.group_no_one"
attrs="{'invisible': [('share', '=', True)]}"/>
</field>
</data>
</field>
@@ -22,7 +23,8 @@
<field name="arch" type="xml">
<data>
<field name="signature" position="before">
<field name="odoobot_state" readonly="0" groups="base.group_no_one"/>
<field name="odoobot_state" readonly="0" groups="base.group_no_one"
attrs="{'invisible': [('share', '=', True)]}"/>
</field>
</data>
</field>
+1 -1
View File
@@ -32,7 +32,7 @@ class TestWebsiteBlogCommon(common.TransactionCase):
'name': 'Cedric Public',
'login': 'cedric',
'email': 'cedric.public@example.com',
'notification_type': 'inbox',
'notification_type': 'email',
'groups_id': [(6, 0, [group_public_id])]
})
@@ -16,7 +16,7 @@ class TestWebsiteBlogFlow(TestWebsiteBlogCommon):
'name': 'Dorian Portal',
'login': 'portal_user',
'email': 'portal_user@example.com',
'notification_type': 'inbox',
'notification_type': 'email',
'groups_id': [(6, 0, [group_portal.id])]
})
@@ -102,7 +102,7 @@ class TestPartnerLeadPortal(TestCrmCommon):
company_id=self.env.ref("base.main_company").id,
grade_id=self.grade.id,
user_id=self.user_sales_manager.id,
notification_type='inbox',
notification_type='email',
groups='base.group_portal',
)
+21 -3
View File
@@ -271,6 +271,7 @@ class Users(models.Model):
'image_1024', 'image_512', 'image_256', 'image_128', 'lang', 'tz',
'tz_offset', 'groups_id', 'partner_id', '__last_update', 'action_id',
'avatar_1920', 'avatar_1024', 'avatar_512', 'avatar_256', 'avatar_128',
'share',
]
@property
@@ -1235,7 +1236,8 @@ class GroupsView(models.Model):
user_type_field_name = field_name
user_type_readonly = str({'readonly': [(user_type_field_name, '!=', group_employee.id)]})
attrs['widget'] = 'radio'
attrs['groups'] = 'base.group_no_one'
# Trigger the on_change of this "virtual field"
attrs['on_change'] = '1'
xml1.append(E.field(name=field_name, **attrs))
xml1.append(E.newline())
@@ -1273,9 +1275,9 @@ class GroupsView(models.Model):
xml2.append(E.group(*(xml_by_category[xml_cat]), col="2", string=master_category_name))
xml = E.field(
E.group(*(xml1), col="2"),
E.group(*(xml1), col="2", groups="base.group_no_one"),
E.group(*(xml2), col="2", attrs=str(user_type_attrs)),
E.group(*(xml3), col="4", attrs=str(user_type_attrs)), name="groups_id", position="replace")
E.group(*(xml3), col="4", attrs=str(user_type_attrs), groups="base.group_no_one"), name="groups_id", position="replace")
xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS"))
# serialize and update the view
@@ -1431,6 +1433,22 @@ class UsersView(models.Model):
return values
def onchange(self, values, field_name, field_onchange):
# field_name can be either a string, a list or Falsy
if isinstance(field_name, list):
names = field_name
elif field_name:
names = [field_name]
else:
names = []
if any(is_reified_group(field) for field in names):
field_name = (
['groups_id']
+ [field for field in names if not is_reified_group(field)]
)
values.pop('groups_id', None)
values.update(self._remove_reified_groups(values))
field_onchange['groups_id'] = ''
result = super().onchange(values, field_name, field_onchange)
if not field_name: # merged default_get
+25
View File
@@ -171,3 +171,28 @@ class TestUsers2(TransactionCase):
user.write({fname: group2.id})
self.assertEqual(user.groups_id & groups, groups)
self.assertEqual(user.read([fname])[0][fname], group2.id)
def test_reified_groups_on_change(self):
"""Test that a change on a reified fields trigger the onchange of groups_id."""
group_public = self.env.ref('base.group_public')
group_portal = self.env.ref('base.group_portal')
group_user = self.env.ref('base.group_user')
# Build the reified group field name
user_groups = group_public | group_portal | group_user
user_groups_ids = [str(group_id) for group_id in sorted(user_groups.ids)]
group_field_name = f"sel_groups_{'_'.join(user_groups_ids)}"
user_form = Form(self.env['res.users'], view='base.view_users_form')
user_form.name = "Test"
user_form.login = "Test"
self.assertFalse(user_form.share)
setattr(user_form, group_field_name, group_portal.id)
self.assertTrue(user_form.share, 'The groups_id onchange should have been triggered')
setattr(user_form, group_field_name, group_user.id)
self.assertFalse(user_form.share, 'The groups_id onchange should have been triggered')
setattr(user_form, group_field_name, group_public.id)
self.assertTrue(user_form.share, 'The groups_id onchange should have been triggered')
+6 -2
View File
@@ -223,6 +223,7 @@
<group>
<field name="partner_id" readonly="1" required="0" groups="base.group_no_one"
attrs="{'invisible': [('id', '=', False)]}"/>
<field name="share" invisible="1"/>
</group>
</div>
<notebook colspan="4">
@@ -251,7 +252,8 @@
<field name="tz" widget="timezone_mismatch" options="{'tz_offset_field': 'tz_offset'}" />
<field name="tz_offset" invisible="1"/>
</group>
<group string="Menus Customization" groups="base.group_no_one">
<group string="Menus Customization" groups="base.group_no_one"
attrs="{'invisible': [('share', '=', True)]}">
<field name="action_id"/>
</group>
</group>
@@ -320,7 +322,8 @@
<field name="name" filter_domain="['|', '|', ('name','ilike',self), ('login','ilike',self), ('email','ilike',self)]" string="User"/>
<field name="company_ids" string="Company" groups="base.group_multi_company"/>
<field name="share"/>
<filter name="no_share" string="Internal Users" domain="[('share','=',False)]"/>
<filter name="filter_no_share" string="Internal Users" domain="[('share', '=', False)]"/>
<filter name="filter_share" string="Portal Users" domain="[('share', '=', True)]"/>
<separator/>
<filter name="Inactive" string="Inactive Users" domain="[('active','=',False)]"/>
</search>
@@ -453,6 +456,7 @@
<field name="tz" widget="timezone_mismatch" options="{'tz_offset_field': 'tz_offset'}" readonly="0"/>
<field name="tz_offset" invisible="1"/>
</group>
<field name="share" invisible="1"/>
</group>
<group name="signature">
<field name="signature" readonly="0" options="{'style-inline': true}"/>