From 20d2c9093ab7bb788340e2fcc721a54112d44862 Mon Sep 17 00:00:00 2001 From: Matthias Hochmeister Date: Fri, 13 Mar 2026 15:09:43 +0100 Subject: [PATCH] update --- backend/src/controllers/auth.controller.ts | 3 ++ backend/src/services/member.service.ts | 18 +++++++++++ frontend/src/pages/MitgliedDetail.tsx | 35 ++++++++++++++++++---- frontend/src/pages/Mitglieder.tsx | 2 +- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/backend/src/controllers/auth.controller.ts b/backend/src/controllers/auth.controller.ts index 18d105d..3c60250 100644 --- a/backend/src/controllers/auth.controller.ts +++ b/backend/src/controllers/auth.controller.ts @@ -3,6 +3,7 @@ import { z } from 'zod'; import authentikService from '../services/authentik.service'; import tokenService from '../services/token.service'; import userService from '../services/user.service'; +import memberService from '../services/member.service'; import logger from '../utils/logger'; import auditService, { AuditAction, AuditResourceType } from '../services/audit.service'; import { extractIp, extractUserAgent } from '../middleware/audit.middleware'; @@ -119,6 +120,7 @@ class AuthController { }); await userService.updateGroups(user.id, groups); + await memberService.ensureProfileExists(user.id); // Audit: first-ever login (user record creation) auditService.logAudit({ @@ -142,6 +144,7 @@ class AuthController { await userService.updateLastLogin(user.id); await userService.updateGroups(user.id, groups); + await memberService.ensureProfileExists(user.id); const { given_name: updatedGivenName, family_name: updatedFamilyName } = extractNames(userInfo); diff --git a/backend/src/services/member.service.ts b/backend/src/services/member.service.ts index eab68ed..28fd59c 100644 --- a/backend/src/services/member.service.ts +++ b/backend/src/services/member.service.ts @@ -544,6 +544,24 @@ class MemberService { } } + /** + * Ensures a mitglieder_profile row exists for the given user. + * Safe to call on every login — idempotent via ON CONFLICT DO NOTHING. + * Errors are caught and logged without throwing. + */ + async ensureProfileExists(userId: string): Promise { + try { + await pool.query( + `INSERT INTO mitglieder_profile (user_id, status) + VALUES ($1, 'aktiv') + ON CONFLICT (user_id) DO NOTHING`, + [userId] + ); + } catch (error) { + logger.warn('ensureProfileExists failed (non-fatal)', { error, userId }); + } + } + /** * Returns aggregate member counts, used by the dashboard KPI cards. * Optionally scoped to a single status value. diff --git a/frontend/src/pages/MitgliedDetail.tsx b/frontend/src/pages/MitgliedDetail.tsx index 61bd1f4..550c34b 100644 --- a/frontend/src/pages/MitgliedDetail.tsx +++ b/frontend/src/pages/MitgliedDetail.tsx @@ -61,7 +61,7 @@ import { function useCanWrite(): boolean { const { user } = useAuth(); const groups: string[] = (user as any)?.groups ?? []; - return groups.includes('feuerwehr-admin') || groups.includes('feuerwehr-kommandant'); + return groups.includes('dashboard_admin') || groups.includes('dashboard_kommando'); } function useCurrentUserId(): string | undefined { @@ -473,11 +473,36 @@ function MitgliedDetail() { {!profile && ( - + { + if (!userId) return; + setSaving(true); + setSaveError(null); + try { + await membersService.createMemberProfile(userId, { status: 'aktiv' }); + await loadMember(); + } catch { + setSaveError('Profil konnte nicht erstellt werden.'); + } finally { + setSaving(false); + } + }} + > + {saving ? : 'Profil erstellen'} + + ) : undefined + } + > Für dieses Mitglied wurde noch kein Profil angelegt. - {canWrite - ? ' Ein Kommandant kann das Profil unter "Stammdaten" erstellen.' - : ' Wende dich an einen Administrator, um dein Profil anlegen zu lassen.'} + {!canWrite && ' Wende dich an einen Administrator, um dein Profil anlegen zu lassen.'} )} diff --git a/frontend/src/pages/Mitglieder.tsx b/frontend/src/pages/Mitglieder.tsx index cafc1b3..038a3de 100644 --- a/frontend/src/pages/Mitglieder.tsx +++ b/frontend/src/pages/Mitglieder.tsx @@ -53,7 +53,7 @@ import { function useCanWrite(): boolean { const { user } = useAuth(); const groups: string[] = (user as any)?.groups ?? []; - return groups.includes('feuerwehr-admin') || groups.includes('feuerwehr-kommandant'); + return groups.includes('dashboard_admin') || groups.includes('dashboard_kommando'); } // ----------------------------------------------------------------