[IMP] mail: display guest in channel member list

Part of task-2664860

closes odoo/odoo#95859

Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
This commit is contained in:
Sébastien Theys
2022-07-12 18:31:42 +02:00
parent 4161e1d04e
commit 458cb9b55a
10 changed files with 103 additions and 53 deletions
+22 -8
View File
@@ -1176,15 +1176,29 @@ class Channel(models.Model):
count = self.env['mail.channel.partner'].search_count(
domain=[('channel_id', '=', self.id)],
)
return {
'channelMembers': [('insert', [{
members_data = []
for member in channel_partners:
if member.partner_id:
persona = {
'partner': [('insert-and-replace', {
'id': member.partner_id.id,
'name': member.partner_id.name,
'im_status': member.partner_id.im_status,
})],
}
if member.guest_id:
persona = {
'guest': [('insert-and-replace', {
'id': member.guest_id.id,
'name': member.guest_id.name,
})],
}
members_data.append({
'id': member.id,
'partner': [('insert', {
'id': member.partner_id.id,
'name': member.partner_id.name,
'im_status': member.partner_id.im_status,
})] if member.partner_id else [('clear',)],
} for member in channel_partners])],
'persona': [('insert-and-replace', persona)],
})
return {
'channelMembers': [('insert', members_data)],
'memberCount': count,
}
@@ -2,9 +2,9 @@
<templates xml:space="preserve">
<t t-name="mail.ChannelMember" owl="1">
<div class="o_ChannelMember d-flex align-items-center mx-2 p-2" t-att-class="{'o_cursor_pointer': channelMemberView.hasOpenChat}" t-attf-class="{{ className }}" t-att-data-partner-local-id="channelMemberView.channelMember.partner.localId" t-att-title="channelMemberView.memberTitleText" t-on-click="channelMemberView.onClickMember" t-ref="root">
<div class="o_ChannelMember d-flex align-items-center mx-2 p-2" t-att-class="{'o_cursor_pointer': channelMemberView.hasOpenChat}" t-attf-class="{{ className }}" t-att-data-partner-id="channelMemberView.channelMember.persona.partner and channelMemberView.channelMember.persona.partner.id" t-att-title="channelMemberView.memberTitleText" t-on-click="channelMemberView.onClickMember" t-ref="root">
<div class="o_ChannelMember_avatarContainer position-relative flex-shrink-0">
<img class="o_ChannelMember_avatar rounded-circle w-100 h-100" t-attf-src="/mail/channel/{{ channelMemberView.channelMember.channel.id }}/partner/{{ channelMemberView.channelMember.partner.id }}/avatar_128" alt="Avatar"/>
<img class="o_ChannelMember_avatar rounded-circle w-100 h-100" t-att-src="channelMemberView.channelMember.avatarUrl" alt="Avatar"/>
<t t-if="channelMemberView.personaImStatusIconView">
<PersonaImStatusIcon
@@ -19,7 +19,7 @@
</t>
</div>
<span class="o_ChannelMember_name ms-2 flex-column-1 text-truncate">
<t t-esc="channelMemberView.channelMember.partner.nameOrDisplayName"/>
<t t-esc="channelMemberView.channelMember.persona.name"/>
</span>
</div>
</t>
+2 -2
View File
@@ -52,8 +52,8 @@ registerModel({
*/
_sortMembers() {
return [
['truthy-first', 'name'],
['case-insensitive-asc', 'name'],
['truthy-first', 'persona.name'],
['case-insensitive-asc', 'persona.name'],
];
},
},
+31 -15
View File
@@ -8,32 +8,50 @@ registerModel({
name: 'ChannelMember',
identifyingFields: ['id'],
recordMethods: {
/**
* @private
* @returns {string|FieldCommand}
*/
_computeAvatarUrl() {
if (this.persona.partner) {
return `/mail/channel/${this.channel.id}/partner/${this.persona.partner.id}/avatar_128`;
}
if (this.persona.guest) {
return `/mail/channel/${this.channel.id}/guest/${this.persona.guest.id}/avatar_128?unique=${this.persona.guest.name}`;
}
return clear();
},
/**
* @private
* @returns {FieldCommand}
*/
_computeChannelAsOfflineMember() {
return this.partner && !this.partner.isOnline ? replace(this.channel) : clear();
if (this.persona.partner) {
return !this.persona.partner.isOnline ? replace(this.channel) : clear();
}
if (this.persona.guest) {
return replace(this.channel);
}
return clear();
},
/**
* @private
* @returns {FieldCommand}
*/
_computeChannelAsOnlineMember() {
return this.partner && this.partner.isOnline ? replace(this.channel) : clear();
},
/**
* @private
* @returns {string}
*/
_computeName() {
if (!this.partner) {
return;
if (this.persona.partner) {
return this.persona.partner.isOnline ? replace(this.channel) : clear();
}
return this.partner.nameOrDisplayName;
if (this.persona.guest) {
return clear();
}
return clear();
},
},
fields: {
avatarUrl: attr({
compute: '_computeAvatarUrl',
}),
channel: one('Channel', {
inverse: 'channelMembers',
readonly: true,
@@ -55,12 +73,10 @@ registerModel({
readonly: true,
required: true,
}),
name: attr({
compute: '_computeName',
}),
partner: one('Partner', {
persona: one('Persona', {
inverse: 'channelMembers',
readonly: true,
required: true,
}),
},
});
@@ -15,17 +15,17 @@ registerModel({
* @param {MouseEvent} ev
*/
onClickMember(ev) {
if (isEventHandled(ev, 'PersonaImStatusIcon.Click') || !this.channelMember.partner) {
if (isEventHandled(ev, 'PersonaImStatusIcon.Click') || !this.channelMember.persona.partner) {
return;
}
this.channelMember.partner.openChat();
this.channelMember.persona.partner.openChat();
},
/**
* @private
* @returns {Boolean}
*/
_computeHasOpenChat() {
return this.channelMember.partner ? true : false;
return this.channelMember.persona.partner ? true : false;
},
/**
* @private
@@ -39,7 +39,7 @@ registerModel({
* @returns {FieldCommand}
*/
_computePersonaImStatusIconView() {
return this.channelMember.partner && this.channelMember.partner.isImStatusSet ? insertAndReplace() : clear();
return this.channelMember.persona.partner && this.channelMember.persona.partner.isImStatusSet ? insertAndReplace() : clear();
},
},
fields: {
-4
View File
@@ -383,10 +383,6 @@ registerModel({
inverse: 'partner',
isCausal: true,
}),
channelMembers: many('ChannelMember', {
inverse: 'partner',
isCausal: true,
}),
country: one('Country'),
/**
* Deprecated.
+5 -1
View File
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
import { attr, many, one } from '@mail/model/model_field';
import { clear } from '@mail/model/model_field_command';
registerModel({
@@ -36,6 +36,10 @@ registerModel({
},
},
fields: {
channelMembers: many('ChannelMember', {
inverse: 'persona',
isCausal: true,
}),
guest: one('Guest', {
inverse: 'persona',
readonly: true,
@@ -25,7 +25,7 @@ registerModel({
return replace(this.channelInvitationFormSelectablePartnerViewOwner.partner.persona);
}
if (this.channelMemberViewOwner) {
return replace(this.channelMemberViewOwner.channelMember.partner.persona);
return replace(this.channelMemberViewOwner.channelMember.persona);
}
if (this.composerSuggestionViewOwner) {
return replace(this.composerSuggestionViewOwner.suggestable.partner.persona);
@@ -1329,17 +1329,41 @@ patch(MockServer.prototype, 'mail', {
const memberCount = this.pyEnv['mail.channel.partner'].searchCount([
['channel_id', 'in', channel_ids],
]);
return {
channelMembers: [['insert', channelPartners.map(channelPartner => {
const membersData = [];
for (const channelPartner of channelPartners) {
let persona;
if (channelPartner.partner_id) {
const [partner] = this.pyEnv['res.partner'].searchRead(
[['id', '=', channelPartner.partner_id[0]]],
{ fields: ['id', 'name', 'im_status'] }
);
return {
id: channelPartner.id,
partner: [['insert', partner]],
persona = {
'partner': [['insert-and-replace', {
'id': partner.id,
'name': partner.name,
'im_status': partner.im_status,
}]],
};
})]],
}
if (channelPartner.guest_id) {
const [guest] = this.pyEnv['mail.guest'].searchRead(
[['id', '=', channelPartner.guest_id[0]]],
{ fields: ['id', 'name'] }
);
persona = {
'guest': [['insert-and-replace', {
'id': guest.id,
'name': guest.name,
}]],
};
}
membersData.push({
'id': channelPartner.id,
'persona': [['insert-and-replace', persona]],
});
}
return {
channelMembers: [['insert', membersData]],
memberCount,
};
},
@@ -79,7 +79,7 @@ QUnit.test('should have correct members in member list', async function (assert)
channel_type: 'group',
public: 'private',
});
const { click, messaging, openDiscuss } = await start({
const { click, openDiscuss } = await start({
discuss: {
context: {
active_id: `mail.channel_${mailChannelId1}`,
@@ -96,16 +96,12 @@ QUnit.test('should have correct members in member list', async function (assert)
);
assert.containsOnce(
document.body,
`.o_ChannelMember[data-partner-local-id="${
messaging.models['Partner'].findFromIdentifyingData({ id: pyEnv.currentPartnerId }).localId
}"]`,
`.o_ChannelMember[data-partner-id="${pyEnv.currentPartnerId}"]`,
"should have current partner in member list (current partner is a member)",
);
assert.containsOnce(
document.body,
`.o_ChannelMember[data-partner-local-id="${
messaging.models['Partner'].findFromIdentifyingData({ id: resPartnerId1 }).localId
}"]`,
`.o_ChannelMember[data-partner-id="${resPartnerId1}"]`,
"should have 'Demo' in member list ('Demo' is a member)",
);
});
@@ -215,7 +211,7 @@ QUnit.test('chat with member should be opened after clicking on channel member',
channel_type: 'group',
public: 'private',
});
const { click, messaging, openDiscuss } = await start({
const { click, openDiscuss } = await start({
discuss: {
context: {
active_id: `mail.channel_${mailChannelId1}`,
@@ -225,7 +221,7 @@ QUnit.test('chat with member should be opened after clicking on channel member',
await openDiscuss();
await click('.o_ThreadViewTopbar_showMemberListButton');
await click(`.o_ChannelMember[data-partner-local-id="${messaging.models['Partner'].findFromIdentifyingData({ id: resPartnerId1 }).localId}"]`);
await click(`.o_ChannelMember[data-partner-id="${resPartnerId1}"]`);
assert.containsOnce(
document.body,
`.o_ThreadView[data-correspondent-id="${resPartnerId1}"]`,