Permalink
Browse files

[IMP] mail, test_mail: new 'History' mailbox in Discuss

This commit adds a new mailbox in the Discuss app called 'History'.
Messages that have been marked as read are moved to 'History'.

Note that this feature only works with notification management
handled in Odoo, which can be changed in the user preferences.

Task-ID 40597
  • Loading branch information...
nla-odoo committed Feb 2, 2018
1 parent 80f3eb2 commit c40fc82fbc4527c10b357bd8802c091ee88dda7c
@@ -192,54 +192,29 @@ def _search_need_moderation(self, operator, operand):
#------------------------------------------------------

@api.model
def mark_all_as_read(self, channel_ids=None, domain=None):
""" Remove all needactions of the current partner. If channel_ids is
given, restrict to messages written in one of those channels. """
def mark_all_as_read(self, domain=None):
# not really efficient method: it does one db request for the
# search, and one for each message in the result set to archive the
# current notifications from the relation.
partner_id = self.env.user.partner_id.id
delete_mode = not self.env.user.share # delete employee notifs, keep customer ones
if not domain and delete_mode:
query = "DELETE FROM mail_message_res_partner_needaction_rel WHERE res_partner_id IN %s"
args = [(partner_id,)]
if channel_ids:
query += """
AND mail_message_id in
(SELECT mail_message_id
FROM mail_message_mail_channel_rel
WHERE mail_channel_id in %s)"""
args += [tuple(channel_ids)]
query += " RETURNING mail_message_id as id"
self._cr.execute(query, args)
self.invalidate_cache()

ids = [m['id'] for m in self._cr.dictfetchall()]
else:
# not really efficient method: it does one db request for the
# search, and one for each message in the result set to remove the
# current user from the relation.
msg_domain = [('needaction_partner_ids', 'in', partner_id)]
if channel_ids:
msg_domain += [('channel_ids', 'in', channel_ids)]
unread_messages = self.search(expression.AND([msg_domain, domain]))
notifications = self.env['mail.notification'].sudo().search([
('mail_message_id', 'in', unread_messages.ids),
('res_partner_id', '=', self.env.user.partner_id.id),
('is_read', '=', False)])
if delete_mode:
notifications.unlink()
else:
notifications.write({'is_read': True})
ids = unread_messages.mapped('id')
msg_domain = [('needaction_partner_ids', 'in', partner_id)]
unread_messages = self.search(expression.AND([msg_domain, domain]))
notifications = self.env['mail.notification'].sudo().search([
('mail_message_id', 'in', unread_messages.ids),
('res_partner_id', '=', partner_id),
('is_read', '=', False)])
notifications.write({'is_read': True})
ids = unread_messages.mapped('id')

notification = {'type': 'mark_as_read', 'message_ids': ids, 'channel_ids': channel_ids}
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), notification)
notification = {'type': 'mark_as_read', 'message_ids': ids}
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', partner_id), notification)

return ids

@api.multi
def set_message_done(self):
""" Remove the needaction from messages for the current partner. """
partner_id = self.env.user.partner_id
delete_mode = not self.env.user.share # delete employee notifs, keep customer ones

notifications = self.env['mail.notification'].sudo().search([
('mail_message_id', 'in', self.ids),
@@ -267,10 +242,7 @@ def set_message_done(self):
current_group = [record.id]
current_channel_ids = record.channel_ids

if delete_mode:
notifications.unlink()
else:
notifications.write({'is_read': True})
notifications.write({'is_read': True})

for (msg_ids, channel_ids) in groups:
notification = {'type': 'mark_as_read', 'message_ids': msg_ids, 'channel_ids': [c.id for c in channel_ids]}
@@ -509,7 +481,7 @@ def message_format(self):

# fetch notification status
notif_dict = {}
notifs = self.env['mail.notification'].sudo().search([('mail_message_id', 'in', list(mid for mid in message_tree)), ('is_read', '=', False)])
notifs = self.env['mail.notification'].sudo().search([('mail_message_id', 'in', list(mid for mid in message_tree))])
for notif in notifs:
mid = notif.mail_message_id.id
if not notif_dict.get(mid):
@@ -522,6 +494,7 @@ def message_format(self):
message['is_discussion'] = message['subtype_id'] and subtypes_dict[message['subtype_id'][0]]['id'] == com_id
message['is_notification'] = message['is_note'] and not message['model'] and not message['res_id']
message['subtype_description'] = message['subtype_id'] and subtypes_dict[message['subtype_id'][0]]['description']
message['is_history'] = notifs.filtered(lambda x: (x.mail_message_id.id == message['id']) and (x.res_partner_id == self.env.user.partner_id)).is_read
if message['model'] and self.env[message['model']]._original_module:
message['module_icon'] = modules.module.get_module_icon(self.env[message['model']]._original_module)
return message_values
@@ -71,7 +71,7 @@ Discuss.include({
* @returns {Boolean} true iff we currently are in the Inbox tab
*/
_isInInboxTab: function () {
return _.contains(['mailbox_inbox', 'mailbox_starred'], this._currentState);
return _.contains(['mailbox_inbox', 'mailbox_starred', 'mailbox_history'], this._currentState);
},
/**
* @override
@@ -160,7 +160,7 @@ Discuss.include({
*/
_updateContent: function (type) {
var self = this;
var inMailbox = type === 'mailbox_inbox' || type === 'mailbox_starred';
var inMailbox = _.contains(['mailbox_inbox', 'mailbox_starred', 'mailbox_history'], type);
if (!inMailbox && this._isInInboxTab()) {
// we're leaving the inbox, so store the thread scrolltop
this._storeThreadState();
@@ -230,8 +230,8 @@ Discuss.include({

// update bottom buttons
self.$('.o_mail_mobile_tab').removeClass('active');
// mailbox_inbox and mailbox_starred share the same tab
type = type === 'mailbox_starred' ? 'mailbox_inbox' : type;
// mailbox_inbox, mailbox_starred and mailbox_history share the same tab
type = _.contains(['mailbox_inbox', 'mailbox_starred', 'mailbox_history'], type) ? 'mailbox_inbox' : type;
self.$('.o_mail_mobile_tab[data-type=' + type + ']').addClass('active');
});
},
@@ -28,6 +28,8 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
* @param {string} [data.customer_email_status]
* @param {string} [data.email_from]
* @param {string} [data.info]
* @param {boolean} [data.is_history] if set, the message should be put in
* the 'History' mailbox.
* @param {string} [data.model]
* @param {string} [data.moderation_status='accepted']
* @param {string} [data.module_icon]
@@ -55,6 +57,7 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
this._info = data.info;
this._moduleIcon = data.module_icon;
this._needactionPartnerIDs = data.needaction_partner_ids || [];
this._isHistory = data.is_history;
this._starredPartnerIDs = data.starred_partner_ids || [];
this._subject = data.subject;
this._subtypeDescription = data.subtype_description;
@@ -645,12 +648,15 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
* @private
*/
_processMailboxes: function () {
if (_.contains(this._needactionPartnerIDs, session.partner_id)) {
if (_.contains(this._needactionPartnerIDs, session.partner_id) && !this._isHistory) {
this._setNeedaction(true);
}
if (_.contains(this._starredPartnerIDs, session.partner_id)) {
this.setStarred(true);
}
if (this._isHistory) {
this._setHistory(true);
}
if (
this.originatesFromChannel() &&
_.contains(
@@ -729,6 +735,21 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
});
}
},
/**
* Set whether the message is history or not.
* If it is history, the message is moved to the "History" mailbox.
* Note that this function only applies it locally, the server is not aware
*
* @private
* @param {boolean} history if set, the message is history
*/
_setHistory: function (history) {
if (history) {
this._addThread('mailbox_history');
} else {
this.removeThread('mailbox_history');
}
},
/**
* Set whether the message is moderated by current user or not.
* If it is moderated by the current user, the message is moved to the
@@ -124,11 +124,11 @@ var Mailbox = SearchableThread.extend({
*/
markAllMessagesAsRead: function (domain) {
if (this._id === 'mailbox_inbox' && this.getMailboxCounter() > 0) {
this.trigger_up('move_messages_to_history', { messages: this.getMessages() });
return this._rpc({
model: 'mail.message',
method: 'mark_all_as_read',
kwargs: {
channel_ids: [],
domain: domain,
},
});
@@ -183,6 +183,8 @@ var Mailbox = SearchableThread.extend({
return [['needaction', '=', true]];
} else if (this._id === 'mailbox_starred') {
return [['starred', '=', true]];
} else if (this._id === 'mailbox_history') {
return [['needaction', '=', false]];
} else if (this._id === 'mailbox_moderation') {
return [['need_moderation', '=', true]];
} else {
@@ -47,6 +47,10 @@ var MailManager = AbstractService.extend({
dependencies: ['ajax', 'bus_service', 'local_storage'],
_ODOOBOT_ID: "ODOOBOT", // default authorID for transient messages

custom_events: _.extend({}, AbstractService.prototype.custom_events, {
move_messages_to_history: '_onMoveMessagesToHistory',
}),

/**
* @override
*/
@@ -321,8 +325,12 @@ var MailManager = AbstractService.extend({
*/
markMessagesAsRead: function (messageIDs) {
var self = this;
var history = this.getMailbox('history');
var ids = _.filter(messageIDs, function (id) {
var message = self.getMessage(id);
if (message) {
history.addMessage(message, {});
}
// If too many messages, not all are fetched,
// and some might not be found
return !message || message.isNeedaction();
@@ -1212,7 +1220,8 @@ var MailManager = AbstractService.extend({
},
/**
* Update the mailboxes with mail data fetched from server, namely 'Inbox',
* 'Starred', and 'Moderation Queue' if the user is a moderator of a channel
* 'Starred', 'History', and 'Moderation Queue' if the user is a moderator
* of a channel
*
* @private
* @param {Object} data
@@ -1236,6 +1245,10 @@ var MailManager = AbstractService.extend({
name: _t("Starred"),
mailboxCounter: data.starred_counter || 0,
});
this._addMailbox({
id: 'history',
name: _t("History"),
});

if (data.is_moderator) {
this._addMailbox({
@@ -1283,6 +1296,20 @@ var MailManager = AbstractService.extend({
_onDiscussOpen: function (open) {
this._discussOpen = open;
},
/**
* Called when marking messages as read in the inbox, should move the
* provided messages to the history
*
* @private
* @param {OdooEvent} ev
* @param {mail.model.Message[]} ev.data.messages
*/
_onMoveMessagesToHistory: function (ev) {
var history = this.getMailbox('history');
_.each(ev.data.messages, function (message) {
history.addMessage(message, {});
});
},
/**
* Reset out of focus unread message counter + tab title
*
@@ -60,6 +60,10 @@
<t t-set="counter" t-value="starred.getMailboxCounter()"/>
<t t-call="mail.discuss.SidebarCounter"/>
</div>
<div t-attf-class="o_mail_discuss_title_main o_mail_mailbox_title_history o_mail_discuss_item #{(activeThreadID === 'mailbox_history') ? 'o_active': ''}"
data-thread-id="mailbox_history">
<span class="o_thread_name"><i class="fa fa-history mr8"/>History</span>
</div>
<div t-if="isMyselfModerator" t-attf-class="o_mail_discuss_title_main o_mail_discuss_item #{(activeThreadID == 'mailbox_moderation') ? 'o_active': ''}"
data-thread-id="mailbox_moderation">
<span class="o_thread_name"> <i class="fa fa-envelope mr8"/>Moderation Queue</span>
@@ -238,6 +242,9 @@
<button type="button" class="btn btn-secondary d-inline d-md-none o_mailbox_inbox_item" title="Starred" data-type="mailbox_starred">
Starred
</button>
<button type="button" class="btn btn-secondary d-inline d-md-none o_mailbox_inbox_item" title="History" data-type="mailbox_history">
History
</button>
</div>
<div class="o_mail_discuss_content"/>
<div class="o_mail_mobile_tabs">
@@ -131,6 +131,10 @@
<div class="o_thread_title">No starred message</div>
<div>You can mark any message as 'starred', and it shows up in this mailbox.</div>
</t>
<t t-if="thread.getID() === 'mailbox_history'">
<div class="o_thread_title">No history message</div>
<div>You can mark any message as 'read', and it shows up in this mailbox.</div>
</t>
<t t-if="thread.getID() === 'mailbox_moderation'">
<div class="o_thread_title">You have no message to moderate</div>
<div>Pending moderation messages appear here.</div>
Oops, something went wrong.

0 comments on commit c40fc82

Please sign in to comment.