rights system
This commit is contained in:
@@ -1,6 +1,55 @@
|
||||
import pool from '../config/database';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
// Default configs — used when no DB config exists yet
|
||||
const DEFAULT_GROUP_HIERARCHY: Record<string, string[]> = {
|
||||
'dashboard_mitglied': ['dashboard_chargen', 'dashboard_atemschutz', 'dashboard_moderator', 'dashboard_zeugmeister', 'dashboard_fahrmeister', 'dashboard_gruppenfuehrer', 'dashboard_kommando'],
|
||||
'dashboard_chargen': ['dashboard_gruppenfuehrer', 'dashboard_kommando'],
|
||||
'dashboard_atemschutz': ['dashboard_kommando'],
|
||||
'dashboard_moderator': ['dashboard_kommando'],
|
||||
'dashboard_zeugmeister': ['dashboard_kommando'],
|
||||
'dashboard_fahrmeister': ['dashboard_kommando'],
|
||||
'dashboard_gruppenfuehrer': ['dashboard_kommando'],
|
||||
'dashboard_kommando': [],
|
||||
};
|
||||
|
||||
const DEFAULT_PERMISSION_DEPS: Record<string, string[]> = {
|
||||
'kalender:create': ['kalender:view'],
|
||||
'kalender:cancel': ['kalender:view'],
|
||||
'kalender:mark_attendance': ['kalender:view'],
|
||||
'kalender:create_bookings': ['kalender:view'],
|
||||
'kalender:edit_bookings': ['kalender:view', 'kalender:create_bookings'],
|
||||
'kalender:cancel_own_bookings': ['kalender:view'],
|
||||
'kalender:delete_bookings': ['kalender:view', 'kalender:edit_bookings'],
|
||||
'kalender:manage_categories': ['kalender:view'],
|
||||
'kalender:view_reports': ['kalender:view'],
|
||||
'kalender:widget_events': ['kalender:view'],
|
||||
'kalender:widget_bookings': ['kalender:view'],
|
||||
'kalender:widget_quick_add': ['kalender:view', 'kalender:create'],
|
||||
'fahrzeuge:create': ['fahrzeuge:view'],
|
||||
'fahrzeuge:change_status': ['fahrzeuge:view'],
|
||||
'fahrzeuge:manage_maintenance': ['fahrzeuge:view'],
|
||||
'fahrzeuge:delete': ['fahrzeuge:view', 'fahrzeuge:create'],
|
||||
'fahrzeuge:widget': ['fahrzeuge:view'],
|
||||
'einsaetze:view_reports': ['einsaetze:view'],
|
||||
'einsaetze:create': ['einsaetze:view'],
|
||||
'einsaetze:delete': ['einsaetze:view', 'einsaetze:create'],
|
||||
'einsaetze:manage_personnel': ['einsaetze:view'],
|
||||
'ausruestung:create': ['ausruestung:view'],
|
||||
'ausruestung:manage_maintenance': ['ausruestung:view'],
|
||||
'ausruestung:delete': ['ausruestung:view', 'ausruestung:create'],
|
||||
'ausruestung:widget': ['ausruestung:view'],
|
||||
'mitglieder:view_all': ['mitglieder:view_own'],
|
||||
'mitglieder:edit': ['mitglieder:view_own', 'mitglieder:view_all'],
|
||||
'mitglieder:create_profile': ['mitglieder:view_own', 'mitglieder:view_all', 'mitglieder:edit'],
|
||||
'atemschutz:create': ['atemschutz:view'],
|
||||
'atemschutz:delete': ['atemschutz:view', 'atemschutz:create'],
|
||||
'atemschutz:widget': ['atemschutz:view'],
|
||||
'wissen:widget_recent': ['wissen:view'],
|
||||
'wissen:widget_search': ['wissen:view'],
|
||||
'admin:write': ['admin:view'],
|
||||
};
|
||||
|
||||
export interface FeatureGroupRow {
|
||||
id: string;
|
||||
label: string;
|
||||
@@ -255,10 +304,76 @@ class PermissionService {
|
||||
'UPDATE feature_groups SET maintenance = $1 WHERE id = $2',
|
||||
[active, featureGroup]
|
||||
);
|
||||
// Reload cache
|
||||
await this.loadCache();
|
||||
logger.info('Maintenance flag updated', { featureGroup, active });
|
||||
}
|
||||
|
||||
// ── Dependency config (stored in app_settings) ──
|
||||
|
||||
async getGroupHierarchy(): Promise<Record<string, string[]>> {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT value FROM app_settings WHERE key = 'permission_group_hierarchy'"
|
||||
);
|
||||
if (result.rows.length > 0 && result.rows[0].value) {
|
||||
const val = typeof result.rows[0].value === 'string'
|
||||
? JSON.parse(result.rows[0].value)
|
||||
: result.rows[0].value;
|
||||
return val;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn('Failed to load group hierarchy from DB, using defaults', { error });
|
||||
}
|
||||
return DEFAULT_GROUP_HIERARCHY;
|
||||
}
|
||||
|
||||
async setGroupHierarchy(hierarchy: Record<string, string[]>, userId: string): Promise<void> {
|
||||
await pool.query(
|
||||
`INSERT INTO app_settings (key, value, updated_by, updated_at)
|
||||
VALUES ('permission_group_hierarchy', $1, $2, NOW())
|
||||
ON CONFLICT (key) DO UPDATE SET value = $1, updated_by = $2, updated_at = NOW()`,
|
||||
[JSON.stringify(hierarchy), userId]
|
||||
);
|
||||
logger.info('Group hierarchy updated', { userId });
|
||||
}
|
||||
|
||||
async getPermissionDeps(): Promise<Record<string, string[]>> {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT value FROM app_settings WHERE key = 'permission_deps'"
|
||||
);
|
||||
if (result.rows.length > 0 && result.rows[0].value) {
|
||||
const val = typeof result.rows[0].value === 'string'
|
||||
? JSON.parse(result.rows[0].value)
|
||||
: result.rows[0].value;
|
||||
return val;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn('Failed to load permission deps from DB, using defaults', { error });
|
||||
}
|
||||
return DEFAULT_PERMISSION_DEPS;
|
||||
}
|
||||
|
||||
async setPermissionDeps(deps: Record<string, string[]>, userId: string): Promise<void> {
|
||||
await pool.query(
|
||||
`INSERT INTO app_settings (key, value, updated_by, updated_at)
|
||||
VALUES ('permission_deps', $1, $2, NOW())
|
||||
ON CONFLICT (key) DO UPDATE SET value = $1, updated_by = $2, updated_at = NOW()`,
|
||||
[JSON.stringify(deps), userId]
|
||||
);
|
||||
logger.info('Permission deps updated', { userId });
|
||||
}
|
||||
|
||||
async getDependencyConfig(): Promise<{
|
||||
groupHierarchy: Record<string, string[]>;
|
||||
permissionDeps: Record<string, string[]>;
|
||||
}> {
|
||||
const [groupHierarchy, permissionDeps] = await Promise.all([
|
||||
this.getGroupHierarchy(),
|
||||
this.getPermissionDeps(),
|
||||
]);
|
||||
return { groupHierarchy, permissionDeps };
|
||||
}
|
||||
}
|
||||
|
||||
export const permissionService = new PermissionService();
|
||||
|
||||
Reference in New Issue
Block a user