Browse Source

Newsletter moved to Frappe

version-14
Kanchan Chauhan 9 years ago
parent
commit
a23ee192f3
21 changed files with 1081 additions and 1 deletions
  1. +15
    -0
      frappe/config/setup.py
  2. +0
    -0
      frappe/email/doctype/email_group/__init__.py
  3. +49
    -0
      frappe/email/doctype/email_group/email_group.js
  4. +109
    -0
      frappe/email/doctype/email_group/email_group.json
  5. +99
    -0
      frappe/email/doctype/email_group/email_group.py
  6. +12
    -0
      frappe/email/doctype/email_group/test_email_group.py
  7. +6
    -0
      frappe/email/doctype/email_group/test_records.json
  8. +0
    -0
      frappe/email/doctype/email_group_member/__init__.py
  9. +8
    -0
      frappe/email/doctype/email_group_member/email_group_member.js
  10. +135
    -0
      frappe/email/doctype/email_group_member/email_group_member.json
  11. +13
    -0
      frappe/email/doctype/email_group_member/email_group_member.py
  12. +12
    -0
      frappe/email/doctype/email_group_member/test_email_group_member.py
  13. +0
    -0
      frappe/email/doctype/newsletter/__init__.py
  14. +63
    -0
      frappe/email/doctype/newsletter/newsletter.js
  15. +302
    -0
      frappe/email/doctype/newsletter/newsletter.json
  16. +189
    -0
      frappe/email/doctype/newsletter/newsletter.py
  17. +10
    -0
      frappe/email/doctype/newsletter/newsletter_list.js
  18. +49
    -0
      frappe/email/doctype/newsletter/test_newsletter.py
  19. +4
    -1
      frappe/hooks.py
  20. +1
    -0
      frappe/patches.txt
  21. +5
    -0
      frappe/patches/v7_0/rename_newsletter_list_to_email_group.py

+ 15
- 0
frappe/config/setup.py View File

@@ -137,6 +137,21 @@ def get_data():
"name": "Standard Reply", "name": "Standard Reply",
"description": _("Standard replies to common queries.") "description": _("Standard replies to common queries.")
}, },
{
"type": "doctype",
"name": "Newsletter",
"description": _("Newsletters to contacts, leads."),
},
{
"type": "doctype",
"name": "Email Group",
"description": _("Email Group List"),
},
{
"type": "doctype",
"name": "Email Group Member",
"description": _("Email Group Member List"),
},
] ]
}, },
{ {


+ 0
- 0
frappe/email/doctype/email_group/__init__.py View File


+ 49
- 0
frappe/email/doctype/email_group/email_group.js View File

@@ -0,0 +1,49 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on("Email Group", "refresh", function(frm) {
if(!frm.is_new()) {
frm.add_custom_button(__("View Subscribers"), function() {
frappe.route_options = {"email_group": frm.doc.name};
frappe.set_route("Report", "Email Group Member");
}, __("View"));

frm.add_custom_button(__("Import Subscribers"), function() {
frappe.prompt({fieldtype:"Select", options: frm.doc.__onload.import_types,
label:__("Import Email From"), fieldname:"doctype", reqd:1}, function(data) {
frappe.call({
method: "frappe.email.doctype.email_group.email_group.import_from",
args: {
"name": frm.doc.name,
"doctype": data.doctype
},
callback: function(r) {
frm.set_value("total_subscribers", r.message);
}
})
}, __("Import Subscribers"), __("Import"));
}, __("Action"));

frm.add_custom_button(__("Add Subscribers"), function() {
frappe.prompt({fieldtype:"Text",
label:__("Email Ids"), fieldname:"email_list", reqd:1}, function(data) {
frappe.call({
method: "frappe.email.doctype.email_group.email_group.add_subscribers",
args: {
"name": frm.doc.name,
"email_list": data.email_list
},
callback: function(r) {
frm.set_value("total_subscribers", r.message);
}
})
}, __("Add Subscribers"), __("Add"));
}, __("Action"));

frm.add_custom_button(__("New Newsletter"), function() {
frappe.route_options = {"email_group": frm.doc.name};
frappe.new_doc("Newsletter");
}, __("Action"));

}
});

+ 109
- 0
frappe/email/doctype/email_group/email_group.json View File

@@ -0,0 +1,109 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "field:title",
"beta": 0,
"creation": "2015-03-18 06:08:32.729800",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Title",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "0",
"fieldname": "total_subscribers",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Total Subscribers",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-06-28 15:33:58.274566",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Group",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Newsletter Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

+ 99
- 0
frappe/email/doctype/email_group/email_group.py View File

@@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class EmailGroup(Document):
def onload(self):
singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})]
self.get("__onload").import_types = [{"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} \
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"})
if d.parent not in singles]

def import_from(self, doctype):
"""Extract email ids from given doctype and add them to the current list"""
meta = frappe.get_meta(doctype)
email_field = [d.fieldname for d in meta.fields
if d.fieldtype in ("Data", "Small Text", "Text", "Code") and d.options=="Email"][0]
unsubscribed_field = "unsubscribed" if meta.get_field("unsubscribed") else None
added = 0

for user in frappe.db.get_all(doctype, [email_field, unsubscribed_field or "name"]):
try:
email = parseaddr(user.get(email_field))[1]
if email:
frappe.get_doc({
"doctype": "Email Group Member",
"email_group": self.name,
"email": email,
"unsubscribed": user.get(unsubscribed_field) if unsubscribed_field else 0
}).insert(ignore_permissions=True)

added += 1
except frappe.UniqueValidationError:
pass

frappe.msgprint(_("{0} subscribers added").format(added))

return self.update_total_subscribers()

def update_total_subscribers(self):
self.total_subscribers = self.get_total_subscribers()
self.db_update()
return self.total_subscribers

def get_total_subscribers(self):
return frappe.db.sql("""select count(*) from `tabEmail Group Member`
where email_group=%s""", self.name)[0][0]

def on_trash(self):
for d in frappe.get_all("Email Group Member", "name", {"email_group": self.name}):
frappe.delete_doc("Email Group Member", d.name)

@frappe.whitelist()
def import_from(name, doctype):
nlist = frappe.get_doc("Email Group", name)
if nlist.has_permission("write"):
return nlist.import_from(doctype)

@frappe.whitelist()
def add_subscribers(name, email_list):
if not isinstance(email_list, (list, tuple)):
email_list = email_list.replace(",", "\n").split("\n")
count = 0
for email in email_list:
email = email.strip()
valid = validate_email_add(email, False)

if valid:
if not frappe.db.get_value("Email Group Member",
{"email_group": name, "email": email}):
frappe.get_doc({
"doctype": "Email Group Member",
"email_group": name,
"email": email
}).insert(ignore_permissions = frappe.flags.ignore_permissions)

count += 1
else:
pass
else:
frappe.msgprint(_("{0} is not a valid email id").format(email))

frappe.msgprint(_("{0} subscribers added").format(count))

return frappe.get_doc("Email Group", name).update_total_subscribers()

def restrict_email_group(doc, method):
from frappe.limits import get_limits

email_group_limit = get_limits().get('newsletter_recipients')
if not email_group_limit:
return

nl = frappe.get_doc("Email Group", doc.email_group)
if nl.get_total_subscribers() >= email_group_limit:
frappe.throw(_("Please Upgrade to add more than {0} subscribers").format(email_group_limit))

+ 12
- 0
frappe/email/doctype/email_group/test_email_group.py View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe
import unittest

# test_records = frappe.get_test_records('Email Group')

class TestEmailGroup(unittest.TestCase):
pass

+ 6
- 0
frappe/email/doctype/email_group/test_records.json View File

@@ -0,0 +1,6 @@
[
{
"doctype": "Email Group",
"title": "_Test Email Group"
}
]

+ 0
- 0
frappe/email/doctype/email_group_member/__init__.py View File


+ 8
- 0
frappe/email/doctype/email_group_member/email_group_member.js View File

@@ -0,0 +1,8 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Email Group Member', {
refresh: function(frm) {

}
});

+ 135
- 0
frappe/email/doctype/email_group_member/email_group_member.json View File

@@ -0,0 +1,135 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "hash",
"beta": 0,
"creation": "2015-03-18 06:15:59.321619",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "email_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Email Group",
"length": 0,
"no_copy": 0,
"options": "Email Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Email",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "unsubscribed",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Unsubscribed",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-06-28 17:00:27.546534",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Group Member",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Newsletter Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "email",
"track_seen": 0
}

+ 13
- 0
frappe/email/doctype/email_group_member/email_group_member.py View File

@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class EmailGroupMember(Document):
pass

def after_doctype_insert():
frappe.db.add_unique("Email Group Member", ("email_group", "email"))

+ 12
- 0
frappe/email/doctype/email_group_member/test_email_group_member.py View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe
import unittest

# test_records = frappe.get_test_records('Email Group Member')

class TestEmailGroupMember(unittest.TestCase):
pass

+ 0
- 0
frappe/email/doctype/newsletter/__init__.py View File


+ 63
- 0
frappe/email/doctype/newsletter/newsletter.js View File

@@ -0,0 +1,63 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

cur_frm.cscript.onload = function(doc) {
return frappe.call({
method: "frappe.email.doctype.newsletter.newsletter.get_lead_options",
type: "GET",
callback: function(r) {
set_field_options("lead_source", r.message.sources.join("\n"))
set_field_options("lead_status", r.message.statuses.join("\n"))
}
});
}

cur_frm.cscript.refresh = function(doc) {
erpnext.toggle_naming_series();
if(!doc.__islocal && !cint(doc.email_sent) && !doc.__unsaved
&& inList(frappe.boot.user.can_write, doc.doctype)) {
cur_frm.add_custom_button(__('Send'), function() {
return $c_obj(doc, 'send_emails', '', function(r) {
cur_frm.refresh();
});
}, "icon-play", "btn-success");
}

cur_frm.cscript.setup_dashboard();

if(doc.__islocal && !doc.send_from) {
cur_frm.set_value("send_from",
repl("%(fullname)s <%(email)s>", frappe.user_info(doc.owner)));
}
}

cur_frm.cscript.setup_dashboard = function() {
cur_frm.dashboard.reset();
if(!cur_frm.doc.__islocal && cint(cur_frm.doc.email_sent) && cur_frm.doc.__onload && cur_frm.doc.__onload.status_count) {
var stat = cur_frm.doc.__onload.status_count;
var total = frappe.utils.sum($.map(stat, function(v) { return v; }));
if(total) {
$.each(stat, function(k, v) {
stat[k] = flt(v * 100 / total, 2) + '%';
});

cur_frm.dashboard.add_progress("Status", [
{
title: stat["Sent"] + "% Sent",
width: stat["Sent"],
progress_class: "progress-bar-success"
},
{
title: stat["Sending"] + "% Sending",
width: stat["Sending"],
progress_class: "progress-bar-warning"
},
{
title: stat["Error"] + "% Error",
width: stat["Error"],
progress_class: "progress-bar-danger"
}
]);
}
}
}

+ 302
- 0
frappe/email/doctype/newsletter/newsletter.json View File

@@ -0,0 +1,302 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:subject",
"beta": 0,
"creation": "2013-01-10 16:34:31",
"custom": 0,
"description": "Create and Send Newsletters",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "email_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Email Group",
"length": 0,
"no_copy": 0,
"options": "Email Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "subject",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Subject",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "",
"fieldname": "send_from",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1,
"in_filter": 0,
"in_list_view": 0,
"label": "Sender",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "email_sent",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Email Sent?",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "newsletter_content",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "message",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "",
"fieldname": "test_the_newsletter",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "A Lead with this email id should exist",
"fieldname": "test_email_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Test Email Id",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "test_send",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Test",
"length": 0,
"no_copy": 0,
"options": "test_send",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-envelope",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-06-28 17:20:07.227578",
"modified_by": "Administrator",
"module": "Email",
"name": "Newsletter",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 1,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 1,
"cancel": 0,
"create": 0,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Newsletter Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 0
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_order": "ASC",
"title_field": "subject",
"track_seen": 0
}

+ 189
- 0
frappe/email/doctype/newsletter/newsletter.py View File

@@ -0,0 +1,189 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals

import frappe
import frappe.utils
from frappe import throw, _
from frappe.model.document import Document
from frappe.email.queue import check_email_limit
from frappe.utils.verified_command import get_signed_params, verify_request
from frappe.utils.background_jobs import enqueue
from frappe.utils.scheduler import log
from frappe.email.queue import send
from frappe.email.doctype.email_group.email_group import add_subscribers

class Newsletter(Document):
def onload(self):
if self.email_sent:
self.get("__onload").status_count = dict(frappe.db.sql("""select status, count(name)
from `tabEmail Queue` where reference_doctype=%s and reference_name=%s
group by status""", (self.doctype, self.name))) or None

def test_send(self, doctype="Lead"):
self.recipients = frappe.utils.split_emails(self.test_email_id)
self.queue_all()
frappe.msgprint(_("Scheduled to send to {0}").format(self.test_email_id))

def send_emails(self):
"""send emails to leads and customers"""
if self.email_sent:
throw(_("Newsletter has already been sent"))

self.recipients = self.get_recipients()

if getattr(frappe.local, "is_ajax", False):
self.validate_send()

# using default queue with a longer timeout as this isn't a scheduled task
enqueue(send_newsletter, queue='default', timeout=1500, event='send_newsletter', newsletter=self.name)

else:
self.queue_all()

frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients)))

frappe.db.set(self, "email_sent", 1)

def queue_all(self):
if not self.get("recipients"):
# in case it is called via worker
self.recipients = self.get_recipients()

self.validate_send()

sender = self.send_from or frappe.utils.get_formatted_email(self.owner)

if not frappe.flags.in_test:
frappe.db.auto_commit_on_many_writes = True

send(recipients = self.recipients, sender = sender,
subject = self.subject, message = self.message,
reference_doctype = self.doctype, reference_name = self.name,
unsubscribe_method = "/api/method/frappe.email.doctype.newsletter.newsletter.unsubscribe",
unsubscribe_params = {"name": self.email_group},
send_priority = 0)

if not frappe.flags.in_test:
frappe.db.auto_commit_on_many_writes = False

def get_recipients(self):
"""Get recipients from Email Group"""
return [d.email for d in frappe.db.get_all("Email Group Member", ["email"],
{"unsubscribed": 0, "email_group": self.email_group})]

def validate_send(self):
if self.get("__islocal"):
throw(_("Please save the Newsletter before sending"))
check_email_limit(self.recipients)

@frappe.whitelist()
def get_lead_options():
return {
"sources": ["All"] + filter(None,
frappe.db.sql_list("""select distinct source from tabLead""")),
"statuses": ["All"] + filter(None,
frappe.db.sql_list("""select distinct status from tabLead"""))
}


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

subs_id = frappe.db.get_value("Email Group Member", {"email": email, "email_group": name})
if subs_id:
subscriber = frappe.get_doc("Email Group Member", subs_id)
subscriber.unsubscribed = 1
subscriber.save(ignore_permissions=True)

frappe.db.commit()

return_unsubscribed_page(email)

def return_unsubscribed_page(email):
frappe.respond_as_web_page(_("Unsubscribed"), _("{0} has been successfully unsubscribed from this list.").format(email))

def create_lead(email_id):
"""create a lead if it does not exist"""
from email.utils import parseaddr
from frappe.model.naming import get_default_naming_series
real_name, email_id = parseaddr(email_id)

if frappe.db.get_value("Lead", {"email_id": email_id}):
return

lead = frappe.get_doc({
"doctype": "Lead",
"email_id": email_id,
"lead_name": real_name or email_id,
"status": "Lead",
"naming_series": get_default_naming_series("Lead"),
"company": frappe.db.get_default("Company"),
"source": "Email"
})
lead.insert()


@frappe.whitelist(allow_guest=True)
def subscribe(email):
url = frappe.utils.get_url("/api/method/frappe.email.doctype.newsletter.newsletter.confirm_subscription") +\
"?" + get_signed_params({"email": email})

messages = (
_("Thank you for your interest in subscribing to our updates"),
_("Please verify your email id"),
url,
_("Click here to verify")
)

content = """
<p>{0}. {1}.</p>
<p><a href="{2}">{3}</a></p>
"""

frappe.sendmail(email, subject=_("Confirm Your Email"), content=content.format(*messages))

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

if not frappe.db.exists("Email Group", _("Website")):
frappe.get_doc({
"doctype": "Email Group",
"title": _("Website")
}).insert(ignore_permissions=True)


frappe.flags.ignore_permissions = True

add_subscribers(_("Website"), email)
frappe.db.commit()

frappe.respond_as_web_page(_("Confirmed"), _("{0} has been successfully added to our Email Group.").format(email))


def send_newsletter(newsletter):
try:
doc = frappe.get_doc("Newsletter", newsletter)
doc.queue_all()

except:
frappe.db.rollback()

# wasn't able to send emails :(
doc.db_set("email_sent", 0)
frappe.db.commit()

log("send_newsletter")

raise

else:
frappe.db.commit()




+ 10
- 0
frappe/email/doctype/newsletter/newsletter_list.js View File

@@ -0,0 +1,10 @@
frappe.listview_settings['Newsletter'] = {
add_fields: ["subject", "email_sent"],
get_indicator: function(doc) {
if(doc.email_sent) {
return [__("Sent"), "green", "email_sent,=,Yes"];
} else {
return [__("Not Sent"), "orange", "email_sent,=,No"];
}
}
};

+ 49
- 0
frappe/email/doctype/newsletter/test_newsletter.py View File

@@ -0,0 +1,49 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals

import frappe, unittest

from frappe.email.doctype.newsletter.newsletter import unsubscribe
from urllib import unquote

class TestNewsletter(unittest.TestCase):
def setUp(self):
frappe.db.sql('delete from `tabEmail Group Member`')
for email in ["test_subscriber1@example.com", "test_subscriber2@example.com",
"test_subscriber3@example.com"]:
frappe.get_doc({
"doctype": "Email Group Member",
"email": email,
"email_group": "_Test Email Group"
}).insert()

def test_send(self):
self.send_newsletter()
self.assertEquals(len(frappe.get_all("Email Queue")), 3)

def test_unsubscribe(self):
# test unsubscribe
self.send_newsletter()

email = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0])

unsubscribe(email, "_Test Email Group")

self.send_newsletter()
self.assertEquals(len(frappe.get_all("Email Queue")), 2)

def send_newsletter(self):
frappe.db.sql("delete from `tabEmail Queue`")
frappe.delete_doc("Newsletter", "_Test Newsletter")
newsletter = frappe.get_doc({
"doctype": "Newsletter",
"subject": "_Test Newsletter",
"email_group": "_Test Email Group",
"send_from": "Test Sender <test_sender@example.com>",
"message": "Testing my news."
}).insert(ignore_permissions=True)

newsletter.send_emails()

test_dependencies = ["Email Group"]

+ 4
- 1
frappe/hooks.py View File

@@ -97,7 +97,10 @@ standard_queries = {
doc_events = { doc_events = {
"*": { "*": {
"after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", "after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",
"validate": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",
"validate": [
"frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",
"frappe.email.doctype.email_group.email_group.restrict_email_group"
],
"on_update": [ "on_update": [
"frappe.desk.notifications.clear_doctype_notifications", "frappe.desk.notifications.clear_doctype_notifications",
"frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",


+ 1
- 0
frappe/patches.txt View File

@@ -132,3 +132,4 @@ frappe.patches.v7_0.setup_list_settings
execute:frappe.db.sql('''delete from `tabSingles` where doctype="Email Settings"''') # 2016-06-13 execute:frappe.db.sql('''delete from `tabSingles` where doctype="Email Settings"''') # 2016-06-13
execute:frappe.db.sql("delete from `tabWeb Page` where ifnull(template_path, '')!=''") execute:frappe.db.sql("delete from `tabWeb Page` where ifnull(template_path, '')!=''")
frappe.patches.v7_0.re_route #2016-06-27 frappe.patches.v7_0.re_route #2016-06-27
frappe.patches.v7_0.rename_newsletter_list_to_email_group

+ 5
- 0
frappe/patches/v7_0/rename_newsletter_list_to_email_group.py View File

@@ -0,0 +1,5 @@
import frappe

def execute():
frappe.rename_doc('DocType', 'Newsletter List', 'Email Group')
frappe.rename_doc('DocType', 'Newsletter List Subscriber', 'Email Group Member')

Loading…
Cancel
Save