mirror of https://github.com/OCA/social.git
[MIG] mail_broker: Migration to 14.0
parent
294aa506d4
commit
ad8cbb3438
|
@ -5,7 +5,7 @@
|
||||||
"name": "Mail Broker",
|
"name": "Mail Broker",
|
||||||
"summary": """
|
"summary": """
|
||||||
Set a broker""",
|
Set a broker""",
|
||||||
"version": "13.0.1.0.0",
|
"version": "14.0.1.0.0",
|
||||||
"license": "AGPL-3",
|
"license": "AGPL-3",
|
||||||
"author": "Creu Blanca,Odoo Community Association (OCA)",
|
"author": "Creu Blanca,Odoo Community Association (OCA)",
|
||||||
"website": "https://github.com/OCA/social",
|
"website": "https://github.com/OCA/social",
|
||||||
|
|
|
@ -17,6 +17,10 @@ class NewMailChatController(MailChatController):
|
||||||
def _poll(self, dbname, channels, last, options):
|
def _poll(self, dbname, channels, last, options):
|
||||||
if request.session.uid:
|
if request.session.uid:
|
||||||
if request.env.user.has_group("mail_broker.broker_user"):
|
if request.env.user.has_group("mail_broker.broker_user"):
|
||||||
for bot in request.env["mail.broker"].search([]):
|
channels = list(channels)
|
||||||
channels.append((request.db, "mail.broker", bot.id))
|
for channel in request.env["mail.channel"].search(
|
||||||
return super()._poll(dbname, channels, last, options)
|
[("public", "=", "broker")]
|
||||||
|
):
|
||||||
|
channels.append((request.db, "mail.channel", channel.id))
|
||||||
|
result = super()._poll(dbname, channels, last, options)
|
||||||
|
return result
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MailBroker(models.Model):
|
||||||
|
|
||||||
def _get_channel_id(self, chat_token):
|
def _get_channel_id(self, chat_token):
|
||||||
return (
|
return (
|
||||||
self.env["mail.broker.channel"]
|
self.env["mail.channel"]
|
||||||
.search(
|
.search(
|
||||||
[("token", "=", str(chat_token)), ("broker_id", "=", self.id)],
|
[("token", "=", str(chat_token)), ("broker_id", "=", self.id)],
|
||||||
limit=1,
|
limit=1,
|
||||||
|
@ -94,7 +94,7 @@ class MailBroker(models.Model):
|
||||||
"channel_name": "broker_%s" % record.id,
|
"channel_name": "broker_%s" % record.id,
|
||||||
"threads": [
|
"threads": [
|
||||||
thread._get_thread_data()
|
thread._get_thread_data()
|
||||||
for thread in self.env["mail.broker.channel"].search(
|
for thread in self.env["mail.channel"].search(
|
||||||
[("show_on_app", "=", True), ("broker_id", "=", record.id)]
|
[("show_on_app", "=", True), ("broker_id", "=", record.id)]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -107,7 +107,7 @@ class MailBroker(models.Model):
|
||||||
domain = [("broker_id", "=", self.id)]
|
domain = [("broker_id", "=", self.id)]
|
||||||
if name:
|
if name:
|
||||||
domain += [("name", "ilike", "%" + name + "%")]
|
domain += [("name", "ilike", "%" + name + "%")]
|
||||||
return self.env["mail.broker.channel"].search(domain).read(["name"])
|
return self.env["mail.channel"].search(domain).read(["name"])
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
res = super(MailBroker, self).write(vals)
|
res = super(MailBroker, self).write(vals)
|
||||||
|
|
|
@ -7,39 +7,32 @@ from xmlrpc.client import DateTime
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
class MailBrokerChannel(models.Model):
|
class MailChannel(models.Model):
|
||||||
_name = "mail.broker.channel"
|
_inherit = "mail.channel"
|
||||||
_description = "Mail Broker Channel"
|
|
||||||
|
|
||||||
name = fields.Char(required=True)
|
token = fields.Char()
|
||||||
active = fields.Boolean(default=True)
|
broker_id = fields.Many2one("mail.broker")
|
||||||
token = fields.Char(required=True)
|
broker_message_ids = fields.One2many(
|
||||||
broker_id = fields.Many2one("mail.broker", required=True)
|
|
||||||
message_ids = fields.One2many(
|
|
||||||
"mail.message.broker",
|
"mail.message.broker",
|
||||||
inverse_name="channel_id",
|
inverse_name="channel_id",
|
||||||
)
|
)
|
||||||
mail_message_ids = fields.One2many(
|
|
||||||
"mail.message",
|
|
||||||
inverse_name="broker_channel_id",
|
|
||||||
)
|
|
||||||
last_message_date = fields.Datetime(
|
last_message_date = fields.Datetime(
|
||||||
compute="_compute_message_data",
|
compute="_compute_message_data",
|
||||||
store=True,
|
store=True,
|
||||||
)
|
)
|
||||||
unread = fields.Integer(
|
public = fields.Selection(
|
||||||
|
selection_add=[("broker", "Broker")], ondelete={"broker": "set default"}
|
||||||
|
)
|
||||||
|
channel_type = fields.Selection(
|
||||||
|
selection_add=[("broker", "Broker")], ondelete={"broker": "set default"}
|
||||||
|
)
|
||||||
|
broker_unread = fields.Integer(
|
||||||
compute="_compute_message_data",
|
compute="_compute_message_data",
|
||||||
store=True,
|
store=True,
|
||||||
)
|
)
|
||||||
broker_token = fields.Char(related="broker_id.token", store=True, required=False)
|
broker_token = fields.Char(related="broker_id.token", store=True, required=False)
|
||||||
show_on_app = fields.Boolean()
|
show_on_app = fields.Boolean()
|
||||||
partner_id = fields.Many2one("res.partner")
|
broker_partner_id = fields.Many2one("res.partner")
|
||||||
message_main_attachment_id = fields.Many2one(
|
|
||||||
string="Main Attachment",
|
|
||||||
comodel_name="ir.attachment",
|
|
||||||
index=True,
|
|
||||||
copy=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
def message_fetch(self, domain=False, limit=30):
|
def message_fetch(self, domain=False, limit=30):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
@ -52,9 +45,9 @@ class MailBrokerChannel(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.depends(
|
@api.depends(
|
||||||
"mail_message_ids",
|
"message_ids",
|
||||||
"mail_message_ids.date",
|
"message_ids.date",
|
||||||
"mail_message_ids.broker_unread",
|
"message_ids.broker_unread",
|
||||||
)
|
)
|
||||||
def _compute_message_data(self):
|
def _compute_message_data(self):
|
||||||
for r in self:
|
for r in self:
|
||||||
|
@ -67,7 +60,7 @@ class MailBrokerChannel(models.Model):
|
||||||
)
|
)
|
||||||
.date
|
.date
|
||||||
)
|
)
|
||||||
r.unread = self.env["mail.message"].search_count(
|
r.broker_unread = self.env["mail.message"].search_count(
|
||||||
[("broker_channel_id", "=", r.id), ("broker_unread", "=", True)]
|
[("broker_channel_id", "=", r.id), ("broker_unread", "=", True)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -78,12 +71,19 @@ class MailBrokerChannel(models.Model):
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"last_message_date": self.last_message_date,
|
"last_message_date": self.last_message_date,
|
||||||
"channel_type": "broker_thread",
|
"channel_type": "broker_thread",
|
||||||
"unread": self.unread,
|
"unread": self.broker_unread,
|
||||||
"broker_id": self.broker_id.id,
|
"broker_id": self.broker_id.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _broker_message_post_vals(self, body, **kwargs):
|
def _broker_message_post_vals(
|
||||||
subtype_id = kwargs.get("subtype_id", False)
|
self,
|
||||||
|
body,
|
||||||
|
subtype_id=False,
|
||||||
|
author_id=False,
|
||||||
|
date=False,
|
||||||
|
message_id=False,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
if not subtype_id:
|
if not subtype_id:
|
||||||
subtype = kwargs.get("subtype") or "mt_note"
|
subtype = kwargs.get("subtype") or "mt_note"
|
||||||
if "." not in subtype:
|
if "." not in subtype:
|
||||||
|
@ -91,21 +91,21 @@ class MailBrokerChannel(models.Model):
|
||||||
subtype_id = self.env["ir.model.data"].xmlid_to_res_id(subtype)
|
subtype_id = self.env["ir.model.data"].xmlid_to_res_id(subtype)
|
||||||
vals = {
|
vals = {
|
||||||
"channel_id": self.id,
|
"channel_id": self.id,
|
||||||
|
"channel_ids": [(4, self.id)],
|
||||||
"body": body,
|
"body": body,
|
||||||
"subtype_id": subtype_id,
|
"subtype_id": subtype_id,
|
||||||
"model": self._name,
|
"model": self._name,
|
||||||
"res_id": self.id,
|
"res_id": self.id,
|
||||||
"broker_type": self.broker_id.broker_type,
|
"broker_type": self.broker_id.broker_type,
|
||||||
}
|
}
|
||||||
if kwargs.get("author_id", False):
|
if author_id:
|
||||||
vals["author_id"] = kwargs["author_id"]
|
vals["author_id"] = author_id
|
||||||
if "date" in kwargs:
|
if date:
|
||||||
date = kwargs["date"]
|
|
||||||
if isinstance(date, DateTime):
|
if isinstance(date, DateTime):
|
||||||
date = datetime.strptime(str(date), "%Y%m%dT%H:%M:%S")
|
date = datetime.strptime(str(date), "%Y%m%dT%H:%M:%S")
|
||||||
vals["date"] = date
|
vals["date"] = date
|
||||||
if "message_id" in kwargs:
|
if message_id:
|
||||||
vals["message_id"] = kwargs["message_id"]
|
vals["message_id"] = message_id
|
||||||
vals["broker_unread"] = kwargs.get("broker_unread", False)
|
vals["broker_unread"] = kwargs.get("broker_unread", False)
|
||||||
vals["attachment_ids"] = []
|
vals["attachment_ids"] = []
|
||||||
for attachment_id in kwargs.get("attachment_ids", []):
|
for attachment_id in kwargs.get("attachment_ids", []):
|
||||||
|
@ -136,12 +136,40 @@ class MailBrokerChannel(models.Model):
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
vals = self._broker_message_post_vals(
|
vals = self._broker_message_post_vals(
|
||||||
body, broker_unread=True, author_id=self.partner_id.id, **kwargs
|
body, broker_unread=True, author_id=self.broker_partner_id.id, **kwargs
|
||||||
)
|
)
|
||||||
vals["state"] = "received"
|
vals["state"] = "received"
|
||||||
vals["broker_type"] = broker_type
|
vals["broker_type"] = broker_type
|
||||||
return self.env["mail.message.broker"].create(vals)
|
return self.env["mail.message.broker"].create(vals)
|
||||||
|
|
||||||
|
@api.returns("mail.message", lambda value: value.id)
|
||||||
|
def message_post(self, *args, **kwargs):
|
||||||
|
message = super().message_post(*args, **kwargs)
|
||||||
|
if self.broker_id:
|
||||||
|
self.env["mail.message.broker"].create(
|
||||||
|
{
|
||||||
|
"mail_message_id": message.id,
|
||||||
|
"channel_id": self.id,
|
||||||
|
}
|
||||||
|
).send()
|
||||||
|
return message
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def channel_fetch_slot(self):
|
||||||
|
result = super().channel_fetch_slot()
|
||||||
|
broker_channels = self.env["mail.channel"].search([("public", "=", "broker")])
|
||||||
|
result["channel_channel"] += broker_channels.channel_info()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def channel_info(self, *args, **kwargs):
|
||||||
|
result = super().channel_info(*args, **kwargs)
|
||||||
|
for channel, channel_info in zip(self, result):
|
||||||
|
channel_info["broker_id"] = (
|
||||||
|
channel.broker_id and channel.broker_id.id or False
|
||||||
|
)
|
||||||
|
channel_info["broker_unread_counter"] = channel.broker_unread
|
||||||
|
return result
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals_list):
|
def create(self, vals_list):
|
||||||
channels = super().create(vals_list)
|
channels = super().create(vals_list)
|
||||||
|
|
|
@ -9,7 +9,7 @@ class MailMessage(models.Model):
|
||||||
_inherit = "mail.message"
|
_inherit = "mail.message"
|
||||||
|
|
||||||
broker_channel_id = fields.Many2one(
|
broker_channel_id = fields.Many2one(
|
||||||
"mail.broker.channel",
|
"mail.channel",
|
||||||
readonly=True,
|
readonly=True,
|
||||||
compute="_compute_broker_channel_id",
|
compute="_compute_broker_channel_id",
|
||||||
store=True,
|
store=True,
|
||||||
|
@ -51,5 +51,7 @@ class MailMessage(models.Model):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def set_message_done(self):
|
def set_message_done(self):
|
||||||
self.write({"broker_unread": False})
|
# We need to set it as sudo in order to avoid collateral damages.
|
||||||
|
# In fact, it is done with sudo on the original method
|
||||||
|
self.sudo().filtered(lambda r: r.broker_unread).write({"broker_unread": False})
|
||||||
return super().set_message_done()
|
return super().set_message_done()
|
||||||
|
|
|
@ -25,9 +25,7 @@ class MailMessageBroker(models.Model):
|
||||||
auto_join=True,
|
auto_join=True,
|
||||||
)
|
)
|
||||||
message_id = fields.Char(readonly=True)
|
message_id = fields.Char(readonly=True)
|
||||||
channel_id = fields.Many2one(
|
channel_id = fields.Many2one("mail.channel", required=True, ondelete="cascade")
|
||||||
"mail.broker.channel", required=True, ondelete="cascade"
|
|
||||||
)
|
|
||||||
state = fields.Selection(
|
state = fields.Selection(
|
||||||
[
|
[
|
||||||
("outgoing", "Outgoing"),
|
("outgoing", "Outgoing"),
|
||||||
|
@ -54,17 +52,10 @@ class MailMessageBroker(models.Model):
|
||||||
if self.env.context.get("notify_broker", False):
|
if self.env.context.get("notify_broker", False):
|
||||||
notifications = []
|
notifications = []
|
||||||
for message in messages:
|
for message in messages:
|
||||||
notifications.append(
|
notifications += message.channel_id._channel_message_notifications(
|
||||||
[
|
message.mail_message_id
|
||||||
(
|
|
||||||
self._cr.dbname,
|
|
||||||
"mail.broker",
|
|
||||||
message.channel_id.broker_id.id,
|
|
||||||
),
|
|
||||||
{"message": message.mail_message_id.message_format()[0]},
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
self.env["bus.bus"].sendmany(notifications)
|
self.env["bus.bus"].sudo().sendmany(notifications)
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
def send(self, auto_commit=False, raise_exception=False, parse_mode="HTML"):
|
def send(self, auto_commit=False, raise_exception=False, parse_mode="HTML"):
|
||||||
|
|
|
@ -3,8 +3,5 @@ access_mail_message_broker_all,mail.message.broker.all,model_mail_message_broker
|
||||||
access_mail_message_broker_portal,mail.message.broker.portal,model_mail_message_broker,base.group_portal,1,1,1,0
|
access_mail_message_broker_portal,mail.message.broker.portal,model_mail_message_broker,base.group_portal,1,1,1,0
|
||||||
access_mail_message_broker_user,mail.message.broker.user,model_mail_message_broker,base.group_user,1,1,1,0
|
access_mail_message_broker_user,mail.message.broker.user,model_mail_message_broker,base.group_user,1,1,1,0
|
||||||
access_mail_message_broker_system,mail.message.broker.system,model_mail_message_broker,base.group_system,1,1,1,1
|
access_mail_message_broker_system,mail.message.broker.system,model_mail_message_broker,base.group_system,1,1,1,1
|
||||||
access_mail_broker_channel_all,mail.telegram.chat.all,model_mail_broker_channel,,1,0,0,0
|
|
||||||
access_mail_broker_channel_system,mail_broker_channel,model_mail_broker_channel,base.group_system,1,1,1,1
|
|
||||||
access_mail_broker_all,mail.telegram.bot.all,model_mail_broker,,1,0,0,0
|
access_mail_broker_all,mail.telegram.bot.all,model_mail_broker,,1,0,0,0
|
||||||
access_mail_broker_channel_user,mail_broker_manager_bot,model_mail_broker_channel,mail_broker.broker_user,1,1,0,0
|
|
||||||
access_mail_broker_system,mail_broker,model_mail_broker,base.group_system,1,1,1,1
|
access_mail_broker_system,mail_broker,model_mail_broker,base.group_system,1,1,1,1
|
||||||
|
|
|
|
@ -11,4 +11,25 @@
|
||||||
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
||||||
/>
|
/>
|
||||||
</record>
|
</record>
|
||||||
|
<record id="mail_channel_broker_rule" model="ir.rule">
|
||||||
|
<field name="name">Mail.channel: access broker</field>
|
||||||
|
<field name="model_id" ref="mail.model_mail_channel" />
|
||||||
|
<field name="groups" eval="[(4, ref('mail_broker.broker_user'))]" />
|
||||||
|
<field name="domain_force">[('public', '=', 'broker')]</field>
|
||||||
|
<field name="perm_create" eval="False" />
|
||||||
|
<field name="perm_unlink" eval="True" />
|
||||||
|
</record>
|
||||||
|
<record id="ir_rule_mail_channel_partner_group_user" model="ir.rule">
|
||||||
|
<field
|
||||||
|
name="name"
|
||||||
|
>mail.channel.partner: write its own entries on broker channels</field>
|
||||||
|
<field name="model_id" ref="mail.model_mail_channel_partner" />
|
||||||
|
<field name="groups" eval="[(4, ref('mail_broker.broker_user'))]" />
|
||||||
|
<field name="domain_force">[('channel_id.public', '=', 'broker')]</field>
|
||||||
|
<field name="perm_read" eval="False" />
|
||||||
|
<field name="perm_write" eval="True" />
|
||||||
|
<field name="perm_create" eval="False" />
|
||||||
|
<field name="perm_unlink" eval="True" />
|
||||||
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2018 ACSONE SA/NV
|
# Copyright 2022 CreuBlanca
|
||||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||||
from odoo.addons.base_rest import restapi
|
from odoo.addons.base_rest import restapi
|
||||||
from odoo.addons.component.core import AbstractComponent
|
from odoo.addons.component.core import AbstractComponent
|
||||||
|
@ -17,6 +17,12 @@ class BrokerMethodParams(restapi.RestMethodParam):
|
||||||
def to_openapi_responses(self, service):
|
def to_openapi_responses(self, service):
|
||||||
return {"200": {"content": {}}}
|
return {"200": {"content": {}}}
|
||||||
|
|
||||||
|
def to_openapi_query_parameters(self, service, spec):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def to_json_schema(self, service, spec, direction):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class MailBrokerService(AbstractComponent):
|
class MailBrokerService(AbstractComponent):
|
||||||
_inherit = "base.rest.service"
|
_inherit = "base.rest.service"
|
||||||
|
@ -60,10 +66,10 @@ class MailBrokerService(AbstractComponent):
|
||||||
def _get_channel(self, broker, token, update, force_create=False):
|
def _get_channel(self, broker, token, update, force_create=False):
|
||||||
chat_id = broker._get_channel_id(token)
|
chat_id = broker._get_channel_id(token)
|
||||||
if chat_id:
|
if chat_id:
|
||||||
return self.env["mail.broker.channel"].browse(chat_id)
|
return broker.env["mail.channel"].browse(chat_id)
|
||||||
if not force_create and broker.has_new_channel_security:
|
if not force_create and broker.has_new_channel_security:
|
||||||
return False
|
return False
|
||||||
return self.env["mail.broker.channel"].create(
|
return broker.env["mail.channel"].create(
|
||||||
self._get_channel_vals(broker, token, update)
|
self._get_channel_vals(broker, token, update)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,6 +78,8 @@ class MailBrokerService(AbstractComponent):
|
||||||
"token": token,
|
"token": token,
|
||||||
"broker_id": broker.id,
|
"broker_id": broker.id,
|
||||||
"show_on_app": broker.show_on_app,
|
"show_on_app": broker.show_on_app,
|
||||||
|
"public": "broker",
|
||||||
|
"channel_type": "broker",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _send(self, record, auto_commit=False, raise_exception=False, parse_mode=False):
|
def _send(self, record, auto_commit=False, raise_exception=False, parse_mode=False):
|
||||||
|
|
|
@ -1,429 +1,124 @@
|
||||||
odoo.define("mail_broker.Broker", function (require) {
|
odoo.define("mail_broker/static/src/broker.js", function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var BasicComposer = require("mail.composer.Basic");
|
const components = {
|
||||||
var ExtendedComposer = require("mail.composer.Extended");
|
Discuss: require("mail_broker/static/src/discuss.js"),
|
||||||
var core = require("web.core");
|
};
|
||||||
var AbstractAction = require("web.AbstractAction");
|
const AbstractAction = require("web.AbstractAction");
|
||||||
// Var ControlPanelMixin = require("web.ControlPanelMixin");
|
const {action_registry} = require("web.core");
|
||||||
var ThreadWidget = require("mail.widget.Thread");
|
|
||||||
var dom = require("web.dom");
|
|
||||||
|
|
||||||
var QWeb = core.qweb;
|
const {Component} = owl;
|
||||||
var _t = core._t;
|
|
||||||
|
|
||||||
var Broker = AbstractAction.extend({
|
var Broker = AbstractAction.extend({
|
||||||
contentTemplate: "mail_broker.broker",
|
template: "mail.widgets.Discuss",
|
||||||
events: {
|
hasControlPanel: false,
|
||||||
"click .o_mail_channel_settings": "_onChannelSettingsClicked",
|
loadControlPanel: false,
|
||||||
"click .o_mail_discuss_item": "_onSelectBrokerChannel",
|
withSearchBar: false,
|
||||||
"click .o_mail_sidebar_title .o_add": "_onSearchThread",
|
searchMenuTypes: ["filter", "favorite"],
|
||||||
"blur .o_mail_add_thread input": "_onSearchThreadBlur",
|
/**
|
||||||
},
|
* @override {web.AbstractAction}
|
||||||
init: function (parent, action, options) {
|
* @param {web.ActionManager} parent
|
||||||
this._super.apply(this, arguments);
|
* @param {Object} action
|
||||||
|
* @param {Object} [action.context]
|
||||||
|
* @param {String} [action.context.active_id]
|
||||||
|
* @param {Object} [action.params]
|
||||||
|
* @param {String} [action.params.default_active_id]
|
||||||
|
* @param {Object} [options={}]
|
||||||
|
*/
|
||||||
|
init(parent, action, options = {}) {
|
||||||
|
this._super(...arguments);
|
||||||
|
// Control panel attributes
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.action_manager = parent;
|
this.actionManager = parent;
|
||||||
this.domain = [];
|
this.searchModelConfig.modelName = "mail.message";
|
||||||
this.options = options || {};
|
this.discuss = undefined;
|
||||||
this._threadsScrolltop = {};
|
this.options = options;
|
||||||
this._composerStates = {};
|
|
||||||
this._defaultChatID =
|
this.component = undefined;
|
||||||
|
|
||||||
|
this._lastPushStateActiveThread = null;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
async willStart() {
|
||||||
|
await this._super(...arguments);
|
||||||
|
this.env = Component.env;
|
||||||
|
await this.env.messagingCreatedPromise;
|
||||||
|
const initActiveId =
|
||||||
this.options.active_id ||
|
this.options.active_id ||
|
||||||
this.action.context.active_id ||
|
(this.action.context && this.action.context.active_id) ||
|
||||||
this.action.params.default_active_id;
|
(this.action.params && this.action.params.default_active_id) ||
|
||||||
this._selectedMessage = null;
|
"mail.box_inbox";
|
||||||
|
this.discuss = this.env.messaging.discuss;
|
||||||
|
this.discuss.update({initActiveId});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override {web.AbstractAction}
|
||||||
*/
|
*/
|
||||||
on_attach_callback: function () {
|
destroy() {
|
||||||
if (this._thread) {
|
if (this.component) {
|
||||||
this._threadWidget.scrollToPosition(
|
this.component.destroy();
|
||||||
this._threadsScrolltop[this._thread.getID()]
|
this.component = undefined;
|
||||||
);
|
|
||||||
this._loadEnoughMessages();
|
|
||||||
}
|
}
|
||||||
|
this._super(...arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override {web.AbstractAction}
|
||||||
*/
|
*/
|
||||||
on_detach_callback: function () {
|
on_attach_callback() {
|
||||||
if (this._thread) {
|
this._super(...arguments);
|
||||||
this._threadsScrolltop[
|
if (this.component) {
|
||||||
this._thread.getID()
|
// Prevent twice call to on_attach_callback (FIXME)
|
||||||
] = this._threadWidget.getScrolltop();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
start: function () {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
return this._super.apply(this, arguments).then(function () {
|
|
||||||
return self._initRender();
|
|
||||||
});
|
|
||||||
/*
|
|
||||||
Return this.alive($.when.apply($, defs))
|
|
||||||
.then(function() {
|
|
||||||
if (self._defaultChatID) {
|
|
||||||
return self.alive(self._setThread(self._defaultChatID));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function() {
|
|
||||||
self._updateThreads();
|
|
||||||
self._startListening();
|
|
||||||
self._threadWidget.$el.on(
|
|
||||||
"scroll",
|
|
||||||
null,
|
|
||||||
_.debounce(function() {
|
|
||||||
var $noContent = self._threadWidget.$(".o_mail_no_content");
|
|
||||||
if (
|
|
||||||
self._threadWidget.getScrolltop() < 20 &&
|
|
||||||
!self._thread.isAllHistoryLoaded() &&
|
|
||||||
!$noContent.length
|
|
||||||
) {
|
|
||||||
self._loadMoreMessages();
|
|
||||||
}
|
|
||||||
if (self._threadWidget.isAtBottom()) {
|
|
||||||
self._thread.markAsRead();
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
_initRender: function () {
|
|
||||||
var self = this;
|
|
||||||
this._basicComposer = new BasicComposer(this, {
|
|
||||||
mentionPartnersRestricted: true,
|
|
||||||
});
|
|
||||||
this._extendedComposer = new ExtendedComposer(this, {
|
|
||||||
mentionPartnersRestricted: true,
|
|
||||||
});
|
|
||||||
this._basicComposer
|
|
||||||
.on("post_message", this, this._onPostMessage)
|
|
||||||
.on("input_focused", this, this._onComposerFocused);
|
|
||||||
this._extendedComposer
|
|
||||||
.on("post_message", this, this._onPostMessage)
|
|
||||||
.on("input_focused", this, this._onComposerFocused);
|
|
||||||
this._renderButtons();
|
|
||||||
|
|
||||||
var defs = [];
|
|
||||||
|
|
||||||
defs.push(this._renderThread());
|
|
||||||
defs.push(this._basicComposer.appendTo(this.$(".o_mail_discuss_content")));
|
|
||||||
return Promise.all(defs)
|
|
||||||
.then(function () {
|
|
||||||
if (self._defaultChatID) {
|
|
||||||
return self._setThread(self._defaultChatID);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function () {
|
|
||||||
self._updateThreads();
|
|
||||||
self._startListening();
|
|
||||||
self._threadWidget.$el.on(
|
|
||||||
"scroll",
|
|
||||||
null,
|
|
||||||
_.debounce(function () {
|
|
||||||
var $noContent = self._threadWidget.$(".o_mail_no_content");
|
|
||||||
if (
|
|
||||||
self._threadWidget.getScrolltop() < 20 &&
|
|
||||||
!self._thread.isAllHistoryLoaded() &&
|
|
||||||
!$noContent.length
|
|
||||||
) {
|
|
||||||
self._loadMoreMessages();
|
|
||||||
}
|
|
||||||
if (self._threadWidget.isAtBottom()) {
|
|
||||||
self._thread.markAsRead();
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_startListening: function () {
|
|
||||||
this.call("mail_service", "getMailBus").on(
|
|
||||||
"new_message",
|
|
||||||
this,
|
|
||||||
this._onNewMessage
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_setThread: function (threadID) {
|
|
||||||
this._storeThreadState();
|
|
||||||
var thread = this.call("mail_service", "getThread", threadID);
|
|
||||||
if (!thread) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._thread = thread;
|
const DiscussComponent = components.Discuss;
|
||||||
|
this.component = new DiscussComponent();
|
||||||
var self = this;
|
this._pushStateActionManagerEventListener = (ev) => {
|
||||||
this.messagesSeparatorPosition = undefined;
|
ev.stopPropagation();
|
||||||
return this._fetchAndRenderThread().then(function () {
|
if (this._lastPushStateActiveThread === this.discuss.thread) {
|
||||||
self._thread.markAsRead();
|
return;
|
||||||
// Restore scroll position and composer of the new
|
|
||||||
// current thread
|
|
||||||
self._restoreThreadState();
|
|
||||||
|
|
||||||
// Update control panel before focusing the composer, otherwise
|
|
||||||
// focus is on the searchview
|
|
||||||
self.set("title", self._thread.getTitle());
|
|
||||||
|
|
||||||
self.action_manager.do_push_state({
|
|
||||||
action: self.action.id,
|
|
||||||
active_id: self._thread.getID(),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_storeThreadState: function () {
|
|
||||||
if (this._thread) {
|
|
||||||
this._threadsScrolltop[
|
|
||||||
this._thread.getID()
|
|
||||||
] = this._threadWidget.getScrolltop();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_loadEnoughMessages: function () {
|
|
||||||
var $el = this._threadWidget.el;
|
|
||||||
var loadMoreMessages =
|
|
||||||
$el.clientHeight &&
|
|
||||||
$el.clientHeight === $el.scrollHeight &&
|
|
||||||
!this._thread.isAllHistoryLoaded();
|
|
||||||
if (loadMoreMessages) {
|
|
||||||
return this._loadMoreMessages().then(
|
|
||||||
this._loadEnoughMessages.bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_getThreadRenderingOptions: function () {
|
|
||||||
if (_.isUndefined(this.messagesSeparatorPosition)) {
|
|
||||||
if (this._unreadCounter) {
|
|
||||||
var messageID = this._thread.getLastSeenMessageID();
|
|
||||||
this.messagesSeparatorPosition = messageID || "top";
|
|
||||||
} else {
|
|
||||||
// No unread message -> don't display separator
|
|
||||||
this.messagesSeparatorPosition = false;
|
|
||||||
}
|
}
|
||||||
}
|
this._pushStateActionManager();
|
||||||
return {
|
this._lastPushStateActiveThread = this.discuss.thread;
|
||||||
displayLoadMore: !this._thread.isAllHistoryLoaded(),
|
|
||||||
squashCloseMessages: true,
|
|
||||||
messagesSeparatorPosition: this.messagesSeparatorPosition,
|
|
||||||
displayEmailIcons: false,
|
|
||||||
displayReplyIcons: false,
|
|
||||||
displayBottomThreadFreeSpace: true,
|
|
||||||
displayModerationCommands: false,
|
|
||||||
displayMarkAsRead: false,
|
|
||||||
displayDocumentLinks: false,
|
|
||||||
displayStars: false,
|
|
||||||
};
|
};
|
||||||
},
|
|
||||||
_fetchAndRenderThread: function () {
|
|
||||||
var self = this;
|
|
||||||
return this._thread.fetchMessages().then(function () {
|
|
||||||
self._threadWidget.render(
|
|
||||||
self._thread,
|
|
||||||
self._getThreadRenderingOptions()
|
|
||||||
);
|
|
||||||
return self._loadEnoughMessages();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_renderButtons: function () {
|
|
||||||
// This is a hook just in case some buttons are required
|
|
||||||
},
|
|
||||||
_renderThread: function () {
|
|
||||||
this._threadWidget = new ThreadWidget(this, {
|
|
||||||
areMessageAttachmentsDeletable: false,
|
|
||||||
loadMoreOnScroll: true,
|
|
||||||
});
|
|
||||||
this._threadWidget.on("load_more_messages", this, this._loadMoreMessages);
|
|
||||||
return this._threadWidget.appendTo(this.$(".o_mail_discuss_content"));
|
|
||||||
},
|
|
||||||
_renderSidebar: function (options) {
|
|
||||||
var $sidebar = $(
|
|
||||||
QWeb.render("mail_broker.broker.Sidebar", {
|
|
||||||
activeThreadID: this._thread ? this._thread.getID() : undefined,
|
|
||||||
bots: options.bots,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return $sidebar;
|
|
||||||
},
|
|
||||||
_restoreThreadState: function () {
|
|
||||||
var $newMessagesSeparator = this.$(".o_thread_new_messages_separator");
|
|
||||||
if ($newMessagesSeparator.length) {
|
|
||||||
this._threadWidget.$el.scrollTo($newMessagesSeparator);
|
|
||||||
} else {
|
|
||||||
var newThreadScrolltop = this._threadsScrolltop[this._thread.getID()];
|
|
||||||
this._threadWidget.scrollToPosition(newThreadScrolltop);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_updateThreads: function () {
|
|
||||||
var bots = this.call("mail_service", "getBrokerBots");
|
|
||||||
var $sidebar = this._renderSidebar({
|
|
||||||
bots: bots,
|
|
||||||
});
|
|
||||||
this.$(".o_mail_discuss_sidebar").html($sidebar.contents());
|
|
||||||
var self = this;
|
|
||||||
_.each(bots, function (bot, broker_id) {
|
|
||||||
var $input = self.$(
|
|
||||||
".o_mail_add_thread[data-bot=" + broker_id + "] input"
|
|
||||||
);
|
|
||||||
self._prepareAddThreadInput($input, broker_id, bot);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_prepareAddThreadInput: function ($input, broker_id) {
|
|
||||||
var self = this;
|
|
||||||
$input.autocomplete({
|
|
||||||
source: function (request, response) {
|
|
||||||
self._lastSearchVal = _.escape(request.term);
|
|
||||||
self._searchChannel(broker_id, self._lastSearchVal).then(function (
|
|
||||||
result
|
|
||||||
) {
|
|
||||||
response(result);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
select: function (ev, ui) {
|
|
||||||
self._setThread("broker_thread_" + ui.item.id);
|
|
||||||
self._updateThreads();
|
|
||||||
},
|
|
||||||
focus: function (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
},
|
|
||||||
html: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_loadMoreMessages: function () {
|
|
||||||
var self = this;
|
|
||||||
var oldestMessageID = this.$(".o_thread_message").first().data("messageId");
|
|
||||||
var oldestMessageSelector =
|
|
||||||
'.o_thread_message[data-message-id="' + oldestMessageID + '"]';
|
|
||||||
var offset = -dom.getPosition(document.querySelector(oldestMessageSelector))
|
|
||||||
.top;
|
|
||||||
return this._thread.fetchMessages({loadMore: true}).then(function () {
|
|
||||||
if (self.messagesSeparatorPosition === "top") {
|
|
||||||
// Reset value to re-compute separator position
|
|
||||||
self.messagesSeparatorPosition = undefined;
|
|
||||||
}
|
|
||||||
self._threadWidget.render(
|
|
||||||
self._thread,
|
|
||||||
self._getThreadRenderingOptions()
|
|
||||||
);
|
|
||||||
offset += dom.getPosition(document.querySelector(oldestMessageSelector))
|
|
||||||
.top;
|
|
||||||
self._threadWidget.scrollToPosition(offset);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_onSearchThread: function (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
var bot = $(ev.target).data("bot");
|
|
||||||
this.$(".o_mail_add_thread[data-bot=" + bot + "]")
|
|
||||||
.show()
|
|
||||||
.find("input")
|
|
||||||
.focus();
|
|
||||||
},
|
|
||||||
_onSearchThreadBlur: function () {
|
|
||||||
this.$(".o_mail_add_thread").hide();
|
|
||||||
},
|
|
||||||
_onChannelSettingsClicked: function (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
var threadID = $(ev.target).data("thread-id");
|
|
||||||
var thread = this.call("mail_service", "getThread", threadID);
|
|
||||||
this.do_action({
|
|
||||||
type: "ir.actions.act_window",
|
|
||||||
res_model: "mail.broker.channel",
|
|
||||||
res_id: thread.resId,
|
|
||||||
name: _t("Configure chat"),
|
|
||||||
views: [[false, "form"]],
|
|
||||||
target: "new",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_onNewMessage: function (message) {
|
|
||||||
var thread_id = "broker_thread_" + message.broker_channel_id;
|
|
||||||
if (this._thread && thread_id === this._thread.getID()) {
|
|
||||||
this._thread.markAsRead();
|
|
||||||
var shouldScroll = this._threadWidget.isAtBottom();
|
|
||||||
var self = this;
|
|
||||||
this._fetchAndRenderThread().then(function () {
|
|
||||||
if (shouldScroll) {
|
|
||||||
self._threadWidget.scrollToMessage({
|
|
||||||
msgID: message.getID(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Re-render sidebar to indicate that there is a new message in
|
|
||||||
// The corresponding threads
|
|
||||||
this._updateThreads();
|
|
||||||
// Dump scroll position of threads in which the new message arrived
|
|
||||||
this._threadsScrolltop = _.omit(
|
|
||||||
this._threadsScrolltop,
|
|
||||||
message.getThreadIDs()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_searchChannel: function (broker_id, searchVal) {
|
|
||||||
return this._rpc({
|
|
||||||
model: "mail.broker",
|
|
||||||
method: "channel_search",
|
|
||||||
args: [[parseInt(broker_id, 10)], searchVal],
|
|
||||||
}).then(function (result) {
|
|
||||||
var values = [];
|
|
||||||
_.each(result, function (channel) {
|
|
||||||
var escapedName = _.escape(channel.name);
|
|
||||||
values.push(
|
|
||||||
_.extend(channel, {
|
|
||||||
value: escapedName,
|
|
||||||
label: escapedName,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return values;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_onComposerFocused: function () {
|
|
||||||
// Hook
|
|
||||||
},
|
|
||||||
_onSelectBrokerChannel: function (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
var threadID = $(ev.currentTarget).data("thread-id");
|
|
||||||
this._setThread(threadID);
|
|
||||||
this._updateThreads();
|
|
||||||
},
|
|
||||||
_onPostMessage: function (messageData) {
|
|
||||||
var self = this;
|
|
||||||
var options = {};
|
|
||||||
if (this._selectedMessage) {
|
|
||||||
messageData.subtype = this._selectedMessage.isNote()
|
|
||||||
? "mail.mt_note"
|
|
||||||
: "mail.mt_comment";
|
|
||||||
messageData.subtype_id = false;
|
|
||||||
messageData.broker_type = "comment";
|
|
||||||
|
|
||||||
options.documentID = this._selectedMessage.getDocumentID();
|
this.el.addEventListener(
|
||||||
options.documentModel = this._selectedMessage.getDocumentModel();
|
"o-push-state-action-manager",
|
||||||
|
this._pushStateActionManagerEventListener
|
||||||
|
);
|
||||||
|
return this.component.mount(this.el);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override {web.AbstractAction}
|
||||||
|
*/
|
||||||
|
on_detach_callback() {
|
||||||
|
this._super(...arguments);
|
||||||
|
if (this.component) {
|
||||||
|
this.component.destroy();
|
||||||
}
|
}
|
||||||
this._thread
|
this.component = undefined;
|
||||||
.postMessage(messageData, options)
|
this.el.removeEventListener(
|
||||||
.then(function () {
|
"o-push-state-action-manager",
|
||||||
if (self._selectedMessage) {
|
this._pushStateActionManagerEventListener
|
||||||
self._renderSnackbar(
|
);
|
||||||
"mail.discuss.MessageSentSnackbar",
|
this._lastPushStateActiveThread = null;
|
||||||
{
|
},
|
||||||
documentName: self._selectedMessage.getDocumentName(),
|
|
||||||
},
|
// --------------------------------------------------------------------------
|
||||||
5000
|
// Private
|
||||||
);
|
// --------------------------------------------------------------------------
|
||||||
self._unselectMessage();
|
|
||||||
} else {
|
/**
|
||||||
self._threadWidget.scrollToBottom();
|
* @private
|
||||||
}
|
*/
|
||||||
})
|
_pushStateActionManager() {
|
||||||
.catch(function () {
|
this.actionManager.do_push_state({
|
||||||
// TODO: Display notifications
|
action: this.action.id,
|
||||||
});
|
active_id: this.discuss.activeId,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
action_registry.add("mail.broker", Broker);
|
||||||
core.action_registry.add("mail.broker", Broker);
|
|
||||||
|
|
||||||
return Broker;
|
return Broker;
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
odoo.define("mail_broker/static/src/js/broker_model.js", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {
|
||||||
|
registerNewModel,
|
||||||
|
registerInstancePatchModel,
|
||||||
|
registerFieldPatchModel,
|
||||||
|
registerClassPatchModel,
|
||||||
|
} = require("mail/static/src/model/model_core.js");
|
||||||
|
const {attr, many2one} = require("mail/static/src/model/model_field.js");
|
||||||
|
|
||||||
|
function factoryBroker(dependencies) {
|
||||||
|
class Broker extends dependencies["mail.model"] {}
|
||||||
|
Broker.modelName = "mail.broker";
|
||||||
|
Broker.fields = {
|
||||||
|
id: attr(),
|
||||||
|
name: attr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Broker;
|
||||||
|
}
|
||||||
|
registerNewModel("mail.broker", factoryBroker);
|
||||||
|
registerInstancePatchModel(
|
||||||
|
"mail.messaging_initializer",
|
||||||
|
"mail_broker/static/src/js/broker_model.js",
|
||||||
|
{
|
||||||
|
async _init({broker_slots}) {
|
||||||
|
_.each(broker_slots, (broker_slot) =>
|
||||||
|
this.env.models["mail.broker"].insert(
|
||||||
|
Object.assign({model: "mail.broker"}, broker_slot)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return this._super(...arguments);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
registerInstancePatchModel(
|
||||||
|
"mail.discuss",
|
||||||
|
"mail_broker/static/src/js/broker_model.js",
|
||||||
|
{
|
||||||
|
async openBrokerChannel(thread) {
|
||||||
|
this.update({
|
||||||
|
brokerChannel: [["link", thread]],
|
||||||
|
});
|
||||||
|
this.focus();
|
||||||
|
this.env.bus.trigger("do-action", {
|
||||||
|
action: "mail_broker.mail_broker_action_window",
|
||||||
|
options: {
|
||||||
|
active_id: this.threadToActiveId(this),
|
||||||
|
clear_breadcrumbs: false,
|
||||||
|
on_reverse_breadcrumb: () => this.close(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
registerClassPatchModel(
|
||||||
|
"mail.thread",
|
||||||
|
"mail_broker/static/src/js/broker_model.js",
|
||||||
|
{
|
||||||
|
convertData(data) {
|
||||||
|
const data2 = this._super(data);
|
||||||
|
data2.broker_id = data.broker_id;
|
||||||
|
data2.broker_unread_counter = data.broker_unread_counter;
|
||||||
|
return data2;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
registerFieldPatchModel(
|
||||||
|
"mail.discuss",
|
||||||
|
"mail_broker/static/src/js/broker_model.js",
|
||||||
|
{
|
||||||
|
brokerChannel: many2one("mail.thread"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
registerFieldPatchModel(
|
||||||
|
"mail.thread",
|
||||||
|
"mail_broker/static/src/js/broker_model.js",
|
||||||
|
{
|
||||||
|
broker_id: attr(),
|
||||||
|
broker_unread_counter: attr(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
|
@ -0,0 +1,69 @@
|
||||||
|
odoo.define("mail_broker/static/src/discuss.js", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Discuss = require("mail/static/src/components/discuss/discuss.js");
|
||||||
|
const DiscussSidebar = require("mail/static/src/components/discuss_sidebar/discuss_sidebar.js");
|
||||||
|
const DiscussSidebarItem = require("mail/static/src/components/discuss_sidebar_item/discuss_sidebar_item.js");
|
||||||
|
|
||||||
|
const {Component} = owl;
|
||||||
|
|
||||||
|
class BrokerDiscussSidebarItem extends DiscussSidebarItem {
|
||||||
|
get counter() {
|
||||||
|
if (this.thread.channel_type === "broker") {
|
||||||
|
return this.thread.broker_unread_counter;
|
||||||
|
}
|
||||||
|
return super.counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DiscussSidebarBroker extends Component {
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
this.mailBroker = this.env.models["mail.broker"].get(this.props.brokerId);
|
||||||
|
}
|
||||||
|
get quickSearchOrderedAndPinnedBrokerChannels() {
|
||||||
|
return this.env.models["mail.thread"]
|
||||||
|
.all((channel) => channel.broker_id === this.mailBroker.id)
|
||||||
|
.sort((c1, c2) => {
|
||||||
|
if (!c1.lastMessage && !c2.lastMessage) {
|
||||||
|
return c1.id < c2.id;
|
||||||
|
} else if (!c2.lastMessage) {
|
||||||
|
return -1;
|
||||||
|
} else if (!c1.lastMessage) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return c1.lastMessage.id < c2.lastMessage.id ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.assign(DiscussSidebarBroker, {
|
||||||
|
components: Object.assign(DiscussSidebar.components, {
|
||||||
|
DiscussSidebarItem: BrokerDiscussSidebarItem,
|
||||||
|
}),
|
||||||
|
props: {
|
||||||
|
brokerId: String,
|
||||||
|
},
|
||||||
|
template: "mail_broker.DiscussSidebarBroker",
|
||||||
|
});
|
||||||
|
|
||||||
|
class BrokerDiscussSidebar extends DiscussSidebar {
|
||||||
|
get mailBrokers() {
|
||||||
|
return this.env.models["mail.broker"].all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.assign(BrokerDiscussSidebar, {
|
||||||
|
components: Object.assign(DiscussSidebar.components, {DiscussSidebarBroker}),
|
||||||
|
props: DiscussSidebar.props,
|
||||||
|
template: "mail_broker.DiscussSidebar",
|
||||||
|
});
|
||||||
|
|
||||||
|
class NewDiscuss extends Discuss {}
|
||||||
|
Object.assign(NewDiscuss, {
|
||||||
|
components: Object.assign({}, Discuss.components, {
|
||||||
|
DiscussSidebar: BrokerDiscussSidebar,
|
||||||
|
}),
|
||||||
|
props: Discuss.props,
|
||||||
|
template: Discuss.template,
|
||||||
|
});
|
||||||
|
return NewDiscuss;
|
||||||
|
});
|
|
@ -1,18 +1,23 @@
|
||||||
odoo.define("mail_broker.model.Message", function (require) {
|
odoo.define("mail_broker/static/src/js/message.js", function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Message = require("mail.model.Message");
|
const {registerClassPatchModel} = require("mail/static/src/model/model_core.js");
|
||||||
|
|
||||||
Message.include({
|
registerClassPatchModel(
|
||||||
init: function (parent, data) {
|
"mail.message",
|
||||||
this._super.apply(this, arguments);
|
"mail/static/src/models/message/message.js",
|
||||||
this.broker_channel_id = data.broker_channel_id || false;
|
{
|
||||||
this.broker_unread = data.broker_unread || false;
|
convertData(data) {
|
||||||
this.broker_type = data.broker_type || false;
|
const data2 = this._super(data);
|
||||||
this.customer_status = data.customer_status || false;
|
if ("broker_channel_id" in data) {
|
||||||
},
|
data2.broker_channel_id = data.broker_channel_id || false;
|
||||||
isNeedaction: function () {
|
data2.broker_unread = data.broker_unread || false;
|
||||||
return this._super.apply(this, arguments) || this.broker_unread;
|
data2.broker_type = data.broker_type || false;
|
||||||
},
|
data2.customer_status = data.customer_status || false;
|
||||||
});
|
data2.isNeedaction = data2.isNeedaction || data.broker_unread;
|
||||||
|
}
|
||||||
|
return data2;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -65,7 +65,7 @@ odoo.define("mail_broker.BrokerThread", function (require) {
|
||||||
domain = [["id", "<", minMessageID]].concat(domain);
|
domain = [["id", "<", minMessageID]].concat(domain);
|
||||||
}
|
}
|
||||||
return this._rpc({
|
return this._rpc({
|
||||||
model: "mail.broker.channel",
|
model: "mail.channel",
|
||||||
method: "message_fetch",
|
method: "message_fetch",
|
||||||
args: [[this.resId], domain],
|
args: [[this.resId], domain],
|
||||||
kwargs: this._getFetchMessagesKwargs(options),
|
kwargs: this._getFetchMessagesKwargs(options),
|
||||||
|
|
|
@ -1,5 +1,63 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="mail_broker.broker">
|
||||||
|
<div class="o_widget_Discuss" />
|
||||||
|
</t>
|
||||||
|
<t t-name="mail_broker.DiscussSidebarBroker" owl="1">
|
||||||
|
<div>
|
||||||
|
<div class="o_DiscussSidebar_groupHeader">
|
||||||
|
<div
|
||||||
|
class="o_DiscussSidebar_groupHeaderItem o_DiscussSidebar_groupTitle o-clickable"
|
||||||
|
t-esc="mailBroker.name"
|
||||||
|
/>
|
||||||
|
<div class="o-autogrow" />
|
||||||
|
<div
|
||||||
|
class="o_DiscussSidebar_groupHeaderItem o_DiscussSidebar_groupHeaderItemAdd fa fa-plus"
|
||||||
|
t-on-click="_onClickChannelAdd"
|
||||||
|
title="Add or join a channel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="o_DiscussSidebar_list">
|
||||||
|
<div class="o_DiscussSidebar_item o_DiscussSidebar_itemNew">
|
||||||
|
<AutocompleteInput
|
||||||
|
class="o_DiscussSidebar_itemNewInput"
|
||||||
|
customClass="'o_DiscussSidebar_newChannelAutocompleteSuggestions'"
|
||||||
|
isFocusOnMount="true"
|
||||||
|
isHtml="true"
|
||||||
|
placeholder="FIND_OR_CREATE_CHANNEL"
|
||||||
|
select="_onAddChannelAutocompleteSelect"
|
||||||
|
source="_onAddChannelAutocompleteSource"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<t
|
||||||
|
t-foreach="quickSearchOrderedAndPinnedBrokerChannels"
|
||||||
|
t-as="brokerChannel"
|
||||||
|
t-key="brokerChannel.localId"
|
||||||
|
>
|
||||||
|
<DiscussSidebarItem
|
||||||
|
class="o_DiscussSidebar_item"
|
||||||
|
threadLocalId="brokerChannel.localId"
|
||||||
|
/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<t t-name="mail_broker.DiscussSidebar" owl="1">
|
||||||
|
<div name="root" class="o_DiscussSidebar">
|
||||||
|
<div class="o_DiscussSidebar_group o_DiscussSidebar_groupChannel">
|
||||||
|
<div class="o_DiscussSidebar_list">
|
||||||
|
<t
|
||||||
|
t-foreach="mailBrokers"
|
||||||
|
t-as="mailBroker"
|
||||||
|
t-key="mailBroker.localId"
|
||||||
|
>
|
||||||
|
<DiscussSidebarBroker brokerId="mailBroker.localId" />
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
<!--
|
||||||
<t t-extend="mail.widget.Thread.Message">
|
<t t-extend="mail.widget.Thread.Message">
|
||||||
<t t-jquery=".o_mail_info" t-operation="append">
|
<t t-jquery=".o_mail_info" t-operation="append">
|
||||||
<span
|
<span
|
||||||
|
@ -44,5 +102,5 @@
|
||||||
<t t-jquery=".o_input" t-operation="attributes">
|
<t t-jquery=".o_input" t-operation="attributes">
|
||||||
<attribute name="t-attf-data-bot">#{bot_key}</attribute>
|
<attribute name="t-attf-data-bot">#{bot_key}</attribute>
|
||||||
</t>
|
</t>
|
||||||
</t>
|
</t>-->
|
||||||
</templates>
|
</templates>
|
||||||
|
|
|
@ -8,9 +8,16 @@
|
||||||
/>
|
/>
|
||||||
<script
|
<script
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="/mail_broker/static/src/js/manager.js"
|
src="/mail_broker/static/src/js/discuss.js"
|
||||||
|
/><!--
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/mail_broker/static/src/js/messaging_initializer.js"
|
||||||
|
/>-->
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/mail_broker/static/src/js/broker_model.js"
|
||||||
/>
|
/>
|
||||||
<script type="text/javascript" src="/mail_broker/static/src/js/thread.js" />
|
|
||||||
<script type="text/javascript" src="/mail_broker/static/src/js/broker.js" />
|
<script type="text/javascript" src="/mail_broker/static/src/js/broker.js" />
|
||||||
<link rel="stylesheet" href="/mail_broker/static/src/scss/broker.scss" />
|
<link rel="stylesheet" href="/mail_broker/static/src/scss/broker.scss" />
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
|
@ -2,72 +2,10 @@
|
||||||
<!-- Copyright 2020 Creu Blanca
|
<!-- Copyright 2020 Creu Blanca
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||||
<odoo>
|
<odoo>
|
||||||
<record model="ir.ui.view" id="mail_broker_channel_form_view">
|
|
||||||
<field name="name">mail.broker.channel.form</field>
|
|
||||||
<field name="model">mail.broker.channel</field>
|
|
||||||
<field name="priority">10</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form>
|
|
||||||
<header />
|
|
||||||
<sheet>
|
|
||||||
<div class="oe_button_box" name="button_box" />
|
|
||||||
<group>
|
|
||||||
<field name="name" />
|
|
||||||
<field name="partner_id" />
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.ui.view" id="mail_broker_channel_form_root_view">
|
|
||||||
<field name="name">mail.broker.channel.form</field>
|
|
||||||
<field name="model">mail.broker.channel</field>
|
|
||||||
<field name="inherit_id" ref="mail_broker.mail_broker_channel_form_view" />
|
|
||||||
<field name="groups_id" eval="[(6, 0, [ref('base.group_system')])]" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="name" position="after">
|
|
||||||
<field name="token" />
|
|
||||||
<field name="broker_id" />
|
|
||||||
<field name="show_on_app" />
|
|
||||||
<field name="token" />
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.ui.view" id="mail_broker_channel_search_view">
|
|
||||||
<field name="name">mail.broker.channel.search (in mail_broker)</field>
|
|
||||||
<field name="model">mail.broker.channel</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search>
|
|
||||||
<field name="name" />
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.ui.view" id="mail_broker_channel_tree_view">
|
|
||||||
<field name="name">mail.broker.channel.tree (in mail_broker)</field>
|
|
||||||
<field name="model">mail.broker.channel</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree>
|
|
||||||
<field name="name" />
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.actions.act_window" id="mail_broker_channel_act_window">
|
|
||||||
<field name="name">Mail Broker Channel</field>
|
|
||||||
<field name="res_model">mail.broker.channel</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
<field name="domain">[]</field>
|
|
||||||
<field name="context">{}</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.ui.menu" id="mail_broker_channel_menu">
|
|
||||||
<field name="name">Mail Broker Channel</field>
|
|
||||||
<field name="parent_id" ref="base.menu_email" />
|
|
||||||
<field name="action" ref="mail_broker_channel_act_window" />
|
|
||||||
<field name="sequence" eval="16" />
|
|
||||||
</record>
|
|
||||||
<record id="mail_broker_action_window" model="ir.actions.client">
|
<record id="mail_broker_action_window" model="ir.actions.client">
|
||||||
<field name="name">Broker</field>
|
<field name="name">Broker</field>
|
||||||
<field name="tag">mail.broker</field>
|
<field name="tag">mail.broker</field>
|
||||||
<field name="res_model">mail.broker.channel</field>
|
<field name="res_model">mail.channel</field>
|
||||||
<field name="params" eval="{}" />
|
<field name="params" eval="{}" />
|
||||||
</record>
|
</record>
|
||||||
<menuitem
|
<menuitem
|
||||||
|
|
Loading…
Reference in New Issue