diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index e54ac1a64e2..ee213449d66 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -819,6 +819,7 @@ class Channel(models.Model): 'public': channel.public, 'group_based_subscription': bool(channel.group_ids), 'create_uid': channel.create_uid.id, + 'authorizedGroupFullName': channel.group_public_id.full_name, } # add last message preview (only used in mobile) info['last_message_id'] = channel_last_message_ids.get(channel.id, False) diff --git a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml index 8613b5f629e..c4f6c4c2860 100644 --- a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml +++ b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml @@ -40,7 +40,7 @@

Invitation Link

-
+
@@ -49,6 +49,9 @@
+ +
+
diff --git a/addons/mail/static/src/models/channel_invitation_form.js b/addons/mail/static/src/models/channel_invitation_form.js index bcd8474c800..3f7f603fd32 100644 --- a/addons/mail/static/src/models/channel_invitation_form.js +++ b/addons/mail/static/src/models/channel_invitation_form.js @@ -5,6 +5,8 @@ import { attr, many, one } from '@mail/model/model_field'; import { clear, insertAndReplace, link, replace, unlink } from '@mail/model/model_field_command'; import { cleanSearchTerm } from '@mail/utils/utils'; +import { sprintf } from '@web/core/utils/strings'; + registerModel({ name: 'ChannelInvitationForm', identifyingFields: [['chatWindow', 'popoverViewOwner']], @@ -156,6 +158,25 @@ registerModel({ } } }, + /** + * @private + * @returns {string|FieldCommand} + */ + _computeAccessRestrictedToGroupText() { + if (!this.thread) { + return clear(); + } + if ( + !this.thread.authorizedGroupFullName || + this.thread.public !== 'groups' + ) { + return clear(); + } + return sprintf( + this.env._t('Access restricted to group "%(groupFullName)s"'), + { 'groupFullName': this.thread.authorizedGroupFullName } + ); + }, /** * @private * @returns {string} @@ -211,6 +232,9 @@ registerModel({ }, }, fields: { + accessRestrictedToGroupText: attr({ + compute: '_computeAccessRestrictedToGroupText', + }), chatWindow: one('ChatWindow', { inverse: 'channelInvitationForm', readonly: true, diff --git a/addons/mail/static/src/models/thread.js b/addons/mail/static/src/models/thread.js index 22f009db7d9..8b0c6c483af 100644 --- a/addons/mail/static/src/models/thread.js +++ b/addons/mail/static/src/models/thread.js @@ -41,6 +41,9 @@ registerModel({ */ convertData(data) { const data2 = {}; + if ('authorizedGroupFullName' in data) { + data2.authorizedGroupFullName = data.authorizedGroupFullName; + } if ('avatarCacheKey' in data) { data2.avatarCacheKey = data.avatarCacheKey; } @@ -1814,6 +1817,7 @@ registerModel({ attachments: many('Attachment', { inverse: 'threads', }), + authorizedGroupFullName: attr(), /** * Cache key to force a reload of the avatar when avatar is changed. * It only makes sense for channels. diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js index 2ee7f80e99d..ab9cd3da64c 100644 --- a/addons/mail/static/tests/helpers/mock_server.js +++ b/addons/mail/static/tests/helpers/mock_server.js @@ -789,7 +789,7 @@ MockServer.include({ channel_last_seen_partner_ids: [[2, channelMember.id]], }, ); - this.pyEnv['bus.bus']._sendone(this.currentPartner, 'mail.channel/leave', { + this.pyEnv['bus.bus']._sendone(this.currentPartner, 'mail.channel/leave', { 'id': channel.id, }); /** @@ -1004,6 +1004,9 @@ MockServer.include({ ['model', '=', 'mail.channel'], ['res_id', '=', channel.id], ]); + const [group_public_id] = this.getRecords('res.groups', [ + ['id', '=', channel.group_public_id], + ]); const lastMessageId = messages.reduce((lastMessageId, message) => { if (!lastMessageId || message.id > lastMessageId) { return message.id; @@ -1019,6 +1022,7 @@ MockServer.include({ last_message_id: lastMessageId, members: [...this._mockResPartnerMailPartnerFormat(partnerIds).values()], message_needaction_counter: messageNeedactionCounter, + authorizedGroupFullName: group_public_id ? group_public_id.name : false, }); if (channel.channel_type === 'channel') { delete res.members; @@ -1065,8 +1069,8 @@ MockServer.include({ ); } if (!pinned) { - this.pyEnv['bus.bus']._sendone(this.currentPartner, 'mail.channel/unpin', { - 'id': channel.id, + this.pyEnv['bus.bus']._sendone(this.currentPartner, 'mail.channel/unpin', { + 'id': channel.id, }); } else { this.pyEnv['bus.bus']._sendone(this.currentPartner, 'mail.channel/legacy_insert', this._mockMailChannelChannelInfo([channel.id])[0]); @@ -1260,9 +1264,9 @@ MockServer.include({ }, ); const channel = this.pyEnv['mail.channel'].searchRead([['id', '=', id]])[0]; - this.pyEnv['bus.bus']._sendone(channel, 'mail.channel/insert', { - 'id': id, - 'avatarCacheKey': channel.avatarCacheKey + this.pyEnv['bus.bus']._sendone(channel, 'mail.channel/insert', { + 'id': id, + 'avatarCacheKey': channel.avatarCacheKey }); }, /** diff --git a/addons/mail/static/tests/helpers/model_definitions_setup.js b/addons/mail/static/tests/helpers/model_definitions_setup.js index 5bf9435175e..3352ee335e4 100644 --- a/addons/mail/static/tests/helpers/model_definitions_setup.js +++ b/addons/mail/static/tests/helpers/model_definitions_setup.js @@ -16,7 +16,7 @@ addModelNamesToFetch([ 'ir.attachment', 'ir.model', 'ir.model.fields', 'mail.activity', 'mail.activity.type', 'mail.channel', 'mail.channel.partner', 'mail.followers', 'mail.message', 'mail.message.subtype', 'mail.notification', 'mail.shortcode', 'mail.template', 'mail.tracking.value', - 'res.company', 'res.country', 'res.partner', 'res.users', 'res.users.settings', + 'res.company', 'res.country', 'res.partner', 'res.users', 'res.users.settings', 'res.groups' ]); addFakeModel('res.fake', { diff --git a/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js index d8f8a0ac9a0..12d006ab37d 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js @@ -123,5 +123,42 @@ QUnit.test('should be able to create a new group chat from an existing chat', as ); }); +QUnit.test('Invitation form should display channel group restriction', async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const resPartnerId1 = pyEnv['res.partner'].create({ + email: "testpartner@odoo.com", + name: "TestPartner", + }); + pyEnv['res.users'].create({ partner_id: resPartnerId1 }); + const resGroupId1 = pyEnv['res.groups'].create({ + name: "testGroup", + }); + const mailChannelId1 = pyEnv['mail.channel'].create({ + channel_last_seen_partner_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + ], + channel_type: 'channel', + public: 'groups', + group_public_id: resGroupId1, + }); + const { click, openDiscuss } = await start({ + discuss: { + context: { + active_id: mailChannelId1, + }, + }, + }); + await openDiscuss(); + + await click(`.o_ThreadViewTopbar_inviteButton`); + assert.containsOnce( + document.body, + '.o_ChannelInvitationForm_accessRestrictedToGroup', + "should display the channel restriction warning" + ); +}); + }); }); diff --git a/addons/test_discuss_full/tests/test_performance.py b/addons/test_discuss_full/tests/test_performance.py index 10cf9eb89f1..dd371a81aaa 100644 --- a/addons/test_discuss_full/tests/test_performance.py +++ b/addons/test_discuss_full/tests/test_performance.py @@ -6,17 +6,18 @@ from dateutil.relativedelta import relativedelta from odoo import Command from odoo.tests.common import users, tagged, TransactionCase, warmup -from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT @tagged('post_install', '-at_install') class TestDiscussFullPerformance(TransactionCase): def setUp(self): super().setUp() + self.group_user = self.env.ref('base.group_user') self.users = self.env['res.users'].create([ { 'email': 'e.e@example.com', - 'groups_id': [Command.link(self.env.ref('base.group_user').id)], + 'groups_id': [Command.link(self.group_user.id)], 'login': 'emp', 'name': 'Ernest Employee', 'notification_type': 'inbox', @@ -100,7 +101,7 @@ class TestDiscussFullPerformance(TransactionCase): self.maxDiff = None self.users[0].flush() self.users[0].invalidate_cache() - with self.assertQueryCount(emp=82): + with self.assertQueryCount(emp=83): init_messaging = self.users[0].with_user(self.users[0])._init_messaging() self.assertEqual(init_messaging, { @@ -108,6 +109,7 @@ class TestDiscussFullPerformance(TransactionCase): 'starred_counter': 1, 'channels': [ { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_general._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': user_root.id, @@ -122,7 +124,7 @@ class TestDiscussFullPerformance(TransactionCase): 'is_pinned': True, 'last_interest_dt': channel_general.channel_last_seen_partner_ids.filtered(lambda p: p.partner_id == self.users[0].partner_id).last_interest_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), 'last_message_id': next(res['message_id'] for res in channel_general._channel_last_message_ids()), - 'memberCount': len(self.env.ref('base.group_user').users | user_root), + 'memberCount': len(self.group_user.users | user_root), 'message_needaction_counter': 0, 'message_unread_counter': 5, 'name': 'general', @@ -133,6 +135,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_general.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_public_1._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -158,6 +161,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_public_1.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_public_2._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -183,6 +187,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_public_2.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_group_1._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -208,6 +213,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_group_1.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_group_2._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -233,6 +239,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_group_2.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_private_1._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -258,6 +265,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_private_1.uuid, }, { + 'authorizedGroupFullName': self.group_user.full_name, 'avatarCacheKey': channel_channel_private_2._get_avatar_cache_key(), 'channel_type': 'channel', 'create_uid': self.env.user.id, @@ -283,6 +291,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_channel_private_2.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_group_1._get_avatar_cache_key(), 'channel_type': 'group', 'create_uid': self.env.user.id, @@ -347,6 +356,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_group_1.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_chat_1._get_avatar_cache_key(), 'channel_type': 'chat', 'create_uid': self.env.user.id, @@ -411,6 +421,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_chat_1.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_chat_2._get_avatar_cache_key(), 'channel_type': 'chat', 'create_uid': self.env.user.id, @@ -475,6 +486,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_chat_2.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_chat_3._get_avatar_cache_key(), 'channel_type': 'chat', 'create_uid': self.env.user.id, @@ -539,6 +551,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_chat_3.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_chat_4._get_avatar_cache_key(), 'channel_type': 'chat', 'create_uid': self.env.user.id, @@ -603,6 +616,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_chat_4.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_livechat_1._get_avatar_cache_key(), 'channel_type': 'livechat', 'create_uid': self.env.user.id, @@ -667,6 +681,7 @@ class TestDiscussFullPerformance(TransactionCase): 'uuid': channel_livechat_1.uuid, }, { + 'authorizedGroupFullName': False, 'avatarCacheKey': channel_livechat_2._get_avatar_cache_key(), 'channel_type': 'livechat', 'create_uid': self.env.ref('base.public_user').id,