[IMP] im_livechat, mail: allow CORS livechat actions
This PR makes several actions available for the embed livechat such as: - calls - message edition - message reactions - link previews task-3523930 closes odoo/odoo#136618 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -3,3 +3,4 @@ from . import controllers
|
||||
from . import models
|
||||
from . import report
|
||||
from . import demo
|
||||
from . import tools
|
||||
|
||||
@@ -107,6 +107,7 @@ Help your customers with this chat, and analyse their feedback.
|
||||
'im_livechat/static/src/embed/livechat_data.js',
|
||||
('remove', 'im_livechat/static/src/embed/frontend/**/*'),
|
||||
('remove', 'im_livechat/static/src/embed/external/**/*'),
|
||||
('remove', 'im_livechat/static/src/embed/cors/**/*'),
|
||||
],
|
||||
'im_livechat.assets_embed': [
|
||||
'web/static/lib/jquery/jquery.js',
|
||||
@@ -132,6 +133,10 @@ Help your customers with this chat, and analyse their feedback.
|
||||
('include', 'im_livechat.assets_core'),
|
||||
'im_livechat/static/src/embed/external/**/*',
|
||||
],
|
||||
'im_livechat.assets_cors': [
|
||||
('include', 'im_livechat.assets_embed'),
|
||||
'im_livechat/static/src/embed/cors/**/*',
|
||||
],
|
||||
'im_livechat.embed_test_assets': [
|
||||
('include', 'web.tests_assets'),
|
||||
('remove', 'web/static/tests/mock_server_tests.js'),
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
from . import chatbot
|
||||
from . import main
|
||||
from . import webclient
|
||||
from . import cors
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import channel
|
||||
from . import link_preview
|
||||
from . import main
|
||||
from . import message_reaction
|
||||
from . import rtc
|
||||
from . import thread
|
||||
from . import webclient
|
||||
@@ -0,0 +1,17 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.discuss.channel import ChannelController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class LivechatChannelController(ChannelController):
|
||||
@route("/im_livechat/cors/channel/messages", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_channel_messages(self, guest_token, channel_id, before=None, after=None, limit=30, around=None):
|
||||
force_guest_env(guest_token)
|
||||
return self.discuss_channel_messages(channel_id, before, after, limit, around)
|
||||
|
||||
@route("/im_livechat/cors/channel/set_last_seen_message", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_channel_mark_as_seen(self, guest_token, channel_id, last_message_id, allow_older=False):
|
||||
force_guest_env(guest_token)
|
||||
return self.discuss_channel_mark_as_seen(channel_id, last_message_id, allow_older)
|
||||
@@ -0,0 +1,17 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.link_preview import LinkPreviewController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class LivechatLinkPreviewController(LinkPreviewController):
|
||||
@route("/im_livechat/cors/link_preview", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_link_preview(self, guest_token, message_id, clear=None):
|
||||
force_guest_env(guest_token)
|
||||
self.mail_link_preview(message_id, clear)
|
||||
|
||||
@route("/im_livechat/cors/link_preview/delete", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_link_preview_delete(self, guest_token, link_preview_ids):
|
||||
force_guest_env(guest_token)
|
||||
self.mail_link_preview_delete(link_preview_ids)
|
||||
@@ -0,0 +1,21 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.im_livechat.controllers.main import LivechatController
|
||||
from odoo.addons.im_livechat.tools.misc import downgrade_to_public_user, force_guest_env
|
||||
|
||||
|
||||
class CorsLivechatController(LivechatController):
|
||||
@route("/im_livechat/cors/visitor_leave_session", type="json", auth="public", cors="*")
|
||||
def cors_visitor_leave_session(self, guest_token, uuid):
|
||||
force_guest_env(guest_token)
|
||||
self.visitor_leave_session(uuid)
|
||||
|
||||
@route("/im_livechat/cors/get_session", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def cors_get_session(
|
||||
self, channel_id, anonymous_name, previous_operator_id=None, chatbot_script_id=None, persisted=True, **kwargs
|
||||
):
|
||||
downgrade_to_public_user()
|
||||
return self.get_session(
|
||||
channel_id, anonymous_name, previous_operator_id, chatbot_script_id, persisted, **kwargs
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.message_reaction import MessageReactionController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class LivechatMessageReactionController(MessageReactionController):
|
||||
@route("/im_livechat/cors/message/reaction", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_message_add_reaction(self, guest_token, message_id, content, action):
|
||||
force_guest_env(guest_token)
|
||||
return self.mail_message_add_reaction(message_id, content, action)
|
||||
@@ -0,0 +1,32 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.discuss.rtc import RtcController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class LivechatRtcController(RtcController):
|
||||
@route("/im_livechat/cors/rtc/channel/join_call", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_channel_call_join(self, guest_token, channel_id, check_rtc_session_ids=None):
|
||||
force_guest_env(guest_token)
|
||||
return self.channel_call_join(channel_id, check_rtc_session_ids)
|
||||
|
||||
@route("/im_livechat/cors/rtc/channel/leave_call", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_channel_call_leave(self, guest_token, channel_id):
|
||||
force_guest_env(guest_token)
|
||||
return self.channel_call_leave(channel_id)
|
||||
|
||||
@route("/im_livechat/cors/rtc/session/update_and_broadcast", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_session_update_and_broadcast(self, guest_token, session_id, values):
|
||||
force_guest_env(guest_token)
|
||||
self.session_update_and_broadcast(session_id, values)
|
||||
|
||||
@route("/im_livechat/cors/rtc/session/notify_call_members", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_session_call_notify(self, guest_token, peer_notifications):
|
||||
force_guest_env(guest_token)
|
||||
self.session_call_notify(peer_notifications)
|
||||
|
||||
@route("/im_livechat/cors/channel/ping", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_channel_ping(self, guest_token, channel_id, rtc_session_id=None, check_rtc_session_ids=None):
|
||||
force_guest_env(guest_token)
|
||||
return self.channel_ping(channel_id, rtc_session_id, check_rtc_session_ids)
|
||||
@@ -0,0 +1,19 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.thread import ThreadController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class LivechatThreadController(ThreadController):
|
||||
@route("/im_livechat/cors/message/post", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_message_post(self, guest_token, thread_model, thread_id, post_data, context=None):
|
||||
force_guest_env(guest_token)
|
||||
return self.mail_message_post(thread_model, thread_id, post_data, context)
|
||||
|
||||
@route("/im_livechat/cors/message/update_content", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_message_update_content(
|
||||
self, guest_token, message_id, body, attachment_ids, attachment_tokens=None, partner_ids=None
|
||||
):
|
||||
force_guest_env(guest_token)
|
||||
return self.mail_message_update_content(message_id, body, attachment_ids, attachment_tokens, partner_ids)
|
||||
@@ -0,0 +1,12 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.controllers.webclient import WebclientController
|
||||
from odoo.addons.im_livechat.tools.misc import force_guest_env
|
||||
|
||||
|
||||
class WebClient(WebclientController):
|
||||
@route("/im_livechat/cors/init_messaging", methods=["POST"], type="json", auth="public", cors="*")
|
||||
def livechat_init_messaging(self, guest_token):
|
||||
force_guest_env(guest_token)
|
||||
return super().mail_init_messaging()
|
||||
@@ -3,6 +3,7 @@
|
||||
from markupsafe import Markup
|
||||
import re
|
||||
from werkzeug.exceptions import NotFound
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
from odoo import http, tools, _, release
|
||||
from odoo.http import request
|
||||
@@ -30,7 +31,13 @@ class LivechatController(http.Controller):
|
||||
|
||||
@http.route('/im_livechat/assets_embed.<any(css, js):ext>', type='http', auth='public', cors='*')
|
||||
def assets_embed(self, ext, **kwargs):
|
||||
# If the request comes from a different origin, we must provide the CORS
|
||||
# assets to enable the redirection of routes to the CORS controller.
|
||||
headers = request.httprequest.headers
|
||||
origin_url = urlsplit(headers.get('referer'))
|
||||
bundle = 'im_livechat.assets_embed'
|
||||
if origin_url.netloc != headers.get('host') or origin_url.scheme != request.httprequest.scheme:
|
||||
bundle = 'im_livechat.assets_cors'
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
if ext not in ('css', 'js'):
|
||||
raise request.not_found()
|
||||
@@ -143,7 +150,7 @@ class LivechatController(http.Controller):
|
||||
def _get_guest_name(self):
|
||||
return _("Visitor")
|
||||
|
||||
@http.route('/im_livechat/get_session', methods=["POST"], type="json", auth='public', cors="*")
|
||||
@http.route('/im_livechat/get_session', methods=["POST"], type="json", auth='public')
|
||||
@add_guest_to_context
|
||||
def get_session(self, channel_id, anonymous_name, previous_operator_id=None, chatbot_script_id=None, persisted=True, **kwargs):
|
||||
user_id = None
|
||||
@@ -252,20 +259,6 @@ class LivechatController(http.Controller):
|
||||
channel._send_history_message(pid, page_history)
|
||||
return True
|
||||
|
||||
@http.route('/im_livechat/notify_typing', type='json', auth='public', cors="*")
|
||||
def notify_typing(self, uuid, is_typing):
|
||||
""" Broadcast the typing notification of the website user to other channel members
|
||||
: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['discuss.channel'].sudo().search([('uuid', '=', uuid)])
|
||||
if not channel:
|
||||
raise NotFound()
|
||||
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['discuss.channel'].sudo().search([
|
||||
@@ -274,7 +267,7 @@ class LivechatController(http.Controller):
|
||||
if channel:
|
||||
channel._email_livechat_transcript(email)
|
||||
|
||||
@http.route('/im_livechat/visitor_leave_session', type='json', auth="public", cors="*")
|
||||
@http.route('/im_livechat/visitor_leave_session', type='json', auth="public")
|
||||
@add_guest_to_context
|
||||
def visitor_leave_session(self, uuid):
|
||||
""" Called when the livechat visitor leaves the conversation.
|
||||
@@ -287,11 +280,3 @@ class LivechatController(http.Controller):
|
||||
channel_member_sudo = request.env["discuss.channel.member"]._get_as_sudo_from_context_or_raise(channel_id=discuss_channel.id)
|
||||
channel_member_sudo._rtc_leave_call()
|
||||
discuss_channel._close_livechat_session()
|
||||
|
||||
@http.route(['/im_livechat/chat_history'], type="json", auth="public", cors="*")
|
||||
def im_livechat_chat_history(self, uuid, last_id=False, limit=20):
|
||||
channel = request.env["discuss.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
|
||||
if not channel:
|
||||
return []
|
||||
else:
|
||||
return channel._channel_fetch_message(last_id, limit)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { livechatRoutingMap } from "@im_livechat/embed/cors/livechat_routing_map";
|
||||
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { jsonrpc } from "@web/core/network/rpc_service";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { session } from "@web/session";
|
||||
|
||||
(async function boot() {
|
||||
const { fetch } = browser;
|
||||
browser.fetch = function (url, ...args) {
|
||||
if (!url.match(/^(?:https?:)?\/\//)) {
|
||||
url = session.origin + url;
|
||||
}
|
||||
return fetch(url, ...args);
|
||||
};
|
||||
// Override the rpc service to forward requests to CORS-allowed routes. The
|
||||
// "guest_token" will be appended to the request parameters for
|
||||
// authentication.
|
||||
registry.category("services").add(
|
||||
"rpc",
|
||||
{
|
||||
async: true,
|
||||
start(env) {
|
||||
return function rpc(route, params = {}, settings) {
|
||||
if (route in livechatRoutingMap.content) {
|
||||
route = livechatRoutingMap.get(route, route);
|
||||
if (env.services["im_livechat.livechat"]?.guestToken) {
|
||||
params = {
|
||||
...params,
|
||||
guest_token: env.services["im_livechat.livechat"].guestToken,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!route.match(/^(?:https?:)?\/\//)) {
|
||||
route = session.origin + route;
|
||||
}
|
||||
return jsonrpc(route, params, { bus: env.bus, ...settings });
|
||||
};
|
||||
},
|
||||
},
|
||||
{ force: true }
|
||||
);
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
/**
|
||||
* This routing map is used to redirect the requests made by the livechat to
|
||||
* dedicated CORS-allowed routes. Every route expected to be called by the
|
||||
* livechat should be added here. Note that this will only be used if the
|
||||
* livechat is loaded from a different origin than the Odoo server.
|
||||
*
|
||||
* @see /im_livechat/embed/cors/boot.js
|
||||
*/
|
||||
export const livechatRoutingMap = registry.category("discuss.routing_map");
|
||||
|
||||
livechatRoutingMap
|
||||
.add("/discuss/channel/messages", "/im_livechat/cors/channel/messages")
|
||||
.add(
|
||||
"/discuss/channel/set_last_seen_message",
|
||||
"/im_livechat/cors/channel/set_last_seen_message"
|
||||
)
|
||||
.add("/discuss/channel/ping", "/im_livechat/cors/channel/ping")
|
||||
.add("/mail/init_messaging", "/im_livechat/cors/init_messaging")
|
||||
.add("/mail/link_preview", "/im_livechat/cors/link_preview")
|
||||
.add("/mail/link_preview/delete", "/im_livechat/cors/link_preview/delete")
|
||||
.add("/mail/message/post", "/im_livechat/cors/message/post")
|
||||
.add("/mail/message/reaction", "/im_livechat/cors/message/reaction")
|
||||
.add("/mail/message/update_content", "/im_livechat/cors/message/update_content")
|
||||
.add("/mail/rtc/channel/join_call", "/im_livechat/cors/rtc/channel/join_call")
|
||||
.add("/mail/rtc/channel/leave_call", "/im_livechat/cors/rtc/channel/leave_call")
|
||||
.add(
|
||||
"/mail/rtc/session/notify_call_members",
|
||||
"/im_livechat/cors/rtc/session/notify_call_members"
|
||||
)
|
||||
.add(
|
||||
"/mail/rtc/session/update_and_broadcast",
|
||||
"/im_livechat/cors/rtc/session/update_and_broadcast"
|
||||
)
|
||||
.add("/im_livechat/visitor_leave_session", "/im_livechat/cors/visitor_leave_session")
|
||||
.add("/im_livechat/get_session", "/im_livechat/cors/get_session");
|
||||
+1
-25
@@ -1,7 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { makeRoot, makeShadow } from "@im_livechat/embed/boot_helpers";
|
||||
import { LivechatButton } from "@im_livechat/embed/core_ui/livechat_button";
|
||||
import { makeShadow, makeRoot } from "@im_livechat/embed/boot_helpers";
|
||||
import { serverUrl } from "@im_livechat/embed/livechat_data";
|
||||
|
||||
import { ChatWindowContainer } from "@mail/core/common/chat_window_container";
|
||||
@@ -9,37 +9,13 @@ import { ChatWindowContainer } from "@mail/core/common/chat_window_container";
|
||||
import { mount, whenReady } from "@odoo/owl";
|
||||
|
||||
import { templates } from "@web/core/assets";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { MainComponentsContainer } from "@web/core/main_components_container";
|
||||
import { jsonrpc } from "@web/core/network/rpc_service";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { makeEnv, startServices } from "@web/env";
|
||||
import { session } from "@web/session";
|
||||
|
||||
(async function boot() {
|
||||
session.origin = serverUrl;
|
||||
const { fetch } = browser;
|
||||
browser.fetch = function (url, ...args) {
|
||||
if (!url.match(/^(?:https?:)?\/\//)) {
|
||||
url = session.origin + url;
|
||||
}
|
||||
return fetch(url, ...args);
|
||||
};
|
||||
registry.category("services").add(
|
||||
"rpc",
|
||||
{
|
||||
async: true,
|
||||
start(env) {
|
||||
return function rpc(route, params = {}, settings = {}) {
|
||||
if (!route.match(/^(?:https?:)?\/\//)) {
|
||||
route = session.origin + route;
|
||||
}
|
||||
return jsonrpc(route, params, { bus: env.bus, ...settings });
|
||||
};
|
||||
},
|
||||
},
|
||||
{ force: true }
|
||||
);
|
||||
await whenReady();
|
||||
const mainComponentsRegistry = registry.category("main_components");
|
||||
mainComponentsRegistry.add("LivechatRoot", { Component: LivechatButton });
|
||||
|
||||
@@ -5,6 +5,7 @@ from . import chatbot_common
|
||||
from . import test_chatbot_form_ui
|
||||
from . import test_chatbot_internals
|
||||
from . import test_digest
|
||||
from . import test_cors_livechat
|
||||
from . import test_get_discuss_channel
|
||||
from . import test_get_operator
|
||||
from . import test_im_livechat_report
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import tagged, HttpCase, JsonRpcException
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestCorsLivechat(HttpCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.operator = cls.env["res.users"].create(
|
||||
{
|
||||
"name": "Operator",
|
||||
"login": "operator",
|
||||
}
|
||||
)
|
||||
cls.env["bus.presence"].create(
|
||||
{
|
||||
"user_id": cls.operator.id,
|
||||
"status": "online",
|
||||
}
|
||||
)
|
||||
cls.livechat_channel = cls.env["im_livechat.channel"].create(
|
||||
{"name": "Test Livechat Channel", "user_ids": [cls.operator.id]}
|
||||
)
|
||||
|
||||
def test_ignore_user_cookie(self):
|
||||
self.authenticate("admin", "admin")
|
||||
channel_info = self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/get_session",
|
||||
{
|
||||
"anonymous_name": "Visitor",
|
||||
"channel_id": self.livechat_channel.id,
|
||||
"persisted": True,
|
||||
},
|
||||
)
|
||||
channel = self.env["discuss.channel"].browse(channel_info["id"])
|
||||
self.assertEqual(channel.channel_member_ids[0].partner_id, self.operator.partner_id)
|
||||
self.assertFalse(channel.channel_member_ids[1].partner_id)
|
||||
self.assertTrue(channel.channel_member_ids[1].guest_id)
|
||||
|
||||
def test_ignore_guest_cookie(self):
|
||||
guest = self.env["mail.guest"].create({"name": "Visitor"})
|
||||
channel_info = self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/get_session",
|
||||
{
|
||||
"anonymous_name": "Visitor",
|
||||
"channel_id": self.livechat_channel.id,
|
||||
"persisted": True,
|
||||
},
|
||||
headers={"Cookie": f"{guest._cookie_name}={guest.id}{guest._cookie_separator}{guest.access_token};"},
|
||||
)
|
||||
channel = self.env["discuss.channel"].browse(channel_info["id"])
|
||||
channel_guest = channel.channel_member_ids.filtered(lambda member: member.guest_id).guest_id
|
||||
self.assertNotEqual(channel_guest, guest)
|
||||
|
||||
def test_access_routes_with_valid_guest_token(self):
|
||||
channel_info = self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/get_session",
|
||||
{
|
||||
"anonymous_name": "Visitor",
|
||||
"channel_id": self.livechat_channel.id,
|
||||
"persisted": True,
|
||||
},
|
||||
)
|
||||
self.authenticate(None, None)
|
||||
self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/channel/messages",
|
||||
{
|
||||
"guest_token": channel_info["guest_token"],
|
||||
"channel_id": channel_info["id"],
|
||||
},
|
||||
)
|
||||
|
||||
def test_access_denied_for_wrong_channel(self):
|
||||
channel_info = self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/get_session",
|
||||
{
|
||||
"anonymous_name": "Visitor",
|
||||
"channel_id": self.livechat_channel.id,
|
||||
"persisted": True,
|
||||
},
|
||||
)
|
||||
guest = self.env["mail.guest"].create({"name": "Visitor"})
|
||||
self.authenticate(None, None)
|
||||
with self.assertRaises(JsonRpcException, msg="werkzeug.exceptions.NotFound"):
|
||||
self.make_jsonrpc_request(
|
||||
"/im_livechat/cors/channel/messages",
|
||||
{
|
||||
"guest_token": guest.access_token,
|
||||
"channel_id": channel_info["id"],
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import misc
|
||||
@@ -0,0 +1,25 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import request
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
def downgrade_to_public_user():
|
||||
"""Replace the request user by the public one. All the cookies are removed
|
||||
in order to ensure that the no user-specific data is kept in the request."""
|
||||
public_user = request.env.ref("base.public_user")
|
||||
request.update_env(user=public_user)
|
||||
request.httprequest.cookies = {}
|
||||
|
||||
|
||||
def force_guest_env(guest_token):
|
||||
"""Retrieve the guest from the given token and add it to the context.
|
||||
The request user is then replaced by the public one.
|
||||
|
||||
:param str guest_token:
|
||||
:raise NotFound: if the guest cannot be found from the token
|
||||
"""
|
||||
guest = request.env["mail.guest"]._get_guest_from_token(guest_token)
|
||||
if not guest:
|
||||
raise NotFound()
|
||||
request.update_context(guest=guest)
|
||||
downgrade_to_public_user()
|
||||
@@ -28,21 +28,15 @@ def add_guest_to_context(func):
|
||||
req.httprequest.cookies.get(req.env["mail.guest"]._cookie_name)
|
||||
or req.env.context.get("guest_token", "")
|
||||
)
|
||||
parts = token.split(req.env["mail.guest"]._cookie_separator)
|
||||
guest = req.env["mail.guest"]
|
||||
if len(parts) == 2:
|
||||
guest_id, guest_access_token = parts
|
||||
guest = req.env["mail.guest"].browse(int(guest_id)).sudo().exists()
|
||||
if not guest or not guest.access_token or not consteq(guest.access_token, guest_access_token):
|
||||
guest = req.env["mail.guest"]
|
||||
elif not guest.timezone:
|
||||
timezone = req.env["mail.guest"]._get_timezone_from_request(req)
|
||||
if timezone:
|
||||
guest._update_timezone(timezone)
|
||||
guest = guest.sudo(False)
|
||||
req.update_context(guest=guest)
|
||||
if hasattr(self, "env"):
|
||||
self.env.context = {**self.env.context, "guest": guest}
|
||||
guest = req.env["mail.guest"]._get_guest_from_token(token)
|
||||
if guest and not guest.timezone:
|
||||
timezone = req.env["mail.guest"]._get_timezone_from_request(req)
|
||||
if timezone:
|
||||
guest._update_timezone(timezone)
|
||||
if guest:
|
||||
req.update_context(guest=guest)
|
||||
if hasattr(self, "env"):
|
||||
self.env.context = {**self.env.context, "guest": guest}
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
@@ -83,6 +77,17 @@ class MailGuest(models.Model):
|
||||
for guest in self:
|
||||
guest.im_status = res.get(guest.id, 'offline')
|
||||
|
||||
def _get_guest_from_token(self, token=""):
|
||||
"""Returns the guest record for the given token, if applicable."""
|
||||
guest = self.env["mail.guest"]
|
||||
parts = token.split(self._cookie_separator)
|
||||
if len(parts) == 2:
|
||||
guest_id, guest_access_token = parts
|
||||
guest = self.browse(int(guest_id)).sudo().exists()
|
||||
if not guest or not guest.access_token or not consteq(guest.access_token, guest_access_token):
|
||||
guest = self.env["mail.guest"]
|
||||
return guest.sudo(False)
|
||||
|
||||
def _get_guest_from_context(self):
|
||||
"""Returns the current guest record from the context, if applicable."""
|
||||
guest = self.env.context.get('guest')
|
||||
|
||||
Reference in New Issue
Block a user