All checks were successful
Deploy Development / deploy (push) Successful in 40s
Test Suite / pytest-backend (push) Successful in 25s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 8s
Test Suite / playwright-tests (push) Successful in 23s
Test Suite / pytest-backend (pull_request) Successful in 23s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 6s
Test Suite / playwright-tests (pull_request) Successful in 30s
- Updated visibility logic for exercises, media assets, and training programs to ensure access is correctly managed based on active club memberships. - Refactored SQL queries to streamline visibility checks for platform admins and club members, ensuring only relevant content is displayed. - Improved user interface elements to reflect the status of club memberships, including visual indicators for inactive memberships. - Enhanced test cases to validate the new visibility logic and ensure proper access control across various components.
163 lines
4.7 KiB
Python
163 lines
4.7 KiB
Python
"""Unit tests ohne Datenbank für die Zugriffsschicht (Visibility-SQL, Header-Parsing)."""
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
from tenant_context import library_content_visibility_sql, parse_active_club_header, resolve_tenant_context
|
|
|
|
|
|
def test_library_visibility_sql_platform_admin_restricts_club_by_membership():
|
|
sql, params = library_content_visibility_sql(
|
|
alias="e",
|
|
profile_id=1,
|
|
role="admin",
|
|
effective_club_id=None,
|
|
)
|
|
assert "e.visibility = 'official'" in sql
|
|
assert "club_members" in sql
|
|
assert params == [1, 1]
|
|
|
|
|
|
def test_library_visibility_sql_superadmin_uses_membership_clause_for_club_visibility():
|
|
sql, params = library_content_visibility_sql(
|
|
alias="fp",
|
|
profile_id=2,
|
|
role="superadmin",
|
|
effective_club_id=100,
|
|
)
|
|
assert "club_members" in sql
|
|
assert params == [2, 2]
|
|
|
|
|
|
def test_library_visibility_sql_trainer_without_active_club_no_shared_club_branch():
|
|
sql, params = library_content_visibility_sql(
|
|
alias="g",
|
|
profile_id=42,
|
|
role="trainer",
|
|
effective_club_id=None,
|
|
)
|
|
assert "official" in sql
|
|
assert "private" in sql
|
|
assert "visibility = 'club'" not in sql
|
|
assert params == [42]
|
|
|
|
|
|
def test_library_visibility_sql_user_with_active_club_includes_club_branch():
|
|
sql, params = library_content_visibility_sql(
|
|
alias="t",
|
|
profile_id=7,
|
|
role="user",
|
|
effective_club_id=99,
|
|
)
|
|
assert "visibility = 'club'" in sql
|
|
assert "club_members" in sql
|
|
assert params[0] == 7 # private branch created_by
|
|
assert 99 in params
|
|
assert params.count(7) >= 2 # private + EXISTS membership
|
|
|
|
|
|
def test_parse_active_club_header_none_and_empty():
|
|
assert parse_active_club_header(None) is None
|
|
assert parse_active_club_header("") is None
|
|
assert parse_active_club_header(" ") is None
|
|
|
|
|
|
def test_parse_active_club_header_valid():
|
|
assert parse_active_club_header("12") == 12
|
|
|
|
|
|
def test_parse_active_club_header_invalid():
|
|
with pytest.raises(HTTPException) as exc:
|
|
parse_active_club_header("not-int")
|
|
assert exc.value.status_code == 400
|
|
|
|
|
|
def test_parse_active_club_header_non_positive():
|
|
with pytest.raises(HTTPException) as exc:
|
|
parse_active_club_header("0")
|
|
assert exc.value.status_code == 400
|
|
|
|
|
|
def test_resolve_platform_admin_uses_stored_club_without_header(monkeypatch):
|
|
"""Ohne X-Active-Club-Id: effective wie gespeichertes Profil (Sync mit Dropdown/DB)."""
|
|
cur = object()
|
|
|
|
def fake_exists(c, cid):
|
|
return cid == 99
|
|
|
|
monkeypatch.setattr("tenant_context._club_exists", fake_exists)
|
|
ctx = resolve_tenant_context(
|
|
cur,
|
|
profile_id=1,
|
|
global_role="admin",
|
|
header_raw=None,
|
|
memberships=[{"id": 10}],
|
|
stored_active_club_id=99,
|
|
)
|
|
assert ctx.effective_club_id == 99
|
|
|
|
|
|
def test_resolve_platform_admin_header_overrides_stored(monkeypatch):
|
|
cur = object()
|
|
|
|
def fake_exists(c, cid):
|
|
return cid in (5, 99)
|
|
|
|
monkeypatch.setattr("tenant_context._club_exists", fake_exists)
|
|
ctx = resolve_tenant_context(
|
|
cur,
|
|
profile_id=1,
|
|
global_role="superadmin",
|
|
header_raw="5",
|
|
memberships=[{"id": 10}],
|
|
stored_active_club_id=99,
|
|
)
|
|
assert ctx.effective_club_id == 5
|
|
|
|
|
|
def test_resolve_platform_admin_no_header_stored_invalid(monkeypatch):
|
|
cur = object()
|
|
monkeypatch.setattr("tenant_context._club_exists", lambda c, cid: False)
|
|
ctx = resolve_tenant_context(
|
|
cur,
|
|
profile_id=1,
|
|
global_role="admin",
|
|
header_raw=None,
|
|
memberships=[{"id": 1}],
|
|
stored_active_club_id=123,
|
|
)
|
|
assert ctx.effective_club_id is None
|
|
|
|
|
|
def test_resolve_trainer_club_ids_excludes_inactive_memberships():
|
|
"""Nur aktive Vereinszugänge zählen für Mandant / Header-Validierung."""
|
|
cur = object()
|
|
ctx = resolve_tenant_context(
|
|
cur,
|
|
profile_id=9,
|
|
global_role="user",
|
|
header_raw=None,
|
|
memberships=[
|
|
{"id": 10, "membership_status": "inactive"},
|
|
{"id": 20, "membership_status": "active"},
|
|
],
|
|
stored_active_club_id=None,
|
|
invalid_header_policy="ignore",
|
|
)
|
|
assert ctx.club_ids == frozenset({20})
|
|
assert ctx.effective_club_id == 20
|
|
|
|
|
|
def test_resolve_all_memberships_inactive_no_effective_club():
|
|
cur = object()
|
|
ctx = resolve_tenant_context(
|
|
cur,
|
|
profile_id=9,
|
|
global_role="user",
|
|
header_raw=None,
|
|
memberships=[{"id": 10, "membership_status": "inactive"}],
|
|
stored_active_club_id=10,
|
|
invalid_header_policy="ignore",
|
|
)
|
|
assert ctx.club_ids == frozenset()
|
|
assert ctx.effective_club_id is None
|