From 10a5900ed3d792653623d97da4a3128737f03f63 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 27 Jul 2020 19:47:46 +0530 Subject: [PATCH 1/6] fix: Attach files to the document if they are set programmatically --- frappe/core/doctype/file/file.py | 37 ++++++++++++++++++++++++++++++++ frappe/hooks.py | 3 ++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 1748c60020..316915e43a 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -922,3 +922,40 @@ def update_existing_file_docs(doc): content_hash=doc.content_hash, file_name=doc.name )) + +def attach_files_to_document(doc, event): + """ Runs on on_update hook of all documents. + Goes through every Attach and Attach Image field and attaches + the file url to the document if it is not already attached. + """ + + attach_fields = doc.meta.get( + "fields", {"fieldtype": ["in", ["Attach", "Attach Image"]]} + ) + + for df in attach_fields: + # this method runs in on_update hook of all documents + # we dont want the update to fail if file cannot be attached for some reason + try: + value = doc.get(df.fieldname) + if not value.startswith(("/files", "/private/files")): + return + + if frappe.db.exists("File", { + "file_url": value, + "attached_to_name": doc.name, + "attached_to_doctype": doc.doctype, + "attached_to_field": df.fieldname, + }): + return + + frappe.get_doc( + doctype="File", + file_url=value, + attached_to_name=doc.name, + attached_to_doctype=doc.doctype, + attached_to_field=df.fieldname, + folder="Home/Attachments", + ).insert() + except Exception: + frappe.log_error(title=_("Error Attaching File")) diff --git a/frappe/hooks.py b/frappe/hooks.py index 1f209f00a2..0a3d5d011c 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -132,7 +132,8 @@ doc_events = { "frappe.core.doctype.activity_log.feed.update_feed", "frappe.workflow.doctype.workflow_action.workflow_action.process_workflow_actions", "frappe.automation.doctype.assignment_rule.assignment_rule.apply", - "frappe.automation.doctype.milestone_tracker.milestone_tracker.evaluate_milestone" + "frappe.automation.doctype.milestone_tracker.milestone_tracker.evaluate_milestone", + "frappe.core.doctype.file.file.attach_files_to_document" ], "after_rename": "frappe.desk.notifications.clear_doctype_notifications", "on_cancel": [ From 46ac0735b3e4c0c71f4bcd9dd4a591f16777e525 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Sun, 9 Aug 2020 03:12:25 +0000 Subject: [PATCH 2/6] fix(Data Import): Allow parent with differing child table lengths Prior to this commit, if a parent has multiple child tables and the child tables have different numbers of rows, then the data import will fail with an error when it detects missing mandatory fields in the (necessary) empty records in the shorter child table. This commit fixes the problem by ignoring child rows that have only INVALID_VALUES for fields relating to that child (e.g., that are altogether empty in the fields for that child). Fixes #11222. --- frappe/core/doctype/data_import/importer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index 485f7caf08..161ab5d9a0 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -465,6 +465,7 @@ class ImportFile: if doctype != self.doctype and table_df: child_doc = row.parse_doc(doctype, parent_doc, table_df) + if child_doc is None: continue parent_doc[table_df.fieldname] = parent_doc.get(table_df.fieldname, []) parent_doc[table_df.fieldname].append(child_doc) @@ -589,17 +590,22 @@ class Row: for key in frappe.model.default_fields + ("__islocal",): doc.pop(key, None) + record_is_empty = True for col, value in zip(columns, values): df = col.df if value in INVALID_VALUES: value = None if value is not None: + record_is_empty = False value = self.validate_value(value, col) if value is not None: doc[df.fieldname] = self.parse_value(value, col) + if record_is_empty: + return None + is_table = frappe.get_meta(doctype).istable is_update = self.import_type == UPDATE if is_table and is_update: From 56521d51b5200089028c79f2cfed37369a0856ac Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 19 Aug 2020 14:36:39 +0530 Subject: [PATCH 3/6] fix: return early in parse_doc if invalid values --- frappe/core/doctype/data_import/importer.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index 161ab5d9a0..2c10c6b0a5 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -465,7 +465,8 @@ class ImportFile: if doctype != self.doctype and table_df: child_doc = row.parse_doc(doctype, parent_doc, table_df) - if child_doc is None: continue + if child_doc is None: + continue parent_doc[table_df.fieldname] = parent_doc.get(table_df.fieldname, []) parent_doc[table_df.fieldname].append(child_doc) @@ -571,6 +572,11 @@ class Row: def parse_doc(self, doctype, parent_doc=None, table_df=None): col_indexes = self.header.get_column_indexes(doctype, table_df) values = self.get_values(col_indexes) + + if all(v in INVALID_VALUES for v in values): + # if all values are invalid, no need to parse it + return None + columns = self.header.get_columns(col_indexes) doc = self._parse_doc(doctype, columns, values, parent_doc, table_df) return doc @@ -590,22 +596,17 @@ class Row: for key in frappe.model.default_fields + ("__islocal",): doc.pop(key, None) - record_is_empty = True for col, value in zip(columns, values): df = col.df if value in INVALID_VALUES: value = None if value is not None: - record_is_empty = False value = self.validate_value(value, col) if value is not None: doc[df.fieldname] = self.parse_value(value, col) - if record_is_empty: - return None - is_table = frappe.get_meta(doctype).istable is_update = self.import_type == UPDATE if is_table and is_update: From eb87e6b77358c8bddd860cea90592d08891871bb Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 21 Aug 2020 13:30:20 +0530 Subject: [PATCH 4/6] fix: Set fieldname when attaching to field --- frappe/public/js/frappe/file_uploader/FileUploader.vue | 7 +++++++ frappe/public/js/frappe/file_uploader/index.js | 2 ++ frappe/public/js/frappe/form/controls/attach.js | 1 + 3 files changed, 10 insertions(+) diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 845fbf92b4..f8d9253931 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -144,6 +144,9 @@ export default { docname: { default: null }, + fieldname: { + default: null + }, folder: { default: 'Home' }, @@ -406,6 +409,10 @@ export default { form_data.append('docname', this.docname); } + if (this.fieldname) { + form_data.append('fieldname', this.fieldname); + } + if (this.method) { form_data.append('method', this.method); } diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js index f81a1f1776..62a7bff822 100644 --- a/frappe/public/js/frappe/file_uploader/index.js +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -7,6 +7,7 @@ export default class FileUploader { on_success, doctype, docname, + fieldname, files, folder, restrictions, @@ -28,6 +29,7 @@ export default class FileUploader { show_upload_button: !Boolean(this.dialog), doctype, docname, + fieldname, method, folder, on_success, diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index 15cbd3b043..fe662c1ada 100644 --- a/frappe/public/js/frappe/form/controls/attach.js +++ b/frappe/public/js/frappe/form/controls/attach.js @@ -66,6 +66,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({ if (this.frm) { options.doctype = this.frm.doctype; options.docname = this.frm.docname; + options.fieldname = this.df.fieldname; } if (this.df.options) { From 85cac9122e9e2d9a478d455e3049ef47f38d9a9e Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 21 Aug 2020 13:31:07 +0530 Subject: [PATCH 5/6] test: For file attachment on update --- frappe/core/doctype/file/test_file.py | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py index ec4f97bf67..85397ea1ee 100644 --- a/frappe/core/doctype/file/test_file.py +++ b/frappe/core/doctype/file/test_file.py @@ -328,3 +328,49 @@ class TestFile(unittest.TestCase): self.assertTrue(os.path.exists(file2.get_full_path())) +class TestAttachment(unittest.TestCase): + test_doctype = 'Test For Attachment' + + def setUp(self): + if frappe.db.exists('DocType', self.test_doctype): + return + + frappe.get_doc( + doctype='DocType', + name=self.test_doctype, + module='Custom', + custom=1, + fields=[ + {'label': 'Title', 'fieldname': 'title', 'fieldtype': 'Data'}, + {'label': 'Attachment', 'fieldname': 'attachment', 'fieldtype': 'Attach'}, + ] + ).insert() + + def tearDown(self): + frappe.delete_doc('DocType', self.test_doctype) + + def test_file_attachment_on_update(self): + doc = frappe.get_doc( + doctype=self.test_doctype, + title='test for attachment on update' + ).insert() + + file = frappe.get_doc({ + 'doctype': 'File', + 'file_name': 'test_attach.txt', + 'content': 'Test Content' + }) + file.save() + + doc.attachment = file.file_url + doc.save() + + exists = frappe.db.exists('File', { + 'file_name': 'test_attach.txt', + 'file_url': file.file_url, + 'attached_to_doctype': self.test_doctype, + 'attached_to_name': doc.name, + 'attached_to_field': 'attachment' + }) + + self.assertTrue(exists) From df7a57529541bf02d12c93fa90c7c9f1d1862a45 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 24 Aug 2020 11:55:28 +0530 Subject: [PATCH 6/6] fix: Sanitize 2FA response (#11263) Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/twofactor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/frappe/twofactor.py b/frappe/twofactor.py index 253636764f..dfa3f394e5 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -187,9 +187,7 @@ def process_2fa_for_otp_app(user, otp_secret, otp_issuer): otp_setup_completed = False verification_obj = { - 'totp_uri': totp_uri, 'method': 'OTP App', - 'qrcode': get_qr_svg_code(totp_uri), 'setup': otp_setup_completed } return verification_obj