diff --git a/.env.example b/.env.example index c9cc51e..543579c 100644 --- a/.env.example +++ b/.env.example @@ -22,8 +22,8 @@ ASSOCIATION_NAME="Sportsclub XYZ" # These have defaults in docker-compose.prod.yml, only override if needed # OIDC_CLIENT_ID=mv # OIDC_BASE_URL=http://localhost:8080/auth/v1 -# OIDC_REDIRECT_URI=http://localhost:4001/auth/user/rauthy/callback -# OIDC_CLIENT_SECRET=your-rauthy-client-secret +# OIDC_REDIRECT_URI=http://localhost:4001/auth/user/oidc/callback +# OIDC_CLIENT_SECRET=your-oidc-client-secret # Optional: OIDC group → Admin role sync (e.g. Authentik groups from profile scope) # If OIDC_ADMIN_GROUP_NAME is set, users in that group get Admin role on registration/sign-in. diff --git a/CODE_GUIDELINES.md b/CODE_GUIDELINES.md index 3e2bbd0..50c9eca 100644 --- a/CODE_GUIDELINES.md +++ b/CODE_GUIDELINES.md @@ -983,9 +983,9 @@ defmodule Mv.Accounts.User do hashed_password_field :hashed_password end - oauth2 :rauthy do + oidc :oidc do client_id fn _, _ -> - Application.fetch_env!(:mv, :rauthy)[:client_id] + Application.fetch_env!(:mv, :oidc)[:client_id] end # ... other config end @@ -1866,7 +1866,7 @@ authentication do hashed_password_field :hashed_password end - oauth2 :rauthy do + oidc :oidc do # OIDC configuration end end @@ -2093,7 +2093,7 @@ plug :protect_from_forgery ```elixir # config/runtime.exs -config :mv, :rauthy, +config :mv, :oidc, client_id: System.get_env("OIDC_CLIENT_ID") || "mv", client_secret: System.get_env("OIDC_CLIENT_SECRET"), base_url: System.get_env("OIDC_BASE_URL") diff --git a/README.md b/README.md index 94adf08..b35d742 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Mila uses OIDC for Single Sign-On. In development, a local **Rauthy** instance i 3. Login with "admin@localhost" and password from `BOOTSTRAP_ADMIN_PASSWORD_PLAIN` in docker-compose.yml 4. add client from the admin panel - Client ID: mv - - redirect uris: http://localhost:4000/auth/user/rauthy/callback + - redirect uris: http://localhost:4000/auth/user/oidc/callback - Authorization Flows: authorization_code - allowed origins: http://localhost:4000 - access/id token algortihm: RS256 (EDDSA did not work for me, found just few infos in the ashauthentication docs) @@ -153,13 +153,13 @@ Now you can log in to Mila via OIDC! ### OIDC with other providers (Authentik, Keycloak, etc.) -Mila works with any OIDC-compliant provider. The internal strategy is named `:rauthy`, but this is just a name — it works with any provider. +Mila works with any OIDC-compliant provider. The internal strategy is named `:oidc` — it works with any OIDC-compliant provider. -**Important:** The redirect URI must always end with `/auth/user/rauthy/callback`. +**Important:** The redirect URI must always end with `/auth/user/oidc/callback`. Example for Authentik: 1. Create an OAuth2/OpenID Provider in Authentik -2. Set the redirect URI to: `https://your-domain.com/auth/user/rauthy/callback` +2. Set the redirect URI to: `https://your-domain.com/auth/user/oidc/callback` 3. Configure environment variables: ```bash DOMAIN=your-domain.com # or PHX_HOST=your-domain.com @@ -168,7 +168,7 @@ Example for Authentik: OIDC_CLIENT_SECRET=your-client-secret # or use OIDC_CLIENT_SECRET_FILE ``` -The `OIDC_REDIRECT_URI` is auto-generated as `https://{DOMAIN}/auth/user/rauthy/callback` if not explicitly set. +The `OIDC_REDIRECT_URI` is auto-generated as `https://{DOMAIN}/auth/user/oidc/callback` if not explicitly set. ## ⚙️ Configuration @@ -238,7 +238,7 @@ For testing the production Docker build locally: # OIDC_CLIENT_ID=mv # OIDC_BASE_URL=http://localhost:8080/auth/v1 # OIDC_CLIENT_SECRET= - # OIDC_REDIRECT_URI is auto-generated as https://{DOMAIN}/auth/user/rauthy/callback + # OIDC_REDIRECT_URI is auto-generated as https://{DOMAIN}/auth/user/oidc/callback # Alternative: Use _FILE variables for Docker secrets (takes priority over regular vars): # SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base diff --git a/assets/css/app.css b/assets/css/app.css index 0149c5d..21b1b25 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -357,4 +357,16 @@ } } +/* ============================================ + Collapsed Sidebar: User Menu Dropdown Richtung + ============================================ */ + +/* Bei eingeklappter Sidebar liegt der Avatar-Button am linken Rand. + dropdown-end würde das Menü nach links öffnen (off-screen). + Stattdessen nach rechts öffnen (in den Content-Bereich). */ +#app-layout[data-sidebar-expanded="false"] .dropdown.dropdown-top > ul.dropdown-content { + right: auto !important; + left: 0 !important; +} + /* This file is for your main application CSS */ diff --git a/assets/js/app.js b/assets/js/app.js index 267ae05..de3f154 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -86,6 +86,16 @@ Hooks.SidebarState = { this.setSidebarState(!current) } }, + + updated() { + // LiveView patches data-sidebar-expanded back to the template default ("true") + // on every DOM update. Re-apply the stored state from localStorage after each patch. + const expanded = localStorage.getItem('sidebar-expanded') !== 'false' + const current = this.el.dataset.sidebarExpanded === 'true' + if (current !== expanded) { + this.setSidebarState(expanded) + } + }, setSidebarState(expanded) { // Convert boolean to string for consistency @@ -228,6 +238,13 @@ document.addEventListener("DOMContentLoaded", () => { // Listen for changes to the drawer checkbox drawerToggle.addEventListener("change", () => { + // On desktop (lg:drawer-open), the mobile drawer must never open. + // The hamburger label is lg:hidden, but guard here as a safety net + // against any accidental toggles (e.g. from overlapping elements or JS). + if (drawerToggle.checked && window.innerWidth >= 1024) { + drawerToggle.checked = false + return + } const isOpen = drawerToggle.checked updateAriaExpanded() updateSidebarTabIndex(isOpen) diff --git a/config/dev.exs b/config/dev.exs index 9af8e74..e7b2af8 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -93,11 +93,11 @@ config :mv, :secret_key_base, "ryn7D6ssmIHQFWIks2sFiTGATgwwAR1+3bN8p7fy6qVtB8qnx # Signing Secret for Authentication config :mv, :token_signing_secret, "IwUwi65TrEeExwBXXFPGm2I7889NsL" -config :mv, :rauthy, +config :mv, :oidc, client_id: "mv", base_url: "http://localhost:8080/auth/v1", client_secret: System.get_env("OIDC_CLIENT_SECRET"), - redirect_uri: "http://localhost:4000/auth/user/rauthy/callback" + redirect_uri: "http://localhost:4000/auth/user/oidc/callback" # AshAuthentication development configuration config :mv, :session_identifier, :jti diff --git a/config/runtime.exs b/config/runtime.exs index f1df5b7..93df5bb 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -129,8 +129,7 @@ if config_env() == :prod do config :mv, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") # OIDC configuration (works with any OIDC provider: Authentik, Rauthy, Keycloak, etc.) - # Note: The strategy is named :rauthy internally, but works with any OIDC provider. - # The redirect_uri callback path is always /auth/user/rauthy/callback regardless of provider. + # The redirect_uri callback path is /auth/user/oidc/callback. # # Supports OIDC_CLIENT_SECRET or OIDC_CLIENT_SECRET_FILE for Docker secrets. # OIDC_CLIENT_SECRET is required only if OIDC is being used (indicated by explicit OIDC env vars). @@ -150,9 +149,9 @@ if config_env() == :prod do # Build redirect_uri: use OIDC_REDIRECT_URI if set, otherwise build from host. # Uses HTTPS since production runs behind TLS termination. - default_redirect_uri = "https://#{host}/auth/user/rauthy/callback" + default_redirect_uri = "https://#{host}/auth/user/oidc/callback" - config :mv, :rauthy, + config :mv, :oidc, client_id: oidc_client_id || "mv", base_url: oidc_base_url || "http://localhost:8080/auth/v1", client_secret: client_secret, diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 1ed863a..2c342f9 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -18,11 +18,11 @@ services: PHX_HOST: "${PHX_HOST:-localhost}" PORT: "4001" PHX_SERVER: "true" - # Rauthy OIDC config - use host.docker.internal to reach host services + # OIDC config - use host.docker.internal to reach host services OIDC_CLIENT_ID: "mv" OIDC_BASE_URL: "http://host.docker.internal:8080/auth/v1" OIDC_CLIENT_SECRET_FILE: "/run/secrets/oidc_client_secret" - OIDC_REDIRECT_URI: "http://localhost:4001/auth/user/rauthy/callback" + OIDC_REDIRECT_URI: "http://localhost:4001/auth/user/oidc/callback" secrets: - db_password - secret_key_base diff --git a/docs/admin-bootstrap-and-oidc-role-sync.md b/docs/admin-bootstrap-and-oidc-role-sync.md index b0da019..ef7c4ce 100644 --- a/docs/admin-bootstrap-and-oidc-role-sync.md +++ b/docs/admin-bootstrap-and-oidc-role-sync.md @@ -39,8 +39,8 @@ ### Where It Runs -1. Registration: register_with_rauthy after_action calls OidcRoleSync. -2. Sign-in: sign_in_with_rauthy prepare after_action calls OidcRoleSync for each user. +1. Registration: register_with_oidc after_action calls OidcRoleSync. +2. Sign-in: sign_in_with_oidc prepare after_action calls OidcRoleSync for each user. ### Internal Action diff --git a/docs/development-progress-log.md b/docs/development-progress-log.md index 1dcf994..97c586b 100644 --- a/docs/development-progress-log.md +++ b/docs/development-progress-log.md @@ -886,7 +886,7 @@ just regen-migrations **Checklist:** 1. ✅ Rauthy running: `docker compose ps` 2. ✅ Client created in Rauthy admin panel -3. ✅ Redirect URI matches exactly: `http://localhost:4000/auth/user/rauthy/callback` +3. ✅ Redirect URI matches exactly: `http://localhost:4000/auth/user/oidc/callback` 4. ✅ OIDC_CLIENT_SECRET in .env 5. ✅ App restarted after .env update diff --git a/docs/feature-roadmap.md b/docs/feature-roadmap.md index 41b3d83..b699560 100644 --- a/docs/feature-roadmap.md +++ b/docs/feature-roadmap.md @@ -501,8 +501,8 @@ Since this is a **Phoenix LiveView** application with **Ash Framework**, we have |--------|-------|---------|------|---------|----------| | `GET` | `/auth/user/password/sign_in` | Show password login form | 🔓 | - | HTML form | | `POST` | `/auth/user/password/sign_in` | Submit password login | 🔓 | `{email, password}` | Redirect + session cookie | -| `GET` | `/auth/user/rauthy` | Initiate OIDC flow | 🔓 | - | Redirect to Rauthy | -| `GET` | `/auth/user/rauthy/callback` | Handle OIDC callback | 🔓 | `{code, state}` | Redirect + session cookie | +| `GET` | `/auth/user/oidc` | Initiate OIDC flow | 🔓 | - | Redirect to Rauthy | +| `GET` | `/auth/user/oidc/callback` | Handle OIDC callback | 🔓 | `{code, state}` | Redirect + session cookie | | `POST` | `/auth/user/sign_out` | Sign out user | 🔐 | - | Redirect to login | | `GET` | `/auth/link-oidc-account` | OIDC account linking (password verification) | 🔓 | - | LiveView form | ✅ Implemented | | `GET` | `/auth/user/password/reset` | Show password reset form | 🔓 | - | HTML form | @@ -515,9 +515,9 @@ Since this is a **Phoenix LiveView** application with **Ash Framework**, we have | Resource | Action | Purpose | Auth | Input | Output | |----------|--------|---------|------|-------|--------| | `User` | `:sign_in_with_password` | Password authentication | 🔓 | `{email, password}` | `{:ok, user}` or `{:error, reason}` | -| `User` | `:sign_in_with_rauthy` | OIDC authentication | 🔓 | `{oidc_id, email, user_info}` | `{:ok, user}` or `{:error, reason}` | +| `User` | `:sign_in_with_oidc` | OIDC authentication | 🔓 | `{oidc_id, email, user_info}` | `{:ok, user}` or `{:error, reason}` | | `User` | `:register_with_password` | Create user with password | 🔓 | `{email, password}` | `{:ok, user}` | -| `User` | `:register_with_rauthy` | Create user via OIDC | 🔓 | `{oidc_id, email}` | `{:ok, user}` | +| `User` | `:register_with_oidc` | Create user via OIDC | 🔓 | `{oidc_id, email}` | `{:ok, user}` | | `User` | `:request_password_reset` | Generate reset token | 🔓 | `{email}` | `{:ok, token}` | | `User` | `:reset_password` | Reset password with token | 🔓 | `{token, password}` | `{:ok, user}` | | `Token` | `:revoke` | Revoke authentication token | 🔐 | `{jti}` | `{:ok, token}` | diff --git a/docs/oidc-account-linking.md b/docs/oidc-account-linking.md index 29c2233..570d4e8 100644 --- a/docs/oidc-account-linking.md +++ b/docs/oidc-account-linking.md @@ -10,10 +10,10 @@ This feature implements secure account linking between password-based accounts a #### 1. Security Fix: `lib/accounts/user.ex` -**Change**: The `sign_in_with_rauthy` action now filters by `oidc_id` instead of `email`. +**Change**: The `sign_in_with_oidc` action now filters by `oidc_id` instead of `email`. ```elixir -read :sign_in_with_rauthy do +read :sign_in_with_oidc do argument :user_info, :map, allow_nil?: false argument :oauth_tokens, :map, allow_nil?: false prepare AshAuthentication.Strategy.OAuth2.SignInPreparation diff --git a/lib/accounts/accounts.ex b/lib/accounts/accounts.ex index 13218e0..071112a 100644 --- a/lib/accounts/accounts.ex +++ b/lib/accounts/accounts.ex @@ -9,7 +9,7 @@ defmodule Mv.Accounts do ## Public API The domain exposes these main actions: - User CRUD: `create_user/1`, `list_users/0`, `update_user/2`, `destroy_user/1` - - Authentication: `create_register_with_rauthy/1`, `read_sign_in_with_rauthy/1` + - Authentication: `create_register_with_oidc/1`, `read_sign_in_with_oidc/1` """ use Ash.Domain, extensions: [AshAdmin.Domain, AshPhoenix] @@ -24,8 +24,8 @@ defmodule Mv.Accounts do define :list_users, action: :read define :update_user, action: :update_user define :destroy_user, action: :destroy - define :create_register_with_rauthy, action: :register_with_rauthy - define :read_sign_in_with_rauthy, action: :sign_in_with_rauthy + define :create_register_with_oidc, action: :register_with_oidc + define :read_sign_in_with_oidc, action: :sign_in_with_oidc end resource Mv.Accounts.Token diff --git a/lib/accounts/user.ex b/lib/accounts/user.ex index 9ac7605..5e24445 100644 --- a/lib/accounts/user.ex +++ b/lib/accounts/user.ex @@ -28,7 +28,7 @@ defmodule Mv.Accounts.User do @doc """ AshAuthentication specific: Defines the strategies we want to use for authentication. - Currently password and SSO with Rauthy as OIDC provider + Currently password and SSO via OIDC (supports any provider: Authentik, Rauthy, Keycloak, etc.) """ authentication do session_identifier Application.compile_env!(:mv, :session_identifier) @@ -52,7 +52,7 @@ defmodule Mv.Accounts.User do end strategies do - oidc :rauthy do + oidc :oidc do client_id Mv.Secrets base_url Mv.Secrets redirect_uri Mv.Secrets @@ -88,7 +88,7 @@ defmodule Mv.Accounts.User do # Always use one of these explicit create actions instead: # - :create_user (for manual user creation with optional member link) # - :register_with_password (for password-based registration) - # - :register_with_rauthy (for OIDC-based registration) + # - :register_with_oidc (for OIDC-based registration) defaults [:read] destroy :destroy do @@ -267,7 +267,7 @@ defmodule Mv.Accounts.User do prepare AshAuthentication.Preparations.FilterBySubject end - read :sign_in_with_rauthy do + read :sign_in_with_oidc do # Single record expected; required for AshAuthentication OAuth2 strategy (returns list of 0 or 1). get? true argument :user_info, :map, allow_nil?: false @@ -302,7 +302,7 @@ defmodule Mv.Accounts.User do end) end - create :register_with_rauthy do + create :register_with_oidc do argument :user_info, :map, allow_nil?: false argument :oauth_tokens, :map, allow_nil?: false upsert? true diff --git a/lib/membership/custom_field.ex b/lib/membership/custom_field.ex index 411e95d..ef6c79a 100644 --- a/lib/membership/custom_field.ex +++ b/lib/membership/custom_field.ex @@ -52,7 +52,8 @@ defmodule Mv.Membership.CustomField do use Ash.Resource, domain: Mv.Membership, data_layer: AshPostgres.DataLayer, - authorizers: [Ash.Policy.Authorizer] + authorizers: [Ash.Policy.Authorizer], + primary_read_warning?: false postgres do table "custom_fields" @@ -60,9 +61,13 @@ defmodule Mv.Membership.CustomField do end actions do - defaults [:read] default_accept [:name, :value_type, :description, :required, :show_in_overview] + read :read do + primary? true + prepare build(sort: [name: :asc]) + end + create :create do accept [:name, :value_type, :description, :required, :show_in_overview] change Mv.Membership.Changes.GenerateSlug diff --git a/lib/mv/oidc_role_sync.ex b/lib/mv/oidc_role_sync.ex index f268154..fbec9de 100644 --- a/lib/mv/oidc_role_sync.ex +++ b/lib/mv/oidc_role_sync.ex @@ -2,7 +2,7 @@ defmodule Mv.OidcRoleSync do @moduledoc """ Syncs user role from OIDC user_info (e.g. groups claim → Admin role). - Used after OIDC registration (register_with_rauthy) and on sign-in so that + Used after OIDC registration (register_with_oidc) and on sign-in so that users in the configured admin group get the Admin role; others get Mitglied. Configure via OIDC_ADMIN_GROUP_NAME and OIDC_GROUPS_CLAIM (see OidcRoleSyncConfig). diff --git a/lib/mv/secrets.ex b/lib/mv/secrets.ex index ee1519e..d3bc30d 100644 --- a/lib/mv/secrets.ex +++ b/lib/mv/secrets.ex @@ -7,7 +7,7 @@ defmodule Mv.Secrets do particularly for OIDC (Rauthy) authentication. ## Configuration Source - Secrets are read from the `:rauthy` key in the application configuration, + Secrets are read from the `:oidc` key in the application configuration, which is typically set in `config/runtime.exs` from environment variables: - `OIDC_CLIENT_ID` - `OIDC_CLIENT_SECRET` @@ -21,7 +21,7 @@ defmodule Mv.Secrets do use AshAuthentication.Secret def secret_for( - [:authentication, :strategies, :rauthy, :client_id], + [:authentication, :strategies, :oidc, :client_id], Mv.Accounts.User, _opts, _meth @@ -30,7 +30,7 @@ defmodule Mv.Secrets do end def secret_for( - [:authentication, :strategies, :rauthy, :redirect_uri], + [:authentication, :strategies, :oidc, :redirect_uri], Mv.Accounts.User, _opts, _meth @@ -39,7 +39,7 @@ defmodule Mv.Secrets do end def secret_for( - [:authentication, :strategies, :rauthy, :client_secret], + [:authentication, :strategies, :oidc, :client_secret], Mv.Accounts.User, _opts, _meth @@ -48,7 +48,7 @@ defmodule Mv.Secrets do end def secret_for( - [:authentication, :strategies, :rauthy, :base_url], + [:authentication, :strategies, :oidc, :base_url], Mv.Accounts.User, _opts, _meth @@ -58,7 +58,7 @@ defmodule Mv.Secrets do defp get_config(key) do :mv - |> Application.fetch_env!(:rauthy) + |> Application.fetch_env!(:oidc) |> Keyword.fetch!(key) |> then(&{:ok, &1}) end diff --git a/lib/mv_web/components/layouts.ex b/lib/mv_web/components/layouts.ex index 0a0da4c..89e3549 100644 --- a/lib/mv_web/components/layouts.ex +++ b/lib/mv_web/components/layouts.ex @@ -54,7 +54,7 @@ defmodule MvWeb.Layouts do data-sidebar-expanded="true" phx-hook="SidebarState" > - +
diff --git a/lib/mv_web/controllers/auth_controller.ex b/lib/mv_web/controllers/auth_controller.ex index d9690df..28f3846 100644 --- a/lib/mv_web/controllers/auth_controller.ex +++ b/lib/mv_web/controllers/auth_controller.ex @@ -48,8 +48,8 @@ defmodule MvWeb.AuthController do log_failure_safely(activity, reason) case {activity, reason} do - {{:rauthy, _action}, reason} -> - handle_rauthy_failure(conn, reason) + {{:oidc, _action}, reason} -> + handle_oidc_failure(conn, reason) {_, %AshAuthentication.Errors.AuthenticationFailed{caused_by: caused_by}} -> handle_authentication_failed(conn, caused_by) @@ -61,8 +61,8 @@ defmodule MvWeb.AuthController do end end - # Log authentication failures safely, avoiding sensitive data for {:rauthy, _} activities - defp log_failure_safely({:rauthy, _action} = activity, reason) do + # Log authentication failures safely, avoiding sensitive data for {:oidc, _} activities + defp log_failure_safely({:oidc, _action} = activity, reason) do # For Assent errors, use safe_assent_meta to avoid logging tokens/URLs with query params case reason do %Assent.ServerUnreachableError{} = err -> @@ -76,7 +76,7 @@ defmodule MvWeb.AuthController do Logger.warning(message) _ -> - # For other rauthy errors, log only error type, not full details + # For other OIDC errors, log only error type, not full details error_type = get_error_type(reason) Logger.warning( @@ -86,7 +86,7 @@ defmodule MvWeb.AuthController do end defp log_failure_safely(activity, reason) do - # For non-rauthy activities, safe to log full reason + # For non-OIDC activities, safe to log full reason Logger.warning( "Authentication failure - Activity: #{inspect(activity)}, Reason: #{inspect(reason)}" ) @@ -119,12 +119,12 @@ defmodule MvWeb.AuthController do if Enum.empty?(parts), do: "", else: " - " <> Enum.join(parts, ", ") end - # Handle all Rauthy (OIDC) authentication failures - defp handle_rauthy_failure(conn, %Ash.Error.Invalid{errors: errors}) do + # Handle all OIDC authentication failures + defp handle_oidc_failure(conn, %Ash.Error.Invalid{errors: errors}) do handle_oidc_email_collision(conn, errors) end - defp handle_rauthy_failure(conn, %AshAuthentication.Errors.AuthenticationFailed{ + defp handle_oidc_failure(conn, %AshAuthentication.Errors.AuthenticationFailed{ caused_by: caused_by }) do case caused_by do @@ -139,7 +139,7 @@ defmodule MvWeb.AuthController do end # Handle Assent server unreachable errors (network/connectivity issues) - defp handle_rauthy_failure(conn, %Assent.ServerUnreachableError{} = _err) do + defp handle_oidc_failure(conn, %Assent.ServerUnreachableError{} = _err) do # Logging already done safely in failure/3 via log_failure_safely/2 # No need to log again here to avoid duplicate logs @@ -152,7 +152,7 @@ defmodule MvWeb.AuthController do end # Handle Assent invalid response errors (configuration or malformed responses) - defp handle_rauthy_failure(conn, %Assent.InvalidResponseError{} = _err) do + defp handle_oidc_failure(conn, %Assent.InvalidResponseError{} = _err) do # Logging already done safely in failure/3 via log_failure_safely/2 # No need to log again here to avoid duplicate logs @@ -165,7 +165,7 @@ defmodule MvWeb.AuthController do end # Catch-all clause for any other error types - defp handle_rauthy_failure(conn, _reason) do + defp handle_oidc_failure(conn, _reason) do # Logging already done safely in failure/3 via log_failure_safely/2 # No need to log again here to avoid duplicate logs diff --git a/lib/mv_web/live/auth/link_oidc_account_live.ex b/lib/mv_web/live/auth/link_oidc_account_live.ex index 325a2fd..b6c24b1 100644 --- a/lib/mv_web/live/auth/link_oidc_account_live.ex +++ b/lib/mv_web/live/auth/link_oidc_account_live.ex @@ -84,7 +84,7 @@ defmodule MvWeb.LinkOidcAccountLive do :info, dgettext("auth", "Account activated! Redirecting to complete sign-in...") ) - |> Phoenix.LiveView.redirect(to: ~p"/auth/user/rauthy") + |> Phoenix.LiveView.redirect(to: ~p"/auth/user/oidc") {:error, error} -> Logger.warning( @@ -223,7 +223,7 @@ defmodule MvWeb.LinkOidcAccountLive do "Your OIDC account has been successfully linked! Redirecting to complete sign-in..." ) ) - |> Phoenix.LiveView.redirect(to: ~p"/auth/user/rauthy")} + |> Phoenix.LiveView.redirect(to: ~p"/auth/user/oidc")} {:error, error} -> Logger.warning( diff --git a/lib/mv_web/live/member_live/show/membership_fees_component.ex b/lib/mv_web/live/member_live/show/membership_fees_component.ex index 1ce6f77..b8757a0 100644 --- a/lib/mv_web/live/member_live/show/membership_fees_component.ex +++ b/lib/mv_web/live/member_live/show/membership_fees_component.ex @@ -214,47 +214,49 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do <:action :let={cycle}> -
+
<%= if @can_update_cycle do %> - - - +
+ + + +
<% end %> <%= if @can_destroy_cycle do %>