Commit graph

600 commits

Author SHA1 Message Date
e47547e065 Add Role resource policies (defense-in-depth)
- PermissionSets: Role read :all for own_data, read_only, normal_user; admin keeps full CRUD
- Role resource: authorizers and policies with HasPermission
- Tests: role_policies_test.exs (read all, create/update/destroy admin only)
- Fix existing tests to pass actor or authorize?: false for Role operations
2026-02-04 12:37:48 +01:00
083592489f ARIA: set aria-sort on th for sortable columns
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
- Table: optional col sort_field; th gets aria-sort when col is sorted.
- User index: pass sort_field/sort_order to table, sort_field: :email on email col.
2026-02-04 11:40:23 +01:00
24d130ffb5 OIDC: use UserHelpers.has_oidc? in index and show
- Index OIDC column and show OIDC item use has_oidc? instead of raw oidc_id.
- Avoids empty string showing as Linked.
2026-02-04 11:40:21 +01:00
503401f2e6 Setting: remove unused actor in default_fee_type validation
- Docs: Regenerate Cycles server-side enforcement note in membership-fee-architecture.
2026-02-04 11:40:19 +01:00
d7c6d20483 User form: red warning for OIDC users when setting/changing password
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
- Show alert when user has oidc_id and password section is visible.
- Explains that password here does not change SSO/identity provider password.
2026-02-04 11:07:01 +01:00
541c79e501 ARIA: remove aria-sort from sort button; Password column tests
- Sort button: aria-sort removed (button role does not support it).
- Index tests: remove aria-sort assertions; add Password column display tests.
2026-02-04 11:06:55 +01:00
c6082f2831 Users list and show: Role, Password, OIDC columns; UserHelpers
- Index: load :role; columns Role, Password (has_password?), OIDC; contrast fix.
- Show: Role, OIDC (Linked/Not linked); has_password? for Password Authentication.
- UserHelpers: has_password?/1, has_oidc?/1. Gettext: new strings and DE translations.
2026-02-04 11:06:52 +01:00
7eba21dc9c Hide Regenerate Cycles button when no membership fee type assigned
All checks were successful
continuous-integration/drone/push Build is passing
- Button only shown when @member.membership_fee_type is set (same as Create Cycle).
- Test: no-type view asserts Regenerate Cycles button is not present.
2026-02-04 09:38:26 +01:00
178f5a01c7 MembershipFeeCycle: own_data read :linked via bypass and HasPermission scope
- own_data gets read scope :linked; apply_scope in HasPermission; bypass check for own_data.
- PermissionSetsTest expects own_data :linked, others :all for MFC read.
2026-02-04 09:20:10 +01:00
890a4d3752 MemberGroup: restrict bypass to own_data via MemberGroupReadLinkedForOwnData
- ActorPermissionSetIs check; bypass policy filters by member_id for own_data only.
- Admin with member_id still gets :all via HasPermission. Tests added.
2026-02-04 09:19:57 +01:00
67ce514ba0 User: fix last-admin validation and forbid non-admin role_id change
- Last-admin only when target role is non-admin (admins may switch admin roles).
- Use Ash.Changeset.get_attribute for new role_id. Tests: admin role switch, non-admin update_user role_id forbidden.
2026-02-04 09:19:47 +01:00
dbd0a57292 Secure regenerate_cycles: require can?(:create, MembershipFeeCycle) in handler
- Handler returns flash error when non-admin triggers event (e.g. DevTools).
- Test: read_only cannot create MembershipFeeCycle so handler rejects.
2026-02-04 09:19:37 +01:00
182d34fe58 MemberLive: confirm_delete_all_cycles via Ash.destroy, reduce current_actor
- Delete each cycle with Ash.destroy(actor:) so policies apply; add do_delete_all_cycles/5.
- Use positive can? check; remove duplicate current_actor(socket) in change_membership_fee_type.
2026-02-04 00:34:00 +01:00
e799f0271c Refactor PermissionSets: define admin permissions via perm_all()
Use perm/3 helper for admin resource permissions (DRY). MemberGroup
keeps read/create/destroy only (no update in domain).
2026-02-04 00:33:58 +01:00
101fd39f18 Fee settings and fee type form: pass actor for MembershipFeeType read
- membership_fee_settings_live: current_actor(socket), Ash.read! with actor
- membership_fee_type_live/form: Ash.get! with actor in mount
- check_page_permission_test: normal_user /groups/new and /groups/:slug/edit allowed
- membership_fee_type_live form_test: actor for Ash.read_one!/get!
2026-02-03 23:52:27 +01:00
e3bea17827 Member show & MembershipFees: permissions, delete all, regenerate, errors
- Show: handle_info :member_updated and :put_flash; Linked User only when can_access_page? /users
- MembershipFeesComponent: can_create_cycle/can_destroy_cycle/can_update_cycle; buttons gated
- Delete all cycles via Ash.destroy (policy enforced); format_error Forbidden
- Regenerate cycles for normal_user and admin (no admin-only check)
- Member form: format_error tuple for membership_fee_type_id; Select a membership fee type (no None)
- show_membership_fees_test: read_only UI and policy tests
2026-02-03 23:52:24 +01:00
8ec4a07103 User form: persist role, member linking, Forbidden handling
- User resource: update_user accepts role_id, manage_relationship :member
- user_live/form: touch role_id, params_with_member_if_unchanged to avoid unlink
- Handle Forbidden in form, extract error message for display
- user_policies_test and form_test coverage
2026-02-03 23:52:20 +01:00
5ed41555e9 Member/Setting/validations: domain, actor, and seeds
- setting.ex: domain/authorize for default_membership_fee_type_id check
- validate_same_interval: require membership_fee_type (no None)
- set_membership_fee_start_date: domain/actor for fee type lookup
- Validations: domain/authorize for cross-resource checks
- helpers.ex, email_sync change, seeds.exs actor/authorize fixes
- Update related tests
2026-02-03 23:52:16 +01:00
5889683854 Add resource policies for Group, MemberGroup, MembershipFeeType, MembershipFeeCycle
- Group/MemberGroup/MembershipFeeType/MembershipFeeCycle: HasPermission policy
- normal_user: Group and MembershipFeeCycle create/update/destroy; pages /groups/new, /groups/:slug/edit
- Add policy tests for all four resources
2026-02-03 23:52:12 +01:00
893f9453bd Add PermissionSets for Group, MemberGroup, MembershipFeeType, MembershipFeeCycle
- Extend permission_sets.ex with resources and pages for new domains
- Adjust HasPermission check for resource/action/scope
- Update roles-and-permissions and implementation-plan docs
- Add permission_sets_test.exs coverage
2026-02-03 23:52:09 +01:00
ee6bfbacbb User LiveViews: row_id and data-testid for actions
Table row_id for scoped selectors; data-testid on New/Edit/Delete.
2026-02-03 17:16:13 +01:00
a4b13cef49 Member LiveViews: row_id and data-testid for actions
Table row_id for scoped selectors; data-testid on New/Edit/Delete.
2026-02-03 17:16:11 +01:00
286972964d CoreComponents: allow data-testid on button
Include data-testid in button rest for test selectors.
2026-02-03 17:16:10 +01:00
c36812bf3f Authorization: document can_access_page? nil-safety
Doc and example for nil user returning false.
2026-02-03 17:16:09 +01:00
2ddd22078d Sidebar: use PagePaths, add testid for Administration
Gate menu items via PagePaths; add data-testid=sidebar-administration
for stable tests. menu_group accepts optional testid attr.
2026-02-03 17:16:08 +01:00
9e8910344e Add MvWeb.PagePaths for central sidebar/page paths
Single source for path strings used by Sidebar and can_access_page?.
Keep in sync with router when routes change.
2026-02-03 17:16:07 +01:00
f779fd61e0
Gate sidebar menu items by can_access_page?
Members, Fee Types and Administration subitems only shown when user
has page permission. Add admin_menu_visible? helper. Sidebar test
uses admin user so menu items render.
2026-02-03 16:56:52 +01:00
2f67c7099d
Apply UI authorization to User LiveViews (Index and Show)
Gate New User button, Edit and Delete links with can?/3.
Edit button on User Show visible only when user can update the user.
2026-02-03 16:56:51 +01:00
505e31653a
Apply UI authorization to Member LiveViews (Index and Show)
Gate New Member button, Edit and Delete links with can?/3.
Edit button on Member Show visible only when user can update the member.
2026-02-03 16:56:51 +01:00
47b6a16177
Doc: Actor maybe_load_role comment; ActorIsAdmin system user = admin 2026-02-03 16:07:39 +01:00
60a4181255
Validation: error message admin or linked user; resolve_actor fallback 2026-02-03 16:07:26 +01:00
4e6b7305b6
Doc: Loader auth-independent for link checks; email-sync rule rationale 2026-02-03 16:07:13 +01:00
4ea31f0f37 Add email-change permission validation for linked members
All checks were successful
continuous-integration/drone/push Build is passing
Only admins or the linked user may change a linked member's email.
- New validation EmailChangePermission (uses Actor.admin?, Loader.get_linked_user).
- Register on Member update_member; docs and gettext.
2026-02-03 14:35:32 +01:00
ad02f8914f Use EmailSync.Loader.get_linked_user in EmailNotUsedByOtherUser
Remove duplicate get_linked_user_id; reuse Loader for linked user lookup.
2026-02-03 14:35:08 +01:00
3d46ba655f Add Actor.permission_set_name/1 and admin?/1 for consistent capability checks
- Actor.permission_set_name(actor) returns role's permission set (supports nil role load).
- Actor.admin?(actor) returns true for system user or admin permission set.
- ActorIsAdmin policy check delegates to Actor.admin?/1.
2026-02-03 14:34:24 +01:00
960506d16a refactoring
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2026-02-02 16:56:07 +01:00
b21c3df7ef refactoring 2026-02-02 14:34:12 +01:00
71db9cf3c1 formatting
Some checks failed
continuous-integration/drone/push Build is failing
2026-02-02 13:54:27 +01:00
9e27de84cb Merge branch 'main' into feature/338_import_custom_fields
Some checks failed
continuous-integration/drone/push Build is failing
2026-02-02 13:46:05 +01:00
f5591c392a i18n: add translation 2026-02-02 13:42:16 +01:00
12715f3d85 refactoring 2026-02-02 13:07:08 +01:00
3f8797c356 feat: import custom fields via CSV 2026-02-02 11:42:07 +01:00
4997819c73 feat: validate config 2026-02-02 10:22:21 +01:00
e74154581c feat: changes UI info based on config for limits 2026-02-02 10:10:02 +01:00
3f551c5f8d feat: add configs for impor tlimits
Some checks failed
continuous-integration/drone/push Build is failing
2026-02-02 09:49:13 +01:00
6e13a3aa34
Docs: note User-Member Linking enforcement in code
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
- update_user restricted via ActorIsAdmin; Form gates Member-Linking UI
2026-01-30 11:28:41 +01:00
06d6531569 UserLive.Form: gate Member-Linking to admin, use :update for non-admin
- Show Member-Linking UI only when can_manage_member_linking (admin)
- perform_member_link_action runs only for admin
- assign_form: non-admin uses :update (email), admin uses :update_user
- Load members for linking only when can_manage_member_linking
2026-01-30 11:13:28 +01:00
14fa873640 Restrict User.update_user to admin; allow :update for email only
- Add ActorIsAdmin policy check (admin permission set only)
- User: policy action(:update_user) forbid_unless + authorize_if ActorIsAdmin
- User: primary :update action accept [:email] for non-admin profile edit
2026-01-30 11:13:23 +01:00
a1fe36b7f2 Delegate can_access_page? to CheckPagePermission
- UI uses same rules as plug (reserved 'new', own/linked path checks)
2026-01-30 10:22:31 +01:00
d318dad612 Add /users/:id (own) and /members/:id/show/edit for redirect and normal_user
- read_only and normal_user: allow /users/:id, /users/:id/edit, /users/:id/show/edit (own only)
- normal_user: allow /members/:id/show/edit
- Fixes redirect loop when sidebar links to profile
2026-01-30 10:22:27 +01:00