From cb7add2ebd50c1981e35bb12a3e52a69a58bc05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20K=C3=BChn?= Date: Wed, 4 Jul 2018 13:44:49 +0200 Subject: [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. --- .../src/js/models/threads/document_thread.js | 317 +++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 addons/mail/static/src/js/models/threads/document_thread.js (limited to 'addons/mail/static/src/js/models/threads/document_thread.js') 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} + */ + 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} 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; + +}); -- cgit v1.2.3