From fd9db95d6128facfc13ab9e6e4865dcb4bd74b96 Mon Sep 17 00:00:00 2001 From: Rahul Prajapati Date: Tue, 17 May 2022 05:55:54 +0000 Subject: [PATCH] [IMP] im_livechat: unpin read livechat sessions after one day Purpose: Make sure livechat operators are not buried under a huge pile of old sessions. Specification: Unpin read livechat sessions, 24 hours after the last message has been read by the operator. Task-2446972 Part-of: odoo/odoo#92053 --- .../im_livechat/models/mail_channel_member.py | 22 ++++++++--------- .../tests/test_get_mail_channel.py | 24 +++++++++++++++++++ addons/mail/models/mail_channel.py | 1 + addons/mail/models/mail_channel_member.py | 1 + 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/addons/im_livechat/models/mail_channel_member.py b/addons/im_livechat/models/mail_channel_member.py index 4b5764738ce..f0e961d763e 100644 --- a/addons/im_livechat/models/mail_channel_member.py +++ b/addons/im_livechat/models/mail_channel_member.py @@ -1,5 +1,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import datetime, timedelta + from odoo import api, models @@ -8,15 +10,13 @@ class ChannelMember(models.Model): @api.autovacuum def _gc_unpin_livechat_sessions(self): - """ Unpin livechat sessions with no activity for at least one day to + """ Unpin read livechat sessions with no activity for at least one day to clean the operator's interface """ - self.env.cr.execute(""" - UPDATE mail_channel_member - SET is_pinned = false - WHERE id in ( - SELECT cm.id FROM mail_channel_member cm - INNER JOIN mail_channel c on c.id = cm.channel_id - WHERE c.channel_type = 'livechat' AND cm.is_pinned is true AND - cm.write_date < current_timestamp - interval '1 day' - ) - """) + members = self.env['mail.channel.member'].search([ + ('is_pinned', '=', True), + ('last_seen_dt', '<=', datetime.now() - timedelta(days=1)), + ('channel_id.channel_type', '=', 'livechat'), + ]) + sessions_to_be_unpinned = members.filtered(lambda m: m.message_unread_counter == 0) + sessions_to_be_unpinned.write({'is_pinned': False}) + self.env['bus.bus']._sendmany([(member.partner_id, 'mail.channel/unpin', {'id': member.channel_id.id}) for member in sessions_to_be_unpinned]) diff --git a/addons/im_livechat/tests/test_get_mail_channel.py b/addons/im_livechat/tests/test_get_mail_channel.py index 18117d64c9f..b123f4a4853 100644 --- a/addons/im_livechat/tests/test_get_mail_channel.py +++ b/addons/im_livechat/tests/test_get_mail_channel.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import timedelta +from freezegun import freeze_time +from odoo import fields from odoo.tests.common import TransactionCase @@ -138,3 +141,24 @@ class TestGetMailChannel(TransactionCase): self.assertEqual(message_formats[0]['author_id'][1], operator.livechat_username) self.assertEqual(message_formats[0]['author_id'][2], operator.livechat_username) self.assertFalse(message_formats[0].get('email_from'), "should not send email_from to livechat user") + + def test_read_channel_unpined_for_operator_after_one_day(self): + public_user = self.env.ref('base.public_user') + channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='visitor') + member_of_operator = self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)]) + message = self.env['mail.channel'].browse(channel_info['id']).message_post(body='cc') + member_of_operator.channel_id.with_user(self.operators.filtered( + lambda operator: operator.partner_id == member_of_operator.partner_id + ))._channel_seen(message.id) + with freeze_time(fields.Datetime.to_string(fields.datetime.now() + timedelta(days=1))): + member_of_operator._gc_unpin_livechat_sessions() + self.assertFalse(member_of_operator.is_pinned, "read channel should be unpinned after one day") + + def test_unread_channel_not_unpined_for_operator_after_autovacuum(self): + public_user = self.env.ref('base.public_user') + channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='visitor') + member_of_operator = self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)]) + self.env['mail.channel'].browse(channel_info['id']).message_post(body='cc') + with freeze_time(fields.Datetime.to_string(fields.datetime.now() + timedelta(days=1))): + member_of_operator._gc_unpin_livechat_sessions() + self.assertTrue(member_of_operator.is_pinned, "unread channel should not be unpinned after autovacuum") diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index 5b49132a8a2..eaed74778d2 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -989,6 +989,7 @@ class Channel(models.Model): member.write({ 'fetched_message_id': last_message.id, 'seen_message_id': last_message.id, + 'last_seen_dt': fields.Datetime.now(), }) def channel_fetched(self): diff --git a/addons/mail/models/mail_channel_member.py b/addons/mail/models/mail_channel_member.py index 51be36caa57..47cc4c5f702 100644 --- a/addons/mail/models/mail_channel_member.py +++ b/addons/mail/models/mail_channel_member.py @@ -28,6 +28,7 @@ class ChannelMember(models.Model): is_minimized = fields.Boolean("Conversation is minimized") is_pinned = fields.Boolean("Is pinned on the interface", default=True) last_interest_dt = fields.Datetime("Last Interest", default=fields.Datetime.now, help="Contains the date and time of the last interesting event that happened in this channel for this partner. This includes: creating, joining, pinning, and new message posted.") + last_seen_dt = fields.Datetime("Last seen date") # RTC rtc_session_ids = fields.One2many(string="RTC Sessions", comodel_name='mail.channel.rtc.session', inverse_name='channel_member_id') rtc_inviting_session_id = fields.Many2one('mail.channel.rtc.session', string='Ringing session')