[REF] mail: move service.update() to discuss models
These `update()` functions are specific to a discuss record, so it's best to be defined in the model rather than another service. Part-of: odoo/odoo#136308
This commit is contained in:
@@ -48,6 +48,17 @@ patch(Thread, {
|
||||
patch(Thread.prototype, {
|
||||
chatbotScriptId: null,
|
||||
|
||||
update(data) {
|
||||
super.update(...arguments);
|
||||
if (data.operator_pid) {
|
||||
this.operator = this._store.Persona.insert({
|
||||
type: "partner",
|
||||
id: data.operator_pid[0],
|
||||
name: data.operator_pid[1],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
get isChannel() {
|
||||
return this.type === "livechat" || super.isChannel;
|
||||
},
|
||||
|
||||
@@ -63,17 +63,6 @@ patch(ThreadService.prototype, {
|
||||
}
|
||||
},
|
||||
|
||||
async update(thread, data) {
|
||||
super.update(...arguments);
|
||||
if (data.operator_pid) {
|
||||
thread.operator = this.store.Persona.insert({
|
||||
type: "partner",
|
||||
id: data.operator_pid[0],
|
||||
name: data.operator_pid[1],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
avatarUrl(author, thread) {
|
||||
if (thread.type !== "livechat") {
|
||||
return super.avatarUrl(...arguments);
|
||||
|
||||
@@ -28,10 +28,45 @@ export class Attachment extends Record {
|
||||
}
|
||||
const attachment = this.get(data) ?? this.new(data);
|
||||
Object.assign(attachment, { id: data.id });
|
||||
this.env.services["mail.attachment"].update(attachment, data);
|
||||
attachment.update(data);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
assignDefined(this, data, [
|
||||
"checksum",
|
||||
"create_date",
|
||||
"filename",
|
||||
"mimetype",
|
||||
"name",
|
||||
"type",
|
||||
"url",
|
||||
"uploading",
|
||||
"extension",
|
||||
"accessToken",
|
||||
"tmpUrl",
|
||||
"message",
|
||||
"res_name",
|
||||
]);
|
||||
if (!("extension" in data) && data["name"]) {
|
||||
this.extension = this.name.split(".").pop();
|
||||
}
|
||||
if (data.originThread !== undefined) {
|
||||
const threadData = Array.isArray(data.originThread)
|
||||
? data.originThread[0][1]
|
||||
: data.originThread;
|
||||
this.originThread = this._store.Thread.insert({
|
||||
model: threadData.model,
|
||||
id: threadData.id,
|
||||
});
|
||||
const thread = this.originThread;
|
||||
if (this.notIn(thread.attachments)) {
|
||||
thread.attachments.push(this);
|
||||
thread.attachments.sort((a1, a2) => (a1.id < a2.id ? 1 : -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accessToken;
|
||||
checksum;
|
||||
extension;
|
||||
|
||||
@@ -19,41 +19,6 @@ export class AttachmentService {
|
||||
this.rpc = services["rpc"];
|
||||
}
|
||||
|
||||
update(attachment, data) {
|
||||
assignDefined(attachment, data, [
|
||||
"checksum",
|
||||
"create_date",
|
||||
"filename",
|
||||
"mimetype",
|
||||
"name",
|
||||
"type",
|
||||
"url",
|
||||
"uploading",
|
||||
"extension",
|
||||
"accessToken",
|
||||
"tmpUrl",
|
||||
"message",
|
||||
"res_name",
|
||||
]);
|
||||
if (!("extension" in data) && data["name"]) {
|
||||
attachment.extension = attachment.name.split(".").pop();
|
||||
}
|
||||
if (data.originThread !== undefined) {
|
||||
const threadData = Array.isArray(data.originThread)
|
||||
? data.originThread[0][1]
|
||||
: data.originThread;
|
||||
attachment.originThread = this.store.Thread.insert({
|
||||
model: threadData.model,
|
||||
id: threadData.id,
|
||||
});
|
||||
const thread = attachment.originThread;
|
||||
if (attachment.notIn(thread.attachments)) {
|
||||
thread.attachments.push(attachment);
|
||||
thread.attachments.sort((a1, a2) => (a1.id < a2.id ? 1 : -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given attachment globally.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
|
||||
/**
|
||||
* @class ChannelMember
|
||||
@@ -28,10 +29,50 @@ export class ChannelMember extends Record {
|
||||
static insert(data) {
|
||||
const memberData = Array.isArray(data) ? data[1] : data;
|
||||
const member = this.get(memberData) ?? this.new(memberData);
|
||||
this.env.services["discuss.channel.member"].update(member, data);
|
||||
member.update(data);
|
||||
return member;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
const [command, memberData] = Array.isArray(data) ? data : ["insert", data];
|
||||
this.id = memberData.id;
|
||||
if ("persona" in memberData) {
|
||||
this.persona = this._store.Persona.insert({
|
||||
...(memberData.persona.partner ?? memberData.persona.guest),
|
||||
type: memberData.persona.guest ? "guest" : "partner",
|
||||
country: memberData.persona.partner?.country,
|
||||
channelId: memberData.persona.guest ? memberData.channel.id : null,
|
||||
});
|
||||
}
|
||||
let thread = memberData.thread ?? this.thread;
|
||||
if (!thread && memberData.channel?.id) {
|
||||
thread = this._store.Thread.insert({
|
||||
id: memberData.channel.id,
|
||||
model: "discuss.channel",
|
||||
});
|
||||
}
|
||||
if (thread && !this.thread) {
|
||||
this.thread = thread;
|
||||
}
|
||||
switch (command) {
|
||||
case "insert":
|
||||
{
|
||||
if (this.thread && this.notIn(this.thread.channelMembers)) {
|
||||
this.thread.channelMembers.push(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "unlink":
|
||||
removeFromArray(this._store.ChannelMember.records, this);
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case "insert-and-unlink":
|
||||
if (this.thread) {
|
||||
removeFromArray(this.thread.channelMembers, this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {number} */
|
||||
id;
|
||||
persona = Record.one("Persona");
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
export class ChannelMemberService {
|
||||
@@ -14,46 +12,6 @@ export class ChannelMemberService {
|
||||
this.store = services["mail.store"];
|
||||
}
|
||||
|
||||
update(member, data) {
|
||||
const [command, memberData] = Array.isArray(data) ? data : ["insert", data];
|
||||
member.id = memberData.id;
|
||||
if ("persona" in memberData) {
|
||||
member.persona = this.store.Persona.insert({
|
||||
...(memberData.persona.partner ?? memberData.persona.guest),
|
||||
type: memberData.persona.guest ? "guest" : "partner",
|
||||
country: memberData.persona.partner?.country,
|
||||
channelId: memberData.persona.guest ? memberData.channel.id : null,
|
||||
});
|
||||
}
|
||||
let thread = memberData.thread ?? member.thread;
|
||||
if (!thread && memberData.channel?.id) {
|
||||
thread = this.store.Thread.insert({
|
||||
id: memberData.channel.id,
|
||||
model: "discuss.channel",
|
||||
});
|
||||
}
|
||||
if (thread && !member.thread) {
|
||||
member.thread = thread;
|
||||
}
|
||||
switch (command) {
|
||||
case "insert":
|
||||
{
|
||||
if (member.thread && member.notIn(member.thread.channelMembers)) {
|
||||
member.thread.channelMembers.push(member);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "unlink":
|
||||
removeFromArray(this.store.ChannelMember.records, member);
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case "insert-and-unlink":
|
||||
if (member.thread) {
|
||||
removeFromArray(member.thread.channelMembers, member);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").ChannelMember} member
|
||||
* @returns {string}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { replaceArrayWithCompare } from "@mail/utils/common/arrays";
|
||||
import { htmlToTextContentInline } from "@mail/utils/common/format";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
|
||||
import { toRaw } from "@odoo/owl";
|
||||
|
||||
@@ -36,10 +38,139 @@ export class Message extends Record {
|
||||
});
|
||||
}
|
||||
const message = this.get(data) ?? this.new(data);
|
||||
this.env.services["mail.message"].update(message, data);
|
||||
message.update(data);
|
||||
return message;
|
||||
}
|
||||
|
||||
/** @param {Object} data */
|
||||
update(data) {
|
||||
const {
|
||||
attachment_ids: attachments = this.attachments,
|
||||
default_subject: defaultSubject = this.defaultSubject,
|
||||
is_discussion: isDiscussion = this.isDiscussion,
|
||||
is_note: isNote = this.isNote,
|
||||
is_transient: isTransient = this.isTransient,
|
||||
linkPreviews = this.linkPreviews,
|
||||
message_type: type = this.type,
|
||||
model: resModel = this.resModel,
|
||||
module_icon,
|
||||
notifications = this.notifications,
|
||||
parentMessage,
|
||||
recipients = this.recipients,
|
||||
record_name,
|
||||
res_id: resId = this.resId,
|
||||
res_model_name,
|
||||
subtype_description: subtypeDescription = this.subtypeDescription,
|
||||
...remainingData
|
||||
} = data;
|
||||
assignDefined(this, remainingData);
|
||||
assignDefined(this, {
|
||||
defaultSubject,
|
||||
isDiscussion,
|
||||
isNote,
|
||||
isStarred: this._store.user
|
||||
? this.starred_partner_ids.includes(this._store.user.id)
|
||||
: false,
|
||||
isTransient,
|
||||
parentMessage: parentMessage ? this._store.Message.insert(parentMessage) : undefined,
|
||||
resId,
|
||||
resModel,
|
||||
subtypeDescription,
|
||||
type,
|
||||
});
|
||||
// origin thread before other information (in particular notification insert uses it)
|
||||
if (this.originThread) {
|
||||
assignDefined(this.originThread, {
|
||||
modelName: res_model_name || undefined,
|
||||
module_icon: module_icon || undefined,
|
||||
name:
|
||||
this.originThread.model === "discuss.channel"
|
||||
? undefined
|
||||
: record_name || undefined,
|
||||
});
|
||||
}
|
||||
replaceArrayWithCompare(
|
||||
this.attachments,
|
||||
attachments.map((attachment) =>
|
||||
this._store.Attachment.insert({ message: this, ...attachment })
|
||||
)
|
||||
);
|
||||
if (
|
||||
Array.isArray(this.author) &&
|
||||
this.author.some((command) => command.includes("clear"))
|
||||
) {
|
||||
this.author = undefined;
|
||||
}
|
||||
if (data.author?.id) {
|
||||
this.author = this._store.Persona.insert({
|
||||
...data.author,
|
||||
type: "partner",
|
||||
});
|
||||
}
|
||||
if (data.guestAuthor?.id) {
|
||||
this.author = this._store.Persona.insert({
|
||||
...data.guestAuthor,
|
||||
type: "guest",
|
||||
channelId: this.originThread.id,
|
||||
});
|
||||
}
|
||||
replaceArrayWithCompare(
|
||||
this.linkPreviews,
|
||||
linkPreviews.map((data) => this._store.LinkPreview.insert({ ...data, message: this }))
|
||||
);
|
||||
replaceArrayWithCompare(
|
||||
this.notifications,
|
||||
notifications.map((notification) =>
|
||||
this._store.Notification.insert({ ...notification, message: this })
|
||||
)
|
||||
);
|
||||
replaceArrayWithCompare(
|
||||
this.recipients,
|
||||
recipients.map((recipient) =>
|
||||
this._store.Persona.insert({ ...recipient, type: "partner" })
|
||||
)
|
||||
);
|
||||
if ("user_follower_id" in data && data.user_follower_id && this._store.self) {
|
||||
this.originThread.selfFollower = this._store.Follower.insert({
|
||||
followedThread: this.originThread,
|
||||
id: data.user_follower_id,
|
||||
isActive: true,
|
||||
partner: this._store.self,
|
||||
});
|
||||
}
|
||||
if (data.messageReactionGroups) {
|
||||
const reactionContentToUnlink = new Set();
|
||||
const reactionsToInsert = [];
|
||||
for (const rawReaction of data.messageReactionGroups) {
|
||||
const [command, reactionData] = Array.isArray(rawReaction)
|
||||
? rawReaction
|
||||
: ["insert", rawReaction];
|
||||
const reaction = this._store.MessageReactions.insert(reactionData);
|
||||
if (command === "insert") {
|
||||
reactionsToInsert.push(reaction);
|
||||
} else {
|
||||
reactionContentToUnlink.add(reaction.content);
|
||||
}
|
||||
}
|
||||
this.reactions = this.reactions.filter(
|
||||
({ content }) => !reactionContentToUnlink.has(content)
|
||||
);
|
||||
reactionsToInsert.forEach((reaction) => {
|
||||
const idx = this.reactions.findIndex(({ content }) => reaction.content === content);
|
||||
if (idx !== -1) {
|
||||
this.reactions[idx] = reaction;
|
||||
} else {
|
||||
this.reactions.push(reaction);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.isNotification && !this.notificationType) {
|
||||
const parser = new DOMParser();
|
||||
const htmlBody = parser.parseFromString(this.body, "text/html");
|
||||
this.notificationType = htmlBody.querySelector(".o_mail_notification")?.dataset.oeType;
|
||||
}
|
||||
}
|
||||
|
||||
attachments = Record.many("Attachment");
|
||||
author = Record.one("Persona");
|
||||
/** @type {string} */
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { removeFromArrayWithPredicate, replaceArrayWithCompare } from "@mail/utils/common/arrays";
|
||||
import { removeFromArrayWithPredicate } from "@mail/utils/common/arrays";
|
||||
import { convertBrToLineBreak, prettifyMessageContent } from "@mail/utils/common/format";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
@@ -202,206 +201,6 @@ export class MessageService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Message} message
|
||||
* @param {Object} data
|
||||
*/
|
||||
update(message, data) {
|
||||
const {
|
||||
attachment_ids: attachments = message.attachments,
|
||||
default_subject: defaultSubject = message.defaultSubject,
|
||||
is_discussion: isDiscussion = message.isDiscussion,
|
||||
is_note: isNote = message.isNote,
|
||||
is_transient: isTransient = message.isTransient,
|
||||
linkPreviews = message.linkPreviews,
|
||||
message_type: type = message.type,
|
||||
model: resModel = message.resModel,
|
||||
module_icon,
|
||||
notifications = message.notifications,
|
||||
parentMessage,
|
||||
recipients = message.recipients,
|
||||
record_name,
|
||||
res_id: resId = message.resId,
|
||||
res_model_name,
|
||||
subtype_description: subtypeDescription = message.subtypeDescription,
|
||||
...remainingData
|
||||
} = data;
|
||||
assignDefined(message, remainingData);
|
||||
assignDefined(message, {
|
||||
defaultSubject,
|
||||
isDiscussion,
|
||||
isNote,
|
||||
isStarred: this.store.user
|
||||
? message.starred_partner_ids.includes(this.store.user.id)
|
||||
: false,
|
||||
isTransient,
|
||||
parentMessage: parentMessage ? this.store.Message.insert(parentMessage) : undefined,
|
||||
resId,
|
||||
resModel,
|
||||
subtypeDescription,
|
||||
type,
|
||||
});
|
||||
// origin thread before other information (in particular notification insert uses it)
|
||||
if (message.originThread) {
|
||||
assignDefined(message.originThread, {
|
||||
modelName: res_model_name || undefined,
|
||||
module_icon: module_icon || undefined,
|
||||
name:
|
||||
message.originThread.model === "discuss.channel"
|
||||
? undefined
|
||||
: record_name || undefined,
|
||||
});
|
||||
}
|
||||
replaceArrayWithCompare(
|
||||
message.attachments,
|
||||
attachments.map((attachment) =>
|
||||
this.store.Attachment.insert({ message, ...attachment })
|
||||
)
|
||||
);
|
||||
if (
|
||||
Array.isArray(message.author) &&
|
||||
message.author.some((command) => command.includes("clear"))
|
||||
) {
|
||||
message.author = undefined;
|
||||
}
|
||||
if (data.author?.id) {
|
||||
message.author = this.store.Persona.insert({
|
||||
...data.author,
|
||||
type: "partner",
|
||||
});
|
||||
}
|
||||
if (data.guestAuthor?.id) {
|
||||
message.author = this.store.Persona.insert({
|
||||
...data.guestAuthor,
|
||||
type: "guest",
|
||||
channelId: message.originThread.id,
|
||||
});
|
||||
}
|
||||
replaceArrayWithCompare(
|
||||
message.linkPreviews,
|
||||
linkPreviews.map((data) => this.store.LinkPreview.insert({ ...data, message }))
|
||||
);
|
||||
replaceArrayWithCompare(
|
||||
message.notifications,
|
||||
notifications.map((notification) =>
|
||||
this.store.Notification.insert({ ...notification, message })
|
||||
)
|
||||
);
|
||||
replaceArrayWithCompare(
|
||||
message.recipients,
|
||||
recipients.map((recipient) =>
|
||||
this.store.Persona.insert({ ...recipient, type: "partner" })
|
||||
)
|
||||
);
|
||||
if ("user_follower_id" in data && data.user_follower_id && this.store.self) {
|
||||
message.originThread.selfFollower = this.env.services["mail.store"].Follower.insert({
|
||||
followedThread: message.originThread,
|
||||
id: data.user_follower_id,
|
||||
isActive: true,
|
||||
partner: this.store.self,
|
||||
});
|
||||
}
|
||||
if (data.messageReactionGroups) {
|
||||
this._updateReactions(message, data.messageReactionGroups);
|
||||
}
|
||||
if (message.isNotification && !message.notificationType) {
|
||||
const parser = new DOMParser();
|
||||
const htmlBody = parser.parseFromString(message.body, "text/html");
|
||||
message.notificationType =
|
||||
htmlBody.querySelector(".o_mail_notification")?.dataset.oeType;
|
||||
}
|
||||
this.env.bus.trigger("mail.message/onUpdate", { message, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Message} message
|
||||
*/
|
||||
_updateReactions(message, reactionGroups) {
|
||||
const reactionContentToUnlink = new Set();
|
||||
const reactionsToInsert = [];
|
||||
for (const rawReaction of reactionGroups) {
|
||||
const [command, reactionData] = Array.isArray(rawReaction)
|
||||
? rawReaction
|
||||
: ["insert", rawReaction];
|
||||
const reaction = this.store.MessageReactions.insert(reactionData);
|
||||
if (command === "insert") {
|
||||
reactionsToInsert.push(reaction);
|
||||
} else {
|
||||
reactionContentToUnlink.add(reaction.content);
|
||||
}
|
||||
}
|
||||
message.reactions = message.reactions.filter(
|
||||
({ content }) => !reactionContentToUnlink.has(content)
|
||||
);
|
||||
reactionsToInsert.forEach((reaction) => {
|
||||
const idx = message.reactions.findIndex(({ content }) => reaction.content === content);
|
||||
if (idx !== -1) {
|
||||
message.reactions[idx] = reaction;
|
||||
} else {
|
||||
message.reactions.push(reaction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateNotification(notification, data) {
|
||||
Object.assign(notification, {
|
||||
message: data.message,
|
||||
notification_status: data.notification_status,
|
||||
notification_type: data.notification_type,
|
||||
failure_type: data.failure_type,
|
||||
persona: data.res_partner_id
|
||||
? this.store.Persona.insert({
|
||||
id: data.res_partner_id[0],
|
||||
displayName: data.res_partner_id[1],
|
||||
type: "partner",
|
||||
})
|
||||
: undefined,
|
||||
});
|
||||
if (!notification.message.author?.eq(this.store.self)) {
|
||||
return;
|
||||
}
|
||||
const thread = notification.message.originThread;
|
||||
this.store.NotificationGroup.insert({
|
||||
modelName: thread?.modelName,
|
||||
resId: thread?.id,
|
||||
resModel: thread?.model,
|
||||
status: notification.notification_status,
|
||||
type: notification.notification_type,
|
||||
notifications: [
|
||||
[notification.isFailure ? "insert" : "insert-and-unlink", notification],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
updateNotificationGroup(group, data) {
|
||||
Object.assign(group, {
|
||||
modelName: data.modelName ?? group.modelName,
|
||||
resModel: data.resModel ?? group.resModel,
|
||||
type: data.type ?? group.type,
|
||||
status: data.status ?? group.status,
|
||||
});
|
||||
const notifications = data.notifications ?? [];
|
||||
const alreadyKnownNotifications = new Set(group.notifications.map(({ id }) => id));
|
||||
const notificationIdsToRemove = new Set();
|
||||
for (const [commandName, notification] of notifications) {
|
||||
if (commandName === "insert" && !alreadyKnownNotifications.has(notification.id)) {
|
||||
group.notifications.push(notification);
|
||||
} else if (commandName === "insert-and-unlink") {
|
||||
notificationIdsToRemove.add(notification.id);
|
||||
}
|
||||
}
|
||||
group.notifications = group.notifications.filter(
|
||||
({ id }) => !notificationIdsToRemove.has(id)
|
||||
);
|
||||
group.lastMessage = group.notifications[0]?.message;
|
||||
for (const notification of group.notifications) {
|
||||
if (group.lastMessage?.id < notification.message?.id) {
|
||||
group.lastMessage = notification.message;
|
||||
}
|
||||
}
|
||||
group.resIds.add(data.resId);
|
||||
}
|
||||
|
||||
scheduledDateSimple(message) {
|
||||
return message.scheduledDate.toLocaleString(DateTime.TIME_SIMPLE, {
|
||||
locale: this.userService.lang?.replace("_", "-"),
|
||||
|
||||
@@ -38,13 +38,42 @@ export class NotificationGroup extends Record {
|
||||
// return reactive
|
||||
group = this.store.NotificationGroup.records.find((g) => g.eq(group));
|
||||
}
|
||||
this.env.services["mail.message"].updateNotificationGroup(group, data);
|
||||
group.update(data);
|
||||
if (group.notifications.length === 0) {
|
||||
removeFromArrayWithPredicate(this.records, (gr) => gr.eq(group));
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
Object.assign(this, {
|
||||
modelName: data.modelName ?? this.modelName,
|
||||
resModel: data.resModel ?? this.resModel,
|
||||
type: data.type ?? this.type,
|
||||
status: data.status ?? this.status,
|
||||
});
|
||||
const notifications = data.notifications ?? [];
|
||||
const alreadyKnownNotifications = new Set(this.notifications.map(({ id }) => id));
|
||||
const notificationIdsToRemove = new Set();
|
||||
for (const [commandName, notification] of notifications) {
|
||||
if (commandName === "insert" && !alreadyKnownNotifications.has(notification.id)) {
|
||||
this.notifications.push(notification);
|
||||
} else if (commandName === "insert-and-unlink") {
|
||||
notificationIdsToRemove.add(notification.id);
|
||||
}
|
||||
}
|
||||
this.notifications = this.notifications.filter(
|
||||
({ id }) => !notificationIdsToRemove.has(id)
|
||||
);
|
||||
this.lastMessage = this.notifications[0]?.message;
|
||||
for (const notification of this.notifications) {
|
||||
if (this.lastMessage?.id < notification.message?.id) {
|
||||
this.lastMessage = notification.message;
|
||||
}
|
||||
}
|
||||
this.resIds.add(data.resId);
|
||||
}
|
||||
|
||||
notifications = Record.many("Notification");
|
||||
/** @type {string} */
|
||||
modelName;
|
||||
|
||||
@@ -23,10 +23,38 @@ export class Notification extends Record {
|
||||
static insert(data) {
|
||||
const notification = this.get(data) ?? this.new(data);
|
||||
Object.assign(notification, { id: data.id });
|
||||
this.env.services["mail.message"].updateNotification(notification, data);
|
||||
notification.update(data);
|
||||
return notification;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
Object.assign(this, {
|
||||
message: data.message,
|
||||
notification_status: data.notification_status,
|
||||
notification_type: data.notification_type,
|
||||
failure_type: data.failure_type,
|
||||
persona: data.res_partner_id
|
||||
? this._store.Persona.insert({
|
||||
id: data.res_partner_id[0],
|
||||
displayName: data.res_partner_id[1],
|
||||
type: "partner",
|
||||
})
|
||||
: undefined,
|
||||
});
|
||||
if (!this.message.author?.eq(this._store.self)) {
|
||||
return;
|
||||
}
|
||||
const thread = this.message.originThread;
|
||||
this._store.NotificationGroup.insert({
|
||||
modelName: thread?.modelName,
|
||||
resId: thread?.id,
|
||||
resModel: thread?.model,
|
||||
status: this.notification_status,
|
||||
type: this.notification_type,
|
||||
notifications: [[this.isFailure ? "insert" : "insert-and-unlink", this]],
|
||||
});
|
||||
}
|
||||
|
||||
/** @type {number} */
|
||||
id;
|
||||
message = Record.one("Message");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { AND, Record } from "@mail/core/common/record";
|
||||
import { assignDefined, nullifyClearCommands } from "@mail/utils/common/misc";
|
||||
|
||||
/**
|
||||
* @typedef {'offline' | 'bot' | 'online' | 'away' | 'im_partner' | undefined} ImStatus
|
||||
@@ -30,11 +31,24 @@ export class Persona extends Record {
|
||||
*/
|
||||
static insert(data) {
|
||||
const persona = this.get(data) ?? this.new(data);
|
||||
this.env.services["mail.persona"].update(persona, data);
|
||||
persona.update(data);
|
||||
// return reactive version
|
||||
return persona;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
nullifyClearCommands(data);
|
||||
assignDefined(this, { ...data });
|
||||
if (
|
||||
this.type === "partner" &&
|
||||
this.im_status !== "im_partner" &&
|
||||
!this.is_public &&
|
||||
!this._store.registeredImStatusPartners?.includes(this.id)
|
||||
) {
|
||||
this._store.registeredImStatusPartners?.push(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {number} */
|
||||
id;
|
||||
/** @type {boolean | undefined} */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { assignDefined, nullifyClearCommands } from "@mail/utils/common/misc";
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useSequential } from "@mail/utils/common/hooks";
|
||||
import { markRaw } from "@odoo/owl";
|
||||
@@ -38,19 +36,6 @@ export class PersonaService {
|
||||
});
|
||||
}
|
||||
|
||||
update(persona, data) {
|
||||
nullifyClearCommands(data);
|
||||
assignDefined(persona, { ...data });
|
||||
if (
|
||||
persona.type === "partner" &&
|
||||
persona.im_status !== "im_partner" &&
|
||||
!persona.is_public &&
|
||||
!this.store.registeredImStatusPartners?.includes(persona.id)
|
||||
) {
|
||||
this.store.registeredImStatusPartners?.push(persona.id);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchIsCompany(persona) {
|
||||
if (persona.type !== "partner") {
|
||||
// non-partner persona are always considered as not a company
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import { AND, Record } from "@mail/core/common/record";
|
||||
import { ScrollPosition } from "@mail/core/common/scroll_position";
|
||||
import { onChange } from "@mail/utils/common/misc";
|
||||
import { replaceArrayWithCompare } from "@mail/utils/common/arrays";
|
||||
import { assignDefined, nullifyClearCommands, onChange } from "@mail/utils/common/misc";
|
||||
|
||||
import { deserializeDateTime } from "@web/core/l10n/dates";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
@@ -57,7 +58,7 @@ export class Thread extends Record {
|
||||
}
|
||||
let thread = this.get(data);
|
||||
if (thread) {
|
||||
this.env.services["mail.thread"].update(thread, data);
|
||||
thread.update(data);
|
||||
return thread;
|
||||
}
|
||||
thread = this.new(data);
|
||||
@@ -78,12 +79,142 @@ export class Thread extends Record {
|
||||
this.store.discuss.threadLocalId = null;
|
||||
}
|
||||
});
|
||||
this.env.services["mail.thread"].update(thread, data);
|
||||
thread.update(data);
|
||||
this.store.Composer.insert({ thread });
|
||||
// return reactive version.
|
||||
return thread;
|
||||
}
|
||||
|
||||
/** @param {Object} data */
|
||||
update(data) {
|
||||
const { id, name, attachments: attachmentsData, description, ...serverData } = data;
|
||||
assignDefined(this, { id, name, description });
|
||||
if (attachmentsData) {
|
||||
replaceArrayWithCompare(
|
||||
this.attachments,
|
||||
attachmentsData
|
||||
.map((attachmentData) => this._store.Attachment.insert(attachmentData))
|
||||
.sort((a1, a2) => a2.id - a1.id)
|
||||
);
|
||||
}
|
||||
if (serverData) {
|
||||
assignDefined(this, serverData, [
|
||||
"uuid",
|
||||
"authorizedGroupFullName",
|
||||
"description",
|
||||
"hasWriteAccess",
|
||||
"is_pinned",
|
||||
"isLoaded",
|
||||
"isLoadingAttachments",
|
||||
"mainAttachment",
|
||||
"message_unread_counter",
|
||||
"message_needaction_counter",
|
||||
"name",
|
||||
"seen_message_id",
|
||||
"state",
|
||||
"type",
|
||||
"status",
|
||||
"group_based_subscription",
|
||||
"last_interest_dt",
|
||||
"is_editable",
|
||||
"defaultDisplayMode",
|
||||
]);
|
||||
if (serverData.channel && "message_unread_counter" in serverData.channel) {
|
||||
this.message_unread_counter = serverData.channel.message_unread_counter;
|
||||
}
|
||||
const lastServerMessageId = serverData.last_message_id ?? this.lastServerMessage?.id;
|
||||
if (this.lastServerMessage?.id !== lastServerMessageId) {
|
||||
this.lastServerMessage = this._store.Message.insert({
|
||||
id: lastServerMessageId,
|
||||
});
|
||||
}
|
||||
if (this.model === "discuss.channel" && serverData.channel) {
|
||||
nullifyClearCommands(serverData.channel);
|
||||
this.channel = assignDefined(this.channel ?? {}, serverData.channel);
|
||||
}
|
||||
|
||||
this.memberCount = serverData.channel?.memberCount ?? this.memberCount;
|
||||
if (this.type === "chat" && serverData.channel) {
|
||||
this.customName = serverData.channel.custom_channel_name;
|
||||
}
|
||||
if (serverData.channel?.channelMembers) {
|
||||
for (const [command, membersData] of serverData.channel.channelMembers) {
|
||||
const members = Array.isArray(membersData) ? membersData : [membersData];
|
||||
for (const memberData of members) {
|
||||
const member = this._store.ChannelMember.insert([command, memberData]);
|
||||
if (this.type !== "chat") {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
member.persona.notEq(this._store.user) ||
|
||||
(serverData.channel.channelMembers[0][1].length === 1 &&
|
||||
member.persona?.eq(this._store.user))
|
||||
) {
|
||||
this.chatPartner = member.persona;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("invitedMembers" in serverData) {
|
||||
if (!serverData.invitedMembers) {
|
||||
this.invitedMemberIds.clear();
|
||||
return;
|
||||
}
|
||||
const command = serverData.invitedMembers[0][0];
|
||||
const members = serverData.invitedMembers[0][1];
|
||||
switch (command) {
|
||||
case "insert":
|
||||
if (members) {
|
||||
for (const member of members) {
|
||||
const record = this._store.ChannelMember.insert(member);
|
||||
this.invitedMemberIds.add(record.id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "unlink":
|
||||
case "insert-and-unlink":
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
for (const member of members) {
|
||||
this.invitedMemberIds.delete(member.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ("seen_partners_info" in serverData) {
|
||||
this.seenInfos = serverData.seen_partners_info.map(
|
||||
({ fetched_message_id, partner_id, seen_message_id }) => {
|
||||
return {
|
||||
lastFetchedMessage: fetched_message_id
|
||||
? this._store.Message.insert({ id: fetched_message_id })
|
||||
: undefined,
|
||||
lastSeenMessage: seen_message_id
|
||||
? this._store.Message.insert({ id: seen_message_id })
|
||||
: undefined,
|
||||
partner: this._store.Persona.insert({
|
||||
id: partner_id,
|
||||
type: "partner",
|
||||
}),
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
this.type === "channel" &&
|
||||
!this._store.discuss.channels.threads.includes(this.localId)
|
||||
) {
|
||||
this._store.discuss.channels.threads.push(this.localId);
|
||||
} else if (
|
||||
(this.type === "chat" || this.type === "group") &&
|
||||
!this._store.discuss.chats.threads.includes(this.localId)
|
||||
) {
|
||||
this._store.discuss.chats.threads.push(this.localId);
|
||||
}
|
||||
if (!this.type && !["mail.box", "discuss.channel"].includes(this.model)) {
|
||||
this.type = "chatter";
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {number} */
|
||||
id;
|
||||
/** @type {string} */
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
import { loadEmoji } from "@web/core/emoji_picker/emoji_picker";
|
||||
import { DEFAULT_AVATAR } from "@mail/core/common/persona_service";
|
||||
import { removeFromArray, replaceArrayWithCompare } from "@mail/utils/common/arrays";
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
import { prettifyMessageContent } from "@mail/utils/common/format";
|
||||
import { assignDefined, nullifyClearCommands } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
@@ -120,7 +119,7 @@ export class ThreadService {
|
||||
newUnreadCounter++;
|
||||
}
|
||||
}
|
||||
this.update(thread, {
|
||||
thread.update({
|
||||
seen_message_id: lastSeenId,
|
||||
message_needaction_counter: newNeedactionCounter,
|
||||
message_unread_counter: newUnreadCounter,
|
||||
@@ -203,7 +202,7 @@ export class ThreadService {
|
||||
Object.assign(data, { body: data.body ? markup(data.body) : data.body })
|
||||
);
|
||||
});
|
||||
this.update(thread, { isLoaded: true });
|
||||
thread.update({ isLoaded: true });
|
||||
return messages;
|
||||
} catch (e) {
|
||||
thread.hasLoadingFailed = true;
|
||||
@@ -663,140 +662,6 @@ export class ThreadService {
|
||||
thread.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Thread} thread
|
||||
* @param {Object} data
|
||||
*/
|
||||
update(thread, data) {
|
||||
const { id, name, attachments: attachmentsData, description, ...serverData } = data;
|
||||
assignDefined(thread, { id, name, description });
|
||||
if (attachmentsData) {
|
||||
replaceArrayWithCompare(
|
||||
thread.attachments,
|
||||
attachmentsData.map((attachmentData) =>
|
||||
this.store.Attachment.insert(attachmentData)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (serverData) {
|
||||
assignDefined(thread, serverData, [
|
||||
"uuid",
|
||||
"authorizedGroupFullName",
|
||||
"description",
|
||||
"hasWriteAccess",
|
||||
"is_pinned",
|
||||
"isLoaded",
|
||||
"isLoadingAttachments",
|
||||
"mainAttachment",
|
||||
"message_unread_counter",
|
||||
"message_needaction_counter",
|
||||
"name",
|
||||
"seen_message_id",
|
||||
"state",
|
||||
"type",
|
||||
"status",
|
||||
"group_based_subscription",
|
||||
"last_interest_dt",
|
||||
"is_editable",
|
||||
"defaultDisplayMode",
|
||||
]);
|
||||
if (serverData.channel && "message_unread_counter" in serverData.channel) {
|
||||
thread.message_unread_counter = serverData.channel.message_unread_counter;
|
||||
}
|
||||
const lastServerMessageId = serverData.last_message_id ?? thread.lastServerMessage?.id;
|
||||
if (thread.lastServerMessage?.id !== lastServerMessageId) {
|
||||
thread.lastServerMessage = this.store.Message.insert({
|
||||
id: lastServerMessageId,
|
||||
});
|
||||
}
|
||||
if (thread.model === "discuss.channel" && serverData.channel) {
|
||||
nullifyClearCommands(serverData.channel);
|
||||
thread.channel = assignDefined(thread.channel ?? {}, serverData.channel);
|
||||
}
|
||||
|
||||
thread.memberCount = serverData.channel?.memberCount ?? thread.memberCount;
|
||||
if (thread.type === "chat" && serverData.channel) {
|
||||
thread.customName = serverData.channel.custom_channel_name;
|
||||
}
|
||||
if (serverData.channel?.channelMembers) {
|
||||
for (const [command, membersData] of serverData.channel.channelMembers) {
|
||||
const members = Array.isArray(membersData) ? membersData : [membersData];
|
||||
for (const memberData of members) {
|
||||
const member = this.store.ChannelMember.insert([command, memberData]);
|
||||
if (thread.type !== "chat") {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
member.persona.notEq(thread._store.user) ||
|
||||
(serverData.channel.channelMembers[0][1].length === 1 &&
|
||||
member.persona?.eq(thread._store.user))
|
||||
) {
|
||||
thread.chatPartner = member.persona;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("invitedMembers" in serverData) {
|
||||
if (!serverData.invitedMembers) {
|
||||
thread.invitedMemberIds.clear();
|
||||
return;
|
||||
}
|
||||
const command = serverData.invitedMembers[0][0];
|
||||
const members = serverData.invitedMembers[0][1];
|
||||
switch (command) {
|
||||
case "insert":
|
||||
if (members) {
|
||||
for (const member of members) {
|
||||
const record = this.store.ChannelMember.insert(member);
|
||||
thread.invitedMemberIds.add(record.id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "unlink":
|
||||
case "insert-and-unlink":
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
for (const member of members) {
|
||||
thread.invitedMemberIds.delete(member.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ("seen_partners_info" in serverData) {
|
||||
thread.seenInfos = serverData.seen_partners_info.map(
|
||||
({ fetched_message_id, partner_id, seen_message_id }) => {
|
||||
return {
|
||||
lastFetchedMessage: fetched_message_id
|
||||
? this.store.Message.insert({ id: fetched_message_id })
|
||||
: undefined,
|
||||
lastSeenMessage: seen_message_id
|
||||
? this.store.Message.insert({ id: seen_message_id })
|
||||
: undefined,
|
||||
partner: this.store.Persona.insert({
|
||||
id: partner_id,
|
||||
type: "partner",
|
||||
}),
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
thread.type === "channel" &&
|
||||
!this.store.discuss.channels.threads.includes(thread.localId)
|
||||
) {
|
||||
this.store.discuss.channels.threads.push(thread.localId);
|
||||
} else if (
|
||||
(thread.type === "chat" || thread.type === "group") &&
|
||||
!this.store.discuss.chats.threads.includes(thread.localId)
|
||||
) {
|
||||
this.store.discuss.chats.threads.push(thread.localId);
|
||||
}
|
||||
if (!thread.type && !["mail.box", "discuss.channel"].includes(thread.model)) {
|
||||
thread.type = "chatter";
|
||||
}
|
||||
this.env.bus.trigger("mail.thread/onUpdate", { thread, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Thread} thread
|
||||
* @param {string} body
|
||||
|
||||
@@ -63,7 +63,7 @@ patch(ThreadService.prototype, {
|
||||
}
|
||||
}
|
||||
if ("attachments" in result) {
|
||||
this.update(thread, {
|
||||
thread.update({
|
||||
areAttachmentsLoaded: true,
|
||||
attachments: result.attachments,
|
||||
isLoadingAttachments: false,
|
||||
|
||||
@@ -141,9 +141,7 @@ export class CallParticipantCard extends Component {
|
||||
channel_id: this.props.thread.id,
|
||||
member_ids: [this.channelMember.id],
|
||||
});
|
||||
this.threadService.update(this.props.thread, {
|
||||
invitedMembers: channelData.invitedMembers,
|
||||
});
|
||||
this.props.thread.update({ invitedMembers: channelData.invitedMembers });
|
||||
}
|
||||
|
||||
async onClickReplay() {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { BlurManager } from "@mail/discuss/call/common/blur_manager";
|
||||
import { monitorAudio } from "@mail/discuss/call/common/media_monitoring";
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
import { closeStream, onChange } from "@mail/utils/common/misc";
|
||||
|
||||
import { reactive } from "@odoo/owl";
|
||||
@@ -158,9 +157,6 @@ export class Rtc {
|
||||
await this.resetAudioTrack({ force: true });
|
||||
}
|
||||
});
|
||||
this.env.bus.addEventListener("mail.thread/onUpdate", ({ detail: { thread, data } }) => {
|
||||
this.onThreadUpdate(thread, data);
|
||||
});
|
||||
this.env.bus.addEventListener(
|
||||
"RTC-SERVICE:UPDATE_RTC_SESSIONS",
|
||||
({ detail: { commands = [], record, thread } }) => {
|
||||
@@ -284,44 +280,6 @@ export class Rtc {
|
||||
);
|
||||
}
|
||||
|
||||
onThreadUpdate(thread, data) {
|
||||
if ("rtc_inviting_session" in data) {
|
||||
this.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread,
|
||||
record: data.rtc_inviting_session,
|
||||
});
|
||||
thread.rtcInvitingSession = this.store.RtcSession.insert({
|
||||
id: data.rtc_inviting_session.id,
|
||||
});
|
||||
if (!this.store.ringingThreads.includes(thread.localId)) {
|
||||
this.store.ringingThreads.push(thread.localId);
|
||||
}
|
||||
}
|
||||
if ("rtcInvitingSession" in data) {
|
||||
if (Array.isArray(data.rtcInvitingSession)) {
|
||||
if (data.rtcInvitingSession[0][0] === "unlink") {
|
||||
thread.rtcInvitingSession = undefined;
|
||||
removeFromArray(this.store.ringingThreads, thread.localId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread,
|
||||
record: data.rtcInvitingSession,
|
||||
});
|
||||
thread.rtcInvitingSession = this.store.RtcSession.insert({
|
||||
id: data.rtcInvitingSession.id,
|
||||
});
|
||||
this.store.ringingThreads.push(thread.localId);
|
||||
}
|
||||
if ("rtcSessions" in data) {
|
||||
this.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread,
|
||||
commands: data.rtcSessions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} id
|
||||
*/
|
||||
@@ -781,7 +739,7 @@ export class Rtc {
|
||||
this.notification.add(_t("Your browser does not support webRTC."), { type: "warning" });
|
||||
return;
|
||||
}
|
||||
const { rtcSessions, iceServers, sessionId, invitedMembers } = await this.rpc(
|
||||
const { rtcSessions, iceServers, sessionId } = await this.rpc(
|
||||
"/mail/rtc/channel/join_call",
|
||||
{
|
||||
channel_id: channel.id,
|
||||
@@ -795,7 +753,7 @@ export class Rtc {
|
||||
this.clear();
|
||||
this.state.logs.clear();
|
||||
this.state.channel = channel;
|
||||
this.onThreadUpdate(this.state.channel, { rtcSessions, invitedMembers });
|
||||
this.state.channel.update({ rtcSessions });
|
||||
this.state.selfSession = this.store.RtcSession.get(sessionId);
|
||||
this.state.iceServers = iceServers || DEFAULT_ICE_SERVERS;
|
||||
this.state.logs.set("channelId", this.state.channel?.id);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Thread } from "@mail/core/common/thread_model";
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Thread.prototype, {
|
||||
update(data) {
|
||||
super.update(data);
|
||||
if ("rtc_inviting_session" in data) {
|
||||
this.Model.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread: this,
|
||||
record: data.rtc_inviting_session,
|
||||
});
|
||||
this.rtcInvitingSession = this._store.RtcSession.insert({
|
||||
id: data.rtc_inviting_session.id,
|
||||
});
|
||||
if (!this._store.ringingThreads.includes(this.localId)) {
|
||||
this._store.ringingThreads.push(this.localId);
|
||||
}
|
||||
}
|
||||
if ("rtcInvitingSession" in data) {
|
||||
if (Array.isArray(data.rtcInvitingSession)) {
|
||||
if (data.rtcInvitingSession[0][0] === "unlink") {
|
||||
this.rtcInvitingSession = undefined;
|
||||
removeFromArray(this._store.ringingThreads, this.localId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.Model.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread: this,
|
||||
record: data.rtcInvitingSession,
|
||||
});
|
||||
this.rtcInvitingSession = this._store.RtcSession.insert({
|
||||
id: data.rtcInvitingSession.id,
|
||||
});
|
||||
this._store.ringingThreads.push(this.localId);
|
||||
}
|
||||
if ("rtcSessions" in data) {
|
||||
this.Model.env.bus.trigger("RTC-SERVICE:UPDATE_RTC_SESSIONS", {
|
||||
thread: this,
|
||||
commands: data.rtcSessions,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -49,7 +49,7 @@ export class DiscussCoreCommon {
|
||||
const { id, last_interest_dt } = payload;
|
||||
const channel = this.store.Thread.get({ model: "discuss.channel", id });
|
||||
if (channel) {
|
||||
this.threadService.update(channel, { last_interest_dt });
|
||||
channel.update({ last_interest_dt });
|
||||
if (channel.type !== "channel") {
|
||||
this.threadService.sortChannels();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,24 @@ patch(MessageModel.prototype, {
|
||||
/** @type {string} */
|
||||
this.pinnedAt = undefined;
|
||||
},
|
||||
update(data) {
|
||||
super.update(data);
|
||||
const { pinned_at: pinnedAt } = data;
|
||||
if (
|
||||
this.originThread?.model === "discuss.channel" &&
|
||||
(pinnedAt !== undefined || this.isEmpty)
|
||||
) {
|
||||
if (pinnedAt && !this.isEmpty) {
|
||||
if (this.notIn(this.originThread.pinnedMessages)) {
|
||||
this.originThread.pinnedMessages.push(this);
|
||||
}
|
||||
this.pinnedAt = pinnedAt;
|
||||
} else {
|
||||
delete this.pinnedAt;
|
||||
this.originThread.pinnedMessages.delete(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export class MessagePin {
|
||||
@@ -49,13 +67,6 @@ export class MessagePin {
|
||||
this.store = services["mail.store"];
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.env.bus.addEventListener("mail.message/onUpdate", ({ detail: { message, data } }) => {
|
||||
this.onMessageUpdate(message, data);
|
||||
});
|
||||
this.busService.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Thread} channel
|
||||
*/
|
||||
@@ -115,27 +126,6 @@ export class MessagePin {
|
||||
return this.getPinnedMessages(channel).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("models").Message}
|
||||
* @param {Object} data
|
||||
*/
|
||||
onMessageUpdate(message, { pinned_at: pinnedAt }) {
|
||||
if (
|
||||
message.originThread?.model === "discuss.channel" &&
|
||||
(pinnedAt !== undefined || message.isEmpty)
|
||||
) {
|
||||
if (pinnedAt && !message.isEmpty) {
|
||||
if (message.notIn(message.originThread.pinnedMessages)) {
|
||||
message.originThread.pinnedMessages.push(message);
|
||||
}
|
||||
message.pinnedAt = pinnedAt;
|
||||
} else {
|
||||
delete message.pinnedAt;
|
||||
message.originThread.pinnedMessages.delete(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for confirmation, then sets pinned to true.
|
||||
*
|
||||
@@ -196,7 +186,6 @@ export const messagePinService = {
|
||||
*/
|
||||
start(env, services) {
|
||||
const messagePin = reactive(new MessagePin(env, services));
|
||||
messagePin.setup();
|
||||
return messagePin;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,6 +4,12 @@ import { Attachment } from "@mail/core/common/attachment_model";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Attachment.prototype, {
|
||||
update(data) {
|
||||
super.update(...arguments);
|
||||
if (data["voice"]) {
|
||||
this.isVoice = true;
|
||||
}
|
||||
},
|
||||
get isViewable() {
|
||||
return !this.isVoice && super.isViewable;
|
||||
},
|
||||
|
||||
@@ -9,12 +9,6 @@ patch(AttachmentService.prototype, {
|
||||
/** @type {import("@mail/discuss/voice_message/common/voice_message_service").VoiceMessageService} */
|
||||
this.voiceMessageService = services["discuss.voice_message"];
|
||||
},
|
||||
update(attachment, data) {
|
||||
super.update(...arguments);
|
||||
if (data["voice"]) {
|
||||
attachment.isVoice = true;
|
||||
}
|
||||
},
|
||||
remove(attachment) {
|
||||
if (attachment.isVoice && attachment.id > 0) {
|
||||
this.voiceMessageService.activePlayer = null;
|
||||
|
||||
@@ -5,6 +5,22 @@ import { _t } from "@web/core/l10n/translation";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Persona.prototype, {
|
||||
update(data) {
|
||||
super.update(data);
|
||||
if (this.type === "visitor") {
|
||||
this.history = data.history ?? this.history;
|
||||
this.isConnected = data.is_connected ?? this.isConnected;
|
||||
this.im_status = this.isConnected ? "online" : undefined;
|
||||
this.langName = data.lang_name ?? this.langName;
|
||||
this.name = data.display_name ?? this.name;
|
||||
this.websiteName = data.website_name ?? this.websiteName;
|
||||
}
|
||||
if (data.country_id) {
|
||||
this.country = this.country ?? {};
|
||||
this.country.id = data.country_id;
|
||||
this.country.code = data.country_code ?? this.country.code;
|
||||
}
|
||||
},
|
||||
get countryFlagUrl() {
|
||||
const country = this.partner?.country ?? this.country;
|
||||
return country
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { PersonaService } from "@mail/core/common/persona_service";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(PersonaService.prototype, {
|
||||
update(persona, data) {
|
||||
super.update(persona, data);
|
||||
if (persona.type === "visitor") {
|
||||
persona.history = data.history ?? persona.history;
|
||||
persona.isConnected = data.is_connected ?? persona.isConnected;
|
||||
persona.im_status = persona.isConnected ? "online" : undefined;
|
||||
persona.langName = data.lang_name ?? persona.langName;
|
||||
persona.name = data.display_name ?? persona.name;
|
||||
persona.websiteName = data.website_name ?? persona.websiteName;
|
||||
}
|
||||
if (data.country_id) {
|
||||
persona.country = persona.country ?? {};
|
||||
persona.country.id = data.country_id;
|
||||
persona.country.code = data.country_code ?? persona.country.code;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Thread } from "@mail/core/common/thread_model";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Thread.prototype, {
|
||||
update(data) {
|
||||
super.update(data);
|
||||
if (data?.visitor) {
|
||||
this.visitor = this._store.Persona.insert({
|
||||
...data.visitor,
|
||||
type: "visitor",
|
||||
});
|
||||
}
|
||||
assignDefined(this, data, ["requested_by_operator"]);
|
||||
},
|
||||
});
|
||||
@@ -2,20 +2,9 @@
|
||||
|
||||
import { DEFAULT_AVATAR } from "@mail/core/common/persona_service";
|
||||
import { ThreadService } from "@mail/core/common/thread_service";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(ThreadService.prototype, {
|
||||
update(thread, data) {
|
||||
super.update(thread, data);
|
||||
if (data?.visitor) {
|
||||
thread.visitor = this.store.Persona.insert({
|
||||
...data.visitor,
|
||||
type: "visitor",
|
||||
});
|
||||
}
|
||||
assignDefined(thread, data, ["requested_by_operator"]);
|
||||
},
|
||||
/**
|
||||
* @param {import("models").Persona} persona
|
||||
* @param {import("models").Thread} [thread]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Thread } from "@mail/core/common/thread_model";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Thread.prototype, {
|
||||
update(data) {
|
||||
super.update(data);
|
||||
assignDefined(this, data, ["requested_by_operator"]);
|
||||
},
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { ThreadService } from "@mail/core/common/thread_service";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(ThreadService.prototype, {
|
||||
update(thread, data) {
|
||||
super.update(thread, data);
|
||||
assignDefined(thread, data, ["requested_by_operator"]);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user