瀏覽代碼

feat: Allow Contact to unsubscribe from specific lists (#6458)

* intial commit

* changes

* added validation

* bux fixes

* confirmed_unsubscribe code raw mysql query removed

* moved everything to single file for optimisation

* UI fixes

* fixed csrf token not found

* removed the older function(method)

* code refracted or added some comment

* changes

* ui enhancement

* codacy fixes

* Ui fixes

* Applied Requested changes

* code optimisation

* fixed unit test

* more validation

* Ui fixes

* removed print statement which was used for tracing

* change

*  done changes requested

* done chnages requested

* Make code more self-explanatory

* Fix some code formatting
- Add more descriptive name/id for buttons
- Rearrange a comment
- Remove some unwanted line breaks
- change status values

fixes #15961 issue
version-14
Anurag Mishra 6 年之前
committed by Suraj Shetty
父節點
當前提交
94a4acf364
共有 4 個文件被更改,包括 174 次插入34 次删除
  1. +8
    -28
      frappe/email/doctype/newsletter/newsletter.py
  2. +11
    -6
      frappe/email/doctype/newsletter/test_newsletter.py
  3. +111
    -0
      frappe/www/unsubscribe.html
  4. +44
    -0
      frappe/www/unsubscribe.py

+ 8
- 28
frappe/email/doctype/newsletter/newsletter.py 查看文件

@@ -85,7 +85,7 @@ class Newsletter(WebsiteGenerator):
subject = self.subject, message = self.message,
reference_doctype = self.doctype, reference_name = self.name,
add_unsubscribe_link = self.send_unsubscribe_link, attachments=attachments,
unsubscribe_method = "/api/method/frappe.email.doctype.newsletter.newsletter.unsubscribe",
unsubscribe_method = "/unsubscribe",
unsubscribe_params = {"name": self.name},
send_priority = 0, queue_separately=True)

@@ -132,33 +132,13 @@ def get_email_groups(name):


@frappe.whitelist(allow_guest=True)
def unsubscribe(email, name):
if not verify_request():
return

primary_action = frappe.utils.get_url() + "/api/method/frappe.email.doctype.newsletter.newsletter.confirmed_unsubscribe"+\
"?" + get_signed_params({"email": email, "name":name})
return_confirmation_page(email, name, primary_action)


@frappe.whitelist(allow_guest=True)
def confirmed_unsubscribe(email, name):
if not verify_request():
return

for email_group in get_email_groups(name):
frappe.db.sql('''update `tabEmail Group Member` set unsubscribed=1 where email=%s and email_group=%s''',(email, email_group.email_group))

frappe.db.commit()
return_unsubscribed_page(email, name)

def return_confirmation_page(email, name, primary_action):
frappe.respond_as_web_page(_("Unsubscribe from Newsletter"),_("Do you want to unsubscribe from this mailing list?"),
indicator_color="blue", primary_label = _("Unsubscribe"), primary_action=primary_action)

def return_unsubscribed_page(email, name):
frappe.respond_as_web_page(_("Unsubscribed from Newsletter"),
_("<b>{0}</b> has been successfully unsubscribed from this mailing list.").format(email, name), indicator_color='green')
def confirmed_unsubscribe(email, group):
""" unsubscribe the email(user) from the mailing list(email_group) """
frappe.flags.ignore_permissions=True
doc = frappe.get_doc("Email Group Member", {"email": email, "email_group": group})
if not doc.unsubscribed:
doc.unsubscribed = 1
doc.save(ignore_permissions = True)

def create_lead(email_id):
"""create a lead if it does not exist"""


+ 11
- 6
frappe/email/doctype/newsletter/test_newsletter.py 查看文件

@@ -7,6 +7,7 @@ import frappe, unittest
from frappe.email.doctype.newsletter.newsletter import confirmed_unsubscribe
from six.moves.urllib.parse import unquote

test_dependencies = ["Email Group"]

emails = ["test_subscriber1@example.com", "test_subscriber2@example.com",
"test_subscriber3@example.com", "test1@example.com"]
@@ -15,6 +16,13 @@ class TestNewsletter(unittest.TestCase):
def setUp(self):
frappe.set_user("Administrator")
frappe.db.sql('delete from `tabEmail Group Member`')

group_exist=frappe.db.exists("Email Group", "_Test Email Group")
if len(group_exist) == 0:
frappe.get_doc({
"doctype": "Email Group",
"title": "_Test Email Group"
}).insert()
for email in emails:
frappe.get_doc({
"doctype": "Email Group Member",
@@ -37,8 +45,8 @@ class TestNewsletter(unittest.TestCase):
from frappe.email.queue import flush
flush(from_test=True)
to_unsubscribe = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0])
confirmed_unsubscribe(to_unsubscribe, name)
group = frappe.get_all("Newsletter Email Group", filters={"parent" : name}, fields=["email_group"])
confirmed_unsubscribe(to_unsubscribe, group[0].email_group)

name = self.send_newsletter()

@@ -81,7 +89,4 @@ class TestNewsletter(unittest.TestCase):
doc = frappe.get_doc("Newsletter", newsletter_name)
doc.get_context(context)
self.assertEqual(context.no_cache, 1)
self.assertTrue("attachments" not in list(context))


test_dependencies = ["Email Group"]
self.assertTrue("attachments" not in list(context))

+ 111
- 0
frappe/www/unsubscribe.html 查看文件

@@ -0,0 +1,111 @@
{% extends "templates/web.html" %}

{% block title %} Unsubscribe from Newsletter {% endblock %}

{% block page_content %}

<script>
frappe.ready(function() {
$("#select-all-btn").click(function() {
$(".group").prop('checked', true);

});
$("#unselect-all-btn").click(function() {
$(".group").prop('checked', false);
});
});
</script>

{% if status == "waiting_for_confirmation" %}
<!-- Confirmation page to select the group to unsubscribe -->
<div class="page-card ">
<div class='page-card-head'>
<span class='indicator blue'>Unsubscribe</span>
</div>
{% if email_groups %}
<div>
Select groups you wish to unsubscribe from.
<span class="text-muted">{{ email }}</span>
</div>
<!-- Show 'Select All' or 'Unselect All' buttons only if there are more than 5 groups -->
{% if email_groups|length > 5 %}
<button id="select-all-btn"class="small-btn">Select All</button>
<button id="unselect-all-btn"class="small-btn">Unselect All</button>
{% endif %}
<form method="post">
<input type="hidden" name="user_email" value="{{ email }}">
<input type="hidden" name="csrf_token" value="{{ frappe.session.csrf_token }}">
<!-- Break into columns if there are more than 20 groups -->
<div class="checkbox-container {% if email_groups|length > 10 %} row {% endif %}">
{% for group in email_groups %}
<div class="checkbox {% if email_groups|length > 10 %} col-sm-6 {% endif %}">
<label>
<input
type="checkbox"
{% if current_group[0].email_group == group.email_group %} checked {% endif %}
class="group"
name='{{ group.email_group }}'>
<span style="padding-left: 10px">{{ group.email_group }}</span>
</label>
</div>
{% endfor %}
</div>
<button
type="submit"
id="unsubscribe"
class="btn btn-primary">
Unsubscribe
</button>
</form>
{% else %}
<div>
You are not registered to any mailing list.
<span class="text-muted">{{ email }}</span>
</div>
{% endif %}
</div>

{% elif status == "unsubscribed" %}
<!-- Unsubscribed page comes after submission -->
<div class="page-card">
<div class='page-card-head'>
<span class='indicator green'>Unsubscribed</span>
</div>
You have been unsubscribed from selected mailing list.
</div>

{% else %}
<!-- For invalid and unsigned request -->
<div class="page-card">
<div class='page-card-head'>
<span class='indicator red'>Unsubscribe</span>
</div>
<b>Invalid Request.</b>
</div>
{% endif %}

{% endblock %}

{% block style %}
<style>
{% include "templates/styles/card_style.css" %}
.small-btn {
padding: 1px 5px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
color: inherit;
background-color: #f0f4f7;
border-color: transparent;
margin: 15px 5px 0 0;
}
.checkbox-container {
margin-top: 20px;
}
.main-div {
width: 500px;
height: auto;
}
</style>
{% endblock %}


+ 44
- 0
frappe/www/unsubscribe.py 查看文件

@@ -0,0 +1,44 @@
from __future__ import unicode_literals
import frappe
from frappe.utils.verified_command import verify_request
from frappe.email.doctype.newsletter.newsletter import confirmed_unsubscribe

no_cache = True

def get_context(context):
frappe.flags.ignore_permissions = True
# Called for confirmation.
if "email" in frappe.form_dict:
if verify_request():
user_email = frappe.form_dict["email"]
context.email = user_email
title = frappe.form_dict["name"]
context.email_groups = get_email_groups(user_email)
context.current_group = get_current_groups(title)
context.status = "waiting_for_confirmation"

# Called when form is submitted.
elif "user_email" in frappe.form_dict:
context.status = "unsubscribed"
email = frappe.form_dict['user_email']
email_group = get_email_groups(email)
for group in email_group:
if group.email_group in frappe.form_dict:
confirmed_unsubscribe(email, group.email_group)

# Called on Invalid or unsigned request.
else:
context.status = "invalid"

def get_email_groups(user_email):
# Return the all email_groups in which the email has been registered.
return frappe.get_all("Email Group Member",
fields=["email_group"],
filters={"email": user_email, "unsubscribed": 0})


def get_current_groups(name):
# Return current group by which the mail has been sent.
return frappe.db.get_all("Newsletter Email Group",
fields=["email_group"],
filters={"parent":name, "parenttype":"Newsletter"})

Loading…
取消
儲存