@@ -269,7 +269,7 @@ def get_request_header(key, default=None): | |||
return request.headers.get(key, default) | |||
def sendmail(recipients=(), sender="", subject="No Subject", message="No Message", | |||
as_markdown=False, bulk=False, ref_doctype=None, ref_docname=None, | |||
as_markdown=False, bulk=False, reference_doctype=None, reference_name=None, | |||
unsubscribe_url=False, attachments=None, content=None, doctype=None, name=None, reply_to=None): | |||
"""Send email using user's default **Email Account** or global default **Email Account**. | |||
@@ -280,8 +280,8 @@ def sendmail(recipients=(), sender="", subject="No Subject", message="No Message | |||
:param message: (or `content`) Email Content. | |||
:param as_markdown: Convert content markdown to HTML. | |||
:param bulk: Send via scheduled email sender **Bulk Email**. Don't send immediately. | |||
:param ref_doctype: (or `doctype`) Append as communication to this DocType. | |||
:param ref_docname: (or `name`) Append as communication to this document name. | |||
:param reference_doctype: (or `doctype`) Append as communication to this DocType. | |||
:param reference_name: (or `name`) Append as communication to this document name. | |||
:param unsubscribe_url: Unsubscribe url with options email, doctype, name. e.g. `/api/method/unsubscribe?email={email}&name={name}` | |||
:param attachments: List of attachments. | |||
:param reply_to: Reply-To email id. | |||
@@ -290,8 +290,8 @@ def sendmail(recipients=(), sender="", subject="No Subject", message="No Message | |||
if bulk: | |||
import frappe.email.bulk | |||
frappe.email.bulk.send(recipients=recipients, sender=sender, | |||
subject=subject, message=content or message, ref_doctype = doctype or ref_doctype, | |||
ref_docname = name or ref_docname, unsubscribe_url=unsubscribe_url, attachments=attachments, | |||
subject=subject, message=content or message, reference_doctype = doctype or reference_doctype, | |||
reference_name = name or reference_name, unsubscribe_url=unsubscribe_url, attachments=attachments, | |||
reply_to=reply_to) | |||
else: | |||
@@ -861,7 +861,7 @@ def add_version(doc): | |||
A **Version** is a JSON dump of the current document state.""" | |||
get_doc({ | |||
"doctype": "Version", | |||
"ref_doctype": doc.doctype, | |||
"reference_doctype": doc.doctype, | |||
"docname": doc.name, | |||
"doclist_json": as_json(doc.as_dict()) | |||
}).insert(ignore_permissions=True) | |||
@@ -90,8 +90,8 @@ class Communication(Document): | |||
"sender": mail.sender, | |||
"recipient": mail.recipients[0], | |||
"message": mail.as_string(), | |||
"ref_doctype": self.reference_doctype, | |||
"ref_docname": self.reference_name | |||
"reference_doctype": self.reference_doctype, | |||
"reference_name": self.reference_name | |||
}).insert(ignore_permissions=True) | |||
def notify(self, mail, except_sender=False): | |||
@@ -4,75 +4,107 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import HTMLParser | |||
from urllib import quote_plus | |||
from frappe import msgprint, throw, _ | |||
from frappe.email.smtp import SMTPServer, get_outgoing_email_account | |||
from frappe.email.email_body import get_email, get_formatted_html | |||
from frappe.utils.verified_command import get_signed_params, verify_request | |||
from html2text import html2text | |||
from frappe.utils import get_url, nowdate | |||
class BulkLimitCrossedError(frappe.ValidationError): pass | |||
def send(recipients=None, sender=None, doctype='User', email_field='email', | |||
subject='[No Subject]', message='[No Content]', ref_doctype=None, | |||
ref_docname=None, unsubscribe_url=True, attachments=None, reply_to=None): | |||
def send(recipients=None, sender=None, subject=None, message=None, reference_doctype=None, | |||
reference_name=None, unsubscribe_method=None, unsubscribe_params=None, | |||
attachments=None, reply_to=None, footer_message=None): | |||
"""Add email to sending queue (Bulk Email) | |||
if not unsubscribe_url: | |||
unsubscribe_url = "/api/method/frappe.email.bulk.unsubscribe?doctype={doctype}&name={name}&email={email}" | |||
:param recipients: List of recipients. | |||
:param sender: Email sender. | |||
:param subject: Email subject. | |||
:param message: Email message. | |||
:param reference_doctype: Reference DocType of caller document. | |||
:param reference_name: Reference name of caller document. | |||
:param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.bulk.unsubscribe`. | |||
:param unsubscribe_params: additional params for unsubscribed links. default are name, doctype, email | |||
:param attachments: Attachments to be sent. | |||
:param reply_to: Reply to be captured here (default inbox)""" | |||
def check_bulk_limit(new_mails): | |||
this_month = frappe.db.sql("""select count(*) from `tabBulk Email` where | |||
month(creation)=month(%s)""" % nowdate())[0][0] | |||
# No limit for own email settings | |||
smtp_server = SMTPServer() | |||
if smtp_server.email_account and not getattr(smtp_server.email_account, | |||
"from_site_config", False) or frappe.flags.in_test: | |||
monthly_bulk_mail_limit = frappe.conf.get('monthly_bulk_mail_limit') or 500 | |||
if (this_month + len(recipients)) > monthly_bulk_mail_limit: | |||
throw(_("Bulk email limit {0} crossed").format(monthly_bulk_mail_limit), | |||
BulkLimitCrossedError) | |||
def update_message(formatted, unsubscribe_url, email): | |||
updated = formatted | |||
my_unsubscribe_url = unsubscribe_url.format(email=quote_plus(email), doctype=quote_plus(ref_doctype), | |||
name=quote_plus(ref_docname)) | |||
unsubscribe_link = """<div style="padding: 7px; border-top: 1px solid #aaa; margin-top: 17px;"> | |||
<small><a href="{base_url}/{url}">{message}</a></small></div>""".format(base_url = get_url(), | |||
url = my_unsubscribe_url, message = _("Unsubscribe from this list")) | |||
updated = updated.replace("<!--unsubscribe link here-->", unsubscribe_link) | |||
return updated | |||
if not unsubscribe_method: | |||
unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" | |||
if not recipients: | |||
recipients = [] | |||
return | |||
if not sender or sender == "Administrator": | |||
email_account = get_outgoing_email_account() | |||
sender = email_account.get("sender") or email_account.email_id | |||
check_bulk_limit(len(recipients)) | |||
check_bulk_limit(recipients) | |||
formatted = get_formatted_html(subject, message) | |||
try: | |||
text_content = html2text(formatted) | |||
except HTMLParser.HTMLParseError: | |||
text_content = "See html attachment" | |||
unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", | |||
{"reference_doctype": ref_doctype, "reference_name": ref_docname})] | |||
{"reference_doctype": reference_doctype, "reference_name": reference_name})] | |||
for email in filter(None, list(set(recipients))): | |||
if email not in unsubscribed: | |||
unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email, | |||
unsubscribe_method, unsubscribe_params) | |||
for r in filter(None, list(set(recipients))): | |||
if r not in unsubscribed: | |||
# add to queue | |||
updated = update_message(formatted, unsubscribe_url) | |||
try: | |||
text_content = html2text(updated) | |||
except HTMLParser.HTMLParseError: | |||
text_content = "[See html attachment]" | |||
updated = add_unsubscribe_link(formatted, email, reference_doctype, reference_name, | |||
unsubscribe_url, footer_message) | |||
text_content += "\n" + _("Unsubscribe link: {0}").format(unsubscribe_url) | |||
add(email, sender, subject, updated, text_content, reference_doctype, reference_name, attachments, reply_to) | |||
add(r, sender, subject, updated, text_content, ref_doctype, ref_docname, attachments, reply_to) | |||
def check_bulk_limit(recipients): | |||
this_month = frappe.db.sql("""select count(*) from `tabBulk Email` where | |||
month(creation)=month(%s)""" % nowdate())[0][0] | |||
# No limit for own email settings | |||
smtp_server = SMTPServer() | |||
if smtp_server.email_account and not getattr(smtp_server.email_account, | |||
"from_site_config", False) or frappe.flags.in_test: | |||
monthly_bulk_mail_limit = frappe.conf.get('monthly_bulk_mail_limit') or 500 | |||
if (this_month + len(recipients)) > monthly_bulk_mail_limit: | |||
throw(_("Bulk email limit {0} crossed").format(monthly_bulk_mail_limit), | |||
BulkLimitCrossedError) | |||
def add_unsubscribe_link(message, email, reference_doctype, reference_name, unsubscribe_url, footer_message): | |||
unsubscribe_link = """<div style="padding: 7px; border-top: 1px solid #aaa; margin-top: 17px;"> | |||
<small>{footer_message} | |||
<a href="{unsubscribe_url}">{unsubscribe_message}</a></small></div>""".format(unsubscribe_url = unsubscribe_url, | |||
unsubscribe_message = _("Unsubscribe from this list"), footer_message= footer_message or "") | |||
message = message.replace("<!--unsubscribe link here-->", unsubscribe_link) | |||
return message | |||
def get_unsubcribed_url(reference_doctype, reference_name, email, unsubscribe_method, unsubscribe_params): | |||
params = {"email": email.encode("utf-8"), | |||
"doctype": reference_doctype.encode("utf-8"), | |||
"name": reference_name.encode("utf-8")} | |||
if unsubscribe_params: | |||
params.update(unsubscribe_params) | |||
query_string = get_signed_params(params) | |||
# for test | |||
frappe.local.flags.signed_query_string = query_string | |||
return get_url(unsubscribe_method + "?" + get_signed_params(params)) | |||
def add(email, sender, subject, formatted, text_content=None, | |||
ref_doctype=None, ref_docname=None, attachments=None, reply_to=None): | |||
reference_doctype=None, reference_name=None, attachments=None, reply_to=None): | |||
"""add to bulk mail queue""" | |||
e = frappe.new_doc('Bulk Email') | |||
e.sender = sender | |||
@@ -85,27 +117,29 @@ def add(email, sender, subject, formatted, text_content=None, | |||
# bad email id - don't add to queue | |||
return | |||
e.ref_doctype = ref_doctype | |||
e.ref_docname = ref_docname | |||
e.reference_doctype = reference_doctype | |||
e.reference_name = reference_name | |||
e.insert(ignore_permissions=True) | |||
@frappe.whitelist(allow_guest=True) | |||
def unsubscribe(doctype, name, email): | |||
# unsubsribe from comments and communications | |||
frappe.g | |||
if not verify_request(): | |||
return | |||
frappe.get_doc({ | |||
"doctype": "Email Unsubscribe", | |||
"email": email, | |||
"reference_doctype": doctype, | |||
"reference_name": name | |||
}).insert(ignore_permissions=True) | |||
if not frappe.form_dict.get("from_test"): | |||
frappe.db.commit() | |||
frappe.db.commit() | |||
return_unsubscribed_page(email) | |||
def return_unsubscribed_page(email): | |||
frappe.local.message_title = _("Unsubscribed") | |||
frappe.local.message = "<h3>" + _("Unsubscribed") + "</h3><p>" \ | |||
+ _("{0} has been successfully unsubscribed").fomrat(email) + "</p>" | |||
frappe.response['type'] = 'page' | |||
frappe.response['page_name'] = 'message.html' | |||
frappe.respond_as_web_page(_("Unsubscribed"), _("{0} has been successfully unsubscribed").format(email)) | |||
def flush(from_test=False): | |||
"""flush email queue, every time: called from scheduler""" | |||
@@ -44,7 +44,7 @@ | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"fieldname": "ref_doctype", | |||
"fieldname": "reference_doctype", | |||
"fieldtype": "Link", | |||
"label": "Reference DocType", | |||
"options": "DocType", | |||
@@ -53,7 +53,7 @@ | |||
"reqd": 0 | |||
}, | |||
{ | |||
"fieldname": "ref_docname", | |||
"fieldname": "reference_name", | |||
"fieldtype": "Data", | |||
"label": "Reference DocName", | |||
"permlevel": 0, | |||
@@ -64,7 +64,7 @@ | |||
"icon": "icon-envelope", | |||
"idx": 1, | |||
"in_create": 1, | |||
"modified": "2015-01-23 04:32:39.175147", | |||
"modified": "2015-03-19 05:36:16.813340", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Bulk Email", | |||
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Bulk Email') | |||
class TestBulkEmail(unittest.TestCase): | |||
pass |
@@ -91,5 +91,5 @@ def evaluate_alert(doc, alert, event): | |||
frappe.sendmail(recipients=recipients, subject=alert.subject, | |||
message= frappe.render_template(alert.message, {"doc": doc, "alert":alert}), | |||
bulk=True, ref_doctype = doc.doctype, ref_docname = doc.name, | |||
bulk=True, reference_doctype = doc.doctype, reference_name = doc.name, | |||
attachments = [frappe.attach_print(doc.doctype, doc.name)] if alert.attach_print else None) |
@@ -20,16 +20,16 @@ class TestEmailAlert(unittest.TestCase): | |||
comment.comment = "test" | |||
comment.insert(ignore_permissions=True) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Comment", | |||
"ref_docname": comment.name, "status":"Not Sent"})) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Comment", | |||
"reference_name": comment.name, "status":"Not Sent"})) | |||
frappe.db.sql("""delete from `tabBulk Email`""") | |||
comment.description = "test" | |||
comment.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Comment", | |||
"ref_docname": comment.name, "status":"Not Sent"})) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Comment", | |||
"reference_name": comment.name, "status":"Not Sent"})) | |||
def test_condition(self): | |||
event = frappe.new_doc("Event") | |||
@@ -38,14 +38,14 @@ class TestEmailAlert(unittest.TestCase): | |||
event.starts_on = "2014-06-06 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
event.event_type = "Public" | |||
event.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
def test_value_changed(self): | |||
event = frappe.new_doc("Event") | |||
@@ -54,20 +54,20 @@ class TestEmailAlert(unittest.TestCase): | |||
event.starts_on = "2014-06-06 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
event.subject = "test 1" | |||
event.save() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
event.description = "test" | |||
event.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
def test_date_changed(self): | |||
event = frappe.new_doc("Event") | |||
@@ -76,23 +76,23 @@ class TestEmailAlert(unittest.TestCase): | |||
event.starts_on = "2014-01-01 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | |||
# not today, so no alert | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
event.starts_on = frappe.utils.add_days(frappe.utils.nowdate(), 2) + " 12:00:00" | |||
event.save() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) | |||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | |||
# today so show alert | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||
"reference_name": event.name, "status":"Not Sent"})) |
@@ -241,7 +241,7 @@ class BaseDocument(object): | |||
values = ", ".join(["%s"] * len(columns)) | |||
), d.values()) | |||
except Exception, e: | |||
if e.args[0]==1062 and "PRIMARY" in e.message: | |||
if e.args[0]==1062 and "PRIMARY" in e.args[1]: | |||
if self.meta.autoname=="hash": | |||
self.name = None | |||
self.db_insert() | |||
@@ -74,9 +74,9 @@ def get_default_value(df, defaults, user_permissions, parent_doc): | |||
# default value based on another document | |||
ref_doctype = df.default[1:] | |||
ref_fieldname = ref_doctype.lower().replace(" ", "_") | |||
ref_docname = parent_doc.get(ref_fieldname) if parent_doc else frappe.db.get_default(ref_fieldname) | |||
reference_name = parent_doc.get(ref_fieldname) if parent_doc else frappe.db.get_default(ref_fieldname) | |||
default_value = frappe.db.get_value(ref_doctype, ref_docname, df.fieldname) | |||
default_value = frappe.db.get_value(ref_doctype, reference_name, df.fieldname) | |||
is_allowed_default_value = (not user_permissions_exist or | |||
(default_value in user_permissions.get(df.options, []))) | |||
@@ -65,3 +65,4 @@ frappe.patches.v5_0.fix_feed | |||
frappe.patches.v5_0.update_shared | |||
frappe.patches.v5_0.bookmarks_to_stars | |||
frappe.patches.v5_0.style_settings_to_website_theme | |||
frappe.patches.v5_0.rename_ref_type_fieldnames |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
def execute(): | |||
frappe.db.sql("alter table `tabBulk Email` change `ref_docname` `reference_name` varchar(255)") | |||
frappe.db.sql("alter table `tabBulk Email` change `reference_doctype` `reference_doctype` varchar(255)") | |||
frappe.reload_doctype("Bulk Email") |
@@ -1,3 +1,7 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
def execute(): | |||
@@ -53,11 +53,9 @@ def add_comment(args=None): | |||
from frappe.email.bulk import send | |||
send(recipients=recipients, | |||
doctype='Comment', | |||
email_field='comment_by', | |||
subject = _("New comment on {0} {1}").format(comment.comment_doctype, comment.comment_docname), | |||
message = message, | |||
ref_doctype=comment.comment_doctype, ref_docname=comment.comment_docname) | |||
reference_doctype=comment.comment_doctype, reference_name=comment.comment_docname) | |||
template = frappe.get_template("templates/includes/comments/comment.html") | |||
@@ -11,7 +11,7 @@ make_test_records("Email Account") | |||
class TestEmail(unittest.TestCase): | |||
def setUp(self): | |||
frappe.db.sql("""update tabUser set unsubscribed=0""") | |||
frappe.db.sql("""delete from `tabEmail Unsubscribe`""") | |||
frappe.db.sql("""delete from `tabBulk Email`""") | |||
def test_send(self): | |||
@@ -22,7 +22,7 @@ class TestEmail(unittest.TestCase): | |||
from frappe.email.bulk import send | |||
send(recipients = ['test@example.com', 'test1@example.com'], | |||
sender="admin@example.com", | |||
doctype='User', email_field='email', | |||
reference_doctype='User', reference_name='Administrator', | |||
subject='Testing Bulk', message='This is a bulk mail!') | |||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Not Sent'""", as_dict=1) | |||
@@ -42,17 +42,14 @@ class TestEmail(unittest.TestCase): | |||
def test_unsubscribe(self): | |||
from frappe.email.bulk import unsubscribe, send | |||
frappe.local.form_dict = frappe._dict({ | |||
'email':'test@example.com', | |||
'type':'User', | |||
'email_field':'email', | |||
"from_test": True | |||
}) | |||
unsubscribe() | |||
unsubscribe(doctype="User", name="Administrator", email="test@example.com") | |||
self.assertTrue(frappe.db.get_value("Email Unsubscribe", | |||
{"reference_doctype": "User", "reference_name": "Administrator", "email": "test@example.com"})) | |||
send(recipients = ['test@example.com', 'test1@example.com'], | |||
sender="admin@example.com", | |||
doctype='User', email_field='email', | |||
reference_doctype='User', reference_name= "Administrator", | |||
subject='Testing Bulk', message='This is a bulk mail!') | |||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Not Sent'""", | |||
@@ -67,7 +64,7 @@ class TestEmail(unittest.TestCase): | |||
self.assertRaises(BulkLimitCrossedError, send, | |||
recipients=['test@example.com']*1000, | |||
sender="admin@example.com", | |||
doctype='User', email_field='email', | |||
reference_doctype = "User", reference_name="Administrator", | |||
subject='Testing Bulk', message='This is a bulk mail!') | |||
@@ -4,25 +4,40 @@ | |||
from __future__ import unicode_literals | |||
import hmac | |||
import urllib | |||
from frappe import _ | |||
import frappe | |||
import frappe.utils | |||
def get_signed_params(params): | |||
"""Sign a url by appending `&_signature=xxxxx` to given params (string or dict). | |||
:param params: String or dict of parameters.""" | |||
if not isinstance(params, basestring): | |||
params = urllib.urlencode(params) | |||
signature = hmac.new(params) | |||
signature.update(get_secret()) | |||
return params + "&_signature=" + signature.hexdigest() | |||
def get_secret(): | |||
return frappe.local.conf.get("secret") or frappe.db.get_value("User", "Administrator", "creation") | |||
return frappe.local.conf.get("secret") or str(frappe.db.get_value("User", "Administrator", "creation")) | |||
def verify_request(): | |||
params, signature = frappe.request.query_string.split("&_signature=") | |||
given_signature = hmac.new(params) | |||
"""Verify if the incoming signed request if it is correct.""" | |||
query_string = frappe.request.query_string if hasattr(frappe.request, "query_string") \ | |||
else frappe.local.flags.signed_query_string | |||
params, signature = query_string.split("&_signature=") | |||
given_signature = hmac.new(params.encode("utf-8")) | |||
given_signature.update(get_secret()) | |||
return signature == given_signature | |||
valid = signature == given_signature.hexdigest() | |||
if not valid: | |||
frappe.respond_as_web_page(_("Invalid Link"), | |||
_("This link is invalid or expired. Please make sure you have pasted correctly.")) | |||
return valid | |||
def get_url(cmd, params, nonce=None, secret=None): | |||
if not nonce: | |||