defmodule MvWeb.JoinConfirmController do @moduledoc """ Handles GET /confirm_join/:token for the public join flow (double opt-in). Renders a full HTML page with public header and hero layout (success, expired, or invalid). Calls a configurable callback (default Mv.Membership) so tests can stub the dependency. Public route; no authentication required. """ use MvWeb, :controller def confirm(conn, %{"token" => token}) when is_binary(token) do callback = Application.get_env(:mv, :join_confirm_callback, Mv.Membership) case callback.confirm_join_request(token, actor: nil) do {:ok, _request} -> success_response(conn) {:error, :token_expired} -> expired_response(conn) {:error, _} -> invalid_response(conn) end end def confirm(conn, _params), do: invalid_response(conn) defp success_response(conn) do conn |> assign_confirm_assigns(:success) |> put_view(MvWeb.JoinConfirmHTML) |> render("confirm.html") end defp expired_response(conn) do conn |> assign_confirm_assigns(:expired) |> put_view(MvWeb.JoinConfirmHTML) |> render("confirm.html") end defp invalid_response(conn) do conn |> put_status(404) |> assign_confirm_assigns(:invalid) |> put_view(MvWeb.JoinConfirmHTML) |> render("confirm.html") end defp assign_confirm_assigns(conn, result) do club_name = case Mv.Membership.get_settings() do {:ok, settings} -> settings.club_name || "Mitgliederverwaltung" _ -> "Mitgliederverwaltung" end conn |> assign(:result, result) |> assign(:club_name, club_name) |> assign(:csrf_token, Plug.CSRFProtection.get_csrf_token()) end end