From cc59a40a1b094ff135176ba5c05c5a92750007fa Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 10 Feb 2026 22:31:35 +0100 Subject: [PATCH] Add statistics route, permissions, and sidebar entry - /statistics route and PagePaths.statistics - Permission sets: viewer and admin can access /statistics - Sidebar link with can_access_page check - Plug and sidebar tests updated --- docs/page-permission-route-coverage.md | 1 + lib/mv/authorization/permission_sets.ex | 8 +++-- lib/mv_web/components/layouts/sidebar.ex | 8 +++++ lib/mv_web/page_paths.ex | 4 +++ lib/mv_web/router.ex | 3 ++ .../components/sidebar_authorization_test.exs | 12 ++++--- .../plugs/check_page_permission_test.exs | 31 +++++++++++++++++++ 7 files changed, 61 insertions(+), 6 deletions(-) diff --git a/docs/page-permission-route-coverage.md b/docs/page-permission-route-coverage.md index 9151a44..b8eafbd 100644 --- a/docs/page-permission-route-coverage.md +++ b/docs/page-permission-route-coverage.md @@ -26,6 +26,7 @@ This document lists all protected routes, which permission set may access them, | `/groups/new` | ✗ | ✗ | ✗ | ✓ | | `/groups/:slug` | ✗ | ✓ | ✓ | ✓ | | `/groups/:slug/edit` | ✗ | ✗ | ✗ | ✓ | +| `/statistics` | ✗ | ✓ | ✓ | ✓ | | `/admin/roles` | ✗ | ✗ | ✗ | ✓ | | `/admin/roles/new` | ✗ | ✗ | ✗ | ✓ | | `/admin/roles/:id` | ✗ | ✗ | ✗ | ✓ | diff --git a/lib/mv/authorization/permission_sets.ex b/lib/mv/authorization/permission_sets.ex index ea878a2..fffc818 100644 --- a/lib/mv/authorization/permission_sets.ex +++ b/lib/mv/authorization/permission_sets.ex @@ -178,7 +178,9 @@ defmodule Mv.Authorization.PermissionSets do # Groups overview "/groups", # Group detail - "/groups/:slug" + "/groups/:slug", + # Statistics + "/statistics" ] } end @@ -243,7 +245,9 @@ defmodule Mv.Authorization.PermissionSets do # Group detail "/groups/:slug", # Edit group - "/groups/:slug/edit" + "/groups/:slug/edit", + # Statistics + "/statistics" ] } end diff --git a/lib/mv_web/components/layouts/sidebar.ex b/lib/mv_web/components/layouts/sidebar.ex index 89519ae..1896f24 100644 --- a/lib/mv_web/components/layouts/sidebar.ex +++ b/lib/mv_web/components/layouts/sidebar.ex @@ -88,6 +88,14 @@ defmodule MvWeb.Layouts.Sidebar do /> <% end %> + <%= if can_access_page?(@current_user, PagePaths.statistics()) do %> + <.menu_item + href={~p"/statistics"} + icon="hero-chart-bar" + label={gettext("Statistics")} + /> + <% end %> + <%= if admin_menu_visible?(@current_user) do %> <.menu_group icon="hero-cog-6-tooth" diff --git a/lib/mv_web/page_paths.ex b/lib/mv_web/page_paths.ex index 5606c76..2720c0f 100644 --- a/lib/mv_web/page_paths.ex +++ b/lib/mv_web/page_paths.ex @@ -9,6 +9,7 @@ defmodule MvWeb.PagePaths do # Sidebar top-level menu paths @members "/members" @membership_fee_types "/membership_fee_types" + @statistics "/statistics" # Administration submenu paths (all must match router) @users "/users" @@ -31,6 +32,9 @@ defmodule MvWeb.PagePaths do @doc "Path for Membership Fee Types index (sidebar and page permission check)." def membership_fee_types, do: @membership_fee_types + @doc "Path for Statistics page (sidebar and page permission check)." + def statistics, do: @statistics + @doc "Paths for Administration menu; show group if user can access any of these." def admin_menu_paths, do: @admin_page_paths diff --git a/lib/mv_web/router.ex b/lib/mv_web/router.ex index 97e0642..4f8c8a5 100644 --- a/lib/mv_web/router.ex +++ b/lib/mv_web/router.ex @@ -73,6 +73,9 @@ defmodule MvWeb.Router do # Membership Fee Types Management live "/membership_fee_types", MembershipFeeTypeLive.Index, :index + + # Statistics + live "/statistics", StatisticsLive, :index live "/membership_fee_types/new", MembershipFeeTypeLive.Form, :new live "/membership_fee_types/:id/edit", MembershipFeeTypeLive.Form, :edit diff --git a/test/mv_web/components/sidebar_authorization_test.exs b/test/mv_web/components/sidebar_authorization_test.exs index 079572f..110d9e5 100644 --- a/test/mv_web/components/sidebar_authorization_test.exs +++ b/test/mv_web/components/sidebar_authorization_test.exs @@ -25,12 +25,13 @@ defmodule MvWeb.SidebarAuthorizationTest do end describe "sidebar menu with admin user" do - test "shows Members, Fee Types and Administration with all subitems" do + test "shows Members, Fee Types, Statistics and Administration with all subitems" do user = Fixtures.user_with_role_fixture("admin") html = render_sidebar(sidebar_assigns(user)) assert html =~ ~s(href="/members") assert html =~ ~s(href="/membership_fee_types") + assert html =~ ~s(href="/statistics") assert html =~ ~s(data-testid="sidebar-administration") assert html =~ ~s(href="/users") assert html =~ ~s(href="/groups") @@ -41,11 +42,12 @@ defmodule MvWeb.SidebarAuthorizationTest do end describe "sidebar menu with read_only user (Vorstand/Buchhaltung)" do - test "shows Members and Groups (from Administration)" do + test "shows Members, Statistics and Groups (from Administration)" do user = Fixtures.user_with_role_fixture("read_only") html = render_sidebar(sidebar_assigns(user)) assert html =~ ~s(href="/members") + assert html =~ ~s(href="/statistics") assert html =~ ~s(href="/groups") end @@ -61,11 +63,12 @@ defmodule MvWeb.SidebarAuthorizationTest do end describe "sidebar menu with normal_user (Kassenwart)" do - test "shows Members and Groups" do + test "shows Members, Statistics and Groups" do user = Fixtures.user_with_role_fixture("normal_user") html = render_sidebar(sidebar_assigns(user)) assert html =~ ~s(href="/members") + assert html =~ ~s(href="/statistics") assert html =~ ~s(href="/groups") end @@ -88,10 +91,11 @@ defmodule MvWeb.SidebarAuthorizationTest do refute html =~ ~s(href="/members") end - test "does not show Fee Types or Administration" do + test "does not show Statistics, Fee Types or Administration" do user = Fixtures.user_with_role_fixture("own_data") html = render_sidebar(sidebar_assigns(user)) + refute html =~ ~s(href="/statistics") refute html =~ ~s(href="/membership_fee_types") refute html =~ ~s(href="/users") refute html =~ ~s(data-testid="sidebar-administration") diff --git a/test/mv_web/plugs/check_page_permission_test.exs b/test/mv_web/plugs/check_page_permission_test.exs index 2e33474..e342744 100644 --- a/test/mv_web/plugs/check_page_permission_test.exs +++ b/test/mv_web/plugs/check_page_permission_test.exs @@ -107,6 +107,37 @@ defmodule MvWeb.Plugs.CheckPagePermissionTest do end end + describe "statistics route /statistics" do + test "read_only can access /statistics" do + user = Fixtures.user_with_role_fixture("read_only") + conn = conn_with_user("/statistics", user) |> CheckPagePermission.call([]) + + refute conn.halted + end + + test "normal_user can access /statistics" do + user = Fixtures.user_with_role_fixture("normal_user") + conn = conn_with_user("/statistics", user) |> CheckPagePermission.call([]) + + refute conn.halted + end + + test "admin can access /statistics" do + user = Fixtures.user_with_role_fixture("admin") + conn = conn_with_user("/statistics", user) |> CheckPagePermission.call([]) + + refute conn.halted + end + + test "own_data cannot access /statistics" do + user = Fixtures.user_with_role_fixture("own_data") + conn = conn_with_user("/statistics", user) |> CheckPagePermission.call([]) + + assert conn.halted + assert redirected_to(conn) == "/users/#{user.id}" + end + end + describe "read_only and normal_user denied on admin routes" do test "read_only cannot access /admin/roles" do user = Fixtures.user_with_role_fixture("read_only")