diff --git a/mass_mailing_custom_unsubscribe/README.rst b/mass_mailing_custom_unsubscribe/README.rst new file mode 100644 index 00000000..3f626252 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/README.rst @@ -0,0 +1 @@ +**This file is going to be generated by oca-gen-addon-readme.** diff --git a/mass_mailing_custom_unsubscribe/__init__.py b/mass_mailing_custom_unsubscribe/__init__.py new file mode 100644 index 00000000..d93811e7 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import controllers, models +from .hooks import post_init_hook diff --git a/mass_mailing_custom_unsubscribe/__manifest__.py b/mass_mailing_custom_unsubscribe/__manifest__.py new file mode 100644 index 00000000..a0691927 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/__manifest__.py @@ -0,0 +1,35 @@ +# Copyright 2016 Jairo Llopis +# Copyright 2018 David Vidal +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + 'name': 'Customizable unsubscription process on mass mailing emails', + 'summary': 'Know and track (un)subscription reasons, GDPR compliant', + 'category': 'Marketing', + 'version': '11.0.1.0.0', + 'depends': [ + 'website_mass_mailing', + ], + 'data': [ + 'security/ir.model.access.csv', + 'data/mail_unsubscription_reason.xml', + 'templates/general_reason_form.xml', + 'templates/mass_mailing_contact_reason.xml', + 'views/assets.xml', + 'views/mail_unsubscription_reason_view.xml', + 'views/mail_mass_mailing_list_view.xml', + 'views/mail_mass_mailing_contact_view.xml', + 'views/mail_unsubscription_view.xml', + ], + 'demo': [ + 'demo/assets.xml', + ], + 'images': [ + 'images/form.png', + ], + 'author': 'Tecnativa,' + 'Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/social', + 'license': 'AGPL-3', + 'installable': True, + 'post_init_hook': 'post_init_hook', +} diff --git a/mass_mailing_custom_unsubscribe/controllers/__init__.py b/mass_mailing_custom_unsubscribe/controllers/__init__.py new file mode 100644 index 00000000..4ca7a1b8 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/controllers/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2016 Jairo Llopis +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import main diff --git a/mass_mailing_custom_unsubscribe/controllers/main.py b/mass_mailing_custom_unsubscribe/controllers/main.py new file mode 100644 index 00000000..d2dcac65 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/controllers/main.py @@ -0,0 +1,108 @@ +# Copyright 2015 Antiun Ingeniería S.L. (http://www.antiun.com) +# Copyright 2016 Jairo Llopis +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from odoo.http import request, route +from odoo.addons.website_mass_mailing.controllers.main \ + import MassMailController + +_logger = logging.getLogger(__name__) + + +class CustomUnsubscribe(MassMailController): + def reason_form(self, mailing, email, res_id, token): + """Get the unsubscription reason form. + + :param mail.mass_mailing mailing: + Mailing where the unsubscription is being processed. + + :param str email: + Email to be unsubscribed. + + :param int res_id: + ID of the unsubscriber. + + :param str token: + Security token for unsubscriptions. + """ + reasons = request.env["mail.unsubscription.reason"].search([]) + return request.render( + "mass_mailing_custom_unsubscribe.reason_form", + { + "email": email, + "mailing": mailing, + "reasons": reasons, + "res_id": res_id, + "token": token, + }) + + @route() + def mailing(self, mailing_id, email=None, res_id=None, token="", **post): + """Ask/save unsubscription reason.""" + _logger.debug( + "Called `mailing()` with: %r", + (mailing_id, email, res_id, token, post)) + mailing = request.env["mail.mass_mailing"].sudo().browse(mailing_id) + # Mass mailing list contacts are a special case because they have a + # subscription management form + if mailing.mailing_model_real == 'mail.mass_mailing.contact': + result = super(CustomUnsubscribe, self).mailing( + mailing_id, email, res_id, token=token, **post) + result.qcontext.update({ + "contacts": result.qcontext["contacts"].filtered( + lambda contact: + not any(contact.list_ids.mapped( + 'not_cross_unsubscriptable')) or + contact.list_ids <= mailing.contact_list_ids + ), + "reasons": + request.env["mail.unsubscription.reason"].search([]), + }) + return result + # Any other record type gets a simplified form + try: + # Check if we already have a reason for unsubscription + reason_id = int(post["reason_id"]) + except (KeyError, ValueError): + # No reasons? Ask for them + return self.reason_form(mailing, email, res_id, token) + else: + # Unsubscribe, saving reason and details by context + request.context = dict( + request.context, + default_reason_id=reason_id, + default_details=post.get("details") or False, + ) + # You could get a DetailsRequiredError here, but only if HTML5 + # validation fails, which should not happen in modern browsers + return super(CustomUnsubscribe, self).mailing( + mailing_id, email, res_id, token=token, **post) + + @route() + def unsubscribe(self, mailing_id, opt_in_ids, opt_out_ids, email, res_id, + token, reason_id=None, details=None): + """Store unsubscription reasons when unsubscribing from RPC.""" + # Update request context and reset environment + environ = request.httprequest.headers.environ + extra_context = { + "default_metadata": "\n".join( + "%s: %s" % (val, environ.get(val)) for val in ( + "REMOTE_ADDR", + "HTTP_USER_AGENT", + "HTTP_ACCEPT_LANGUAGE", + ) + ), + } + if reason_id: + extra_context["default_reason_id"] = int(reason_id) + if details: + extra_context["default_details"] = details + request.context = dict(request.context, **extra_context) + _logger.debug( + "Called `unsubscribe()` with: %r", + (mailing_id, opt_in_ids, opt_out_ids, email, res_id, token, + reason_id, details)) + return super(CustomUnsubscribe, self).unsubscribe( + mailing_id, opt_in_ids, opt_out_ids, email) diff --git a/mass_mailing_custom_unsubscribe/data/mail_unsubscription_reason.xml b/mass_mailing_custom_unsubscribe/data/mail_unsubscription_reason.xml new file mode 100644 index 00000000..24a6eda3 --- /dev/null +++ b/mass_mailing_custom_unsubscribe/data/mail_unsubscription_reason.xml @@ -0,0 +1,39 @@ + + + + + + + I'm not interested + 10 + + + + + I did not request this + 20 + + + + + I get too many emails + 30 + + + + + Other reason + 100 + + + + diff --git a/mass_mailing_custom_unsubscribe/demo/assets.xml b/mass_mailing_custom_unsubscribe/demo/assets.xml new file mode 100644 index 00000000..c55f302b --- /dev/null +++ b/mass_mailing_custom_unsubscribe/demo/assets.xml @@ -0,0 +1,17 @@ + + + + + +