In the frontend only plaintext is saved without any javascript fiddling so in the controller it should be adapted to be saved. With this change, the behavior is more similar to backend chatter which sends html (processed by javascript) to the server. opw-1817918 closes #23706
109 lines
5.6 KiB
Python
109 lines
5.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from werkzeug.exceptions import NotFound, Forbidden
|
|
|
|
from odoo import http
|
|
from odoo.http import request
|
|
from odoo.osv import expression
|
|
from odoo.tools import consteq, plaintext2html
|
|
|
|
|
|
def _has_token_access(res_model, res_id, token=''):
|
|
record = request.env[res_model].browse(res_id).sudo()
|
|
token_field = request.env[res_model]._mail_post_token_field
|
|
return (token and record and consteq(record[token_field], token))
|
|
|
|
def _message_post_helper(res_model='', res_id=None, message='', token='', nosubscribe=True, **kw):
|
|
""" Generic chatter function, allowing to write on *any* object that inherits mail.thread.
|
|
If a token is specified, all logged in users will be able to write a message regardless
|
|
of access rights; if the user is the public user, the message will be posted under the name
|
|
of the partner_id of the object (or the public user if there is no partner_id on the object).
|
|
|
|
:param string res_model: model name of the object
|
|
:param int res_id: id of the object
|
|
:param string message: content of the message
|
|
|
|
optional keywords arguments:
|
|
:param string token: access token if the object's model uses some kind of public access
|
|
using tokens (usually a uuid4) to bypass access rules
|
|
:param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True)
|
|
|
|
The rest of the kwargs are passed on to message_post()
|
|
"""
|
|
record = request.env[res_model].browse(res_id)
|
|
author_id = request.env.user.partner_id.id if request.env.user.partner_id else False
|
|
if token:
|
|
access_as_sudo = _has_token_access(res_model, res_id, token=token)
|
|
if access_as_sudo:
|
|
record = record.sudo()
|
|
if request.env.user == request.env.ref('base.public_user'):
|
|
author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id
|
|
else:
|
|
if not author_id:
|
|
raise NotFound()
|
|
else:
|
|
raise Forbidden()
|
|
kw.pop('csrf_token', None)
|
|
kw.pop('attachment_ids', None)
|
|
return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message,
|
|
message_type=kw.pop('message_type', "comment"),
|
|
subtype=kw.pop('subtype', "mt_comment"),
|
|
author_id=author_id,
|
|
**kw)
|
|
|
|
|
|
class PortalChatter(http.Controller):
|
|
|
|
@http.route(['/mail/chatter_post'], type='http', methods=['POST'], auth='public', website=True)
|
|
def portal_chatter_post(self, res_model, res_id, message, **kw):
|
|
url = request.httprequest.referrer
|
|
if message:
|
|
# message is received in plaintext and saved in html
|
|
message = plaintext2html(message)
|
|
_message_post_helper(res_model, int(res_id), message, **kw)
|
|
url = url + "#discussion"
|
|
return request.redirect(url)
|
|
|
|
@http.route('/mail/chatter_init', type='json', auth='public', website=True)
|
|
def portal_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
|
|
is_user_public = request.env.user.has_group('base.group_public')
|
|
message_data = self.portal_message_fetch(res_model, res_id, domain=domain, limit=limit, **kwargs)
|
|
display_composer = False
|
|
if kwargs.get('allow_composer'):
|
|
display_composer = kwargs.get('token') or not is_user_public
|
|
return {
|
|
'messages': message_data['messages'],
|
|
'options': {
|
|
'message_count': message_data['message_count'],
|
|
'is_user_public': is_user_public,
|
|
'is_user_publisher': request.env.user.has_group('website.group_website_publisher'),
|
|
'display_composer': display_composer,
|
|
'partner_id': request.env.user.partner_id.id
|
|
}
|
|
}
|
|
|
|
@http.route('/mail/chatter_fetch', type='json', auth='public', website=True)
|
|
def portal_message_fetch(self, res_model, res_id, domain=False, limit=10, offset=0, **kw):
|
|
if not domain:
|
|
domain = []
|
|
# Only search into website_message_ids, so apply the same domain to perform only one search
|
|
# extract domain from the 'website_message_ids' field
|
|
field_domain = request.env[res_model]._fields['website_message_ids'].domain
|
|
domain += field_domain(request.env[res_model]) if callable(field_domain) else field_domain
|
|
domain += [('res_id', '=', res_id)]
|
|
# Check access
|
|
Message = request.env['mail.message']
|
|
if kw.get('token'):
|
|
access_as_sudo = _has_token_access(res_model, res_id, token=kw.get('token'))
|
|
if not access_as_sudo: # if token is not correct, raise Forbidden
|
|
raise Forbidden()
|
|
# Non-employee see only messages with not internal subtype (aka, no internal logs)
|
|
if not request.env['res.users'].has_group('base.group_user'):
|
|
domain = expression.AND([['&', '&', ('subtype_id', '!=', False), ('subtype_id.internal', '=', False)], domain])
|
|
Message = request.env['mail.message'].sudo()
|
|
return {
|
|
'messages': Message.search(domain, limit=limit, offset=offset).portal_message_format(),
|
|
'message_count': Message.search_count(domain)
|
|
}
|