From 528d04213e5123d89ae7979cbbb182ca9520736c Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Mon, 5 Oct 2020 17:16:23 +0530 Subject: [PATCH 001/460] feat: clear failed jobs queue --- .../page/background_jobs/background_jobs.js | 22 +++++++++--- .../page/background_jobs/background_jobs.py | 34 ++++++++++++------- .../background_jobs_outer.html | 5 ++- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/frappe/core/page/background_jobs/background_jobs.js b/frappe/core/page/background_jobs/background_jobs.js index bbc8bf049b..9dd2c10b05 100644 --- a/frappe/core/page/background_jobs/background_jobs.js +++ b/frappe/core/page/background_jobs/background_jobs.js @@ -1,5 +1,5 @@ frappe.pages['background_jobs'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ + let page = frappe.ui.make_app_page({ parent: wrapper, title: __('Background Jobs'), single_column: true @@ -9,6 +9,9 @@ frappe.pages['background_jobs'].on_page_load = function(wrapper) { page.content = $(page.body).find('.table-area'); frappe.pages.background_jobs.page = page; + + let $remove_failed_btn = page.body.find('.remove-failed'); + $remove_failed_btn.click(remove_failed_jobs); } frappe.pages['background_jobs'].on_page_show = function(wrapper) { @@ -22,10 +25,10 @@ frappe.pages['background_jobs'].on_page_show = function(wrapper) { } frappe.pages.background_jobs.refresh_jobs = function() { - var page = frappe.pages.background_jobs.page; + let page = frappe.pages.background_jobs.page; // don't call if already waiting for a response - if(page.called) return; + if (page.called) return; page.called = true; frappe.call({ method: 'frappe.core.page.background_jobs.background_jobs.get_info', @@ -35,11 +38,20 @@ frappe.pages.background_jobs.refresh_jobs = function() { callback: function(r) { page.called = false; page.body.find('.list-jobs').remove(); - $(frappe.render_template('background_jobs', {jobs:r.message || []})).appendTo(page.content); + $(frappe.render_template('background_jobs', { jobs: r.message || [] })).appendTo(page.content); - if(frappe.get_route()[0]==='background_jobs') { + if (frappe.get_route()[0] === 'background_jobs') { frappe.background_jobs_timeout = setTimeout(frappe.pages.background_jobs.refresh_jobs, 2000); } } }); } + +const remove_failed_jobs = function() { + frappe.call({ + method: 'frappe.core.page.background_jobs.background_jobs.remove_failed_jobs', + callback: function (r) { + frappe.pages.background_jobs.refresh_jobs(); + } + }); +} diff --git a/frappe/core/page/background_jobs/background_jobs.py b/frappe/core/page/background_jobs/background_jobs.py index 4a94de4ace..2185149024 100644 --- a/frappe/core/page/background_jobs/background_jobs.py +++ b/frappe/core/page/background_jobs/background_jobs.py @@ -1,14 +1,13 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals -import frappe - from rq import Queue, Worker -from frappe.utils.background_jobs import get_redis_conn -from frappe.utils import format_datetime, cint, convert_utc_to_user_timezone -from frappe.utils.scheduler import is_scheduler_inactive + +import frappe from frappe import _ +from frappe.utils import cint, convert_utc_to_user_timezone, format_datetime +from frappe.utils.background_jobs import get_redis_conn +from frappe.utils.scheduler import is_scheduler_inactive colors = { 'queued': 'orange', @@ -17,6 +16,7 @@ colors = { 'finished': 'green' } + @frappe.whitelist() def get_info(show_failed=False): conn = get_redis_conn() @@ -25,11 +25,9 @@ def get_info(show_failed=False): jobs = [] def add_job(j, name): - if j.kwargs.get('site')==frappe.local.site: + if j.kwargs.get('site') == frappe.local.site: jobs.append({ - 'job_name': j.kwargs.get('kwargs', {}).get('playbook_method') \ - or j.kwargs.get('kwargs', {}).get('job_type') \ - or str(j.kwargs.get('job_name')), + 'job_name': j.kwargs.get('kwargs', {}).get('playbook_method') or j.kwargs.get('kwargs', {}).get('job_type') or str(j.kwargs.get('job_name')), 'status': j.get_status(), 'queue': name, 'creation': format_datetime(convert_utc_to_user_timezone(j.created_at)), 'color': colors[j.get_status()] @@ -44,15 +42,27 @@ def get_info(show_failed=False): for q in queues: if q.name != 'failed': - for j in q.get_jobs(): add_job(j, q.name) + for j in q.get_jobs(): + add_job(j, q.name) if cint(show_failed): for q in queues: if q.name == 'failed': - for j in q.get_jobs()[:10]: add_job(j, q.name) + for j in q.get_jobs()[:10]: + add_job(j, q.name) return jobs + +@frappe.whitelist() +def remove_failed_jobs(): + conn = get_redis_conn() + queues = Queue.all(conn) + for q in queues: + if q.name == 'failed': + q.empty() + + @frappe.whitelist() def get_scheduler_status(): if is_scheduler_inactive(): diff --git a/frappe/core/page/background_jobs/background_jobs_outer.html b/frappe/core/page/background_jobs/background_jobs_outer.html index 4da4498304..8c79806005 100644 --- a/frappe/core/page/background_jobs/background_jobs_outer.html +++ b/frappe/core/page/background_jobs/background_jobs_outer.html @@ -2,9 +2,12 @@

+
+ +

From 09886799e8badea0bb55d2024ab292a13e419632 Mon Sep 17 00:00:00 2001 From: Hendy Irawan Date: Mon, 5 Oct 2020 08:20:18 +0000 Subject: [PATCH 002/460] fix(form): Form UI wrong filename and URL Form UI gives wrong file name and URL of Attach field if filename contains "," --- frappe/public/js/frappe/form/controls/attach.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index fe662c1ada..ba058ccf8e 100644 --- a/frappe/public/js/frappe/form/controls/attach.js +++ b/frappe/public/js/frappe/form/controls/attach.js @@ -1,6 +1,6 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({ make_input: function() { - var me = this; + let me = this; this.$input = $('
- +

-
- -
+
\ No newline at end of file From 3177bcd0acd9a453d641489806c4e9ae945e38d1 Mon Sep 17 00:00:00 2001 From: walstanb Date: Tue, 5 Jan 2021 18:38:22 +0530 Subject: [PATCH 009/460] feat: ability to attach photo from webcam --- .../js/frappe/file_uploader/FileUploader.vue | 31 +++++ frappe/public/js/frappe/ui/capture.js | 125 +++++++----------- 2 files changed, 80 insertions(+), 76 deletions(-) diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 714fa49d2a..a6a1634fe4 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -55,6 +55,13 @@
{{ __('Link') }}
+
{{ upload_notes }} @@ -173,8 +180,12 @@ export default { currently_uploading: -1, show_file_browser: false, show_web_link: false, + allow_take_photo: false, } }, + created() { + this.allow_take_photo = window.navigator.mediaDevices; + }, watch: { files(newvalue, oldvalue) { if (!this.allow_multiple && newvalue.length > 1) { @@ -416,6 +427,26 @@ export default { xhr.send(form_data); }); + }, + urltoFile(url, filename, mimeType){ + return (fetch(url) + .then(function(res){return res.arrayBuffer();}) + .then(function(buf){return new File([buf], filename, {type:mimeType});}) + ); + }, + capture_image() { + const capture = new frappe.ui.Capture({ + animate: false, + error: true + }); + + capture.show(); + capture.submit(data_url => { + let filename = `capture_${frappe.datetime.now_date()}_${frappe.datetime.now_time().replaceAll(":", "-")}.png`; + this.urltoFile(data_url, filename, 'image/png').then((file) => { + return this.add_files([file]) + }); + }); } } } diff --git a/frappe/public/js/frappe/ui/capture.js b/frappe/public/js/frappe/ui/capture.js index f08257d394..ffe321202a 100644 --- a/frappe/public/js/frappe/ui/capture.js +++ b/frappe/public/js/frappe/ui/capture.js @@ -12,16 +12,16 @@ * // returns "data:image/pngbase64,..." */ frappe._.get_data_uri = element => { - const $element = $(element); - const width = $element.width(); - const height = $element.height(); + + const width = element.videoWidth; + const height = element.videoHeight; const $canvas = $(''); $canvas[0].width = width; $canvas[0].height = height; const context = $canvas[0].getContext('2d'); - context.drawImage($element[0], 0, 0, width, height); + context.drawImage(element, 0, 0, width, height); const data_uri = $canvas[0].toDataURL('image/png'); @@ -55,52 +55,56 @@ frappe.ui.Capture = class { render() { return navigator.mediaDevices.getUserMedia({ video: true }).then(stream => { + this.stream = stream; + this.dialog = new frappe.ui.Dialog({ title: this.options.title, animate: this.options.animate, - action: { - secondary: { - label: '×' - } - } }); + this.dialog.get_close_btn().on('click', () => { + this.hide(); + }); + + const set_take_photo_action = () => { + this.dialog.set_primary_action(__('Take Photo'), () => { + const data_url = frappe._.get_data_uri(video); + $e.find('.fc-p').attr('src', data_url); + + $e.find('.fc-s').hide(); + $e.find('.fc-p').show(); + + this.dialog.set_secondary_action_label(__('Retake')); + this.dialog.get_secondary_btn().show(); + + this.dialog.set_primary_action(__('Submit'), () => { + this.hide(); + if (this.callback) this.callback(data_url); + }); + }); + }; + + set_take_photo_action(); + + this.dialog.set_secondary_action(() => { + $e.find('.fc-p').hide(); + $e.find('.fc-s').show(); + + this.dialog.get_secondary_btn().hide(); + this.dialog.get_primary_btn().off('click'); + set_take_photo_action(); + }); + + this.dialog.get_secondary_btn().hide(); + const $e = $(frappe.ui.Capture.TEMPLATE); const video = $e.find('video')[0]; - video.srcObject = stream; + video.srcObject = this.stream; video.play(); - const $container = $(this.dialog.body); + $container.html($e); - - $e.find('.fc-btf').hide(); - - $e.find('.fc-bcp').click(() => { - const data_url = frappe._.get_data_uri(video); - $e.find('.fc-p').attr('src', data_url); - - $e.find('.fc-s').hide(); - $e.find('.fc-p').show(); - - $e.find('.fc-btu').hide(); - $e.find('.fc-btf').show(); - }); - - $e.find('.fc-br').click(() => { - $e.find('.fc-p').hide(); - $e.find('.fc-s').show(); - - $e.find('.fc-btf').hide(); - $e.find('.fc-btu').show(); - }); - - $e.find('.fc-bs').click(() => { - const data_url = frappe._.get_data_uri(video); - this.hide(); - - if (this.callback) this.callback(data_url); - }); }); } @@ -122,6 +126,9 @@ frappe.ui.Capture = class { } hide() { + if (this.stream) this.stream.getTracks().forEach((track) => { + track.stop(); + }); if (this.dialog) this.dialog.hide(); } @@ -138,43 +145,9 @@ frappe.ui.Capture.ERR_MESSAGE = __('Unable to load camera.'); frappe.ui.Capture.TEMPLATE = `
- -
- -
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
- ${''} -
-
-
- -
-
-
+
+ +
From 3a112f8a09665a68c7e54fcdce7dafee9ccaa65e Mon Sep 17 00:00:00 2001 From: pateljannat Date: Thu, 7 Jan 2021 11:13:09 +0530 Subject: [PATCH 010/460] fix: orm and message --- frappe/printing/doctype/letter_head/letter_head.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py index ac779d5688..0ea1d2f242 100644 --- a/frappe/printing/doctype/letter_head/letter_head.py +++ b/frappe/printing/doctype/letter_head/letter_head.py @@ -18,10 +18,10 @@ class LetterHead(Document): def validate_disabled_and_default(self): if self.disabled and self.is_default: - frappe.throw(_("Letter Head cannot be both, {0} and {1}").format(frappe.bold("Disabled"), frappe.bold("Default"))) + frappe.throw(_("Letter Head cannot be both disabled and default")) if not self.is_default and not self.disabled: - if not frappe.db.sql("""select count(*) from `tabLetter Head` where ifnull(is_default,0)=1""")[0][0]: + if not frappe.db.exists('Letter Head', dict(is_default=1)): self.is_default = 1 def set_image(self): From f4dcf5e05eae9ea72853f31495f756a13ac5ff01 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Mon, 21 Dec 2020 11:09:23 +0530 Subject: [PATCH 011/460] fix: letter head disabled and default validation issues --- frappe/printing/doctype/letter_head/letter_head.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py index 491d959755..ac779d5688 100644 --- a/frappe/printing/doctype/letter_head/letter_head.py +++ b/frappe/printing/doctype/letter_head/letter_head.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import is_image from frappe.model.document import Document +from frappe import _ class LetterHead(Document): def before_insert(self): @@ -13,8 +14,14 @@ class LetterHead(Document): def validate(self): self.set_image() - if not self.is_default: - if not frappe.db.sql("""select count(*) from `tabLetter Head` where ifnull(is_default,0)=1"""): + self.validate_disabled_and_default() + + def validate_disabled_and_default(self): + if self.disabled and self.is_default: + frappe.throw(_("Letter Head cannot be both, {0} and {1}").format(frappe.bold("Disabled"), frappe.bold("Default"))) + + if not self.is_default and not self.disabled: + if not frappe.db.sql("""select count(*) from `tabLetter Head` where ifnull(is_default,0)=1""")[0][0]: self.is_default = 1 def set_image(self): From 10f620572dbe922d44f21580a27d51172b08ae23 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Thu, 7 Jan 2021 11:13:09 +0530 Subject: [PATCH 012/460] fix: orm and message --- frappe/printing/doctype/letter_head/letter_head.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py index ac779d5688..0ea1d2f242 100644 --- a/frappe/printing/doctype/letter_head/letter_head.py +++ b/frappe/printing/doctype/letter_head/letter_head.py @@ -18,10 +18,10 @@ class LetterHead(Document): def validate_disabled_and_default(self): if self.disabled and self.is_default: - frappe.throw(_("Letter Head cannot be both, {0} and {1}").format(frappe.bold("Disabled"), frappe.bold("Default"))) + frappe.throw(_("Letter Head cannot be both disabled and default")) if not self.is_default and not self.disabled: - if not frappe.db.sql("""select count(*) from `tabLetter Head` where ifnull(is_default,0)=1""")[0][0]: + if not frappe.db.exists('Letter Head', dict(is_default=1)): self.is_default = 1 def set_image(self): From 8da071edc353576d4b1039e0a189ab58f28eb543 Mon Sep 17 00:00:00 2001 From: Anuja P Date: Wed, 20 Jan 2021 18:25:11 +0530 Subject: [PATCH 013/460] fix: Preventing item qty from resetting to default on Add Multiple --- frappe/public/js/frappe/form/link_selector.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/link_selector.js b/frappe/public/js/frappe/form/link_selector.js index c72e74cafc..9ee9cddcc1 100644 --- a/frappe/public/js/frappe/form/link_selector.js +++ b/frappe/public/js/frappe/form/link_selector.js @@ -152,9 +152,13 @@ frappe.ui.form.LinkSelector = Class.extend({ d = me.target.add_new_row(); }, () => frappe.timeout(0.1), - () => frappe.model.set_value(d.doctype, d.name, me.fieldname, value), - () => frappe.timeout(0.5), - () => frappe.model.set_value(d.doctype, d.name, me.qty_fieldname, data.qty), + () => { + var args = {}; + args[me.fieldname] = value; + args[me.qty_fieldname] = data.qty; + + frappe.model.set_value(d.doctype, d.name, args); + }, () => frappe.show_alert(__("Added {0} ({1})", [value, data.qty])) ]); } From 619a4adfd5c3b353cd1fd73bdd857d06a41592df Mon Sep 17 00:00:00 2001 From: "hasnain2808@gmail.com" Date: Thu, 21 Jan 2021 13:10:06 +0530 Subject: [PATCH 014/460] fix: add patch for List View Settings Rename --- frappe/patches.txt | 1 + ...list_view_setting_to_list_view_settings.py | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py diff --git a/frappe/patches.txt b/frappe/patches.txt index 1a086303ba..c49c70ba64 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -318,3 +318,4 @@ frappe.patches.v13_0.remove_custom_link execute:frappe.delete_doc("DocType", "Footer Item") frappe.patches.v13_0.replace_field_target_with_open_in_new_tab frappe.patches.v13_0.delete_package_publish_tool +frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings \ No newline at end of file diff --git a/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py new file mode 100644 index 0000000000..ee752ae085 --- /dev/null +++ b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py @@ -0,0 +1,21 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + + +def execute(): + if frappe.db.table_exists('List View Setting'): + existing_list_view_settings = frappe.get_all('List View Settings', as_list=True) + for list_view_setting in frappe.get_all('List View Setting', fields = ['disable_count', 'disable_sidebar_stats', 'disable_auto_refresh', 'name']): + name = list_view_setting.pop('name') + if name not in [x[0] for x in existing_list_view_settings]: + list_view_setting['doctype'] = 'List View Settings' + list_view_settings = frappe.get_doc(list_view_setting) + # setting name here is necessary because autoname is set as prompt + list_view_settings.name = name + list_view_settings.insert() + frappe.delete_doc("DocType", "List View Setting", force=True) + frappe.db.commit() + frappe.db.sql("DROP TABLE IF EXISTS `tabList View Setting`") From 0c8c76ed1b69f76d5f747de73c27cfea3b024e7f Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 22 Jan 2021 12:49:23 +0530 Subject: [PATCH 015/460] fix: Do not manually drop the table --- .../v13_0/rename_list_view_setting_to_list_view_settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py index ee752ae085..fcf8afc826 100644 --- a/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py +++ b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py @@ -18,4 +18,3 @@ def execute(): list_view_settings.insert() frappe.delete_doc("DocType", "List View Setting", force=True) frappe.db.commit() - frappe.db.sql("DROP TABLE IF EXISTS `tabList View Setting`") From 01aa5ff928e0324646a545d900f793180ffc1ff8 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Fri, 22 Jan 2021 18:04:02 +0530 Subject: [PATCH 016/460] feat: newsletter modifications --- .../email/doctype/newsletter/newsletter.json | 27 ++++++++++++++++++- frappe/email/doctype/newsletter/newsletter.py | 3 ++- frappe/email/email_body.py | 14 +++++++--- frappe/email/queue.py | 12 +++++++-- frappe/templates/emails/email_footer.html | 8 ++++++ frappe/templates/emails/standard.html | 2 +- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/frappe/email/doctype/newsletter/newsletter.json b/frappe/email/doctype/newsletter/newsletter.json index 1dd6115b43..c0383a7d75 100644 --- a/frappe/email/doctype/newsletter/newsletter.json +++ b/frappe/email/doctype/newsletter/newsletter.json @@ -19,9 +19,13 @@ "message", "message_md", "message_html", + "section_break_13", "send_unsubscribe_link", "send_attachments", + "full_width", + "column_break_9", "published", + "send_webview_link", "route", "test_the_newsletter", "test_email_id", @@ -160,6 +164,27 @@ "fieldtype": "Check", "label": "Schedule Sending", "read_only_depends_on": "eval: doc.email_sent" + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, + { + "default": "0", + "depends_on": "published", + "fieldname": "send_webview_link", + "fieldtype": "Check", + "label": "Send Web View Link" + }, + { + "default": "0", + "fieldname": "full_width", + "fieldtype": "Check", + "label": "Full Width" + }, + { + "fieldname": "section_break_13", + "fieldtype": "Section Break" } ], "has_web_view": 1, @@ -169,7 +194,7 @@ "is_published_field": "published", "links": [], "max_attachments": 3, - "modified": "2020-08-24 19:59:37.262500", + "modified": "2021-01-20 20:21:53.535828", "modified_by": "Administrator", "module": "Email", "name": "Newsletter", diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index 2791ebb75b..eee71d038c 100755 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -74,7 +74,8 @@ class Newsletter(WebsiteGenerator): add_unsubscribe_link=self.send_unsubscribe_link, attachments=attachments, unsubscribe_method="/unsubscribe", unsubscribe_params={"name": self.name}, - send_priority=0, queue_separately=True) + send_priority=0, queue_separately=True, add_web_link=self.send_webview_link, + is_newsletter=True, full_width=self.full_width) if not frappe.flags.in_test: frappe.db.auto_commit_on_many_writes = False diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 8ac071fa61..49b6133c91 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -249,7 +249,8 @@ class EMail: return self.msg_root.as_string(policy=policy.SMTPUTF8) def get_formatted_html(subject, message, footer=None, print_html=None, - email_account=None, header=None, unsubscribe_link=None, sender=None): + email_account=None, header=None, unsubscribe_link=None, sender=None, + web_link=None, is_newsletter=False, full_width=False): if not email_account: email_account = get_outgoing_email_account(False, sender=sender) @@ -257,10 +258,12 @@ def get_formatted_html(subject, message, footer=None, print_html=None, "header": get_header(header), "content": message, "signature": get_signature(email_account), - "footer": get_footer(email_account, footer), + "footer": get_footer(email_account, footer, web_link), "title": subject, "print_html": print_html, - "subject": subject + "subject": subject, + "is_newsletter": is_newsletter, + "full_width": full_width }) html = scrub_urls(rendered_email) @@ -357,7 +360,7 @@ def get_signature(email_account): else: return "" -def get_footer(email_account, footer=None): +def get_footer(email_account, footer=None, web_link=None): """append a footer (signature)""" footer = footer or "" @@ -370,6 +373,9 @@ def get_footer(email_account, footer=None): if company_address: args.update({'company_address': company_address}) + + if web_link: + args.update({'web_link': web_link}) if not cint(frappe.db.get_default("disable_standard_email_footer")): args.update({'default_mail_footer': frappe.get_hooks('default_mail_footer')}) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index f780aebdc1..71a9054e0b 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -24,7 +24,7 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content= attachments=None, reply_to=None, cc=None, bcc=None, message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, send_priority=1, communication=None, now=False, read_receipt=None, queue_separately=False, is_notification=False, add_unsubscribe_link=1, inline_images=None, - header=None, print_letterhead=False): + header=None, print_letterhead=False, is_newsletter=False, full_width=False, add_web_link=False): """Add email to sending queue (Email Queue) :param recipients: List of recipients. @@ -48,6 +48,9 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content= :param add_unsubscribe_link: Send unsubscribe link in the footer of the Email, default 1. :param inline_images: List of inline images as {"filename", "filecontent"}. All src properties will be replaced with random Content-Id :param header: Append header in email (boolean) + :param is_newsletter: Indicates if email is for newsletter + :param full_width: Will make newsletter email appear with full width on screen + :param add_web_link: Will add web view link to newsletter email """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" @@ -127,10 +130,15 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content= if should_append_unsubscribe: unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_text_context += unsubscribe_link.text + + web_link = None + if add_web_link and reference_doctype and reference_doctype == "Newsletter": + web_link = get_url(uri = "/newsletters/{0}".format(reference_name)) email_content = get_formatted_html(subject, message, email_account=email_account, header=header, - unsubscribe_link=unsubscribe_link) + unsubscribe_link=unsubscribe_link, web_link=web_link, + is_newsletter=is_newsletter, full_width=full_width) # add to queue add(recipients, sender, subject, diff --git a/frappe/templates/emails/email_footer.html b/frappe/templates/emails/email_footer.html index 4ad6cb23b5..4e12fbb92e 100644 --- a/frappe/templates/emails/email_footer.html +++ b/frappe/templates/emails/email_footer.html @@ -15,6 +15,14 @@
{% endif %} + {% if web_link %} + + {% endif %} +