Document CustomFieldValue policies and own_data create/destroy in architecture
Update roles-and-permissions-architecture.md with policy layout and permission matrix for CustomFieldValue (linked).
This commit is contained in:
parent
4e032ea778
commit
db95979bf5
1 changed files with 23 additions and 21 deletions
|
|
@ -501,9 +501,11 @@ defmodule Mv.Authorization.PermissionSets do
|
||||||
%{resource: "Member", action: :read, scope: :linked, granted: true},
|
%{resource: "Member", action: :read, scope: :linked, granted: true},
|
||||||
%{resource: "Member", action: :update, scope: :linked, granted: true},
|
%{resource: "Member", action: :update, scope: :linked, granted: true},
|
||||||
|
|
||||||
# CustomFieldValue: Can read/update custom field values of linked member
|
# CustomFieldValue: Can read/update/create/destroy custom field values of linked member
|
||||||
%{resource: "CustomFieldValue", action: :read, scope: :linked, granted: true},
|
%{resource: "CustomFieldValue", action: :read, scope: :linked, granted: true},
|
||||||
%{resource: "CustomFieldValue", action: :update, scope: :linked, granted: true},
|
%{resource: "CustomFieldValue", action: :update, scope: :linked, granted: true},
|
||||||
|
%{resource: "CustomFieldValue", action: :create, scope: :linked, granted: true},
|
||||||
|
%{resource: "CustomFieldValue", action: :destroy, scope: :linked, granted: true},
|
||||||
|
|
||||||
# CustomField: Can read all (needed for forms)
|
# CustomField: Can read all (needed for forms)
|
||||||
%{resource: "CustomField", action: :read, scope: :all, granted: true}
|
%{resource: "CustomField", action: :read, scope: :all, granted: true}
|
||||||
|
|
@ -678,7 +680,7 @@ Quick reference table showing what each permission set allows:
|
||||||
| **User** (all) | - | - | - | R, C, U, D |
|
| **User** (all) | - | - | - | R, C, U, D |
|
||||||
| **Member** (linked) | R, U | - | - | - |
|
| **Member** (linked) | R, U | - | - | - |
|
||||||
| **Member** (all) | - | R | R, C, U | R, C, U, D |
|
| **Member** (all) | - | R | R, C, U | R, C, U, D |
|
||||||
| **CustomFieldValue** (linked) | R, U | - | - | - |
|
| **CustomFieldValue** (linked) | R, U, C, D | - | - | - |
|
||||||
| **CustomFieldValue** (all) | - | R | R, C, U, D | R, C, U, D |
|
| **CustomFieldValue** (all) | - | R | R, C, U, D | R, C, U, D |
|
||||||
| **CustomField** (all) | R | R | R | R, C, U, D |
|
| **CustomField** (all) | R | R | R | R, C, U, D |
|
||||||
| **Role** (all) | - | - | - | R, C, U, D |
|
| **Role** (all) | - | - | - | R, C, U, D |
|
||||||
|
|
@ -1053,35 +1055,33 @@ end
|
||||||
|
|
||||||
### CustomFieldValue Resource Policies
|
### CustomFieldValue Resource Policies
|
||||||
|
|
||||||
**Location:** `lib/mv/membership/custom_field_value.ex`
|
**Location:** `lib/membership/custom_field_value.ex`
|
||||||
|
|
||||||
**Special Case:** Users can access custom field values of their linked member.
|
**Pattern:** Bypass for READ (list queries), CustomFieldValueCreateScope for create (no filter), HasPermission for read/update/destroy. Create uses a dedicated check because Ash cannot apply filters to create actions.
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defmodule Mv.Membership.CustomFieldValue do
|
defmodule Mv.Membership.CustomFieldValue do
|
||||||
use Ash.Resource, ...
|
use Ash.Resource, ...
|
||||||
|
|
||||||
policies do
|
policies do
|
||||||
# SPECIAL CASE: Users can access custom field values of their linked member
|
# Bypass for READ (list queries; expr triggers auto_filter)
|
||||||
# Note: This uses member_id relationship (CustomFieldValue.member_id → Member.id → User.member_id)
|
bypass action_type(:read) do
|
||||||
policy action_type([:read, :update]) do
|
description "Users can read custom field values of their linked member"
|
||||||
description "Users can access custom field values of their linked member"
|
|
||||||
authorize_if expr(member_id == ^actor(:member_id))
|
authorize_if expr(member_id == ^actor(:member_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
# GENERAL: Check permissions from role
|
# CREATE: CustomFieldValueCreateScope (no filter; Ash rejects filters on create)
|
||||||
policy action_type([:read, :create, :update, :destroy]) do
|
# own_data -> create when member_id == actor.member_id; normal_user/admin -> create (scope :all)
|
||||||
description "Check permissions from user's role"
|
policy action_type(:create) do
|
||||||
authorize_if Mv.Authorization.Checks.HasPermission
|
authorize_if Mv.Authorization.Checks.CustomFieldValueCreateScope
|
||||||
end
|
end
|
||||||
|
|
||||||
# DEFAULT: Forbid
|
# READ/UPDATE/DESTROY: HasPermission (scope :linked / :all)
|
||||||
policy action_type([:read, :create, :update, :destroy]) do
|
policy action_type([:read, :update, :destroy]) do
|
||||||
forbid_if always()
|
authorize_if Mv.Authorization.Checks.HasPermission
|
||||||
end
|
end
|
||||||
|
# DEFAULT: Ash implicitly forbids if no policy authorized (fail-closed)
|
||||||
end
|
end
|
||||||
|
|
||||||
# ...
|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1089,11 +1089,13 @@ end
|
||||||
|
|
||||||
| Action | Mitglied | Vorstand | Kassenwart | Buchhaltung | Admin |
|
| Action | Mitglied | Vorstand | Kassenwart | Buchhaltung | Admin |
|
||||||
|--------|----------|----------|------------|-------------|-------|
|
|--------|----------|----------|------------|-------------|-------|
|
||||||
| Read linked | ✅ (special) | ✅ (if linked) | ✅ | ✅ (if linked) | ✅ |
|
| Read linked | ✅ (bypass) | ✅ (if linked) | ✅ | ✅ (if linked) | ✅ |
|
||||||
| Update linked | ✅ (special) | ❌ | ✅ | ❌ | ✅ |
|
| Update linked | ✅ (scope :linked) | ❌ | ✅ | ❌ | ✅ |
|
||||||
|
| Create linked | ✅ (CustomFieldValueCreateScope) | ❌ | ✅ | ❌ | ✅ |
|
||||||
|
| Destroy linked | ✅ (scope :linked) | ❌ | ✅ | ❌ | ✅ |
|
||||||
| Read all | ❌ | ✅ | ✅ | ✅ | ✅ |
|
| Read all | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Create | ❌ | ❌ | ✅ | ❌ | ✅ |
|
| Create all | ❌ | ❌ | ✅ | ❌ | ✅ |
|
||||||
| Destroy | ❌ | ❌ | ✅ | ❌ | ✅ |
|
| Destroy all | ❌ | ❌ | ✅ | ❌ | ✅ |
|
||||||
|
|
||||||
### CustomField Resource Policies
|
### CustomField Resource Policies
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue