* 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 issueversion-14
@@ -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""" | |||
@@ -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)) |
@@ -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 %} | |||
@@ -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"}) |