diff --git a/.eslintrc b/.eslintrc index a80d2910fa..cc7f555669 100644 --- a/.eslintrc +++ b/.eslintrc @@ -149,6 +149,7 @@ "before": true, "beforeEach": true, "qz": true, - "localforage": true + "localforage": true, + "extend_cscript": true } } diff --git a/frappe/core/doctype/data_import/data_import.py b/frappe/core/doctype/data_import/data_import.py index 1c56f54303..7e8374a0a2 100644 --- a/frappe/core/doctype/data_import/data_import.py +++ b/frappe/core/doctype/data_import/data_import.py @@ -211,7 +211,12 @@ def export_json( doctype, path, filters=None, or_filters=None, name=None, order_by="creation asc" ): def post_process(out): - del_keys = ("modified_by", "creation", "owner", "idx") + # Note on Tree DocTypes: + # The tree structure is maintained in the database via the fields "lft" + # and "rgt". They are automatically set and kept up-to-date. Importing + # them would destroy any existing tree structure. For this reason they + # are not exported as well. + del_keys = ("modified_by", "creation", "owner", "idx", "lft", "rgt") for doc in out: for key in del_keys: if key in doc: diff --git a/frappe/email/doctype/email_account/test_records.json b/frappe/email/doctype/email_account/test_records.json index fbe7d9c281..15ca2a886e 100644 --- a/frappe/email/doctype/email_account/test_records.json +++ b/frappe/email/doctype/email_account/test_records.json @@ -19,7 +19,8 @@ "unreplied_for_mins": 20, "send_notification_to": "test_unreplied@example.com", "pop3_server": "pop.test.example.com", - "no_remaining":"0" + "no_remaining":"0", + "track_email_status": 1 }, { "doctype": "ToDo", diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index 076dfc5417..9e2fe32250 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -102,7 +102,7 @@ class EmailQueue(Document): message = ctx.build_message(recipient.recipient) if not frappe.flags.in_test: - ctx.smtp_session.sendmail(recipient.recipient, self.sender, message) + ctx.smtp_session.sendmail(from_addr=self.sender, to_addrs=recipient.recipient, msg=message) ctx.add_to_sent_list(recipient) if frappe.flags.in_test: @@ -218,7 +218,7 @@ class SendMailContext: '' message = '' - if frappe.conf.use_ssl and self.queue_doc.track_email_status: + if frappe.conf.use_ssl and self.email_account_doc.track_email_status: message = quopri.encodestring( tracker_url_html.format(frappe.local.site, self.queue_doc.communication).encode() ).decode() diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json index 1e0ae161bc..7ffdf0a8bf 100644 --- a/frappe/geo/country_info.json +++ b/frappe/geo/country_info.json @@ -953,7 +953,7 @@ "currency_fraction_units": 100, "smallest_currency_fraction_value": 0.01, "currency_symbol": "\u20ac", - "number_format": "#,###.##", + "number_format": "#.###,##", "timezones": [ "Europe/Berlin" ] diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py index 5970eae5ca..fdfd00404c 100644 --- a/frappe/modules/import_file.py +++ b/frappe/modules/import_file.py @@ -107,6 +107,15 @@ def import_doc(docdict, force=False, data_import=False, pre_process=None, doc = frappe.get_doc(docdict) + # Note on Tree DocTypes: + # The tree structure is maintained in the database via the fields "lft" and + # "rgt". They are automatically set and kept up-to-date. Importing them + # would destroy any existing tree structure. + if getattr(doc.meta, 'is_tree', None) and any([doc.lft, doc.rgt]): + print('Ignoring values of `lft` and `rgt` for {} "{}"'.format(doc.doctype, doc.name)) + doc.lft = None + doc.rgt = None + doc.run_method("before_import") doc.flags.ignore_version = ignore_version diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js index 420cda5a82..f960f4f767 100644 --- a/frappe/public/js/frappe/form/script_manager.js +++ b/frappe/public/js/frappe/form/script_manager.js @@ -3,6 +3,14 @@ frappe.provide("frappe.ui.form.handlers"); +window.extend_cscript = (cscript, controller_object) => { + $.extend(cscript, controller_object); + if (cscript && controller_object) { + cscript.__proto__ = controller_object.__proto__; + } + return cscript; +}; + frappe.ui.form.get_event_handler_list = function(doctype, fieldname) { if(!frappe.ui.form.handlers[doctype]) { frappe.ui.form.handlers[doctype] = {}; @@ -74,7 +82,7 @@ frappe.ui.form.ScriptManager = class ScriptManager { $.extend(this, opts); } make(ControllerClass) { - this.frm.cscript = $.extend(this.frm.cscript, + this.frm.cscript = extend_cscript(this.frm.cscript, new ControllerClass({frm: this.frm})); } trigger(event_name, doctype, name) { diff --git a/frappe/tests/test_email.py b/frappe/tests/test_email.py index af90ee7a6b..8340db4852 100644 --- a/frappe/tests/test_email.py +++ b/frappe/tests/test_email.py @@ -71,6 +71,7 @@ class TestEmail(unittest.TestCase): self.assertTrue('CC: test1@example.com' in message) def test_cc_footer(self): + frappe.conf.use_ssl = True # test if sending with cc's makes it into header frappe.sendmail(recipients=['test@example.com'], cc=['test1@example.com'], @@ -88,7 +89,12 @@ class TestEmail(unittest.TestCase): self.assertTrue('This email was sent to test@example.com and copied to test1@example.com' in frappe.safe_decode( frappe.flags.sent_mail)) + # check for email tracker + self.assertTrue('mark_email_as_seen' in frappe.safe_decode(frappe.flags.sent_mail)) + frappe.conf.use_ssl = False + def test_expose(self): + from frappe.utils.verified_command import verify_request frappe.sendmail(recipients=['test@example.com'], cc=['test1@example.com'], diff --git a/frappe/translate.py b/frappe/translate.py index 1d8b1234c7..b9dd5e263a 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -650,7 +650,7 @@ def write_csv_file(path, app_messages, lang_dict): t = lang_dict.get(message, '') # strip whitespaces - translated_string = re.sub('{\s?([0-9]+)\s?}', "{\g<1>}", t) + translated_string = re.sub(r'{\s?([0-9]+)\s?}', r"{\g<1>}", t) if translated_string: w.writerow([message, translated_string, context]) diff --git a/frappe/utils/jinja_globals.py b/frappe/utils/jinja_globals.py index 625d2e6cd5..347d52dc57 100644 --- a/frappe/utils/jinja_globals.py +++ b/frappe/utils/jinja_globals.py @@ -81,9 +81,10 @@ def include_style(path): def bundled_asset(path): from frappe.utils import get_assets_json + from frappe.website.utils import abs_url - if path.startswith("/assets") or ".bundle." not in path: - return path + if ".bundle." in path and not path.startswith("/assets"): + bundled_assets = get_assets_json() + path = bundled_assets.get(path) or path - bundled_assets = get_assets_json() - return bundled_assets.get(path) or path + return abs_url(path) diff --git a/node_utils.js b/node_utils.js index b87c99a07c..ac2f96f655 100644 --- a/node_utils.js +++ b/node_utils.js @@ -6,7 +6,7 @@ const bench_path = path.resolve(__dirname, '..', '..'); function get_conf() { // defaults var conf = { - redis_async_broker_port: 12311, + redis_async_broker_port: 'redis://localhost:12311', socketio_port: 3000 };