@@ -15,6 +15,7 @@ | |||
"engine": "InnoDB", | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -44,6 +45,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -74,6 +76,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -103,6 +106,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -131,6 +135,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -159,6 +164,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -170,7 +176,7 @@ | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 1, | |||
"in_list_view": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Subject", | |||
"length": 0, | |||
@@ -187,6 +193,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -198,7 +205,7 @@ | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Message", | |||
"length": 0, | |||
@@ -215,6 +222,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -245,6 +253,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -275,6 +284,68 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Check this, if you want the Portal User to view this.", | |||
"fieldname": "published", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Published", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "route", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Route", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -304,6 +375,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -333,6 +405,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -362,6 +435,7 @@ | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -391,19 +465,20 @@ | |||
"unique": 0 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"has_web_view": 1, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"icon": "fa fa-envelope", | |||
"idx": 1, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_published_field": "published", | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 3, | |||
"menu_index": 0, | |||
"modified": "2017-03-07 12:59:18.173824", | |||
"modified": "2017-09-11 11:21:29.067493", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Newsletter", | |||
@@ -433,6 +508,7 @@ | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"route": "newsletters", | |||
"show_name_in_global_search": 0, | |||
"sort_order": "ASC", | |||
"title_field": "subject", | |||
@@ -6,7 +6,7 @@ from __future__ import unicode_literals | |||
import frappe | |||
import frappe.utils | |||
from frappe import throw, _ | |||
from frappe.model.document import Document | |||
from frappe.website.website_generator import WebsiteGenerator | |||
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 | |||
@@ -17,7 +17,7 @@ from frappe.utils import parse_addr | |||
from frappe.utils import validate_email_add | |||
class Newsletter(Document): | |||
class Newsletter(WebsiteGenerator): | |||
def onload(self): | |||
if self.email_sent: | |||
self.get("__onload").status_count = dict(frappe.db.sql("""select status, count(name) | |||
@@ -25,6 +25,7 @@ class Newsletter(Document): | |||
group by status""", (self.doctype, self.name))) or None | |||
def validate(self): | |||
self.route = "newsletters/" + self.name | |||
if self.send_from: | |||
validate_email_add(self.send_from, True) | |||
@@ -105,6 +106,24 @@ class Newsletter(Document): | |||
throw(_("Please save the Newsletter before sending")) | |||
check_email_limit(self.recipients) | |||
def get_context(self, context): | |||
newsletter_list = [d.name for d in get_newsletter_list("Newsletter", None, None, 0)] | |||
context.no_cache = 1 | |||
context.show_sidebar = True | |||
if self.name not in newsletter_list: | |||
frappe.redirect_to_message(_('Permission Error'), | |||
_("You are not permitted to view the newsletter.")) | |||
frappe.local.flags.redirect_location = frappe.local.response.location | |||
raise frappe.Redirect | |||
else: | |||
context.attachments = get_attachments(self.name) | |||
def get_attachments(name): | |||
return frappe.get_all("File", | |||
fields=["name", "file_name", "file_url", "is_private"], | |||
filters = {"attached_to_name": name, "attached_to_doctype": "Newsletter", "is_private":0}) | |||
def get_email_groups(name): | |||
return frappe.db.get_all("Newsletter Email Group", ["email_group"],{"parent":name, "parenttype":"Newsletter"}) | |||
@@ -220,14 +239,15 @@ def send_newsletter(newsletter): | |||
def get_list_context(context=None): | |||
return { | |||
context.update({ | |||
"show_sidebar": True, | |||
"show_search": True, | |||
'no_breadcrumbs': True, | |||
"title": _("Newsletter"), | |||
"get_list": get_newsletter_list, | |||
"row_template": "email/doctype/newsletter/templates/newsletter_row.html", | |||
} | |||
}) | |||
def get_newsletter_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by="modified"): | |||
email_group_list = frappe.db.sql('''select eg.name from `tabEmail Group` eg, `tabEmail Group Member` egm | |||
@@ -235,6 +255,6 @@ def get_newsletter_list(doctype, txt, filters, limit_start, limit_page_length=20 | |||
if email_group_list: | |||
return frappe.db.sql('''select n.name, n.subject, n.message, n.modified | |||
from `tabNewsletter` n, `tabNewsletter Email Group` neg | |||
where n.name = neg.parent and n.email_sent=1 and neg.email_group in %s | |||
where n.name = neg.parent and n.email_sent=1 and n.published=1 and neg.email_group in %s | |||
order by n.modified desc limit {0}, {1} | |||
'''.format(limit_start, limit_page_length), [email_group_list], as_dict=1) |
@@ -1,5 +1,5 @@ | |||
<div class="web-list-item transaction-list-item"> | |||
<a href = "/newsletters/{{doc.name}}/"> | |||
<a href = "{{ route }}/"> | |||
<div class="row"> | |||
<div class="col-sm-8 text-left bold"> | |||
{{ doc.subject }} | |||
@@ -12,4 +12,4 @@ | |||
</div> | |||
</div> | |||
</a> | |||
</div> | |||
</div> |
@@ -0,0 +1,23 @@ | |||
/* eslint-disable */ | |||
// rename this file from _test_[name] to test_[name] to activate | |||
// and remove above this line | |||
QUnit.test("test: Newsletter", function (assert) { | |||
let done = assert.async(); | |||
// number of asserts | |||
assert.expect(1); | |||
frappe.run_serially([ | |||
// insert a new Newsletter | |||
() => frappe.tests.make('Newsletter', [ | |||
// values to be set | |||
{key: 'value'} | |||
]), | |||
() => { | |||
assert.equal(cur_frm.doc.key, 'value'); | |||
}, | |||
() => done() | |||
]); | |||
}); |
@@ -53,13 +53,7 @@ web_include_css = [ | |||
website_route_rules = [ | |||
{"from_route": "/blog/<category>", "to_route": "Blog Post"}, | |||
{"from_route": "/kb/<category>", "to_route": "Help Article"}, | |||
{"from_route": "/newsletters", "to_route": "Newsletter"}, | |||
{"from_route": "/newsletters/<path:name>", "to_route": "newsletters", | |||
"defaults": { | |||
"doctype": "Newsletter", | |||
"parents": [{"label": _("Newsletter"), "route": "newsletters"}] | |||
} | |||
} | |||
{"from_route": "/newsletters", "to_route": "Newsletter"} | |||
] | |||
standard_portal_menu_items = [ | |||
@@ -1,16 +0,0 @@ | |||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors | |||
# License: GNU General Public License v3. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
def get_context(context): | |||
context.no_cache = 1 | |||
context.show_sidebar = True | |||
context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) | |||
context.attachments = get_attachments(frappe.form_dict.doctype, frappe.form_dict.name) | |||
def get_attachments(dt, dn): | |||
return frappe.get_all("File", | |||
fields=["name", "file_name", "file_url", "is_private"], | |||
filters = {"attached_to_name": dn, "attached_to_doctype": dt, "is_private":0}) |