permissions-expert
npx skills add https://github.com/kehwar/frappe_tweaks --skill permissions-expert
Agent 安装分布
Skill 文档
Frappe Permissions Expert
This skill provides comprehensive guidance for understanding and extending Frappe’s permission system.
Overview
Frappe’s permission system is multi-layered and evaluates permissions in a specific order:
- Administrator Check: Administrator user bypasses all permission checks
- Role-Based Permissions: DocType permissions configured through Permission Manager
- Controller Permissions: Custom
has_permissionhooks in doctypes - User Permissions: Document-level restrictions based on user-specific rules
- Permission Query Conditions: SQL-based filters for list views and reports
- Share Permissions: Explicit document sharing between users
Permission Types
Frappe supports the following permission types (ptypes):
rights = (
"select", # View in list (limited fields)
"read", # Full read access
"write", # Edit existing documents
"create", # Create new documents
"delete", # Delete documents
"submit", # Submit submittable documents
"cancel", # Cancel submitted documents
"amend", # Amend cancelled documents
"print", # Print documents
"email", # Email documents
"report", # Access reports
"import", # Import documents
"export", # Export documents
"share", # Share documents with others
)
Quick Reference
Main Permission Check Function
frappe.has_permission(
doctype="DocType Name",
ptype="read", # Permission type to check
doc=None, # Optional: specific document instance
user=None, # Optional: defaults to current user
raise_exception=True, # Display error message if False
parent_doctype=None, # Required for child doctypes
debug=False, # Enable debug logging
ignore_share_permissions=False
)
Key Concepts
- Child Tables: Don’t have their own permissions; permissions are checked on the parent document
- Virtual DocTypes: Permission query conditions don’t apply; only
has_permissionhook and role permissions apply - Permission Levels: Provide field-level access control within a document (permlevel 0, 1, 2, etc.)
Extension Hooks
Frappe provides seven main hooks for extending permission logic:
1. has_permission – Controller Permission Check
Purpose: Implement custom document-level permission logic
Location: In your doctype’s .py file or registered in hooks.py
Signature:
def has_permission(doc, ptype=None, user=None, debug=False):
"""
Returns:
bool or None:
- True: Explicitly grant permission
- False: Explicitly deny permission
- None: No opinion, continue with other checks
"""
Important Notes:
- Return
Noneto defer to other permission checks (recommended default) - Return
Falseto explicitly deny permission (overrides role permissions) - Return
Trueto explicitly grant permission (use with caution)
When to read: See references/has-permission-hook.md when implementing document-level permission logic with 7 detailed examples covering owner access, team hierarchies, status restrictions, and more.
2. permission_query_conditions – List View Filtering and Document Access
Purpose: Return SQL WHERE conditions to filter documents in list views and validate individual document access
Location: In your doctype’s .py file or registered in hooks.py
Signature:
def get_permission_query_conditions(user=None, doctype=None):
"""
Returns:
str: SQL WHERE clause without the "WHERE" keyword
Returns empty string "" to allow all documents
"""
Security: Always escape dynamic values with frappe.db.escape()
Important: These conditions are checked both in list views AND when accessing individual documents via has_permission() for read/select operations.
When to read: See references/permission-query-conditions-hook.md when implementing list filtering or document access validation with 7 examples including company filtering, role-based regions, time-based access, and multi-tenant patterns.
3. write_permission_query_conditions – Post-Write Validation
Purpose: Validate that saved/updated documents satisfy custom conditions before committing to database
Location: In your doctype’s .py file or registered in hooks.py
Signature:
def get_write_permission_query_conditions(user=None, doctype=None, ptype="write"):
"""
Return SQL WHERE conditions to validate written documents.
This is automatically called during has_permission() checks
for write/create/submit/cancel/delete operations.
Checked AFTER database write but BEFORE commit.
If validation fails, transaction is rolled back.
"""
When to read: See references/write-permission-query-conditions-hook.md when validating writes before commit with examples for regional restrictions, document age limits, and status-based validation.
4. Server Scripts – Permission Query
Purpose: Define permission query conditions using Server Scripts (Python code in the UI)
Location: Created through Frappe UI at /app/server-script
Script Type: “Permission Query”
When to read: See references/server-scripts.md when prototyping permission logic via UI before moving to code, with examples for department filtering and role-based access.
5. has_website_permission – Website/Portal Access
Purpose: Control access to documents on the website/portal (not desk)
Location: In your doctype’s .py file or registered in hooks.py
When to read: See references/has-website-permission-hook.md when implementing portal/website access control with examples for customer orders, published content, and contact relationships.
Workflow Permission Hooks
Frappe provides two additional hooks specifically for workflow-based permissions:
6. filter_workflow_transitions – Custom Transition Filtering
Purpose: Filter and customize the list of available workflow transitions based on custom logic
Location: Registered in hooks.py
Use Cases:
- Hide specific transitions based on document field values
- Apply time-based or date-based restrictions
- Implement dynamic transition visibility
7. has_workflow_action_permission – Action-Level Permission
Purpose: Control which users should receive workflow action notifications and have permission to execute specific actions
Location: Registered in hooks.py
Use Cases:
- Implement approval hierarchies
- Department or region-based approval routing
- Amount-based approval limits
When to read: See references/workflow-permission-hooks.md when implementing workflow transition filtering or approval routing with 10+ examples covering hierarchical approvals, time restrictions, and regional routing.
User Permissions
User Permissions restrict access to specific document values for link fields.
Creating User Permissions:
from frappe.permissions import add_user_permission
add_user_permission(
doctype="Company",
name="Company A",
user="user@example.com",
applicable_for="Sales Order", # Optional
is_default=1, # Optional
ignore_permissions=True # Optional
)
Use Cases:
- Restrict sales users to their own territory
- Limit employees to their branch/department
- Multi-company access control
When to read: See references/user-permissions.md when implementing document-level restrictions using User Permissions with comprehensive examples for multi-company, territory, and department-based access.
Share Permissions
Documents can be explicitly shared with specific users:
frappe.share.add(
doctype="Sales Order",
name="SO-0001",
user="user@example.com",
read=1,
write=1,
share=0,
submit=0,
notify=1
)
When to read: See references/share-permissions.md when implementing explicit document sharing between users with examples for collaboration, temporary access, and cross-department workflows.
Permission Levels
Permission levels provide field-level access control:
- Each field can have a permlevel (0, 1, 2, etc.)
- Users must have role permission with that permlevel to see/edit the field
- Permlevel 0 is default and always checked
When to read: See references/permission-levels.md when implementing field-level access control with examples for hiding pricing, cost fields, and internal notes from specific roles.
Best Practices
Security
- Always Escape User Input: Use
frappe.db.escape()when building SQL conditions - Fail Secure: Default to denying access when in doubt
- Validate Hook Returns: Ensure hooks return expected types
- Test Permission Boundaries: Test with users having minimal permissions
- Avoid Side Effects: Permission checks should be read-only
Performance
- Optimize SQL Conditions: Use indexed columns in WHERE clauses
- Cache User Data: Cache frequently accessed user properties
- Minimize Hook Complexity: Keep permission logic simple and fast
- Use Appropriate Hooks:
- Use
permission_query_conditionsfor list filtering - Use
has_permissionfor complex document-specific logic
- Use
Maintainability
- Document Permission Logic: Add docstrings explaining the rules
- Separate Concerns: Keep permission logic separate from business logic
- Use Constants: Define permission-related constants
- Consistent Return Values: Be explicit about what you’re returning
When to read: See references/best-practices.md when writing production-ready permission code with comprehensive guidelines for security, performance, and maintainability.
Debugging Permissions
Enable Debug Mode
# In Python
result = frappe.has_permission("DocType", "read", doc, debug=True)
# Logs will show the permission evaluation flow
# Or enable globally
frappe.conf.developer_mode = 1
Check Permission Debug Logs
# After permission check with debug=True
logs = frappe.local.permission_debug_log
for log in logs:
print(log)
When to read: See references/debugging.md when troubleshooting permission issues with comprehensive debugging workflows, common scenarios, and logging techniques.
Common Issues and Solutions
When to read: See references/common-issues.md when facing permission problems with detailed troubleshooting for:
- User Can’t See Documents in List View
- Can See Document in List but Can’t Open
- Permission Query Hook Not Working
- Write Operations Fail Silently
- Virtual DocType Permission Issues
- Share Permissions Not Working
- Administrator Not Seeing All Documents
Common Patterns
When to read: See references/common-patterns.md for 15 ready-to-use permission patterns including:
- Owner-Only Access
- Role-Based Region Filtering
- Hierarchical Access (Team/Department)
- Status-Based Restrictions
- Time-Based Access
- Multi-Tenant Access
- Permission Level Filtering
- Child Table Permissions
- Conditional Field Visibility
- Combined Role and Territory Access
Testing Permission Hooks
When to read: See references/testing.md when writing unit and integration tests for permission logic with comprehensive examples and patterns.
Migration Guide
When to read: See references/migration-guide.md for a step-by-step guide when adding custom permissions to existing DocTypes.
Core Implementation Files
Key files in Frappe codebase:
/frappe/permissions.py– Main permission system/frappe/model/db_query.py– Permission query integration/frappe/model/document.py– Document lifecycle and permission checks/frappe/core/doctype/user_permission/– User permission management
Usage
When working with permissions:
- Identify the requirement: What access control is needed?
- Choose appropriate hook: Select based on use case
- Reference appropriate guide: Use reference files for detailed patterns
- Follow best practices: Security, performance, maintainability
- Test thoroughly: With different roles and edge cases
- Debug when needed: Use debug mode and logging
Important Notes
- Administrator always bypasses all permission checks
- Permission query conditions are applied to both list views AND individual document access
- Virtual doctypes don’t support permission query conditions
- Child tables inherit parent document permissions
- Always escape user input in SQL conditions to prevent SQL injection
- Permission checks should be read-only operations