feat: update application version to 0.8.20 and enhance superadmin role management
- Bumped application version to 0.8.20 in both backend and frontend files. - Introduced migration 041 to promote the oldest admin user to superadmin if no superadmin exists. - Updated registration logic to assign the superadmin role to the first user and those in ADMIN_BOOTSTRAP_EMAILS. - Enhanced changelog to document the new version and changes made in this release.
This commit is contained in:
parent
9afcd762d0
commit
b661d0edb2
20
backend/migrations/041_bootstrap_superadmin.sql
Normal file
20
backend/migrations/041_bootstrap_superadmin.sql
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
-- Migration 041: Super-Admin für bestehende Installationen
|
||||||
|
-- Bisheriger Bootstrap (registration_role) setzte nur 'admin'. Viele Endpunkte
|
||||||
|
-- (z. B. Verein löschen, Super-Rolle vergeben) verlangen 'superadmin'.
|
||||||
|
-- Wenn noch kein Super-Admin existiert: den ältesten Nutzer mit role = admin hochstufen.
|
||||||
|
|
||||||
|
UPDATE profiles p
|
||||||
|
SET role = 'superadmin', updated_at = NOW()
|
||||||
|
FROM (
|
||||||
|
SELECT id
|
||||||
|
FROM profiles
|
||||||
|
WHERE lower(trim(COALESCE(role, ''))) = 'admin'
|
||||||
|
ORDER BY id ASC
|
||||||
|
LIMIT 1
|
||||||
|
) sub
|
||||||
|
WHERE p.id = sub.id
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM profiles
|
||||||
|
WHERE lower(trim(COALESCE(role, ''))) = 'superadmin'
|
||||||
|
);
|
||||||
|
|
@ -187,9 +187,10 @@ def verification_link(token: str) -> str:
|
||||||
|
|
||||||
def registration_role(cur, email_lower: str) -> str:
|
def registration_role(cur, email_lower: str) -> str:
|
||||||
"""
|
"""
|
||||||
bootstrap: erste Registrierung in leerer DB → admin,
|
bootstrap: erste Registrierung in leerer DB → superadmin,
|
||||||
oder E-Mail ∈ ADMIN_BOOTSTRAP_EMAILS (kommasepariert, Groß/Klein egal).
|
oder E-Mail ∈ ADMIN_BOOTSTRAP_EMAILS (kommasepariert, Groß/Klein egal).
|
||||||
|
|
||||||
|
superadmin deckt alle Portal-Rechte ab (inkl. löschen / andere Super-Admins).
|
||||||
Um alle Self-Regs als Trainer zu haben: AUTO_ADMIN_FIRST_USER=false und keine ADMIN_BOOTSTRAP_EMAILS.
|
Um alle Self-Regs als Trainer zu haben: AUTO_ADMIN_FIRST_USER=false und keine ADMIN_BOOTSTRAP_EMAILS.
|
||||||
"""
|
"""
|
||||||
bootstrap = {
|
bootstrap = {
|
||||||
|
|
@ -198,7 +199,7 @@ def registration_role(cur, email_lower: str) -> str:
|
||||||
if x.strip()
|
if x.strip()
|
||||||
}
|
}
|
||||||
if email_lower in bootstrap:
|
if email_lower in bootstrap:
|
||||||
return "admin"
|
return "superadmin"
|
||||||
if os.getenv("AUTO_ADMIN_FIRST_USER", "true").strip().lower() not in ("1", "true", "yes"):
|
if os.getenv("AUTO_ADMIN_FIRST_USER", "true").strip().lower() not in ("1", "true", "yes"):
|
||||||
return "trainer"
|
return "trainer"
|
||||||
cur.execute("SELECT COUNT(*) AS n FROM profiles")
|
cur.execute("SELECT COUNT(*) AS n FROM profiles")
|
||||||
|
|
@ -207,7 +208,7 @@ def registration_role(cur, email_lower: str) -> str:
|
||||||
n = int(row["n"]) if row is not None else 0
|
n = int(row["n"]) if row is not None else 0
|
||||||
except (KeyError, TypeError, ValueError):
|
except (KeyError, TypeError, ValueError):
|
||||||
n = 0
|
n = 0
|
||||||
return "admin" if n == 0 else "trainer"
|
return "superadmin" if n == 0 else "trainer"
|
||||||
|
|
||||||
|
|
||||||
# ── Helper: Send Email ────────────────────────────────────────────────────────
|
# ── Helper: Send Email ────────────────────────────────────────────────────────
|
||||||
|
|
@ -289,7 +290,7 @@ async def register(req: RegisterRequest, request: Request):
|
||||||
verification_token = secrets.token_urlsafe(32)
|
verification_token = secrets.token_urlsafe(32)
|
||||||
verification_expires = datetime.now(timezone.utc) + timedelta(hours=24)
|
verification_expires = datetime.now(timezone.utc) + timedelta(hours=24)
|
||||||
|
|
||||||
# Rolle: erster Nutzer oder ADMIN_BOOTSTRAP_EMAILS → admin
|
# Rolle: erster Nutzer oder ADMIN_BOOTSTRAP_EMAILS → superadmin
|
||||||
role = registration_role(cur, email)
|
role = registration_role(cur, email)
|
||||||
|
|
||||||
# Create profile (inactive until verified) — profiles.id ist SERIAL (INT), keine String-IDs einfügen.
|
# Create profile (inactive until verified) — profiles.id ist SERIAL (INT), keine String-IDs einfügen.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# Shinkan Jinkendo Version Information
|
# Shinkan Jinkendo Version Information
|
||||||
|
|
||||||
APP_VERSION = "0.8.19"
|
APP_VERSION = "0.8.20"
|
||||||
BUILD_DATE = "2026-05-05"
|
BUILD_DATE = "2026-05-05"
|
||||||
DB_SCHEMA_VERSION = "20260505040"
|
DB_SCHEMA_VERSION = "20260505041"
|
||||||
|
|
||||||
MODULE_VERSIONS = {
|
MODULE_VERSIONS = {
|
||||||
"auth": "1.1.0", # Registrierung: optional requested_club_id → Beitrittsantrag
|
"auth": "1.2.0", # Erster/bootstrap Nutzer und ADMIN_BOOTSTRAP_EMAILS → superadmin (nicht mehr admin)
|
||||||
"profiles": "1.3.0", # PUT role/tier (Portal-Admin); GET /profiles; pin_hash aus Liste entfernt
|
"profiles": "1.3.0", # PUT role/tier (Portal-Admin); GET /profiles; pin_hash aus Liste entfernt
|
||||||
"clubs": "0.4.0", # public-directory, members/directory; Vereins-GUI verwendet Endpoints
|
"clubs": "0.4.0", # public-directory, members/directory; Vereins-GUI verwendet Endpoints
|
||||||
"club_memberships": "1.0.0",
|
"club_memberships": "1.0.0",
|
||||||
|
|
@ -26,6 +26,14 @@ MODULE_VERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
|
{
|
||||||
|
"version": "0.8.20",
|
||||||
|
"date": "2026-05-05",
|
||||||
|
"changes": [
|
||||||
|
"Migration 041: wenn noch kein superadmin existiert, werden ältestes Profil mit role admin zu superadmin hochgestuft",
|
||||||
|
"Registrierung: erster Nutzer und ADMIN_BOOTSTRAP_EMAILS erhalten superadmin (vorher admin)",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.8.19",
|
"version": "0.8.19",
|
||||||
"date": "2026-05-05",
|
"date": "2026-05-05",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Shinkan Jinkendo Frontend Version
|
// Shinkan Jinkendo Frontend Version
|
||||||
|
|
||||||
export const APP_VERSION = "0.8.19"
|
export const APP_VERSION = "0.8.20"
|
||||||
export const BUILD_DATE = "2026-05-05"
|
export const BUILD_DATE = "2026-05-05"
|
||||||
|
|
||||||
export const PAGE_VERSIONS = {
|
export const PAGE_VERSIONS = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user