Files
odoo_source/addons/website_mail/controllers/main.py
T
Thibault Delavallée 01ab75f597 [IMP] mail: notification emails with button
Notification emails have been redesigned. They notably include buttons
allowing to perform some action directly from the email.

The notification creation and sending has been partially rewritten
and improved. The purpose is to lessen the number of rendering to perform
when sending emails to recipients. Recipients are first categorized into
groups. Basic groups are partners and users. The notification template
is then rendered twice, one for followers and one for not-followers. In most
cases there will be few rendering to perform. Through inheritance it
is possible to further categorize users. For example HR users / officers
that have approve / refuse buttons in their email.

A custom data structure is used to store data about buttons and actions.
URLs, follow / unfollow are added in the structure and used in the
template to render the email for a given group.

New routes are added in mail. Those allow to perform some action, like
going to a form in create mode, following / unfollowing, executing a method,
sending a signal for a workflow. Those routes are for users only and rely
on classic access rights.

A generic route for viewing records is added. It replaces the old redirect
action. According to some specific action given by the already-existing
get_access_action, the record will be visible for everybody (forum, blog)
or restricted (going on the Inbox / login / form view, according to access
rights).

The next commit will add the various inherits necessary to add the actions
in the main addons.
2015-08-28 17:30:42 +02:00

169 lines
8.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from hashlib import sha1
from time import time
from werkzeug.exceptions import NotFound
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:
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()
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
@http.route(['/website_mail/post/json'], type='json', auth='public', website=True)
def chatter_json(self, res_model='', res_id=None, message='', **kw):
res_id = int(res_id)
try:
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
except Exception:
return False
@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):
res_id = int(res_id)
message = _message_post_helper(res_model, res_id, message, **kw)
return request.redirect(request.httprequest.referrer + "#message-%s" % (message.id,))