social/mail_tracking/static/src/js/failed_message/discuss.js

406 lines
14 KiB
JavaScript

/* Copyright 2019 Alexandre Díaz
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
odoo.define("mail_tracking.FailedMessageDiscuss", function(require) {
"use strict";
// To be considered:
// - One message can be displayed in many threads
// - A thread can be a mailbox, channel, ...
// - A mailbox is a type of thread that is displayed on top of
// the discuss menu, has a counter, etc...
var MailManagerNotif = require("mail.Manager.Notification");
var AbstractMessage = require("mail.model.AbstractMessage");
var Message = require("mail.model.Message");
var Discuss = require("mail.Discuss");
var MailManager = require("mail.Manager");
var Mailbox = require("mail.model.Mailbox");
var core = require("web.core");
var session = require("web.session");
var QWeb = core.qweb;
var _t = core._t;
/* The states to consider a message as failed message */
var FAILED_STATES = ["error", "rejected", "spam", "bounced", "soft-bounced"];
AbstractMessage.include({
/**
* Abstract declaration to know if a message is included in the
* failed mailbox. By default it should be false.
*
* @returns {Boolean}
*/
isFailed: function() {
return false;
},
});
Message.include({
/**
* Overrides to store information from server
*
* @override
*/
init: function(parent, data) {
this._isFailedMessage = data.is_failed_message;
return this._super.apply(this, arguments);
},
/**
* Implementation to know if a message is included in the
* failed mailbox.
*
* @override
*/
isFailed: function() {
return _.contains(this._threadIDs, "mailbox_failed");
},
/**
* Adds/Removes message to/from failed mailbox
*
* @param {Boolean} failed
*/
setFailed: function(failed) {
if (failed) {
this._addThread("mailbox_failed");
} else {
this.removeThread("mailbox_failed");
}
},
/**
* Include the message in the 'failed' mailbox if needed
*
* @override
*/
_processMailboxes: function() {
this.setFailed(this._isFailedMessage);
return this._super.apply(this, arguments);
},
});
MailManagerNotif.include({
/**
* Overrides to handle changes in the 'mail_tracking_needs_action' flag
*
* @override
*/
_handlePartnerNotification: function(data) {
if (data.type === "toggle_tracking_status") {
this._handleChangeTrackingNeedsActionNotification(data);
} else {
// Workaround to avoid call '_handlePartnerChannelNotification'
// because this is related with the failed mailbox, not a
// channel.
this._super.apply(this, arguments);
}
},
/**
* This method updates messages in the failed mailbox when the flag
* 'mail_tracking_needs_action' was changed to False. This can
* remove/add the message from/to failed mailbox and update mailbox
* counter.
*
* @private
* @param {Object} data
*/
_handleChangeTrackingNeedsActionNotification: function(data) {
var self = this;
var failed = this.getMailbox("failed");
_.each(data.message_ids, function(messageID) {
var message = _.find(self._messages, function(msg) {
return msg.getID() === messageID;
});
if (message) {
message.setFailed(data.needs_actions);
if (message.isFailed() === false) {
self._removeMessageFromThread("mailbox_failed", message);
} else {
self._addMessageToThreads(message, []);
var channelFailed = self.getMailbox("failed");
channelFailed.invalidateCaches();
}
self._mailBus.trigger("update_message", message, data.type);
}
});
if (data.needs_actions) {
// Increase failed counter if message is marked as failed
failed.incrementMailboxCounter(data.message_ids.length);
} else {
// Decrease failed counter if message is removed from failed
failed.decrementMailboxCounter(data.message_ids.length);
}
// Trigger event to refresh threads
this._mailBus.trigger("update_failed", failed.getMailboxCounter());
},
});
Discuss.include({
events: _.extend({}, Discuss.prototype.events, {
"click .o_failed_message_retry": "_onRetryFailedMessage",
"click .o_failed_message_reviewed": "_onMarkFailedMessageReviewed",
}),
/**
* Paramaters used to render 'failed' mailbox entry in Discuss
*
* @private
* @returns {Object}
*/
_sidebarQWebParams: function() {
var failed = this.call("mail_service", "getMailbox", "failed");
return {
activeThreadID: this._thread ? this._thread.getID() : undefined,
failedCounter: failed.getMailboxCounter(),
};
},
/**
* Render 'failed' mailbox menu entry in Discuss
* - Initial render
*
* @override
*/
_renderSidebar: function() {
var $sidebar = this._super.apply(this, arguments);
// Because Odoo implementation isn't designed to be inherited
// properly, we inject 'failed' button using jQuery.
var $failed_item = $(
QWeb.render("mail_tracking.SidebarFailed", this._sidebarQWebParams())
);
$failed_item.insertAfter(
$sidebar.find(".o_mail_discuss_title_main").filter(":last")
);
return $sidebar;
},
/**
* Render 'failed' mailbox menu entry in Discuss
* - Update status render (not called if the mailbox is empty)
*
* @override
*/
_renderSidebarMailboxes: function() {
this._super.apply(this, arguments);
this.$(".o_mail_discuss_sidebar_mailboxes").append(
QWeb.render("mail_tracking.SidebarFailed", this._sidebarQWebParams())
);
},
/**
* Overrides to listen click on 'Set all as reviewed' button
*
* @override
*/
_renderButtons: function() {
this._super.apply(this, arguments);
this.$btn_set_all_reviewed = this.$buttons.find(
".o_mail_discuss_button_set_all_reviewed"
);
this.$btn_set_all_reviewed.on(
"click",
$.proxy(this, "_onSetAllAsReviewedClicked")
);
},
/**
* Show or hide 'set all as reviewed' button in discuss mailbox
*
* This means in which thread the button should be displayed.
*
* @override
*/
_updateControlPanelButtons: function(thread) {
this.$btn_set_all_reviewed.toggleClass(
"d-none d-md-none",
thread.getID() !== "mailbox_failed"
);
return this._super.apply(this, arguments);
},
/**
* Overrides to update 'set all as reviewed' button.
*
* Disabled button if doesn't have more failed messages
*
* @override
*/
_updateButtonStatus: function(disabled, type) {
if (this._thread.getID() === "mailbox_failed") {
this.$btn_set_all_reviewed.toggleClass("disabled", disabled);
// Display Rainbowman when all failed messages are reviewed
// through 'TOGGLE TRACKING STATUS' or marking last failed
// message as reviewed
if (disabled && type === "toggle_tracking_status") {
this.trigger_up("show_effect", {
message: _t("Congratulations, your failed mailbox is empty"),
type: "rainbow_man",
});
}
}
},
/**
* Overrides to update messages in 'failed' mailbox thread
*
* @override
*/
_onMessageUpdated: function(message, type) {
var self = this;
var currentThreadID = this._thread.getID();
if (currentThreadID === "mailbox_failed" && !message.isFailed()) {
this._thread.fetchMessages(this.domain).then(function() {
var options = self._getThreadRenderingOptions();
self._threadWidget
.removeMessageAndRender(message.getID(), self._thread, options)
.then(function() {
self._updateButtonStatus(!self._thread.hasMessages(), type);
});
});
} else {
// Workaround to avoid calling '_fetchAndRenderThread' and
// refetching thread messages because these messages are
// actually fetched above.
this._super.apply(this, arguments);
}
},
/**
* Hide reply feature in the 'failed' mailbox, where it has no sense.
* Show instead 'Retry' and 'Set as reviewed' buttons.
*
* @override
*/
_getThreadRenderingOptions: function() {
var values = this._super.apply(this, arguments);
if (this._thread.getID() === "mailbox_failed") {
values.displayEmailIcons = true;
values.displayReplyIcons = false;
values.displayRetryButton = true;
values.displayReviewedButton = true;
}
return values;
},
/**
* Listen also to the event that refreshes thread messages
*
* @override
*/
_startListening: function() {
this._super.apply(this, arguments);
this.call("mail_service", "getMailBus").on(
"update_failed",
this,
this._throttledUpdateThreads
);
},
// Handlers
/**
* Open the resend mail.resend.message wizard
*
* @private
* @param {Event} event
*/
_onRetryFailedMessage: function(event) {
event.preventDefault();
var messageID = $(event.currentTarget).data("message-id");
this.do_action("mail.mail_resend_message_action", {
additional_context: {
mail_message_to_resend: messageID,
},
});
},
/**
* Toggle 'mail_tracking_needs_action' flag
*
* @private
* @param {Event} event
* @returns {Promise}
*/
_onMarkFailedMessageReviewed: function(event) {
event.preventDefault();
var messageID = $(event.currentTarget).data("message-id");
return this._rpc({
model: "mail.message",
method: "set_need_action_done",
args: [[messageID]],
context: this.getSession().user_context,
});
},
/**
* Inheritable method that call thread implementation
*
* @private
*/
_onSetAllAsReviewedClicked: function() {
this._thread.setAllMessagesAsReviewed();
},
});
MailManager.include({
/**
* Add the 'failed' mailbox
*
* @override
*/
_updateMailboxesFromServer: function(data) {
this._super.apply(this, arguments);
this._addMailbox({
id: "failed",
name: _t("Failed"),
mailboxCounter: data.failed_counter || 0,
});
},
});
Mailbox.include({
/**
* Overrides to add domain for 'failed' mailbox thread
*
* @override
*/
_getThreadDomain: function() {
if (this._id === "mailbox_failed") {
return [
["mail_tracking_ids.state", "in", FAILED_STATES],
["mail_tracking_needs_action", "=", true],
"|",
["partner_ids", "in", [session.partner_id]],
["author_id", "=", session.partner_id],
];
}
// Workaround to avoid throw 'Missing domain' exception. Call _super
// without a valid (hard-coded) thread id causes that exeception.
return this._super.apply(this, arguments);
},
/**
* Sets all messages from the mailbox as reviewed.
*
* At the moment, this method makes only sense for 'Failed'.
*
* @returns {$.Promise} resolved when all messages have been marked as
* reviewed on the server
*/
setAllMessagesAsReviewed: function() {
if (this._id === "mailbox_failed" && this.getMailboxCounter() > 0) {
return this._rpc({
model: "mail.message",
method: "set_all_as_reviewed",
});
}
return $.when();
},
});
});