[IMP] mail, *: remove this.async()
*: calendar, hr, snailmail Task-2837854 closes odoo/odoo#90230 Related: odoo/enterprise#26790 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -30,11 +30,14 @@ patchRecordMethods('Activity', {
|
||||
if (!this.calendar_event_id){
|
||||
await this._super();
|
||||
} else {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'unlink_w_meeting',
|
||||
args: [[this.id]],
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.delete();
|
||||
}
|
||||
},
|
||||
@@ -47,11 +50,11 @@ patchRecordMethods('Activity', {
|
||||
if (!this.calendar_event_id){
|
||||
this._super();
|
||||
} else {
|
||||
const action = await this.async(() => this.messaging.rpc({
|
||||
const action = await this.messaging.rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'action_create_calendar_event',
|
||||
args: [[this.id]],
|
||||
}));
|
||||
});
|
||||
this.env.bus.trigger('do-action', {
|
||||
action
|
||||
});
|
||||
|
||||
@@ -104,7 +104,10 @@ registerModel({
|
||||
*/
|
||||
async getChat() {
|
||||
if (!this.user && !this.hasCheckedUser) {
|
||||
await this.async(() => this.checkIsUser());
|
||||
await this.checkIsUser();
|
||||
}
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
// prevent chatting with non-users
|
||||
if (!this.user) {
|
||||
@@ -126,11 +129,17 @@ registerModel({
|
||||
* @returns {Thread|undefined}
|
||||
*/
|
||||
async openChat(options) {
|
||||
const chat = await this.async(() => this.getChat());
|
||||
const chat = await this.getChat();
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
if (!chat) {
|
||||
return;
|
||||
}
|
||||
await this.async(() => chat.open(options));
|
||||
await chat.open(options);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
return chat;
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -11,11 +11,14 @@ addRecordMethods('Partner', {
|
||||
* applicable.
|
||||
*/
|
||||
async checkIsEmployee() {
|
||||
await this.async(() => this.messaging.models['Employee'].performRpcSearchRead({
|
||||
await this.messaging.models['Employee'].performRpcSearchRead({
|
||||
context: { active_test: false },
|
||||
domain: [['user_partner_id', '=', this.id]],
|
||||
fields: ['user_id', 'user_partner_id'],
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({ hasCheckedEmployee: true });
|
||||
},
|
||||
});
|
||||
@@ -31,7 +34,10 @@ patchRecordMethods('Partner', {
|
||||
// limitation of patch, `this._super` becomes unavailable after `await`
|
||||
const _super = this._super.bind(this, ...arguments);
|
||||
if (!this.employee && !this.hasCheckedEmployee) {
|
||||
await this.async(() => this.checkIsEmployee());
|
||||
await this.checkIsEmployee();
|
||||
}
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
if (this.employee) {
|
||||
return this.employee.openProfile();
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
export class RecordDeletedError extends Error {
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {string} recordLocalId local id of record that has been deleted
|
||||
* @param {...any} args
|
||||
*/
|
||||
constructor(recordLocalId, ...args) {
|
||||
super(...args);
|
||||
this.recordLocalId = recordLocalId;
|
||||
this.name = 'RecordDeletedError';
|
||||
}
|
||||
}
|
||||
@@ -106,11 +106,14 @@ registerModel({
|
||||
* Delete the record from database and locally.
|
||||
*/
|
||||
async deleteServerRecord() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'unlink',
|
||||
args: [[this.id]],
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.delete();
|
||||
},
|
||||
/**
|
||||
@@ -167,7 +170,8 @@ registerModel({
|
||||
*/
|
||||
async markAsDone({ attachments = [], feedback = false }) {
|
||||
const attachmentIds = attachments.map(attachment => attachment.id);
|
||||
await this.async(() => this.messaging.rpc({
|
||||
const thread = this.thread;
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'action_feedback',
|
||||
args: [[this.id]],
|
||||
@@ -175,8 +179,13 @@ registerModel({
|
||||
attachment_ids: attachmentIds,
|
||||
feedback,
|
||||
},
|
||||
}));
|
||||
this.thread.fetchData(['attachments', 'messages']);
|
||||
});
|
||||
if (thread.exists()) {
|
||||
thread.fetchData(['attachments', 'messages']);
|
||||
}
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.delete();
|
||||
},
|
||||
/**
|
||||
@@ -185,15 +194,19 @@ registerModel({
|
||||
* @returns {Object}
|
||||
*/
|
||||
async markAsDoneAndScheduleNext({ feedback }) {
|
||||
const action = await this.async(() => this.messaging.rpc({
|
||||
const thread = this.thread;
|
||||
const action = await this.messaging.rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'action_feedback_schedule_next',
|
||||
args: [[this.id]],
|
||||
kwargs: { feedback },
|
||||
}));
|
||||
this.thread.fetchData(['activities', 'attachments', 'messages']);
|
||||
const thread = this.thread;
|
||||
this.delete();
|
||||
});
|
||||
if (thread.exists()) {
|
||||
thread.fetchData(['activities', 'attachments', 'messages']);
|
||||
}
|
||||
if (this.exists()) {
|
||||
this.delete();
|
||||
}
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
@@ -201,6 +214,9 @@ registerModel({
|
||||
action,
|
||||
options: {
|
||||
on_close: () => {
|
||||
if (!thread.exists()) {
|
||||
return;
|
||||
}
|
||||
thread.fetchData(['activities']);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -77,19 +77,24 @@ registerModel({
|
||||
if (!this.isUploading) {
|
||||
this.update({ isUnlinkPending: true });
|
||||
try {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
route: `/mail/attachment/delete`,
|
||||
params: {
|
||||
access_token: this.accessToken,
|
||||
attachment_id: this.id,
|
||||
},
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
} finally {
|
||||
this.update({ isUnlinkPending: false });
|
||||
if (this.exists()) {
|
||||
this.update({ isUnlinkPending: false });
|
||||
}
|
||||
}
|
||||
} else if (this.uploadingAbortController) {
|
||||
this.uploadingAbortController.abort();
|
||||
}
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.delete();
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -40,12 +40,14 @@ registerModel({
|
||||
* A smoother transfer would be moving the RTC sessions from one channel to
|
||||
* the other (server-side too), but it would be considerably more complex.
|
||||
*/
|
||||
await this.async(() => channel.toggleCall({
|
||||
await channel.toggleCall({
|
||||
startWithVideo: !!this.thread.rtc.videoTrack,
|
||||
videoType: this.thread.rtc.sendUserVideo ? 'user-video' : 'display',
|
||||
}));
|
||||
});
|
||||
}
|
||||
if (channel.exists()) {
|
||||
channel.open();
|
||||
}
|
||||
channel.open();
|
||||
} else {
|
||||
await this.messaging.rpc(({
|
||||
model: 'mail.channel',
|
||||
|
||||
@@ -1301,7 +1301,7 @@ registerModel({
|
||||
}
|
||||
const model = this.messaging.models[this.suggestionModelName];
|
||||
const searchTerm = this.suggestionSearchTerm;
|
||||
await this.async(() => model.fetchSuggestions(searchTerm, { thread: this.composer.activeThread }));
|
||||
await model.fetchSuggestions(searchTerm, { thread: this.composer.activeThread });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,12 +40,10 @@ registerModel({
|
||||
const name = this.addingChannelValue;
|
||||
this.clearIsAddingItem();
|
||||
if (ui.item.special) {
|
||||
const channel = await this.async(() =>
|
||||
this.messaging.models['Thread'].performRpcCreateChannel({
|
||||
name,
|
||||
privacy: ui.item.special === 'private' ? 'private' : 'groups',
|
||||
})
|
||||
);
|
||||
const channel = await this.messaging.models['Thread'].performRpcCreateChannel({
|
||||
name,
|
||||
privacy: ui.item.special === 'private' ? 'private' : 'groups',
|
||||
});
|
||||
channel.open();
|
||||
} else {
|
||||
const channel = this.messaging.models['Thread'].insert({
|
||||
|
||||
@@ -79,14 +79,19 @@ registerModel({
|
||||
async remove() {
|
||||
const partner_ids = [];
|
||||
partner_ids.push(this.partner.id);
|
||||
await this.async(() => this.messaging.rpc({
|
||||
const followedThread = this.followedThread;
|
||||
await this.messaging.rpc({
|
||||
model: this.followedThread.model,
|
||||
method: 'message_unsubscribe',
|
||||
args: [[this.followedThread.id], partner_ids]
|
||||
}));
|
||||
const followedThread = this.followedThread;
|
||||
});
|
||||
if (followedThread.exists()) {
|
||||
followedThread.fetchData(['suggestedRecipients']);
|
||||
}
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.delete();
|
||||
followedThread.fetchData(['suggestedRecipients']);
|
||||
},
|
||||
/**
|
||||
* @param {FollowerSubtype} subtype
|
||||
@@ -100,10 +105,13 @@ registerModel({
|
||||
* Show (editable) list of subtypes of this follower.
|
||||
*/
|
||||
async showSubtypes() {
|
||||
const subtypesData = await this.async(() => this.messaging.rpc({
|
||||
const subtypesData = await this.messaging.rpc({
|
||||
route: '/mail/read_subscription_data',
|
||||
params: { follower_id: this.id },
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({ subtypes: clear() });
|
||||
for (const data of subtypesData) {
|
||||
const subtype = this.messaging.models['FollowerSubtype'].insert(
|
||||
@@ -139,12 +147,15 @@ registerModel({
|
||||
if (this.partner) {
|
||||
kwargs.partner_ids = [this.partner.id];
|
||||
}
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: this.followedThread.model,
|
||||
method: 'message_subscribe',
|
||||
args: [[this.followedThread.id]],
|
||||
kwargs,
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.messaging.notify({
|
||||
type: 'success',
|
||||
message: this.env._t("The subscription preferences were successfully applied."),
|
||||
|
||||
@@ -38,12 +38,15 @@ registerModel({
|
||||
* @param {Activity} activity
|
||||
*/
|
||||
async send(activity) {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
const thread = activity.thread;
|
||||
await this.messaging.rpc({
|
||||
model: activity.thread.model,
|
||||
method: 'activity_send_mail',
|
||||
args: [[activity.thread.id], this.id],
|
||||
}));
|
||||
activity.thread.fetchData(['attachments', 'messages']);
|
||||
});
|
||||
if (thread.exists()) {
|
||||
thread.fetchData(['attachments', 'messages']);
|
||||
}
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
|
||||
@@ -223,11 +223,11 @@ registerModel({
|
||||
* partner Inbox.
|
||||
*/
|
||||
async markAsRead() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.message',
|
||||
method: 'set_message_done',
|
||||
args: [[this.id]]
|
||||
}));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Opens the view that allows to resend the message in case of failure.
|
||||
@@ -267,11 +267,11 @@ registerModel({
|
||||
* Toggle the starred status of the provided message.
|
||||
*/
|
||||
async toggleStar() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.message',
|
||||
method: 'toggle_message_starred',
|
||||
args: [[this.id]]
|
||||
}));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Updates the message's content.
|
||||
|
||||
@@ -80,11 +80,14 @@ registerModel({
|
||||
* @returns {Thread|undefined}
|
||||
*/
|
||||
async openChat(person, options) {
|
||||
const chat = await this.async(() => this.getChat(person));
|
||||
if (!chat) {
|
||||
const chat = await this.getChat(person);
|
||||
if (!this.exists() || !chat) {
|
||||
return;
|
||||
}
|
||||
await chat.open(options);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
await this.async(() => chat.open(options));
|
||||
return chat;
|
||||
},
|
||||
/**
|
||||
@@ -129,9 +132,11 @@ registerModel({
|
||||
if (model === 'mail.channel') {
|
||||
let channel = this.messaging.models['Thread'].findFromIdentifyingData({ id, model: 'mail.channel' });
|
||||
if (!channel) {
|
||||
channel = (await this.async(() =>
|
||||
this.messaging.models['Thread'].performRpcChannelInfo({ ids: [id] })
|
||||
))[0];
|
||||
const res = await this.messaging.models['Thread'].performRpcChannelInfo({ ids: [id] });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
channel = res[0];
|
||||
}
|
||||
if (!channel) {
|
||||
this.messaging.notify({
|
||||
|
||||
@@ -35,10 +35,16 @@ registerModel({
|
||||
});
|
||||
this.messaging.device.start();
|
||||
const discuss = this.messaging.discuss;
|
||||
const data = await this.async(() => this.messaging.rpc({
|
||||
const data = await this.messaging.rpc({
|
||||
route: '/mail/init_messaging',
|
||||
}, { shadow: true }));
|
||||
await this.async(() => this._init(data));
|
||||
}, { shadow: true });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
await this._init(data);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
if (discuss.discussView) {
|
||||
discuss.openInitThread();
|
||||
}
|
||||
@@ -110,7 +116,10 @@ registerModel({
|
||||
this._initCommands();
|
||||
}
|
||||
// channels when the rest of messaging is ready
|
||||
await this.async(() => this._initChannels(channels));
|
||||
await this._initChannels(channels);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
discuss.update({ menu_id });
|
||||
// company related data
|
||||
this.messaging.update({ companyName });
|
||||
|
||||
@@ -124,7 +124,7 @@ registerModel({
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.async(() => Promise.all(proms));
|
||||
await Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
* @abstract
|
||||
@@ -244,9 +244,11 @@ registerModel({
|
||||
// "required" by the rest of the code and is necessary for some
|
||||
// features such as chat windows.
|
||||
if (!channel) {
|
||||
channel = (await this.async(() =>
|
||||
this.messaging.models['Thread'].performRpcChannelInfo({ ids: [channelId] })
|
||||
))[0];
|
||||
const res = await this.messaging.models['Thread'].performRpcChannelInfo({ ids: [channelId] });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
channel = res[0];
|
||||
}
|
||||
if (!channel.isPinned) {
|
||||
channel.pin();
|
||||
@@ -656,8 +658,8 @@ registerModel({
|
||||
const message = sprintf(this.env._t('%s connected'), username);
|
||||
const title = this.env._t("This is their first connection. Wish them luck.");
|
||||
this.env.services['bus_service'].sendNotification({ message, title, type: 'info' });
|
||||
const chat = await this.async(() => this.messaging.getChat({ partnerId }));
|
||||
if (!chat || this.messaging.device.isSmall) {
|
||||
const chat = await this.messaging.getChat({ partnerId });
|
||||
if (!this.exists() || !chat || this.messaging.device.isSmall) {
|
||||
return;
|
||||
}
|
||||
this.messaging.chatWindowManager.openThread(chat);
|
||||
|
||||
@@ -299,14 +299,17 @@ registerModel({
|
||||
* applicable.
|
||||
*/
|
||||
async checkIsUser() {
|
||||
const userIds = await this.async(() => this.messaging.rpc({
|
||||
const userIds = await this.messaging.rpc({
|
||||
model: 'res.users',
|
||||
method: 'search',
|
||||
args: [[['partner_id', '=', this.id]]],
|
||||
kwargs: {
|
||||
context: { active_test: false },
|
||||
},
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({ hasCheckedUser: true });
|
||||
if (userIds.length > 0) {
|
||||
this.update({ user: insert({ id: userIds[0] }) });
|
||||
@@ -321,7 +324,10 @@ registerModel({
|
||||
*/
|
||||
async getChat() {
|
||||
if (!this.user && !this.hasCheckedUser) {
|
||||
await this.async(() => this.checkIsUser());
|
||||
await this.checkIsUser();
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// prevent chatting with non-users
|
||||
if (!this.user) {
|
||||
@@ -343,11 +349,14 @@ registerModel({
|
||||
* @returns {Thread|undefined}
|
||||
*/
|
||||
async openChat(options) {
|
||||
const chat = await this.async(() => this.getChat());
|
||||
if (!chat) {
|
||||
const chat = await this.getChat();
|
||||
if (!this.exists() || !chat) {
|
||||
return;
|
||||
}
|
||||
await chat.open(options);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
await this.async(() => chat.open(options));
|
||||
return chat;
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { RecordDeletedError } from '@mail/model/model_errors';
|
||||
import { one } from '@mail/model/model_field';
|
||||
import { insertAndReplace } from '@mail/model/model_field_command';
|
||||
|
||||
@@ -147,35 +146,6 @@ registerModel({
|
||||
},
|
||||
},
|
||||
recordMethods: {
|
||||
/**
|
||||
* Perform an async function and wait until it is done. If the record
|
||||
* is deleted, it raises a RecordDeletedError.
|
||||
*
|
||||
* @param {function} func an async function
|
||||
* @throws {RecordDeletedError} in case the current record is not alive
|
||||
* at the end of async function call, whether it's resolved or
|
||||
* rejected.
|
||||
* @throws {any} forwards any error in case the current record is still
|
||||
* alive at the end of rejected async function call.
|
||||
* @returns {any} result of resolved async function.
|
||||
*/
|
||||
async async(func) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Promise.resolve(func()).then(result => {
|
||||
if (this.exists()) {
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new RecordDeletedError(this.localId));
|
||||
}
|
||||
}).catch(error => {
|
||||
if (this.exists()) {
|
||||
reject(error);
|
||||
} else {
|
||||
reject(new RecordDeletedError(this.localId));
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* This method deletes this record.
|
||||
*/
|
||||
|
||||
@@ -263,14 +263,20 @@ registerModel({
|
||||
}
|
||||
audioTrack.addEventListener('ended', async () => {
|
||||
// this mostly happens when the user retracts microphone permission.
|
||||
await this.async(() => this.updateLocalAudioTrack(false));
|
||||
await this.updateLocalAudioTrack(false);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.currentRtcSession.updateAndBroadcast({ isSelfMuted: true });
|
||||
await this.async(() => this._updateLocalAudioTrackEnabledState());
|
||||
await this._updateLocalAudioTrackEnabledState();
|
||||
});
|
||||
this.currentRtcSession.updateAndBroadcast({ isSelfMuted: false });
|
||||
audioTrack.enabled = !this.currentRtcSession.isMute && this.currentRtcSession.isTalking;
|
||||
this.update({ audioTrack });
|
||||
await this.async(() => this.updateVoiceActivation());
|
||||
await this.updateVoiceActivation();
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
for (const rtcSession of this.connectedRtcSessions) {
|
||||
await this._updateRemoteTrack(rtcSession.rtcPeerConnection.peerConnection, 'audio', { token: rtcSession.id });
|
||||
}
|
||||
@@ -1014,9 +1020,7 @@ registerModel({
|
||||
const videoTrack = videoStream ? videoStream.getVideoTracks()[0] : undefined;
|
||||
if (videoTrack) {
|
||||
videoTrack.addEventListener('ended', async () => {
|
||||
await this.async(() =>
|
||||
this._toggleVideoBroadcast({ force: false, type })
|
||||
);
|
||||
await this._toggleVideoBroadcast({ force: false, type });
|
||||
});
|
||||
}
|
||||
this.update({
|
||||
|
||||
@@ -34,11 +34,11 @@ registerModel({
|
||||
*/
|
||||
this._currentPartnerInactiveTypingTimer = new Timer(
|
||||
this.messaging,
|
||||
() => this.async(() => {
|
||||
() => {
|
||||
if (this.messaging.currentPartner) {
|
||||
return this._onCurrentPartnerInactiveTypingTimeout();
|
||||
}
|
||||
}),
|
||||
},
|
||||
5 * 1000
|
||||
);
|
||||
/**
|
||||
@@ -67,7 +67,7 @@ registerModel({
|
||||
*/
|
||||
this._currentPartnerLongTypingTimer = new Timer(
|
||||
this.messaging,
|
||||
() => this.async(() => this._onCurrentPartnerLongTypingTimeout()),
|
||||
() => this._onCurrentPartnerLongTypingTimeout(),
|
||||
50 * 1000
|
||||
);
|
||||
/**
|
||||
@@ -104,7 +104,9 @@ registerModel({
|
||||
*/
|
||||
this._throttleNotifyCurrentPartnerTypingStatus = throttle(
|
||||
this.messaging,
|
||||
({ isTyping }) => this.async(() => this._notifyCurrentPartnerTypingStatus({ isTyping })),
|
||||
({ isTyping }) => {
|
||||
this._notifyCurrentPartnerTypingStatus({ isTyping });
|
||||
},
|
||||
2.5 * 1000
|
||||
);
|
||||
},
|
||||
@@ -669,24 +671,27 @@ registerModel({
|
||||
* Add current user to provided thread's followers.
|
||||
*/
|
||||
async follow() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: this.model,
|
||||
method: 'message_subscribe',
|
||||
args: [[this.id]],
|
||||
kwargs: {
|
||||
partner_ids: [this.messaging.currentPartner.id],
|
||||
},
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.fetchData(['followers', 'suggestedRecipients']);
|
||||
},
|
||||
/**
|
||||
* Performs the rpc to leave the rtc call of the channel.
|
||||
*/
|
||||
async performRpcLeaveCall() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
route: '/mail/rtc/channel/leave_call',
|
||||
params: { channel_id: this.id },
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
},
|
||||
/**
|
||||
* Leaves the current call if there is one, joins the call if the user was
|
||||
@@ -723,13 +728,13 @@ registerModel({
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { rtcSessions, iceServers, sessionId, invitedPartners, invitedGuests } = await this.async(() => this.messaging.rpc({
|
||||
const { rtcSessions, iceServers, sessionId, invitedPartners, invitedGuests } = await this.messaging.rpc({
|
||||
route: '/mail/rtc/channel/join_call',
|
||||
params: {
|
||||
channel_id: this.id,
|
||||
check_rtc_session_ids: this.rtcSessions.map(rtcSession => rtcSession.id),
|
||||
},
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
@@ -740,13 +745,16 @@ registerModel({
|
||||
invitedGuests,
|
||||
invitedPartners,
|
||||
});
|
||||
await this.async(() => this.messaging.rtc.initSession({
|
||||
await this.messaging.rtc.initSession({
|
||||
currentSessionId: sessionId,
|
||||
iceServers,
|
||||
startWithAudio: true,
|
||||
startWithVideo,
|
||||
videoType,
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.messaging.soundEffects.channelJoin.play();
|
||||
},
|
||||
/**
|
||||
@@ -810,11 +818,11 @@ registerModel({
|
||||
* Mark the specified conversation as fetched.
|
||||
*/
|
||||
async markAsFetched() {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.channel',
|
||||
method: 'channel_fetched',
|
||||
args: [[this.id]],
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
},
|
||||
/**
|
||||
* Mark the specified conversation as read/seen.
|
||||
@@ -847,9 +855,7 @@ registerModel({
|
||||
* Marks as read all needaction messages with this thread as origin.
|
||||
*/
|
||||
async markNeedactionMessagesAsOriginThreadAsRead() {
|
||||
await this.async(() =>
|
||||
this.messaging.models['Message'].markAsRead(this.needactionMessagesAsOriginThread)
|
||||
);
|
||||
await this.messaging.models['Message'].markAsRead(this.needactionMessagesAsOriginThread);
|
||||
},
|
||||
/**
|
||||
* Notifies the server of new fold state. Useful for initial,
|
||||
@@ -1007,7 +1013,7 @@ registerModel({
|
||||
registerOtherMemberTypingMember(partner) {
|
||||
const timer = new Timer(
|
||||
this.messaging,
|
||||
() => this.async(() => this._onOtherMemberLongTypingTimeout(partner)),
|
||||
() => this._onOtherMemberLongTypingTimeout(partner),
|
||||
60 * 1000
|
||||
);
|
||||
this._otherMembersLongTypingTimers.set(partner, timer);
|
||||
@@ -1057,7 +1063,7 @@ registerModel({
|
||||
const currentPartnerFollower = this.followers.find(
|
||||
follower => follower.partner === this.messaging.currentPartner
|
||||
);
|
||||
await this.async(() => currentPartnerFollower.remove());
|
||||
await currentPartnerFollower.remove();
|
||||
},
|
||||
/**
|
||||
* Unpin this thread and notify server of the change.
|
||||
@@ -1096,9 +1102,7 @@ registerModel({
|
||||
if (immediateNotify) {
|
||||
this._throttleNotifyCurrentPartnerTypingStatus.clear();
|
||||
}
|
||||
await this.async(
|
||||
() => this._throttleNotifyCurrentPartnerTypingStatus({ isTyping: false })
|
||||
);
|
||||
await this._throttleNotifyCurrentPartnerTypingStatus({ isTyping: false });
|
||||
},
|
||||
/**
|
||||
* Called to unregister an other member partner that is no longer typing
|
||||
@@ -1694,12 +1698,15 @@ registerModel({
|
||||
isTyping !== this._currentPartnerLastNotifiedIsTyping
|
||||
) {
|
||||
if (this.model === 'mail.channel') {
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.channel',
|
||||
method: 'notify_typing',
|
||||
args: [this.id],
|
||||
kwargs: { is_typing: isTyping },
|
||||
}, { shadow: true }));
|
||||
}, { shadow: true });
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isTyping && this._currentPartnerLongTypingTimer.isRunning) {
|
||||
this._currentPartnerLongTypingTimer.reset();
|
||||
@@ -1773,8 +1780,11 @@ registerModel({
|
||||
action,
|
||||
options: {
|
||||
on_close: async () => {
|
||||
await this.async(() => this.fetchData(['followers']));
|
||||
this.env.bus.trigger('Thread:promptAddFollower-closed');
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
await this.fetchData(['followers']);
|
||||
this.env.bus.trigger('Thread:promptAddFollower-closed');
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1841,7 +1851,7 @@ registerModel({
|
||||
* @private
|
||||
*/
|
||||
async _onCurrentPartnerInactiveTypingTimeout() {
|
||||
await this.async(() => this.unregisterCurrentPartnerIsTyping());
|
||||
await this.unregisterCurrentPartnerIsTyping();
|
||||
},
|
||||
/**
|
||||
* Called when current partner has been typing for a very long time.
|
||||
@@ -1852,9 +1862,7 @@ registerModel({
|
||||
async _onCurrentPartnerLongTypingTimeout() {
|
||||
this._forceNotifyNextCurrentPartnerTypingStatus = true;
|
||||
this._throttleNotifyCurrentPartnerTypingStatus.clear();
|
||||
await this.async(
|
||||
() => this._throttleNotifyCurrentPartnerTypingStatus({ isTyping: true })
|
||||
);
|
||||
await this._throttleNotifyCurrentPartnerTypingStatus({ isTyping: true });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { RecordDeletedError } from '@mail/model/model_errors';
|
||||
import { attr, many, one } from '@mail/model/model_field';
|
||||
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
|
||||
import { OnChange } from '@mail/model/model_onchange';
|
||||
@@ -240,12 +239,7 @@ registerModel({
|
||||
if (this.messaging.currentGuest) {
|
||||
return;
|
||||
}
|
||||
this.thread.markAsSeen(this.thread.lastNonTransientMessage).catch(e => {
|
||||
// prevent crash when executing compute during destroy
|
||||
if (!(e instanceof RecordDeletedError)) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
this.thread.markAsSeen(this.thread.lastNonTransientMessage);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -275,11 +269,13 @@ registerModel({
|
||||
if (this.threadCache && this.threadCache.isLoading) {
|
||||
if (!this.isLoading && !this.isPreparingLoading) {
|
||||
this.update({ isPreparingLoading: true });
|
||||
this.async(() =>
|
||||
new Promise(resolve => {
|
||||
(new Promise(resolve => {
|
||||
this.update({ loaderTimeout: this.messaging.browser.setTimeout(resolve, this.messaging.loadingBaseDelayDuration) });
|
||||
}
|
||||
)).then(() => {
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
const isLoading = this.threadCache
|
||||
? this.threadCache.isLoading
|
||||
: false;
|
||||
|
||||
@@ -74,7 +74,10 @@ registerModel({
|
||||
*/
|
||||
async getChat() {
|
||||
if (!this.partner) {
|
||||
await this.async(() => this.fetchPartner());
|
||||
await this.fetchPartner();
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!this.partner) {
|
||||
// This user has been deleted from the server or never existed:
|
||||
@@ -97,11 +100,12 @@ registerModel({
|
||||
if (!chat || !chat.isPinned) {
|
||||
// if chat is not pinned then it has to be pinned client-side
|
||||
// and server-side, which is a side effect of following rpc
|
||||
chat = await this.async(() =>
|
||||
this.messaging.models['Thread'].performRpcCreateChat({
|
||||
partnerIds: [this.partner.id],
|
||||
})
|
||||
);
|
||||
chat = await this.messaging.models['Thread'].performRpcCreateChat({
|
||||
partnerIds: [this.partner.id],
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!chat) {
|
||||
this.messaging.notify({
|
||||
@@ -121,11 +125,14 @@ registerModel({
|
||||
* @returns {Thread|undefined}
|
||||
*/
|
||||
async openChat(options) {
|
||||
const chat = await this.async(() => this.getChat());
|
||||
if (!chat) {
|
||||
const chat = await this.getChat();
|
||||
if (!this.exists() || !chat) {
|
||||
return;
|
||||
}
|
||||
await chat.open(options);
|
||||
if (!this.exists() || !chat.exists()) {
|
||||
return;
|
||||
}
|
||||
await this.async(() => chat.open(options));
|
||||
return chat;
|
||||
},
|
||||
/**
|
||||
@@ -137,7 +144,10 @@ registerModel({
|
||||
*/
|
||||
async openProfile() {
|
||||
if (!this.partner) {
|
||||
await this.async(() => this.fetchPartner());
|
||||
await this.fetchPartner();
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!this.partner) {
|
||||
// This user has been deleted from the server or never existed:
|
||||
|
||||
@@ -12,11 +12,11 @@ addRecordMethods('Message', {
|
||||
*/
|
||||
async cancelLetter() {
|
||||
// the result will come from longpolling: message_notification_update
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.message',
|
||||
method: 'cancel_letter',
|
||||
args: [[this.id]],
|
||||
}));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Opens the action about 'snailmail.letter' format error.
|
||||
@@ -35,11 +35,11 @@ addRecordMethods('Message', {
|
||||
* Opens the action about 'snailmail.letter' missing fields.
|
||||
*/
|
||||
async openMissingFieldsLetterAction() {
|
||||
const letterIds = await this.async(() => this.messaging.rpc({
|
||||
const letterIds = await this.messaging.rpc({
|
||||
model: 'snailmail.letter',
|
||||
method: 'search',
|
||||
args: [[['message_id', '=', this.id]]],
|
||||
}));
|
||||
});
|
||||
this.env.bus.trigger('do-action', {
|
||||
action: 'snailmail.snailmail_letter_missing_required_fields_action',
|
||||
options: {
|
||||
@@ -54,10 +54,10 @@ addRecordMethods('Message', {
|
||||
*/
|
||||
async resendLetter() {
|
||||
// the result will come from longpolling: message_notification_update
|
||||
await this.async(() => this.messaging.rpc({
|
||||
await this.messaging.rpc({
|
||||
model: 'mail.message',
|
||||
method: 'send_letter',
|
||||
args: [[this.id]],
|
||||
}));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,21 +7,27 @@ import '@mail/models/messaging';
|
||||
|
||||
addRecordMethods('Messaging', {
|
||||
async fetchSnailmailCreditsUrl() {
|
||||
const snailmail_credits_url = await this.async(() => this.messaging.rpc({
|
||||
const snailmail_credits_url = await this.messaging.rpc({
|
||||
model: 'iap.account',
|
||||
method: 'get_credits_url',
|
||||
args: ['snailmail'],
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({
|
||||
snailmail_credits_url,
|
||||
});
|
||||
},
|
||||
async fetchSnailmailCreditsUrlTrial() {
|
||||
const snailmail_credits_url_trial = await this.async(() => this.messaging.rpc({
|
||||
const snailmail_credits_url_trial = await this.messaging.rpc({
|
||||
model: 'iap.account',
|
||||
method: 'get_credits_url',
|
||||
args: ['snailmail', '', 0, true],
|
||||
}));
|
||||
});
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({
|
||||
snailmail_credits_url_trial,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user