-
Notifications
You must be signed in to change notification settings - Fork 3
Frappe Draw: Writer-style diagram sharing (view/comment/edit) — backend #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Permission helpers for Draw Diagram sharing (Writer-style view/edit/comment). | ||
| # Diagrams are owner-scoped by default (the Draw User role's if_owner perms); this | ||
| # widens list visibility to also include diagrams shared with the user (Frappe | ||
| # core DocShare) and public ones. Document-level read/write come from DocShare | ||
| # automatically; the custom "comment" permission type is checked via | ||
| # frappe.has_permission("Draw Diagram", "comment", doc=name). | ||
|
|
||
| import frappe | ||
|
|
||
|
|
||
| def query_conditions(user: str | None = None) -> str: | ||
| """SQL clause limiting Draw Diagram list queries to what `user` may see: | ||
| their own diagrams, ones shared with them, and public ones. System Managers | ||
| (full access) get no restriction.""" | ||
| user = user or frappe.session.user | ||
| if "System Manager" in frappe.get_roles(user): | ||
| return "" | ||
|
|
||
| table = "`tabDraw Diagram`" | ||
| conditions = [ | ||
| f"{table}.owner = {frappe.db.escape(user)}", | ||
| f"{table}.is_public = 1", | ||
| ] | ||
| shared = frappe.share.get_shared("Draw Diagram", user) | ||
| if shared: | ||
| names = ", ".join(frappe.db.escape(name) for name in shared) | ||
| conditions.append(f"{table}.name in ({names})") | ||
| return "(" + " or ".join(conditions) + ")" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # Writer-style sharing for Draw Diagram — view / comment / edit access levels, | ||
| # built on Frappe core DocShare (frappe.share) plus a custom "comment" permission | ||
| # type (registered by draw.patches.register_comment_permission_type). No Frappe | ||
| # Drive dependency. Public access reuses the diagram's own `is_public` flag, which | ||
| # draw.api.permission.query_conditions already honours. | ||
|
|
||
| import frappe | ||
| from frappe import _ | ||
| from frappe.utils import cint | ||
|
|
||
| # Access level -> DocShare flags. "edit" also grants share so collaborators can | ||
| # re-share, matching the Drive/Writer "editor" tier. | ||
| LEVEL_FLAGS = { | ||
| "view": {"read": 1, "comment": 0, "write": 0, "share": 0}, | ||
| "comment": {"read": 1, "comment": 1, "write": 0, "share": 0}, | ||
| "edit": {"read": 1, "comment": 1, "write": 1, "share": 1}, | ||
| } | ||
|
|
||
|
|
||
| def _check_can_share(name: str) -> None: | ||
| if not frappe.has_permission("Draw Diagram", "share", doc=name): | ||
| frappe.throw(_("You are not permitted to share this diagram."), frappe.PermissionError) | ||
|
|
||
|
|
||
| @frappe.whitelist() | ||
| def share_diagram(name: str, user: str, level: str = "view") -> list: | ||
| """Share a diagram with a user at view / comment / edit level (idempotent — | ||
| re-sharing updates the level). Returns the current share list.""" | ||
| _check_can_share(name) | ||
| flags = LEVEL_FLAGS.get(level) | ||
| if not flags: | ||
| frappe.throw(_("Unknown access level: {0}").format(level)) | ||
| # Clear any prior grant first so lowering a level actually removes flags. | ||
| frappe.share.remove("Draw Diagram", name, user) | ||
| frappe.share.add("Draw Diagram", name, user=user, notify=0, **flags) | ||
| return get_diagram_shares(name) | ||
|
|
||
|
|
||
| @frappe.whitelist() | ||
| def unshare_diagram(name: str, user: str) -> list: | ||
| """Revoke a user's access. Returns the current share list.""" | ||
| _check_can_share(name) | ||
| frappe.share.remove("Draw Diagram", name, user) | ||
| return get_diagram_shares(name) | ||
|
|
||
|
|
||
| @frappe.whitelist() | ||
| def get_diagram_shares(name: str) -> list: | ||
| """The users this diagram is shared with, each with their access flags.""" | ||
| if not frappe.has_permission("Draw Diagram", "read", doc=name): | ||
| frappe.throw(_("Not permitted."), frappe.PermissionError) | ||
| return frappe.share.get_users("Draw Diagram", name) | ||
|
|
||
|
|
||
| @frappe.whitelist() | ||
| def set_public(name: str, enabled) -> None: | ||
| """Toggle "anyone in this site can view" via the diagram's is_public flag | ||
| (honoured by draw.api.permission.query_conditions).""" | ||
| _check_can_share(name) | ||
| frappe.db.set_value("Draw Diagram", name, "is_public", 1 if cint(enabled) else 0) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # Idempotent app setup, run from BOTH the after_install and after_migrate hooks. | ||
| # | ||
| # Why hooks and not patches: patches in patches.txt are marked complete WITHOUT | ||
| # executing on a fresh install (they exist to migrate existing data), so a fresh | ||
| # Frappe Cloud install would otherwise never get the Draw User role or the custom | ||
| # permission type. Running an idempotent setup from after_install (fresh) + | ||
| # after_migrate (upgrades) covers both. | ||
|
|
||
| import frappe | ||
|
|
||
| ROLE = "Draw User" | ||
| OWNED_DOCTYPES = ("Draw Diagram", "Draw Folder") | ||
|
|
||
|
|
||
| def ensure_setup(*args, **kwargs) -> None: | ||
| """Create the Draw User role + owner-scoped perms and register the diagram | ||
| "comment" permission type. Safe to run repeatedly.""" | ||
| _ensure_role() | ||
| for doctype in OWNED_DOCTYPES: | ||
| _ensure_owner_permission(doctype) | ||
| _ensure_comment_permission_type() | ||
| frappe.clear_cache() | ||
|
|
||
|
|
||
| def _ensure_role() -> None: | ||
| """Create the Draw User role idempotently (desk-enabled, normal users get it).""" | ||
| if frappe.db.exists("Role", ROLE): | ||
| return | ||
| frappe.get_doc({"doctype": "Role", "role_name": ROLE, "desk_access": 1}).insert( | ||
| ignore_permissions=True | ||
| ) | ||
|
|
||
|
|
||
| def _ensure_owner_permission(doctype: str) -> None: | ||
| """Add an if_owner perm row for Draw User on the given doctype if missing.""" | ||
| if frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": ROLE, "if_owner": 1}): | ||
| return | ||
| frappe.get_doc( | ||
| { | ||
| "doctype": "Custom DocPerm", | ||
| "parent": doctype, | ||
| "parenttype": "DocType", | ||
| "parentfield": "permissions", | ||
| "role": ROLE, | ||
| "if_owner": 1, | ||
| "read": 1, | ||
| "write": 1, | ||
| "create": 1, | ||
| "delete": 1, | ||
| "share": 1, | ||
| } | ||
| ).insert(ignore_permissions=True) | ||
|
|
||
|
|
||
| def _ensure_comment_permission_type() -> None: | ||
| """Register a "comment" permission type for Draw Diagram so diagrams can be | ||
| shared at a view / comment / edit level. Adds a `comment` Check to DocShare + | ||
| the doctype's perm rules. No-ops on Frappe versions without Permission Type.""" | ||
| if not frappe.db.exists("DocType", "Permission Type"): | ||
| return | ||
| if frappe.db.exists("Permission Type", {"doc_type": "Draw Diagram", "perm_type": "comment"}): | ||
| return | ||
| frappe.get_doc( | ||
| {"doctype": "Permission Type", "doc_type": "Draw Diagram", "perm_type": "comment"} | ||
| ).insert(ignore_permissions=True) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_diagram_sharesonly requiresreadpermission, so any "view"-only user can call it and get the full share list (every collaborator's email + their access level). The PR description says all endpoints are "gated on the caller holdingshare" — this one is not. Change the gate toshare.