core.permissions
Overview
Object-level and row-level permission classes for CRUD and workflow integration.
Classes
check_action_permission
Whether request.user may perform action against instance -- or the model at large, when instance is None -- through viewset's own configured permission classes.
Checked as action over its own HTTP method, independently of whatever action the surrounding response is actually for: a list response does not substitute list permission for retrieve, and a write response does not substitute its own write permission for read. instance=None decides through has_permission alone, the model-level check, which lets a matching workflow-state grant settle a model-level denial without scanning any row (:func:has_matching_state_grant). A specific instance instead decides through viewset.check_object_permissions, the same hook the endpoint itself calls to enforce the request, so a viewset that overrides that hook to add its own object-level rules is honoured here too, not only at the endpoint. It folds in row-level and per-object workflow-state rules for that object either way.
request is None when there is no request to authorize against (for example, schema generation building metadata without a live requester); every caller of this function leaves its result unfiltered in that case.
Caches its answer on viewset per (action, instance) for that viewset instance's own lifetime -- one request -- so two callers asking the identical question (an object's own available_actions checking retrieve, and history-list availability checking read the same way) pay for one permission pass, not two. The cache keys on id(instance), since a model instance is unhashable without a primary key and a composite primary key is not reliably hashable either; it holds a reference to instance alongside its answer so that id cannot be freed and reassigned to an unrelated object for as long as the cache entry lives, which would otherwise alias a later, different row onto this row's cached answer.
Signature
check_action_permission(viewset, request, instance, action)
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| viewset | yes | |||
| request | yes | |||
| instance | yes | |||
| action | yes |
Returns
bool
Source
server/vueda/core/permissions.py:62
filter_rows_for_user
Apply row-level and workflow-aware queryset filters for the given perm_type. Calls RowLevelPermissions.check_queryset and, when the model has a workflow, also annotates state permission info and calls check_queryset_workflow.
This is the single row-visibility rule. A viewset reaches it through apply_row_level_filter. History and the filter choices endpoint reach it directly, so an event about a related row follows the same rule as reading that row, and a filter choice comes only from a row the user may list.
Signature
filter_rows_for_user(queryset, user, perm_type)
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| queryset | yes | |||
| user | yes | |||
| perm_type | no | 'list' |
Source
server/vueda/core/permissions.py:379
has_matching_state_grant
Whether a workflow state of model grants user any of required_permissions.
This is the one model-scope deferral rule. A model-level denial stands unless a state rule matches the caller's groups, a requested codename, the model's content type, and the model's own workflow, and that rule grants rather than denies.
The answer says only that an object's state can still admit the request. It does not say that any particular object does. Call it only from a path that goes on to make that per-object decision, and let the object decision, including a matching deny, settle the request.
Signature
has_matching_state_grant(model, user, required_permissions)
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| model | yes | |||
| user | yes | |||
| required_permissions | yes |
Returns
bool
Source
server/vueda/core/permissions.py:27
has_row_dependent_authorization
Whether reading a row of model depends on the row rather than only on the model.
A model is row-dependent when it declares RowLevelPermissions or participates in a configured workflow. History uses this to decide whether an event about a row that has since been deleted can still be authorized. When the row is gone there is nothing left to evaluate, so a row-dependent model fails closed.
Signature
has_row_dependent_authorization(model)
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| model | yes |
Returns
bool
Source
server/vueda/core/permissions.py:358
Source
server/vueda/core/permissions.py