Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

597 righe
20 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # License: MIT. See LICENSE
  3. import copy
  4. import frappe
  5. import frappe.share
  6. from frappe import _, msgprint
  7. from frappe.utils import cint
  8. from frappe.query_builder import DocType
  9. rights = ("select", "read", "write", "create", "delete", "submit", "cancel", "amend",
  10. "print", "email", "report", "import", "export", "set_user_permissions", "share")
  11. def check_admin_or_system_manager(user=None):
  12. if not user: user = frappe.session.user
  13. if ("System Manager" not in frappe.get_roles(user)) and (user!="Administrator"):
  14. frappe.throw(_("Not permitted"), frappe.PermissionError)
  15. def print_has_permission_check_logs(func):
  16. def inner(*args, **kwargs):
  17. frappe.flags['has_permission_check_logs'] = []
  18. result = func(*args, **kwargs)
  19. self_perm_check = True if not kwargs.get('user') else kwargs.get('user') == frappe.session.user
  20. raise_exception = False if kwargs.get('raise_exception') == False else True
  21. # print only if access denied
  22. # and if user is checking his own permission
  23. if not result and self_perm_check and raise_exception:
  24. msgprint(('<br>').join(frappe.flags.get('has_permission_check_logs', [])))
  25. frappe.flags.pop('has_permission_check_logs', None)
  26. return result
  27. return inner
  28. @print_has_permission_check_logs
  29. def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None, raise_exception=True, parent_doctype=None):
  30. """Returns True if user has permission `ptype` for given `doctype`.
  31. If `doc` is passed, it also checks user, share and owner permissions.
  32. Note: if Table DocType is passed, it always returns True.
  33. """
  34. if not user: user = frappe.session.user
  35. if not doc and hasattr(doctype, 'doctype'):
  36. # first argument can be doc or doctype
  37. doc = doctype
  38. doctype = doc.doctype
  39. if user == "Administrator":
  40. return True
  41. if frappe.is_table(doctype):
  42. return has_child_table_permission(doctype, ptype, doc, verbose,
  43. user, raise_exception, parent_doctype)
  44. meta = frappe.get_meta(doctype)
  45. if doc:
  46. if isinstance(doc, str):
  47. doc = frappe.get_doc(meta.name, doc)
  48. perm = get_doc_permissions(doc, user=user, ptype=ptype).get(ptype)
  49. if not perm: push_perm_check_log(_('User {0} does not have access to this document').format(frappe.bold(user)))
  50. else:
  51. if ptype=="submit" and not cint(meta.is_submittable):
  52. push_perm_check_log(_("Document Type is not submittable"))
  53. return False
  54. if ptype=="import" and not cint(meta.allow_import):
  55. push_perm_check_log(_("Document Type is not importable"))
  56. return False
  57. role_permissions = get_role_permissions(meta, user=user)
  58. perm = role_permissions.get(ptype)
  59. if not perm:
  60. push_perm_check_log(_('User {0} does not have doctype access via role permission for document {1}').format(frappe.bold(user), frappe.bold(doctype)))
  61. def false_if_not_shared():
  62. if ptype in ("read", "write", "share", "submit", "email", "print"):
  63. shared = frappe.share.get_shared(doctype, user,
  64. ["read" if ptype in ("email", "print") else ptype])
  65. if doc:
  66. doc_name = get_doc_name(doc)
  67. if doc_name in shared:
  68. if ptype in ("read", "write", "share", "submit") or meta.permissions[0].get(ptype):
  69. return True
  70. elif shared:
  71. # if atleast one shared doc of that type, then return True
  72. # this is used in db_query to check if permission on DocType
  73. return True
  74. return False
  75. if not perm:
  76. perm = false_if_not_shared()
  77. return bool(perm)
  78. def get_doc_permissions(doc, user=None, ptype=None):
  79. """Returns a dict of evaluated permissions for given `doc` like `{"read":1, "write":1}`"""
  80. if not user: user = frappe.session.user
  81. if frappe.is_table(doc.doctype): return {"read": 1, "write": 1}
  82. meta = frappe.get_meta(doc.doctype)
  83. def is_user_owner():
  84. return (doc.get("owner") or "").lower() == user.lower()
  85. if has_controller_permissions(doc, ptype, user=user) is False:
  86. push_perm_check_log('Not allowed via controller permission check')
  87. return {ptype: 0}
  88. permissions = copy.deepcopy(get_role_permissions(meta, user=user, is_owner=is_user_owner()))
  89. if not cint(meta.is_submittable):
  90. permissions["submit"] = 0
  91. if not cint(meta.allow_import):
  92. permissions["import"] = 0
  93. # Override with `if_owner` perms irrespective of user
  94. if permissions.get('has_if_owner_enabled'):
  95. # apply owner permissions on top of existing permissions
  96. # some access might be only for the owner
  97. # eg. everyone might have read access but only owner can delete
  98. permissions.update(permissions.get("if_owner", {}))
  99. if not has_user_permission(doc, user):
  100. if is_user_owner():
  101. # replace with owner permissions
  102. permissions = permissions.get("if_owner", {})
  103. # if_owner does not come with create rights...
  104. permissions['create'] = 0
  105. else:
  106. permissions = {}
  107. return permissions
  108. def get_role_permissions(doctype_meta, user=None, is_owner=None):
  109. """
  110. Returns dict of evaluated role permissions like
  111. {
  112. "read": 1,
  113. "write": 0,
  114. // if "if_owner" is enabled
  115. "if_owner":
  116. {
  117. "read": 1,
  118. "write": 0
  119. }
  120. }
  121. """
  122. if isinstance(doctype_meta, str):
  123. doctype_meta = frappe.get_meta(doctype_meta) # assuming doctype name was passed
  124. if not user: user = frappe.session.user
  125. cache_key = (doctype_meta.name, user)
  126. if user == 'Administrator':
  127. return allow_everything()
  128. if not frappe.local.role_permissions.get(cache_key):
  129. perms = frappe._dict(
  130. if_owner={}
  131. )
  132. roles = frappe.get_roles(user)
  133. def is_perm_applicable(perm):
  134. return perm.role in roles and cint(perm.permlevel)==0
  135. def has_permission_without_if_owner_enabled(ptype):
  136. return any(p.get(ptype, 0) and not p.get('if_owner', 0) for p in applicable_permissions)
  137. applicable_permissions = list(filter(is_perm_applicable, getattr(doctype_meta, 'permissions', [])))
  138. has_if_owner_enabled = any(p.get('if_owner', 0) for p in applicable_permissions)
  139. perms['has_if_owner_enabled'] = has_if_owner_enabled
  140. for ptype in rights:
  141. pvalue = any(p.get(ptype, 0) for p in applicable_permissions)
  142. # check if any perm object allows perm type
  143. perms[ptype] = cint(pvalue)
  144. if (
  145. pvalue
  146. and has_if_owner_enabled
  147. and not has_permission_without_if_owner_enabled(ptype)
  148. and ptype != 'create'
  149. ):
  150. perms['if_owner'][ptype] = cint(pvalue and is_owner)
  151. # has no access if not owner
  152. # only provide select or read access so that user is able to at-least access list
  153. # (and the documents will be filtered based on owner sin further checks)
  154. perms[ptype] = 1 if ptype in ('select', 'read') else 0
  155. frappe.local.role_permissions[cache_key] = perms
  156. return frappe.local.role_permissions[cache_key]
  157. def get_user_permissions(user):
  158. from frappe.core.doctype.user_permission.user_permission import get_user_permissions
  159. return get_user_permissions(user)
  160. def has_user_permission(doc, user=None):
  161. '''Returns True if User is allowed to view considering User Permissions'''
  162. from frappe.core.doctype.user_permission.user_permission import get_user_permissions
  163. user_permissions = get_user_permissions(user)
  164. if not user_permissions:
  165. # no user permission rules specified for this doctype
  166. return True
  167. # user can create own role permissions, so nothing applies
  168. if get_role_permissions('User Permission', user=user).get('write'):
  169. return True
  170. apply_strict_user_permissions = frappe.get_system_settings('apply_strict_user_permissions')
  171. doctype = doc.get('doctype')
  172. docname = doc.get('name')
  173. # STEP 1: ---------------------
  174. # check user permissions on self
  175. if doctype in user_permissions:
  176. allowed_docs = get_allowed_docs_for_doctype(user_permissions.get(doctype, []), doctype)
  177. # if allowed_docs is empty it states that there is no applicable permission under the current doctype
  178. # only check if allowed_docs is not empty
  179. if allowed_docs and docname not in allowed_docs:
  180. # no user permissions for this doc specified
  181. push_perm_check_log(_('Not allowed for {0}: {1}').format(_(doctype), docname))
  182. return False
  183. # STEP 2: ---------------------------------
  184. # check user permissions in all link fields
  185. def check_user_permission_on_link_fields(d):
  186. # check user permissions for all the link fields of the given
  187. # document object d
  188. #
  189. # called for both parent and child records
  190. meta = frappe.get_meta(d.get("doctype"))
  191. # check all link fields for user permissions
  192. for field in meta.get_link_fields():
  193. if field.ignore_user_permissions: continue
  194. # empty value, do you still want to apply user permissions?
  195. if not d.get(field.fieldname) and not apply_strict_user_permissions:
  196. # nah, not strict
  197. continue
  198. if field.options not in user_permissions:
  199. continue
  200. # get the list of all allowed values for this link
  201. allowed_docs = get_allowed_docs_for_doctype(user_permissions.get(field.options, []), doctype)
  202. if allowed_docs and d.get(field.fieldname) not in allowed_docs:
  203. # restricted for this link field, and no matching values found
  204. # make the right message and exit
  205. if d.get('parentfield'):
  206. # "Not allowed for Company = Restricted Company in Row 3. Restricted field: reference_type"
  207. msg = _('Not allowed for {0}: {1} in Row {2}. Restricted field: {3}').format(
  208. _(field.options), d.get(field.fieldname), d.idx, field.fieldname)
  209. else:
  210. # "Not allowed for Company = Restricted Company. Restricted field: reference_type"
  211. msg = _('Not allowed for {0}: {1}. Restricted field: {2}').format(
  212. _(field.options), d.get(field.fieldname), field.fieldname)
  213. push_perm_check_log(msg)
  214. return False
  215. return True
  216. if not check_user_permission_on_link_fields(doc):
  217. return False
  218. for d in doc.get_all_children():
  219. if not check_user_permission_on_link_fields(d):
  220. return False
  221. return True
  222. def has_controller_permissions(doc, ptype, user=None):
  223. """Returns controller permissions if defined. None if not defined"""
  224. if not user: user = frappe.session.user
  225. methods = frappe.get_hooks("has_permission").get(doc.doctype, [])
  226. if not methods:
  227. return None
  228. for method in reversed(methods):
  229. controller_permission = frappe.call(frappe.get_attr(method), doc=doc, ptype=ptype, user=user)
  230. if controller_permission is not None:
  231. return controller_permission
  232. # controller permissions could not decide on True or False
  233. return None
  234. def get_doctypes_with_read():
  235. return list({p.parent if type(p.parent) == str else p.parent.encode('UTF8') for p in get_valid_perms()})
  236. def get_valid_perms(doctype=None, user=None):
  237. '''Get valid permissions for the current user from DocPerm and Custom DocPerm'''
  238. roles = get_roles(user)
  239. perms = get_perms_for(roles)
  240. custom_perms = get_perms_for(roles, 'Custom DocPerm')
  241. doctypes_with_custom_perms = get_doctypes_with_custom_docperms()
  242. for p in perms:
  243. if not p.parent in doctypes_with_custom_perms:
  244. custom_perms.append(p)
  245. if doctype:
  246. return [p for p in custom_perms if p.parent == doctype]
  247. else:
  248. return custom_perms
  249. def get_all_perms(role):
  250. '''Returns valid permissions for a given role'''
  251. perms = frappe.get_all('DocPerm', fields='*', filters=dict(role=role))
  252. custom_perms = frappe.get_all('Custom DocPerm', fields='*', filters=dict(role=role))
  253. doctypes_with_custom_perms = frappe.get_all("Custom DocPerm", pluck="parent", distinct=True)
  254. for p in perms:
  255. if p.parent not in doctypes_with_custom_perms:
  256. custom_perms.append(p)
  257. return custom_perms
  258. def get_roles(user=None, with_standard=True):
  259. """get roles of current user"""
  260. if not user:
  261. user = frappe.session.user
  262. if user=='Guest':
  263. return ['Guest']
  264. def get():
  265. if user == 'Administrator':
  266. return frappe.get_all("Role", pluck="name") # return all available roles
  267. else:
  268. table = DocType("Has Role")
  269. roles = frappe.qb.from_(table).where(
  270. (table.parent == user) & (table.role.notin(["All", "Guest"]))
  271. ).select(table.role).run(pluck=True)
  272. return roles + ['All', 'Guest']
  273. roles = frappe.cache().hget("roles", user, get)
  274. # filter standard if required
  275. if not with_standard:
  276. roles = filter(lambda x: x not in ['All', 'Guest', 'Administrator'], roles)
  277. return roles
  278. def get_doctype_roles(doctype, access_type="read"):
  279. """Returns a list of roles that are allowed to access passed doctype."""
  280. meta = frappe.get_meta(doctype)
  281. return [d.role for d in meta.get("permissions") if d.get(access_type)]
  282. def get_perms_for(roles, perm_doctype='DocPerm'):
  283. '''Get perms for given roles'''
  284. filters = {
  285. 'permlevel': 0,
  286. 'docstatus': 0,
  287. 'role': ['in', roles]
  288. }
  289. return frappe.db.get_all(perm_doctype, fields=['*'], filters=filters)
  290. def get_doctypes_with_custom_docperms():
  291. '''Returns all the doctypes with Custom Docperms'''
  292. doctypes = frappe.db.get_all('Custom DocPerm', fields=['parent'], distinct=1)
  293. return [d.parent for d in doctypes]
  294. def can_set_user_permissions(doctype, docname=None):
  295. # System Manager can always set user permissions
  296. if frappe.session.user == "Administrator" or "System Manager" in frappe.get_roles():
  297. return True
  298. meta = frappe.get_meta(doctype)
  299. # check if current user has read permission for docname
  300. if docname and not has_permission(doctype, "read", docname):
  301. return False
  302. # check if current user has a role that can set permission
  303. if get_role_permissions(meta).set_user_permissions!=1:
  304. return False
  305. return True
  306. def set_user_permission_if_allowed(doctype, name, user, with_message=False):
  307. if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1:
  308. add_user_permission(doctype, name, user)
  309. def add_user_permission(doctype, name, user, ignore_permissions=False, applicable_for=None,
  310. is_default=0, hide_descendants=0):
  311. '''Add user permission'''
  312. from frappe.core.doctype.user_permission.user_permission import user_permission_exists
  313. if not user_permission_exists(user, doctype, name, applicable_for):
  314. if not frappe.db.exists(doctype, name):
  315. frappe.throw(_("{0} {1} not found").format(_(doctype), name), frappe.DoesNotExistError)
  316. frappe.get_doc(dict(
  317. doctype='User Permission',
  318. user=user,
  319. allow=doctype,
  320. for_value=name,
  321. is_default=is_default,
  322. applicable_for=applicable_for,
  323. hide_descendants=hide_descendants,
  324. )).insert(ignore_permissions=ignore_permissions)
  325. def remove_user_permission(doctype, name, user):
  326. user_permission_name = frappe.db.get_value('User Permission',
  327. dict(user=user, allow=doctype, for_value=name))
  328. frappe.delete_doc('User Permission', user_permission_name)
  329. def clear_user_permissions_for_doctype(doctype, user=None):
  330. filters = {'allow': doctype}
  331. if user:
  332. filters['user'] = user
  333. user_permissions_for_doctype = frappe.db.get_all('User Permission', filters=filters)
  334. for d in user_permissions_for_doctype:
  335. frappe.delete_doc('User Permission', d.name)
  336. def can_import(doctype, raise_exception=False):
  337. if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")):
  338. if raise_exception:
  339. raise frappe.PermissionError("You are not allowed to import: {doctype}".format(doctype=doctype))
  340. else:
  341. return False
  342. return True
  343. def can_export(doctype, raise_exception=False):
  344. if "System Manager" in frappe.get_roles():
  345. return True
  346. else:
  347. role_permissions = frappe.permissions.get_role_permissions(doctype)
  348. has_access = role_permissions.get('export') or \
  349. role_permissions.get('if_owner').get('export')
  350. if not has_access and raise_exception:
  351. raise frappe.PermissionError(_("You are not allowed to export {} doctype").format(doctype))
  352. return has_access
  353. def update_permission_property(doctype, role, permlevel, ptype, value=None, validate=True):
  354. '''Update a property in Custom Perm'''
  355. from frappe.core.doctype.doctype.doctype import validate_permissions_for_doctype
  356. out = setup_custom_perms(doctype)
  357. name = frappe.get_value('Custom DocPerm', dict(parent=doctype, role=role,
  358. permlevel=permlevel))
  359. table = DocType("Custom DocPerm")
  360. frappe.qb.update(table).set(ptype, value).where(table.name == name).run()
  361. if validate:
  362. validate_permissions_for_doctype(doctype)
  363. return out
  364. def setup_custom_perms(parent):
  365. '''if custom permssions are not setup for the current doctype, set them up'''
  366. if not frappe.db.exists('Custom DocPerm', dict(parent=parent)):
  367. copy_perms(parent)
  368. return True
  369. def add_permission(doctype, role, permlevel=0, ptype=None):
  370. '''Add a new permission rule to the given doctype
  371. for the given Role and Permission Level'''
  372. from frappe.core.doctype.doctype.doctype import validate_permissions_for_doctype
  373. setup_custom_perms(doctype)
  374. if frappe.db.get_value('Custom DocPerm', dict(parent=doctype, role=role,
  375. permlevel=permlevel, if_owner=0)):
  376. return
  377. if not ptype:
  378. ptype = 'read'
  379. custom_docperm = frappe.get_doc({
  380. "doctype":"Custom DocPerm",
  381. "__islocal": 1,
  382. "parent": doctype,
  383. "parenttype": "DocType",
  384. "parentfield": "permissions",
  385. "role": role,
  386. "permlevel": permlevel,
  387. ptype: 1,
  388. })
  389. custom_docperm.save()
  390. validate_permissions_for_doctype(doctype)
  391. return custom_docperm.name
  392. def copy_perms(parent):
  393. '''Copy all DocPerm in to Custom DocPerm for the given document'''
  394. for d in frappe.get_all('DocPerm', fields='*', filters=dict(parent=parent)):
  395. custom_perm = frappe.new_doc('Custom DocPerm')
  396. custom_perm.update(d)
  397. custom_perm.insert(ignore_permissions=True)
  398. def reset_perms(doctype):
  399. """Reset permissions for given doctype."""
  400. from frappe.desk.notifications import delete_notification_count_for
  401. delete_notification_count_for(doctype)
  402. frappe.db.delete("Custom DocPerm", {"parent": doctype})
  403. def get_linked_doctypes(dt):
  404. return list(set([dt] + [d.options for d in
  405. frappe.get_meta(dt).get("fields", {
  406. "fieldtype":"Link",
  407. "ignore_user_permissions":("!=", 1),
  408. "options": ("!=", "[Select]")
  409. })
  410. ]))
  411. def get_doc_name(doc):
  412. if not doc: return None
  413. return doc if isinstance(doc, str) else doc.name
  414. def allow_everything():
  415. '''
  416. returns a dict with access to everything
  417. eg. {"read": 1, "write": 1, ...}
  418. '''
  419. perm = {ptype: 1 for ptype in rights}
  420. return perm
  421. def get_allowed_docs_for_doctype(user_permissions, doctype):
  422. ''' Returns all the docs from the passed user_permissions that are
  423. allowed under provided doctype '''
  424. return filter_allowed_docs_for_doctype(user_permissions, doctype, with_default_doc=False)
  425. def filter_allowed_docs_for_doctype(user_permissions, doctype, with_default_doc=True):
  426. ''' Returns all the docs from the passed user_permissions that are
  427. allowed under provided doctype along with default doc value if with_default_doc is set '''
  428. allowed_doc = []
  429. default_doc = None
  430. for doc in user_permissions:
  431. if not doc.get('applicable_for') or doc.get('applicable_for') == doctype:
  432. allowed_doc.append(doc.get('doc'))
  433. if doc.get('is_default') or len(user_permissions) == 1 and with_default_doc:
  434. default_doc = doc.get('doc')
  435. return (allowed_doc, default_doc) if with_default_doc else allowed_doc
  436. def push_perm_check_log(log):
  437. if frappe.flags.get('has_permission_check_logs') is None:
  438. return
  439. frappe.flags.get('has_permission_check_logs').append(_(log))
  440. def has_child_table_permission(child_doctype, ptype="read", child_doc=None,
  441. verbose=False, user=None, raise_exception=True, parent_doctype=None):
  442. parent_doc = None
  443. if child_doc:
  444. parent_doctype = child_doc.get("parenttype")
  445. parent_doc = frappe.get_cached_doc({
  446. "doctype": parent_doctype,
  447. "docname": child_doc.get("parent")
  448. })
  449. if parent_doctype:
  450. if not is_parent_valid(child_doctype, parent_doctype):
  451. frappe.throw(_("{0} is not a valid parent DocType for {1}").format(
  452. frappe.bold(parent_doctype),
  453. frappe.bold(child_doctype)
  454. ), title=_("Invalid Parent DocType"))
  455. else:
  456. frappe.throw(_("Please specify a valid parent DocType for {0}").format(
  457. frappe.bold(child_doctype)
  458. ), title=_("Parent DocType Required"))
  459. return has_permission(parent_doctype, ptype=ptype, doc=parent_doc,
  460. verbose=verbose, user=user, raise_exception=raise_exception)
  461. def is_parent_valid(child_doctype, parent_doctype):
  462. from frappe.core.utils import find
  463. parent_meta = frappe.get_meta(parent_doctype)
  464. child_table_field_exists = find(parent_meta.get_table_fields(), lambda d: d.options == child_doctype)
  465. return not parent_meta.istable and child_table_field_exists