Add 'force_display' param for the frontend chatter to allow public user to see the textarea. When submitting his comment, he will be redirect to login page (like it was before generic chatter) in both mode (json and post mode). This required changing the error handeling of json mode : when a login is required, the user switch to post mode to allow http redirect, keeping its submitted params (rating, comment, ...).
199 lines
9.7 KiB
Python
199 lines
9.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import urllib
|
|
|
|
from hashlib import sha1
|
|
from time import time
|
|
from werkzeug.exceptions import NotFound
|
|
from werkzeug import url_encode
|
|
|
|
from openerp import SUPERUSER_ID, _
|
|
from openerp.addons.web import http
|
|
from openerp.addons.web.http import request
|
|
|
|
|
|
def object_shasign(record=False, res_model='', res_id=None, **kw):
|
|
""" Generate a sha signature using the current time, database secret and the
|
|
record object or the res_model and res_id parameters
|
|
Return the sha signature and the time of generation in a tuple"""
|
|
secret = request.env['ir.config_parameter'].sudo().get_param('database.secret')
|
|
shasign = False
|
|
timestamp = int(time())
|
|
if record:
|
|
shasign = sha1('%s%s%s%s' % (record._model, record.id, secret, timestamp)).hexdigest()
|
|
elif res_model and res_id:
|
|
shasign = sha1('%s%s%s%s' % (res_model, res_id, secret, timestamp)).hexdigest()
|
|
return (shasign, timestamp)
|
|
|
|
|
|
def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', sha_in='', sha_time=None, nosubscribe=True, **kw):
|
|
""" Generic chatter function, allowing to write on *any* object that inherits mail.thread.
|
|
If a token or a shasign 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 string token_field: name of the field that contains the token on the object (defaults to 'token')
|
|
:param string sha_in: sha1 hash of the string composed of res_model, res_id and the dabase secret in ir.config_parameter
|
|
if you wish to allow public users to write on the object with some security but you don't want
|
|
to add a token field on the object, the sha-sign prevents public users from writing to any other
|
|
object that the one specified by res_model and res_id
|
|
to generate the shasign, you can import the function object_shasign from this file in your controller
|
|
:param str sha_time: timestamp of sha signature generation (signatures are valid for 24h)
|
|
: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()
|
|
"""
|
|
res = request.env[res_model].browse(res_id)
|
|
author_id = request.env.user.partner_id.id
|
|
if token and res and token == getattr(res.sudo(), token_field, None):
|
|
res = res.sudo()
|
|
if request.env.user == request.env['ir.model.data'].xmlid_to_object('base.public_user'):
|
|
author_id = (res.partner_id and res.partner_id.id) if hasattr(res, 'partner_id') else author_id
|
|
else:
|
|
author_id = request.env.user.partner_id and request.env.user.partner_id.id
|
|
if not author_id:
|
|
raise NotFound()
|
|
elif sha_in:
|
|
timestamp = int(sha_time)
|
|
secret = request.env['ir.config_parameter'].sudo().get_param('database.secret')
|
|
shasign = sha1('%s%s%s%s' % (res_model, res_id, secret, timestamp))
|
|
if sha_in == shasign.hexdigest() and int(time()) < timestamp + 3600 * 24:
|
|
res = res.sudo()
|
|
else:
|
|
raise NotFound()
|
|
kw.pop('force_display', False)
|
|
return res.with_context({'mail_create_nosubscribe': nosubscribe}).message_post(body=message,
|
|
message_type=kw.pop('message_type', False) or "comment",
|
|
subtype=kw.pop('subtype', False) or "mt_comment",
|
|
author_id=author_id,
|
|
**kw)
|
|
|
|
class WebsiteMail(http.Controller):
|
|
|
|
@http.route(['/website_mail/follow'], type='json', auth="public", website=True)
|
|
def website_message_subscribe(self, id=0, object=None, message_is_follower="on", email=False, **post):
|
|
# TDE FIXME: check this method with new followers
|
|
cr, uid, context = request.cr, request.uid, request.context
|
|
|
|
partner_obj = request.registry['res.partner']
|
|
user_obj = request.registry['res.users']
|
|
|
|
_id = int(id)
|
|
_message_is_follower = message_is_follower == 'on'
|
|
_object = request.registry[object]
|
|
|
|
# search partner_id
|
|
public_id = request.website.user_id.id
|
|
if uid != public_id:
|
|
partner_ids = [user_obj.browse(cr, uid, uid, context).partner_id.id]
|
|
else:
|
|
# mail_thread method
|
|
partner_ids = _object._find_partner_from_emails(
|
|
cr, SUPERUSER_ID, [_id], [email], context=context, check_followers=True)
|
|
if not partner_ids or not partner_ids[0]:
|
|
name = email.split('@')[0]
|
|
partner_ids = [partner_obj.create(cr, SUPERUSER_ID, {'name': name, 'email': email}, context=context)]
|
|
|
|
# add or remove follower
|
|
if _message_is_follower:
|
|
_object.check_access_rule(cr, uid, [_id], 'read', context)
|
|
_object.message_unsubscribe(cr, SUPERUSER_ID, [_id], partner_ids, context=context)
|
|
return False
|
|
else:
|
|
_object.check_access_rule(cr, uid, [_id], 'read', context)
|
|
# add partner to session
|
|
request.session['partner_id'] = partner_ids[0]
|
|
_object.message_subscribe(cr, SUPERUSER_ID, [_id], partner_ids, context=context)
|
|
return True
|
|
|
|
@http.route(['/website_mail/is_follower'], type='json', auth="public", website=True)
|
|
def call(self, model, id, **post):
|
|
id = int(id)
|
|
cr, uid, context = request.cr, request.uid, request.context
|
|
|
|
partner_obj = request.registry.get('res.partner')
|
|
users_obj = request.registry.get('res.users')
|
|
obj = request.registry.get(model)
|
|
|
|
partner_id = None
|
|
public_id = request.website.user_id.id
|
|
if uid != public_id:
|
|
partner_id = users_obj.browse(cr, SUPERUSER_ID, uid, context).partner_id
|
|
elif request.session.get('partner_id'):
|
|
partner_id = partner_obj.browse(cr, SUPERUSER_ID, request.session.get('partner_id'), context)
|
|
email = partner_id and partner_id.email or ""
|
|
|
|
values = {
|
|
'is_user': uid != public_id,
|
|
'email': email,
|
|
'is_follower': False,
|
|
'alias_name': False,
|
|
}
|
|
|
|
if not obj:
|
|
return values
|
|
obj_ids = obj.exists(cr, SUPERUSER_ID, [id], context=context)
|
|
if obj_ids:
|
|
if partner_id:
|
|
values['is_follower'] = len(
|
|
request.registry['mail.followers'].search(
|
|
cr, SUPERUSER_ID, [
|
|
('res_model', '=', model),
|
|
('res_id', '=', obj_ids[0]),
|
|
('partner_id', '=', partner_id.id)
|
|
], context=context)) == 1
|
|
return values
|
|
|
|
def _generate_login_url(self):
|
|
url_params = request.params
|
|
url_params.pop('force_display')
|
|
url_params.update(redirect=request.httprequest.referrer)
|
|
redirect_login_url = '/website_mail/post/post' + '?' + url_encode(url_params)
|
|
url = '/web/login?redirect=%s' % urllib.quote(redirect_login_url)
|
|
return url
|
|
|
|
@http.route(['/website_mail/post/json'], type='json', auth='public', website=True)
|
|
def chatter_json(self, res_model='', res_id=None, message='', **kw):
|
|
# if the chatter is displayed but the user is not logged, redirect him to login page
|
|
if kw.get('force_display') and not request.session.uid:
|
|
return {'redirect': self._generate_login_url()}
|
|
# otherwise, try to post the comment
|
|
res_id = int(res_id)
|
|
try:
|
|
if message:
|
|
msg = _message_post_helper(res_model, res_id, message, **kw)
|
|
data = {
|
|
'id': msg.id,
|
|
'body': msg.body,
|
|
'date': msg.date,
|
|
'author': msg.author_id.name,
|
|
'image_url': request.website.image_url(msg.author_id, 'image_small')
|
|
}
|
|
return data
|
|
else:
|
|
return {'error': _('Empty comments are not allowed. Please fill the textearea.')}
|
|
except Exception:
|
|
return {'error': _('Oops! Something went wrong. Try to reload the page and to log in.')}
|
|
|
|
@http.route(['/website_mail/post/post'], type='http', method=['POST'], auth='public', website=True)
|
|
def chatter_post(self, res_model='', res_id=None, message='', redirect=None, **kw):
|
|
url = request.httprequest.referrer
|
|
if kw.get('force_display') and not request.session.uid:
|
|
# set the redirection param to be redirect here when logged in
|
|
url = self._generate_login_url()
|
|
else:
|
|
res_id = int(res_id)
|
|
url = redirect or url
|
|
if message:
|
|
message = _message_post_helper(res_model, res_id, message, **kw)
|
|
url = url + "#message-%s" % (message.id,)
|
|
return request.redirect(url)
|