123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- # -*- coding: utf-8 -*-
- # © 2015 Antiun Ingeniería S.L. (http://www.antiun.com)
- # © 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
- # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
- from openerp import exceptions
- from openerp.http import local_redirect, request, route
- from openerp.addons.mass_mailing.controllers.main import MassMailController
- from .. import exceptions as _ex
- class CustomUnsubscribe(MassMailController):
- def _mailing_list_contacts_by_email(self, email):
- """Gets the mailing list contacts by email.
- This should not be displayed to the final user if security validations
- have not been matched.
- """
- return request.env["mail.mass_mailing.contact"].sudo().search([
- ("email", "=", email),
- ("opt_out", "=", False),
- ("list_id.not_cross_unsubscriptable", "=", False),
- ])
- def unsubscription_reason(self, mailing_id, email, res_id, token,
- qcontext_extra=None):
- """Get the unsubscription reason form.
- :param mail.mass_mailing mailing_id:
- Mailing where the unsubscription is being processed.
- :param str email:
- Email to be unsubscribed.
- :param int res_id:
- ID of the unsubscriber.
- :param dict qcontext_extra:
- Additional dictionary to pass to the view.
- """
- values = self.unsubscription_qcontext(mailing_id, email, res_id, token)
- values.update(qcontext_extra or dict())
- return request.website.render(
- "mass_mailing_custom_unsubscribe.reason_form",
- values)
- def unsubscription_qcontext(self, mailing_id, email, res_id, token):
- """Get rendering context for unsubscription form.
- :param mail.mass_mailing mailing_id:
- Mailing where the unsubscription is being processed.
- :param str email:
- Email to be unsubscribed.
- :param int res_id:
- ID of the unsubscriber.
- """
- email_fname = origin_name = None
- domain = [("id", "=", res_id)]
- record_ids = request.env[mailing_id.mailing_model].sudo()
- if "email_from" in record_ids._fields:
- email_fname = "email_from"
- elif "email" in record_ids._fields:
- email_fname = "email"
- if not (email_fname and email):
- # Trying to unsubscribe without email? Bad boy...
- raise exceptions.AccessDenied()
- domain.append((email_fname, "ilike", email))
- # Search additional mailing lists for the unsubscriber
- additional_contacts = self._mailing_list_contacts_by_email(email)
- if record_ids._name == "mail.mass_mailing.contact":
- domain.append(
- ("list_id", "in", mailing_id.contact_list_ids.ids))
- # Unsubscription targets
- record_ids = record_ids.search(domain)
- if record_ids._name == "mail.mass_mailing.contact":
- additional_contacts -= record_ids
- if not record_ids:
- # Trying to unsubscribe with fake criteria? Bad boy...
- raise exceptions.AccessDenied()
- # Get data to identify the source of the unsubscription
- fnames = self.unsubscription_special_fnames(record_ids._name)
- first = record_ids[:1]
- contact_name = first[fnames.get("contact", "name")]
- origin_model_name = request.env["ir.model"].search(
- [("model", "=", first._name)]).name
- try:
- first = first[fnames["related"]]
- except KeyError:
- pass
- try:
- origin_name = first[fnames["origin"]]
- except KeyError:
- pass
- # Get available reasons
- reason_ids = (
- request.env["mail.unsubscription.reason"].search([]))
- return {
- "additional_contact_ids": additional_contacts,
- "contact_name": contact_name,
- "email": email,
- "mailing_id": mailing_id,
- "origin_model_name": origin_model_name,
- "origin_name": origin_name,
- "reason_ids": reason_ids,
- "record_ids": record_ids,
- "res_id": res_id,
- "token": token,
- }
- def unsubscription_special_fnames(self, model):
- """Define special field names to generate the unsubscription qcontext.
- :return dict:
- Special fields will depend on the model, so this method should
- return something like::
- {
- "related": "parent_id",
- "origin": "display_name",
- "contact": "contact_name",
- }
- Where:
- - ``model.name`` is the technical name of the model.
- - ``related`` indicates the name of a field in ``model.name`` that
- contains a :class:`openerp.fields.Many2one` field which is
- considered what the user is unsubscribing from.
- - ``origin``: is the name of the field that contains the name of
- what the user is unsubscribing from.
- - ``contact`` is the name of the field that contains the name of
- the user that is unsubscribing.
- Missing keys will mean that nothing special is required for that
- model and it will use the default values.
- """
- specials = {
- "mail.mass_mailing.contact": {
- "related": "list_id",
- "origin": "display_name",
- },
- "crm.lead": {
- "origin": "name",
- "contact": "contact_name",
- },
- "hr.applicant": {
- "related": "job_id",
- "origin": "name",
- },
- # In case you install OCA's event_registration_mass_mailing
- "event.registration": {
- "related": "event_id",
- "origin": "name",
- },
- }
- return specials.get(model, dict())
- @route(auth="public", website=True)
- def mailing(self, mailing_id, email=None, res_id=None, **post):
- """Display a confirmation form to get the unsubscription reason."""
- mailing = request.env["mail.mass_mailing"]
- path = "/page/mass_mailing_custom_unsubscribe.%s"
- good_token = mailing.hash_create(mailing_id, res_id, email)
- # Trying to unsubscribe with fake hash? Bad boy...
- if good_token and post.get("token") != good_token:
- return local_redirect(path % "failure")
- mailing = mailing.sudo().browse(mailing_id)
- contact = request.env["mail.mass_mailing.contact"].sudo()
- unsubscription = request.env["mail.unsubscription"].sudo()
- if not post.get("reason_id"):
- # We need to know why you leave, get to the form
- return self.unsubscription_reason(
- mailing, email, res_id, post.get("token"))
- # Save reason and details
- try:
- with request.env.cr.savepoint():
- records = unsubscription.create({
- "email": email,
- "unsubscriber_id": ",".join(
- (mailing.mailing_model, res_id)),
- "reason_id": int(post["reason_id"]),
- "details": post.get("details", False),
- "mass_mailing_id": mailing_id,
- })
- # Should provide details, go back to form
- except _ex.DetailsRequiredError:
- return self.unsubscription_reason(
- mailing, email, res_id, post.get("token"),
- {"error_details_required": True})
- # Unsubscribe from additional lists
- for key, value in post.iteritems():
- try:
- label, list_id = key.split(",")
- if label != "list_id":
- raise ValueError
- list_id = int(list_id)
- except ValueError:
- pass
- else:
- contact_id = contact.browse(int(value))
- if contact_id.list_id.id == list_id:
- contact_id.opt_out = True
- records += unsubscription.create({
- "email": email,
- "unsubscriber_id": ",".join((contact._name, value)),
- "reason_id": int(post["reason_id"]),
- "details": post.get("details", False),
- "mass_mailing_id": mailing_id,
- })
- # All is OK, unsubscribe
- result = super(CustomUnsubscribe, self).mailing(
- mailing_id, email, res_id, **post)
- records.write({"success": result.data == "OK"})
- # Redirect to the result
- return local_redirect(path % ("success" if result.data == "OK"
- else "failure"))
|