The DocShare Doctype in Frappe is a system-level Doctype used to record and manage explicit sharing of individual documents with specific users or with "Everyone". It underpins Frappe's document sharing feature, allowing for granular access control beyond the standard role-based permissions.
- To create a persistent record each time a document is shared with a user or made publicly accessible (shared with "Everyone").
- To define the specific permissions (read, write, share, submit) granted to the user for that particular document instance.
- To enable users to share documents they have access to with others, if they themselves have "share" permission on that document.
- To provide an audit trail of sharing activities through comments on the shared document.
docshare.json: Defines the schema (fields, properties, permissions) of the DocShare Doctype.docshare.py: Contains the server-side Python controller logic, handling validation, permission checks, and integration with the commenting system.docshare.js: The client-side JavaScript file for the DocShare form (which is minimal as users don't directly interact with these records).test_docshare.py: Contains unit tests for the sharing logic.
This JSON file outlines the structure for each DocShare record.
autoname: "hash"andnaming_rule`: "Random": Each DocShare record is given a unique system-generated hash ID.document_type: "System": Classified as a system-level Doctype.- Key Fields:
user(Link to User, In List View): The user with whom the document is being shared. This field is null if theeveryoneflag is checked.share_doctype(Link to DocType, Required, In List View): The Doctype of the document that is being shared (e.g., "Sales Invoice", "Project").share_name(Dynamic Link, Options:share_doctype, Required, In List View): The specific name (ID) of the document instance being shared (e.g., "SINV-0001", "PROJ-002").read(Check, Default: 0): Grants read access to the shared document.write(Check, Default: 0): Grants write/edit access.share(Check, Default: 0): Grants permission for the recipient user to further share the document with others.submit(Check, Default: 0): Grants permission to submit the document (if theshare_doctypeis submittable).everyone(Check, Default: 0): If checked, the document is shared with all users who have at least read access to theshare_doctypebased on role permissions. Theuserfield is typically ignored in this case.notify_by_email(Check, Default: 1): If checked, an email notification is sent to theuserwhen the document is shared with them.
in_create: 1: Users cannot manually create DocShare records. These are generated by the system when a document's "Share" dialog is used.read_only: 1: DocShare records are read-only after creation. To change sharing permissions, a user would typically un-share and then re-share with the new permissions from the source document.- Permissions (for DocShare Doctype itself):
- Only "System Manager" role has full CRUD permissions on DocShare records, primarily for administrative or debugging purposes.
track_changes: 1: Changes to DocShare records are versioned (though direct user changes are not typical).- Module: "Core"
The Python controller for DocShare handles validations and actions related to the sharing process.
DocShare(Document)Class:no_feed_on_delete = True: Prevents an Activity Log entry when a DocShare record is deleted (i.e., when a document is un-shared).validate():- Ensures
useris set ifeveryoneis false, and vice-versa. - Checks if the user initiating the share (
self.owner) has "share" permission on theshare_doctypeandshare_name. - If
submitpermission is granted, verifies that theshare_doctypeis actually submittable. - Calls
cascade_permissions_downwards()to ensure logical dependencies (e.g., granting write also grants read). - Calls a
validate_sharehook on the actual document being shared, allowing the target Doctype to have custom share validation logic.
- Ensures
cascade_permissions_downwards(): Enforces permission hierarchy (e.g., write implies read, submit implies write).after_insert(): Adds a "Comment" of type "Shared" to the timeline of theshare_namedocument, logging who shared it and with whom.on_trash(): When a DocShare record is deleted (un-sharing), it adds a "Comment" of type "Unshared" to theshare_namedocument's timeline.
on_doctype_update()(Global Function):- Executed during
bench migrate. - Adds database indexes on
(user, share_doctype)and(share_doctype, share_name)in thetabDocSharetable to optimize queries related to finding shared documents or shares for a user.
- Executed during
The client-side JavaScript for the DocShare Doctype's own form view is minimal.
frappe.ui.form.on("DocShare", { refresh: function (frm) {}, });- The
refreshfunction is empty, indicating no special client-side behavior is needed for the direct form view of a DocShare record. Users interact with sharing via the "Share" dialog on actual documents.
- The
- A user opens a document (e.g., "Project PROJ-001").
- They click the "Share" button/menu option on that document's form.
- A dialog appears allowing them to:
- Enter a User to share with.
- Select permissions (Read, Write, Share, Submit).
- Optionally, check "Notify by email".
- Alternatively, they can choose to share with "Everyone".
- Upon submitting this dialog:
- A new "DocShare" record is created in the background.
share_doctype= "Project",share_name= "PROJ-001".user= (selected user) or null ifeveryone= 1.- Permission flags are set as chosen.
- The
docshare.pycontroller validates the action. - An email notification might be sent.
- A "Shared" comment is added to "PROJ-001".
- When the recipient user logs in, Frappe's permission engine considers these DocShare records in addition to role-based permissions to determine if they can access "PROJ-001" and with what rights.
- To un-share, the original sharer (or someone with share rights) would typically go back to the "Share" dialog on "PROJ-001" and remove the share entry. This deletes the corresponding "DocShare" record.
The DocShare Doctype is a critical component for enabling fine-grained, instance-level sharing of documents in Frappe.