Commit graph

827 commits

Author SHA1 Message Date
f8a3cc4c47 Run seeds only once (#475)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
continuous-integration/drone/tag Build is passing
## Description of the implemented changes
The changes were:
- [ ] Bugfixing
- [x] New Feature
- [ ] Breaking Change
- [x] Refactoring

**Seeds run only on first startup.** On every application start (e.g. `just run`, Docker entrypoint), seed scripts are still invoked, but they exit immediately when the admin user already exists. This avoids duplicate seed data (e.g. join requests), keeps startup fast after the first run, and works the same in dev and production.

## What has been changed?

- **`lib/mv/release.ex`**
  - Added `bootstrap_seeds_applied?/0`: returns whether the admin user (from `ADMIN_EMAIL` or default `admin@localhost`) exists. We check the admin *user*, not the Admin *role*, so we do not skip when only migrations have run (migrations can create the Admin role for the system actor).
  - `run_seeds/0`: if `bootstrap_seeds_applied?()` is true, prints “Seeds already applied (admin user exists). Skipping.” and returns without running bootstrap or dev seeds; otherwise unchanged behaviour.
  - Module docs updated for the new function and the skip behaviour.

- **`priv/repo/seeds.exs`**
  - Ensures the app is started (`Application.ensure_all_started(:mv)`).
  - If `Mv.Release.bootstrap_seeds_applied?()` is true, prints the same skip message and does not run bootstrap or dev seeds; otherwise runs as before (bootstrap + dev seeds in dev/test).
  - Comment at the top updated to describe the skip behaviour.

- **Documentation**
  - `CODE_GUIDELINES.md` §1.2.1: seeds run on every start but exit early when already applied; mentions `bootstrap_seeds_applied?/0`.
  - `docs/admin-bootstrap-and-oidc-role-sync.md`: run_seeds skips when admin user exists; description of `run_seeds/0` updated.
  - `CHANGELOG.md` [Unreleased]: new “Seeds run only when needed” entry under Changed.

## Definition of Done
### Code Quality
- [x] No new technical depths
- [x] Linting passed
- [x] Documentation is added where needed

### Accessibility
- [x] New elements are properly defined with html-tags *(no new UI)*
- [x] Colour contrast follows WCAG criteria *(no new UI)*
- [x] Aria labels are added when needed *(no new UI)*
- [x] Everything is accessible by keyboard *(no new UI)*
- [x] Tab-Order is comprehensible *(no new UI)*
- [x] All interactive elements have a visible focus *(no new UI)*

### Testing
- [x] Tests for new code are written *(existing seeds and release tests cover behaviour; idempotency test still passes when second run skips)*
- [x] All tests pass
- [x] axe-core dev tools show no critical or major issues *(no UI changes)*

## Additional Notes

- **Review focus:** Logic in `Mv.Release` and `priv/repo/seeds.exs`; the “already applied” check is a single DB read for the admin user. On failure (e.g. DB down), `bootstrap_seeds_applied?/0` returns `false`, so seeds run (safe for first deploy).
- **Suggested check:** Run `mix test test/seeds_test.exs test/mv/release_test.exs` to confirm seeds and release behaviour.

Reviewed-on: #475
Co-authored-by: Simon <s.thiessen@local-it.org>
Co-committed-by: Simon <s.thiessen@local-it.org>
2026-03-16 19:27:31 +01:00
c381b86b5e Improve oidc only mode (#474)
All checks were successful
continuous-integration/drone/push Build is passing
## Description of the implemented changes
The changes were:
- [x] Bugfixing
- [x] New Feature
- [ ] Breaking Change
- [x] Refactoring

**OIDC-only mode improvements and UX tweaks (success toasts, unauthenticated redirect).**

## What has been changed?

### OIDC-only mode (new feature)
- **Admin settings:** "Only OIDC sign-in" is an immediate toggle at the top of the OIDC section (no save button). Enabling it also turns off "Allow direct registration". When OIDC-only is on, the registration checkbox is disabled and shows a tooltip (DaisyUI `<.tooltip>`).
- **Backend:** Password sign-in is forbidden via Ash policy (`OidcOnlyActive` check). Password registration is blocked via validation `OidcOnlyBlocksPasswordRegistration`. New plug `OidcOnlySignInRedirect`: when OIDC-only and OIDC are configured, GET `/sign-in` redirects to the OIDC flow; GET `/auth/user/password/sign_in_with_token` is rejected with redirect + flash. `AuthController.success/4` also rejects password sign-in when OIDC-only.
- **Tests:** GlobalSettingsLive (OIDC-only UI), AuthController (redirect and password sign-in rejection), User authentication (register_with_password blocked when OIDC-only).

### UX / behaviour (no new feature flag)
- **Success toasts:** Success flash messages auto-dismiss after 5 seconds via JS hook `FlashAutoDismiss` and optional `auto_clear_ms` on `<.flash>` (used for success in root layout and `flash_group`).
- **Unauthenticated users:** Redirect to sign-in without the "You don't have permission to access this page" flash; that message is only shown to logged-in users who lack access. Logic in `LiveHelpers` and `CheckPagePermission` plug; test updated accordingly.

### Other
- Layouts: comment about unprocessed join-request count no longer uses "TODO" (Credo).
- Gettext: German translation for "Home" (Startseite); POT/PO kept in sync.
- CHANGELOG: Unreleased section updated with the above.

## Definition of Done
### Code Quality
- [x] No new technical depths
- [x] Linting passed
- [x] Documentation is added where needed (module docs, comments where non-obvious)

### Accessibility
- [x] New elements are properly defined with html-tags (labels, aria-label on checkboxes)
- [x] Colour contrast follows WCAG criteria (unchanged)
- [x] Aria labels are added when needed (e.g. oidc-only and registration checkboxes)
- [x] Everything is accessible by keyboard (toggles and buttons unchanged)
- [x] Tab-Order is comprehensible
- [x] All interactive elements have a visible focus (existing patterns)

### Testing
- [x] Tests for new code are written (OIDC-only UI, auth controller, user auth; SMTP config builder and mailer)
- [x] All tests pass
- [ ] axe-core dev tools show no critical or major issues (not re-run for this PR; suggest spot-check on settings and sign-in)

## Additional Notes
- **OIDC-only:** When the `OIDC_ONLY` env var is set, the toggle is read-only and shows "(From OIDC_ONLY)". When OIDC is not configured, the toggle is disabled.
- **Invalidation:** Enabling OIDC-only sets `registration_enabled: false` in one update; disabling OIDC-only only updates `oidc_only` (registration left as-is).
- **Review focus:** Plug order in router (OidcOnlySignInRedirect), policy/validation order in User, and that all OIDC-only paths (form, plug, controller) stay consistent.

Reviewed-on: #474
Co-authored-by: Simon <s.thiessen@local-it.org>
Co-committed-by: Simon <s.thiessen@local-it.org>
2026-03-16 19:09:07 +01:00
e8f27690a1
refactor: unify smtp config logic
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-16 14:23:46 +01:00
e95c1d6254
fix: repaired smtp configuration for port 587
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-16 14:00:23 +01:00
c933144920
feat: unify page titles
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-13 19:01:50 +01:00
e8ec620d57
feat: add timezone handling
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-13 18:22:12 +01:00
349cee0ce6
refactor: review remarks
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-13 17:55:17 +01:00
09e4b64663
feat: allow disabling registration
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-13 16:40:39 +01:00
eb18209669
feat: rearrange smtp settings
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 15:56:02 +01:00
104faf7006
feat: add theme selector to unauthenticated pages
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-13 14:48:10 +01:00
99a8d64344
fix: translation of login page
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 14:11:54 +01:00
086ecdcb1b
feat: prevent join requests with equal mail
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 11:18:34 +01:00
40a4461d23
fix: join confirmation mail configuration
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-13 09:34:56 +01:00
a7481f6ab1
feat: improve field order for approvals and add seeds
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-12 16:15:57 +01:00
a5ce7cb921
fix group performance test
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
2026-03-12 15:46:52 +01:00
942f2afd9e
refactor: adress review
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-12 15:29:54 +01:00
4af80a8305
Merge remote-tracking branch 'origin/main' into feature/308-web-form
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-12 13:52:33 +01:00
a4f3aa5d6f
feat: add smtp settings
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-12 13:39:48 +01:00
03d91d4029 fix tests
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-11 11:40:32 +01:00
762402adf9 fix translations
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-11 11:30:26 +01:00
ca9e4accc8 fix formatting
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-11 11:25:16 +01:00
45c2f3e2b3 i18n: fix translations
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-11 11:13:21 +01:00
c4135308e6
test: add tests for smtp mailer config 2026-03-11 09:18:37 +01:00
f53a3ce3cc
refactor: integrate approval ui review changes
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
2026-03-11 02:20:29 +01:00
28f97184b3 Merge branch 'main' into feature/308-web-form
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 02:05:13 +01:00
86d9242d83
feat: add approval ui for join requests
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 02:04:03 +01:00
f79c9ac515 Merge pull request 'add public join form' (#466) from feature/308-web-form into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #466
2026-03-10 23:08:26 +01:00
021b709e6a
refactor: address review comments for join view
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
2026-03-10 22:54:41 +01:00
7686b63d7f
fix: use WCAG AA warning text class for Vereinfacht notice 2026-03-10 20:17:26 +01:00
a9c61f703d
fix: resolve Mix.env at compile time in Vereinfacht client
Mix.env() is not available in production releases. Use module
attribute so it is only evaluated at compile time.
2026-03-10 20:17:26 +01:00
f1d0526209
feat: add join form
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-10 18:25:17 +01:00
21812542ad
refactor: address review comments for join request settings
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
2026-03-10 16:47:38 +01:00
05e2a298fe
feat: add accessible drag&drop table component
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-10 15:40:28 +01:00
fa738aae88
feat: add join form settings
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-10 14:29:49 +01:00
5deb102e45
refactor: adress review comments
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:54:40 +01:00
0614592674
Merge remote-tracking branch 'origin/main' into feature/308-web-form
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:18:16 +01:00
6385fbc831
feat: add join confirmation and mail templating
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:15:12 +01:00
3672ef0d03
test: add tests for join mail confirmation
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-09 17:02:30 +01:00
f601550526 fix translations
Some checks reported errors
continuous-integration/drone/push Build was killed
2026-03-09 16:45:14 +01:00
ad6ef169ac
Merge remote-tracking branch 'origin/main' into feature/308-web-form
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2026-03-09 15:40:02 +01:00
a41d8498ac
refactor: apply review changes to joinrequest
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 15:36:19 +01:00
d032f1ca0c
Run bootstrap seeds in production; add RUN_DEV_SEEDS support
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
2026-03-09 15:16:02 +01:00
2515a679b8
feat: add join request resource
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 14:44:45 +01:00
8da22b3d88 Apply review feedback and fix Credo in fee type filter
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
- Index: use FilterParams and constants; fix parse recursion; validate fee type/group
  IDs; OR semantics for :in; build_query_params/reset_all_filters map-based API;
  alias order (Credo); Map.take list deprecation fix
- MemberFilterComponent: use FilterParams and constants; fee_type_filter_part
  helper (Credo nesting); in_not_in_filter_label_class; reset_all_filters map;
  button label for :not_in and combined filter count; fieldset borders
- Gettext: Fee types, filter count plural, 'without %{name}' (en/de)
2026-03-09 14:33:58 +01:00
ae07e3efc2 Add filter prefix constants and shared FilterParams module
- Mv.Constants: group_filter_prefix/0, fee_type_filter_prefix/0
- MvWeb.MemberLive.Index.FilterParams: parse_in_not_in_value/1 for URL param parsing
2026-03-09 14:33:58 +01:00
a8f12d1c91 Add member fee type filter to member list
- Filter by membership fee type in same style as groups (All/Yes/No per type)
- Index: load fee types, fee_type_filters, URL params, apply_fee_type_filters
- MemberFilterComponent: fee types section, events, reset, button label
- Refactor update_filters: extract parse/dispatch helpers to satisfy Credo complexity
2026-03-09 14:33:58 +01:00
fc7b035123
CSV export: robust apply_export_filters, single custom_field_ids_union, string boolean_filters, more tests
Some checks reported errors
continuous-integration/drone/push Build was killed
2026-03-04 21:15:54 +01:00
d71d5881cf
CSV export: apply cycle_status_filter and boolean_filters when exporting all 2026-03-04 21:15:54 +01:00
01b9ebd74b
Vereinfacht client: email normalization, multi-match warning, Bypass tests, doc note
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
- Normalize email (trim + downcase) before filter lookup
- Log warning when API returns multiple contacts for same email
- Add Bypass tests for find_contact_by_email (query params, empty/single response parsing)
- Document vereinfacht_required_field? as legacy/unused in vereinfacht-api.md
- Add bypass dependency (dev+test) for HTTP stubbing
2026-03-04 20:55:59 +01:00
9f169b9835
Vereinfacht: sync country with finance contact API
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-04 20:21:51 +01:00