update
This commit is contained in:
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|||||||
import authentikService from '../services/authentik.service';
|
import authentikService from '../services/authentik.service';
|
||||||
import tokenService from '../services/token.service';
|
import tokenService from '../services/token.service';
|
||||||
import userService from '../services/user.service';
|
import userService from '../services/user.service';
|
||||||
|
import memberService from '../services/member.service';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
import auditService, { AuditAction, AuditResourceType } from '../services/audit.service';
|
import auditService, { AuditAction, AuditResourceType } from '../services/audit.service';
|
||||||
import { extractIp, extractUserAgent } from '../middleware/audit.middleware';
|
import { extractIp, extractUserAgent } from '../middleware/audit.middleware';
|
||||||
@@ -119,6 +120,7 @@ class AuthController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await userService.updateGroups(user.id, groups);
|
await userService.updateGroups(user.id, groups);
|
||||||
|
await memberService.ensureProfileExists(user.id);
|
||||||
|
|
||||||
// Audit: first-ever login (user record creation)
|
// Audit: first-ever login (user record creation)
|
||||||
auditService.logAudit({
|
auditService.logAudit({
|
||||||
@@ -142,6 +144,7 @@ class AuthController {
|
|||||||
|
|
||||||
await userService.updateLastLogin(user.id);
|
await userService.updateLastLogin(user.id);
|
||||||
await userService.updateGroups(user.id, groups);
|
await userService.updateGroups(user.id, groups);
|
||||||
|
await memberService.ensureProfileExists(user.id);
|
||||||
|
|
||||||
const { given_name: updatedGivenName, family_name: updatedFamilyName } = extractNames(userInfo);
|
const { given_name: updatedGivenName, family_name: updatedFamilyName } = extractNames(userInfo);
|
||||||
|
|
||||||
|
|||||||
@@ -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<void> {
|
||||||
|
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.
|
* Returns aggregate member counts, used by the dashboard KPI cards.
|
||||||
* Optionally scoped to a single status value.
|
* Optionally scoped to a single status value.
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import {
|
|||||||
function useCanWrite(): boolean {
|
function useCanWrite(): boolean {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const groups: string[] = (user as any)?.groups ?? [];
|
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 {
|
function useCurrentUserId(): string | undefined {
|
||||||
@@ -473,11 +473,36 @@ function MitgliedDetail() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{!profile && (
|
{!profile && (
|
||||||
<Alert severity="info" sx={{ mt: 2 }}>
|
<Alert
|
||||||
|
severity="info"
|
||||||
|
sx={{ mt: 2 }}
|
||||||
|
action={
|
||||||
|
canWrite ? (
|
||||||
|
<Button
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
disabled={saving}
|
||||||
|
onClick={async () => {
|
||||||
|
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 ? <CircularProgress size={16} /> : 'Profil erstellen'}
|
||||||
|
</Button>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
Für dieses Mitglied wurde noch kein Profil angelegt.
|
Für dieses Mitglied wurde noch kein Profil angelegt.
|
||||||
{canWrite
|
{!canWrite && ' Wende dich an einen Administrator, um dein Profil anlegen zu lassen.'}
|
||||||
? ' Ein Kommandant kann das Profil unter "Stammdaten" erstellen.'
|
|
||||||
: ' Wende dich an einen Administrator, um dein Profil anlegen zu lassen.'}
|
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ import {
|
|||||||
function useCanWrite(): boolean {
|
function useCanWrite(): boolean {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const groups: string[] = (user as any)?.groups ?? [];
|
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');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user