Files
odoo_source/addons/mail/wizard/mail_wizard_invite.py
T
Didier (did) 1afcc9c368 [IMP] bus, mail, *: improve longpolling bus notification format
* = auth_signup, calendar, im_livechat, snailmail_account, survey, test_mail,
    web_editor, website_crm_iap_reveal, website_livechat

The aim of this PR is to improve/fix various flaws and limitation of the current
API, to make it easier to use and more efficient.

Notification are now defined with 3 distinct parts:

- the channel determines which client(s) should receive it
- the type determines how it should be handled
- the payload determines any extra information helpful for handling it

Channel
=======

Business code
-------------

- Record channel is introduced for ease of subscribing to and sending
  notifications to specific partners, channels, documents, ...
- String channel is still supported (but it is converted internally to the tuple
  channel).
- Tuple channel is still supported without any change (but should be avoided
  whenever possible due to its complex syntax).

The channel is no longer sent to the client. When the channel was used for
business purpose, the information it contained has been moved into either the
new type, or the payload itself.

Technical note
--------------

All channels are now internally converted to the tuple (db, ...) channel, which
is necessary for the platform code (saas/sh).

Internally, the bus.bus table is not changed, type and payload are grouped
together into what was (and still is) called message.

Type
====

Type is introduced to uniformize the way notifications are sent and handled.
All existing notifications already had some kind of manually-built type in them.
This is now officially supported at the bus API.

In client code this will allow (to be done in future commits) to register one
handler per specific type, instead of having to iterate and to filter all
received notifications on every handler.

Payload
=======

Payload (ex message) did not change, it can still be anything depending on
business needs.

Few adaptations:
- When the type was included on the payload, the type has been moved to the new
  type parameter.
- When the channel was used in business code, its data has been copied into the
  payload.

task-1891151

closes odoo/odoo#79201

X-original-commit: 543af27c7d6836ffac9e80ff8490b6ddbd849221
Related: odoo/enterprise#21998
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
2021-10-29 16:05:23 +00:00

90 lines
4.6 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from lxml import etree
from lxml.html import builder as html
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class Invite(models.TransientModel):
""" Wizard to invite partners (or channels) and make them followers. """
_name = 'mail.wizard.invite'
_description = 'Invite wizard'
@api.model
def default_get(self, fields):
result = super(Invite, self).default_get(fields)
if 'message' not in fields:
return result
user_name = self.env.user.display_name
model = result.get('res_model')
res_id = result.get('res_id')
if model and res_id:
document = self.env['ir.model']._get(model).display_name
title = self.env[model].browse(res_id).display_name
msg_fmt = _('%(user_name)s invited you to follow %(document)s document: %(title)s')
else:
msg_fmt = _('%(user_name)s invited you to follow a new document.')
text = msg_fmt % locals()
message = html.DIV(
html.P(_('Hello,')),
html.P(text)
)
result['message'] = etree.tostring(message)
return result
res_model = fields.Char('Related Document Model', required=True, index=True, help='Model of the followed resource')
res_id = fields.Integer('Related Document ID', index=True, help='Id of the followed resource')
partner_ids = fields.Many2many('res.partner', string='Recipients', help="List of partners that will be added as follower of the current document.",
domain=[('type', '!=', 'private')])
message = fields.Html('Message')
send_mail = fields.Boolean('Send Email', default=True, help="If checked, the partners will receive an email warning they have been added in the document's followers.")
def add_followers(self):
if not self.env.user.email:
raise UserError(_("Unable to post message, please configure the sender's email address."))
email_from = self.env.user.email_formatted
for wizard in self:
Model = self.env[wizard.res_model]
document = Model.browse(wizard.res_id)
# filter partner_ids to get the new followers, to avoid sending email to already following partners
new_partners = wizard.partner_ids - document.sudo().message_partner_ids
document.message_subscribe(partner_ids=new_partners.ids)
model_name = self.env['ir.model']._get(wizard.res_model).display_name
# send an email if option checked and if a message exists (do not send void emails)
if wizard.send_mail and wizard.message and not wizard.message == '<br>': # when deleting the message, cleditor keeps a <br>
message = self.env['mail.message'].create({
'subject': _('Invitation to follow %(document_model)s: %(document_name)s', document_model=model_name, document_name=document.display_name),
'body': wizard.message,
'record_name': document.display_name,
'email_from': email_from,
'reply_to': email_from,
'model': wizard.res_model,
'res_id': wizard.res_id,
'reply_to_force_new': True,
'add_sign': True,
})
partners_data = []
recipient_data = self.env['mail.followers']._get_recipient_data(document, 'comment', False, pids=new_partners.ids)
for pid, active, pshare, notif, groups in recipient_data:
pdata = {'id': pid, 'share': pshare, 'active': active, 'notif': 'email', 'groups': groups or []}
if not pshare and notif: # has an user and is not shared, is therefore user
partners_data.append(dict(pdata, type='user'))
elif pshare and notif: # has an user and is shared, is therefore portal
partners_data.append(dict(pdata, type='portal'))
else: # has no user, is therefore customer
partners_data.append(dict(pdata, type='customer'))
document._notify_record_by_email(message, partners_data, send_after_commit=False)
# in case of failure, the web client must know the message was
# deleted to discard the related failure notification
self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.message/delete', {'message_ids': message.ids})
message.unlink()
return {'type': 'ir.actions.act_window_close'}