[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:
Alexandre Kühn
2022-05-04 15:38:25 +02:00
parent 1ff279f11c
commit 23962f3d4b
23 changed files with 237 additions and 180 deletions
@@ -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
});
+12 -3
View File
@@ -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;
},
/**
+9 -3
View File
@@ -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';
}
}
+26 -10
View File
@@ -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']);
},
},
+8 -3
View File
@@ -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;
}
+4 -6
View File
@@ -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({
+19 -8
View File
@@ -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: {
+4 -4
View File
@@ -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.
+11 -6
View File
@@ -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);
+15 -6
View File
@@ -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;
},
/**
-30
View File
@@ -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.
*/
+10 -6
View File
@@ -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({
+38 -30
View File
@@ -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
+5 -9
View File
@@ -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;
+20 -10
View File
@@ -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,
});