You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

228 line
5.8 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # License: MIT. See LICENSE
  3. import frappe
  4. from frappe import _
  5. from frappe.desk.doctype.notification_log.notification_log import (
  6. enqueue_create_notification,
  7. get_title,
  8. get_title_html,
  9. )
  10. from frappe.desk.form.document_follow import follow_document
  11. from frappe.utils import cint
  12. @frappe.whitelist()
  13. def add(doctype, name, user=None, read=1, write=0, submit=0, share=0, everyone=0, notify=0):
  14. """Expose function without flags to the client-side"""
  15. return add_docshare(
  16. doctype,
  17. name,
  18. user=user,
  19. read=read,
  20. write=write,
  21. submit=submit,
  22. share=share,
  23. everyone=everyone,
  24. notify=notify,
  25. )
  26. def add_docshare(
  27. doctype, name, user=None, read=1, write=0, submit=0, share=0, everyone=0, flags=None, notify=0
  28. ):
  29. """Share the given document with a user."""
  30. if not user:
  31. user = frappe.session.user
  32. if not (flags or {}).get("ignore_share_permission"):
  33. check_share_permission(doctype, name)
  34. share_name = get_share_name(doctype, name, user, everyone)
  35. if share_name:
  36. doc = frappe.get_doc("DocShare", share_name)
  37. else:
  38. doc = frappe.new_doc("DocShare")
  39. doc.update(
  40. {"user": user, "share_doctype": doctype, "share_name": name, "everyone": cint(everyone)}
  41. )
  42. if flags:
  43. doc.flags.update(flags)
  44. doc.update(
  45. {
  46. # always add read, since you are adding!
  47. "read": 1,
  48. "write": cint(write),
  49. "submit": cint(submit),
  50. "share": cint(share),
  51. }
  52. )
  53. doc.save(ignore_permissions=True)
  54. notify_assignment(user, doctype, name, everyone, notify=notify)
  55. if frappe.get_cached_value("User", user, "follow_shared_documents"):
  56. follow_document(doctype, name, user)
  57. return doc
  58. def remove(doctype, name, user, flags=None):
  59. share_name = frappe.db.get_value(
  60. "DocShare", {"user": user, "share_name": name, "share_doctype": doctype}
  61. )
  62. if share_name:
  63. frappe.delete_doc("DocShare", share_name, flags=flags)
  64. @frappe.whitelist()
  65. def set_permission(doctype, name, user, permission_to, value=1, everyone=0):
  66. """Expose function without flags to the client-side"""
  67. set_docshare_permission(doctype, name, user, permission_to, value=value, everyone=everyone)
  68. def set_docshare_permission(doctype, name, user, permission_to, value=1, everyone=0, flags=None):
  69. """Set share permission."""
  70. if not (flags or {}).get("ignore_share_permission"):
  71. check_share_permission(doctype, name)
  72. share_name = get_share_name(doctype, name, user, everyone)
  73. value = int(value)
  74. if not share_name:
  75. if value:
  76. share = add_docshare(doctype, name, user, everyone=everyone, **{permission_to: 1}, flags=flags)
  77. else:
  78. # no share found, nothing to remove
  79. share = {}
  80. pass
  81. else:
  82. share = frappe.get_doc("DocShare", share_name)
  83. if flags:
  84. share.flags.update(flags)
  85. share.flags.ignore_permissions = True
  86. share.set(permission_to, value)
  87. if not value:
  88. # un-set higher-order permissions too
  89. if permission_to == "read":
  90. share.read = share.write = share.submit = share.share = 0
  91. share.save()
  92. if not (share.read or share.write or share.submit or share.share):
  93. share.delete()
  94. share = None
  95. return share
  96. @frappe.whitelist()
  97. def get_users(doctype, name):
  98. """Get list of users with which this document is shared"""
  99. return frappe.get_all(
  100. "DocShare",
  101. fields=[
  102. "`name`",
  103. "`user`",
  104. "`read`",
  105. "`write`",
  106. "`submit`",
  107. "`share`",
  108. "everyone",
  109. "owner",
  110. "creation",
  111. ],
  112. filters=dict(share_doctype=doctype, share_name=name),
  113. )
  114. def get_shared(doctype, user=None, rights=None):
  115. """Get list of shared document names for given user and DocType.
  116. :param doctype: DocType of which shared names are queried.
  117. :param user: User for which shared names are queried.
  118. :param rights: List of rights for which the document is shared. List of `read`, `write`, `share`"""
  119. if not user:
  120. user = frappe.session.user
  121. if not rights:
  122. rights = ["read"]
  123. filters = [[right, "=", 1] for right in rights]
  124. filters += [["share_doctype", "=", doctype]]
  125. or_filters = [["user", "=", user]]
  126. if user != "Guest":
  127. or_filters += [["everyone", "=", 1]]
  128. shared_docs = frappe.get_all(
  129. "DocShare", fields=["share_name"], filters=filters, or_filters=or_filters
  130. )
  131. return [doc.share_name for doc in shared_docs]
  132. def get_shared_doctypes(user=None):
  133. """Return list of doctypes in which documents are shared for the given user."""
  134. if not user:
  135. user = frappe.session.user
  136. table = frappe.qb.DocType("DocShare")
  137. query = (
  138. frappe.qb.from_(table)
  139. .where((table.user == user) | (table.everyone == 1))
  140. .select(table.share_doctype)
  141. .distinct()
  142. )
  143. return query.run(pluck=True)
  144. def get_share_name(doctype, name, user, everyone):
  145. if cint(everyone):
  146. share_name = frappe.db.get_value(
  147. "DocShare", {"everyone": 1, "share_name": name, "share_doctype": doctype}
  148. )
  149. else:
  150. share_name = frappe.db.get_value(
  151. "DocShare", {"user": user, "share_name": name, "share_doctype": doctype}
  152. )
  153. return share_name
  154. def check_share_permission(doctype, name):
  155. """Check if the user can share with other users"""
  156. if not frappe.has_permission(doctype, ptype="share", doc=name):
  157. frappe.throw(
  158. _("No permission to {0} {1} {2}").format("share", _(doctype), name), frappe.PermissionError
  159. )
  160. def notify_assignment(shared_by, doctype, doc_name, everyone, notify=0):
  161. if not (shared_by and doctype and doc_name) or everyone or not notify:
  162. return
  163. from frappe.utils import get_fullname
  164. title = get_title(doctype, doc_name)
  165. reference_user = get_fullname(frappe.session.user)
  166. notification_message = _("{0} shared a document {1} {2} with you").format(
  167. frappe.bold(reference_user), frappe.bold(_(doctype)), get_title_html(title)
  168. )
  169. notification_doc = {
  170. "type": "Share",
  171. "document_type": doctype,
  172. "subject": notification_message,
  173. "document_name": doc_name,
  174. "from_user": frappe.session.user,
  175. }
  176. enqueue_create_notification(shared_by, notification_doc)