Files
ebbe.bassandClaude Sonnet 5.5 49c7fd4a0b feat: add password change
Password page with the AD policy listed first, ordered service (throttle limit below the lockout threshold, verification, local hints, directory change, ended sessions, audit and confirmation mail in one transaction), plain-language errors, German text and tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
2026-10-18 10:08:17 +02:00

62 lines
1.7 KiB
Python

"""The left menu, declared once. An entry is shown only to users who may open its page."""
from __future__ import annotations
from dataclasses import dataclass
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
@dataclass(frozen=True)
class Entry:
label: object # lazy translated string
url_name: str
@dataclass(frozen=True)
class Group:
title: object | None
role: str | None # None: everyone; otherwise "publisher" or "admin"
entries: tuple[Entry, ...]
MENU = (
Group(None, None, (Entry(_("Home"), "home"), Entry(_("Change password"), "password"))),
Group(
_("Publishing"),
"publisher",
(Entry(_("Manage announcements"), "publish-announcements"),),
),
Group(
_("Administration"),
"admin",
(
Entry(_("Appearance"), "admin-appearance"),
Entry(_("Settings"), "admin-settings"),
Entry(_("Audit log"), "admin-audit"),
Entry(_("Status"), "admin-status"),
),
),
)
def _allowed(group: Group, portal_user) -> bool:
if group.role is None:
return True
return bool(getattr(portal_user, f"is_{group.role}", False))
def for_user(portal_user, current_path: str) -> list[dict]:
"""The groups this user sees, each entry with its address and whether it is current."""
groups = []
for group in MENU:
if not _allowed(group, portal_user):
continue
entries = []
for entry in group.entries:
url = reverse(entry.url_name)
entries.append({"label": entry.label, "url": url, "current": url == current_path})
groups.append({"title": group.title, "entries": entries})
return groups