From 4c6c8c8b80f0e82fc3b68a5dd2e0fe89eba94c3e Mon Sep 17 00:00:00 2001 From: scdanieli <23150094+scdanieli@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:06:14 +0100 Subject: [PATCH 1/6] feat: restrict permissions for Tags by Organizations (LAN-790) --- landa/hooks.py | 13 ++- landa/organization_management/custom/tag.json | 93 +++++++++++++++++++ .../doctype/tag_organization/__init__.py | 0 .../tag_organization/tag_organization.json | 31 +++++++ .../tag_organization/tag_organization.py | 9 ++ landa/organization_management/tag/tag.py | 63 +++++++++++++ 6 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 landa/organization_management/custom/tag.json create mode 100644 landa/organization_management/doctype/tag_organization/__init__.py create mode 100644 landa/organization_management/doctype/tag_organization/tag_organization.json create mode 100644 landa/organization_management/doctype/tag_organization/tag_organization.py create mode 100644 landa/organization_management/tag/tag.py diff --git a/landa/hooks.py b/landa/hooks.py index 65b868d1..46fe0454 100644 --- a/landa/hooks.py +++ b/landa/hooks.py @@ -229,13 +229,12 @@ permission_query_conditions = { "Report": "landa.permissions.report_query", + "Tag": "landa.organization_management.tag.tag.get_permission_query_conditions", } -# has_permission = { -# "Contact": "landa.address_and_contact.has_permission", -# "Address": "landa.address_and_contact.has_permission" -# "Event": "frappe.desk.doctype.event.event.has_permission", -# } +has_permission = { + "Tag": "landa.organization_management.tag.tag.has_permission", +} # DocType Class # --------------- @@ -308,6 +307,9 @@ "Water Body Management Local Organization": { "after_insert": "landa.water_body_management.utils.create_version_log", }, + "Tag": { + "before_insert": "landa.organization_management.tag.tag.before_insert", + }, } # Scheduled Tasks @@ -354,6 +356,7 @@ "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice": "landa.landa_stock.delivery_note.delivery_note.make_landa_sales_invoice", "frappe.desk.like.toggle_like": "landa.utils.no_liked_by", "frappe.contacts.doctype.address.address.get_address_display": "landa.organization_management.address.address.get_address_display", + "frappe.desk.doctype.tag.tag.add_tag": "landa.organization_management.tag.tag.add_tag", } # diff --git a/landa/organization_management/custom/tag.json b/landa/organization_management/custom/tag.json new file mode 100644 index 00000000..f3404b24 --- /dev/null +++ b/landa/organization_management/custom/tag.json @@ -0,0 +1,93 @@ +{ + "custom_fields": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2024-01-02 16:44:06.931009", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Tag", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "organizations", + "fieldtype": "Table", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "description", + "label": "Organizations", + "length": 0, + "mandatory_depends_on": null, + "modified": "2024-01-02 16:44:06.931009", + "modified_by": "Administrator", + "name": "Tag-organizations", + "no_copy": 0, + "non_negative": 0, + "options": "Tag Organization", + "owner": "Administrator", + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 0, + "unique": 0, + "width": null + } + ], + "custom_perms": [], + "doctype": "Tag", + "property_setters": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2024-01-02 16:43:05.963829", + "default_value": null, + "doc_type": "Tag", + "docstatus": 0, + "doctype_or_field": "DocType", + "field_name": null, + "idx": 0, + "modified": "2024-01-02 16:43:05.963829", + "modified_by": "Administrator", + "name": "Tag-main-title_field", + "owner": "Administrator", + "parent": null, + "parentfield": null, + "parenttype": null, + "property": "title_field", + "property_type": "Data", + "row_name": null, + "value": "" + } + ], + "sync_on_migrate": 1 +} \ No newline at end of file diff --git a/landa/organization_management/doctype/tag_organization/__init__.py b/landa/organization_management/doctype/tag_organization/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/landa/organization_management/doctype/tag_organization/tag_organization.json b/landa/organization_management/doctype/tag_organization/tag_organization.json new file mode 100644 index 00000000..3ec9101f --- /dev/null +++ b/landa/organization_management/doctype/tag_organization/tag_organization.json @@ -0,0 +1,31 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2024-01-02 14:54:10.801210", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "organization" + ], + "fields": [ + { + "fieldname": "organization", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Organization", + "options": "Organization", + "reqd": 1 + } + ], + "istable": 1, + "links": [], + "modified": "2024-01-02 14:54:10.801210", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Tag Organization", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/landa/organization_management/doctype/tag_organization/tag_organization.py b/landa/organization_management/doctype/tag_organization/tag_organization.py new file mode 100644 index 00000000..7d3e06aa --- /dev/null +++ b/landa/organization_management/doctype/tag_organization/tag_organization.py @@ -0,0 +1,9 @@ +# Copyright (c) 2024, ALYF GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class TagOrganization(Document): + pass diff --git a/landa/organization_management/tag/tag.py b/landa/organization_management/tag/tag.py new file mode 100644 index 00000000..991cdf25 --- /dev/null +++ b/landa/organization_management/tag/tag.py @@ -0,0 +1,63 @@ +# Copyright (c) 2024, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe + +from landa.utils import get_current_member_data + + +def has_permission(doc, user): + if not user: + user = frappe.session.user + + if "System Manager" in frappe.get_roles(user): + return True + + allowed_organizations = frappe.get_all( + "User Permission", filters={"user": user, "allow": "Organization"}, pluck="for_value" + ) + + if any(org.organization in allowed_organizations for org in doc.get("organizations")): + return True + + return False + + +def get_permission_query_conditions(user): + if not user: + user = frappe.session.user + + if "System Manager" in frappe.get_roles(user): + return None + + return """exists ( + select 1 from `tabTag Organization` + where + `tabTag Organization`.parent = `tabTag`.name and + `tabTag Organization`.organization in ( + select for_value + from `tabUser Permission` + where `allow` = 'Organization' + and `user` = {user} + ) + )""".format( + user=frappe.db.escape(user) + ) + + +def before_insert(doc, method): + doc.append("organizations", {"organization": get_current_member_data().get("organization")}) + + +@frappe.whitelist() +def add_tag(tag, dt, dn, color=None): + organization = get_current_member_data().get("organization") + + if organization and frappe.db.exists("Tag", tag): + tag_doc = frappe.get_doc("Tag", tag) + + if organization not in [org.organization for org in tag_doc.organizations]: + tag_doc.append("organizations", {"organization": organization}) + tag_doc.save(ignore_permissions=True) + + return frappe.desk.doctype.tag.tag.add_tag(tag, dt, dn, color) From d869e5154d48a095a4b42ed8d40755198328e33b Mon Sep 17 00:00:00 2001 From: scdanieli <23150094+scdanieli@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:28:03 +0100 Subject: [PATCH 2/6] feat: update Tag permissions (LAN-790) LANDA State Organization Employee should see all Tags and should also be able to delete Tags --- landa/organization_management/custom/tag.json | 105 +++++++++++++++++- landa/organization_management/tag/tag.py | 8 +- 2 files changed, 110 insertions(+), 3 deletions(-) diff --git a/landa/organization_management/custom/tag.json b/landa/organization_management/custom/tag.json index f3404b24..fbc2d165 100644 --- a/landa/organization_management/custom/tag.json +++ b/landa/organization_management/custom/tag.json @@ -61,7 +61,110 @@ "width": null } ], - "custom_perms": [], + "custom_perms": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "amend": 0, + "cancel": 0, + "create": 1, + "creation": "2016-05-25 09:43:44.767581", + "delete": 1, + "docstatus": 0, + "email": 1, + "export": 1, + "idx": 1, + "if_owner": 0, + "import": 0, + "modified": "2024-01-03 23:21:12.987064", + "modified_by": "Administrator", + "name": "503e791796", + "owner": "Administrator", + "parent": "Tag", + "parentfield": "permissions", + "parenttype": "DocType", + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "select": 0, + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "amend": 0, + "cancel": 0, + "create": 1, + "creation": "2016-05-25 09:43:44.767581", + "delete": 0, + "docstatus": 0, + "email": 1, + "export": 1, + "idx": 2, + "if_owner": 0, + "import": 0, + "modified": "2024-01-03 23:21:13.162344", + "modified_by": "Administrator", + "name": "dde00b6d17", + "owner": "Administrator", + "parent": "Tag", + "parentfield": "permissions", + "parenttype": "DocType", + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "All", + "select": 0, + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "amend": 0, + "cancel": 0, + "create": 1, + "creation": "2024-01-03 23:21:13.186968", + "delete": 1, + "docstatus": 0, + "email": 0, + "export": 0, + "idx": 0, + "if_owner": 0, + "import": 0, + "modified": "2024-01-03 23:21:13.186968", + "modified_by": "Administrator", + "name": "b7de9df6bd", + "owner": "Administrator", + "parent": "Tag", + "parentfield": "permissions", + "parenttype": "DocType", + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "LANDA State Organization Employee", + "select": 0, + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 1 + } + ], "doctype": "Tag", "property_setters": [ { diff --git a/landa/organization_management/tag/tag.py b/landa/organization_management/tag/tag.py index 991cdf25..93c5b3a8 100644 --- a/landa/organization_management/tag/tag.py +++ b/landa/organization_management/tag/tag.py @@ -10,7 +10,9 @@ def has_permission(doc, user): if not user: user = frappe.session.user - if "System Manager" in frappe.get_roles(user): + user_roles = frappe.get_roles(user) + + if "System Manager" in user_roles or "LANDA State Organization Employee" in user_roles: return True allowed_organizations = frappe.get_all( @@ -27,7 +29,9 @@ def get_permission_query_conditions(user): if not user: user = frappe.session.user - if "System Manager" in frappe.get_roles(user): + user_roles = frappe.get_roles(user) + + if "System Manager" in user_roles or "LANDA State Organization Employee" in user_roles: return None return """exists ( From cc8bbc13f5a73f376d6724a02aa93b3945dcb319 Mon Sep 17 00:00:00 2001 From: scdanieli <23150094+scdanieli@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:50:26 +0100 Subject: [PATCH 3/6] feat: patch existing Tags (LAN-790) --- landa/patches.txt | 1 + landa/patches/add_organization_to_tags.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 landa/patches/add_organization_to_tags.py diff --git a/landa/patches.txt b/landa/patches.txt index dc3a3b42..59dff9ff 100644 --- a/landa/patches.txt +++ b/landa/patches.txt @@ -31,3 +31,4 @@ landa.patches.add_water_body_title_in_stocking landa.patches.multi_to_polygon landa.patches.add_award_types landa.patches.multi_to_line +landa.patches.add_organization_to_tags diff --git a/landa/patches/add_organization_to_tags.py b/landa/patches/add_organization_to_tags.py new file mode 100644 index 00000000..524148cb --- /dev/null +++ b/landa/patches/add_organization_to_tags.py @@ -0,0 +1,17 @@ +import frappe + +from landa.utils import get_member_and_organization + + +def execute(): + tags = frappe.get_all("Tag", fields=["name", "owner"]) + + for tag in tags: + owner_organization = get_member_and_organization(tag["owner"])[1] + + if owner_organization: + tag_doc = frappe.get_doc("Tag", tag["name"]) + + if not any(org.organization == owner_organization for org in tag_doc.get("organizations")): + tag_doc.append("organizations", {"organization": owner_organization}) + tag_doc.save(ignore_permissions=True) From eaf1f1c0c70b680fb5649cc04490cc09f1dff857 Mon Sep 17 00:00:00 2001 From: scdanieli <23150094+scdanieli@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:10:24 +0100 Subject: [PATCH 4/6] refactor: apply review suggestions (LAN-790) --- landa/organization_management/tag/tag.py | 33 ++++++++++-------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/landa/organization_management/tag/tag.py b/landa/organization_management/tag/tag.py index 93c5b3a8..6848112a 100644 --- a/landa/organization_management/tag/tag.py +++ b/landa/organization_management/tag/tag.py @@ -2,6 +2,8 @@ # For license information, please see license.txt import frappe +from frappe.core.doctype.user_permission.user_permission import get_permitted_documents +from frappe.desk.doctype.tag.tag import add_tag as frappe_add_tag from landa.utils import get_current_member_data @@ -15,11 +17,9 @@ def has_permission(doc, user): if "System Manager" in user_roles or "LANDA State Organization Employee" in user_roles: return True - allowed_organizations = frappe.get_all( - "User Permission", filters={"user": user, "allow": "Organization"}, pluck="for_value" - ) - - if any(org.organization in allowed_organizations for org in doc.get("organizations")): + if any( + org.organization in get_permitted_documents("Organization") for org in doc.get("organizations") + ): return True return False @@ -34,19 +34,14 @@ def get_permission_query_conditions(user): if "System Manager" in user_roles or "LANDA State Organization Employee" in user_roles: return None - return """exists ( - select 1 from `tabTag Organization` - where - `tabTag Organization`.parent = `tabTag`.name and - `tabTag Organization`.organization in ( - select for_value - from `tabUser Permission` - where `allow` = 'Organization' - and `user` = {user} - ) - )""".format( - user=frappe.db.escape(user) - ) + permitted_organizations = ", ".join(f"'{org}'" for org in get_permitted_documents("Organization")) + + return f"""exists ( + select 1 from `tabTag Organization` + where + `tabTag Organization`.parent = `tabTag`.name and + `tabTag Organization`.organization in ({permitted_organizations}) + )""" def before_insert(doc, method): @@ -64,4 +59,4 @@ def add_tag(tag, dt, dn, color=None): tag_doc.append("organizations", {"organization": organization}) tag_doc.save(ignore_permissions=True) - return frappe.desk.doctype.tag.tag.add_tag(tag, dt, dn, color) + return frappe_add_tag(tag, dt, dn, color) From 6ca542551ed31410267e7d8cec6d69cb64862444 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:22:13 +0100 Subject: [PATCH 5/6] refactor: tag has_permission --- landa/organization_management/tag/tag.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/landa/organization_management/tag/tag.py b/landa/organization_management/tag/tag.py index 6848112a..29e1439f 100644 --- a/landa/organization_management/tag/tag.py +++ b/landa/organization_management/tag/tag.py @@ -17,12 +17,8 @@ def has_permission(doc, user): if "System Manager" in user_roles or "LANDA State Organization Employee" in user_roles: return True - if any( - org.organization in get_permitted_documents("Organization") for org in doc.get("organizations") - ): - return True - - return False + permitted_documents = get_permitted_documents("Organization") + return any(org.organization in permitted_documents for org in doc.get("organizations")) def get_permission_query_conditions(user): From 4ab60f80835c2a7a14fb1dd6ce261545041e2e20 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:22:59 +0100 Subject: [PATCH 6/6] fix: make the patch work (LAN-790) --- landa/patches/add_organization_to_tags.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/landa/patches/add_organization_to_tags.py b/landa/patches/add_organization_to_tags.py index 524148cb..845bb3ca 100644 --- a/landa/patches/add_organization_to_tags.py +++ b/landa/patches/add_organization_to_tags.py @@ -1,9 +1,17 @@ import frappe +from frappe.modules.utils import sync_customizations from landa.utils import get_member_and_organization def execute(): + """Add organization to tags""" + # make sure Tag Organization is available + frappe.reload_doc("organization_management", "doctype", "tag_organization") + + # make sure Tag is customized + sync_customizations("landa") + tags = frappe.get_all("Tag", fields=["name", "owner"]) for tag in tags: @@ -12,6 +20,6 @@ def execute(): if owner_organization: tag_doc = frappe.get_doc("Tag", tag["name"]) - if not any(org.organization == owner_organization for org in tag_doc.get("organizations")): + if all(org.organization != owner_organization for org in tag_doc.get("organizations", [])): tag_doc.append("organizations", {"organization": owner_organization}) tag_doc.save(ignore_permissions=True)