new features
This commit is contained in:
@@ -112,8 +112,16 @@ class PermissionController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await permissionService.setMultipleGroupPermissions(updates, req.user!.id);
|
const result = await permissionService.setMultipleGroupPermissions(updates, req.user!.id);
|
||||||
res.json({ success: true, message: 'Berechtigungen aktualisiert' });
|
if (result.droppedPermissions.length > 0) {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: `Berechtigungen aktualisiert. Warnung: ${result.droppedPermissions.length} Berechtigung(en) existieren nicht in der Datenbank und wurden ignoriert: ${result.droppedPermissions.join(', ')}`,
|
||||||
|
droppedPermissions: result.droppedPermissions,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.json({ success: true, message: 'Berechtigungen aktualisiert' });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to set bulk permissions', { error });
|
logger.error('Failed to set bulk permissions', { error });
|
||||||
res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' });
|
res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' });
|
||||||
|
|||||||
@@ -248,11 +248,17 @@ class AuditService {
|
|||||||
const perm = meta?.required_permission ?? '?';
|
const perm = meta?.required_permission ?? '?';
|
||||||
const path = meta?.attempted_path ?? '';
|
const path = meta?.attempted_path ?? '';
|
||||||
const method = meta?.attempted_method ?? '';
|
const method = meta?.attempted_method ?? '';
|
||||||
nachricht = `${entry.user_email ?? 'Unbekannt'}: ${method} ${path} — benötigt "${perm}"`;
|
const userLabel = entry.user_email ?? 'Unbekannt';
|
||||||
|
nachricht = `${userLabel}: ${method} ${path} — benötigt "${perm}"`;
|
||||||
} else {
|
} else {
|
||||||
nachricht = `${entry.action} auf ${entry.resource_type}${entry.resource_id ? ' ' + entry.resource_id : ''} durch ${entry.user_email ?? 'System'}`;
|
nachricht = `${entry.action} auf ${entry.resource_type}${entry.resource_id ? ' ' + entry.resource_id : ''} durch ${entry.user_email ?? 'System'}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Include user name/email in quell_id so each user+action combo is unique
|
||||||
|
const quellId = entry.action === 'PERMISSION_DENIED'
|
||||||
|
? `${entry.action}_${(entry.metadata as any)?.required_permission ?? ''}_${entry.user_id ?? Date.now()}`
|
||||||
|
: `${entry.action}_${entry.resource_type}_${entry.resource_id ?? Date.now()}`;
|
||||||
|
|
||||||
for (const admin of admins) {
|
for (const admin of admins) {
|
||||||
// Don't notify the admin about their own actions
|
// Don't notify the admin about their own actions
|
||||||
if (admin.id === entry.user_id) continue;
|
if (admin.id === entry.user_id) continue;
|
||||||
@@ -264,7 +270,7 @@ class AuditService {
|
|||||||
nachricht,
|
nachricht,
|
||||||
schwere: entry.action === 'PERMISSION_DENIED' ? 'warnung' : 'info',
|
schwere: entry.action === 'PERMISSION_DENIED' ? 'warnung' : 'info',
|
||||||
quell_typ: 'audit_alert',
|
quell_typ: 'audit_alert',
|
||||||
quell_id: `${entry.action}_${entry.resource_type}_${entry.resource_id ?? Date.now()}`,
|
quell_id: quellId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ class PermissionService {
|
|||||||
async setMultipleGroupPermissions(
|
async setMultipleGroupPermissions(
|
||||||
updates: { group: string; permissions: string[] }[],
|
updates: { group: string; permissions: string[] }[],
|
||||||
grantedBy: string,
|
grantedBy: string,
|
||||||
): Promise<void> {
|
): Promise<{ droppedPermissions: string[] }> {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
@@ -282,8 +282,18 @@ class PermissionService {
|
|||||||
validSet = new Set(validResult.rows.map((r: any) => r.id));
|
validSet = new Set(validResult.rows.map((r: any) => r.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allDropped: string[] = [];
|
||||||
|
|
||||||
for (const { group, permissions } of updates) {
|
for (const { group, permissions } of updates) {
|
||||||
const validPermIds = permissions.filter(p => validSet.has(p));
|
const validPermIds = permissions.filter(p => validSet.has(p));
|
||||||
|
const droppedPermIds = permissions.filter(p => !validSet.has(p));
|
||||||
|
if (droppedPermIds.length > 0) {
|
||||||
|
logger.warn('Permissions dropped during save — not found in permissions table', {
|
||||||
|
group,
|
||||||
|
droppedPermIds,
|
||||||
|
});
|
||||||
|
allDropped.push(...droppedPermIds);
|
||||||
|
}
|
||||||
|
|
||||||
await client.query('DELETE FROM group_permissions WHERE authentik_group = $1', [group]);
|
await client.query('DELETE FROM group_permissions WHERE authentik_group = $1', [group]);
|
||||||
|
|
||||||
@@ -307,6 +317,8 @@ class PermissionService {
|
|||||||
groupCount: updates.length,
|
groupCount: updates.length,
|
||||||
grantedBy,
|
grantedBy,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { droppedPermissions: [...new Set(allDropped)] };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await client.query('ROLLBACK');
|
await client.query('ROLLBACK');
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -168,10 +168,14 @@ function PermissionMatrixTab() {
|
|||||||
const permissionMutation = useMutation({
|
const permissionMutation = useMutation({
|
||||||
mutationFn: (updates: { group: string; permissions: string[] }[]) =>
|
mutationFn: (updates: { group: string; permissions: string[] }[]) =>
|
||||||
permissionsApi.setBulkPermissions(updates),
|
permissionsApi.setBulkPermissions(updates),
|
||||||
onSuccess: () => {
|
onSuccess: (result) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['admin-permission-matrix'] });
|
queryClient.invalidateQueries({ queryKey: ['admin-permission-matrix'] });
|
||||||
queryClient.invalidateQueries({ queryKey: ['my-permissions'] });
|
queryClient.invalidateQueries({ queryKey: ['my-permissions'] });
|
||||||
showSuccess('Berechtigungen gespeichert');
|
if (result?.droppedPermissions && result.droppedPermissions.length > 0) {
|
||||||
|
showError(`Berechtigungen gespeichert, aber ${result.droppedPermissions.length} Berechtigung(en) existieren nicht in der DB und wurden ignoriert: ${result.droppedPermissions.join(', ')}`);
|
||||||
|
} else {
|
||||||
|
showSuccess('Berechtigungen gespeichert');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError: () => showError('Fehler beim Speichern der Berechtigungen'),
|
onError: () => showError('Fehler beim Speichern der Berechtigungen'),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ export const permissionsApi = {
|
|||||||
await api.delete(`/api/permissions/admin/group/${encodeURIComponent(group)}`);
|
await api.delete(`/api/permissions/admin/group/${encodeURIComponent(group)}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
setBulkPermissions: async (updates: { group: string; permissions: string[] }[]): Promise<void> => {
|
setBulkPermissions: async (updates: { group: string; permissions: string[] }[]): Promise<{ droppedPermissions?: string[] }> => {
|
||||||
await api.put('/api/permissions/admin/bulk', { updates });
|
const r = await api.put('/api/permissions/admin/bulk', { updates });
|
||||||
|
return r.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
setMaintenanceFlag: async (featureGroup: string, active: boolean): Promise<void> => {
|
setMaintenanceFlag: async (featureGroup: string, active: boolean): Promise<void> => {
|
||||||
|
|||||||
Reference in New Issue
Block a user