mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 03:52:01 +02:00
327 lines
14 KiB
Python
327 lines
14 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import json
|
|
|
|
from markupsafe import Markup
|
|
from requests.exceptions import HTTPError
|
|
|
|
from odoo import fields
|
|
from odoo.addons.base.tests.common import HttpCase
|
|
from odoo.addons.mail.tests.common import mail_new_test_user, MailCommon
|
|
from odoo.http import Request
|
|
from odoo.tests import JsonRpcException
|
|
from odoo.tools import file_open, mute_logger
|
|
|
|
|
|
class MessagePostSubTestData:
|
|
def __init__(self, user, allowed, /, *, partners=None, partner_emails=None, add_mention_token=False, route_kw=None,
|
|
exp_author=None, exp_partners=None, exp_emails=None):
|
|
self.user = user if user._name == "res.users" else user.env.ref("base.public_user")
|
|
self.guest = user if user._name == "mail.guest" else user.env["mail.guest"]
|
|
self.allowed = allowed
|
|
self.route_kw = {
|
|
"context": {"mail_post_autofollow_author_skip": True, "mail_post_autofollow": False},
|
|
**(route_kw or {}),
|
|
}
|
|
self.post_data = {
|
|
"body": "<p>Hello</p>",
|
|
"message_type": "comment",
|
|
"subtype_xmlid": "mail.mt_comment",
|
|
}
|
|
if partner_emails is not None:
|
|
self.post_data["partner_emails"] = partner_emails
|
|
if partners is not None:
|
|
self.post_data["partner_ids"] = partners.ids
|
|
if add_mention_token:
|
|
self.post_data["partner_ids_mention_token"] = {
|
|
partner.id: partner._get_mention_token() for partner in partners
|
|
}
|
|
self.exp_author = exp_author
|
|
self.exp_partners = exp_partners
|
|
self.exp_emails = exp_emails
|
|
|
|
|
|
class MailControllerCommon(HttpCase, MailCommon):
|
|
# Note that '_get_with_access' is going to call '_get_thread_with_access'
|
|
# which relies on classic portal parameter given as kwargs on most routes
|
|
# (aka hash, token, pid)
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.maxDiff = None
|
|
cls._create_portal_user()
|
|
cls.guest = cls.env["mail.guest"].create({"name": "Guest"})
|
|
last_message = cls.env["mail.message"].search([], order="id desc", limit=1)
|
|
cls.fake_message = cls.env["mail.message"].browse(last_message.id + 1000000)
|
|
cls.user_employee_nopartner = mail_new_test_user(
|
|
cls.env,
|
|
company_id=cls.company_admin.id,
|
|
country_id=cls.env.ref('base.be').id,
|
|
groups='base.group_user,mail.group_mail_template_editor',
|
|
login='employee_nopartner',
|
|
name='Elodie EmployeeNoPartner',
|
|
notification_type='inbox',
|
|
)
|
|
# whatever default creation values, we need a "no partner manager" user
|
|
cls.user_employee_nopartner.write({'group_ids': [(3, cls.env.ref('base.group_partner_manager').id)]})
|
|
|
|
def _authenticate_pseudo_user(self, pseudo_user):
|
|
user = pseudo_user if pseudo_user._name == "res.users" else self.user_public
|
|
guest = pseudo_user if pseudo_user._name == "mail.guest" else self.env["mail.guest"]
|
|
if user and user != self.user_public:
|
|
self.authenticate(user.login, user.login)
|
|
else:
|
|
self.authenticate(None, None)
|
|
if guest:
|
|
self.opener.cookies[guest._cookie_name] = guest._format_auth_cookie()
|
|
return user, guest
|
|
|
|
def _get_sign_token_params(self, record):
|
|
if 'access_token' not in record:
|
|
raise ValueError("Test should run with portal installed")
|
|
access_token = record._portal_ensure_token()
|
|
partner = record.env["res.partner"].create({"name": "Sign Partner"})
|
|
_hash = record._sign_token(partner.id)
|
|
token = {"token": access_token}
|
|
bad_token = {"token": "incorrect token"}
|
|
sign = {"hash": _hash, "pid": partner.id}
|
|
bad_sign = {"hash": "incorrect hash", "pid": partner.id}
|
|
return token, bad_token, sign, bad_sign, partner
|
|
|
|
|
|
class MailControllerAttachmentCommon(MailControllerCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.all_users = (
|
|
cls.guest,
|
|
cls.user_admin,
|
|
cls.user_employee,
|
|
cls.user_portal,
|
|
cls.user_public,
|
|
)
|
|
|
|
def _execute_subtests_upload(self, document, subtests):
|
|
for data_user, allowed, *args in subtests:
|
|
route_kw = args[0] if args else {}
|
|
user, guest = self._authenticate_pseudo_user(data_user)
|
|
with self.subTest(document=document, user=user.name, guest=guest.name, route_kw=route_kw):
|
|
if allowed:
|
|
attachment_id = self._upload_attachment(document, route_kw)
|
|
attachment = self.env["ir.attachment"].sudo().search([("id", "=", attachment_id)])
|
|
self.assertTrue(attachment)
|
|
else:
|
|
with self.assertRaises(
|
|
HTTPError, msg="upload attachment should raise NotFound"
|
|
):
|
|
self._upload_attachment(document, route_kw)
|
|
|
|
def _execute_subtests_delete(self, users, token, allowed, thread=None):
|
|
for user_data in users:
|
|
user, guest = self._authenticate_pseudo_user(user_data)
|
|
with self.subTest(
|
|
user=user.name, guest=guest.name, token=token, allowed=allowed, thread=thread,
|
|
):
|
|
attachment = self.env["ir.attachment"].create({"name": "sample attachment"})
|
|
if thread:
|
|
attachment.write({"res_model": thread._name, "res_id": thread.id})
|
|
if allowed:
|
|
self._delete_attachment(attachment, token)
|
|
self.assertFalse(attachment.exists())
|
|
else:
|
|
with self.assertRaises(JsonRpcException, msg="Wrong access token"):
|
|
self._delete_attachment(attachment, token)
|
|
|
|
def _upload_attachment(self, document, route_kw):
|
|
with mute_logger("odoo.http"), file_open("addons/web/__init__.py") as file:
|
|
res = self.url_open(
|
|
url="/mail/attachment/upload",
|
|
data={
|
|
"csrf_token": Request.csrf_token(self),
|
|
"is_pending": True,
|
|
"thread_id": document.id,
|
|
"thread_model": document._name,
|
|
**route_kw,
|
|
},
|
|
files={"ufile": file},
|
|
)
|
|
res.raise_for_status()
|
|
data = json.loads(res.content.decode("utf-8"))["data"]
|
|
self.assertIn(
|
|
data["attachment_id"],
|
|
[a["id"] for a in data["store_data"]["ir.attachment"]]
|
|
)
|
|
return data["attachment_id"]
|
|
|
|
def _delete_attachment(self, attachment, token):
|
|
with mute_logger("odoo.http"):
|
|
self.make_jsonrpc_request(
|
|
route="/mail/attachment/delete",
|
|
params={
|
|
"attachment_id": attachment.id,
|
|
"access_token": attachment._get_ownership_token() if token else None,
|
|
},
|
|
)
|
|
|
|
|
|
class MailControllerBinaryCommon(MailControllerCommon):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.guest_2 = cls.env["mail.guest"].create({"name": "Guest 2"})
|
|
|
|
def _execute_subtests(self, record, subtests):
|
|
for data_user, allowed in subtests:
|
|
user, guest = self._authenticate_pseudo_user(data_user)
|
|
with self.subTest(user=user.name, guest=guest.name, record=record):
|
|
if allowed:
|
|
self.assertEqual(
|
|
self._get_avatar_url(record).headers["Content-Disposition"],
|
|
f'inline; filename="{record.name}.svg"',
|
|
)
|
|
else:
|
|
self.assertEqual(
|
|
self._get_avatar_url(record).headers["Content-Disposition"],
|
|
"inline; filename=placeholder.png",
|
|
)
|
|
|
|
def _get_avatar_url(self, record):
|
|
url = f"/web/image?field=avatar_128&id={record.id}&model={record._name}&unique={fields.Datetime.to_string(record.write_date)}"
|
|
return self.url_open(url)
|
|
|
|
def _post_message(self, document, auth_pseudo_user):
|
|
_user, _guest = self._authenticate_pseudo_user(auth_pseudo_user)
|
|
self.make_jsonrpc_request(
|
|
route="/mail/message/post",
|
|
params={
|
|
"thread_model": document._name,
|
|
"thread_id": document.id,
|
|
"post_data": {
|
|
"body": "Test",
|
|
"message_type": "comment",
|
|
"subtype_xmlid": "mail.mt_comment",
|
|
},
|
|
},
|
|
)
|
|
|
|
|
|
class MailControllerReactionCommon(MailControllerCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.reaction = "😊"
|
|
|
|
def _execute_subtests(self, message, subtests):
|
|
for data_user, allowed, *args in subtests:
|
|
route_kw = args[0] if args else {}
|
|
kwargs = args[1] if len(args) > 1 else {}
|
|
user, guest = self._authenticate_pseudo_user(data_user)
|
|
with self.subTest(user=user.name, guest=guest.name, route_kw=route_kw):
|
|
if allowed:
|
|
self._add_reaction(message, self.reaction, route_kw)
|
|
reactions = message.reaction_ids
|
|
self.assertEqual(len(reactions), 1)
|
|
expected_partner = kwargs.get("partner")
|
|
if guest and not expected_partner:
|
|
self.assertEqual(reactions.guest_id, guest)
|
|
else:
|
|
self.assertEqual(reactions.partner_id, expected_partner or user.partner_id)
|
|
self._remove_reaction(message, self.reaction, route_kw)
|
|
self.assertFalse(message.reaction_ids)
|
|
else:
|
|
with self.assertRaises(
|
|
JsonRpcException, msg="add reaction should raise NotFound"
|
|
):
|
|
self._add_reaction(message, self.reaction, route_kw)
|
|
with self.assertRaises(
|
|
JsonRpcException, msg="remove reaction should raise NotFound"
|
|
):
|
|
self._remove_reaction(message, self.reaction, route_kw)
|
|
|
|
def _add_reaction(self, message, content, route_kw):
|
|
self.make_jsonrpc_request(
|
|
route="/mail/message/reaction",
|
|
params={"action": "add", "content": content, "message_id": message.id, **route_kw},
|
|
)
|
|
|
|
def _remove_reaction(self, message, content, route_kw):
|
|
self.make_jsonrpc_request(
|
|
route="/mail/message/reaction",
|
|
params={"action": "remove", "content": content, "message_id": message.id, **route_kw},
|
|
)
|
|
|
|
|
|
class MailControllerThreadCommon(MailControllerCommon):
|
|
|
|
def _execute_message_post_subtests(self, record, tests: list[MessagePostSubTestData]):
|
|
for test in tests:
|
|
self._authenticate_pseudo_user(test.user if (test.user and test.user != self.user_public) else test.guest)
|
|
with self.subTest(record=record, user=test.user.name, guest=test.guest.name, route_kw=test.route_kw):
|
|
if test.allowed:
|
|
message = self._message_post(record, test.post_data, test.route_kw)
|
|
if test.guest and not test.exp_author:
|
|
self.assertEqual(message.author_guest_id, test.guest)
|
|
else:
|
|
self.assertEqual(message.author_id, test.exp_author or test.user.partner_id)
|
|
if test.exp_partners is not None:
|
|
self.assertEqual(message.partner_ids, test.exp_partners)
|
|
if test.exp_emails is not None:
|
|
self.assertEqual(message.partner_ids.mapped("email"), test.exp_emails)
|
|
else:
|
|
with self.assertRaises(JsonRpcException, msg="werkzeug.exceptions.NotFound"):
|
|
self._message_post(record, test.post_data, test.route_kw)
|
|
|
|
def _message_post(self, record, post_data, route_kw):
|
|
self.make_jsonrpc_request(
|
|
route="/mail/message/post",
|
|
params={
|
|
"thread_model": record._name,
|
|
"thread_id": record.id,
|
|
"post_data": post_data,
|
|
**route_kw,
|
|
},
|
|
)
|
|
return self.env["mail.message"].search(
|
|
[("res_id", "=", record.id), ("model", "=", record._name)], order="id desc", limit=1
|
|
)
|
|
|
|
|
|
class MailControllerUpdateCommon(MailControllerCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.message_body = "Message body"
|
|
cls.alter_message_body = "Altered message body"
|
|
|
|
def _execute_subtests(self, message, subtests):
|
|
for data_user, allowed, *args in subtests:
|
|
route_kw = args[0] if args else {}
|
|
user, guest = self._authenticate_pseudo_user(data_user)
|
|
with self.subTest(user=user.name, guest=guest.name, route_kw=route_kw):
|
|
if allowed:
|
|
self._update_content(message.id, self.alter_message_body, route_kw)
|
|
self.assertEqual(message.body,
|
|
Markup('<p>Altered message body<span class="o-mail-Message-edited"></span></p>'))
|
|
else:
|
|
with self.assertRaises(
|
|
JsonRpcException,
|
|
msg="update message content should raise NotFound",
|
|
):
|
|
self._update_content(message.id, self.alter_message_body, route_kw)
|
|
|
|
def _update_content(self, message_id, body, route_kw):
|
|
self.make_jsonrpc_request(
|
|
route="/mail/message/update_content",
|
|
params={
|
|
"message_id": message_id,
|
|
"update_data": {
|
|
"body": body,
|
|
"attachment_ids": [],
|
|
},
|
|
**route_kw,
|
|
},
|
|
)
|