From 05c1cb30c65f07cb93e802462e500c492dcb0c19 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 18:59:51 +0530 Subject: [PATCH 01/16] fix: get correct doc when checking child table permission --- frappe/permissions.py | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index acbdf76989..d07da20a5f 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -70,14 +70,14 @@ def has_permission( if not user: user = frappe.session.user + if user == "Administrator": + return True + if not doc and hasattr(doctype, "doctype"): # first argument can be doc or doctype doc = doctype doctype = doc.doctype - if user == "Administrator": - return True - if frappe.is_table(doctype): return has_child_table_permission( doctype, ptype, doc, verbose, user, raise_exception, parent_doctype @@ -667,32 +667,27 @@ def has_child_table_permission( raise_exception=True, parent_doctype=None, ): - parent_doc = None - if child_doc: - parent_doctype = child_doc.get("parenttype") - parent_doc = frappe.get_cached_doc( - {"doctype": parent_doctype, "docname": child_doc.get("parent")} - ) + parent_doctype = child_doc.parenttype - if parent_doctype: - if not is_parent_valid(child_doctype, parent_doctype): - frappe.throw( - _("{0} is not a valid parent DocType for {1}").format( - frappe.bold(parent_doctype), frappe.bold(child_doctype) - ), - title=_("Invalid Parent DocType"), - ) - else: + if not parent_doctype: frappe.throw( _("Please specify a valid parent DocType for {0}").format(frappe.bold(child_doctype)), title=_("Parent DocType Required"), ) + if not is_parent_valid(child_doctype, parent_doctype): + frappe.throw( + _("{0} is not a valid parent DocType for {1}").format( + frappe.bold(parent_doctype), frappe.bold(child_doctype) + ), + title=_("Invalid Parent DocType"), + ) + return has_permission( parent_doctype, ptype=ptype, - doc=parent_doc, + doc=getattr(child_doc, "parent_doc", child_doc.parent), verbose=verbose, user=user, raise_exception=raise_exception, @@ -700,10 +695,8 @@ def has_child_table_permission( def is_parent_valid(child_doctype, parent_doctype): - from frappe.core.utils import find - parent_meta = frappe.get_meta(parent_doctype) - child_table_field_exists = find( - parent_meta.get_table_fields(), lambda d: d.options == child_doctype + + return not parent_meta.istable and any( + df.options == child_doctype for df in parent_meta.get_table_fields() ) - return not parent_meta.istable and child_table_field_exists From 35671295ee770f0202c8778ba37f08832453c5f7 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 19:51:28 +0530 Subject: [PATCH 02/16] fix: handle permlevel --- frappe/permissions.py | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index d07da20a5f..f55a26a3c3 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -667,36 +667,55 @@ def has_child_table_permission( raise_exception=True, parent_doctype=None, ): + parent_doc = None + if child_doc: + if isinstance(child_doc, str): + child_doc = frappe.get_doc(child_doctype, child_doc) + parent_doctype = child_doc.parenttype + parent_doc = getattr(child_doc, "parent_doc", None) + + if not parent_doc and child_doc.parent: + parent_doc = frappe.get_doc(parent_doctype, child_doc.parent) + child_doc.parent_doc = parent_doc if not parent_doctype: - frappe.throw( - _("Please specify a valid parent DocType for {0}").format(frappe.bold(child_doctype)), - title=_("Parent DocType Required"), + push_perm_check_log( + _("Please specify a valid parent DocType for {0}").format(frappe.bold(child_doctype)) ) + return False - if not is_parent_valid(child_doctype, parent_doctype): - frappe.throw( + parent_meta = parent_doc.meta if parent_doc else frappe.get_meta(parent_doctype) + + if not parent_meta.istable and any( + df.options == child_doctype for df in parent_meta.get_table_fields() + ): + push_perm_check_log( _("{0} is not a valid parent DocType for {1}").format( frappe.bold(parent_doctype), frappe.bold(child_doctype) - ), - title=_("Invalid Parent DocType"), + ) ) + return False + + if ( + child_doc + and child_doc.parentfield + and ( + parent_meta.get_field(child_doc.parentfield).permlevel + not in parent_meta.get_permlevel_access(ptype) + ) + ): + push_perm_check_log( + _("Insufficient Permission Level for {0}").format(frappe.bold(parent_doctype)) + ) + return False return has_permission( parent_doctype, ptype=ptype, - doc=getattr(child_doc, "parent_doc", child_doc.parent), + doc=parent_doc, verbose=verbose, user=user, raise_exception=raise_exception, ) - - -def is_parent_valid(child_doctype, parent_doctype): - parent_meta = frappe.get_meta(parent_doctype) - - return not parent_meta.istable and any( - df.options == child_doctype for df in parent_meta.get_table_fields() - ) From 30175f426e95e92443ec905bb8f9c15a50e3ed8b Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 20:02:32 +0530 Subject: [PATCH 03/16] fix: dont init child doc --- frappe/permissions.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index f55a26a3c3..5c2b9276d8 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -667,18 +667,16 @@ def has_child_table_permission( raise_exception=True, parent_doctype=None, ): - parent_doc = None - if child_doc: if isinstance(child_doc, str): - child_doc = frappe.get_doc(child_doctype, child_doc) + child_doc = frappe.db.get_value( + child_doctype, + child_doc, + ("parent", "parenttype", "parentfield"), + as_dict=True, + ) parent_doctype = child_doc.parenttype - parent_doc = getattr(child_doc, "parent_doc", None) - - if not parent_doc and child_doc.parent: - parent_doc = frappe.get_doc(parent_doctype, child_doc.parent) - child_doc.parent_doc = parent_doc if not parent_doctype: push_perm_check_log( @@ -686,7 +684,7 @@ def has_child_table_permission( ) return False - parent_meta = parent_doc.meta if parent_doc else frappe.get_meta(parent_doctype) + parent_meta = frappe.get_meta(parent_doctype) if not parent_meta.istable and any( df.options == child_doctype for df in parent_meta.get_table_fields() @@ -714,7 +712,7 @@ def has_child_table_permission( return has_permission( parent_doctype, ptype=ptype, - doc=parent_doc, + doc=child_doc and getattr(child_doc, "parent_doc", child_doc.parent), verbose=verbose, user=user, raise_exception=raise_exception, From 4c4d9ac60e5bcc3b0a891db64ff87e7522a04c32 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 20:49:25 +0530 Subject: [PATCH 04/16] fix: check permlevel only if > 0 --- frappe/permissions.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index 5c2b9276d8..7b2b5ae65b 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -667,15 +667,15 @@ def has_child_table_permission( raise_exception=True, parent_doctype=None, ): - if child_doc: - if isinstance(child_doc, str): - child_doc = frappe.db.get_value( - child_doctype, - child_doc, - ("parent", "parenttype", "parentfield"), - as_dict=True, - ) + if isinstance(child_doc, str): + child_doc = frappe.db.get_value( + child_doctype, + child_doc, + ("parent", "parenttype", "parentfield"), + as_dict=True, + ) + if child_doc: parent_doctype = child_doc.parenttype if not parent_doctype: @@ -699,10 +699,8 @@ def has_child_table_permission( if ( child_doc and child_doc.parentfield - and ( - parent_meta.get_field(child_doc.parentfield).permlevel - not in parent_meta.get_permlevel_access(ptype) - ) + and (permlevel := parent_meta.get_field(child_doc.parentfield).permlevel) > 0 + and permlevel not in parent_meta.get_permlevel_access(ptype) ): push_perm_check_log( _("Insufficient Permission Level for {0}").format(frappe.bold(parent_doctype)) From 7183efa60d2519ac47bf1ae8a719676b8505f211 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 21:07:02 +0530 Subject: [PATCH 05/16] fix: assume parentfield to be set and valid --- frappe/permissions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index 7b2b5ae65b..cde043c816 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -698,7 +698,6 @@ def has_child_table_permission( if ( child_doc - and child_doc.parentfield and (permlevel := parent_meta.get_field(child_doc.parentfield).permlevel) > 0 and permlevel not in parent_meta.get_permlevel_access(ptype) ): From a63363d433c1036ca7e49ed5041685589a88a5cc Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 21:56:35 +0530 Subject: [PATCH 06/16] refactor: `has_child_table_permission` => `has_child_permission` --- frappe/permissions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index cde043c816..50e4799410 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -79,9 +79,7 @@ def has_permission( doctype = doc.doctype if frappe.is_table(doctype): - return has_child_table_permission( - doctype, ptype, doc, verbose, user, raise_exception, parent_doctype - ) + return has_child_permission(doctype, ptype, doc, verbose, user, raise_exception, parent_doctype) meta = frappe.get_meta(doctype) @@ -658,7 +656,7 @@ def push_perm_check_log(log): frappe.flags.get("has_permission_check_logs").append(_(log)) -def has_child_table_permission( +def has_child_permission( child_doctype, ptype="read", child_doc=None, From 2b873b34dd68b9cf6c0253d22a8ed37bd5a23ceb Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 30 Jul 2022 23:42:38 +0530 Subject: [PATCH 07/16] refactor: remove `verbose` parameter; add `user` parameter to `Meta.get_permlevel_access` --- frappe/model/meta.py | 4 ++-- frappe/permissions.py | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 014dd5faf1..51f9241e58 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -539,9 +539,9 @@ class Meta(Document): return self.high_permlevel_fields - def get_permlevel_access(self, permission_type="read", parenttype=None): + def get_permlevel_access(self, permission_type="read", parenttype=None, *, user=None): has_access_to = [] - roles = frappe.get_roles() + roles = frappe.get_roles(user) for perm in self.get_permissions(parenttype): if perm.role in roles and perm.get(permission_type): if perm.permlevel not in has_access_to: diff --git a/frappe/permissions.py b/frappe/permissions.py index 50e4799410..791b1d0c3e 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -65,8 +65,19 @@ def has_permission( """Returns True if user has permission `ptype` for given `doctype`. If `doc` is passed, it also checks user, share and owner permissions. - Note: if Table DocType is passed, it always returns True. + :param doctype: DocType to check permission for + :param ptype: Permission Type to check + :param doc: Check User Permissions for specified document. + :param verbose: DEPRECATED, will be removed in a future version. + :param user: User to check permission for. Defaults to session user. + :param raise_exception: + DOES NOT raise an exception. + If True, will print a message explaining why permission check failed. + + :param parent_doctype: + Required when checking permission for a child DocType (unless doc is specified) """ + if not user: user = frappe.session.user @@ -79,7 +90,7 @@ def has_permission( doctype = doc.doctype if frappe.is_table(doctype): - return has_child_permission(doctype, ptype, doc, verbose, user, raise_exception, parent_doctype) + return has_child_permission(doctype, ptype, doc, user, raise_exception, parent_doctype) meta = frappe.get_meta(doctype) @@ -660,7 +671,6 @@ def has_child_permission( child_doctype, ptype="read", child_doc=None, - verbose=False, user=None, raise_exception=True, parent_doctype=None, @@ -697,7 +707,7 @@ def has_child_permission( if ( child_doc and (permlevel := parent_meta.get_field(child_doc.parentfield).permlevel) > 0 - and permlevel not in parent_meta.get_permlevel_access(ptype) + and permlevel not in parent_meta.get_permlevel_access(ptype, user=user) ): push_perm_check_log( _("Insufficient Permission Level for {0}").format(frappe.bold(parent_doctype)) @@ -708,7 +718,6 @@ def has_child_permission( parent_doctype, ptype=ptype, doc=child_doc and getattr(child_doc, "parent_doc", child_doc.parent), - verbose=verbose, user=user, raise_exception=raise_exception, ) From d6aa17cc1409ddadc68b9c08ba8b70a79b3ff6c6 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sun, 31 Jul 2022 00:22:41 +0530 Subject: [PATCH 08/16] chore: add deprecation warning everywhere verbose is used --- frappe/__init__.py | 17 +++++++++++++---- frappe/model/db_query.py | 1 + frappe/model/document.py | 11 +++++++---- frappe/permissions.py | 3 ++- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index e1fa902eba..2f49cab5a6 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -905,15 +905,25 @@ def only_has_select_perm(doctype, user=None, ignore_permissions=False): def has_permission( - doctype=None, ptype="read", doc=None, user=None, verbose=False, throw=False, parent_doctype=None + doctype=None, + ptype="read", + doc=None, + user=None, + verbose=False, + throw=False, + *, + parent_doctype=None, ): - """Raises `frappe.PermissionError` if not permitted. + """ + Raises `frappe.PermissionError` if not permitted. :param doctype: DocType for which permission is to be check. :param ptype: Permission type (`read`, `write`, `create`, `submit`, `cancel`, `amend`). Default: `read`. :param doc: [optional] Checks User permissions for given doc. :param user: [optional] Check for given user. Default: current user. - :param parent_doctype: Required when checking permission for a child DocType (unless doc is specified).""" + :param verbose: DEPRECATED, will be removed in a future release. + :param parent_doctype: Required when checking permission for a child DocType (unless doc is specified). + """ import frappe.permissions if not doctype and doc: @@ -923,7 +933,6 @@ def has_permission( doctype, ptype, doc=doc, - verbose=verbose, user=user, raise_exception=throw, parent_doctype=parent_doctype, diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index a29ede37bf..9ce4cc4942 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -97,6 +97,7 @@ class DatabaseQuery: strict=True, pluck=None, ignore_ddl=False, + *, parent_doctype=None, ) -> list: diff --git a/frappe/model/document.py b/frappe/model/document.py index cadfa573d0..e4d927feec 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -194,15 +194,18 @@ class Document(BaseDocument): self.raise_no_permission_to(permlevel or permtype) def has_permission(self, permtype="read", verbose=False) -> bool: - """Call `frappe.has_permission` if `self.flags.ignore_permissions` - is not set. + """ + Call `frappe.has_permission` if `self.flags.ignore_permissions` is not set. - :param permtype: one of `read`, `write`, `submit`, `cancel`, `delete`""" + :param permtype: one of `read`, `write`, `submit`, `cancel`, `delete` + :param verbose: DEPRECATED, will be removed in a future release. + """ import frappe.permissions if self.flags.ignore_permissions: return True - return frappe.permissions.has_permission(self.doctype, permtype, self, verbose=verbose) + + return frappe.permissions.has_permission(self.doctype, permtype, self) def raise_no_permission_to(self, perm_type): """Raise `frappe.PermissionError`.""" diff --git a/frappe/permissions.py b/frappe/permissions.py index 791b1d0c3e..e250cb1635 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -60,6 +60,7 @@ def has_permission( verbose=False, user=None, raise_exception=True, + *, parent_doctype=None, ): """Returns True if user has permission `ptype` for given `doctype`. @@ -68,7 +69,7 @@ def has_permission( :param doctype: DocType to check permission for :param ptype: Permission Type to check :param doc: Check User Permissions for specified document. - :param verbose: DEPRECATED, will be removed in a future version. + :param verbose: DEPRECATED, will be removed in a future release. :param user: User to check permission for. Defaults to session user. :param raise_exception: DOES NOT raise an exception. From 56717602b4c9ff6bab78a64b3bc61f71bdef3fb5 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 2 Aug 2022 04:08:50 +0530 Subject: [PATCH 09/16] fix: reverse logic for failing permission check --- frappe/permissions.py | 4 ++-- frappe/tests/test_permissions.py | 26 +++++--------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index e250cb1635..2fd39fdafd 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -695,8 +695,8 @@ def has_child_permission( parent_meta = frappe.get_meta(parent_doctype) - if not parent_meta.istable and any( - df.options == child_doctype for df in parent_meta.get_table_fields() + if parent_meta.istable or all( + df.options != child_doctype for df in parent_meta.get_table_fields() ): push_perm_check_log( _("{0} is not a valid parent DocType for {1}").format( diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index b4f0402a16..ed0f815d3d 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -649,29 +649,13 @@ class TestPermissions(FrappeTestCase): # reset the user frappe.set_user(current_user) - def test_child_table_permissions(self): + def test_child_permissions(self): frappe.set_user("test@example.com") self.assertIsInstance(frappe.get_list("Has Role", parent_doctype="User", limit=1), list) - self.assertRaisesRegex( - frappe.exceptions.ValidationError, - ".* is not a valid parent DocType for .*", - frappe.get_list, - doctype="Has Role", - parent_doctype="ToDo", - ) - self.assertRaisesRegex( - frappe.exceptions.ValidationError, - "Please specify a valid parent DocType for .*", - frappe.get_list, - "Has Role", - ) - self.assertRaisesRegex( - frappe.exceptions.ValidationError, - ".* is not a valid parent DocType for .*", - frappe.get_list, - doctype="Has Role", - parent_doctype="Has Role", - ) + + self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role") + self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role", parent_doctype="ToDo") + self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role", parent_doctype="Has Role") def test_select_user(self): """If test3@example.com is restricted by a User Permission to see only From b66f1d44e332f7c91bfdde04eaacf9dab69d1679 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 2 Aug 2022 04:46:41 +0530 Subject: [PATCH 10/16] test: add tests for `frappe.get_doc` --- frappe/tests/test_permissions.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index ed0f815d3d..64c8bdc3b8 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -651,11 +651,28 @@ class TestPermissions(FrappeTestCase): def test_child_permissions(self): frappe.set_user("test@example.com") - self.assertIsInstance(frappe.get_list("Has Role", parent_doctype="User", limit=1), list) + self.assertIsInstance(frappe.get_list("DefaultValue", parent_doctype="User", limit=1), list) - self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role") - self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role", parent_doctype="ToDo") - self.assertRaises(frappe.PermissionError, frappe.get_list, "Has Role", parent_doctype="Has Role") + # frappe.get_list + self.assertRaises(frappe.PermissionError, frappe.get_list, "DefaultValue") + self.assertRaises(frappe.PermissionError, frappe.get_list, "DefaultValue", parent_doctype="ToDo") + self.assertRaises( + frappe.PermissionError, frappe.get_list, "DefaultValue", parent_doctype="DefaultValue" + ) + + # frappe.get_doc + user = frappe.get_doc("User", frappe.session.user) + doc = user.append("defaults") + doc.check_permission() + + # false by permlevel + doc = user.append("roles") + self.assertRaises(frappe.PermissionError, doc.check_permission) + + # false by user permission + user = frappe.get_doc("User", "Administrator") + doc = user.append("defaults") + self.assertRaises(frappe.PermissionError, doc.check_permission) def test_select_user(self): """If test3@example.com is restricted by a User Permission to see only From a9b69351e66b5c0bc6163b4fd1ea92a98dff87e5 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 2 Aug 2022 05:01:10 +0530 Subject: [PATCH 11/16] test: use different user --- frappe/tests/test_permissions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index 64c8bdc3b8..f48273135a 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -650,7 +650,7 @@ class TestPermissions(FrappeTestCase): frappe.set_user(current_user) def test_child_permissions(self): - frappe.set_user("test@example.com") + frappe.set_user("test3@example.com") self.assertIsInstance(frappe.get_list("DefaultValue", parent_doctype="User", limit=1), list) # frappe.get_list From cafd2c920db23fc1f7a2e2b6988d59d1a95e000b Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 8 Aug 2022 18:36:54 +0530 Subject: [PATCH 12/16] fix(sanitize-html): allow all data-* attrs --- frappe/utils/html_utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frappe/utils/html_utils.py b/frappe/utils/html_utils.py index b9d0e8dfe2..fa84170330 100644 --- a/frappe/utils/html_utils.py +++ b/frappe/utils/html_utils.py @@ -162,7 +162,13 @@ def sanitize_html(html, linkify=False): + mathml_elements + ["html", "head", "meta", "link", "body", "style", "o:p"] ) - attributes = {"*": acceptable_attributes, "svg": svg_attributes} + + def attributes_filter(tag, name, value): + if name.startswith("data-"): + return True + return name in acceptable_attributes + + attributes = {"*": attributes_filter, "svg": svg_attributes} styles = bleach_allowlist.all_styles strip_comments = False From 7129d6128ff0e30ee2ec2a73818c2b5bc894e873 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 9 Aug 2022 11:50:15 +0530 Subject: [PATCH 13/16] chore: lazier import; improved docstrings --- frappe/__init__.py | 3 ++- frappe/model/document.py | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 2f49cab5a6..914b887f2a 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -915,7 +915,8 @@ def has_permission( parent_doctype=None, ): """ - Raises `frappe.PermissionError` if not permitted. + Returns True if the user has permission `ptype` for given `doctype` or `doc` + Raises `frappe.PermissionError` if user isn't permitted and `throw` is truthy :param doctype: DocType for which permission is to be check. :param ptype: Permission type (`read`, `write`, `create`, `submit`, `cancel`, `amend`). Default: `read`. diff --git a/frappe/model/document.py b/frappe/model/document.py index e4d927feec..f5d76b6484 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -195,16 +195,17 @@ class Document(BaseDocument): def has_permission(self, permtype="read", verbose=False) -> bool: """ - Call `frappe.has_permission` if `self.flags.ignore_permissions` is not set. + Call `frappe.permissions.has_permission` if `ignore_permissions` flag isn't truthy - :param permtype: one of `read`, `write`, `submit`, `cancel`, `delete` + :param permtype: `read`, `write`, `submit`, `cancel`, `delete`, etc. :param verbose: DEPRECATED, will be removed in a future release. """ - import frappe.permissions if self.flags.ignore_permissions: return True + import frappe.permissions + return frappe.permissions.has_permission(self.doctype, permtype, self) def raise_no_permission_to(self, perm_type): From 7a19d65ea4915e9eb6a2b91bafd9b8e28b1cd4e4 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 9 Aug 2022 12:00:16 +0530 Subject: [PATCH 14/16] chore: improve docstring --- frappe/permissions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index 2fd39fdafd..3bcddfc0f9 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -70,10 +70,11 @@ def has_permission( :param ptype: Permission Type to check :param doc: Check User Permissions for specified document. :param verbose: DEPRECATED, will be removed in a future release. - :param user: User to check permission for. Defaults to session user. + :param user: User to check permission for. Defaults to current user. :param raise_exception: DOES NOT raise an exception. - If True, will print a message explaining why permission check failed. + If not False, will display a message using frappe.msgprint + which explains why the permission check failed. :param parent_doctype: Required when checking permission for a child DocType (unless doc is specified) From 28fc208b511fe624f8e0f27aa376ad75845bcdb0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 9 Aug 2022 14:47:18 +0530 Subject: [PATCH 15/16] test: sanitize_html attributes behaviour --- frappe/tests/test_utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index e903c655b0..e68e8372af 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -254,6 +254,13 @@ class TestHTMLUtils(unittest.TestCase): self.assertTrue("

Hello

" in clean) self.assertTrue('text' in clean) + def test_sanitize_html(self): + from frappe.utils.html_utils import sanitize_html + + clean = sanitize_html("
    ") + self.assertIn("ordered", clean) + self.assertNotIn("xyz", clean) + class TestValidationUtils(unittest.TestCase): def test_valid_url(self): From cde6755aff07f6f17cffbf8ff3df3f258630a323 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 9 Aug 2022 14:57:48 +0530 Subject: [PATCH 16/16] feat: Multilanguage sites: language selector only will show "enabled" languages and language default always will be System default (#17745) (#17766) * feat: Select only enabled languages for "language selector", and use System Settings lang as default one [skip ci] (cherry picked from commit e5b8a47835d22b7834865324d30d796bb3031dd5) Co-authored-by: Development for People <47140294+developmentforpeople@users.noreply.github.com> --- frappe/translate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/translate.py b/frappe/translate.py index 884ec127d2..06176e28ba 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -99,8 +99,8 @@ def get_language(lang_list: list = None) -> str: if parent_language in lang_set: return parent_language - # fallback to language set in User or System Settings - return frappe.local.lang + # fallback to language set in System Settings or "en" + return frappe.db.get_default("lang") or "en" @functools.lru_cache @@ -1270,13 +1270,13 @@ def get_translator_url(): @frappe.whitelist(allow_guest=True) def get_all_languages(with_language_name=False): - """Returns all language codes ar, ch etc""" + """Returns all enabled language codes ar, ch etc""" def get_language_codes(): - return frappe.get_all("Language", pluck="name") + return frappe.get_all("Language", filters={"enabled": 1}, pluck="name") def get_all_language_with_name(): - return frappe.db.get_all("Language", ["language_code", "language_name"]) + return frappe.get_all("Language", ["language_code", "language_name"], {"enabled": 1}) if not frappe.db: frappe.connect()