diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index b10e3fd28d..ef8de394ca 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -125,7 +125,7 @@ class BaseDocument(object): if key not in self.__dict__: self.__dict__[key] = None - if getattr(self, "_metaclass", False) or self.doctype in ("DocType", "DocField", "DocPerm"): + if self.doctype in ("DocField", "DocPerm") and self.parent in ("DocType", "DocField", "DocPerm"): from frappe.model.meta import get_table_columns valid = get_table_columns(self.doctype) else: diff --git a/frappe/permissions.py b/frappe/permissions.py index e6ea32fa8f..3559c4979c 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -13,39 +13,39 @@ def check_admin_or_system_manager(): if ("System Manager" not in frappe.get_roles()) and \ (frappe.session.user!="Administrator"): msgprint("Only Allowed for Role System Manager or Administrator", raise_exception=True) - + def has_permission(doctype, ptype="read", doc=None, verbose=True): """check if user has permission""" if frappe.is_table(doctype): return True - + meta = frappe.get_meta(doctype) - + if ptype=="submit" and not cint(meta.is_submittable): return False - + if ptype=="import" and not cint(meta.allow_import): return False - + if frappe.session.user=="Administrator": return True - + # get user permissions if not get_user_perms(meta).get(ptype): return False - + if doc: if isinstance(doc, basestring): doc = frappe.get_doc(meta.name, doc) - + if not has_unrestricted_access(doc, verbose=verbose): return False - + if not has_controller_permissions(doc): return False return True - + def get_user_perms(meta, user=None): if not user: user = frappe.session.user @@ -53,7 +53,7 @@ def get_user_perms(meta, user=None): if not frappe.local.user_perms.get(cache_key): perms = frappe._dict() user_roles = frappe.get_roles(user) - + for p in meta.permissions: if cint(p.permlevel)==0 and (p.role in user_roles): for ptype in rights: @@ -61,18 +61,18 @@ def get_user_perms(meta, user=None): perms[ptype] = perms.get(ptype, 1) and cint(p.get(ptype)) else: perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype)) - + frappe.local.user_perms[cache_key] = perms return frappe.local.user_perms[cache_key] - + def has_unrestricted_access(doc, verbose=True): from frappe.defaults import get_restrictions restrictions = get_restrictions() - meta = frappe.get_meta(doc.get("doctype")) + meta = frappe.get_meta(doc.get("doctype")) if get_user_perms(meta).restricted: - if doc.owner == frappe.session.user: + if d.owner == frappe.session.user: # owner is always allowed for restricted permissions return True elif not restrictions: @@ -80,58 +80,67 @@ def has_unrestricted_access(doc, verbose=True): else: if not restrictions: return True - - # evaluate specific restrictions - fields_to_check = meta.get_restricted_fields(restrictions.keys()) - - has_restricted_data = False - for df in fields_to_check: - if doc.get(df.fieldname) and doc.get(df.fieldname) not in restrictions[df.options]: - if verbose: - msg = "{not_allowed}: {doctype} {having} {label} = {value}".format( - not_allowed=_("Sorry, you are not allowed to access"), doctype=_(df.options), - having=_("having"), label=_(df.label), value=doc.get(df.fieldname)) - - if doc.parentfield: - msg = "{doctype}, {row} #{idx}, ".format(doctype=_(doc.doctype), - row=_("Row"), idx=doc.idx) + msg - - msgprint(msg) - - has_restricted_data = True - + + def _has_unrestricted_access(d): + meta = frappe.get_meta(d.get("doctype")) + + # evaluate specific restrictions + fields_to_check = meta.get_restricted_fields(restrictions.keys()) + + _has_restricted_data = False + for df in fields_to_check: + if d.get(df.fieldname) and d.get(df.fieldname) not in restrictions[df.options]: + if verbose: + msg = "{not_allowed}: {doctype} {having} {label} = {value}".format( + not_allowed=_("Sorry, you are not allowed to access"), doctype=_(df.options), + having=_("having"), label=_(df.label), value=d.get(df.fieldname)) + + if d.parentfield: + msg = "{doctype}, {row} #{idx}, ".format(doctype=_(d.doctype), + row=_("Row"), idx=d.idx) + msg + + msgprint(msg) + + _has_restricted_data = True + + return _has_restricted_data + + has_restricted_data = _has_unrestricted_access(doc) + for d in doc.get_all_children(): + has_restricted_data = _has_unrestricted_access(d) or has_restricted_data + # check all restrictions before returning return False if has_restricted_data else True - + def has_controller_permissions(doc): if doc.get("__islocal"): doc = frappe.get_doc(doc) else: doc = frappe.get_doc(doc.doctype, doc.name) - + condition_methods = frappe.get_hooks("has_permission:" + doc.doctype) for method in frappe.get_hooks("has_permission:" + doc.doctype): if not frappe.call(frappe.get_attr(method), doc=doc): return False - + return True - + def can_restrict_user(user, doctype, docname=None): if not can_restrict(doctype, docname): return False - + # check if target user does not have restrict permission if has_only_non_restrict_role(doctype, user): return True - + return False - + def can_restrict(doctype, docname=None): # System Manager can always restrict if "System Manager" in frappe.get_roles(): return True meta = frappe.get_meta(doctype) - + # check if current user has read permission for docname if docname and not has_permission(doctype, "read", docname): return False @@ -139,18 +148,18 @@ def can_restrict(doctype, docname=None): # check if current user has a role with restrict permission if not has_restrict_permission(meta): return False - + return True - + def has_restrict_permission(meta=None, user=None): return get_user_perms(meta, user).restrict==1 - + def has_only_non_restrict_role(doctype, user): meta = frappe.get_meta(doctype) # check if target user does not have restrict permission if has_restrict_permission(meta, user): return False - + # and has non-restrict role return get_user_perms(meta, user).restrict==0 @@ -161,7 +170,7 @@ def can_import(doctype, raise_exception=False): else: return False return True - + def can_export(doctype, raise_exception=False): if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "export")): if raise_exception: @@ -169,4 +178,3 @@ def can_export(doctype, raise_exception=False): else: return False return True - \ No newline at end of file