[REF] mail, *: rename mail.channel to discuss.channel

* = bus, calendar, crm_livechat, hr, hr_holidays, im_livechat, mail_bot,
    mass_mailing, privacy_lookup, test_discuss_full, test_mail,
    test_mail_full, website_crm_livechat, website_livechat, base

In preparation of splitting discuss and mail modules.

Part of task-3265211

closes odoo/odoo#118354

Related: odoo/upgrade#4553
Related: odoo/enterprise#39661
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Sébastien Theys
2023-04-21 02:21:53 +02:00
parent 65fd6d9b24
commit 90cb44e1e1
225 changed files with 2509 additions and 2468 deletions
+1 -1
View File
@@ -9,5 +9,5 @@ class TestIrWebsocket(common.HttpCase):
self.env['ir.websocket']._subscribe({
'inactivity_period': 1000,
'last': 0,
'channels': [('odoo', 'mail.channel', 5)],
'channels': [('odoo', 'discuss.channel', 5)],
})
+2 -2
View File
@@ -106,7 +106,7 @@ class Meeting(models.Model):
videocall_location = fields.Char('Meeting URL', compute='_compute_videocall_location', store=True, copy=True)
access_token = fields.Char('Invitation Token', store=True, copy=False, index=True)
videocall_source = fields.Selection([('discuss', 'Discuss'), ('custom', 'Custom')], compute='_compute_videocall_source')
videocall_channel_id = fields.Many2one('mail.channel', 'Discuss Channel')
videocall_channel_id = fields.Many2one('discuss.channel', 'Discuss Channel')
# visibility
privacy = fields.Selection(
[('public', 'Public'),
@@ -756,7 +756,7 @@ class Meeting(models.Model):
self.videocall_channel_id.channel_change_description(self.recurrence_id.name if self.recurrency else self.display_time)
def _create_videocall_channel_id(self, name, partner_ids):
videocall_channel_id = self.env['mail.channel'].create_group(partner_ids, default_display_mode='video_full_screen', name=name)
videocall_channel_id = self.env['discuss.channel'].create_group(partner_ids, default_display_mode='video_full_screen', name=name)
# if recurrent event, set channel to all other records of the same recurrency
if self.recurrency:
recurrent_events_without_channel = self.env['calendar.event'].search([
+1 -1
View File
@@ -3,4 +3,4 @@
from . import chatbot_script
from . import chatbot_script_step
from . import mail_channel
from . import discuss_channel
@@ -14,9 +14,9 @@ class ChatbotScriptStep(models.Model):
help="Used in combination with 'create_lead' step type in order to automatically "
"assign the created lead/opportunity to the defined team")
def _chatbot_crm_prepare_lead_values(self, mail_channel, description):
def _chatbot_crm_prepare_lead_values(self, discuss_channel, description):
return {
'description': description + mail_channel._get_channel_history(),
'description': description + discuss_channel._get_channel_history(),
'name': _("%s's New Lead", self.chatbot_script_id.title),
'source_id': self.chatbot_script_id.source_id.id,
'team_id': self.crm_team_id.id,
@@ -24,17 +24,17 @@ class ChatbotScriptStep(models.Model):
'user_id': False,
}
def _process_step(self, mail_channel):
def _process_step(self, discuss_channel):
self.ensure_one()
posted_message = super()._process_step(mail_channel)
posted_message = super()._process_step(discuss_channel)
if self.step_type == 'create_lead':
self._process_step_create_lead(mail_channel)
self._process_step_create_lead(discuss_channel)
return posted_message
def _process_step_create_lead(self, mail_channel):
def _process_step_create_lead(self, discuss_channel):
""" When reaching a 'create_lead' step, we extract the relevant information: visitor's
email, phone and conversation history to create a crm.lead.
@@ -46,7 +46,7 @@ class ChatbotScriptStep(models.Model):
their interest / needs before creating the lead. """
customer_values = self._chatbot_prepare_customer_values(
mail_channel, create_partner=False, update_partner=True)
discuss_channel, create_partner=False, update_partner=True)
if self.env.user._is_public():
create_values = {
'email_from': customer_values['email'],
@@ -60,6 +60,6 @@ class ChatbotScriptStep(models.Model):
}
create_values.update(self._chatbot_crm_prepare_lead_values(
mail_channel, customer_values['description']))
discuss_channel, customer_values['description']))
self.env['crm.lead'].create(create_values)
@@ -6,8 +6,8 @@ from odoo import models, _
from odoo.tools import html2plaintext
class MailChannel(models.Model):
_inherit = 'mail.channel'
class DiscussChannel(models.Model):
_inherit = 'discuss.channel'
def execute_command_lead(self, **kwargs):
partner = self.env.user.partner_id
@@ -3,7 +3,7 @@
import { _lt } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
registry.category("mail.channel_commands").add("lead", {
registry.category("discuss.channel_commands").add("lead", {
help: _lt("Create a new lead (/lead lead title)"),
methodName: "execute_command_lead",
});
@@ -7,7 +7,7 @@ QUnit.module("composer");
QUnit.test("Can execute lead command", async function (assert) {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({ name: "General" });
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
const { openDiscuss } = await start({
mockRPC(route, args) {
if (args.method === "execute_command_lead") {
@@ -33,19 +33,19 @@ class CrmChatbotCase(chatbot_common.CrmChatbotCase):
self.assertEqual(created_lead.type, 'lead')
def _chatbot_create_lead(self, user):
channel_info = self.livechat_channel._open_livechat_mail_channel(
channel_info = self.livechat_channel._open_livechat_discuss_channel(
anonymous_name='Test Visitor', chatbot_script=self.chatbot_script, user_id=user.id)
mail_channel = self.env['mail.channel'].sudo().browse(channel_info['id'])
discuss_channel = self.env['discuss.channel'].sudo().browse(channel_info['id'])
self._post_answer_and_trigger_next_step(
mail_channel,
discuss_channel,
self.step_dispatch_create_lead.name,
chatbot_script_answer=self.step_dispatch_create_lead
)
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_create_lead_email)
self._post_answer_and_trigger_next_step(mail_channel, 'test2@example.com')
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_create_lead_email)
self._post_answer_and_trigger_next_step(discuss_channel, 'test2@example.com')
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_create_lead_phone)
self._post_answer_and_trigger_next_step(mail_channel, '123456')
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_create_lead_phone)
self._post_answer_and_trigger_next_step(discuss_channel, '123456')
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_create_lead)
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_create_lead)
+3 -3
View File
@@ -31,7 +31,7 @@ class TestLivechatLead(TestCrmCommon):
def test_crm_lead_creation_guest(self):
""" Test customer set on lead: not if public, guest if not public """
# public: should not be set as customer
channel = self.env['mail.channel'].create({
channel = self.env['discuss.channel'].create({
'name': 'Chat with Visitor',
'channel_partner_ids': [(4, self.user_anonymous.partner_id.id)]
})
@@ -48,7 +48,7 @@ class TestLivechatLead(TestCrmCommon):
# 'base.public_user' is archived by default
self.assertFalse(self.env.ref('base.public_user').active)
channel = self.env['mail.channel'].create({
channel = self.env['discuss.channel'].create({
'name': 'Chat with Visitor',
'channel_partner_ids': [(4, self.env.ref('base.public_partner').id)]
})
@@ -69,7 +69,7 @@ class TestLivechatLead(TestCrmCommon):
self.assertEqual(lead.partner_id, self.env['res.partner'])
# portal: should be set as customer
channel = self.env['mail.channel'].create({
channel = self.env['discuss.channel'].create({
'name': 'Chat with Visitor',
'channel_partner_ids': [(4, self.user_portal.partner_id.id)]
})
@@ -128,7 +128,7 @@ class Challenge(models.Model):
('yearly', "Yearly")
], default='never',
string="Report Frequency", required=True)
report_message_group_id = fields.Many2one('mail.channel', string="Send a copy to", help="Group that will receive a copy of the report in addition to the user")
report_message_group_id = fields.Many2one('discuss.channel', string="Send a copy to", help="Group that will receive a copy of the report in addition to the user")
report_template_id = fields.Many2one('mail.template', default=lambda self: self._get_report_template(), string="Report Template", required=True)
remind_update_delay = fields.Integer("Non-updated manual goals will be reminded after", help="Never reminded if no value or zero is specified.")
last_report_date = fields.Date("Last Report Date", default=fields.Date.today)
+1 -1
View File
@@ -34,7 +34,7 @@
'views/hr_work_location_views.xml',
'views/hr_views.xml',
'views/res_config_settings_views.xml',
'views/mail_channel_views.xml',
'views/discuss_channel_views.xml',
'views/res_users.xml',
'views/res_partner_views.xml',
'views/hr_templates.xml',
+1 -1
View File
@@ -14,7 +14,7 @@ from . import hr_plan_activity_type
from . import hr_plan_employee_activity
from . import hr_work_location
from . import mail_alias
from . import mail_channel
from . import discuss_channel
from . import models
from . import res_config_settings
from . import res_partner
@@ -6,7 +6,7 @@ from odoo.exceptions import ValidationError
class Channel(models.Model):
_inherit = 'mail.channel'
_inherit = 'discuss.channel'
subscription_department_ids = fields.Many2many(
'hr.department', string='HR Departments',
+2 -2
View File
@@ -354,7 +354,7 @@ class HrEmployeePrivate(models.Model):
return employees
employee_departments = employees.department_id
if employee_departments:
self.env['mail.channel'].sudo().search([
self.env['discuss.channel'].sudo().search([
('subscription_department_ids', 'in', employee_departments.ids)
])._subscribe_users_automatically()
onboarding_notes_bodies = {}
@@ -392,7 +392,7 @@ class HrEmployeePrivate(models.Model):
if vals.get('department_id') or vals.get('user_id'):
department_id = vals['department_id'] if vals.get('department_id') else self[:1].department_id.id
# When added to a department or changing user, subscribe to the channels auto-subscribed by department
self.env['mail.channel'].sudo().search([
self.env['discuss.channel'].sudo().search([
('subscription_department_ids', 'in', department_id)
])._subscribe_users_automatically()
return res
+1 -1
View File
@@ -10,7 +10,7 @@ class TestChannel(TestHrCommon):
def setUpClass(cls):
super(TestChannel, cls).setUpClass()
cls.channel = cls.env['mail.channel'].create({'name': 'Test'})
cls.channel = cls.env['discuss.channel'].create({'name': 'Test'})
emp0 = cls.env['hr.employee'].create({
'user_id': cls.res_users_hr_officer.id,
@@ -1,9 +1,9 @@
<?xml version="1.0" ?>
<odoo><data>
<record id="mail_channel_view_form_" model="ir.ui.view">
<field name="name">mail.channel.view.form.inherit.hr</field>
<field name="model">mail.channel</field>
<field name="inherit_id" ref="mail.mail_channel_view_form"/>
<record id="discuss_channel_view_form" model="ir.ui.view">
<field name="name">discuss.channel.view.form.inherit.hr</field>
<field name="model">discuss.channel</field>
<field name="inherit_id" ref="mail.discuss_channel_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='group_ids']" position="after">
<field name="subscription_department_ids" widget="many2many_tags"
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-inherit="mail.Thread" t-inherit-mode="extension">
<xpath expr="//*[hasclass('o-mail-Thread')]" position="before">
<div t-if="props.thread.model === 'mail.channel' and props.thread.correspondent and personaService.outOfOfficeText(props.thread.correspondent)" class="alert alert-primary" t-esc="personaService.outOfOfficeText(props.thread.correspondent)" role="alert"/>
<div t-if="props.thread.model === 'discuss.channel' and props.thread.correspondent and personaService.outOfOfficeText(props.thread.correspondent)" class="alert alert-primary" t-esc="personaService.outOfOfficeText(props.thread.correspondent)" role="alert"/>
</xpath>
</t>
</templates>
@@ -9,11 +9,11 @@ QUnit.module("im_status");
QUnit.test("on leave & online", async (assert) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "leave_online" });
const channelId = pyEnv["mail.channel"].create({ name: "General" });
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
pyEnv["mail.message"].create({
author_id: partnerId,
body: "not empty",
model: "mail.channel",
model: "discuss.channel",
res_id: channelId,
});
const { advanceTime, afterNextRender, openDiscuss } = await start({
@@ -27,11 +27,11 @@ QUnit.test("on leave & online", async (assert) => {
QUnit.test("on leave & away", async (assert) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "leave_away" });
const channelId = pyEnv["mail.channel"].create({ name: "General" });
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
pyEnv["mail.message"].create({
author_id: partnerId,
body: "not empty",
model: "mail.channel",
model: "discuss.channel",
res_id: channelId,
});
const { advanceTime, afterNextRender, openDiscuss } = await start({
@@ -45,11 +45,11 @@ QUnit.test("on leave & away", async (assert) => {
QUnit.test("on leave & offline", async (assert) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Demo", im_status: "leave_offline" });
const channelId = pyEnv["mail.channel"].create({ name: "General" });
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
pyEnv["mail.message"].create({
author_id: partnerId,
body: "not empty",
model: "mail.channel",
model: "discuss.channel",
res_id: channelId,
});
const { advanceTime, afterNextRender, openDiscuss } = await start({
@@ -10,7 +10,7 @@ QUnit.test("thread icon of a chat when correspondent is on leave & online", asyn
im_status: "leave_online",
name: "Demo",
});
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -31,7 +31,7 @@ QUnit.test("thread icon of a chat when correspondent is on leave & away", async
im_status: "leave_away",
name: "Demo",
});
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -52,7 +52,7 @@ QUnit.test("thread icon of a chat when correspondent is on leave & offline", asy
im_status: "leave_offline",
name: "Demo",
});
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -11,7 +11,7 @@ QUnit.test("out of office message on direct chat with out of office partner", as
im_status: "leave_online",
out_of_office_date_end: "2023-01-01",
});
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -41,7 +41,7 @@ class TestOutOfOffice(TestHrHolidaysCommon):
partner = self.employee_hruser.user_id.partner_id
partner2 = self.user_employee.partner_id
channel = self.env['mail.channel'].with_user(self.user_employee).with_context({
channel = self.env['discuss.channel'].with_user(self.user_employee).with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True,
}).create({
+3 -3
View File
@@ -20,7 +20,7 @@ Help your customers with this chat, and analyse their feedback.
'data': [
"security/im_livechat_channel_security.xml",
"security/ir.model.access.csv",
"data/mail_shortcode_data.xml",
"data/discuss_shortcode_data.xml",
"data/mail_templates.xml",
"data/im_livechat_channel_data.xml",
"data/im_livechat_chatbot_data.xml",
@@ -29,7 +29,7 @@ Help your customers with this chat, and analyse their feedback.
'views/chatbot_script_step_views.xml',
'views/chatbot_script_views.xml',
"views/rating_rating_views.xml",
"views/mail_channel_views.xml",
"views/discuss_channel_views.xml",
"views/im_livechat_channel_views.xml",
"views/im_livechat_channel_templates.xml",
"views/im_livechat_chatbot_templates.xml",
@@ -40,7 +40,7 @@ Help your customers with this chat, and analyse their feedback.
],
'demo': [
"data/im_livechat_channel_demo.xml",
'data/mail_shortcode_demo.xml',
'data/discuss_shortcode_demo.xml',
],
'depends': ["mail", "rating", "digest", "utm"],
'installable': True,
+23 -23
View File
@@ -10,32 +10,32 @@ class LivechatChatbotScriptController(http.Controller):
@http.route('/chatbot/restart', type="json", auth="public", cors="*")
def chatbot_restart(self, channel_uuid, chatbot_script_id):
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
chatbot = request.env['chatbot.script'].browse(chatbot_script_id)
if not mail_channel or not chatbot.exists():
if not discuss_channel or not chatbot.exists():
return None
return mail_channel._chatbot_restart(chatbot).message_format()[0]
return discuss_channel._chatbot_restart(chatbot).message_format()[0]
@http.route('/chatbot/post_welcome_steps', type="json", auth="public", cors="*")
def chatbot_post_welcome_steps(self, channel_uuid, chatbot_script_id):
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
chatbot = request.env['chatbot.script'].sudo().browse(chatbot_script_id)
if not mail_channel or not chatbot.exists():
if not discuss_channel or not chatbot.exists():
return None
return chatbot._post_welcome_steps(mail_channel).message_format()
return chatbot._post_welcome_steps(discuss_channel).message_format()
@http.route('/chatbot/answer/save', type="json", auth="public", cors="*")
def chatbot_save_answer(self, channel_uuid, message_id, selected_answer_id):
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
chatbot_message = request.env['chatbot.message'].sudo().search([
('mail_message_id', '=', message_id),
('mail_channel_id', '=', mail_channel.id),
('discuss_channel_id', '=', discuss_channel.id),
], limit=1)
selected_answer = request.env['chatbot.script.answer'].sudo().browse(selected_answer_id)
if not mail_channel or not chatbot_message or not selected_answer.exists():
if not discuss_channel or not chatbot_message or not selected_answer.exists():
return
if selected_answer in chatbot_message.script_step_id.answer_ids:
@@ -43,20 +43,20 @@ class LivechatChatbotScriptController(http.Controller):
@http.route('/chatbot/step/trigger', type="json", auth="public", cors="*")
def chatbot_trigger_step(self, channel_uuid, chatbot_script_id=None):
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
if not mail_channel:
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
if not discuss_channel:
return None
next_step = False
if mail_channel.chatbot_current_step_id:
chatbot = mail_channel.chatbot_current_step_id.chatbot_script_id
user_messages = mail_channel.message_ids.filtered(
if discuss_channel.chatbot_current_step_id:
chatbot = discuss_channel.chatbot_current_step_id.chatbot_script_id
user_messages = discuss_channel.message_ids.filtered(
lambda message: message.author_id != chatbot.operator_partner_id
)
user_answer = request.env['mail.message'].sudo()
if user_messages:
user_answer = user_messages.sorted(lambda message: message.id)[-1]
next_step = mail_channel.chatbot_current_step_id._process_answer(mail_channel, user_answer.body)
next_step = discuss_channel.chatbot_current_step_id._process_answer(discuss_channel, user_answer.body)
elif chatbot_script_id: # when restarting, we don't have a "current step" -> set "next" as first step of the script
chatbot = request.env['chatbot.script'].sudo().browse(chatbot_script_id)
if chatbot.exists():
@@ -65,19 +65,19 @@ class LivechatChatbotScriptController(http.Controller):
if not next_step:
return None
posted_message = next_step._process_step(mail_channel)
posted_message = next_step._process_step(discuss_channel)
return {
'chatbot_posted_message': posted_message.message_format()[0] if posted_message else None,
'chatbot_step': {
'chatbot_operator_found': next_step.step_type == 'forward_operator' and len(
mail_channel.channel_member_ids) > 2,
discuss_channel.channel_member_ids) > 2,
'chatbot_script_step_id': next_step.id,
'chatbot_step_answers': [{
'id': answer.id,
'label': answer.name,
'redirect_link': answer.redirect_link,
} for answer in next_step.answer_ids],
'chatbot_step_is_last': next_step._is_last_step(mail_channel),
'chatbot_step_is_last': next_step._is_last_step(discuss_channel),
'chatbot_step_message': plaintext2html(next_step.message) if not is_html_empty(next_step.message) else False,
'chatbot_step_type': next_step.step_type,
}
@@ -85,18 +85,18 @@ class LivechatChatbotScriptController(http.Controller):
@http.route('/chatbot/step/validate_email', type="json", auth="public", cors="*")
def chatbot_validate_email(self, channel_uuid):
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
if not mail_channel or not mail_channel.chatbot_current_step_id:
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid)], limit=1)
if not discuss_channel or not discuss_channel.chatbot_current_step_id:
return None
chatbot = mail_channel.chatbot_current_step_id.chatbot_script_id
user_messages = mail_channel.message_ids.filtered(
chatbot = discuss_channel.chatbot_current_step_id.chatbot_script_id
user_messages = discuss_channel.message_ids.filtered(
lambda message: message.author_id != chatbot.operator_partner_id
)
if user_messages:
user_answer = user_messages.sorted(lambda message: message.id)[-1]
result = chatbot._validate_email(user_answer.body, mail_channel)
result = chatbot._validate_email(user_answer.body, discuss_channel)
if result['posted_message']:
result['posted_message'] = result['posted_message'].message_format()[0]
+10 -10
View File
@@ -134,7 +134,7 @@ class LivechatController(http.Controller):
if chatbot_script_id:
chatbot_script = request.env['chatbot.script'].sudo().browse(chatbot_script_id)
return request.env["im_livechat.channel"].with_context(lang=False).sudo().browse(channel_id)._open_livechat_mail_channel(
return request.env["im_livechat.channel"].with_context(lang=False).sudo().browse(channel_id)._open_livechat_discuss_channel(
anonymous_name,
previous_operator_id=previous_operator_id,
chatbot_script=chatbot_script,
@@ -145,7 +145,7 @@ class LivechatController(http.Controller):
@http.route('/im_livechat/feedback', type='json', auth='public', cors="*")
def feedback(self, uuid, rate, reason=None, **kwargs):
channel = request.env['mail.channel'].sudo().search([('uuid', '=', uuid)], limit=1)
channel = request.env['discuss.channel'].sudo().search([('uuid', '=', uuid)], limit=1)
if channel:
# limit the creation : only ONE rating per session
values = {
@@ -157,7 +157,7 @@ class LivechatController(http.Controller):
if not channel.rating_ids:
values.update({
'res_id': channel.id,
'res_model_id': request.env['ir.model']._get_id('mail.channel'),
'res_model_id': request.env['ir.model']._get_id('discuss.channel'),
})
# find the partner (operator)
if channel.channel_partner_ids:
@@ -175,7 +175,7 @@ class LivechatController(http.Controller):
@http.route('/im_livechat/history', type="json", auth="public", cors="*")
def history_pages(self, pid, channel_uuid, page_history=None):
partner_ids = (pid, request.env.user.partner_id.id)
channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid), ('channel_partner_ids', 'in', partner_ids)])
channel = request.env['discuss.channel'].sudo().search([('uuid', '=', channel_uuid), ('channel_partner_ids', 'in', partner_ids)])
if channel:
channel._send_history_message(pid, page_history)
return True
@@ -186,17 +186,17 @@ class LivechatController(http.Controller):
:param uuid: (string) the UUID of the livechat channel
:param is_typing: (boolean) tells whether the website user is typing or not.
"""
channel = request.env['mail.channel'].sudo().search([('uuid', '=', uuid)])
channel = request.env['discuss.channel'].sudo().search([('uuid', '=', uuid)])
if not channel:
raise NotFound()
channel_member = channel.env['mail.channel.member'].search([('channel_id', '=', channel.id), ('partner_id', '=', request.env.user.partner_id.id)])
channel_member = channel.env['discuss.channel.member'].search([('channel_id', '=', channel.id), ('partner_id', '=', request.env.user.partner_id.id)])
if not channel_member:
raise NotFound()
channel_member._notify_typing(is_typing=is_typing)
@http.route('/im_livechat/email_livechat_transcript', type='json', auth='public', cors="*")
def email_livechat_transcript(self, uuid, email):
channel = request.env['mail.channel'].sudo().search([
channel = request.env['discuss.channel'].sudo().search([
('channel_type', '=', 'livechat'),
('uuid', '=', uuid)], limit=1)
if channel:
@@ -208,6 +208,6 @@ class LivechatController(http.Controller):
This will clean the chat request and warn the operator that the conversation is over.
This allows also to re-send a new chat request to the visitor, as while the visitor is
in conversation with an operator, it's not possible to send the visitor a chat request."""
mail_channel = request.env['mail.channel'].sudo().search([('uuid', '=', uuid)])
if mail_channel:
mail_channel._close_livechat_session()
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', uuid)])
if discuss_channel:
discuss_channel._close_livechat_session()
@@ -17,7 +17,7 @@
<field eval="[(4, ref('base.user_demo'))]" name="user_ids"/>
</record>
<!-- Session 0 -->
<record id="im_livechat_mail_channel_data_0" model="mail.channel">
<record id="im_livechat_discuss_channel_data_0" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_admin"/>
@@ -26,56 +26,56 @@
</record>
<record id="im_livechat_rating_1" model="rating.rating">
<field name="access_token">LIVECHAT_1</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_0')], 5, 'LIVECHAT_1', None, 'Good Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_0')], 5, 'LIVECHAT_1', None, 'Good Job')"/>
<record id="im_livechat_mail_message_5_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">You're welcome, have a nice day!</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=5)" name="date"/>
</record>
<record id="im_livechat_mail_message_4_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Great! Thanks for the info</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=4)" name="date"/>
</record>
<record id="im_livechat_mail_message_3_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Yes, you can use our Timesheets application to record your time efficiently!</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=3)" name="date"/>
</record>
<record id="im_livechat_mail_message_2_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">I'm looking for an application to record my timesheet, any tips?</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=2)" name="date"/>
</record>
<record id="im_livechat_mail_message_1_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_0"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-0, minutes=1)" name="date"/>
</record>
<!-- Session 1 -->
<record id="im_livechat_mail_channel_data_1" model="mail.channel">
<record id="im_livechat_discuss_channel_data_1" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_demo"/>
@@ -84,56 +84,56 @@
</record>
<record id="im_livechat_rating_2" model="rating.rating">
<field name="access_token">LIVECHAT_2</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_1')], 5, 'LIVECHAT_2', None, 'Super Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_1')], 5, 'LIVECHAT_2', None, 'Super Job')"/>
<record id="im_livechat_mail_message_10_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">You're welcome, enjoy Odoo!</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=10)" name="date"/>
</record>
<record id="im_livechat_mail_message_9_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Awesome, thanks!</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=9)" name="date"/>
</record>
<record id="im_livechat_mail_message_8_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">Yes, we just released a new application called Social Marketing that should fit your needs! Check it out :)</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=8)" name="date"/>
</record>
<record id="im_livechat_mail_message_7_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">I was wondering if Odoo has an application to easily manage social media for my business..</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=7)" name="date"/>
</record>
<record id="im_livechat_mail_message_6_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_1"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-1, minutes=6)" name="date"/>
</record>
<!-- Session 2 -->
<record id="im_livechat_mail_channel_data_2" model="mail.channel">
<record id="im_livechat_discuss_channel_data_2" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_admin"/>
@@ -142,49 +142,49 @@
</record>
<record id="im_livechat_rating_3" model="rating.rating">
<field name="access_token">LIVECHAT_3</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_2"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_2')], 5, 'LIVECHAT_3', None, 'Mega Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_2')], 5, 'LIVECHAT_3', None, 'Mega Job')"/>
<record id="im_livechat_mail_message_14_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_2"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Oh :(</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=14)" name="date"/>
</record>
<record id="im_livechat_mail_message_13_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_2"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Nope, sorry to disappoint :(</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=13)" name="date"/>
</record>
<record id="im_livechat_mail_message_12_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_2"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Hello, are you single?</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=12)" name="date"/>
</record>
<record id="im_livechat_mail_message_11_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_2"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-1, days=-2, minutes=11)" name="date"/>
</record>
<!-- Session 3 -->
<record id="im_livechat_mail_channel_data_3" model="mail.channel">
<record id="im_livechat_discuss_channel_data_3" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_demo"/>
@@ -193,41 +193,41 @@
</record>
<record id="im_livechat_rating_4" model="rating.rating">
<field name="access_token">LIVECHAT_4</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_3"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_3')], 5, 'LIVECHAT_4', None, 'Good Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_3')], 5, 'LIVECHAT_4', None, 'Good Job')"/>
<record id="im_livechat_mail_message_17_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_3"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Thanks for the info, I'll look into it!</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=17)" name="date"/>
</record>
<record id="im_livechat_mail_message_16_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_3"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">Hello Joel Willis, you're at the right place! You can customize Odoo using our Studio application in just a few clicks.</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=16)" name="date"/>
</record>
<record id="im_livechat_mail_message_15_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_3"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Hello, I'm looking for a software that can be easily updated with my needs.</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-3, minutes=15)" name="date"/>
</record>
<!-- Session 4 -->
<record id="im_livechat_mail_channel_data_4" model="mail.channel">
<record id="im_livechat_discuss_channel_data_4" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_admin"/>
@@ -236,48 +236,48 @@
</record>
<record id="im_livechat_rating_5" model="rating.rating">
<field name="access_token">LIVECHAT_5</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_4"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_4')], 5, 'LIVECHAT_5', None, 'Super Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_4')], 5, 'LIVECHAT_5', None, 'Super Job')"/>
<record id="im_livechat_mail_message_21_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_4"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Ok.. Will do, thanks</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=21)" name="date"/>
</record>
<record id="im_livechat_mail_message_20_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_4"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hi, if you need help with your database, feel free to contact our support via http://www.odoo.com/help</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=20)" name="date"/>
</record>
<record id="im_livechat_mail_message_19_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_4"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Hello, it seems that I can't log in to my database. Can you help?</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=19)" name="date"/>
</record>
<record id="im_livechat_mail_message_18_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_4"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-2, days=-4, minutes=18)" name="date"/>
</record>
<!-- Session 5 -->
<record id="im_livechat_mail_channel_data_5" model="mail.channel">
<record id="im_livechat_discuss_channel_data_5" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_admin"/>
@@ -286,48 +286,48 @@
</record>
<record id="im_livechat_rating_6" model="rating.rating">
<field name="access_token">LIVECHAT_6</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_5"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_5')], 5, 'LIVECHAT_6', None, 'Good Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_5')], 5, 'LIVECHAT_6', None, 'Good Job')"/>
<record id="im_livechat_mail_message_25_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_5"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Thanks!</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=25)" name="date"/>
</record>
<record id="im_livechat_mail_message_24_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_5"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Yes, of course, you can find it here: https://www.odoo.com/documentation/master/</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=24)" name="date"/>
</record>
<record id="im_livechat_mail_message_23_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_5"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Hello, I'm a bit lost in the Invetory module, is there some documentation I could find?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=23)" name="date"/>
</record>
<record id="im_livechat_mail_message_22_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_5"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-5, minutes=22)" name="date"/>
</record>
<!-- Session 6 -->
<record id="im_livechat_mail_channel_data_6" model="mail.channel">
<record id="im_livechat_discuss_channel_data_6" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_admin"/>
@@ -336,48 +336,48 @@
</record>
<record id="im_livechat_rating_7" model="rating.rating">
<field name="access_token">LIVECHAT_7</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_6"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_6')], 5, 'LIVECHAT_7', None, 'Super Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_6')], 5, 'LIVECHAT_7', None, 'Super Job')"/>
<record id="im_livechat_mail_message_29_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_6"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Good to hear, thanks!</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=29)" name="date"/>
</record>
<record id="im_livechat_mail_message_28_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_6"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Joel Willis, you'll need our Inventory and Sales application to do so. You can try them for 15 days, FOR FREE :)</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=28)" name="date"/>
</record>
<record id="im_livechat_mail_message_27_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_6"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo_portal"/>
<field name="body">Hi, I need a software to easily manage my stock, and generate sales orders.</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=27)" name="date"/>
</record>
<record id="im_livechat_mail_message_26_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_6"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_admin"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-6, minutes=26)" name="date"/>
</record>
<!-- Session 7 -->
<record id="im_livechat_mail_channel_data_7" model="mail.channel">
<record id="im_livechat_discuss_channel_data_7" model="discuss.channel">
<field name="channel_type">livechat</field>
<field name="livechat_channel_id" ref="im_livechat_channel_data"/>
<field name="livechat_operator_id" ref="base.partner_demo"/>
@@ -386,48 +386,48 @@
</record>
<record id="im_livechat_rating_8" model="rating.rating">
<field name="access_token">LIVECHAT_8</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_7"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_7')], 5, 'LIVECHAT_8', None, 'Super Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_discuss_channel_data_7')], 5, 'LIVECHAT_8', None, 'Super Job')"/>
<record id="im_livechat_mail_message_33_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_7"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">I'm great, thanks for asking!</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=33)" name="date"/>
</record>
<record id="im_livechat_mail_message_32_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_7"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">I'm fine, and you?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=32)" name="date"/>
</record>
<record id="im_livechat_mail_message_31_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_7"/>
<field name="message_type">email</field>
<field eval="False" name="author_id"/>
<field name="body">Heeeey Marc, how are you?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=31)" name="date"/>
</record>
<record id="im_livechat_mail_message_30_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="model">discuss.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_discuss_channel_data_7"/>
<field name="message_type">email</field>
<field name="author_id" ref="base.partner_demo"/>
<field name="body">Hello, how may I help you?</field>
<field eval="DateTime.today() + relativedelta(months=-3, days=-7, minutes=30)" name="date"/>
</record>
<record id="mail_channel_livechat_1" model="mail.channel">
<record id="discuss_channel_livechat_1" model="discuss.channel">
<field name="name">Visitor, Mitchell Admin</field>
<field name="livechat_operator_id" ref="base.partner_admin"/>
<field name="livechat_channel_id" ref="im_livechat.im_livechat_channel_data"/>
@@ -441,16 +441,16 @@
<field name="date" eval="datetime.now() - timedelta(days=1)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1)"/>
<field name="body">Hi</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="mail_message_livechat_2" model="mail.message">
<field name="author_id" ref="base.partner_admin"/>
<field name="date" eval="datetime.now() - timedelta(days=1, seconds=-15)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-15)"/>
<field name="body">Hello, how may I help you?</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="mail_message_livechat_3" model="mail.message">
<field name="author_id" eval="False"/>
@@ -458,16 +458,16 @@
<field name="date" eval="datetime.now() - timedelta(days=1, seconds=-25)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-25)"/>
<field name="body">I would like to know more about the CRM application</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="mail_message_livechat_4" model="mail.message">
<field name="author_id" ref="base.partner_admin"/>
<field name="date" eval="datetime.now() - timedelta(days=1, seconds=-33)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-33)"/>
<field name="body">The CRM application helps you to track leads, close opportunities and get accurate forecasts. You can test it for free on our website.</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="mail_message_livechat_5" model="mail.message">
<field name="author_id" eval="False"/>
@@ -475,8 +475,8 @@
<field name="date" eval="datetime.now() - timedelta(days=1, seconds=-42)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-42)"/>
<field name="body">Great, thanks!</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="mail_message_livechat_6" model="mail.message">
<field name="author_id" eval="False"/>
@@ -484,19 +484,19 @@
<field name="date" eval="datetime.now() - timedelta(days=1, seconds=-53)"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-53)"/>
<field name="body">Rating: :-)</field>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
<field name="model">discuss.channel</field>
</record>
<record id="rating_rating_livechat_1" model="rating.rating">
<field name="access_token">LIVECHAT_9</field>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="res_model_id" ref="mail.model_discuss_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_admin"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-53)"/>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="res_id" ref="im_livechat.discuss_channel_livechat_1"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.mail_channel_livechat_1')], 5, 'LIVECHAT_9', None, 'Super Job')"/>
<function model="discuss.channel" name="rating_apply"
eval="([ref('im_livechat.discuss_channel_livechat_1')], 5, 'LIVECHAT_9', None, 'Super Job')"/>
</data>
</odoo>
+2 -2
View File
@@ -7,8 +7,8 @@ from . import chatbot_script_step
from . import res_users
from . import res_partner
from . import im_livechat_channel
from . import mail_channel
from . import mail_channel_member
from . import discuss_channel
from . import discuss_channel_member
from . import mail_message
from . import res_users_settings
from . import rating_rating
+2 -2
View File
@@ -13,10 +13,10 @@ class ChatbotMailMessage(models.Model):
_name = 'chatbot.message'
_description = 'Chatbot Message'
_order = 'create_date desc, id desc'
_rec_name = 'mail_channel_id'
_rec_name = 'discuss_channel_id'
mail_message_id = fields.Many2one('mail.message', string='Related Mail Message', required=True, ondelete="cascade")
mail_channel_id = fields.Many2one('mail.channel', string='Discussion Channel', required=True, ondelete="cascade")
discuss_channel_id = fields.Many2one('discuss.channel', string='Discussion Channel', required=True, ondelete="cascade")
script_step_id = fields.Many2one(
'chatbot.script.step', string='Chatbot Step', required=True, ondelete='cascade')
user_script_answer_id = fields.Many2one('chatbot.script.answer', string="User's answer", ondelete="set null")
+7 -7
View File
@@ -135,7 +135,7 @@ class ChatbotScript(models.Model):
end user.
This is important because we need to display those welcoming steps in a special fashion on
the frontend, since those are not inserted into the mail.channel as actual mail.messages,
the frontend, since those are not inserted into the discuss.channel as actual mail.messages,
to avoid bloating the channels with bot messages if the end-user never interacts with it. """
self.ensure_one()
@@ -147,21 +147,21 @@ class ChatbotScript(models.Model):
return welcome_steps
def _post_welcome_steps(self, mail_channel):
def _post_welcome_steps(self, discuss_channel):
""" Welcome messages are only posted after the visitor's first interaction with the chatbot.
See 'chatbot.script#_get_welcome_steps()' for more details.
Side note: it is important to set the 'chatbot_current_step_id' on each iteration so that
it's correctly set when going into 'mail_channel#_message_post_after_hook()'. """
it's correctly set when going into 'discuss_channel#_message_post_after_hook()'. """
self.ensure_one()
posted_messages = self.env['mail.message']
for welcome_step in self._get_welcome_steps():
mail_channel.chatbot_current_step_id = welcome_step.id
discuss_channel.chatbot_current_step_id = welcome_step.id
if not is_html_empty(welcome_step.message):
posted_messages += mail_channel.with_context(mail_create_nosubscribe=True).message_post(
posted_messages += discuss_channel.with_context(mail_create_nosubscribe=True).message_post(
author_id=self.operator_partner_id.id,
body=plaintext2html(welcome_step.message),
message_type='comment',
@@ -194,7 +194,7 @@ class ChatbotScript(models.Model):
]
}
def _validate_email(self, email_address, mail_channel):
def _validate_email(self, email_address, discuss_channel):
email_address = html2plaintext(email_address)
email_normalized = email_normalize(email_address)
@@ -205,7 +205,7 @@ class ChatbotScript(models.Model):
"'%(input_email)s' does not look like a valid email. Can you please try again?",
input_email=email_address
)
posted_message = mail_channel._chatbot_post_message(self, plaintext2html(error_message))
posted_message = discuss_channel._chatbot_post_message(self, plaintext2html(error_message))
return {
'success': bool(email_normalized),
@@ -120,24 +120,24 @@ class ChatbotScriptStep(models.Model):
# Business Methods
# --------------------------
def _chatbot_prepare_customer_values(self, mail_channel, create_partner=True, update_partner=True):
""" Common method that allows retreiving default customer values from the mail.channel
def _chatbot_prepare_customer_values(self, discuss_channel, create_partner=True, update_partner=True):
""" Common method that allows retreiving default customer values from the discuss.channel
following a chatbot.script.
This method will return a dict containing the 'customer' values such as:
{
'partner': The created partner (see 'create_partner') or the partner from the
environment if not public
'email': The email extracted from the mail.channel messages
'email': The email extracted from the discuss.channel messages
(see step_type 'question_email')
'phone': The phone extracted from the mail.channel messages
'phone': The phone extracted from the discuss.channel messages
(see step_type 'question_phone')
'description': A default description containing the "Please contact me on" and "Please
call me on" with the related email and phone numbers.
Can be used as a default description to create leads or tickets for example.
}
:param record mail_channel: the mail.channel holding the visitor's conversation with the bot.
:param record discuss_channel: the discuss.channel holding the visitor's conversation with the bot.
:param bool create_partner: whether or not to create a res.partner is the current user is public.
Defaults to True.
:param bool update_partner: whether or not to set update the email and phone on the res.partner
@@ -146,7 +146,7 @@ class ChatbotScriptStep(models.Model):
:return dict: a dict containing the customer values."""
partner = False
user_inputs = mail_channel._chatbot_find_customer_values_in_messages({
user_inputs = discuss_channel._chatbot_find_customer_values_in_messages({
'question_email': 'email',
'question_phone': 'phone',
})
@@ -254,18 +254,18 @@ class ChatbotScriptStep(models.Model):
return step
return self.env['chatbot.script.step']
def _is_last_step(self, mail_channel=False):
def _is_last_step(self, discuss_channel=False):
self.ensure_one()
mail_channel = mail_channel or self.env['mail.channel']
discuss_channel = discuss_channel or self.env['discuss.channel']
# if it's not a question and if there is no next step, then we end the script
if self.step_type != 'question_selection' and not self._fetch_next_step(
mail_channel.chatbot_message_ids.user_script_answer_id):
discuss_channel.chatbot_message_ids.user_script_answer_id):
return True
return False
def _process_answer(self, mail_channel, message_body):
def _process_answer(self, discuss_channel, message_body):
""" Method called when the user reacts to the current chatbot.script step.
For most chatbot.script.step#step_types it simply returns the next chatbot.script.step of
the script (see '_fetch_next_step').
@@ -274,7 +274,7 @@ class ChatbotScriptStep(models.Model):
we store the user raw answer (the mail message HTML body) into the chatbot.message in order
to be able to recover it later (see '_chatbot_prepare_customer_values').
:param mail_channel:
:param discuss_channel:
:param message_body:
:return: script step to display next
:rtype: 'chatbot.script.step' """
@@ -288,7 +288,7 @@ class ChatbotScriptStep(models.Model):
if self.step_type in ['question_email', 'question_phone']:
chatbot_message = self.env['chatbot.message'].search([
('mail_channel_id', '=', mail_channel.id),
('discuss_channel_id', '=', discuss_channel.id),
('script_step_id', '=', self.id),
], limit=1)
@@ -296,9 +296,9 @@ class ChatbotScriptStep(models.Model):
chatbot_message.write({'user_raw_answer': message_body})
self.env.flush_all()
return self._fetch_next_step(mail_channel.chatbot_message_ids.user_script_answer_id)
return self._fetch_next_step(discuss_channel.chatbot_message_ids.user_script_answer_id)
def _process_step(self, mail_channel):
def _process_step(self, discuss_channel):
""" When we reach a chatbot.step in the script we need to do some processing on behalf of
the bot. Which is for most chatbot.script.step#step_types just posting the message field.
@@ -310,14 +310,14 @@ class ChatbotScriptStep(models.Model):
self.ensure_one()
# We change the current step to the new step
mail_channel.chatbot_current_step_id = self.id
discuss_channel.chatbot_current_step_id = self.id
if self.step_type == 'forward_operator':
return self._process_step_forward_operator(mail_channel)
return self._process_step_forward_operator(discuss_channel)
return mail_channel._chatbot_post_message(self.chatbot_script_id, plaintext2html(self.message))
return discuss_channel._chatbot_post_message(self.chatbot_script_id, plaintext2html(self.message))
def _process_step_forward_operator(self, mail_channel):
def _process_step_forward_operator(self, discuss_channel):
""" Special type of step that will add a human operator to the conversation when reached,
which stops the script and allow the visitor to discuss with a real person.
@@ -328,28 +328,28 @@ class ChatbotScriptStep(models.Model):
human_operator = False
posted_message = False
if mail_channel.livechat_channel_id:
human_operator = mail_channel.livechat_channel_id._get_random_operator()
if discuss_channel.livechat_channel_id:
human_operator = discuss_channel.livechat_channel_id._get_random_operator()
# handle edge case where we found yourself as available operator -> don't do anything
# it will act as if no-one is available (which is fine)
if human_operator and human_operator != self.env.user:
mail_channel.sudo().add_members(
discuss_channel.sudo().add_members(
human_operator.partner_id.ids,
open_chat_window=True,
post_joined_message=False)
if self.message:
# first post the message of the step (if we have one)
posted_message = mail_channel._chatbot_post_message(self.chatbot_script_id, plaintext2html(self.message))
posted_message = discuss_channel._chatbot_post_message(self.chatbot_script_id, plaintext2html(self.message))
# then post a small custom 'Operator has joined' notification
mail_channel._chatbot_post_message(
discuss_channel._chatbot_post_message(
self.chatbot_script_id,
Markup('<div class="o_mail_notification">%s</div>') % _('%s has joined', human_operator.partner_id.name))
mail_channel._broadcast(human_operator.partner_id.ids)
mail_channel.channel_pin(pinned=True)
discuss_channel._broadcast(human_operator.partner_id.ids)
discuss_channel.channel_pin(pinned=True)
return posted_message
+2 -2
View File
@@ -15,7 +15,7 @@ class Digest(models.Model):
kpi_livechat_response_value = fields.Float(digits=(16, 2), compute='_compute_kpi_livechat_response_value')
def _compute_kpi_livechat_rating_value(self):
channels = self.env['mail.channel'].search([('channel_type', '=', 'livechat')])
channels = self.env['discuss.channel'].search([('channel_type', '=', 'livechat')])
start, end, __ = self._get_kpi_compute_parameters()
domain = [
('create_date', '>=', start),
@@ -29,7 +29,7 @@ class Digest(models.Model):
def _compute_kpi_livechat_conversations_value(self):
start, end, __ = self._get_kpi_compute_parameters()
self.kpi_livechat_conversations_value = self.env['mail.channel'].search_count([
self.kpi_livechat_conversations_value = self.env['discuss.channel'].search_count([
('channel_type', '=', 'livechat'),
('create_date', '>=', start), ('create_date', '<', end),
])
@@ -7,14 +7,14 @@ from odoo.tools import email_normalize, html_escape, html2plaintext, plaintext2h
from markupsafe import Markup
class MailChannel(models.Model):
class DiscussChannel(models.Model):
""" Chat Session
Reprensenting a conversation between users.
It extends the base method for anonymous usage.
"""
_name = 'mail.channel'
_inherit = ['rating.mixin', 'mail.channel']
_name = 'discuss.channel'
_inherit = ['rating.mixin', 'discuss.channel']
anonymous_name = fields.Char('Anonymous Name')
channel_type = fields.Selection(selection_add=[('livechat', 'Livechat Conversation')], ondelete={'livechat': 'cascade'})
@@ -22,20 +22,20 @@ class MailChannel(models.Model):
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel')
livechat_operator_id = fields.Many2one('res.partner', string='Operator')
chatbot_current_step_id = fields.Many2one('chatbot.script.step', string='Chatbot Current Step')
chatbot_message_ids = fields.One2many('chatbot.message', 'mail_channel_id', string='Chatbot Messages')
chatbot_message_ids = fields.One2many('chatbot.message', 'discuss_channel_id', string='Chatbot Messages')
country_id = fields.Many2one('res.country', string="Country", help="Country of the visitor of the channel")
_sql_constraints = [('livechat_operator_id', "CHECK((channel_type = 'livechat' and livechat_operator_id is not null) or (channel_type != 'livechat'))",
'Livechat Operator ID is required for a channel of type livechat.')]
def _compute_is_chat(self):
super(MailChannel, self)._compute_is_chat()
super()._compute_is_chat()
for record in self:
if record.channel_type == 'livechat':
record.is_chat = True
def _channel_message_notifications(self, message, message_format=False):
""" When a anonymous user create a mail.channel, the operator is not notify (to avoid massive polling when
""" When a anonymous user create a discuss.channel, the operator is not notify (to avoid massive polling when
clicking on livechat button). So when the anonymous person is sending its FIRST message, the channel header
should be added to the notification, since the user cannot be listining to the channel.
"""
@@ -43,7 +43,7 @@ class MailChannel(models.Model):
for channel in self:
# add uuid to allow anonymous to listen
if channel.channel_type == 'livechat':
notifications.append([channel.uuid, 'mail.channel/new_message', notifications[0][2]])
notifications.append([channel.uuid, 'discuss.channel/new_message', notifications[0][2]])
if not message.author_id:
unpinned_members = self.channel_member_ids.filtered(lambda member: not member.is_pinned)
if unpinned_members:
@@ -74,11 +74,11 @@ class MailChannel(models.Model):
hours = 1 # never remove empty session created within the last hour
self.env.cr.execute("""
SELECT id as id
FROM mail_channel C
FROM discuss_channel C
WHERE NOT EXISTS (
SELECT 1
FROM mail_message M
WHERE M.res_id = C.id AND m.model = 'mail.channel'
WHERE M.res_id = C.id AND m.model = 'discuss.channel'
) AND C.channel_type = 'livechat' AND livechat_channel_id IS NOT NULL AND
COALESCE(write_date, create_date, (now() at time zone 'UTC'))::timestamp
< ((now() at time zone 'UTC') - interval %s)""", ("%s hours" % hours,))
@@ -86,7 +86,7 @@ class MailChannel(models.Model):
self.browse(empty_channel_ids).unlink()
def _execute_command_help_message_extra(self):
msg = super(MailChannel, self)._execute_command_help_message_extra()
msg = super()._execute_command_help_message_extra()
if self.channel_type == 'livechat':
return msg + _("Type <b>:shortcut</b> to insert a canned response in your message.<br>")
return msg
@@ -222,10 +222,10 @@ class MailChannel(models.Model):
if self.chatbot_current_step_id:
self.env['chatbot.message'].sudo().create({
'mail_message_id': message.id,
'mail_channel_id': self.id,
'discuss_channel_id': self.id,
'script_step_id': self.chatbot_current_step_id.id,
})
return super(MailChannel, self)._message_post_after_hook(message, msg_vals)
return super()._message_post_after_hook(message, msg_vals)
def _chatbot_restart(self, chatbot_script):
self.write({
@@ -6,20 +6,20 @@ from odoo import api, models
class ChannelMember(models.Model):
_inherit = 'mail.channel.member'
_inherit = 'discuss.channel.member'
@api.autovacuum
def _gc_unpin_livechat_sessions(self):
""" Unpin read livechat sessions with no activity for at least one day to
clean the operator's interface """
members = self.env['mail.channel.member'].search([
members = self.env['discuss.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])
self.env['bus.bus']._sendmany([(member.partner_id, 'discuss.channel/unpin', {'id': member.channel_id.id}) for member in sessions_to_be_unpinned])
def _get_partner_data(self, fields=None):
if self.channel_id.channel_type == 'livechat':
@@ -56,7 +56,7 @@ class ImLivechatChannel(models.Model):
# relationnal fields
user_ids = fields.Many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string='Operators', default=_default_user_ids)
channel_ids = fields.One2many('mail.channel', 'livechat_channel_id', 'Sessions')
channel_ids = fields.One2many('discuss.channel', 'livechat_channel_id', 'Sessions')
chatbot_script_count = fields.Integer(string='Number of Chatbot', compute='_compute_chatbot_script_count')
rule_ids = fields.One2many('im_livechat.channel.rule', 'channel_id', 'Rules')
@@ -87,7 +87,7 @@ class ImLivechatChannel(models.Model):
@api.depends('channel_ids')
def _compute_nbr_channel(self):
data = self.env['mail.channel']._read_group([
data = self.env['discuss.channel']._read_group([
('livechat_channel_id', 'in', self._ids),
('has_message', '=', True)], ['livechat_channel_id'], ['__count'])
channel_count = {livechat_channel.id: count for livechat_channel, count in data}
@@ -137,8 +137,8 @@ class ImLivechatChannel(models.Model):
self.ensure_one()
return self.user_ids.filtered(lambda user: user.im_status == 'online')
def _get_livechat_mail_channel_vals(self, anonymous_name, operator=None, chatbot_script=None, user_id=None, country_id=None):
# partner to add to the mail.channel
def _get_livechat_discuss_channel_vals(self, anonymous_name, operator=None, chatbot_script=None, user_id=None, country_id=None):
# partner to add to the discuss.channel
operator_partner_id = operator.partner_id.id if operator else chatbot_script.operator_partner_id.id
members_to_add = [Command.create({'partner_id': operator_partner_id, 'is_pinned': False})]
visitor_user = False
@@ -167,8 +167,8 @@ class ImLivechatChannel(models.Model):
'name': name,
}
def _open_livechat_mail_channel(self, anonymous_name, previous_operator_id=None, chatbot_script=None, user_id=None, country_id=None, persisted=True):
""" Return a livechat session. If the session is persisted, creates a mail.channel record with a connected operator or with Odoobot as
def _open_livechat_discuss_channel(self, anonymous_name, previous_operator_id=None, chatbot_script=None, user_id=None, country_id=None, persisted=True):
""" Return a livechat session. If the session is persisted, creates a discuss.channel record with a connected operator or with Odoobot as
an operator if a chatbot has been configured, or return false otherwise
:param anonymous_name : the name of the anonymous person of the session
:param previous_operator_id : partner_id.id of the previous operator that this visitor had in the past
@@ -199,19 +199,19 @@ class ImLivechatChannel(models.Model):
if not user_operator and not chatbot_script:
# no one available
return False
mail_channel_vals = self._get_livechat_mail_channel_vals(anonymous_name, user_operator, chatbot_script, user_id=user_id, country_id=country_id)
discuss_channel_vals = self._get_livechat_discuss_channel_vals(anonymous_name, user_operator, chatbot_script, user_id=user_id, country_id=country_id)
if persisted:
# create the session, and add the link with the given channel
mail_channel = self.env["mail.channel"].with_context(mail_create_nosubscribe=False).sudo().create(mail_channel_vals)
discuss_channel = self.env["discuss.channel"].with_context(mail_create_nosubscribe=False).sudo().create(discuss_channel_vals)
if user_operator:
mail_channel._broadcast([user_operator.partner_id.id])
return mail_channel.sudo().channel_info()[0]
discuss_channel._broadcast([user_operator.partner_id.id])
return discuss_channel.sudo().channel_info()[0]
else:
operator_partner_id = user_operator.partner_id if user_operator else chatbot_script.operator_partner_id
display_name = operator_partner_id.user_livechat_username or operator_partner_id.display_name
return {
'name': mail_channel_vals['name'],
'chatbot_current_step_id': mail_channel_vals['chatbot_current_step_id'],
'name': discuss_channel_vals['name'],
'chatbot_current_step_id': discuss_channel_vals['chatbot_current_step_id'],
'state': 'open',
'operator_pid': (operator_partner_id.id, display_name.replace(',', '')),
'chatbot_script_id': chatbot_script.id if chatbot_script else None
@@ -222,7 +222,7 @@ class ImLivechatChannel(models.Model):
A livechat is considered 'active' if it has at least one message within the 30 minutes.
(Some annoying conversions have to be made on the fly because this model holds 'res.users' as available operators
and the mail_channel model stores the partner_id of the randomly selected operator)
and the discuss_channel model stores the partner_id of the randomly selected operator)
:return : user
:rtype : res.users
@@ -232,8 +232,8 @@ class ImLivechatChannel(models.Model):
return False
self.env.cr.execute("""SELECT COUNT(DISTINCT c.id), c.livechat_operator_id
FROM mail_channel c
LEFT OUTER JOIN mail_message m ON c.id = m.res_id AND m.model = 'mail.channel'
FROM discuss_channel c
LEFT OUTER JOIN mail_message m ON c.id = m.res_id AND m.model = 'discuss.channel'
WHERE c.channel_type = 'livechat'
AND c.livechat_operator_id in %s
AND m.create_date > ((now() at time zone 'UTC') - interval '30 minutes')
+4 -4
View File
@@ -20,8 +20,8 @@ class MailMessage(models.Model):
vals_list = super()._message_format(fnames=fnames, format_reply=format_reply, legacy=legacy)
for vals in vals_list:
message_sudo = self.browse(vals['id']).sudo().with_prefetch(self.ids)
mail_channel = self.env['mail.channel'].browse(message_sudo.res_id) if message_sudo.model == 'mail.channel' else self.env['mail.channel']
if mail_channel.channel_type == 'livechat':
discuss_channel = self.env['discuss.channel'].browse(message_sudo.res_id) if message_sudo.model == 'discuss.channel' else self.env['discuss.channel']
if discuss_channel.channel_type == 'livechat':
if message_sudo.author_id:
vals.pop('email_from')
if message_sudo.author_id.user_livechat_username:
@@ -29,8 +29,8 @@ class MailMessage(models.Model):
'id': message_sudo.author_id.id,
'user_livechat_username': message_sudo.author_id.user_livechat_username,
}
if mail_channel.chatbot_current_step_id \
and message_sudo.author_id == mail_channel.chatbot_current_step_id.chatbot_script_id.operator_partner_id:
if discuss_channel.chatbot_current_step_id \
and message_sudo.author_id == discuss_channel.chatbot_current_step_id.chatbot_script_id.operator_partner_id:
chatbot_message_id = self.env['chatbot.message'].sudo().search([
('mail_message_id', '=', message_sudo.id)], limit=1)
if chatbot_message_id.script_step_id:
+3 -3
View File
@@ -13,7 +13,7 @@ class Rating(models.Model):
for rating in self:
# cannot change the rec_name of session since it is use to create the bus channel
# so, need to override this method to set the same alternative rec_name as in reporting
if rating.res_model == 'mail.channel':
if rating.res_model == 'discuss.channel':
current_object = self.env[rating.res_model].sudo().browse(rating.res_id)
rating.res_name = ('%s / %s') % (current_object.livechat_channel_id.name, current_object.id)
else:
@@ -21,7 +21,7 @@ class Rating(models.Model):
def action_open_rated_object(self):
action = super(Rating, self).action_open_rated_object()
if self.res_model == 'mail.channel':
view_id = self.env.ref('im_livechat.mail_channel_view_form').id
if self.res_model == 'discuss.channel':
view_id = self.env.ref('im_livechat.discuss_channel_view_form').id
action['views'] = [[view_id, 'form']]
return action
+2 -2
View File
@@ -11,9 +11,9 @@ class Partners(models.Model):
def _get_channels_as_member(self):
channels = super()._get_channels_as_member()
channels |= self.env['mail.channel'].search([
channels |= self.env['discuss.channel'].search([
('channel_type', '=', 'livechat'),
('channel_member_ids', 'in', self.env['mail.channel.member'].sudo()._search([
('channel_member_ids', 'in', self.env['discuss.channel.member'].sudo()._search([
('partner_id', '=', self.id),
('is_pinned', '=', True),
])),
@@ -13,7 +13,7 @@ class ImLivechatReportChannel(models.Model):
_auto = False
uuid = fields.Char('UUID', readonly=True)
channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
channel_id = fields.Many2one('discuss.channel', 'Conversation', readonly=True)
channel_name = fields.Char('Channel Name', readonly=True)
technical_name = fields.Char('Code', readonly=True)
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
@@ -62,7 +62,7 @@ class ImLivechatReportChannel(models.Model):
WHEN EXISTS (select distinct M.author_id FROM mail_message M
WHERE M.author_id=C.livechat_operator_id
AND M.res_id = C.id
AND M.model = 'mail.channel'
AND M.model = 'discuss.channel'
AND C.livechat_operator_id = M.author_id)
THEN 0
ELSE 1
@@ -89,11 +89,11 @@ class ImLivechatReportChannel(models.Model):
ELSE 1
END as is_unrated,
C.livechat_operator_id as partner_id
FROM mail_channel C
JOIN mail_message M ON (M.res_id = C.id AND M.model = 'mail.channel')
FROM discuss_channel C
JOIN mail_message M ON (M.res_id = C.id AND M.model = 'discuss.channel')
JOIN im_livechat_channel L ON (L.id = C.livechat_channel_id)
LEFT JOIN mail_message MO ON (MO.res_id = C.id AND MO.model = 'mail.channel' AND MO.author_id = C.livechat_operator_id)
LEFT JOIN rating_rating Rate ON (Rate.res_id = C.id and Rate.res_model = 'mail.channel' and Rate.parent_res_model = 'im_livechat.channel')
LEFT JOIN mail_message MO ON (MO.res_id = C.id AND MO.model = 'discuss.channel' AND MO.author_id = C.livechat_operator_id)
LEFT JOIN rating_rating Rate ON (Rate.res_id = C.id and Rate.res_model = 'discuss.channel' and Rate.parent_res_model = 'im_livechat.channel')
WHERE C.livechat_operator_id is not null
GROUP BY C.livechat_operator_id, C.id, C.name, C.livechat_channel_id, L.name, C.create_date, C.uuid, Rate.rating
)
@@ -15,7 +15,7 @@ class ImLivechatReportOperator(models.Model):
partner_id = fields.Many2one('res.partner', 'Operator', readonly=True)
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
nbr_channel = fields.Integer('# of Sessions', readonly=True, group_operator="sum")
channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
channel_id = fields.Many2one('discuss.channel', 'Conversation', readonly=True)
start_date = fields.Datetime('Start Date of session', readonly=True)
time_to_answer = fields.Float('Time to answer', digits=(16, 2), readonly=True, group_operator="avg", help="Average time to give the first answer to the visitor")
duration = fields.Float('Average duration', digits=(16, 2), readonly=True, group_operator="avg", help="Duration of the conversation (in seconds)")
@@ -34,9 +34,9 @@ class ImLivechatReportOperator(models.Model):
C.create_date AS start_date,
EXTRACT('epoch' FROM MAX(M.create_date) - MIN(M.create_date)) AS duration,
EXTRACT('epoch' FROM MIN(MO.create_date) - MIN(M.create_date)) AS time_to_answer
FROM mail_channel C
JOIN mail_message M ON M.res_id = C.id AND M.model = 'mail.channel'
LEFT JOIN mail_message MO ON (MO.res_id = C.id AND MO.model = 'mail.channel' AND MO.author_id = C.livechat_operator_id)
FROM discuss_channel C
JOIN mail_message M ON M.res_id = C.id AND M.model = 'discuss.channel'
LEFT JOIN mail_message MO ON (MO.res_id = C.id AND MO.model = 'discuss.channel' AND MO.author_id = C.livechat_operator_id)
WHERE C.livechat_channel_id IS NOT NULL
GROUP BY C.id, C.livechat_operator_id
)
@@ -21,9 +21,9 @@
</record>
<data noupdate="1">
<record id="im_livechat_rule_manager_read_all_mail_channel" model="ir.rule">
<record id="im_livechat_rule_manager_read_all_discuss_channel" model="ir.rule">
<field name="name">Livechat: Administrator: read all livechat channel</field>
<field name="model_id" ref="model_mail_channel"/>
<field name="model_id" ref="mail.model_discuss_channel"/>
<field name="groups" eval="[(4, ref('im_livechat_group_manager'))]"/>
<field name="domain_force">[('channel_type', '=', 'livechat')]</field>
<field name="perm_read" eval="True"/>
@@ -3,7 +3,7 @@
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
registry.category("mail.channel_commands").add("history", {
registry.category("discuss.channel_commands").add("history", {
channel_types: ["livechat"],
help: _t("See 15 last visited pages"),
methodName: "execute_command_history",
@@ -14,7 +14,7 @@ patch(Messaging.prototype, "im_livechat", {
_handleNotificationLastInterestDtChanged(notif) {
this._super(notif);
const channel = this.store.threads[createLocalId("mail.channel", notif.payload.id)];
const channel = this.store.threads[createLocalId("discuss.channel", notif.payload.id)];
if (channel?.type === "livechat") {
this.threadService.sortChannels();
}
@@ -62,9 +62,9 @@ LivechatButton.include({
* (See chatbot.script#_get_welcome_steps() for more details).
*
* It is important that those messages are sent as "welcome messages", meaning manually added
* within the template, without creating actual mail.messages in the mail.channel.
* within the template, without creating actual mail.messages in the discuss.channel.
*
* Indeed, if the end-user never interacts with the bot, those empty mail.channels are deleted
* Indeed, if the end-user never interacts with the bot, those empty discuss.channels are deleted
* by a garbage collector mechanism.
*
* About "welcomeMessageDelay":
@@ -72,7 +72,7 @@ LivechatButton.include({
* The first time we open the chat, we want to bot to slowly input those messages in one at a
* time, with pauses during which the end-user sees ("The bot is typing...").
*
* However, if the user navigates within the website (meaning he has an opened mail.channel),
* However, if the user navigates within the website (meaning he has an opened discuss.channel),
* then we input all the welcome messages at once without pauses, to avoid having that annoying
* slow effect on every page / refresh.
*
@@ -96,7 +96,7 @@ LivechatButton.include({
chatbot_script_step_id: chatbotStep.chatbot_script_step_id,
chatbot_step_answers: chatbotStep.chatbot_step_answers,
date: time.datetime_to_str(new Date()),
model: "mail.channel",
model: "discuss.channel",
message_type: "comment",
res_id: this.messaging.publicLivechatGlobal.publicLivechat.id,
});
@@ -127,7 +127,7 @@ Model({
},
/**
* Called when the visitor leaves the livechat chatter the first time (first click on X button)
* this will deactivate the mail_channel, notify operator that visitor has left the channel.
* this will deactivate the discuss_channel, notify operator that visitor has left the channel.
*/
leaveSession() {
const cookie = getCookie("im_livechat_session");
@@ -40,7 +40,7 @@ Model({
});
return;
}
case "mail.channel.member/typing_status": {
case "discuss.channel.member/typing_status": {
if (
!this.messaging.publicLivechatGlobal.chatWindow ||
!this.messaging.publicLivechatGlobal.chatWindow.exists()
@@ -75,7 +75,7 @@ Model({
}
return;
}
case "mail.channel/new_message": {
case "discuss.channel/new_message": {
if (
!this.messaging.publicLivechatGlobal.chatWindow ||
!this.messaging.publicLivechatGlobal.chatWindow.exists()
@@ -64,7 +64,7 @@ const LivechatButton = Widget.extend({
},
body: this.messaging.publicLivechatGlobal.livechatButtonView.defaultMessage,
date: time.datetime_to_str(new Date()),
model: "mail.channel",
model: "discuss.channel",
res_id: this.messaging.publicLivechatGlobal.publicLivechat.id,
},
{ prepend: true }
@@ -432,7 +432,7 @@ const PublicLivechatView = Widget.extend({
ev.preventDefault();
const model = $(ev.target).data("oe-model");
let options;
if (model && model !== "mail.channel") {
if (model && model !== "discuss.channel") {
options = {
model,
id,
@@ -6,7 +6,7 @@ QUnit.module("chat window (patch)");
QUnit.test("No call buttons", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -27,7 +27,7 @@ QUnit.test("closing a chat window with no message from admin side unpins it", as
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Demo" });
pyEnv["res.users"].create({ partner_id: partnerId });
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
channel_member_ids: [
[
0,
@@ -46,7 +46,7 @@ QUnit.test("closing a chat window with no message from admin side unpins it", as
await click(".o_menu_systray i[aria-label='Messages']");
await click(".o-mail-NotificationItem");
await click(".o-mail-ChatWindow-header .o-mail-ChatWindow-command[title='Close chat window']");
const channels = await env.services.orm.silent.call("mail.channel", "channel_info", [
const channels = await env.services.orm.silent.call("discuss.channel", "channel_info", [
channelId,
]);
assert.strictEqual(channels[0].is_pinned, false, "Livechat channel should not be pinned");
@@ -14,7 +14,7 @@ QUnit.module("composer (patch)");
QUnit.test("No add attachments button", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
name: "Livechat 1",
channel_type: "livechat",
});
@@ -28,7 +28,7 @@ QUnit.test("Attachment upload via drag and drop disabled", async (assert) => {
assert.expect(2);
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
name: "Livechat 1",
channel_type: "livechat",
});
@@ -42,7 +42,7 @@ QUnit.test("Attachment upload via drag and drop disabled", async (assert) => {
QUnit.test("Can execute help command on livechat channels", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -70,7 +70,7 @@ QUnit.test("Can execute help command on livechat channels", async (assert) => {
QUnit.test('Receives visitor typing status "is typing"', async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 20",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -82,7 +82,7 @@ QUnit.test('Receives visitor typing status "is typing"', async (assert) => {
const { env, openDiscuss } = await start();
await openDiscuss(channelId);
assert.strictEqual($(".o-mail-Typing").text(), "");
const channel = pyEnv["mail.channel"].searchRead([["id", "=", channelId]])[0];
const channel = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0];
// simulate receive typing notification from livechat visitor "is typing"
await afterNextRender(() =>
env.services.rpc("/im_livechat/notify_typing", {
@@ -96,7 +96,7 @@ QUnit.test('Receives visitor typing status "is typing"', async (assert) => {
QUnit.test('display canned response suggestions on typing ":"', async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Mario",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -118,7 +118,7 @@ QUnit.test('display canned response suggestions on typing ":"', async (assert) =
QUnit.test("use a canned response", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Mario",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -147,7 +147,7 @@ QUnit.test("use a canned response", async (assert) => {
QUnit.test("use a canned response some text", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Mario",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -178,7 +178,7 @@ QUnit.test("use a canned response some text", async (assert) => {
QUnit.test("add an emoji after a canned response", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 20",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -12,7 +12,7 @@ QUnit.module("discuss (patch)");
QUnit.test("No call buttons", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -29,7 +29,7 @@ QUnit.test("No call buttons", async (assert) => {
QUnit.test("No reaction button", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_type: "livechat",
livechat_operator_id: pyEnv.currentPartnerId,
@@ -37,7 +37,7 @@ QUnit.test("No reaction button", async (assert) => {
});
pyEnv["mail.message"].create({
body: "not empty",
model: "mail.channel",
model: "discuss.channel",
res_id: channelId,
});
const { openDiscuss } = await start();
@@ -48,7 +48,7 @@ QUnit.test("No reaction button", async (assert) => {
QUnit.test("No reply button", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_type: "livechat",
livechat_operator_id: pyEnv.currentPartnerId,
@@ -56,7 +56,7 @@ QUnit.test("No reply button", async (assert) => {
});
pyEnv["mail.message"].create({
body: "not empty",
model: "mail.channel",
model: "discuss.channel",
res_id: channelId,
});
const { openDiscuss } = await start();
@@ -72,7 +72,7 @@ QUnit.test("add livechat in the sidebar on visitor sending first message", async
const livechatChannelId = pyEnv["im_livechat.channel"].create({
user_ids: [pyEnv.currentUserId],
});
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor (Belgium)",
channel_member_ids: [
[0, 0, { is_pinned: false, partner_id: pyEnv.currentPartnerId }],
@@ -87,7 +87,7 @@ QUnit.test("add livechat in the sidebar on visitor sending first message", async
await openDiscuss();
assert.containsNone($, ".o-mail-DiscussCategory-livechat");
// simulate livechat visitor sending a message
const [channel] = pyEnv["mail.channel"].searchRead([["id", "=", channelId]]);
const [channel] = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]]);
await afterNextRender(async () =>
env.services.rpc("/mail/chat_post", {
context: { mockedUserId: false },
@@ -105,7 +105,7 @@ QUnit.test("add livechat in the sidebar on visitor sending first message", async
QUnit.test("reaction button should not be present on livechat", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_type: "livechat",
livechat_operator_id: pyEnv.currentPartnerId,
@@ -121,7 +121,7 @@ QUnit.test("reaction button should not be present on livechat", async (assert) =
QUnit.test("invite button should be present on livechat", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -139,7 +139,7 @@ QUnit.test(
"livechats are sorted by last activity time in the sidebar: most recent at the top",
async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create([
pyEnv["discuss.channel"].create([
{
anonymous_name: "Visitor 11",
channel_member_ids: [
@@ -60,7 +60,7 @@ patch(MockServer.prototype, "im_livechat/controllers/main", {
anonymous_name = anonymous_name + " (" + country.name + ")";
}
}
return this._mockImLivechatChannel_openLivechatMailChannel(
return this._mockImLivechatChannel_openLivechatDiscussChannel(
channel_id,
anonymous_name,
previous_operator_id,
@@ -77,12 +77,12 @@ patch(MockServer.prototype, "im_livechat/controllers/main", {
* @param {Object} [context={}]
*/
_mockRouteImLivechatNotifyTyping(uuid, is_typing, context = {}) {
const [mailChannel] = this.getRecords("mail.channel", [["uuid", "=", uuid]]);
const [discussChannel] = this.getRecords("discuss.channel", [["uuid", "=", uuid]]);
const partnerId = context.mockedPartnerId || this.currentPartnerId;
const [memberOfCurrentUser] = this.getRecords("mail.channel.member", [
["channel_id", "=", mailChannel.id],
const [memberOfCurrentUser] = this.getRecords("discuss.channel.member", [
["channel_id", "=", discussChannel.id],
["partner_id", "=", partnerId],
]);
this._mockMailChannelMember_NotifyTyping([memberOfCurrentUser.id], is_typing);
this._mockDiscussChannelMember_NotifyTyping([memberOfCurrentUser.id], is_typing);
},
});
@@ -1,18 +1,18 @@
/** @odoo-module **/
import "@mail/../tests/helpers/mock_server/models/mail_channel"; // ensure mail overrides are applied first
import "@mail/../tests/helpers/mock_server/models/discuss_channel"; // ensure mail overrides are applied first
import { patch } from "@web/core/utils/patch";
import { MockServer } from "@web/../tests/helpers/mock_server";
patch(MockServer.prototype, "im_livechat/models/mail_channel", {
patch(MockServer.prototype, "im_livechat/models/discuss_channel", {
/**
* @override
*/
_mockMailChannelChannelInfo(ids) {
_mockDiscussChannelChannelInfo(ids) {
const channelInfos = this._super(...arguments);
for (const channelInfo of channelInfos) {
const channel = this.getRecords("mail.channel", [["id", "=", channelInfo.id]])[0];
const channel = this.getRecords("discuss.channel", [["id", "=", channelInfo.id]])[0];
channelInfo["channel"]["anonymous_name"] = channel.anonymous_name;
// add the last message date
if (channel.channel_type === "livechat") {
@@ -1,17 +1,17 @@
/** @odoo-module **/
import "@mail/../tests/helpers/mock_server/models/mail_channel_member"; // ensure mail overrides are applied first
import "@mail/../tests/helpers/mock_server/models/discuss_channel_member"; // ensure mail overrides are applied first
import { patch } from "@web/core/utils/patch";
import { MockServer } from "@web/../tests/helpers/mock_server";
patch(MockServer.prototype, "im_livechat/models/mail_channel_member", {
patch(MockServer.prototype, "im_livechat/models/discuss_channel_member", {
/**
* @override
*/
_mockMailChannelMember_GetPartnerData(ids) {
const [member] = this.getRecords("mail.channel.member", [["id", "in", ids]]);
const [channel] = this.getRecords("mail.channel", [["id", "=", member.channel_id]]);
_mockDiscussChannelMember_GetPartnerData(ids) {
const [member] = this.getRecords("discuss.channel.member", [["id", "in", ids]]);
const [channel] = this.getRecords("discuss.channel", [["id", "=", member.channel_id]]);
const [partner] = this.getRecords("res.partner", [["id", "=", member.partner_id]], {
active_test: false,
});
@@ -17,20 +17,20 @@ patch(MockServer.prototype, "im_livechat/models/im_livechat_channel", {
return users.filter((user) => user.im_status === "online");
},
/**
* Simulates `_get_livechat_mail_channel_vals` on `im_livechat.channel`.
* Simulates `_get_livechat_discuss_channel_vals` on `im_livechat.channel`.
*
* @private
* @param {integer} id
* @returns {Object}
*/
_mockImLivechatChannel_getLivechatMailChannelVals(
_mockImLivechatChannel_getLivechatDiscussChannelVals(
id,
anonymous_name,
operator,
user_id,
country_id
) {
// partner to add to the mail.channel
// partner to add to the discuss.channel
const operator_partner_id = operator.partner_id;
const membersToAdd = [
[
@@ -80,7 +80,7 @@ patch(MockServer.prototype, "im_livechat/models/im_livechat_channel", {
return availableUsers[0];
},
/**
* Simulates `_open_livechat_mail_channel` on `im_livechat.channel`.
* Simulates `_open_livechat_discuss_channel` on `im_livechat.channel`.
*
* @private
* @param {integer} id
@@ -90,7 +90,7 @@ patch(MockServer.prototype, "im_livechat/models/im_livechat_channel", {
* @param {integer} [country_id]
* @returns {Object}
*/
_mockImLivechatChannel_openLivechatMailChannel(
_mockImLivechatChannel_openLivechatDiscussChannel(
id,
anonymous_name,
previous_operator_id,
@@ -110,15 +110,15 @@ patch(MockServer.prototype, "im_livechat/models/im_livechat_channel", {
return false;
}
// create the session, and add the link with the given channel
const mailChannelVals = this._mockImLivechatChannel_getLivechatMailChannelVals(
const discussChannelVals = this._mockImLivechatChannel_getLivechatDiscussChannelVals(
id,
anonymous_name,
operator,
user_id,
country_id
);
const mailChannelId = this.pyEnv["mail.channel"].create(mailChannelVals);
this._mockMailChannel_broadcast([mailChannelId], [operator.partner_id]);
return this._mockMailChannelChannelInfo([mailChannelId])[0];
const discussChannelId = this.pyEnv["discuss.channel"].create(discussChannelVals);
this._mockDiscussChannel_broadcast([discussChannelId], [operator.partner_id]);
return this._mockDiscussChannelChannelInfo([discussChannelId])[0];
},
});
@@ -11,11 +11,11 @@ patch(MockServer.prototype, "im_livechat/models/res_partner", {
*/
_mockResPartner_GetChannelsAsMember(ids) {
const partner = this.getRecords("res.partner", [["id", "in", ids]])[0];
const members = this.getRecords("mail.channel.member", [
const members = this.getRecords("discuss.channel.member", [
["partner_id", "=", partner.id],
["is_pinned", "=", true],
]);
const livechats = this.getRecords("mail.channel", [
const livechats = this.getRecords("discuss.channel", [
["channel_type", "=", "livechat"],
["channel_member_ids", "in", members.map((member) => member.id)],
]);
@@ -6,7 +6,7 @@ QUnit.module("messaging menu (patch)");
QUnit.test('livechats should be in "chat" filter', async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -11,11 +11,11 @@ QUnit.module("messaging service (patch)");
QUnit.test("Notify message received out of focus", async (assert) => {
const pyEnv = await startServer();
const senderId = pyEnv["res.users"].create({ name: "Bob" });
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
name: "Livechat 1",
channel_type: "livechat",
});
const [channel] = pyEnv["mail.channel"].searchRead([["id", "=", channelId]]);
const [channel] = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]]);
const { env } = await start({
services: {
notification: makeFakeNotificationService((message, { title }) => {
@@ -20,7 +20,7 @@ QUnit.test(
"Livechat button is present when there is at least one livechat thread",
async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -9,7 +9,7 @@ QUnit.module("discuss sidebar (patch)");
QUnit.test("Unknown visitor", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -34,7 +34,7 @@ QUnit.test("Known user with country", async (assert) => {
country_id: countryId,
name: "Jean",
});
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -53,7 +53,7 @@ QUnit.test("Do not show channel when visitor is typing", async (assert) => {
const livechatChannelId = pyEnv["im_livechat.channel"].create({
user_ids: [pyEnv.currentUserId],
});
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
channel_member_ids: [
[
0,
@@ -73,7 +73,7 @@ QUnit.test("Do not show channel when visitor is typing", async (assert) => {
await openDiscuss();
assert.containsNone($, ".o-mail-DiscussCategory-livechat");
// simulate livechat visitor typing
const channel = pyEnv["mail.channel"].searchRead([["id", "=", channelId]])[0];
const channel = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0];
await env.services.rpc("/im_livechat/notify_typing", {
context: {
mockedPartnerId: pyEnv.publicPartnerId,
@@ -87,7 +87,7 @@ QUnit.test("Do not show channel when visitor is typing", async (assert) => {
QUnit.test("Close should update the value on the server", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -120,7 +120,7 @@ QUnit.test("Close should update the value on the server", async (assert) => {
QUnit.test("Open should update the value on the server", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -153,7 +153,7 @@ QUnit.test("Open should update the value on the server", async (assert) => {
QUnit.test("Open from the bus", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -182,7 +182,7 @@ QUnit.test("Open from the bus", async (assert) => {
QUnit.test("Close from the bus", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -211,7 +211,7 @@ QUnit.test("Close from the bus", async (assert) => {
QUnit.test("Smiley face avatar for an anonymous livechat item", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -231,7 +231,7 @@ QUnit.test("Smiley face avatar for an anonymous livechat item", async (assert) =
QUnit.test("Partner profile picture for livechat item linked to a partner", async (assert) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Jean" });
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
@@ -249,7 +249,7 @@ QUnit.test("Partner profile picture for livechat item linked to a partner", asyn
QUnit.test("No counter if the category is unfolded and with unread messages", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[
@@ -276,7 +276,7 @@ QUnit.test("No counter if the category is unfolded and with unread messages", as
QUnit.test("No counter if category is folded and without unread messages", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -302,7 +302,7 @@ QUnit.test(
"Counter should have correct value of unread threads if category is folded and with unread messages",
async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[
@@ -333,7 +333,7 @@ QUnit.test(
QUnit.test("Close manually by clicking the title", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -360,7 +360,7 @@ QUnit.test("Close manually by clicking the title", async (assert) => {
QUnit.test("Open manually by clicking the title", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -387,7 +387,7 @@ QUnit.test("Open manually by clicking the title", async (assert) => {
QUnit.test("Category item should be invisible if the category is closed", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -407,7 +407,7 @@ QUnit.test(
"Active category item should be visible even if the category is closed",
async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -431,7 +431,7 @@ QUnit.test(
QUnit.test("Clicking on unpin button unpins the channel", async (assert) => {
const pyEnv = await startServer();
pyEnv["mail.channel"].create({
pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -454,7 +454,7 @@ QUnit.test("Message unread counter", async (assert) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Harry" });
const userId = pyEnv["res.users"].create({ name: "Harry", partner_id: partnerId });
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 11",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -469,7 +469,7 @@ QUnit.test("Message unread counter", async (assert) => {
env.services.rpc("/mail/chat_post", {
context: { mockedUserId: userId },
message_content: "hu",
uuid: pyEnv["mail.channel"].searchRead([["id", "=", channelId]])[0].uuid,
uuid: pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0].uuid,
})
);
assert.containsOnce($, ".o-mail-DiscussCategoryItem .badge:contains(1)");
@@ -6,7 +6,7 @@ QUnit.module("thread icon (patch)");
QUnit.test("Public website visitor is typing", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["mail.channel"].create({
const channelId = pyEnv["discuss.channel"].create({
anonymous_name: "Visitor 20",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
@@ -18,7 +18,7 @@ QUnit.test("Public website visitor is typing", async (assert) => {
const { env, openDiscuss } = await start();
await openDiscuss(channelId);
assert.containsOnce($, ".o-mail-ThreadIcon .fa.fa-comments");
const channel = pyEnv["mail.channel"].searchRead([["id", "=", channelId]])[0];
const channel = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0];
// simulate receive typing notification from livechat visitor "is typing"
await afterNextRender(() =>
env.services.rpc("/im_livechat/notify_typing", {
+1 -1
View File
@@ -5,7 +5,7 @@ from . import chatbot_common
from . import test_chatbot_form_ui
from . import test_chatbot_internals
from . import test_digest
from . import test_get_mail_channel
from . import test_get_discuss_channel
from . import test_im_livechat_report
from . import test_im_livechat_support_page
from . import test_message
+4 -4
View File
@@ -134,12 +134,12 @@ class ChatbotCase(common.TransactionCase):
})
@classmethod
def _post_answer_and_trigger_next_step(cls, mail_channel, answer, chatbot_script_answer=False):
mail_message = mail_channel.message_post(body=answer)
def _post_answer_and_trigger_next_step(cls, discuss_channel, answer, chatbot_script_answer=False):
mail_message = discuss_channel.message_post(body=answer)
if chatbot_script_answer:
cls.env['chatbot.message'].search([
('mail_message_id', '=', mail_message.id)
], limit=1).user_script_answer_id = chatbot_script_answer.id
next_step = mail_channel.chatbot_current_step_id._process_answer(mail_channel, mail_message.body)
next_step._process_step(mail_channel)
next_step = discuss_channel.chatbot_current_step_id._process_answer(discuss_channel, mail_message.body)
next_step._process_step(discuss_channel)
@@ -44,24 +44,24 @@ class ChatbotCase(chatbot_common.ChatbotCase):
"Only step 'step_no_one_available' should be flagged as forward operator child.")
def test_chatbot_steps(self):
channel_info = self.livechat_channel._open_livechat_mail_channel(
channel_info = self.livechat_channel._open_livechat_discuss_channel(
anonymous_name='Test Visitor', chatbot_script=self.chatbot_script)
mail_channel = self.env['mail.channel'].browse(channel_info['id'])
discuss_channel = self.env['discuss.channel'].browse(channel_info['id'])
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_dispatch)
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_dispatch)
self._post_answer_and_trigger_next_step(
mail_channel,
discuss_channel,
self.step_dispatch_buy_software.name,
chatbot_script_answer=self.step_dispatch_buy_software
)
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_email)
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_email)
with self.assertRaises(ValidationError, msg="Should raise an error since it's not a valid email"):
self._post_answer_and_trigger_next_step(mail_channel, 'test')
self._post_answer_and_trigger_next_step(discuss_channel, 'test')
self._post_answer_and_trigger_next_step(mail_channel, 'test@example.com')
self.assertEqual(mail_channel.chatbot_current_step_id, self.step_email_validated)
self._post_answer_and_trigger_next_step(discuss_channel, 'test@example.com')
self.assertEqual(discuss_channel.chatbot_current_step_id, self.step_email_validated)
def test_chatbot_steps_sequence(self):
""" Ensure sequence is correct when creating chatbots and adding steps to an existing one.
+5 -5
View File
@@ -16,7 +16,7 @@ class TestLiveChatDigest(TestDigestCommon):
other_partner = cls.env['res.partner'].create({'name': 'Other Partner'})
cls.channels = cls.env['mail.channel'].create([{
cls.channels = cls.env['discuss.channel'].create([{
'name': 'Channel 1',
'livechat_operator_id': cls.env.user.partner_id.id,
'channel_type': 'livechat',
@@ -35,25 +35,25 @@ class TestLiveChatDigest(TestDigestCommon):
cls.env['rating.rating'].create([{
'rated_partner_id': cls.env.user.partner_id.id,
'res_id': cls.channels[0].id,
'res_model_id': cls.env['ir.model']._get('mail.channel').id,
'res_model_id': cls.env['ir.model']._get('discuss.channel').id,
'consumed': True,
'rating': 5,
}, {
'rated_partner_id': cls.env.user.partner_id.id,
'res_id': cls.channels[0].id,
'res_model_id': cls.env['ir.model']._get('mail.channel').id,
'res_model_id': cls.env['ir.model']._get('discuss.channel').id,
'consumed': True,
'rating': 0,
}, {
'rated_partner_id': cls.env.user.partner_id.id,
'res_id': cls.channels[0].id,
'res_model_id': cls.env['ir.model']._get('mail.channel').id,
'res_model_id': cls.env['ir.model']._get('discuss.channel').id,
'consumed': True,
'rating': 3,
}, {
'rated_partner_id': cls.env.user.partner_id.id,
'res_id': cls.channels[0].id,
'res_model_id': cls.env['ir.model']._get('mail.channel').id,
'res_model_id': cls.env['ir.model']._get('discuss.channel').id,
'consumed': True,
'rating': 3,
}])
@@ -7,15 +7,15 @@ from odoo import fields
from odoo.addons.im_livechat.tests.common import TestImLivechatCommon
class TestGetMailChannel(TestImLivechatCommon):
def test_get_mail_channel(self):
class TestGetDiscussChannel(TestImLivechatCommon):
def test_get_discuss_channel(self):
"""For a livechat with 5 available operators, we open 5 channels 5 times (25 channels total).
For every 5 channels opening, we check that all operators were assigned.
"""
for i in range(5):
mail_channels = self._open_livechat_mail_channel()
channel_operators = [channel_info['operator_pid'] for channel_info in mail_channels]
discuss_channels = self._open_livechat_discuss_channel()
channel_operators = [channel_info['operator_pid'] for channel_info in discuss_channels]
channel_operator_ids = [channel_operator[0] for channel_operator in channel_operators]
self.assertTrue(all(partner_id in channel_operator_ids for partner_id in self.operators.mapped('partner_id').ids))
@@ -26,7 +26,7 @@ class TestGetMailChannel(TestImLivechatCommon):
# ensure visitor info are correct with anonymous
operator = self.operators[0]
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='Visitor 22', previous_operator_id=operator.partner_id.id, country_id=belgium.id)
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_discuss_channel(anonymous_name='Visitor 22', previous_operator_id=operator.partner_id.id, country_id=belgium.id)
self.assertEqual(channel_info['channel']['anonymous_name'], "Visitor 22")
self.assertEqual(channel_info['channel']['anonymous_country'], {'code': 'BE', 'id': belgium.id, 'name': 'Belgium'})
@@ -46,13 +46,13 @@ class TestGetMailChannel(TestImLivechatCommon):
}], key=lambda m: m['id']))
# ensure visitor info are correct with real user
channel_info = self.livechat_channel.with_user(test_user)._open_livechat_mail_channel(anonymous_name='whatever', previous_operator_id=operator.partner_id.id, user_id=test_user.id)
channel_info = self.livechat_channel.with_user(test_user)._open_livechat_discuss_channel(anonymous_name='whatever', previous_operator_id=operator.partner_id.id, user_id=test_user.id)
self.assertFalse(channel_info['channel']['anonymous_name'])
self.assertEqual(channel_info['channel']['anonymous_country'], [('clear',)])
self.assertEqual(channel_info['channel']['channelMembers'], [('insert', [
{
'channel': {'id': channel_info['id']},
'id': self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id,
'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id,
'persona': {
'partner': {
'active': True,
@@ -65,7 +65,7 @@ class TestGetMailChannel(TestImLivechatCommon):
},
{
'channel': {'id': channel_info['id']},
'id': self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', test_user.partner_id.id)]).id,
'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', test_user.partner_id.id)]).id,
'persona': {
'partner': {
'active': True,
@@ -84,14 +84,14 @@ class TestGetMailChannel(TestImLivechatCommon):
# ensure visitor info are correct when operator is testing themselves
operator = self.operators[0]
channel_info = self.livechat_channel.with_user(operator)._open_livechat_mail_channel(anonymous_name='whatever', previous_operator_id=operator.partner_id.id, user_id=operator.id)
channel_info = self.livechat_channel.with_user(operator)._open_livechat_discuss_channel(anonymous_name='whatever', previous_operator_id=operator.partner_id.id, user_id=operator.id)
self.assertEqual(channel_info['operator_pid'], (operator.partner_id.id, "Michel Operator"))
self.assertFalse(channel_info['channel']['anonymous_name'])
self.assertEqual(channel_info['channel']['anonymous_country'], [('clear',)])
self.assertEqual(channel_info['channel']['channelMembers'], [('insert', [
{
'channel': {'id': channel_info['id']},
'id': self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id,
'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id,
'persona': {
'partner': {
'active': True,
@@ -104,24 +104,24 @@ class TestGetMailChannel(TestImLivechatCommon):
},
])])
def _open_livechat_mail_channel(self):
mail_channels = []
def _open_livechat_discuss_channel(self):
discuss_channels = []
for i in range(5):
mail_channel = self.livechat_channel._open_livechat_mail_channel('Anonymous')
mail_channels.append(mail_channel)
discuss_channel = self.livechat_channel._open_livechat_discuss_channel('Anonymous')
discuss_channels.append(discuss_channel)
# send a message to mark this channel as 'active'
self.env['mail.channel'].browse(mail_channel['id']).message_post(body='cc')
self.env['discuss.channel'].browse(discuss_channel['id']).message_post(body='cc')
return mail_channels
return discuss_channels
def test_channel_not_pinned_for_operator_before_first_message(self):
public_user = self.env.ref('base.public_user')
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='whatever')
operator_channel_member = self.env['mail.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)])
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_discuss_channel(anonymous_name='whatever')
operator_channel_member = self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)])
self.assertEqual(len(operator_channel_member), 1, "operator should be member of channel")
self.assertFalse(operator_channel_member.is_pinned, "channel should not be pinned for operator initially")
self.env['mail.channel'].browse(channel_info['id']).message_post(body='cc')
self.env['discuss.channel'].browse(channel_info['id']).message_post(body='cc')
self.assertTrue(operator_channel_member.is_pinned, "channel should be pinned for operator after visitor sent a message")
self.assertIn(channel_info['id'], operator_channel_member.partner_id._get_channels_as_member().ids, "channel should be fetched by operator on new page")
@@ -134,8 +134,8 @@ class TestGetMailChannel(TestImLivechatCommon):
'email': 'michel@example.com',
'livechat_username': 'Michel at your service',
})
channel_info = self.livechat_channel.with_user(public_user).sudo()._open_livechat_mail_channel(anonymous_name='whatever')
channel = self.env['mail.channel'].browse(channel_info['id'])
channel_info = self.livechat_channel.with_user(public_user).sudo()._open_livechat_discuss_channel(anonymous_name='whatever')
channel = self.env['discuss.channel'].browse(channel_info['id'])
channel.with_user(operator).message_post(body='Hello', message_type='comment', subtype_xmlid='mail.mt_comment')
message_formats = channel.with_user(public_user).sudo()._channel_fetch_message()
self.assertEqual(len(message_formats), 1)
@@ -145,9 +145,9 @@ class TestGetMailChannel(TestImLivechatCommon):
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')
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_discuss_channel(anonymous_name='visitor')
member_of_operator = self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)])
message = self.env['discuss.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)
@@ -157,9 +157,9 @@ class TestGetMailChannel(TestImLivechatCommon):
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')
channel_info = self.livechat_channel.with_user(public_user)._open_livechat_discuss_channel(anonymous_name='visitor')
member_of_operator = self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', 'in', self.operators.partner_id.ids)])
self.env['discuss.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")
@@ -10,12 +10,12 @@ class TestImLivechatReport(TestImLivechatCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env['mail.channel'].search([('livechat_channel_id', '!=', False)]).unlink()
cls.env['discuss.channel'].search([('livechat_channel_id', '!=', False)]).unlink()
with patch.object(type(cls.env['im_livechat.channel']), '_get_available_users', lambda _: cls.operators):
channel_id = cls.livechat_channel._open_livechat_mail_channel('Anonymous')['id']
channel_id = cls.livechat_channel._open_livechat_discuss_channel('Anonymous')['id']
channel = cls.env['mail.channel'].browse(channel_id)
channel = cls.env['discuss.channel'].browse(channel_id)
cls.operator = channel.livechat_operator_id
cls._create_message(channel, cls.visitor_user.partner_id, '2023-03-17 06:05:54')
+3 -3
View File
@@ -28,9 +28,9 @@ class TestImLivechatMessage(TransactionCase):
def test_message_format(self):
im_livechat_channel = self.env['im_livechat.channel'].sudo().create({'name': 'support', 'user_ids': [Command.link(self.users[0].id)]})
self.users[0].im_status = 'online' # make available for livechat (ignore leave)
channel_livechat_1 = self.env['mail.channel'].browse(im_livechat_channel._open_livechat_mail_channel(anonymous_name='anon 1', previous_operator_id=self.users[0].partner_id.id, user_id=self.users[1].id, country_id=self.env.ref('base.in').id)['id'])
channel_livechat_1 = self.env['discuss.channel'].browse(im_livechat_channel._open_livechat_discuss_channel(anonymous_name='anon 1', previous_operator_id=self.users[0].partner_id.id, user_id=self.users[1].id, country_id=self.env.ref('base.in').id)['id'])
record_rating = self.env['rating.rating'].create({
'res_model_id': self.env['ir.model']._get('mail.channel').id,
'res_model_id': self.env['ir.model']._get('discuss.channel').id,
'res_id': channel_livechat_1.id,
'parent_res_model_id': self.env['ir.model']._get('im_livechat.channel').id,
'parent_res_id': im_livechat_channel.id,
@@ -62,7 +62,7 @@ class TestImLivechatMessage(TransactionCase):
'linkPreviews': [],
'message_type': 'notification',
'messageReactionGroups': [],
'model': 'mail.channel',
'model': 'discuss.channel',
'module_icon': '/mail/static/description/icon.png',
'needaction_partner_ids': [],
'notifications': [],
@@ -2,9 +2,9 @@
<odoo>
<data>
<record id="mail_channel_view_search" model="ir.ui.view">
<field name="name">mail.channel.search</field>
<field name="model">mail.channel</field>
<record id="discuss_channel_view_search" model="ir.ui.view">
<field name="name">discuss.channel.search</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<search string="Search history">
<field name="name"/>
@@ -17,9 +17,9 @@
</field>
</record>
<record id="mail_channel_view_tree" model="ir.ui.view">
<field name="name">mail.channel.tree</field>
<field name="model">mail.channel</field>
<record id="discuss_channel_view_tree" model="ir.ui.view">
<field name="name">discuss.channel.tree</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<tree string="History" create="false" default_order="create_date desc">
<field name="create_date" string="Session Date"/>
@@ -30,9 +30,9 @@
</field>
</record>
<record id="mail_channel_view_form" model="ir.ui.view">
<field name="name">mail.channel.form</field>
<field name="model">mail.channel</field>
<record id="discuss_channel_view_form" model="ir.ui.view">
<field name="name">discuss.channel.form</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<form string="Session Form" create="false" edit="false">
<sheet>
@@ -95,11 +95,11 @@
</record>
<record id="mail_channel_action" model="ir.actions.act_window">
<record id="discuss_channel_action" model="ir.actions.act_window">
<field name="name">History</field>
<field name="res_model">mail.channel</field>
<field name="res_model">discuss.channel</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="im_livechat.mail_channel_view_search"/>
<field name="search_view_id" ref="im_livechat.discuss_channel_view_search"/>
<field name="domain">[('livechat_channel_id', '!=', None)]</field>
<field name="context">{'search_default_session_not_empty': 1}</field>
<field name="help" type="html">
@@ -110,44 +110,44 @@
</p>
</field>
</record>
<record id="mail_channel_action_tree" model="ir.actions.act_window.view">
<record id="discuss_channel_action_tree" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="im_livechat.mail_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action"/>
<field name="view_id" ref="im_livechat.discuss_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="mail_channel_action_form" model="ir.actions.act_window.view">
<record id="discuss_channel_action_form" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.mail_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action"/>
<field name="view_id" ref="im_livechat.discuss_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="mail_channel_action_from_livechat_channel" model="ir.actions.act_window">
<record id="discuss_channel_action_from_livechat_channel" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">mail.channel</field>
<field name="res_model">discuss.channel</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('livechat_channel_id', 'in', [active_id]), ('has_message', '=', True)]</field>
<field name="context">{
'search_default_livechat_channel_id': [active_id],
'default_livechat_channel_id': active_id,
}</field>
<field name="search_view_id" ref="mail_channel_view_search"/>
<field name="search_view_id" ref="discuss_channel_view_search"/>
</record>
<record id="mail_channel_action_livechat_tree" model="ir.actions.act_window.view">
<record id="discuss_channel_action_livechat_tree" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="im_livechat.mail_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action_from_livechat_channel"/>
<field name="view_id" ref="im_livechat.discuss_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="mail_channel_action_livechat_form" model="ir.actions.act_window.view">
<record id="discuss_channel_action_livechat_form" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.mail_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action_from_livechat_channel"/>
<field name="view_id" ref="im_livechat.discuss_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
@@ -79,7 +79,7 @@
attrs="{'invisible': [('chatbot_script_count', '=', 0)]}">
<field string="Chatbots" name="chatbot_script_count" widget="statinfo"/>
</button>
<button class="oe_stat_button" type="action" attrs="{'invisible':[('nbr_channel','=', 0)]}" name="%(mail_channel_action_from_livechat_channel)d" icon="fa-comments">
<button class="oe_stat_button" type="action" attrs="{'invisible':[('nbr_channel','=', 0)]}" name="%(discuss_channel_action_from_livechat_channel)d" icon="fa-comments">
<field string="Sessions" name="nbr_channel" widget="statinfo"/>
</button>
<button name="action_view_rating" attrs="{'invisible':[('rating_count', '=', 0)]}" class="oe_stat_button" type="object" icon="fa-smile-o">
@@ -299,7 +299,7 @@
id="session_history"
name="Sessions History"
parent="menu_reporting_livechat"
action="mail_channel_action"
action="discuss_channel_action"
groups="im_livechat_group_user"
sequence="5"/>
+7 -7
View File
@@ -2,7 +2,7 @@
{
'name': 'Discuss',
'version': '1.12',
'version': '1.13',
'category': 'Productivity/Discuss',
'sequence': 145,
'summary': 'Chat, mail gateway and private channels',
@@ -78,10 +78,10 @@ For more specific needs, you may also assign custom-defined actions
'views/mail_mail_views.xml',
'views/mail_followers_views.xml',
'views/mail_ice_server_views.xml',
'views/mail_channel_member_views.xml',
'views/mail_channel_rtc_session_views.xml',
'views/discuss_channel_member_views.xml',
'views/discuss_channel_rtc_session_views.xml',
'views/mail_link_preview_views.xml',
'views/mail_channel_views.xml',
'views/discuss_channel_views.xml',
'views/mail_shortcode_views.xml',
'views/mail_activity_views.xml',
'views/res_config_settings_views.xml',
@@ -90,7 +90,7 @@ For more specific needs, you may also assign custom-defined actions
'data/mail_templates_chatter.xml',
'data/mail_templates_email_layouts.xml',
'data/mail_templates_mailgateway.xml',
'data/mail_channel_data.xml',
'data/discuss_channel_data.xml',
'data/mail_activity_data.xml',
'data/security_notifications_templates.xml',
'data/ir_cron_data.xml',
@@ -111,7 +111,7 @@ For more specific needs, you may also assign custom-defined actions
'views/mail_menus.xml',
],
'demo': [
'data/mail_channel_demo.xml',
'data/discuss_channel_demo.xml',
],
'installable': True,
'application': True,
@@ -137,7 +137,7 @@ For more specific needs, you may also assign custom-defined actions
'mail.assets_discuss_public_test_tours': [
'web/static/tests/legacy/helpers/test_utils_file.js',
'mail/static/tests/tours/discuss_public_tour.js',
'mail/static/tests/tours/mail_channel_as_guest_tour.js',
'mail/static/tests/tours/discuss_channel_as_guest_tour.js',
],
'web.assets_tests': [
'mail/static/tests/tours/**/*',
+5 -5
View File
@@ -20,8 +20,8 @@ class MailChatController(BusController):
# --------------------------
@route('/mail/chat_post', type="json", auth="public", cors="*")
def mail_chat_post(self, uuid, message_content, **kwargs):
mail_channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
if not mail_channel:
channel = request.env["discuss.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
if not channel:
return False
# find the author from the user session
@@ -31,10 +31,10 @@ class MailChatController(BusController):
email_from = author.email_formatted
else: # If Public User, use catchall email from company
author_id = False
email_from = mail_channel.anonymous_name or mail_channel.create_uid.company_id.catchall_formatted
email_from = channel.anonymous_name or channel.create_uid.company_id.catchall_formatted
# post a message without adding followers to the channel. email_from=False avoid to get author from email data
body = tools.plaintext2html(message_content)
message = mail_channel.with_context(mail_create_nosubscribe=True).message_post(
message = channel.with_context(mail_create_nosubscribe=True).message_post(
author_id=author_id,
email_from=email_from,
body=body,
@@ -45,7 +45,7 @@ class MailChatController(BusController):
@route(['/mail/chat_history'], type="json", auth="public", cors="*")
def mail_chat_history(self, uuid, last_id=False, limit=20):
channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
channel = request.env["discuss.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
if not channel:
return []
else:
+56 -56
View File
@@ -38,20 +38,20 @@ class DiscussController(http.Controller):
@http.route('/chat/<int:channel_id>/<string:invitation_token>', methods=['GET'], type='http', auth='public')
def discuss_channel_invitation(self, channel_id, invitation_token, **kwargs):
channel_sudo = request.env['mail.channel'].browse(channel_id).sudo().exists()
channel_sudo = request.env['discuss.channel'].browse(channel_id).sudo().exists()
if not channel_sudo or not channel_sudo.uuid or not consteq(channel_sudo.uuid, invitation_token):
raise NotFound()
return self._response_discuss_channel_invitation(channel_sudo=channel_sudo)
@http.route('/discuss/channel/<int:channel_id>', methods=['GET'], type='http', auth='public')
def discuss_channel(self, channel_id, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return self._response_discuss_public_template(channel_sudo=channel_member_sudo.channel_id)
def _response_discuss_channel_from_token(self, create_token, channel_name=None, default_display_mode=False):
if not request.env['ir.config_parameter'].sudo().get_param('mail.chat_from_token'):
raise NotFound()
channel_sudo = request.env['mail.channel'].sudo().search([('uuid', '=', create_token)])
channel_sudo = request.env['discuss.channel'].sudo().search([('uuid', '=', create_token)])
if not channel_sudo:
try:
channel_sudo = channel_sudo.create({
@@ -77,7 +77,7 @@ class DiscussController(http.Controller):
'isChannelTokenSecret': is_channel_token_secret,
}
add_guest_cookie = False
channel_member_sudo = channel_sudo.env['mail.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_sudo.id)
channel_member_sudo = channel_sudo.env['discuss.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_sudo.id)
if channel_member_sudo:
channel_sudo = channel_member_sudo.channel_id # ensure guest is in context
else:
@@ -123,7 +123,7 @@ class DiscussController(http.Controller):
'data': {
'channelData': channel_sudo.channel_info()[0],
'discussPublicViewData': dict({
'channel': [('insert', {'id': channel_sudo.id, 'model': 'mail.channel'})],
'channel': [('insert', {'id': channel_sudo.id, 'model': 'discuss.channel'})],
'shouldDisplayWelcomeViewInitially': channel_sudo.default_display_mode == 'video_full_screen',
}, **discuss_public_view_data),
},
@@ -134,50 +134,50 @@ class DiscussController(http.Controller):
# Semi-Static Content (GET requests with possible cache)
# --------------------------------------------------------------------------
@http.route('/mail/channel/<int:channel_id>/partner/<int:partner_id>/avatar_128', methods=['GET'], type='http', auth='public')
def mail_channel_partner_avatar_128(self, channel_id, partner_id, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
@http.route('/discuss/channel/<int:channel_id>/partner/<int:partner_id>/avatar_128', methods=['GET'], type='http', auth='public')
def discuss_channel_partner_avatar_128(self, channel_id, partner_id, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
partner_sudo = channel_member_sudo.env['res.partner'].browse(partner_id).exists()
placeholder = partner_sudo._avatar_get_placeholder_path()
if channel_member_sudo and channel_member_sudo.env['mail.channel.member'].search([('channel_id', '=', channel_id), ('partner_id', '=', partner_id)], limit=1):
if channel_member_sudo and channel_member_sudo.env['discuss.channel.member'].search([('channel_id', '=', channel_id), ('partner_id', '=', partner_id)], limit=1):
return request.env['ir.binary']._get_image_stream_from(partner_sudo, field_name='avatar_128', placeholder=placeholder).get_response()
if request.env.user.share:
return request.env['ir.binary']._get_placeholder_stream(placeholder).get_response()
return request.env['ir.binary']._get_image_stream_from(partner_sudo.sudo(False), field_name='avatar_128', placeholder=placeholder).get_response()
@http.route('/mail/channel/<int:channel_id>/guest/<int:guest_id>/avatar_128', methods=['GET'], type='http', auth='public')
def mail_channel_guest_avatar_128(self, channel_id, guest_id, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
@http.route('/discuss/channel/<int:channel_id>/guest/<int:guest_id>/avatar_128', methods=['GET'], type='http', auth='public')
def discuss_channel_guest_avatar_128(self, channel_id, guest_id, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
guest_sudo = channel_member_sudo.env['mail.guest'].browse(guest_id).exists()
placeholder = guest_sudo._avatar_get_placeholder_path()
if channel_member_sudo and channel_member_sudo.env['mail.channel.member'].search([('channel_id', '=', channel_id), ('guest_id', '=', guest_id)], limit=1):
if channel_member_sudo and channel_member_sudo.env['discuss.channel.member'].search([('channel_id', '=', channel_id), ('guest_id', '=', guest_id)], limit=1):
return request.env['ir.binary']._get_image_stream_from(guest_sudo, field_name='avatar_128', placeholder=placeholder).get_response()
if request.env.user.share:
return request.env['ir.binary']._get_placeholder_stream(placeholder).get_response()
return request.env['ir.binary']._get_image_stream_from(guest_sudo.sudo(False), field_name='avatar_128', placeholder=placeholder).get_response()
@http.route('/mail/channel/<int:channel_id>/attachment/<int:attachment_id>', methods=['GET'], type='http', auth='public')
def mail_channel_attachment(self, channel_id, attachment_id, download=None, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
@http.route('/discuss/channel/<int:channel_id>/attachment/<int:attachment_id>', methods=['GET'], type='http', auth='public')
def discuss_channel_attachment(self, channel_id, attachment_id, download=None, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
attachment_sudo = channel_member_sudo.env['ir.attachment'].search([
('id', '=', int(attachment_id)),
('res_id', '=', int(channel_id)),
('res_model', '=', 'mail.channel')
('res_model', '=', 'discuss.channel')
], limit=1)
if not attachment_sudo:
raise NotFound()
return request.env['ir.binary']._get_stream_from(attachment_sudo).get_response(as_attachment=download)
@http.route([
'/mail/channel/<int:channel_id>/image/<int:attachment_id>',
'/mail/channel/<int:channel_id>/image/<int:attachment_id>/<int:width>x<int:height>',
'/discuss/channel/<int:channel_id>/image/<int:attachment_id>',
'/discuss/channel/<int:channel_id>/image/<int:attachment_id>/<int:width>x<int:height>',
], methods=['GET'], type='http', auth='public')
def fetch_image(self, channel_id, attachment_id, width=0, height=0, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
attachment_sudo = channel_member_sudo.env['ir.attachment'].search([
('id', '=', int(attachment_id)),
('res_id', '=', int(channel_id)),
('res_model', '=', 'mail.channel'),
('res_model', '=', 'discuss.channel'),
], limit=1)
if not attachment_sudo:
@@ -200,9 +200,9 @@ class DiscussController(http.Controller):
return guest.sudo()._init_messaging()
raise NotFound()
@http.route('/mail/channel/members', methods=['POST'], type='json', auth='public')
def mail_channel_members(self, channel_id, known_member_ids):
channel_member = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=channel_id)
@http.route('/discuss/channel/members', methods=['POST'], type='json', auth='public')
def discuss_channel_members(self, channel_id, known_member_ids):
channel_member = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=channel_id)
return channel_member.channel_id.sudo().load_more_members(known_member_ids)
@http.route('/mail/load_message_failures', methods=['POST'], type='json', auth='user')
@@ -234,8 +234,8 @@ class DiscussController(http.Controller):
@http.route('/mail/message/post', methods=['POST'], type='json', auth='public')
def mail_message_post(self, thread_model, thread_id, post_data, **kwargs):
if thread_model == 'mail.channel':
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(thread_id))
if thread_model == 'discuss.channel':
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(thread_id))
thread = channel_member_sudo.channel_id
else:
thread = request.env[thread_model].browse(int(thread_id)).exists()
@@ -267,9 +267,9 @@ class DiscussController(http.Controller):
@http.route('/mail/attachment/upload', methods=['POST'], type='http', auth='public')
def mail_attachment_upload(self, ufile, thread_id, thread_model, is_pending=False, **kwargs):
channel_member = request.env['mail.channel.member']
if thread_model == 'mail.channel':
channel_member = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(thread_id))
channel_member = request.env['discuss.channel.member']
if thread_model == 'discuss.channel':
channel_member = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(thread_id))
vals = {
'name': ufile.filename,
'raw': ufile.read(),
@@ -335,7 +335,7 @@ class DiscussController(http.Controller):
if not message_sudo:
raise NotFound()
if request.env.user.sudo()._is_public():
if not guest_sudo or not message_sudo.model == 'mail.channel' or message_sudo.res_id not in guest_sudo.channel_ids.ids:
if not guest_sudo or not message_sudo.model == 'discuss.channel' or message_sudo.res_id not in guest_sudo.channel_ids.ids:
raise NotFound()
message_sudo._message_add_reaction(content=content)
guests = [('insert', {'id': guest_sudo.id})]
@@ -363,7 +363,7 @@ class DiscussController(http.Controller):
if not message_sudo:
raise NotFound()
if request.env.user.sudo()._is_public():
if not guest_sudo or not message_sudo.model == 'mail.channel' or message_sudo.res_id not in guest_sudo.channel_ids.ids:
if not guest_sudo or not message_sudo.model == 'discuss.channel' or message_sudo.res_id not in guest_sudo.channel_ids.ids:
raise NotFound()
message_sudo._message_remove_reaction(content=content)
guests = [('insert-and-unlink', {'id': guest_sudo.id})]
@@ -388,9 +388,9 @@ class DiscussController(http.Controller):
# Channel API
# --------------------------------------------------------------------------
@http.route('/mail/channel/add_guest_as_member', methods=['POST'], type='json', auth='public')
def mail_channel_add_guest_as_member(self, channel_id, channel_uuid, **kwargs):
channel_sudo = request.env['mail.channel'].browse(int(channel_id)).sudo().exists()
@http.route('/discuss/channel/add_guest_as_member', methods=['POST'], type='json', auth='public')
def discuss_channel_add_guest_as_member(self, channel_id, channel_uuid, **kwargs):
channel_sudo = request.env['discuss.channel'].browse(int(channel_id)).sudo().exists()
if not channel_sudo or not channel_sudo.uuid or not consteq(channel_sudo.uuid, channel_uuid):
raise NotFound()
if channel_sudo.channel_type == 'chat':
@@ -399,7 +399,7 @@ class DiscussController(http.Controller):
# Only guests should take this route.
if not guest:
raise NotFound()
channel_member = channel_sudo.env['mail.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
channel_member = channel_sudo.env['discuss.channel.member']._get_as_sudo_from_request(request=request, channel_id=channel_id)
# Do not add the guest to channel members if they are already member.
if not channel_member:
channel_sudo = channel_sudo.with_context(guest=guest)
@@ -408,12 +408,12 @@ class DiscussController(http.Controller):
except UserError:
raise NotFound()
@http.route('/mail/channel/messages', methods=['POST'], type='json', auth='public')
def mail_channel_messages(self, channel_id, before=None, after=None, limit=30, around=None, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
@http.route('/discuss/channel/messages', methods=['POST'], type='json', auth='public')
def discuss_channel_messages(self, channel_id, before=None, after=None, limit=30, around=None, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
domain = [
('res_id', '=', channel_id),
('model', '=', 'mail.channel'),
('model', '=', 'discuss.channel'),
('message_type', '!=', 'user_notification'),
]
messages = channel_member_sudo.env['mail.message']._message_fetch(domain=domain, before=before, after=after, around=around, limit=limit)
@@ -421,24 +421,24 @@ class DiscussController(http.Controller):
messages.set_message_done()
return messages.sorted('id', reverse=True).message_format()
@http.route('/mail/channel/pinned_messages', methods=['POST'], type='json', auth='public')
def mail_channel_pins(self, channel_id, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
@http.route('/discuss/channel/pinned_messages', methods=['POST'], type='json', auth='public')
def discuss_channel_pins(self, channel_id, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return channel_member_sudo.channel_id.pinned_message_ids.sorted(key='pinned_at', reverse=True).message_format()
@http.route('/mail/channel/set_last_seen_message', methods=['POST'], type='json', auth='public')
def mail_channel_mark_as_seen(self, channel_id, last_message_id, allow_older=False, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
@http.route('/discuss/channel/set_last_seen_message', methods=['POST'], type='json', auth='public')
def discuss_channel_mark_as_seen(self, channel_id, last_message_id, allow_older=False, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return channel_member_sudo.channel_id._channel_seen(last_message_id, allow_older=allow_older)
@http.route('/mail/channel/notify_typing', methods=['POST'], type='json', auth='public')
def mail_channel_notify_typing(self, channel_id, is_typing, **kwargs):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
@http.route('/discuss/channel/notify_typing', methods=['POST'], type='json', auth='public')
def discuss_channel_notify_typing(self, channel_id, is_typing, **kwargs):
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo._notify_typing(is_typing)
@http.route('/mail/channel/ping', methods=['POST'], type='json', auth='public')
@http.route('/discuss/channel/ping', methods=['POST'], type='json', auth='public')
def channel_ping(self, channel_id, rtc_session_id=None, check_rtc_session_ids=None):
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
if rtc_session_id:
channel_member_sudo.channel_id.rtc_session_ids.filtered_domain([
('id', '=', int(rtc_session_id)),
@@ -516,7 +516,7 @@ class DiscussController(http.Controller):
guest = request.env['mail.guest']._get_guest_from_request(request)
notifications_by_session = defaultdict(list)
for sender_session_id, target_session_ids, content in peer_notifications:
session_sudo = guest.env['mail.channel.rtc.session'].sudo().browse(int(sender_session_id)).exists()
session_sudo = guest.env['discuss.channel.rtc.session'].sudo().browse(int(sender_session_id)).exists()
if not session_sudo or (session_sudo.guest_id and session_sudo.guest_id != guest) or (session_sudo.partner_id and session_sudo.partner_id != request.env.user.partner_id):
continue
notifications_by_session[session_sudo].append(([int(sid) for sid in target_session_ids], content))
@@ -533,12 +533,12 @@ class DiscussController(http.Controller):
if request.env.user._is_public():
guest = request.env['mail.guest']._get_guest_from_request(request)
if guest:
session = guest.env['mail.channel.rtc.session'].sudo().browse(int(session_id)).exists()
session = guest.env['discuss.channel.rtc.session'].sudo().browse(int(session_id)).exists()
if session and session.guest_id == guest:
session._update_and_broadcast(values)
return
return
session = request.env['mail.channel.rtc.session'].sudo().browse(int(session_id)).exists()
session = request.env['discuss.channel.rtc.session'].sudo().browse(int(session_id)).exists()
if session and session.partner_id == request.env.user.partner_id:
session._update_and_broadcast(values)
@@ -547,7 +547,7 @@ class DiscussController(http.Controller):
""" Joins the RTC call of a channel if the user is a member of that channel
:param int channel_id: id of the channel to join
"""
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return channel_member_sudo._rtc_join_call(check_rtc_session_ids=check_rtc_session_ids)
@http.route('/mail/rtc/channel/leave_call', methods=['POST'], type="json", auth="public")
@@ -555,7 +555,7 @@ class DiscussController(http.Controller):
""" Disconnects the current user from a rtc call and clears any invitation sent to that user on this channel
:param int channel_id: id of the channel from which to disconnect
"""
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return channel_member_sudo._rtc_leave_call()
@http.route('/mail/rtc/channel/cancel_call_invitation', methods=['POST'], type="json", auth="public")
@@ -564,7 +564,7 @@ class DiscussController(http.Controller):
:param member_ids: members whose invitation is to cancel
:type member_ids: list(int) or None
"""
channel_member_sudo = request.env['mail.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
channel_member_sudo = request.env['discuss.channel.member']._get_as_sudo_from_request_or_raise(request=request, channel_id=int(channel_id))
return channel_member_sudo.channel_id._rtc_cancel_invitations(member_ids=member_ids)
@http.route('/mail/rtc/audio_worklet_processor', methods=['GET'], type='http', auth='public')
+4 -4
View File
@@ -8,10 +8,10 @@ from odoo.addons.web.controllers.home import Home as WebHome
def _admin_password_warn(uid):
""" Admin still has `admin` password, flash a message via chatter.
Uses a private mail.channel from the system (/ odoobot) to the user, as
Uses a private discuss.channel from the system (/ odoobot) to the user, as
using a more generic mail.thread could send an email which is undesirable
Uses mail.channel directly because using mail.thread might send an email instead.
Uses discuss.channel directly because using mail.thread might send an email instead.
"""
if request.params['password'] != 'admin':
return
@@ -26,8 +26,8 @@ def _admin_password_warn(uid):
return
user = request.env(user=uid)['res.users']
MailChannel = env(context=user.context_get())['mail.channel']
MailChannel.browse(MailChannel.channel_get([admin.id])['id'])\
DiscussChannel = env(context=user.context_get())['discuss.channel']
DiscussChannel.browse(DiscussChannel.channel_get([admin.id])['id'])\
.message_post(
body=_("Your password is the default (admin)! If this system is exposed to untrusted users it is important to change it immediately for security reasons. I will keep nagging you about it!"),
message_type='comment',
@@ -2,14 +2,14 @@
<odoo>
<data noupdate="1">
<record model="mail.channel" id="channel_all_employees">
<record model="discuss.channel" id="mail.channel_all_employees">
<field name="name">general</field>
<field name="description">General announcements for all employees.</field>
</record>
<!-- notify all employees of module installation -->
<record model="mail.message" id="module_install_notification">
<field name="model">mail.channel</field>
<record model="mail.message" id="mail.module_install_notification">
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_all_employees"/>
<field name="message_type">email</field>
<field name="subtype_id" ref="mail.mt_comment"/>
@@ -18,14 +18,14 @@
<p>This channel is accessible to all users to <b>easily share company information</b>.</p>]]></field>
</record>
<record model="mail.channel.member" id="channel_member_general_channel_for_admin">
<record model="discuss.channel.member" id="channel_member_general_channel_for_admin">
<field name="partner_id" ref="base.partner_admin"/>
<field name="channel_id" ref="mail.channel_all_employees"/>
<field name="fetched_message_id" ref="mail.module_install_notification"/>
<field name="seen_message_id" ref="mail.module_install_notification"/>
</record>
<record model="mail.channel" id="mail.channel_all_employees">
<record model="discuss.channel" id="mail.channel_all_employees">
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]"/>
</record>
</data>
@@ -3,52 +3,52 @@
<data noupdate="1">
<!-- Discussion groups, done in 2 steps to remove creator from followers -->
<record model="mail.channel" id="channel_1">
<record model="discuss.channel" id="mail.channel_1">
<field name="name">sales</field>
<field name="description">Discussion about best sales practices and deals.</field>
</record>
<record model="mail.channel" id="channel_2">
<record model="discuss.channel" id="mail.channel_2">
<field name="name">board-meetings</field>
<field name="description">Board meetings, budgets, strategic plans</field>
</record>
<record model="mail.channel" id="channel_3">
<record model="discuss.channel" id="mail.channel_3">
<field name="name">rd</field>
<field name="description">Research and development discussion group</field>
</record>
<!-- Best sales practices messages -->
<record id="mail_message_channel_1_1" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_1"/>
<field name="body"><![CDATA[<p>Selling a training session and selling the products after the training session is more efficient than directly selling a pack with the training session and the products.</p>]]></field>
<field name="message_type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="date" eval="(DateTime.today() - timedelta(days=5)).strftime('%Y-%m-%d %H:%M')"/>
</record>
<record id="mail_message_channel_1_2" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_1"/>
<field name="body"><![CDATA[<p>I noted I can not manage efficiently my pipeline when I have more than 50 opportunities in the qualification stage.</p><p>Any advice on this? How do you organize your activities with more than 50 opportunities?</p>]]></field>
<field name="message_type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_root"/>
<field name="date" eval="(DateTime.today() - timedelta(days=4)).strftime('%Y-%m-%d %H:%M')"/>
</record>
<record id="mail_message_channel_1_2_1" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_1"/>
<field name="body"><![CDATA[<p>When I have too much opportunities in the pipe, I start communicating with prospects more by email than phonecalls.</p><p>I send an email to create a sense of emergency, like <i>"can I call you this week about our quote?"</i> and I call only those that answer this email.</p><p>You can use the email template feature of Odoo to automate email composition.</p>]]></field>
<field name="message_type">comment</field>
<field name="parent_id" ref="mail_message_channel_1_2"/>
<field name="subtype_id" ref="mt_comment"/>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="date" eval="(DateTime.today() - timedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/>
</record>
<!-- Pushed to all employees -->
<record id="mail_message_channel_whole_1" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_all_employees"/>
<field name="body"><![CDATA[
<p>
@@ -64,7 +64,7 @@
<field name="subtype_id" ref="mail.mt_comment"/>
</record>
<record id="mail_message_channel_whole_2" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_all_employees"/>
<field name="body"><![CDATA[<p>Your monthly meal vouchers arrived. You can get them at the HR's office.</p>
<p>This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</p>]]></field>
@@ -74,7 +74,7 @@
<field name="subtype_id" ref="mail.mt_comment"/>
</record>
<record id="mail_message_channel_whole_2_1" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="channel_all_employees"/>
<field name="body"><![CDATA[<p>Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!</p>]]></field>
<field name="parent_id" ref="mail_message_channel_whole_2"/>
@@ -84,7 +84,7 @@
<field name="subtype_id" ref="mail.mt_comment"/>
</record>
<record id="mail_message_channel_whole_2_2" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="channel_all_employees"/>
<field name="body"><![CDATA[<p>Building B3, second floor to the right :-).</p>]]></field>
<field name="parent_id" ref="mail_message_channel_whole_2_1"/>
@@ -96,7 +96,7 @@
<!-- Board messages -->
<record id="mail_message_channel_2_1" model="mail.message">
<field name="model">mail.channel</field>
<field name="model">discuss.channel</field>
<field name="res_id" ref="mail.channel_2"/>
<field name="body"><![CDATA[
<p>
@@ -150,7 +150,7 @@
</p>
]]></field>
<field name="message_type">comment</field>
<field name="subtype_id" ref="mt_comment"/>
<field name="subtype_id" ref="mail.mt_comment"/>
<field name="author_id" ref="base.partner_demo"/>
<field name="date" eval="(DateTime.today() - timedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/>
</record>
+3 -3
View File
@@ -34,9 +34,9 @@ from . import mail_tracking_value
from . import mail_template
# discuss
from . import mail_channel_member
from . import mail_channel_rtc_session
from . import mail_channel
from . import discuss_channel_member
from . import discuss_channel_rtc_session
from . import discuss_channel
from . import mail_guest
from . import mail_ice_server
from . import mail_shortcode
@@ -29,10 +29,10 @@ group_avatar = '''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 530.06 53
class Channel(models.Model):
""" A mail.channel is a discussion group that may behave like a listener
""" A discuss.channel is a discussion group that may behave like a listener
on documents. """
_description = 'Discussion Channel'
_name = 'mail.channel'
_name = 'discuss.channel'
_mail_flat_thread = False
_mail_post_access = 'read'
_inherit = ['mail.thread']
@@ -65,10 +65,10 @@ class Channel(models.Model):
compute_sudo=True, search='_search_channel_partner_ids',
groups='base.group_user')
channel_member_ids = fields.One2many(
'mail.channel.member', 'channel_id', string='Members',
'discuss.channel.member', 'channel_id', string='Members',
groups='base.group_user')
pinned_message_ids = fields.One2many('mail.message', 'res_id', domain=lambda self: [('model', '=', 'mail.channel'), ('pinned_at', '!=', False)], string='Pinned Messages')
rtc_session_ids = fields.One2many('mail.channel.rtc.session', 'channel_id', groups="base.group_system")
pinned_message_ids = fields.One2many('mail.message', 'res_id', domain=lambda self: [('model', '=', 'discuss.channel'), ('pinned_at', '!=', False)], string='Pinned Messages')
rtc_session_ids = fields.One2many('discuss.channel.rtc.session', 'channel_id', groups="base.group_system")
is_member = fields.Boolean('Is Member', compute='_compute_is_member', search='_search_is_member')
member_count = fields.Integer(string="Member Count", compute='_compute_member_count', compute_sudo=True)
group_ids = fields.Many2many(
@@ -130,7 +130,7 @@ class Channel(models.Model):
def _inverse_channel_partner_ids(self):
new_members = []
outdated = self.env['mail.channel.member']
outdated = self.env['discuss.channel.member']
for channel in self:
current_members = channel.channel_member_ids
partners = channel.channel_partner_ids
@@ -143,7 +143,7 @@ class Channel(models.Model):
outdated += current_members.filtered(lambda m: m.partner_id not in partners)
if new_members:
self.env['mail.channel.member'].create(new_members)
self.env['discuss.channel.member'].create(new_members)
if outdated:
outdated.sudo().unlink()
@@ -151,7 +151,7 @@ class Channel(models.Model):
return [(
'channel_member_ids',
'in',
self.env['mail.channel.member'].sudo()._search([
self.env['discuss.channel.member'].sudo()._search([
('partner_id', operator, operand)
])
)]
@@ -169,7 +169,7 @@ class Channel(models.Model):
user_domain = [('guest_id', '=', guest.id)]
else:
user_domain = [('partner_id', '=', self.env.user.partner_id.id)]
members = self.env['mail.channel.member'].sudo().search(expression.AND([[('channel_id', 'in', self.ids)], user_domain]))
members = self.env['discuss.channel.member'].sudo().search(expression.AND([[('channel_id', 'in', self.ids)], user_domain]))
is_member_channels = {member.channel_id for member in members}
for channel in self:
channel.is_member = channel in is_member_channels
@@ -186,12 +186,12 @@ class Channel(models.Model):
return [(
'channel_member_ids',
'in' if is_in else 'not in',
self.env['mail.channel.member'].sudo()._search(user_domain)
self.env['discuss.channel.member'].sudo()._search(user_domain)
)]
@api.depends('channel_member_ids')
def _compute_member_count(self):
read_group_res = self.env['mail.channel.member']._read_group(domain=[('channel_id', 'in', self.ids)], groupby=['channel_id'], aggregates=['__count'])
read_group_res = self.env['discuss.channel.member']._read_group(domain=[('channel_id', 'in', self.ids)], groupby=['channel_id'], aggregates=['__count'])
member_count_by_channel_id = {channel.id: count for channel, count in read_group_res}
for channel in self:
channel.member_count = member_count_by_channel_id.get(channel.id, 0)
@@ -239,7 +239,7 @@ class Channel(models.Model):
vals.pop('channel_partner_ids', False)
# Create channel and alias
channels = super(Channel, self.with_context(mail_create_bypass_create_check=self.env['mail.channel.member']._bypass_create_check, mail_create_nolog=True, mail_create_nosubscribe=True)).create(vals_list)
channels = super(Channel, self.with_context(mail_create_bypass_create_check=self.env['discuss.channel.member']._bypass_create_check, mail_create_nolog=True, mail_create_nosubscribe=True)).create(vals_list)
channels._subscribe_users_automatically()
@@ -247,7 +247,7 @@ class Channel(models.Model):
@api.ondelete(at_uninstall=False)
def _unlink_except_all_employee_channel(self):
# Delete mail.channel
# Delete discuss.channel
try:
all_emp_group = self.env.ref('mail.channel_all_employees')
except ValueError:
@@ -276,9 +276,9 @@ class Channel(models.Model):
return result
def init(self):
self._cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_channel_member_seen_message_id_idx',))
self._cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('discuss_channel_member_seen_message_id_idx',))
if not self._cr.fetchone():
self._cr.execute('CREATE INDEX mail_channel_member_seen_message_id_idx ON mail_channel_member (channel_id,partner_id,seen_message_id)')
self._cr.execute('CREATE INDEX discuss_channel_member_seen_message_id_idx ON discuss_channel_member (channel_id,partner_id,seen_message_id)')
# ------------------------------------------------------------
# MEMBERS MANAGEMENT
@@ -292,7 +292,7 @@ class Channel(models.Model):
for channel_id in new_members
for partner_id in new_members[channel_id]
]
self.env['mail.channel.member'].sudo().create(to_create)
self.env['discuss.channel.member'].sudo().create(to_create)
def _subscribe_users_automatically_get_members(self):
""" Return new members per channel ID """
@@ -309,13 +309,13 @@ class Channel(models.Model):
if partner not in self.with_context(active_test=False).channel_partner_ids:
return True
channel_info = self.channel_info()[0] # must be computed before leaving the channel (access rights)
member = self.env['mail.channel.member'].search([('channel_id', '=', self.id), ('partner_id', '=', partner.id)])
member = self.env['discuss.channel.member'].search([('channel_id', '=', self.id), ('partner_id', '=', partner.id)])
member_id = member.id
member.unlink()
# side effect of unsubscribe that wasn't taken into account because
# channel_info is called before actually unpinning the channel
channel_info['is_pinned'] = False
self.env['bus.bus']._sendone(partner, 'mail.channel/leave', channel_info)
self.env['bus.bus']._sendone(partner, 'discuss.channel/leave', channel_info)
notification = Markup('<div class="o_mail_notification">%s</div>') % _('left the channel')
# post 'channel left' message as root since the partner just unsubscribed from the channel
self.sudo().message_post(body=notification, subtype_xmlid="mail.mt_comment", author_id=partner.id)
@@ -359,7 +359,7 @@ class Channel(models.Model):
group_name=channel.group_public_id.name,
guest_names=', '.join(guest.name for guest in guests)
))
existing_members = self.env['mail.channel.member'].search(expression.AND([
existing_members = self.env['discuss.channel.member'].search(expression.AND([
[('channel_id', '=', channel.id)],
expression.OR([
[('partner_id', 'in', partners.ids)],
@@ -374,12 +374,12 @@ class Channel(models.Model):
'guest_id': guest.id,
'channel_id': channel.id,
} for guest in guests - existing_members.guest_id]
new_members = self.env['mail.channel.member'].sudo().create(members_to_create)
new_members = self.env['discuss.channel.member'].sudo().create(members_to_create)
for member in new_members.filtered(lambda member: member.partner_id):
# notify invited members through the bus
user = member.partner_id.user_ids[0] if member.partner_id.user_ids else self.env['res.users']
if user:
notifications.append((member.partner_id, 'mail.channel/joined', {
notifications.append((member.partner_id, 'discuss.channel/joined', {
'channel': member.channel_id.with_user(user).with_context(allowed_company_ids=user.company_ids.ids).sudo().channel_info()[0],
'invited_by_user_id': self.env.user.id,
'open_chat_window': open_chat_window,
@@ -397,12 +397,12 @@ class Channel(models.Model):
message_type="notification", subtype_xmlid="mail.mt_comment")
guest = member.guest_id
if guest:
notifications.append((guest, 'mail.channel/joined', {
notifications.append((guest, 'discuss.channel/joined', {
'channel': member.channel_id.sudo().channel_info()[0],
}))
notifications.append((channel, 'mail.record/insert', {
'Channel': {
'channelMembers': [('insert', list(new_members._mail_channel_member_format().values()))],
'channelMembers': [('insert', list(new_members._discuss_channel_member_format().values()))],
'id': channel.id,
'memberCount': channel.member_count,
}
@@ -413,14 +413,14 @@ class Channel(models.Model):
# create channel from form view, and then join from discuss without refreshing the page.
notifications.append((current_partner or current_guest, 'mail.record/insert', {
'Channel': {
'channelMembers': [('insert', list(existing_members._mail_channel_member_format().values()))],
'channelMembers': [('insert', list(existing_members._discuss_channel_member_format().values()))],
'id': channel.id,
'memberCount': channel.member_count,
}
}))
if invite_to_rtc_call:
for channel in self:
current_channel_member = self.env['mail.channel.member'].sudo().search([('channel_id', '=', channel.id), ('partner_id', '=', current_partner.id), ('guest_id', '=', current_guest.id)])
current_channel_member = self.env['discuss.channel.member'].sudo().search([('channel_id', '=', channel.id), ('partner_id', '=', current_partner.id), ('guest_id', '=', current_guest.id)])
if current_channel_member and current_channel_member.rtc_session_ids:
current_channel_member._rtc_invite_members(member_ids=new_members.ids)
self.env['bus.bus']._sendmany(notifications)
@@ -463,7 +463,7 @@ class Channel(models.Model):
if member_ids:
channel_member_domain = expression.AND([channel_member_domain, [('id', 'in', member_ids)]])
invitation_notifications = []
members = self.env['mail.channel.member'].search(channel_member_domain)
members = self.env['discuss.channel.member'].search(channel_member_domain)
for member in members:
member.rtc_inviting_session_id = False
if member.partner_id:
@@ -473,14 +473,14 @@ class Channel(models.Model):
invitation_notifications.append((target, 'mail.record/insert', {
'Thread': {
'id': self.id,
'model': 'mail.channel',
'model': 'discuss.channel',
'rtcInvitingSession': [('unlink',)],
}
}))
self.env['bus.bus']._sendmany(invitation_notifications)
channel_data = {'id': self.id, 'model': 'mail.channel'}
channel_data = {'id': self.id, 'model': 'discuss.channel'}
if members:
channel_data['invitedMembers'] = [('insert-and-unlink', list(members._mail_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
channel_data['invitedMembers'] = [('insert-and-unlink', list(members._discuss_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
self.env['bus.bus']._sendone(self, 'mail.record/insert', {'Thread': channel_data})
return channel_data
@@ -570,7 +570,7 @@ class Channel(models.Model):
# notification of the message itself to ensure the channel automatically opens.
if self.is_chat or self.channel_type == 'group':
for member in self.channel_member_ids.filtered('partner_id'):
bus_notifications.insert(0, [member.partner_id, 'mail.channel/last_interest_dt_changed', {
bus_notifications.insert(0, [member.partner_id, 'discuss.channel/last_interest_dt_changed', {
'id': self.id,
'isServerPinned': member.is_pinned,
'last_interest_dt': member.last_interest_dt,
@@ -609,7 +609,7 @@ class Channel(models.Model):
# mail_post_autofollow=False is necessary to prevent adding followers
# when using mentions in channels. Followers should not be added to
# channels, and especially not automatically (because channel membership
# should be managed with mail.channel.member instead).
# should be managed with discuss.channel.member instead).
# The current client code might be setting the key to True on sending
# message but it is only useful when targeting customers in chatter.
# This value should simply be set to False in channels no matter what.
@@ -626,7 +626,7 @@ class Channel(models.Model):
""" We don't call super in this override as we want to ignore the
mail.thread behavior completely """
if not message.message_type == 'comment':
raise UserError(_("Only messages type comment can have their content updated on model 'mail.channel'"))
raise UserError(_("Only messages type comment can have their content updated on model 'discuss.channel'"))
def _message_update_content_after_hook(self, message):
self.ensure_one()
@@ -715,7 +715,7 @@ class Channel(models.Model):
allowed_company_ids=user_id.company_ids.ids
)
for channel_info in user_channels.channel_info():
notifications.append((partner, 'mail.channel/legacy_insert', channel_info))
notifications.append((partner, 'discuss.channel/legacy_insert', channel_info))
return notifications
def _channel_message_notifications(self, message, message_format=False):
@@ -732,7 +732,7 @@ class Channel(models.Model):
'id': channel.id,
'message': message_format,
}
notifications.append((channel, 'mail.channel/new_message', payload))
notifications.append((channel, 'discuss.channel/new_message', payload))
return notifications
# ------------------------------------------------------------
@@ -754,7 +754,7 @@ class Channel(models.Model):
self.ensure_one()
message_to_update = self.env['mail.message'].search([
['id', '=', message_id],
['model', '=', 'mail.channel'],
['model', '=', 'discuss.channel'],
['res_id', '=', self.id],
['pinned_at', '=' if pinned else '!=', False]
])
@@ -808,11 +808,11 @@ class Channel(models.Model):
[('partner_id', '=', current_partner.id) if current_partner else expression.FALSE_LEAF],
[('guest_id', '=', current_guest.id) if current_guest else expression.FALSE_LEAF],
])
all_needed_members = self.env['mail.channel.member'].search(expression.AND([[('channel_id', 'in', self.ids)], all_needed_members_domain]), order='id')
all_needed_members = self.env['discuss.channel.member'].search(expression.AND([[('channel_id', 'in', self.ids)], all_needed_members_domain]), order='id')
all_needed_members.partner_id.sudo().mail_partner_format() # prefetch in batch
members_by_channel = defaultdict(lambda: self.env['mail.channel.member'])
invited_members_by_channel = defaultdict(lambda: self.env['mail.channel.member'])
member_of_current_user_by_channel = defaultdict(lambda: self.env['mail.channel.member'])
members_by_channel = defaultdict(lambda: self.env['discuss.channel.member'])
invited_members_by_channel = defaultdict(lambda: self.env['discuss.channel.member'])
member_of_current_user_by_channel = defaultdict(lambda: self.env['discuss.channel.member'])
for member in all_needed_members:
members_by_channel[member.channel_id] |= member
if member.rtc_inviting_session_id:
@@ -843,9 +843,9 @@ class Channel(models.Model):
# find the channel member state
if current_partner or current_guest:
info['message_needaction_counter'] = channel.message_needaction_counter
member = member_of_current_user_by_channel.get(channel, self.env['mail.channel.member']).with_prefetch([m.id for m in member_of_current_user_by_channel.values()])
member = member_of_current_user_by_channel.get(channel, self.env['discuss.channel.member']).with_prefetch([m.id for m in member_of_current_user_by_channel.values()])
if member:
channel_data['channelMembers'] = [('insert', list(member._mail_channel_member_format().values()))]
channel_data['channelMembers'] = [('insert', list(member._discuss_channel_member_format().values()))]
info['state'] = member.fold_state or 'open'
channel_data['message_unread_counter'] = member.message_unread_counter
info['is_minimized'] = member.is_minimized
@@ -860,7 +860,7 @@ class Channel(models.Model):
# avoid sending potentially a lot of members for big channels
# exclude chat and other small channels from this optimization because they are
# assumed to be smaller and it's important to know the member list for them
channel_data['channelMembers'] = [('insert', list(members_by_channel[channel]._mail_channel_member_format().values()))]
channel_data['channelMembers'] = [('insert', list(members_by_channel[channel]._discuss_channel_member_format().values()))]
info['seen_partners_info'] = sorted([{
'id': cp.id,
'partner_id': cp.partner_id.id,
@@ -869,7 +869,7 @@ class Channel(models.Model):
} for cp in members_by_channel[channel] if cp.partner_id], key=lambda p: p['partner_id'])
# add RTC sessions info
info.update({
'invitedMembers': [('insert', list(invited_members_by_channel[channel]._mail_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))],
'invitedMembers': [('insert', list(invited_members_by_channel[channel]._discuss_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))],
'rtcSessions': [('insert', rtc_sessions_by_channel.get(channel, []))],
})
@@ -886,7 +886,7 @@ class Channel(models.Model):
:rtype : list(dict)
"""
self.ensure_one()
domain = ["&", ("model", "=", "mail.channel"), ("res_id", "in", self.ids)]
domain = ["&", ("model", "=", "discuss.channel"), ("res_id", "in", self.ids)]
if last_id:
domain.append(("id", "<", last_id))
return self.env['mail.message']._message_fetch(domain=domain, limit=limit).message_format()
@@ -919,16 +919,16 @@ class Channel(models.Model):
raise UserError(_("A chat should not be created with more than 2 persons. Create a group instead."))
# determine type according to the number of partner in the channel
self.flush_model()
self.env['mail.channel.member'].flush_model()
self.env['discuss.channel.member'].flush_model()
self.env.cr.execute("""
SELECT M.channel_id
FROM mail_channel C, mail_channel_member M
FROM discuss_channel C, discuss_channel_member M
WHERE M.channel_id = C.id
AND M.partner_id IN %s
AND C.channel_type LIKE 'chat'
AND NOT EXISTS (
SELECT 1
FROM mail_channel_member M2
FROM discuss_channel_member M2
WHERE M2.channel_id = C.id
AND M2.partner_id NOT IN %s
)
@@ -942,7 +942,7 @@ class Channel(models.Model):
channel = self.browse(result[0].get('channel_id'))
# pin up the channel for the current partner
if pin:
self.env['mail.channel.member'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', channel.id)]).write({
self.env['discuss.channel.member'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', channel.id)]).write({
'is_pinned': True,
'last_interest_dt': fields.Datetime.now(),
})
@@ -971,7 +971,7 @@ class Channel(models.Model):
:param state : the new status of the session for the current user.
"""
domain = [('partner_id', '=', self.env.user.partner_id.id), ('channel_id', 'in', self.ids)]
for session_state in self.env['mail.channel.member'].search(domain):
for session_state in self.env['discuss.channel.member'].search(domain):
if not state:
state = session_state.fold_state
if session_state.fold_state == 'open':
@@ -989,21 +989,21 @@ class Channel(models.Model):
self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.record/insert', {
'Thread': {
'id': session_state.channel_id.id,
'model': 'mail.channel',
'model': 'discuss.channel',
'serverFoldState': state,
}
})
def channel_pin(self, pinned=False):
self.ensure_one()
member = self.env['mail.channel.member'].search(
member = self.env['discuss.channel.member'].search(
[('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', self.id), ('is_pinned', '!=', pinned)])
if member:
member.write({'is_pinned': pinned})
if not pinned:
self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.channel/unpin', {'id': self.id})
self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/unpin', {'id': self.id})
else:
self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.channel/legacy_insert', self.channel_info()[0])
self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/legacy_insert', self.channel_info()[0])
def _channel_seen(self, last_message_id=None, allow_older=False):
"""
@@ -1015,7 +1015,7 @@ class Channel(models.Model):
as the last seen message.
"""
self.ensure_one()
domain = ["&", ("model", "=", "mail.channel"), ("res_id", "in", self.ids)]
domain = ["&", ("model", "=", "discuss.channel"), ("res_id", "in", self.ids)]
if last_message_id:
domain = expression.AND([domain, [('id', '<=', int(last_message_id))]])
last_message = (
@@ -1031,7 +1031,7 @@ class Channel(models.Model):
'partner_id': self.env.user.partner_id.id,
}
target = self if self.channel_type == 'chat' else self.env.user.partner_id
self.env['bus.bus']._sendone(target, 'mail.channel.member/seen', data)
self.env['bus.bus']._sendone(target, 'discuss.channel.member/seen', data)
return last_message.id
def _set_last_seen_message(self, last_message, allow_older=False):
@@ -1049,7 +1049,7 @@ class Channel(models.Model):
[('seen_message_id', '<', last_message.id)]
])
])
member = self.env['mail.channel.member'].search(channel_member_domain)
member = self.env['discuss.channel.member'].search(channel_member_domain)
member.write({
'fetched_message_id': max(member.fetched_message_id.id, last_message.id),
'seen_message_id': last_message.id,
@@ -1065,14 +1065,14 @@ class Channel(models.Model):
if channel.channel_type != 'chat':
return
last_message_id = channel.message_ids.ids[0] # zero is the index of the last message
member = self.env['mail.channel.member'].search([('channel_id', '=', channel.id), ('partner_id', '=', self.env.user.partner_id.id)], limit=1)
member = self.env['discuss.channel.member'].search([('channel_id', '=', channel.id), ('partner_id', '=', self.env.user.partner_id.id)], limit=1)
if member.fetched_message_id.id == last_message_id:
# last message fetched by user is already up-to-date
return
member.write({
'fetched_message_id': last_message_id,
})
self.env['bus.bus']._sendone(channel, 'mail.channel.member/fetched', {
self.env['bus.bus']._sendone(channel, 'discuss.channel.member/fetched', {
'channel_id': channel.id,
'id': member.id,
'last_message_id': last_message_id,
@@ -1081,7 +1081,7 @@ class Channel(models.Model):
def channel_set_custom_name(self, name):
self.ensure_one()
member = self.env['mail.channel.member'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', self.id)])
member = self.env['discuss.channel.member'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', self.id)])
member.write({'custom_channel_name': name})
self.env['bus.bus']._sendone(member.partner_id, 'mail.record/insert', {
'Channel': {
@@ -1096,7 +1096,7 @@ class Channel(models.Model):
self.env['bus.bus']._sendone(self, 'mail.record/insert', {
'Thread': {
'id': self.id,
'model': 'mail.channel',
'model': 'discuss.channel',
'name': name,
}
})
@@ -1108,7 +1108,7 @@ class Channel(models.Model):
'Thread': {
'id': self.id,
'description': description,
'model': 'mail.channel',
'model': 'discuss.channel',
}
})
@@ -1139,7 +1139,7 @@ class Channel(models.Model):
}
new_channel.message_post(body=notification, message_type="notification", subtype_xmlid="mail.mt_comment")
channel_info = new_channel.channel_info()[0]
self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.channel/legacy_insert', channel_info)
self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/legacy_insert', channel_info)
return channel_info
@api.model
@@ -1203,22 +1203,22 @@ class Channel(models.Model):
self.env.cr.execute("""
SELECT res_id AS id, MAX(id) AS message_id
FROM mail_message
WHERE model = 'mail.channel' AND res_id IN %s
WHERE model = 'discuss.channel' AND res_id IN %s
GROUP BY res_id
""", (tuple(self.ids),))
return self.env.cr.dictfetchall()
def load_more_members(self, known_member_ids):
self.ensure_one()
unknown_members = self.env['mail.channel.member'].search(
unknown_members = self.env['discuss.channel.member'].search(
domain=[('id', 'not in', known_member_ids), ('channel_id', '=', self.id)],
limit=100
)
count = self.env['mail.channel.member'].search_count(
count = self.env['discuss.channel.member'].search_count(
domain=[('channel_id', '=', self.id)],
)
return {
'channelMembers': [('insert', list(unknown_members._mail_channel_member_format().values()))],
'channelMembers': [('insert', list(unknown_members._discuss_channel_member_format().values()))],
'memberCount': count,
}
@@ -1236,7 +1236,7 @@ class Channel(models.Model):
written in this channel.
`content` is HTML, dynamic parts should be escaped by the caller.
"""
self.env['bus.bus']._sendone(partner_to, 'mail.channel/transient_message', {
self.env['bus.bus']._sendone(partner_to, 'discuss.channel/transient_message', {
'body': f"<span class='o_mail_notification'>{content}</span>",
'model': self._name,
'res_id': self.id,
@@ -1247,7 +1247,7 @@ class Channel(models.Model):
if self.channel_type == 'channel':
msg = _("You are in channel <b>#%s</b>.", html_escape(self.name))
else:
all_channel_members = self.env['mail.channel.member'].with_context(active_test=False)
all_channel_members = self.env['discuss.channel.member'].with_context(active_test=False)
channel_members = all_channel_members.search([('partner_id', '!=', partner.id), ('channel_id', '=', self.id)])
msg = _("You are in a private conversation with <b>@%s</b>.", _(" @").join(html_escape(member.partner_id.name or member.guest_id.name) for member in channel_members) if channel_members else _("Anonymous"))
msg += self._execute_command_help_message_extra()
@@ -1268,7 +1268,7 @@ class Channel(models.Model):
self.channel_pin(False)
def execute_command_who(self, **kwargs):
channel_members = self.env['mail.channel.member'].with_context(active_test=False).search([('partner_id', '!=', self.env.user.partner_id.id), ('channel_id', '=', self.id)])
channel_members = self.env['discuss.channel.member'].with_context(active_test=False).search([('partner_id', '!=', self.env.user.partner_id.id), ('channel_id', '=', self.id)])
members = [
m.partner_id._get_html_link(title=f"@{m.partner_id.name}") if m.partner_id else f'<strong>@{html_escape(m.guest_id.name)}</strong>'
for m in channel_members[:30]
@@ -8,9 +8,8 @@ from odoo.osv import expression
class ChannelMember(models.Model):
_name = 'mail.channel.member'
_name = 'discuss.channel.member'
_description = 'Listeners of a Channel'
_table = 'mail_channel_member'
_rec_names_search = ['partner_id', 'guest_id']
_bypass_create_check = {}
@@ -19,7 +18,7 @@ class ChannelMember(models.Model):
guest_id = fields.Many2one(string="Guest", comodel_name='mail.guest', ondelete='cascade', readonly=True, index=True)
partner_email = fields.Char('Email', related='partner_id.email', readonly=False)
# channel
channel_id = fields.Many2one('mail.channel', string='Channel', ondelete='cascade', readonly=True, required=True)
channel_id = fields.Many2one('discuss.channel', string='Channel', ondelete='cascade', readonly=True, required=True)
# state
custom_channel_name = fields.Char('Custom channel name')
fetched_message_id = fields.Many2one('mail.message', string='Last Fetched')
@@ -31,8 +30,8 @@ class ChannelMember(models.Model):
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')
rtc_session_ids = fields.One2many(string="RTC Sessions", comodel_name='discuss.channel.rtc.session', inverse_name='channel_member_id')
rtc_inviting_session_id = fields.Many2one('discuss.channel.rtc.session', string='Ringing session')
@api.depends('channel_id.message_ids', 'seen_message_id')
def _compute_message_unread(self):
@@ -41,18 +40,18 @@ class ChannelMember(models.Model):
self.flush_recordset(['channel_id', 'seen_message_id'])
self.env.cr.execute("""
SELECT count(mail_message.id) AS count,
mail_channel_member.id
discuss_channel_member.id
FROM mail_message
INNER JOIN mail_channel_member
ON mail_channel_member.channel_id = mail_message.res_id
WHERE mail_message.model = 'mail.channel'
INNER JOIN discuss_channel_member
ON discuss_channel_member.channel_id = mail_message.res_id
WHERE mail_message.model = 'discuss.channel'
AND mail_message.message_type NOT IN ('notification', 'user_notification')
AND (
mail_message.id > mail_channel_member.seen_message_id
OR mail_channel_member.seen_message_id IS NULL
mail_message.id > discuss_channel_member.seen_message_id
OR discuss_channel_member.seen_message_id IS NULL
)
AND mail_channel_member.id IN %(ids)s
GROUP BY mail_channel_member.id
AND discuss_channel_member.id IN %(ids)s
GROUP BY discuss_channel_member.id
""", {'ids': tuple(self.ids)})
unread_counter_by_member = {res['id']: res['count'] for res in self.env.cr.dictfetchall()}
for member in self:
@@ -64,8 +63,8 @@ class ChannelMember(models.Model):
return [(record.id, record.partner_id.name or record.guest_id.name) for record in self]
def init(self):
self.env.cr.execute("CREATE UNIQUE INDEX IF NOT EXISTS mail_channel_member_partner_unique ON %s (channel_id, partner_id) WHERE partner_id IS NOT NULL" % self._table)
self.env.cr.execute("CREATE UNIQUE INDEX IF NOT EXISTS mail_channel_member_guest_unique ON %s (channel_id, guest_id) WHERE guest_id IS NOT NULL" % self._table)
self.env.cr.execute("CREATE UNIQUE INDEX IF NOT EXISTS discuss_channel_member_partner_unique ON %s (channel_id, partner_id) WHERE partner_id IS NOT NULL" % self._table)
self.env.cr.execute("CREATE UNIQUE INDEX IF NOT EXISTS discuss_channel_member_guest_unique ON %s (channel_id, guest_id) WHERE guest_id IS NOT NULL" % self._table)
_sql_constraints = [
("partner_or_guest_exists", "CHECK((partner_id IS NOT NULL AND guest_id IS NULL) OR (partner_id IS NULL AND guest_id IS NOT NULL))", "A channel member must be a partner or a guest."),
@@ -82,7 +81,7 @@ class ChannelMember(models.Model):
if not self.env.is_admin() and not self.env.context.get('mail_create_bypass_create_check') is self._bypass_create_check:
for vals in vals_list:
if 'channel_id' in vals:
channel_id = self.env['mail.channel'].browse(vals['channel_id'])
channel_id = self.env['discuss.channel'].browse(vals['channel_id'])
if not channel_id._can_invite(vals.get('partner_id')):
raise AccessError(_('This user can not be added in this channel'))
return super().create(vals_list)
@@ -116,14 +115,14 @@ class ChannelMember(models.Model):
:return: A record set containing the channel member if found, or an
empty record set otherwise. In case of guest, the record is returned
with the 'guest' record in the context.
:rtype: mail.channel.member
:rtype: discuss.channel.member
"""
if request.session.uid:
return self.env['mail.channel.member'].sudo().search([('channel_id', '=', channel_id), ('partner_id', '=', self.env.user.partner_id.id)], limit=1)
return self.env['discuss.channel.member'].sudo().search([('channel_id', '=', channel_id), ('partner_id', '=', self.env.user.partner_id.id)], limit=1)
guest = self.env['mail.guest']._get_guest_from_request(request)
if guest:
return guest.env['mail.channel.member'].sudo().search([('channel_id', '=', channel_id), ('guest_id', '=', guest.id)], limit=1)
return self.env['mail.channel.member'].sudo()
return guest.env['discuss.channel.member'].sudo().search([('channel_id', '=', channel_id), ('guest_id', '=', guest.id)], limit=1)
return self.env['discuss.channel.member'].sudo()
def _notify_typing(self, is_typing):
""" Broadcast the typing notification to channel members
@@ -131,13 +130,13 @@ class ChannelMember(models.Model):
"""
notifications = []
for member in self:
formatted_member = member._mail_channel_member_format().get(member)
formatted_member = member._discuss_channel_member_format().get(member)
formatted_member['isTyping'] = is_typing
notifications.append([member.channel_id, 'mail.channel.member/typing_status', formatted_member])
notifications.append([member.channel_id.uuid, 'mail.channel.member/typing_status', formatted_member]) # notify livechat users
notifications.append([member.channel_id, 'discuss.channel.member/typing_status', formatted_member])
notifications.append([member.channel_id.uuid, 'discuss.channel.member/typing_status', formatted_member]) # notify livechat users
self.env['bus.bus']._sendmany(notifications)
def _mail_channel_member_format(self, fields=None):
def _discuss_channel_member_format(self, fields=None):
if not fields:
fields = {'id': True, 'channel': {}, 'persona': {}}
members_formatted_data = {}
@@ -169,7 +168,7 @@ class ChannelMember(models.Model):
check_rtc_session_ids = (check_rtc_session_ids or []) + self.rtc_session_ids.ids
self.channel_id._rtc_cancel_invitations(member_ids=self.ids)
self.rtc_session_ids.unlink()
rtc_session = self.env['mail.channel.rtc.session'].create({'channel_member_id': self.id})
rtc_session = self.env['discuss.channel.rtc.session'].create({'channel_member_id': self.id})
current_rtc_sessions, outdated_rtc_sessions = self._rtc_sync_sessions(check_rtc_session_ids=check_rtc_session_ids)
res = {
'iceServers': self.env['mail.ice.server']._get_ice_servers() or False,
@@ -183,7 +182,7 @@ class ChannelMember(models.Model):
self.channel_id.message_post(body=_("%s started a live conference", self.partner_id.name or self.guest_id.name), message_type='notification')
invited_members = self._rtc_invite_members()
if invited_members:
res['invitedMembers'] = [('insert', list(invited_members._mail_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
res['invitedMembers'] = [('insert', list(invited_members._discuss_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
return res
def _rtc_leave_call(self):
@@ -204,7 +203,7 @@ class ChannelMember(models.Model):
"""
self.ensure_one()
self.channel_id.rtc_session_ids._delete_inactive_rtc_sessions()
check_rtc_sessions = self.env['mail.channel.rtc.session'].browse([int(check_rtc_session_id) for check_rtc_session_id in (check_rtc_session_ids or [])])
check_rtc_sessions = self.env['discuss.channel.rtc.session'].browse([int(check_rtc_session_id) for check_rtc_session_id in (check_rtc_session_ids or [])])
return self.channel_id.rtc_session_ids, check_rtc_sessions - self.channel_id.rtc_session_ids
def _rtc_invite_members(self, member_ids=None):
@@ -222,7 +221,7 @@ class ChannelMember(models.Model):
if member_ids:
channel_member_domain = expression.AND([channel_member_domain, [('id', 'in', member_ids)]])
invitation_notifications = []
members = self.env['mail.channel.member'].search(channel_member_domain)
members = self.env['discuss.channel.member'].search(channel_member_domain)
for member in members:
member.rtc_inviting_session_id = self.rtc_session_ids.id
if member.partner_id:
@@ -232,13 +231,13 @@ class ChannelMember(models.Model):
invitation_notifications.append((target, 'mail.record/insert', {
'Thread': {
'id': self.channel_id.id,
'model': 'mail.channel',
'model': 'discuss.channel',
'rtcInvitingSession': self.rtc_session_ids._mail_rtc_session_format(),
}
}))
self.env['bus.bus']._sendmany(invitation_notifications)
if members:
channel_data = {'id': self.channel_id.id, 'model': 'mail.channel'}
channel_data['invitedMembers'] = [('insert', list(members._mail_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
channel_data = {'id': self.channel_id.id, 'model': 'discuss.channel'}
channel_data['invitedMembers'] = [('insert', list(members._discuss_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))]
self.env['bus.bus']._sendone(self.channel_id, 'mail.record/insert', {'Thread': channel_data})
return members
@@ -8,12 +8,12 @@ from odoo import api, fields, models
class MailRtcSession(models.Model):
_name = 'mail.channel.rtc.session'
_name = 'discuss.channel.rtc.session'
_description = 'Mail RTC session'
_rec_name = 'channel_member_id'
channel_member_id = fields.Many2one('mail.channel.member', required=True, ondelete='cascade')
channel_id = fields.Many2one('mail.channel', related='channel_member_id.channel_id', store=True, readonly=True)
channel_member_id = fields.Many2one('discuss.channel.member', required=True, ondelete='cascade')
channel_id = fields.Many2one('discuss.channel', related='channel_member_id.channel_id', store=True, readonly=True)
partner_id = fields.Many2one('res.partner', related='channel_member_id.partner_id', string="Partner")
guest_id = fields.Many2one('mail.guest', related='channel_member_id.guest_id')
@@ -32,7 +32,7 @@ class MailRtcSession(models.Model):
@api.model_create_multi
def create(self, vals_list):
rtc_sessions = super().create(vals_list)
self.env['bus.bus']._sendmany([(channel, 'mail.channel/rtc_sessions_update', {
self.env['bus.bus']._sendmany([(channel, 'discuss.channel/rtc_sessions_update', {
'id': channel.id,
'rtcSessions': [('insert', sessions_data)],
}) for channel, sessions_data in rtc_sessions._mail_rtc_session_format_by_channel().items()])
@@ -46,13 +46,13 @@ class MailRtcSession(models.Model):
# Note: invitation depends on field `rtc_inviting_session_id` so the cancel must be
# done before the delete to be able to know who was invited.
channel._rtc_cancel_invitations()
notifications = [(channel, 'mail.channel/rtc_sessions_update', {
notifications = [(channel, 'discuss.channel/rtc_sessions_update', {
'id': channel.id,
'rtcSessions': [('insert-and-unlink', [{'id': session_data['id']} for session_data in sessions_data])],
}) for channel, sessions_data in self._mail_rtc_session_format_by_channel().items()]
for rtc_session in self:
target = rtc_session.guest_id or rtc_session.partner_id
notifications.append((target, 'mail.channel.rtc.session/ended', {'sessionId': rtc_session.id}))
notifications.append((target, 'discuss.channel.rtc.session/ended', {'sessionId': rtc_session.id}))
self.env['bus.bus']._sendmany(notifications)
return super().unlink()
@@ -85,16 +85,16 @@ class MailRtcSession(models.Model):
guarantees that the sender is the current guest or partner.
:param notifications: list of tuple with the following elements:
- target_session_ids: a list of mail.channel.rtc.session ids
- target_session_ids: a list of discuss.channel.rtc.session ids
- content: a string with the content to be sent to the targets
"""
self.ensure_one()
payload_by_target = defaultdict(lambda: {'sender': self.id, 'notifications': []})
for target_session_ids, content in notifications:
for target_session in self.env['mail.channel.rtc.session'].browse(target_session_ids).exists():
for target_session in self.env['discuss.channel.rtc.session'].browse(target_session_ids).exists():
target = target_session.guest_id or target_session.partner_id
payload_by_target[target]['notifications'].append(content)
return self.env['bus.bus']._sendmany([(target, 'mail.channel.rtc.session/peer_notification', payload) for target, payload in payload_by_target.items()])
return self.env['bus.bus']._sendmany([(target, 'discuss.channel.rtc.session/peer_notification', payload) for target, payload in payload_by_target.items()])
def _mail_rtc_session_format(self, fields=None):
self.ensure_one()
@@ -104,7 +104,7 @@ class MailRtcSession(models.Model):
if 'id' in fields:
vals['id'] = self.id
if 'channelMember' in fields:
vals['channelMember'] = self.channel_member_id._mail_channel_member_format(fields=fields.get('channelMember')).get(self.channel_member_id)
vals['channelMember'] = self.channel_member_id._discuss_channel_member_format(fields=fields.get('channelMember')).get(self.channel_member_id)
if 'isCameraOn' in fields:
vals['isCameraOn'] = self.is_camera_on
if 'isDeaf' in fields:
+2 -2
View File
@@ -40,8 +40,8 @@ class IrAttachment(models.Model):
def _delete_and_notify(self):
for attachment in self:
if attachment.res_model == 'mail.channel' and attachment.res_id:
target = self.env['mail.channel'].browse(attachment.res_id)
if attachment.res_model == 'discuss.channel' and attachment.res_id:
target = self.env['discuss.channel'].browse(attachment.res_id)
else:
target = self.env.user.partner_id
self.env['bus.bus']._sendone(target, 'ir.attachment/delete', {
+5 -5
View File
@@ -23,16 +23,16 @@ class IrWebsocket(models.AbstractModel):
req = request or wsrequest
channels = list(channels) # do not alter original list
guest_sudo = self.env['mail.guest']._get_guest_from_request(req).sudo()
mail_channels = self.env['mail.channel']
discuss_channels = self.env['discuss.channel']
if req.session.uid:
partner = self.env.user.partner_id
mail_channels = partner.channel_ids
discuss_channels = partner.channel_ids
channels.append(partner)
elif guest_sudo:
mail_channels = guest_sudo.channel_ids
discuss_channels = guest_sudo.channel_ids
channels.append(guest_sudo)
for mail_channel in mail_channels:
channels.append(mail_channel)
for discuss_channel in discuss_channels:
channels.append(discuss_channel)
return super()._build_bus_channel_list(channels)
def _update_bus_presence(self, inactivity_period, im_status_ids_by_model):
+1 -1
View File
@@ -28,7 +28,7 @@ class MailGuest(models.Model):
country_id = fields.Many2one(string="Country", comodel_name='res.country')
lang = fields.Selection(string="Language", selection=_lang_get)
timezone = fields.Selection(string="Timezone", selection=_tz_get)
channel_ids = fields.Many2many(string="Channels", comodel_name='mail.channel', relation='mail_channel_member', column1='guest_id', column2='channel_id', copy=False)
channel_ids = fields.Many2many(string="Channels", comodel_name='discuss.channel', relation='discuss_channel_member', column1='guest_id', column2='channel_id', copy=False)
im_status = fields.Char('IM Status', compute='_compute_im_status')
def _compute_im_status(self):
+4 -4
View File
@@ -43,8 +43,8 @@ class LinkPreview(models.Model):
if not link_previews:
return
guest = self.env['mail.guest']._get_guest_from_context()
if message.model == 'mail.channel' and message.res_id:
target = self.env['mail.channel'].browse(message.res_id)
if message.model == 'discuss.channel' and message.res_id:
target = self.env['discuss.channel'].browse(message.res_id)
elif self.env.user._is_public() and guest:
target = guest
else:
@@ -67,8 +67,8 @@ class LinkPreview(models.Model):
notifications = []
guest = self.env['mail.guest']._get_guest_from_context()
for link_preview in self:
if link_preview.message_id.model == 'mail.channel' and link_preview.message_id.res_id:
target = self.env['mail.channel'].browse(link_preview.message_id.res_id)
if link_preview.message_id.model == 'discuss.channel' and link_preview.message_id.res_id:
target = self.env['discuss.channel'].browse(link_preview.message_id.res_id)
elif self.env.user._is_public() and guest:
target = guest
else:
+1 -1
View File
@@ -890,7 +890,7 @@ class Message(models.Model):
'message': {'id': message_sudo.id},
'partners': [{'id': partner.id, 'name': partner.name} for partner in reactions.partner_id],
} for content, reactions in reactions_per_content.items()]
if format_reply and message_sudo.model == 'mail.channel' and message_sudo.parent_id:
if format_reply and message_sudo.model == 'discuss.channel' and message_sudo.parent_id:
vals['parentMessage'] = message_sudo.parent_id.message_format(format_reply=False)[0]
allowed_tracking_ids = message_sudo.tracking_value_ids.filtered(lambda tracking: not tracking.field_groups or self.env.is_superuser() or self.user_has_groups(tracking.field_groups))
vals.update({
+2 -2
View File
@@ -6,7 +6,7 @@ from odoo import models
class ResGroups(models.Model):
""" Update of res.groups class
- if adding users from a group, check mail.channels linked to this user
- if adding users from a group, check discuss.channels linked to this user
group and subscribe them. This is done by overriding the write method.
"""
_name = 'res.groups'
@@ -19,5 +19,5 @@ class ResGroups(models.Model):
# form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]}
user_ids = [command[1] for command in vals['users'] if command[0] == 4]
user_ids += [id for command in vals['users'] if command[0] == 6 for id in command[2]]
self.env['mail.channel'].search([('group_ids', 'in', self._ids)])._subscribe_users_automatically()
self.env['discuss.channel'].search([('group_ids', 'in', self._ids)])._subscribe_users_automatically()
return res
+8 -8
View File
@@ -21,7 +21,7 @@ class Partner(models.Model):
user_id = fields.Many2one(tracking=4)
vat = fields.Char(tracking=5)
# channels
channel_ids = fields.Many2many('mail.channel', 'mail_channel_member', 'partner_id', 'channel_id', string='Channels', copy=False)
channel_ids = fields.Many2many('discuss.channel', 'discuss_channel_member', 'partner_id', 'channel_id', string='Channels', copy=False)
# tracked field used for chatter logging purposes
# we need this to be readable inline as tracking messages use inline HTML nodes
contact_address_inline = fields.Char(compute='_compute_contact_address_inline', string='Inlined Complete Address', tracking=True)
@@ -267,16 +267,16 @@ class Partner(models.Model):
def _get_channels_as_member(self):
"""Returns the channels of the partner."""
self.ensure_one()
channels = self.env['mail.channel']
channels = self.env['discuss.channel']
# get the channels and groups
channels |= self.env['mail.channel'].search([
channels |= self.env['discuss.channel'].search([
('channel_type', 'in', ('channel', 'group')),
('channel_partner_ids', 'in', [self.id]),
])
# get the pinned direct messages
channels |= self.env['mail.channel'].search([
channels |= self.env['discuss.channel'].search([
('channel_type', '=', 'chat'),
('channel_member_ids', 'in', self.env['mail.channel.member'].sudo()._search([
('channel_member_ids', 'in', self.env['discuss.channel.member'].sudo()._search([
('partner_id', '=', self.id),
('is_pinned', '=', True),
])),
@@ -301,7 +301,7 @@ class Partner(models.Model):
[('user_ids.share', '=', False)],
])
if channel_id:
channel = self.env['mail.channel'].search([('id', '=', int(channel_id))])
channel = self.env['discuss.channel'].search([('id', '=', int(channel_id))])
domain = expression.AND([domain, [('channel_ids', 'not in', channel.id)]])
if channel.group_public_id:
domain = expression.AND([domain, [('user_ids.groups_id', 'in', channel.group_public_id.id)]])
@@ -342,10 +342,10 @@ class Partner(models.Model):
partners |= self.browse(query)
partners_format = partners.mail_partner_format()
if channel_id:
member_by_partner = {member.partner_id: member for member in self.env['mail.channel.member'].search([('channel_id', '=', channel_id), ('partner_id', 'in', partners.ids)])}
member_by_partner = {member.partner_id: member for member in self.env['discuss.channel.member'].search([('channel_id', '=', channel_id), ('partner_id', 'in', partners.ids)])}
for partner in partners:
partners_format.get(partner)['persona'] = {
'channelMembers': [('insert', member_by_partner.get(partner)._mail_channel_member_format(fields={'id': True, 'channel': {'id'}, 'persona': {'partner': {'id'}}}).get(member_by_partner.get(partner)))],
'channelMembers': [('insert', member_by_partner.get(partner)._discuss_channel_member_format(fields={'id': True, 'channel': {'id'}, 'persona': {'partner': {'id'}}}).get(member_by_partner.get(partner)))],
}
return list(partners_format.values())
+6 -6
View File
@@ -12,7 +12,7 @@ class Users(models.Model):
- make a new user follow itself
- add a welcome message
- add suggestion preference
- if adding groups to a user, check mail.channels linked to this user
- if adding groups to a user, check discuss.channels linked to this user
group, and the user. This is done by overriding the write method.
"""
_name = 'res.users'
@@ -107,8 +107,8 @@ class Users(models.Model):
subtype_xmlid='mail.mt_note'
)
# Auto-subscribe to channels unless skip explicitly requested
if not self.env.context.get('mail_channel_nosubscribe'):
self.env['mail.channel'].search([('group_ids', 'in', users.groups_id.ids)])._subscribe_users_automatically()
if not self.env.context.get('discuss_channel_nosubscribe'):
self.env['discuss.channel'].search([('group_ids', 'in', users.groups_id.ids)])._subscribe_users_automatically()
return users
def write(self, vals):
@@ -172,9 +172,9 @@ class Users(models.Model):
# form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]}
user_group_ids = [command[1] for command in vals['groups_id'] if command[0] == 4]
user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]]
self.env['mail.channel'].search([('group_ids', 'in', user_group_ids)])._subscribe_users_automatically()
self.env['discuss.channel'].search([('group_ids', 'in', user_group_ids)])._subscribe_users_automatically()
elif sel_groups:
self.env['mail.channel'].search([('group_ids', 'in', sel_groups)])._subscribe_users_automatically()
self.env['discuss.channel'].search([('group_ids', 'in', sel_groups)])._subscribe_users_automatically()
return write_res
def unlink(self):
@@ -251,7 +251,7 @@ class Users(models.Model):
public channels are mailing list (e-mail based) and so users should always receive
updates from public channels until they manually un-subscribe themselves.
"""
current_cm = self.env['mail.channel.member'].sudo().search([
current_cm = self.env['discuss.channel.member'].sudo().search([
('partner_id', 'in', self.partner_id.ids),
])
current_cm.filtered(
+2 -2
View File
@@ -1,3 +1,3 @@
from . import mail_channel
from . import mail_channel_member
from . import discuss_channel
from . import discuss_channel_member
from . import mail_message
@@ -3,7 +3,7 @@ from odoo import models
from odoo.tools import populate
class Channel(models.Model):
_inherit = 'mail.channel'
_inherit = 'discuss.channel'
_populate_dependencies = ["res.partner"]
_populate_sizes = {'small': 10, 'medium': 100, 'large': 500}
@@ -3,22 +3,22 @@ from odoo import models
from odoo.tools import populate
class ChannelMember(models.Model):
_inherit = "mail.channel.member"
_populate_dependencies = ["res.partner", "mail.channel"]
_inherit = "discuss.channel.member"
_populate_dependencies = ["res.partner", "discuss.channel"]
_populate_sizes = {'small': 10, 'medium': 100, 'large': 1000}
def _populate_factories(self):
partner_ids = self.env.registry.populated_models["res.partner"]
channel_ids = self.env.registry.populated_models["mail.channel"]
channel_ids = self.env.registry.populated_models["discuss.channel"]
return [
("partner_id", populate.randomize(partner_ids)),
("channel_id", populate.randomize(channel_ids)),
]
def _populate(self, size):
channel_ids = self.env.registry.populated_models["mail.channel"]
channel_ids = self.env.registry.populated_models["discuss.channel"]
for channel_id in channel_ids:
self.env['mail.channel.member'].create({
self.env['discuss.channel.member'].create({
'partner_id': self.env.ref('base.user_admin').partner_id.id,
'channel_id': channel_id
})
+3 -3
View File
@@ -4,11 +4,11 @@ from odoo.tools import populate
class Message(models.Model):
_inherit = 'mail.message'
_populate_dependencies = ['mail.channel', 'mail.channel.member', 'res.partner']
_populate_dependencies = ['discuss.channel', 'discuss.channel.member', 'res.partner']
_populate_sizes = {'small': 1000, 'medium': 10000, 'large': 500000}
def _populate_factories(self):
channel_ids = self.env.registry.populated_models['mail.channel']
channel_ids = self.env.registry.populated_models['discuss.channel']
def get_author_id(values, counter, random):
channel = self.env[values['model']].browse(values['res_id'])
@@ -17,7 +17,7 @@ class Message(models.Model):
return [
('body', populate.constant('message_body_{counter}')),
('message_type', populate.constant('comment')), ('model', populate.constant('mail.channel')),
('message_type', populate.constant('comment')), ('model', populate.constant('discuss.channel')),
('res_id', populate.randomize(channel_ids)),
('author_id', populate.compute(get_author_id)),
]
+8 -8
View File
@@ -15,14 +15,14 @@ access_mail_followers_system,mail.followers.system,model_mail_followers,base.gro
access_mail_notification_portal,mail.notification.portal,model_mail_notification,base.group_portal,1,0,0,0
access_mail_notification_user,mail.notification.user,model_mail_notification,base.group_user,1,1,1,0
access_mail_notification_system, mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
access_mail_channel_all,mail.group.all,model_mail_channel,,1,0,0,0
access_mail_channel_user,mail.group.user,model_mail_channel,base.group_user,1,1,1,0
access_mail_channel_admin,mail.group.system,model_mail_channel,base.group_system,1,1,1,1
access_mail_channel_member_public,mail.channel.member.public,model_mail_channel_member,base.group_public,1,0,0,0
access_mail_channel_member_portal,mail.channel.member.portal,model_mail_channel_member,base.group_portal,1,1,1,1
access_mail_channel_member_user,mail.channel.member.user,model_mail_channel_member,base.group_user,1,1,1,1
access_mail_channel_rtc_session_all,mail.channel.rtc.session.all,model_mail_channel_rtc_session,,0,0,0,0
access_mail_channel_rtc_session_system,mail.channel.rtc.session.system,model_mail_channel_rtc_session,base.group_system,1,1,1,1
access_discuss_channel_all,discuss.channel.all,model_discuss_channel,,1,0,0,0
access_discuss_channel_user,discuss.channel.user,model_discuss_channel,base.group_user,1,1,1,0
access_discuss_channel_admin,discuss.channel.system,model_discuss_channel,base.group_system,1,1,1,1
access_discuss_channel_member_public,discuss.channel.member.public,model_discuss_channel_member,base.group_public,1,0,0,0
access_discuss_channel_member_portal,discuss.channel.member.portal,model_discuss_channel_member,base.group_portal,1,1,1,1
access_discuss_channel_member_user,discuss.channel.member.user,model_discuss_channel_member,base.group_user,1,1,1,1
access_discuss_channel_rtc_session_all,discuss.channel.rtc.session.all,model_discuss_channel_rtc_session,,0,0,0,0
access_discuss_channel_rtc_session_system,discuss.channel.rtc.session.system,model_discuss_channel_rtc_session,base.group_system,1,1,1,1
access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,0,0,0
access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
15 access_mail_notification_portal mail.notification.portal model_mail_notification base.group_portal 1 0 0 0
16 access_mail_notification_user mail.notification.user model_mail_notification base.group_user 1 1 1 0
17 access_mail_notification_system mail.notification.system model_mail_notification base.group_system 1 1 1 1
18 access_mail_channel_all access_discuss_channel_all mail.group.all discuss.channel.all model_mail_channel model_discuss_channel 1 0 0 0
19 access_mail_channel_user access_discuss_channel_user mail.group.user discuss.channel.user model_mail_channel model_discuss_channel base.group_user 1 1 1 0
20 access_mail_channel_admin access_discuss_channel_admin mail.group.system discuss.channel.system model_mail_channel model_discuss_channel base.group_system 1 1 1 1
21 access_mail_channel_member_public access_discuss_channel_member_public mail.channel.member.public discuss.channel.member.public model_mail_channel_member model_discuss_channel_member base.group_public 1 0 0 0
22 access_mail_channel_member_portal access_discuss_channel_member_portal mail.channel.member.portal discuss.channel.member.portal model_mail_channel_member model_discuss_channel_member base.group_portal 1 1 1 1
23 access_mail_channel_member_user access_discuss_channel_member_user mail.channel.member.user discuss.channel.member.user model_mail_channel_member model_discuss_channel_member base.group_user 1 1 1 1
24 access_mail_channel_rtc_session_all access_discuss_channel_rtc_session_all mail.channel.rtc.session.all discuss.channel.rtc.session.all model_mail_channel_rtc_session model_discuss_channel_rtc_session 0 0 0 0
25 access_mail_channel_rtc_session_system access_discuss_channel_rtc_session_system mail.channel.rtc.session.system discuss.channel.rtc.session.system model_mail_channel_rtc_session model_discuss_channel_rtc_session base.group_system 1 1 1 1
26 access_mail_alias_all mail.alias.all model_mail_alias 1 0 0 0
27 access_mail_alias_user mail.alias.user model_mail_alias base.group_user 1 0 0 0
28 access_mail_alias_system mail.alias.system model_mail_alias base.group_system 1 1 1 1
+12 -12
View File
@@ -2,9 +2,9 @@
<odoo noupdate="1">
<!-- RULES -->
<record id="mail_channel_rule" model="ir.rule">
<field name="name">Mail.channel: access only public and joined groups</field>
<field name="model_id" ref="model_mail_channel"/>
<record id="discuss_channel_rule" model="ir.rule">
<field name="name">discuss.channel: access only public and joined groups</field>
<field name="model_id" ref="mail.model_discuss_channel"/>
<field name="groups" eval="[Command.link(ref('base.group_user')), Command.link(ref('base.group_portal')), Command.link(ref('base.group_public'))]"/>
<field name="domain_force">[
'|',
@@ -20,16 +20,16 @@
<field name="perm_create" eval="False"/>
</record>
<record id="mail_channel_admin" model="ir.rule">
<field name="name">Mail.channel: admin full access</field>
<field name="model_id" ref="model_mail_channel"/>
<record id="discuss_channel_admin" model="ir.rule">
<field name="name">discuss.channel: admin full access</field>
<field name="model_id" ref="mail.model_discuss_channel"/>
<field name="groups" eval="[Command.link(ref('base.group_system'))]"/>
<field name="domain_force">[(1, '=', 1)]</field>
</record>
<record id="ir_rule_mail_channel_member_group_user" model="ir.rule">
<field name="name">mail.channel.member: write its own entries</field>
<field name="model_id" ref="model_mail_channel_member"/>
<record id="ir_rule_discuss_channel_member_group_user" model="ir.rule">
<field name="name">discuss.channel.member: write its own entries</field>
<field name="model_id" ref="mail.model_discuss_channel_member"/>
<field name="groups" eval="[(4, ref('base.group_user')), (4, ref('base.group_portal'))]"/>
<field name="domain_force">[
'|',
@@ -48,9 +48,9 @@
<field name="perm_unlink" eval="True"/>
</record>
<record id="ir_rule_mail_channel_member_group_system" model="ir.rule">
<field name="name">mail.channel.member: admin can manipulate all entries</field>
<field name="model_id" ref="model_mail_channel_member"/>
<record id="ir_rule_discuss_channel_member_group_system" model="ir.rule">
<field name="name">discuss.channel.member: admin can manipulate all entries</field>
<field name="model_id" ref="mail.model_discuss_channel_member"/>
<field name="groups" eval="[Command.link(ref('base.group_system'))]"/>
<field name="domain_force">[(1, '=', 1)]</field>
</record>
@@ -53,9 +53,9 @@ export class AttachmentList extends Component {
!this.env.inComposer &&
!this.env.inChatter &&
!attachment.accessToken &&
attachment.originThread?.model === "mail.channel"
attachment.originThread?.model === "discuss.channel"
) {
return `/mail/channel/${attachment.originThread?.id}/image/${attachment.id}/${this.imagesWidth}x${imagesHeight}`;
return `/discuss/channel/${attachment.originThread?.id}/image/${attachment.id}/${this.imagesWidth}x${imagesHeight}`;
}
const accessToken = attachment.accessToken ? `?access_token=${attachment.accessToken}` : "";
return `/web/image/${attachment.id}/${this.imagesWidth}x${imagesHeight}${accessToken}`;
@@ -27,7 +27,7 @@ export class Attachment {
}
get isDeletable() {
if (this.message && this.originThread?.model === "mail.channel") {
if (this.message && this.originThread?.model === "discuss.channel") {
return this.message.editable;
}
return true;
@@ -89,8 +89,8 @@ export class Attachment {
if (!this.isImage) {
return "";
}
if (!this.accessToken && this.originThread?.model === "mail.channel") {
return `/mail/channel/${this.originThread.id}/image/${this.id}`;
if (!this.accessToken && this.originThread?.model === "discuss.channel") {
return `/discuss/channel/${this.originThread.id}/image/${this.id}`;
}
const accessToken = this.accessToken ? `?access_token=${this.accessToken}` : "";
return `/web/image/${this.id}${accessToken}`;
@@ -102,8 +102,8 @@ export class Attachment {
}
if (this.isPdf) {
const pdf_lib = "/web/static/lib/pdfjs/web/viewer.html?file=";
if (!this.accessToken && this.originThread?.model === "mail.channel") {
return `${pdf_lib}/mail/channel/${this.originThread.id}/attachment/${this.id}`;
if (!this.accessToken && this.originThread?.model === "discuss.channel") {
return `${pdf_lib}/discuss/channel/${this.originThread.id}/attachment/${this.id}`;
}
const accessToken = this.accessToken ? `?access_token%3D${this.accessToken}` : "";
return `${pdf_lib}/web/content/${this.id}${accessToken}`;
@@ -120,16 +120,16 @@ export class Attachment {
}
return `https://www.youtube.com/embed/${token}`;
}
if (!this.accessToken && this.originThread?.model === "mail.channel") {
return `/mail/channel/${this.originThread.id}/attachment/${this.id}`;
if (!this.accessToken && this.originThread?.model === "discuss.channel") {
return `/discuss/channel/${this.originThread.id}/attachment/${this.id}`;
}
const accessToken = this.accessToken ? `?access_token=${this.accessToken}` : "";
return `/web/content/${this.id}${accessToken}`;
}
get downloadUrl() {
if (!this.accessToken && this.originThread?.model === "mail.channel") {
return `/mail/channel/${this.originThread.id}/attachment/${this.id}?download=true`;
if (!this.accessToken && this.originThread?.model === "discuss.channel") {
return `/discuss/channel/${this.originThread.id}/attachment/${this.id}?download=true`;
}
const accessToken = this.accessToken ? `access_token=${this.accessToken}&` : "";
return `/web/content/ir.attachment/${this.id}/datas?${accessToken}download=true`;
+1 -1
View File
@@ -471,7 +471,7 @@ export class Composer extends Component {
notifyIsTyping(is_typing = true) {
if (["chat", "channel", "group"].includes(this.thread?.type)) {
this.messaging.rpc(
"/mail/channel/notify_typing",
"/discuss/channel/notify_typing",
{
channel_id: this.thread.id,
is_typing,
@@ -3,7 +3,7 @@
import { cleanTerm } from "@mail/utils/format";
import { registry } from "@web/core/registry";
const commandRegistry = registry.category("mail.channel_commands");
const commandRegistry = registry.category("discuss.channel_commands");
export class SuggestionService {
constructor(env, services) {
@@ -15,7 +15,7 @@ export class SuggestionService {
/** @type {import("@mail/core/persona_service").PersonaService} */
this.personaService = services["mail.persona"];
/** @type {import("@mail/core/channel_member_service").ChannelMemberService} */
this.channelMemberService = services["mail.channel.member"];
this.channelMemberService = services["discuss.channel.member"];
}
getSupportedDelimiters(thread) {
@@ -63,14 +63,14 @@ export class SuggestionService {
async fetchThreads(term) {
const suggestedThreads = await this.orm.call(
"mail.channel",
"discuss.channel",
"get_mention_suggestions",
[],
{ search: term }
);
suggestedThreads.map((data) => {
this.threadService.insert({
model: "mail.channel",
model: "discuss.channel",
...data,
});
});
@@ -352,7 +352,7 @@ export class SuggestionService {
}
export const suggestionService = {
dependencies: ["orm", "mail.store", "mail.thread", "mail.persona", "mail.channel.member"],
dependencies: ["orm", "mail.store", "mail.thread", "mail.persona", "discuss.channel.member"],
start(env, services) {
return new SuggestionService(env, services);
},
@@ -3,7 +3,7 @@
import { registry } from "@web/core/registry";
import { _lt } from "@web/core/l10n/translation";
const commandRegistry = registry.category("mail.channel_commands");
const commandRegistry = registry.category("discuss.channel_commands");
commandRegistry
.add("help", {
@@ -30,6 +30,6 @@ export class ChannelMember {
}
get thread() {
return this._store.threads[createLocalId("mail.channel", this.threadId)];
return this._store.threads[createLocalId("discuss.channel", this.threadId)];
}
}

Some files were not shown because too many files have changed in this diff Show More