social/mass_mailing_custom_unsubscribe/models/mail_mass_mailing.py
Jairo Llopis 708780cab9 [9.0][MIG][mass_mailing_custom_unsubscribe] Migrate.
- Imported last updates from v8.
- Adapted to v9.
- Added a saner default to `mass_mailing.salt` configuration parameter by
  reusing `database.secret` if available, hoping that some day
  https://github.com/odoo/odoo/pull/12040 gets merged.
- Updated README.
- Increase security, drop backwards compatibility.
  Security got improved upstream, which would again break compatibility among current addon and future master upstream.
  I choose to break it now and keep it secured future-wise, so I drop the backwards compatibility features.
- Includes tour tests.
- Removes outdated tests.
- Extends the mailing list management form when unsubscriber is a contact.
- Adds a reason form even if he is not.
- Avoids all methods that were not model-agnostic.

[FIX][mass_mailing_custom_unsubscribe] Reasons noupdate

After this fix, when you update the addon, you will not lose your customized reasons.

[FIX] Compatibilize with mass_mailing_partner

Current test code was based on the assumption that the `@api.model` decorator on `create()` ensured an empty recordset when running the method, but that's not true. This was causing an incompatibility betwee these tests and the `mass_mailing_partner` addon, which works assuming 0-1 recordsets.

Now records are created from an empty recordset, and thus tests work everywhere.

Update instructions

If the user does not add the unsubscribe snippet, nothing will happen, so it's added to README to avoid confusion when testing/using the addon.

[FIX] Use the right operator to preserve recordsets order

Using `|=` sorts records at will each time (treating them as Python's `set`).
Using `+=` always appends a record to the end of the set.
Since we are using the record position in the set, this caused the test to work sometimes and fail other times. Now it works always.
2022-12-16 13:13:16 +01:00

55 lines
2.0 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import hmac
import hashlib
from openerp import api, models
from openerp.exceptions import AccessDenied
from openerp.tools import consteq
class MailMassMailing(models.Model):
_inherit = "mail.mass_mailing"
@api.multi
def _unsubscribe_token(self, res_id, compare=None):
"""Generate a secure hash for this mailing list and parameters.
This is appended to the unsubscription URL and then checked at
unsubscription time to ensure no malicious unsubscriptions are
performed.
:param int res_id:
ID of the resource that will be unsubscribed.
:param str compare:
Received token to be compared with the good one.
:raise AccessDenied:
Will happen if you provide :param:`compare` and it does not match
the good token.
"""
secret = self.env["ir.config_parameter"].sudo().get_param(
"database.secret")
key = (self.env.cr.dbname, self.id, int(res_id))
token = hmac.new(str(secret), repr(key), hashlib.sha512).hexdigest()
if compare is not None and not consteq(token, str(compare)):
raise AccessDenied()
return token
@api.model
def update_opt_out(self, mailing_id, email, res_ids, value):
"""Save unsubscription reason when opting out from mailing."""
mailing = self.browse(mailing_id)
if value and self.env.context.get("default_reason_id"):
for res_id in res_ids:
# reason_id and details are expected from the context
self.env["mail.unsubscription"].create({
"email": email,
"mass_mailing_id": mailing.id,
"unsubscriber_id": "%s,%d" % (
mailing.mailing_model, int(res_id)),
})
return super(MailMassMailing, self).update_opt_out(
mailing_id, email, res_ids, value)