diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 77a190ee01..2a1006c424 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -35,6 +35,8 @@ def getdoc(doctype, name, user=None): if not doc.has_permission("read"): raise frappe.PermissionError, ("read", doctype, name) + doc.apply_fieldlevel_read_permissions() + # add file list get_docinfo(doc) diff --git a/frappe/model/document.py b/frappe/model/document.py index 5f302ff788..83f5196d35 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -410,6 +410,29 @@ class Document(BaseDocument): for d in children: d._extract_images_from_text_editor() + def apply_fieldlevel_read_permissions(self): + '''Remove values the user is not allowed to read (called when loading in desk)''' + has_higher_permlevel = False + for p in self.get_permissions(): + if p.permlevel > 0: + has_higher_permlevel = True + break + + if not has_higher_permlevel: + return + + has_access_to = self.get_permlevel_access('read') + + for df in self.meta.fields: + if not df.permlevel in has_access_to: + self.set(df.fieldname, None) + + for table_field in self.meta.get_table_fields(): + for df in frappe.get_meta(table_field.options): + if not df.permlevel in has_access_to: + for child in self.get(table_field.fieldname) or []: + child.set(df.fieldname, None) + def validate_higher_perm_levels(self): """If the user does not have permissions at permlevel > 0, then reset the values to original / default""" if self.flags.ignore_permissions or frappe.flags.in_install: @@ -428,18 +451,18 @@ class Document(BaseDocument): for d in self.get(df.fieldname): d.reset_values_if_no_permlevel_access(has_access_to, high_permlevel_fields) - def get_permlevel_access(self): + def get_permlevel_access(self, permission_type='write'): if not hasattr(self, "_has_access_to"): user_roles = frappe.get_roles() self._has_access_to = [] for perm in self.get_permissions(): - if perm.role in user_roles and perm.permlevel > 0 and perm.write: + if perm.role in user_roles and perm.permlevel > 0 and perm.get(permission_type): if perm.permlevel not in self._has_access_to: self._has_access_to.append(perm.permlevel) return self._has_access_to - def has_permlevel_access_to(self, fieldname, df=None): + def has_permlevel_access_to(self, fieldname, df=None, permission_type='read'): if not df: df = self.meta.get_field(fieldname) diff --git a/frappe/tests/test_form_load.py b/frappe/tests/test_form_load.py index ddd672e773..95ea03b688 100644 --- a/frappe/tests/test_form_load.py +++ b/frappe/tests/test_form_load.py @@ -3,8 +3,7 @@ from __future__ import unicode_literals import frappe, unittest -from frappe.desk.form.meta import get_meta -from frappe.desk.form.load import getdoctype, getdoc +from frappe.desk.form.load import getdoctype, getdoc class TestFormLoad(unittest.TestCase): def test_load(self): @@ -14,6 +13,48 @@ class TestFormLoad(unittest.TestCase): self.assertTrue(meta.get("__js")) frappe.response.docs = [] - d = getdoctype("Event") + getdoctype("Event") meta = filter(lambda d: d.name=="Event", frappe.response.docs)[0] self.assertTrue(meta.get("__calendar_js")) + + def test_fieldlevel_permissions_in_load(self): + user = frappe.get_doc('User', 'test@example.com') + user.remove_roles('Website Manager') + user.add_roles('Blogger') + frappe.set_user(user.name) + + frappe.db.sql('update tabDocField set permlevel=1 where fieldname="published" and parent="Blog Post"') + frappe.db.sql('update tabDocPerm set permlevel=1 where role="Website Manager" and parent="Blog Post"') + frappe.clear_cache(doctype='Blog Post') + + blog = frappe.db.get_value('Blog Post', {'title': '_Test Blog Post'}) + + getdoc('Blog Post', blog) + + checked = False + + for doc in frappe.response.docs: + if doc.name == blog: + self.assertEquals(doc.published, None) + checked = True + + self.assertTrue(checked, True) + + frappe.db.sql('update tabDocField set permlevel=0 where fieldname="published" and parent="Blog Post"') + frappe.db.sql('update tabDocPerm set permlevel=0 where role="Website Manager" and parent="Blog Post"') + + frappe.clear_cache(doctype='Blog Post') + + frappe.response.docs = [] + getdoc('Blog Post', blog) + + checked = False + + for doc in frappe.response.docs: + if doc.name == blog: + self.assertEquals(doc.published, 1) + checked = True + + self.assertTrue(checked, True) + + frappe.set_user('Administrator')