Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 89 additions & 1 deletion forms_pro/api/form.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import frappe
from frappe import _
from frappe.share import remove
from frappe.share import add_docshare, remove
from pydantic import BaseModel, Field

from forms_pro.api.user import get_user
Expand Down Expand Up @@ -128,6 +128,94 @@ def remove_form_access(form_id: str, user_email: str) -> None:
return remove(doctype="Form", name=form_id, user=user_email, flags={"ignore_permissions": True})


@frappe.whitelist()
def add_form_access(
form_id: str,
user: str,
read: bool = True,
write: bool = False,
share: bool = False,
submit: bool = False,
) -> None:
"""
Grant a user access to a form with the specified permissions.

Uses ``ignore_share_permission`` so the record can be shared regardless of
the caller's role-level DocShare permissions — the explicit
``frappe.has_permission`` check below enforces that only users with share
access on this particular form can invoke this endpoint.

Args:
form_id: Name of the Form document to share.
user: Email of the user to grant access to.
read: Allow the user to read the form (default True).
write: Allow the user to edit the form (default False).
share: Allow the user to share the form with others (default False).
submit: Allow the user to submit the form (default False).

Raises:
frappe.PermissionError: If the calling user does not have share access
on the specified form.
"""
if not frappe.has_permission("Form", "share", form_id):
frappe.throw(_("You do not have share access to this form"), frappe.PermissionError)

add_docshare(
doctype="Form",
name=form_id,
user=user,
read=int(read),
write=int(write),
share=int(share),
submit=int(submit),
flags={"ignore_share_permission": True},
)


@frappe.whitelist()
def set_form_permission(
form_id: str,
user: str,
permission_to: str,
value: bool,
) -> None:
"""
Toggle a single permission bit for a user on a form.

Designed for per-toggle updates from the sharing UI — only the specified
permission field is changed; all other existing permissions are preserved by
Frappe's ``add_docshare`` merge behaviour.

Args:
form_id: Name of the Form document.
user: Email of the user whose permission is being updated.
permission_to: Which permission to update. Must be one of:
``"read"``, ``"write"``, ``"share"``, ``"submit"``.
value: ``True`` to grant the permission, ``False`` to revoke it.

Raises:
frappe.PermissionError: If the calling user does not have share access
on the specified form.
frappe.ValidationError: If ``permission_to`` is not a recognised
permission type.
"""
if not frappe.has_permission("Form", "share", form_id):
frappe.throw(_("You do not have share access to this form"), frappe.PermissionError)

# Guard against arbitrary kwargs being forwarded to add_docshare
allowed_permissions = {"read", "write", "share", "submit"}
if permission_to not in allowed_permissions:
frappe.throw(_("Invalid permission type"), frappe.ValidationError)

add_docshare(
doctype="Form",
name=form_id,
user=user,
**{permission_to: int(bool(value))},
flags={"ignore_share_permission": True},
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.


@frappe.whitelist()
def get_doctype_list() -> list[str]:
if not frappe.has_permission("DocType", "read"):
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/stores/form/manageForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,11 @@ export const useManageForm = defineStore("manageForm", () => {
*/
function addAccess(userId: string, access: AccessPermissions) {
const _access = createResource({
url: "frappe.share.add",
url: "forms_pro.api.form.add_form_access",
method: "POST",
makeParams() {
return {
doctype: "Form",
name: currentFormId.value,
form_id: currentFormId.value,
user: userId,
read: Boolean(access.read),
write: Boolean(access.write),
Expand Down Expand Up @@ -106,12 +105,11 @@ export const useManageForm = defineStore("manageForm", () => {
value: boolean
) {
const _permission = createResource({
url: "frappe.share.set_permission",
url: "forms_pro.api.form.set_form_permission",
method: "POST",
makeParams() {
return {
doctype: "Form",
name: currentFormId.value,
form_id: currentFormId.value,
user: userId,
permission_to: permission,
value: value ? 1 : 0,
Expand Down
Loading