Repository: frappe/frappe

Issue:
Apply permlevel during load
When loading any document, permlevel is not applied. Fields with no reading permissions are shown for example in cur_frm.doc.

This should be fixed. 



Discussion:

Resolving patch:
diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py
--- 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
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -410,6 +410,29 @@ def _validate(self):
 		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 @@ def validate_higher_perm_levels(self):
 				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)
 


Test patch:
diff --git a/frappe/tests/test_form_load.py b/frappe/tests/test_form_load.py
--- 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 @@ def test_load(self):
 		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')