Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

469 rader
16 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(
  131. apply_user_permissions={},
  132. user_permission_doctypes={},
  133. if_owner={}
  134. )
  135. user_roles = frappe.get_roles(user)
  136. dont_match = []
  137. has_a_role_with_apply_user_permissions = False
  138. for p in meta.permissions:
  139. if cint(p.permlevel)==0 and (p.role in user_roles):
  140. # apply only for level 0
  141. for ptype in rights:
  142. # build if_owner dict if applicable for this right
  143. perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype))
  144. if ptype != "set_user_permissions" and p.get(ptype):
  145. perms["apply_user_permissions"][ptype] = (perms["apply_user_permissions"].get(ptype, 1)
  146. and p.get("apply_user_permissions"))
  147. if p.if_owner and p.get(ptype):
  148. perms["if_owner"][ptype] = 1
  149. if p.get(ptype) and not p.if_owner and not p.get("apply_user_permissions"):
  150. dont_match.append(ptype)
  151. if p.apply_user_permissions:
  152. has_a_role_with_apply_user_permissions = True
  153. if p.user_permission_doctypes:
  154. # set user_permission_doctypes in perms
  155. user_permission_doctypes = json.loads(p.user_permission_doctypes)
  156. else:
  157. user_permission_doctypes = get_linked_doctypes(meta.name)
  158. if user_permission_doctypes:
  159. # perms["user_permission_doctypes"][ptype] would be a list of list like [["User", "Blog Post"], ["User"]]
  160. for ptype in rights:
  161. if p.get(ptype):
  162. perms["user_permission_doctypes"].setdefault(ptype, []).append(user_permission_doctypes)
  163. # if atleast one record having both Apply User Permission and If Owner unchecked is found,
  164. # don't match for those rights
  165. for ptype in rights:
  166. if ptype in dont_match:
  167. if perms["apply_user_permissions"].get(ptype):
  168. del perms["apply_user_permissions"][ptype]
  169. if perms["if_owner"].get(ptype):
  170. del perms["if_owner"][ptype]
  171. # if one row has only "Apply User Permissions" checked and another has only "If Owner" checked,
  172. # set Apply User Permissions as checked
  173. # i.e. the case when there is a role with apply_user_permissions as 1, but resultant apply_user_permissions is 0
  174. if has_a_role_with_apply_user_permissions:
  175. for ptype in rights:
  176. if perms["if_owner"].get(ptype) and perms["apply_user_permissions"].get(ptype)==0:
  177. perms["apply_user_permissions"][ptype] = 1
  178. # delete 0 values
  179. for key, value in perms.get("apply_user_permissions").items():
  180. if not value:
  181. del perms["apply_user_permissions"][key]
  182. frappe.local.role_permissions[cache_key] = perms
  183. return frappe.local.role_permissions[cache_key]
  184. def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=None):
  185. from frappe.defaults import get_user_permissions
  186. user_permissions = get_user_permissions(user)
  187. user_permission_doctypes = get_user_permission_doctypes(user_permission_doctypes, user_permissions)
  188. def check_user_permission(d):
  189. meta = frappe.get_meta(d.get("doctype"))
  190. end_result = False
  191. messages = {}
  192. # check multiple sets of user_permission_doctypes using OR condition
  193. for doctypes in user_permission_doctypes:
  194. result = True
  195. for df in meta.get_fields_to_check_permissions(doctypes):
  196. if (d.get(df.fieldname)
  197. and d.get(df.fieldname) not in user_permissions.get(df.options, [])):
  198. result = False
  199. if verbose:
  200. msg = _("Not allowed to access {0} with {1} = {2}").format(df.options, _(df.label), d.get(df.fieldname))
  201. if d.parentfield:
  202. msg = "{doctype}, {row} #{idx}, ".format(doctype=_(d.doctype),
  203. row=_("Row"), idx=d.idx) + msg
  204. messages[df.fieldname] = msg
  205. end_result = end_result or result
  206. if not end_result and messages:
  207. for fieldname, msg in messages.items():
  208. msgprint(msg)
  209. return end_result
  210. _user_has_permission = check_user_permission(doc)
  211. for d in doc.get_all_children():
  212. _user_has_permission = check_user_permission(d) and _user_has_permission
  213. return _user_has_permission
  214. def has_controller_permissions(doc, ptype, user=None):
  215. """Returns controller permissions if defined. None if not defined"""
  216. if not user: user = frappe.session.user
  217. methods = frappe.get_hooks("has_permission").get(doc.doctype, [])
  218. if not methods:
  219. return None
  220. for method in methods:
  221. controller_permission = frappe.call(frappe.get_attr(method), doc=doc, ptype=ptype, user=user)
  222. if controller_permission is not None:
  223. return controller_permission
  224. # controller permissions could not decide on True or False
  225. return None
  226. def get_doctypes_with_read():
  227. return list(set([p.parent for p in get_valid_perms()]))
  228. def get_valid_perms(doctype=None):
  229. '''Get valid permissions for the current user from DocPerm and Custom DocPerm'''
  230. roles = get_roles()
  231. perms = get_perms_for(roles)
  232. custom_perms = get_perms_for(roles, 'Custom DocPerm')
  233. doctypes_with_custom_perms = list(set([d.parent for d in custom_perms]))
  234. for p in perms:
  235. if not p.parent in doctypes_with_custom_perms:
  236. custom_perms.append(p)
  237. if doctype:
  238. return [p for p in custom_perms if p.parent == doctype]
  239. else:
  240. return custom_perms
  241. def get_all_perms(role):
  242. '''Returns valid permissions for a given role'''
  243. perms = frappe.get_all('DocPerm', fields='*', filters=dict(role=role))
  244. custom_perms = frappe.get_all('Custom DocPerm', fields='*', filters=dict(role=role))
  245. doctypes_with_custom_perms = list(set(p.parent for p in custom_perms))
  246. for p in perms:
  247. if p.parent not in doctypes_with_custom_perms:
  248. custom_perms.append(p)
  249. return p
  250. def get_roles(user=None, with_standard=True):
  251. """get roles of current user"""
  252. if not user:
  253. user = frappe.session.user
  254. if user=='Guest':
  255. return ['Guest']
  256. def get():
  257. return [r[0] for r in frappe.db.sql("""select role from tabUserRole
  258. where parent=%s and role not in ('All', 'Guest')""", (user,))] + ['All', 'Guest']
  259. roles = frappe.cache().hget("roles", user, get)
  260. # filter standard if required
  261. if not with_standard:
  262. roles = filter(lambda x: x not in ['All', 'Guest', 'Administrator'], roles)
  263. return roles
  264. def get_perms_for(roles, perm_doctype='DocPerm'):
  265. '''Get perms for given roles'''
  266. return frappe.db.sql("""select * from `tab{doctype}` where docstatus=0
  267. and ifnull(permlevel,0)=0
  268. and role in ({roles})""".format(doctype = perm_doctype,
  269. roles=", ".join(["%s"]*len(roles))), tuple(roles), as_dict=1)
  270. def can_set_user_permissions(doctype, docname=None):
  271. # System Manager can always set user permissions
  272. if frappe.session.user == "Administrator" or "System Manager" in frappe.get_roles():
  273. return True
  274. meta = frappe.get_meta(doctype)
  275. # check if current user has read permission for docname
  276. if docname and not has_permission(doctype, "read", docname):
  277. return False
  278. # check if current user has a role that can set permission
  279. if get_role_permissions(meta).set_user_permissions!=1:
  280. return False
  281. return True
  282. def set_user_permission_if_allowed(doctype, name, user, with_message=False):
  283. if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1:
  284. add_user_permission(doctype, name, user, with_message)
  285. def add_user_permission(doctype, name, user, with_message=False):
  286. '''Add user default'''
  287. if name not in frappe.defaults.get_user_permissions(user).get(doctype, []):
  288. if not frappe.db.exists(doctype, name):
  289. frappe.throw(_("{0} {1} not found").format(_(doctype), name), frappe.DoesNotExistError)
  290. frappe.defaults.add_default(doctype, name, user, "User Permission")
  291. elif with_message:
  292. msgprint(_("Permission already set"))
  293. def remove_user_permission(doctype, name, user, default_value_name=None):
  294. frappe.defaults.clear_default(key=doctype, value=name, parent=user, parenttype="User Permission",
  295. name=default_value_name)
  296. def clear_user_permissions_for_doctype(doctype):
  297. frappe.defaults.clear_default(parenttype="User Permission", key=doctype)
  298. def can_import(doctype, raise_exception=False):
  299. if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")):
  300. if raise_exception:
  301. raise frappe.PermissionError("You are not allowed to import: {doctype}".format(doctype=doctype))
  302. else:
  303. return False
  304. return True
  305. def can_export(doctype, raise_exception=False):
  306. if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "export")):
  307. if raise_exception:
  308. raise frappe.PermissionError("You are not allowed to export: {doctype}".format(doctype=doctype))
  309. else:
  310. return False
  311. return True
  312. def apply_user_permissions(doctype, ptype, user=None):
  313. """Check if apply_user_permissions is checked for a doctype, perm type, user combination"""
  314. role_permissions = get_role_permissions(frappe.get_meta(doctype), user=user)
  315. return role_permissions.get("apply_user_permissions", {}).get(ptype)
  316. def get_user_permission_doctypes(user_permission_doctypes, user_permissions):
  317. """returns a list of list like [["User", "Blog Post"], ["User"]]"""
  318. if cint(frappe.db.get_single_value("System Settings", "ignore_user_permissions_if_missing")):
  319. # select those user permission doctypes for which user permissions exist!
  320. user_permission_doctypes = [list(set(doctypes).intersection(set(user_permissions.keys())))
  321. for doctypes in user_permission_doctypes]
  322. if len(user_permission_doctypes) > 1:
  323. # OPTIMIZATION
  324. # if intersection exists, use that to reduce the amount of querying
  325. # for example, [["Blogger", "Blog Category"], ["Blogger"]], should only search in [["Blogger"]] as the first and condition becomes redundant
  326. common = user_permission_doctypes[0]
  327. for i in xrange(1, len(user_permission_doctypes), 1):
  328. common = list(set(common).intersection(set(user_permission_doctypes[i])))
  329. if not common:
  330. break
  331. if common:
  332. # is common one of the user_permission_doctypes set?
  333. for doctypes in user_permission_doctypes:
  334. # are these lists equal?
  335. if set(common) == set(doctypes):
  336. user_permission_doctypes = [common]
  337. break
  338. return user_permission_doctypes
  339. def reset_perms(doctype):
  340. """Reset permissions for given doctype."""
  341. from frappe.desk.notifications import delete_notification_count_for
  342. delete_notification_count_for(doctype)
  343. frappe.db.sql("""delete from `tabCustom DocPerm` where parent=%s""", doctype)
  344. def get_linked_doctypes(dt):
  345. return list(set([dt] + [d.options for d in
  346. frappe.get_meta(dt).get("fields", {
  347. "fieldtype":"Link",
  348. "ignore_user_permissions":("!=", 1),
  349. "options": ("!=", "[Select]")
  350. })
  351. ]))