# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt from __future__ import unicode_literals import frappe from frappe import _ from frappe.desk.form.document_follow import follow_document from frappe.desk.doctype.notification_log.notification_log import enqueue_create_notification from frappe.utils import cint @frappe.whitelist() def add(doctype, name, user=None, read=1, write=0, share=0, everyone=0, flags=None): """Share the given document with a user.""" if not user: user = frappe.session.user if not (flags or {}).get("ignore_share_permission"): check_share_permission(doctype, name) share_name = get_share_name(doctype, name, user, everyone) if share_name: doc = frappe.get_doc("DocShare", share_name) else: doc = frappe.new_doc("DocShare") doc.update({ "user": user, "share_doctype": doctype, "share_name": name, "everyone": cint(everyone) }) if flags: doc.flags.update(flags) doc.update({ # always add read, since you are adding! "read": 1, "write": cint(write), "share": cint(share) }) doc.save(ignore_permissions=True) notify_assignment(user, doctype, name, everyone) follow_document(doctype, name, user) return doc def remove(doctype, name, user, flags=None): share_name = frappe.db.get_value("DocShare", {"user": user, "share_name": name, "share_doctype": doctype}) if share_name: frappe.delete_doc("DocShare", share_name, flags=flags) @frappe.whitelist() def set_permission(doctype, name, user, permission_to, value=1, everyone=0): """Set share permission.""" check_share_permission(doctype, name) share_name = get_share_name(doctype, name, user, everyone) value = int(value) if not share_name: if value: share = add(doctype, name, user, everyone=everyone, **{permission_to: 1}) else: # no share found, nothing to remove share = {} pass else: share = frappe.get_doc("DocShare", share_name) share.flags.ignore_permissions = True share.set(permission_to, value) if not value: # un-set higher-order permissions too if permission_to=="read": share.read = share.write = share.share = 0 share.save() if not (share.read or share.write or share.share): share.delete() share = {} return share @frappe.whitelist() def get_users(doctype, name): """Get list of users with which this document is shared""" return frappe.db.sql("""select `name`, `user`, `read`, `write`, `share`, `everyone` from `tabDocShare` where share_doctype=%s and share_name=%s""", (doctype, name), as_dict=True) def get_shared(doctype, user=None, rights=None): """Get list of shared document names for given user and DocType. :param doctype: DocType of which shared names are queried. :param user: User for which shared names are queried. :param rights: List of rights for which the document is shared. List of `read`, `write`, `share`""" if not user: user = frappe.session.user if not rights: rights = ["read"] filters = [[right, '=', 1] for right in rights] filters += [['share_doctype', '=', doctype]] or_filters = [['user', '=', user]] if user != 'Guest': or_filters += [['everyone', '=', 1]] shared_docs = frappe.db.get_all('DocShare', fields=['share_name'], filters=filters, or_filters=or_filters) return [doc.share_name for doc in shared_docs] def get_shared_doctypes(user=None): """Return list of doctypes in which documents are shared for the given user.""" if not user: user = frappe.session.user return frappe.db.sql_list("select distinct share_doctype from tabDocShare where (user=%s or everyone=1)", user) def get_share_name(doctype, name, user, everyone): if cint(everyone): share_name = frappe.db.get_value("DocShare", {"everyone": 1, "share_name": name, "share_doctype": doctype}) else: share_name = frappe.db.get_value("DocShare", {"user": user, "share_name": name, "share_doctype": doctype}) return share_name def check_share_permission(doctype, name): """Check if the user can share with other users""" if not frappe.has_permission(doctype, ptype="share", doc=name): frappe.throw(_("No permission to {0} {1} {2}".format("share", doctype, name)), frappe.PermissionError) def notify_assignment(shared_by, doctype, doc_name, everyone): if not (shared_by and doctype and doc_name) or everyone: return from frappe.utils import get_fullname title_field = frappe.get_meta(doctype).get_title_field() title = doc_name if title_field == "name" else \ frappe.db.get_value(doctype, doc_name, title_field) reference_user = get_fullname(frappe.session.user) notification_message = _('{0} shared a document {1} {2} with you').format( frappe.bold(reference_user), frappe.bold(doctype), frappe.bold(title)) notification_doc = { 'type': 'Share', 'document_type': doctype, 'subject': notification_message, 'document_name': doc_name, 'from_user': frappe.session.user } enqueue_create_notification(shared_by, notification_doc)