RATIONALE Simplify field management for mail / phone / sms flows. Make it working out of the box, easier to use and tweak. SPECIFICATIONS In addition to finding the customer, sometimes we just want any partner on a record, notably for VOIP. For that purpose we improve heuristic for finding partner (fields or records). It introspects the model to find any relational field towards res.partner. Note that as it is generic it does not ensure the partner is a customer, just some partner. Task-3422449 (Mail, Phone: Move and improve field helpers) Prepares Task-36879 (Mail: Support MultiCompany Aliases) Part-of: odoo/odoo#130468
81 lines
3.2 KiB
Python
81 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import hashlib
|
|
import hmac
|
|
|
|
from odoo import api, fields, models, _
|
|
|
|
|
|
class MailThread(models.AbstractModel):
|
|
_inherit = 'mail.thread'
|
|
|
|
_mail_post_token_field = 'access_token' # token field for external posts, to be overridden
|
|
|
|
website_message_ids = fields.One2many('mail.message', 'res_id', string='Website Messages',
|
|
domain=lambda self: [('model', '=', self._name), '|', ('message_type', '=', 'comment'), ('message_type', '=', 'email')], auto_join=True,
|
|
help="Website communication history")
|
|
|
|
def _notify_get_recipients_groups(self, message, model_description, msg_vals=None):
|
|
groups = super()._notify_get_recipients_groups(
|
|
message, model_description, msg_vals=msg_vals
|
|
)
|
|
if not self:
|
|
return groups
|
|
|
|
portal_enabled = isinstance(self, type(self.env['portal.mixin']))
|
|
if not portal_enabled:
|
|
return groups
|
|
|
|
customer = self._mail_get_partners(introspect_fields=False)[self.id]
|
|
if customer:
|
|
access_token = self._portal_ensure_token()
|
|
local_msg_vals = dict(msg_vals or {})
|
|
local_msg_vals['access_token'] = access_token
|
|
local_msg_vals['pid'] = customer.id
|
|
local_msg_vals['hash'] = self._sign_token(customer.id)
|
|
local_msg_vals.update(customer.signup_get_auth_param()[customer.id])
|
|
access_link = self._notify_get_action_link('view', **local_msg_vals)
|
|
|
|
new_group = [
|
|
('portal_customer', lambda pdata: pdata['id'] == customer.id, {
|
|
'active': True,
|
|
'button_access': {
|
|
'url': access_link,
|
|
},
|
|
'has_button_access': True,
|
|
})
|
|
]
|
|
else:
|
|
new_group = []
|
|
|
|
# enable portal users that should have access through portal (if not access rights
|
|
# will do their duty)
|
|
portal_group = next(group for group in groups if group[0] == 'portal')
|
|
portal_group[2]['active'] = True
|
|
portal_group[2]['has_button_access'] = True
|
|
|
|
return new_group + groups
|
|
|
|
def _sign_token(self, pid):
|
|
"""Generate a secure hash for this record with the email of the recipient with whom the record have been shared.
|
|
|
|
This is used to determine who is opening the link
|
|
to be able for the recipient to post messages on the document's portal view.
|
|
|
|
:param str email:
|
|
Email of the recipient that opened the link.
|
|
"""
|
|
self.ensure_one()
|
|
# check token field exists
|
|
if self._mail_post_token_field not in self._fields:
|
|
raise NotImplementedError(_(
|
|
"Model %(model_name)s does not support token signature, as it does not have %(field_name)s field.",
|
|
model_name=self._name,
|
|
field_name=self._mail_post_token_field
|
|
))
|
|
# sign token
|
|
secret = self.env["ir.config_parameter"].sudo().get_param("database.secret")
|
|
token = (self.env.cr.dbname, self[self._mail_post_token_field], pid)
|
|
return hmac.new(secret.encode('utf-8'), repr(token).encode('utf-8'), hashlib.sha256).hexdigest()
|