summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js/models/threads/document_thread.js
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2018-07-04 13:44:49 +0200
committerAlexandre Kühn <aku@odoo.com>2018-07-19 13:58:34 +0200
commitcb7add2ebd50c1981e35bb12a3e52a69a58bc05f (patch)
treebc3cd295adaf8113b0fc24c19834c685b46d3ea6 /addons/mail/static/src/js/models/threads/document_thread.js
parent12f4f9a51d1cadc4c0dcdefc46a653e78b46f53f (diff)
[MOV] mail: move thread models in specific folder for thread models
The `model` folder contains several files, so this groups files related to threads directly.
Diffstat (limited to 'addons/mail/static/src/js/models/threads/document_thread.js')
-rw-r--r--addons/mail/static/src/js/models/threads/document_thread.js317
1 files changed, 317 insertions, 0 deletions
diff --git a/addons/mail/static/src/js/models/threads/document_thread.js b/addons/mail/static/src/js/models/threads/document_thread.js
new file mode 100644
index 00000000000..92cc26e845b
--- /dev/null
+++ b/addons/mail/static/src/js/models/threads/document_thread.js
@@ -0,0 +1,317 @@
+odoo.define('mail.model.DocumentThread', function (require) {
+"use strict";
+
+var Thread = require('mail.model.Thread');
+
+var session = require('web.session');
+
+/**
+ * These threads represent threads that are directly attached to documents.
+ * It is sometimes called the "chatter", but technically this is just the
+ * part of the chatter containing the thread, as the chatter also contains
+ * the activity and listener fields.
+ *
+ * Note that there are still some hacks in the handling of document threads,
+ * due to document threads are instantiated from fetched messages, either from
+ * mail.ThreadField or by fetching messages in Inbox.
+ *
+ * Also, because messages are not sent on the longpoll bus for this kind of
+ * threads, it stores the list of message IDs that it contains, which should
+ * be up-to-date whenever someone wants to get the messages in the document
+ * thread.
+ */
+var DocumentThread = Thread.extend({
+
+ /**
+ * @override
+ * @param {string} [data.messagesIDs] the list of message ids linked
+ * to the document (if not given, they will be fetched before fetching the
+ * messages)
+ * @param {string} data.model
+ * @param {integer} data.resID
+ */
+ init: function (parent, data) {
+ data.id = data.resModel + '_' + data.resID;
+ data.type = 'document_thread';
+
+ this._super.apply(this, arguments);
+
+ // ID of the related document
+ this._documentID = data.resID;
+ // model of the related document
+ this._documentModel = data.resModel;
+ // used to handle history of messages
+ this._messageIDs = data.messageIDs || [];
+ // list of loaded messages
+ this._messages = [];
+
+ // if the messageIDs haven't been given, fetch them before fetching the
+ // messages
+ this._mustFetchMessageIDs = !_.isArray(data.messageIDs);
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * Add this message to this document thread.
+ *
+ * @override
+ * @param {mail.model.Message} message
+ */
+ addMessage: function (message) {
+ // update internal list of messages
+ this._messages.push(message);
+ this._messages = _.sortBy(this._messages, function (msg) {
+ return msg.getID();
+ });
+ // update message ids associated to this document thread
+ if (!_.contains(this._messageIDs, message.getID())) {
+ this._messageIDs.push(message.getID());
+ }
+ },
+ /**
+ * Overrides to store the thread's state in the LocalStorage, so that it is
+ * shared between tabs, and restored on F5.
+ *
+ * @override
+ */
+ close: function () {
+ this._super.apply(this, arguments);
+ this.call('mail_service', 'updateDocumentThreadState', this._id, {
+ name: this.getName(),
+ windowState: 'closed',
+ });
+ },
+ /**
+ * Overrides to store the thread's state in the LocalStorage, so that it is
+ * shared between tabs, and restored on F5.
+ *
+ * @override
+ */
+ detach: function () {
+ this._super.apply(this, arguments);
+ var windowState = this._folded ? 'folded' : 'open';
+ this.call('mail_service', 'updateDocumentThreadState', this._id, {
+ name: this.getName(),
+ windowState: windowState,
+ });
+ },
+ /**
+ * Overrides to store the thread's state in the LocalStorage, so that it is
+ * shared between tabs, and restored on F5.
+ *
+ * @override
+ */
+ fold: function () {
+ this._super.apply(this, arguments);
+ var windowState = this._folded ? 'folded' : 'open';
+ this.call('mail_service', 'updateDocumentThreadState', this._id, {
+ name: this.getName(),
+ windowState: windowState,
+ });
+ },
+ /**
+ * Get the model name of the document that is linked to this document thread
+ *
+ * @returns {string}
+ */
+ getDocumentModel: function () {
+ return this._documentModel;
+ },
+ /**
+ * Get the ID of the document that is linked to this document thread
+ *
+ * @returns {integer}
+ */
+ getDocumentID: function () {
+ return this._documentID;
+ },
+ /**
+ * Get he list of message IDs that this document threads contain.
+ *
+ * @returns {integer[]}
+ */
+ getMessageIDs: function () {
+ return this._messageIDs;
+ },
+ /**
+ *
+ * Get messages of the document thread
+ *
+ * @override
+ * @param {Object} options
+ * @param {boolean} [options.forceFetch] if true, fetch anyway, as user
+ * clicked on 'load more'.
+ * @returns {$.Promise<mail.model.Message[]>}
+ */
+ getMessages: function (options) {
+ var self = this;
+ return this._fetchMessages(options).then(function () {
+ self.call('mail_service', 'markMessagesAsRead', self._messageIDs);
+ return self._messages;
+ });
+ },
+ /**
+ * States whether the thread is linked to a document
+ * Document thread's are always linked to a document.
+ *
+ * @override
+ * @returns {boolean}
+ */
+ isLinkedToDocument: function () {
+ return true;
+ },
+ /**
+ * Overrides this method so that all the messages of this document thread
+ * are marked as read on the server.
+ *
+ * @override
+ * @returns {$.Promise} resolved when messages have been marked as read on
+ * the server.
+ */
+ markAsRead: function () {
+ this._super.apply(this, arguments);
+ return this.call('mail_service', 'markMessagesAsRead', this._messageIDs);
+ },
+ /**
+ * Post message for document thread
+ *
+ * @override
+ * @param {Object} data data related to the new message
+ * @return {$.Promise<Object>} resolved when the message has been sent to
+ * the server, with the object message that has been sent to the server.
+ */
+ postMessage: function (data) {
+ var self = this;
+ var resModel = this.getDocumentModel();
+ var resID = this.getDocumentID();
+ return this._super.apply(this, arguments)
+ .then(function (messageData) {
+ _.extend(messageData, {
+ context: data.context,
+ message_type: data.message_type,
+ subtype: data.subtype || "mail.mt_comment",
+ subtype_id: data.subtype_id,
+ });
+ return self._rpc({
+ model: resModel,
+ method: 'message_post',
+ args: [resID],
+ kwargs: messageData,
+ })
+ .then(function (messageID) {
+ return self._rpc({
+ model: 'mail.message',
+ method: 'message_format',
+ args: [[messageID]],
+ })
+ .then(function (messages) {
+ messages[0].model = resModel;
+ messages[0].res_id = resID;
+ self.call('mail_service', 'addMessage', messages[0]);
+ return messages[0];
+ });
+ });
+ });
+ },
+ /**
+ * Set list of message IDs of this document thread
+ *
+ * Useful in order to handle message history of the document thread,
+ * in particular to fetch messages when necessary and/or display 'load more'.
+ *
+ * @param {integer[]} messageIDs
+ */
+ setMessageIDs: function (messageIDs) {
+ this._mustFetchMessageIDs = false;
+ this._messageIDs = messageIDs;
+ },
+ /**
+ * Set the name of this document thread
+ *
+ * This is useful if the name of the document related to the document thread
+ * has changed
+ *
+ * @param {string} newName
+ */
+ setName: function (newName) {
+ this._name = newName;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get most up to date messageIDs
+ *
+ * @private
+ * @returns {$.Promise} resolved when message IDs have been fetched and set
+ * in the model
+ */
+ _fetchMessageIDs: function () {
+ var self = this;
+ var resID = this.getDocumentID();
+ if (!resID || !this._mustFetchMessageIDs) {
+ return $.when();
+ }
+ return this._rpc({
+ model: this.getDocumentModel(),
+ method: 'read',
+ args: [[resID], ['message_ids']],
+ }).then(function (result) {
+ self.setMessageIDs(result[0].message_ids);
+ });
+ },
+ /**
+ * @override
+ * @private
+ * @param {Object} options
+ * @param {boolean} [options.forceFetch]
+ * @returns {$.Promise} resolved when messages have been fetched + document
+ * thread has updated messages
+ */
+ _fetchMessages: function (options) {
+ var self = this;
+ return this._fetchMessageIDs().then(function () {
+ var messageIDs = self._messageIDs;
+ var loadedMessages = _.filter(self._messages, function (message) {
+ return _.contains(messageIDs, message.getID());
+ });
+ var loadedMessageIDs = _.map(loadedMessages, function (message) {
+ return message.getID();
+ });
+
+ options = options || {};
+ var shouldFetch = _.difference(
+ messageIDs.slice(0, self._FETCH_LIMIT),
+ loadedMessageIDs
+ ).length > 0;
+ if (options.forceFetch || shouldFetch) {
+ var idsToLoad = _.difference(messageIDs, loadedMessageIDs)
+ .slice(0, self._FETCH_LIMIT);
+ return self._rpc({
+ model: 'mail.message',
+ method: 'message_format',
+ args: [idsToLoad],
+ context: session.user_context,
+ })
+ .then(function (messagesData) {
+ _.each(messagesData, function (messageData) {
+ self.call('mail_service', 'addMessage', messageData, { silent: true });
+ });
+ });
+ } else {
+ return $.when();
+ }
+
+ });
+ },
+
+});
+
+return DocumentThread;
+
+});