Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

407 linhas
14 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe, copy, json
  5. from frappe import _, msgprint
  6. from frappe.utils import cint
  7. import frappe.share
  8. rights = ("read", "write", "create", "delete", "submit", "cancel", "amend",
  9. "print", "email", "report", "import", "export", "set_user_permissions", "share")
  10. def check_admin_or_system_manager(user=None):
  11. if not user: user = frappe.session.user
  12. if ("System Manager" not in frappe.get_roles(user)) and (user!="Administrator"):
  13. frappe.throw(_("Not permitted"), frappe.PermissionError)
  14. def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
  15. """Returns True if user has permission `ptype` for given `doctype`.
  16. If `doc` is passed, it also checks user, share and owner permissions.
  17. Note: if Table DocType is passed, it always returns True.
  18. """
  19. if not user: user = frappe.session.user
  20. if frappe.is_table(doctype):
  21. if verbose: print "Table type, always true"
  22. return True
  23. meta = frappe.get_meta(doctype)
  24. if ptype=="submit" and not cint(meta.is_submittable):
  25. if verbose: print "Not submittable"
  26. return False
  27. if ptype=="import" and not cint(meta.allow_import):
  28. if verbose: print "Not importable"
  29. return False
  30. if user=="Administrator":
  31. if verbose: print "Administrator"
  32. return True
  33. def false_if_not_shared():
  34. if ptype in ("read", "write", "share", "email", "print"):
  35. shared = frappe.share.get_shared(doctype, user,
  36. ["read" if ptype in ("email", "print") else ptype])
  37. if doc:
  38. doc_name = doc if isinstance(doc, basestring) else doc.name
  39. if doc_name in shared:
  40. if verbose: print "Shared"
  41. if ptype in ("read", "write", "share") or meta.permissions[0].get(ptype):
  42. if verbose: print "Is shared"
  43. return True
  44. elif shared:
  45. # if atleast one shared doc of that type, then return True
  46. # this is used in db_query to check if permission on DocType
  47. if verbose: print "Has a shared document"
  48. return True
  49. if verbose: print "Not Shared"
  50. return False
  51. role_permissions = get_role_permissions(meta, user=user, verbose=verbose)
  52. if not role_permissions.get(ptype):
  53. return false_if_not_shared()
  54. perm = True
  55. if doc:
  56. if isinstance(doc, basestring):
  57. doc = frappe.get_doc(meta.name, doc)
  58. owner_perm = user_perm = controller_perm = None
  59. if role_permissions["if_owner"].get(ptype) and ptype!="create":
  60. owner_perm = doc.owner == frappe.session.user
  61. if verbose: print "Owner permission: {0}".format(owner_perm)
  62. # check if user permission
  63. if not owner_perm and role_permissions["apply_user_permissions"].get(ptype):
  64. user_perm = user_has_permission(doc, verbose=verbose, user=user,
  65. user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or [])
  66. if verbose: print "User permission: {0}".format(user_perm)
  67. if not owner_perm and not user_perm:
  68. controller_perm = has_controller_permissions(doc, ptype, user=user)
  69. if verbose: print "Controller permission: {0}".format(controller_perm)
  70. # permission true if any one condition is explicitly True or all permissions are undefined (None)
  71. perm = any([owner_perm, user_perm, controller_perm]) or \
  72. all([owner_perm==None, user_perm==None, controller_perm==None])
  73. if not perm:
  74. perm = false_if_not_shared()
  75. if verbose: print "Final Permission: {0}".format(perm)
  76. return perm
  77. def get_doc_permissions(doc, verbose=False, user=None):
  78. """Returns a dict of evaluated permissions for given `doc` like `{"read":1, "write":1}`"""
  79. if not user: user = frappe.session.user
  80. if frappe.is_table(doc.doctype):
  81. return {"read":1, "write":1}
  82. meta = frappe.get_meta(doc.doctype)
  83. role_permissions = copy.deepcopy(get_role_permissions(meta, user=user, verbose=verbose))
  84. if not cint(meta.is_submittable):
  85. role_permissions["submit"] = 0
  86. if not cint(meta.allow_import):
  87. role_permissions["import"] = 0
  88. if role_permissions.get("apply_user_permissions"):
  89. # no user permissions, switch off all user-level permissions
  90. for ptype in role_permissions:
  91. if role_permissions["apply_user_permissions"].get(ptype) and not user_has_permission(doc, verbose=verbose, user=user,
  92. user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or []):
  93. role_permissions[ptype] = 0
  94. # apply owner permissions on top of existing permissions
  95. if doc.owner == frappe.session.user:
  96. role_permissions.update(role_permissions.if_owner)
  97. update_share_permissions(role_permissions, doc, user)
  98. return role_permissions
  99. def update_share_permissions(role_permissions, doc, user):
  100. """Updates share permissions on `role_permissions` for given doc, if shared"""
  101. share_ptypes = ("read", "write", "share")
  102. permissions_by_share = frappe.db.get_value("DocShare",
  103. {"share_doctype": doc.doctype, "share_name": doc.name, "user": user},
  104. share_ptypes, as_dict=True)
  105. if permissions_by_share:
  106. for ptype in share_ptypes:
  107. if permissions_by_share[ptype]:
  108. role_permissions[ptype] = 1
  109. def get_role_permissions(meta, user=None, verbose=False):
  110. """Returns dict of evaluated role permissions like `{"read": True, "write":False}`
  111. If user permissions are applicable, it adds a dict of user permissions like
  112. {
  113. // user permissions will apply on these rights
  114. "apply_user_permissions": {"read": 1, "write": 1},
  115. // doctypes that will be applicable for each right
  116. "user_permission_doctypes": {
  117. "read": [
  118. // AND between "DocType 1" and "DocType 2"
  119. ["DocType 1", "DocType 2"],
  120. // OR
  121. ["DocType 3"]
  122. ]
  123. }
  124. "if_owner": {"read": 1, "write": 1}
  125. }
  126. """
  127. if not user: user = frappe.session.user
  128. cache_key = (meta.name, user)
  129. if not frappe.local.role_permissions.get(cache_key):
  130. perms = frappe._dict({ "apply_user_permissions": {}, "user_permission_doctypes": {}, "if_owner": {} })
  131. user_roles = frappe.get_roles(user)
  132. dont_match = []
  133. has_a_role_with_apply_user_permissions = False
  134. for p in meta.permissions:
  135. if cint(p.permlevel)==0 and (p.role in user_roles):
  136. # apply only for level 0
  137. for ptype in rights:
  138. # build if_owner dict if applicable for this right
  139. perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype))
  140. if ptype != "set_user_permissions" and p.get(ptype):
  141. perms["apply_user_permissions"][ptype] = (perms["apply_user_permissions"].get(ptype, 1)
  142. and p.get("apply_user_permissions"))
  143. if p.if_owner and p.get(ptype):
  144. perms["if_owner"][ptype] = 1
  145. if p.get(ptype) and not p.if_owner and not p.get("apply_user_permissions"):
  146. dont_match.append(ptype)
  147. if p.apply_user_permissions:
  148. has_a_role_with_apply_user_permissions = True
  149. if p.user_permission_doctypes:
  150. # set user_permission_doctypes in perms
  151. user_permission_doctypes = json.loads(p.user_permission_doctypes)
  152. else:
  153. user_permission_doctypes = get_linked_doctypes(meta.name)
  154. if user_permission_doctypes:
  155. # perms["user_permission_doctypes"][ptype] would be a list of list like [["User", "Blog Post"], ["User"]]
  156. for ptype in rights:
  157. if p.get(ptype):
  158. perms["user_permission_doctypes"].setdefault(ptype, []).append(user_permission_doctypes)
  159. # if atleast one record having both Apply User Permission and If Owner unchecked is found,
  160. # don't match for those rights
  161. for ptype in rights:
  162. if ptype in dont_match:
  163. if perms["apply_user_permissions"].get(ptype):
  164. del perms["apply_user_permissions"][ptype]
  165. if perms["if_owner"].get(ptype):
  166. del perms["if_owner"][ptype]
  167. # if one row has only "Apply User Permissions" checked and another has only "If Owner" checked,
  168. # set Apply User Permissions as checked
  169. # i.e. the case when there is a role with apply_user_permissions as 1, but resultant apply_user_permissions is 0
  170. if has_a_role_with_apply_user_permissions:
  171. for ptype in rights:
  172. if perms["if_owner"].get(ptype) and perms["apply_user_permissions"].get(ptype)==0:
  173. perms["apply_user_permissions"][ptype] = 1
  174. # delete 0 values
  175. for key, value in perms.get("apply_user_permissions").items():
  176. if not value:
  177. del perms["apply_user_permissions"][key]
  178. frappe.local.role_permissions[cache_key] = perms
  179. return frappe.local.role_permissions[cache_key]
  180. def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=None):
  181. from frappe.defaults import get_user_permissions
  182. user_permissions = get_user_permissions(user)
  183. user_permission_doctypes = get_user_permission_doctypes(user_permission_doctypes, user_permissions)
  184. def check_user_permission(d):
  185. meta = frappe.get_meta(d.get("doctype"))
  186. end_result = False
  187. messages = {}
  188. # check multiple sets of user_permission_doctypes using OR condition
  189. for doctypes in user_permission_doctypes:
  190. result = True
  191. for df in meta.get_fields_to_check_permissions(doctypes):
  192. if (d.get(df.fieldname)
  193. and d.get(df.fieldname) not in user_permissions.get(df.options, [])):
  194. result = False
  195. if verbose:
  196. msg = _("Not allowed to access {0} with {1} = {2}").format(df.options, _(df.label), d.get(df.fieldname))
  197. if d.parentfield:
  198. msg = "{doctype}, {row} #{idx}, ".format(doctype=_(d.doctype),
  199. row=_("Row"), idx=d.idx) + msg
  200. messages[df.fieldname] = msg
  201. end_result = end_result or result
  202. if not end_result and messages:
  203. for fieldname, msg in messages.items():
  204. msgprint(msg)
  205. return end_result
  206. _user_has_permission = check_user_permission(doc)
  207. for d in doc.get_all_children():
  208. _user_has_permission = check_user_permission(d) and _user_has_permission
  209. return _user_has_permission
  210. def has_controller_permissions(doc, ptype, user=None):
  211. """Returns controller permissions if defined. None if not defined"""
  212. if not user: user = frappe.session.user
  213. methods = frappe.get_hooks("has_permission").get(doc.doctype, [])
  214. if not methods:
  215. return None
  216. for method in methods:
  217. controller_permission = frappe.call(frappe.get_attr(method), doc=doc, ptype=ptype, user=user)
  218. if controller_permission is not None:
  219. return controller_permission
  220. # controller permissions could not decide on True or False
  221. return None
  222. def can_set_user_permissions(doctype, docname=None):
  223. # System Manager can always set user permissions
  224. if "System Manager" in frappe.get_roles():
  225. return True
  226. meta = frappe.get_meta(doctype)
  227. # check if current user has read permission for docname
  228. if docname and not has_permission(doctype, "read", docname):
  229. return False
  230. # check if current user has a role that can set permission
  231. if get_role_permissions(meta).set_user_permissions!=1:
  232. return False
  233. return True
  234. def set_user_permission_if_allowed(doctype, name, user, with_message=False):
  235. if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1:
  236. add_user_permission(doctype, name, user, with_message)
  237. def add_user_permission(doctype, name, user, with_message=False):
  238. if name not in frappe.defaults.get_user_permissions(user).get(doctype, []):
  239. if not frappe.db.exists(doctype, name):
  240. frappe.throw(_("{0} {1} not found").format(_(doctype), name), frappe.DoesNotExistError)
  241. frappe.defaults.add_default(doctype, name, user, "User Permission")
  242. elif with_message:
  243. msgprint(_("Permission already set"))
  244. def remove_user_permission(doctype, name, user, default_value_name=None):
  245. frappe.defaults.clear_default(key=doctype, value=name, parent=user, parenttype="User Permission",
  246. name=default_value_name)
  247. def clear_user_permissions_for_doctype(doctype):
  248. frappe.defaults.clear_default(parenttype="User Permission", key=doctype)
  249. def can_import(doctype, raise_exception=False):
  250. if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")):
  251. if raise_exception:
  252. raise frappe.PermissionError("You are not allowed to import: {doctype}".format(doctype=doctype))
  253. else:
  254. return False
  255. return True
  256. def can_export(doctype, raise_exception=False):
  257. if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "export")):
  258. if raise_exception:
  259. raise frappe.PermissionError("You are not allowed to export: {doctype}".format(doctype=doctype))
  260. else:
  261. return False
  262. return True
  263. def apply_user_permissions(doctype, ptype, user=None):
  264. """Check if apply_user_permissions is checked for a doctype, perm type, user combination"""
  265. role_permissions = get_role_permissions(frappe.get_meta(doctype), user=user)
  266. return role_permissions.get("apply_user_permissions", {}).get(ptype)
  267. def get_user_permission_doctypes(user_permission_doctypes, user_permissions):
  268. """returns a list of list like [["User", "Blog Post"], ["User"]]"""
  269. if cint(frappe.db.get_single_value("System Settings", "ignore_user_permissions_if_missing")):
  270. # select those user permission doctypes for which user permissions exist!
  271. user_permission_doctypes = [list(set(doctypes).intersection(set(user_permissions.keys())))
  272. for doctypes in user_permission_doctypes]
  273. if len(user_permission_doctypes) > 1:
  274. # OPTIMIZATION
  275. # if intersection exists, use that to reduce the amount of querying
  276. # for example, [["Blogger", "Blog Category"], ["Blogger"]], should only search in [["Blogger"]] as the first and condition becomes redundant
  277. common = user_permission_doctypes[0]
  278. for i in xrange(1, len(user_permission_doctypes), 1):
  279. common = list(set(common).intersection(set(user_permission_doctypes[i])))
  280. if not common:
  281. break
  282. if common:
  283. # is common one of the user_permission_doctypes set?
  284. for doctypes in user_permission_doctypes:
  285. # are these lists equal?
  286. if set(common) == set(doctypes):
  287. user_permission_doctypes = [common]
  288. break
  289. return user_permission_doctypes
  290. def reset_perms(doctype):
  291. """Reset permissions for given doctype."""
  292. from frappe.desk.notifications import delete_notification_count_for
  293. delete_notification_count_for(doctype)
  294. frappe.db.sql("""delete from tabDocPerm where parent=%s""", doctype)
  295. frappe.reload_doc(frappe.db.get_value("DocType", doctype, "module"),
  296. "DocType", doctype, force=True)
  297. def get_linked_doctypes(dt):
  298. return list(set([dt] + [d.options for d in
  299. frappe.get_meta(dt).get("fields", {
  300. "fieldtype":"Link",
  301. "ignore_user_permissions":("!=", 1),
  302. "options": ("!=", "[Select]")
  303. })
  304. ]))