From 613a5f2643a8b404098b0c28a10a03d8daa98869 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 21:51:12 +0100 Subject: [PATCH 1/3] feat: support email scope to retrieve oidc info --- lib/accounts/user.ex | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/accounts/user.ex b/lib/accounts/user.ex index 749740d..3b7e80b 100644 --- a/lib/accounts/user.ex +++ b/lib/accounts/user.ex @@ -69,7 +69,7 @@ defmodule Mv.Accounts.User do # Default actions for framework/tooling integration: # - :read -> Standard read used across the app and by admin tooling. # - :destroy-> Standard delete used by admin tooling and maintenance tasks. - # + # # NOTE: :create is INTENTIONALLY excluded from defaults! # Using a default :create would bypass email-synchronization logic. # Always use one of these explicit create actions instead: @@ -185,7 +185,9 @@ defmodule Mv.Accounts.User do oidc_user_info = Ash.Changeset.get_argument(changeset, :oidc_user_info) # Get the new email from OIDC user_info - new_email = Map.get(oidc_user_info, "preferred_username") + # Support both "email" (standard OIDC) and "preferred_username" (Rauthy) + new_email = + Map.get(oidc_user_info, "email") || Map.get(oidc_user_info, "preferred_username") changeset |> Ash.Changeset.change_attribute(:oidc_id, oidc_id) @@ -239,8 +241,11 @@ defmodule Mv.Accounts.User do change fn changeset, _ctx -> user_info = Ash.Changeset.get_argument(changeset, :user_info) + # Support both "email" (standard OIDC like Authentik, Keycloak) and "preferred_username" (Rauthy) + email = user_info["email"] || user_info["preferred_username"] + changeset - |> Ash.Changeset.change_attribute(:email, user_info["preferred_username"]) + |> Ash.Changeset.change_attribute(:email, email) |> Ash.Changeset.change_attribute(:oidc_id, user_info["sub"] || user_info["id"]) end From 9cda832b82bf79307e65d293860f9ba5ad531e0b Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 22:02:23 +0100 Subject: [PATCH 2/3] fix: request scopes email and profile --- lib/accounts/user.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/accounts/user.ex b/lib/accounts/user.ex index 3b7e80b..dbc62b2 100644 --- a/lib/accounts/user.ex +++ b/lib/accounts/user.ex @@ -54,6 +54,9 @@ defmodule Mv.Accounts.User do auth_method :client_secret_jwt code_verifier true + # Request email and profile scopes from OIDC provider (required for Authentik, Keycloak, etc.) + authorization_params scope: "openid email profile" + # id_token_signed_response_alg "EdDSA" #-> https://git.local-it.org/local-it/mitgliederverwaltung/issues/87 end From 2f6d5ff81864ee4a9eec87d66126b2f5ffd5555f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Eppl=C3=A9e?= Date: Wed, 3 Dec 2025 21:25:39 +0100 Subject: [PATCH 3/3] Add simple sidebar --- lib/mv_web/components/layouts.ex | 36 ++++++++--- lib/mv_web/components/layouts/navbar.ex | 64 ++++++++----------- lib/mv_web/components/layouts/sidebar.ex | 80 ++++++++++++++++++++++++ priv/gettext/de/LC_MESSAGES/default.po | 19 +++--- priv/gettext/default.pot | 15 +++-- priv/gettext/en/LC_MESSAGES/default.po | 15 +++-- 6 files changed, 162 insertions(+), 67 deletions(-) create mode 100644 lib/mv_web/components/layouts/sidebar.ex diff --git a/lib/mv_web/components/layouts.ex b/lib/mv_web/components/layouts.ex index 487a01f..d45b8d5 100644 --- a/lib/mv_web/components/layouts.ex +++ b/lib/mv_web/components/layouts.ex @@ -10,6 +10,7 @@ defmodule MvWeb.Layouts do use MvWeb, :html use Gettext, backend: MvWeb.Gettext import MvWeb.Layouts.Navbar + import MvWeb.Layouts.Sidebar embed_templates "layouts/*" @@ -39,20 +40,39 @@ defmodule MvWeb.Layouts do slot :inner_block, required: true def app(assigns) do + club_name = get_club_name() + assigns = assign(assigns, :club_name, club_name) + ~H""" - <%= if @current_user do %> - <.navbar current_user={@current_user} /> - <% end %> -
-
- {render_slot(@inner_block)} +
+ +
+ <%= if @current_user do %> + <.navbar current_user={@current_user} /> + <% end %> +
+
+ {render_slot(@inner_block)} +
+
-
+ + <.sidebar current_user={@current_user} club_name={@club_name} /> + <.flash_group flash={@flash} /> """ end + # Helper function to get club name from settings + # Falls back to "Mitgliederverwaltung" if settings can't be loaded + defp get_club_name do + case Mv.Membership.get_settings() do + {:ok, settings} -> settings.club_name + _ -> "Mitgliederverwaltung" + end + end + @doc """ Shows the flash group with standard titles and content. @@ -65,7 +85,7 @@ defmodule MvWeb.Layouts do def flash_group(assigns) do ~H""" -
+
<.flash kind={:success} flash={@flash} /> <.flash kind={:warning} flash={@flash} /> <.flash kind={:info} flash={@flash} /> diff --git a/lib/mv_web/components/layouts/navbar.ex b/lib/mv_web/components/layouts/navbar.ex index 4246c99..8258d43 100644 --- a/lib/mv_web/components/layouts/navbar.ex +++ b/lib/mv_web/components/layouts/navbar.ex @@ -6,37 +6,35 @@ defmodule MvWeb.Layouts.Navbar do use Gettext, backend: MvWeb.Gettext use MvWeb, :verified_routes - alias Mv.Membership - attr :current_user, :map, required: true, doc: "The current user - navbar is only shown when user is present" def navbar(assigns) do - club_name = get_club_name() - - assigns = assign(assigns, :club_name, club_name) - ~H""" -