From f84aee8abe858dd61210c21aa5b6d1642dba6ec1 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:16:59 +0200 Subject: [PATCH 1/6] fix: translate report column labels --- frappe/translate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/translate.py b/frappe/translate.py index 3565bbc32c..5989ff44aa 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -443,8 +443,12 @@ def get_messages_from_report(name): messages = _get_messages_from_page_or_report("Report", name, frappe.db.get_value("DocType", report.ref_doctype, "module")) + if report.columns: + messages.extend([(None, column.label) for column in report.columns]) + if report.query: messages.extend([(None, message) for message in re.findall('"([^:,^"]*):', report.query) if is_translatable(message)]) + messages.append((None,report.report_name)) return messages From bf4a73c3d4890a42016d49a34d455aad18307068 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:28:02 +0200 Subject: [PATCH 2/6] fix: translate report filter labels --- frappe/translate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/translate.py b/frappe/translate.py index 5989ff44aa..a4128794ac 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -444,7 +444,10 @@ def get_messages_from_report(name): frappe.db.get_value("DocType", report.ref_doctype, "module")) if report.columns: - messages.extend([(None, column.label) for column in report.columns]) + messages.extend([(None, report_column.label) for report_column in report.columns]) + + if report.filters: + messages.extend([(None, report_filter.label) for report_filter in report.filters]) if report.query: messages.extend([(None, message) for message in re.findall('"([^:,^"]*):', report.query) if is_translatable(message)]) From 7953896ab5b386b4b3cd580748a22da3ea952af2 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 26 Apr 2021 17:59:02 +0530 Subject: [PATCH 3/6] feat: Deletion Steps in Data Deletion Tool * Track deletion steps in PDDR * Option to commit via pddr._anonymize_data --- .../personal_data_deletion_request.json | 19 +++++- .../personal_data_deletion_request.py | 64 ++++++++++++++++-- .../personal_data_deletion_step/__init__.py | 0 .../personal_data_deletion_step.json | 66 +++++++++++++++++++ .../personal_data_deletion_step.py | 10 +++ 5 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 frappe/website/doctype/personal_data_deletion_step/__init__.py create mode 100644 frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.json create mode 100644 frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.py diff --git a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.json b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.json index e1439fd2dc..0cb11068f5 100644 --- a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.json +++ b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.json @@ -6,7 +6,9 @@ "engine": "InnoDB", "field_order": [ "email", - "status" + "status", + "anonymization_matrix", + "deletion_steps" ], "fields": [ { @@ -27,10 +29,23 @@ "label": "Status", "options": "Pending Verification\nPending Approval\nDeleted", "read_only": 1 + }, + { + "fieldname": "anonymization_matrix", + "fieldtype": "Code", + "label": "Anonymization Matrix", + "options": "JSON", + "read_only": 1 + }, + { + "fieldname": "deletion_steps", + "fieldtype": "Table", + "label": "Deletion Steps ", + "options": "Personal Data Deletion Step" } ], "links": [], - "modified": "2021-02-28 12:36:08.219719", + "modified": "2021-04-23 13:25:53.629308", "modified_by": "Administrator", "module": "Website", "name": "Personal Data Deletion Request", diff --git a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py index 23857a5e66..481012753a 100644 --- a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py +++ b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py @@ -10,6 +10,8 @@ from frappe.model.document import Document from frappe.utils import get_fullname from frappe.utils.user import get_system_managers from frappe.utils.verified_command import get_signed_params, verify_request +import json +from frappe.core.utils import find class PersonalDataDeletionRequest(Document): @@ -118,6 +120,24 @@ class PersonalDataDeletionRequest(Document): now=frappe.flags.in_test, ) + def add_deletion_steps(self): + if self.deletion_steps: + return + + for step in self.full_match_privacy_docs + self.partial_privacy_docs: + row_data = { + "status": "Pending", + "document_type": step.get("doctype"), + "partial": step.get("partial") or False, + "fields": json.dumps(step.get("redact_fields", [])), + "filtered_by": step.get("filtered_by") or "", + } + self.append("deletion_steps", row_data) + + self.anonymization_matrix = json.dumps(self.anonymization_value_map, indent=4) + self.save() + self.reload() + def redact_partial_match_data(self, doctype): self.__redact_partial_match_data(doctype) self.rename_documents(doctype) @@ -207,21 +227,57 @@ class PersonalDataDeletionRequest(Document): ref["doctype"], doc["name"], self.anon, force=True, show_alert=False ) - def _anonymize_data(self, email=None, anon=None, set_data=True): + def _anonymize_data(self, email=None, anon=None, set_data=True, commit=False): email = email or self.email anon = anon or self.name if set_data: self.__set_anonymization_data(email, anon) - for doctype in self.full_match_privacy_docs: - self.redact_full_match_data(doctype, email) + self.add_deletion_steps() - for doctype in self.partial_privacy_docs: + self.full_match_doctypes = ( + x + for x in self.full_match_privacy_docs + if filter( + lambda x: x.document_type == x and x.status == "Pending", self.deletion_steps + ) + ) + + self.partial_match_doctypes = ( + x + for x in self.partial_privacy_docs + if filter( + lambda x: x.document_type == x and x.status == "Pending", self.deletion_steps + ) + ) + + for doctype in self.full_match_doctypes: + self.redact_full_match_data(doctype, email) + self.set_step_status(doctype["doctype"]) + if commit: + frappe.db.commit() + + for doctype in self.partial_match_doctypes: self.redact_partial_match_data(doctype) + self.set_step_status(doctype["doctype"]) + if commit: + frappe.db.commit() frappe.rename_doc("User", email, anon, force=True, show_alert=False) self.db_set("status", "Deleted") + if commit: + frappe.db.commit() + + def set_step_status(self, step, status="Deleted"): + del_step = find(self.deletion_steps, lambda x: x.document_type == step and x.status != status) + + if not del_step: + del_step = find(self.deletion_steps, lambda x: x.document_type == step) + + del_step.status = status + self.save() + self.reload() def __set_anonymization_data(self, email, anon): self.anon = anon or self.name diff --git a/frappe/website/doctype/personal_data_deletion_step/__init__.py b/frappe/website/doctype/personal_data_deletion_step/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.json b/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.json new file mode 100644 index 0000000000..5d38ea6222 --- /dev/null +++ b/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.json @@ -0,0 +1,66 @@ +{ + "actions": [], + "creation": "2021-04-23 13:25:26.162797", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "document_type", + "status", + "partial", + "fields", + "filtered_by" + ], + "fields": [ + { + "allow_in_quick_entry": 1, + "fieldname": "document_type", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Document Type", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_preview": 1, + "label": "Status", + "options": "Pending\nDeleted", + "read_only": 1 + }, + { + "default": "0", + "fieldname": "partial", + "fieldtype": "Check", + "in_preview": 1, + "label": "Partial", + "read_only": 1 + }, + { + "fieldname": "fields", + "fieldtype": "Small Text", + "label": "Fields", + "read_only": 1 + }, + { + "fieldname": "filtered_by", + "fieldtype": "Data", + "label": "Filtered By", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-04-23 13:48:59.658681", + "modified_by": "Administrator", + "module": "Website", + "name": "Personal Data Deletion Step", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.py b/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.py new file mode 100644 index 0000000000..2a7451473d --- /dev/null +++ b/frappe/website/doctype/personal_data_deletion_step/personal_data_deletion_step.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class PersonalDataDeletionStep(Document): + pass From c6356b12c01aa767532f5577b73a91db23bbc737 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 3 May 2021 11:42:05 +0530 Subject: [PATCH 4/6] fix(PDDR): Translation String --- .../personal_data_deletion_request.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py index 481012753a..6fbdcc839b 100644 --- a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py +++ b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py @@ -346,9 +346,8 @@ def confirm_deletion(email, name, host_name): frappe.db.commit() frappe.respond_as_web_page( _("Confirmed"), - _( - "The process for deletion of {0} data associated with {1} has been initiated." - ).format(host_name, email), + _("The process for deletion of {0} data associated with {1} has been initiated.") + .format(host_name, email), indicator_color="green", ) From 021aea5b4f76168d61014dc7b88f176450941a61 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 3 May 2021 12:50:06 +0530 Subject: [PATCH 5/6] fix: Typo in RecorderDetail.vue --- frappe/public/js/frappe/recorder/RecorderDetail.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/recorder/RecorderDetail.vue b/frappe/public/js/frappe/recorder/RecorderDetail.vue index 5d934d7e1e..d17a8f0ec4 100644 --- a/frappe/public/js/frappe/recorder/RecorderDetail.vue +++ b/frappe/public/js/frappe/recorder/RecorderDetail.vue @@ -155,7 +155,7 @@ export default { number: 1, status: (current_page == 1) ? "disabled" : "", },{ - label: __("Previous)", + label: __("Previous"), number: Math.max(current_page - 1, 1), status: (current_page == 1) ? "disabled" : "", }, { From 86ce27e413f82c3acc2f4253c00d7fa6c63e5283 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 3 May 2021 13:21:05 +0530 Subject: [PATCH 6/6] fix: Add __ function in vue global for translation in recorder --- frappe/public/js/frappe/recorder/recorder.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/public/js/frappe/recorder/recorder.js b/frappe/public/js/frappe/recorder/recorder.js index c80fad62f6..eed57ddd4f 100644 --- a/frappe/public/js/frappe/recorder/recorder.js +++ b/frappe/public/js/frappe/recorder/recorder.js @@ -6,6 +6,9 @@ import RecorderRoot from "./RecorderRoot.vue"; import RecorderDetail from "./RecorderDetail.vue"; import RequestDetail from "./RequestDetail.vue"; +Vue.prototype.__ = window.__; +Vue.prototype.frappe = window.frappe; + Vue.use(VueRouter); const routes = [ {