add features
This commit is contained in:
@@ -74,7 +74,7 @@ class IncidentController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
async getIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
|
async getIncident(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const incident = await incidentService.getIncidentById(id);
|
const incident = await incidentService.getIncidentById(id);
|
||||||
|
|
||||||
if (!incident) {
|
if (!incident) {
|
||||||
@@ -147,7 +147,7 @@ class IncidentController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parseResult = UpdateEinsatzSchema.safeParse(req.body);
|
const parseResult = UpdateEinsatzSchema.safeParse(req.body);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
@@ -181,7 +181,7 @@ class IncidentController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
await incidentService.deleteIncident(id, req.user.id);
|
await incidentService.deleteIncident(id, req.user.id);
|
||||||
|
|
||||||
res.status(200).json({ success: true, message: 'Einsatz archiviert' });
|
res.status(200).json({ success: true, message: 'Einsatz archiviert' });
|
||||||
@@ -200,7 +200,7 @@ class IncidentController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
async assignPersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
|
async assignPersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
|
|
||||||
const parseResult = AssignPersonnelSchema.safeParse(req.body);
|
const parseResult = AssignPersonnelSchema.safeParse(req.body);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
@@ -226,7 +226,7 @@ class IncidentController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
async removePersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
|
async removePersonnel(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id, userId } = req.params;
|
const { id, userId } = req.params as Record<string, string>;
|
||||||
await incidentService.removePersonnel(id, userId);
|
await incidentService.removePersonnel(id, userId);
|
||||||
|
|
||||||
res.status(200).json({ success: true, message: 'Person entfernt' });
|
res.status(200).json({ success: true, message: 'Person entfernt' });
|
||||||
@@ -245,7 +245,7 @@ class IncidentController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
async assignVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
|
async assignVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
|
|
||||||
const parseResult = AssignVehicleSchema.safeParse(req.body);
|
const parseResult = AssignVehicleSchema.safeParse(req.body);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
@@ -271,7 +271,7 @@ class IncidentController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
async removeVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
|
async removeVehicle(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id, fahrzeugId } = req.params;
|
const { id, fahrzeugId } = req.params as Record<string, string>;
|
||||||
await incidentService.removeVehicle(id, fahrzeugId);
|
await incidentService.removeVehicle(id, fahrzeugId);
|
||||||
|
|
||||||
res.status(200).json({ success: true, message: 'Fahrzeug entfernt' });
|
res.status(200).json({ success: true, message: 'Fahrzeug entfernt' });
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import memberService from '../services/member.service';
|
import memberService from '../services/member.service';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
import { AppError } from '../middleware/error.middleware';
|
|
||||||
import {
|
import {
|
||||||
CreateMemberProfileSchema,
|
CreateMemberProfileSchema,
|
||||||
UpdateMemberProfileSchema,
|
UpdateMemberProfileSchema,
|
||||||
@@ -79,7 +78,7 @@ class MemberController {
|
|||||||
* Returns aggregate member counts for each status.
|
* Returns aggregate member counts for each status.
|
||||||
* Must be registered BEFORE /:userId to avoid route collision.
|
* Must be registered BEFORE /:userId to avoid route collision.
|
||||||
*/
|
*/
|
||||||
async getMemberStats(req: Request, res: Response): Promise<void> {
|
async getMemberStats(_req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const stats = await memberService.getMemberStats();
|
const stats = await memberService.getMemberStats();
|
||||||
res.status(200).json({ success: true, data: stats });
|
res.status(200).json({ success: true, data: stats });
|
||||||
@@ -100,9 +99,7 @@ class MemberController {
|
|||||||
*/
|
*/
|
||||||
async getMemberById(req: Request, res: Response): Promise<void> {
|
async getMemberById(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { userId } = req.params;
|
const { userId } = req.params as Record<string, string>;
|
||||||
const requestorId = req.user!.id;
|
|
||||||
const requestorRole = getRole(req);
|
|
||||||
const ownProfile = isOwnProfile(req, userId);
|
const ownProfile = isOwnProfile(req, userId);
|
||||||
|
|
||||||
const member = await memberService.getMemberById(userId);
|
const member = await memberService.getMemberById(userId);
|
||||||
@@ -151,7 +148,7 @@ class MemberController {
|
|||||||
*/
|
*/
|
||||||
async createMemberProfile(req: Request, res: Response): Promise<void> {
|
async createMemberProfile(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { userId } = req.params;
|
const { userId } = req.params as Record<string, string>;
|
||||||
|
|
||||||
const parseResult = CreateMemberProfileSchema.safeParse(req.body);
|
const parseResult = CreateMemberProfileSchema.safeParse(req.body);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
@@ -187,7 +184,7 @@ class MemberController {
|
|||||||
*/
|
*/
|
||||||
async updateMember(req: Request, res: Response): Promise<void> {
|
async updateMember(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { userId } = req.params;
|
const { userId } = req.params as Record<string, string>;
|
||||||
const updaterId = req.user!.id;
|
const updaterId = req.user!.id;
|
||||||
const ownProfile = isOwnProfile(req, userId);
|
const ownProfile = isOwnProfile(req, userId);
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ class TrainingController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
getById = async (req: Request, res: Response): Promise<void> => {
|
getById = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const userId = req.user?.id;
|
const userId = req.user?.id;
|
||||||
|
|
||||||
// Determine if the requester may see the full attendee list
|
// Determine if the requester may see the full attendee list
|
||||||
@@ -229,7 +229,7 @@ class TrainingController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
updateEvent = async (req: Request, res: Response): Promise<void> => {
|
updateEvent = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = UpdateUebungSchema.safeParse(req.body);
|
const parsed = UpdateUebungSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
@@ -258,7 +258,7 @@ class TrainingController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
cancelEvent = async (req: Request, res: Response): Promise<void> => {
|
cancelEvent = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = CancelEventSchema.safeParse(req.body);
|
const parsed = CancelEventSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
@@ -287,7 +287,7 @@ class TrainingController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
updateRsvp = async (req: Request, res: Response): Promise<void> => {
|
updateRsvp = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { id: uebungId } = req.params;
|
const { id: uebungId } = req.params as Record<string, string>;
|
||||||
const userId = req.user!.id;
|
const userId = req.user!.id;
|
||||||
const parsed = UpdateRsvpSchema.safeParse(req.body);
|
const parsed = UpdateRsvpSchema.safeParse(req.body);
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ class TrainingController {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
markAttendance = async (req: Request, res: Response): Promise<void> => {
|
markAttendance = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { id: uebungId } = req.params;
|
const { id: uebungId } = req.params as Record<string, string>;
|
||||||
const parsed = MarkAttendanceSchema.safeParse(req.body);
|
const parsed = MarkAttendanceSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class VehicleController {
|
|||||||
* GET /api/vehicles
|
* GET /api/vehicles
|
||||||
* Fleet overview list with per-vehicle inspection badge data.
|
* Fleet overview list with per-vehicle inspection badge data.
|
||||||
*/
|
*/
|
||||||
async listVehicles(req: Request, res: Response): Promise<void> {
|
async listVehicles(_req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const vehicles = await vehicleService.getAllVehicles();
|
const vehicles = await vehicleService.getAllVehicles();
|
||||||
res.status(200).json({ success: true, data: vehicles });
|
res.status(200).json({ success: true, data: vehicles });
|
||||||
@@ -99,7 +99,7 @@ class VehicleController {
|
|||||||
* GET /api/vehicles/stats
|
* GET /api/vehicles/stats
|
||||||
* Aggregated KPI counts for the dashboard strip.
|
* Aggregated KPI counts for the dashboard strip.
|
||||||
*/
|
*/
|
||||||
async getStats(req: Request, res: Response): Promise<void> {
|
async getStats(_req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const stats = await vehicleService.getVehicleStats();
|
const stats = await vehicleService.getVehicleStats();
|
||||||
res.status(200).json({ success: true, data: stats });
|
res.status(200).json({ success: true, data: stats });
|
||||||
@@ -140,7 +140,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async getVehicle(req: Request, res: Response): Promise<void> {
|
async getVehicle(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const vehicle = await vehicleService.getVehicleById(id);
|
const vehicle = await vehicleService.getVehicleById(id);
|
||||||
|
|
||||||
if (!vehicle) {
|
if (!vehicle) {
|
||||||
@@ -185,7 +185,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async updateVehicle(req: Request, res: Response): Promise<void> {
|
async updateVehicle(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = UpdateFahrzeugSchema.safeParse(req.body);
|
const parsed = UpdateFahrzeugSchema.safeParse(req.body);
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
@@ -219,7 +219,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async updateVehicleStatus(req: Request, res: Response): Promise<void> {
|
async updateVehicleStatus(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = UpdateStatusSchema.safeParse(req.body);
|
const parsed = UpdateStatusSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
@@ -262,7 +262,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async addPruefung(req: Request, res: Response): Promise<void> {
|
async addPruefung(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = CreatePruefungSchema.safeParse(req.body);
|
const parsed = CreatePruefungSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
@@ -288,7 +288,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async getPruefungen(req: Request, res: Response): Promise<void> {
|
async getPruefungen(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const pruefungen = await vehicleService.getPruefungenForVehicle(id);
|
const pruefungen = await vehicleService.getPruefungenForVehicle(id);
|
||||||
res.status(200).json({ success: true, data: pruefungen });
|
res.status(200).json({ success: true, data: pruefungen });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -305,7 +305,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async addWartung(req: Request, res: Response): Promise<void> {
|
async addWartung(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const parsed = CreateWartungslogSchema.safeParse(req.body);
|
const parsed = CreateWartungslogSchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
@@ -331,7 +331,7 @@ class VehicleController {
|
|||||||
*/
|
*/
|
||||||
async getWartung(req: Request, res: Response): Promise<void> {
|
async getWartung(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params as Record<string, string>;
|
||||||
const entries = await vehicleService.getWartungslogForVehicle(id);
|
const entries = await vehicleService.getWartungslogForVehicle(id);
|
||||||
res.status(200).json({ success: true, data: entries });
|
res.status(200).json({ success: true, data: entries });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -132,9 +132,9 @@ export function auditMiddleware(
|
|||||||
// Resource ID: prefer controller override, then route param, then body id.
|
// Resource ID: prefer controller override, then route param, then body id.
|
||||||
const resourceId =
|
const resourceId =
|
||||||
res.locals.auditResourceId ??
|
res.locals.auditResourceId ??
|
||||||
req.params.id ??
|
(req.params as Record<string, string>).id ??
|
||||||
(body !== null && typeof body === 'object'
|
(body !== null && typeof body === 'object'
|
||||||
? (body as Record<string, unknown>)?.data?.id as string | undefined
|
? ((body as Record<string, unknown>)?.data as Record<string, unknown>)?.id as string | undefined
|
||||||
: undefined) ??
|
: undefined) ??
|
||||||
null;
|
null;
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ router.get(
|
|||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Invalid query parameters',
|
message: 'Invalid query parameters',
|
||||||
errors: error.errors,
|
errors: error.issues,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ router.get(
|
|||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Invalid query parameters',
|
message: 'Invalid query parameters',
|
||||||
errors: error.errors,
|
errors: error.issues,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,21 +28,6 @@ const router = Router();
|
|||||||
|
|
||||||
type AppRole = 'admin' | 'kommandant' | 'mitglied';
|
type AppRole = 'admin' | 'kommandant' | 'mitglied';
|
||||||
|
|
||||||
// Extend the Express Request type to include role
|
|
||||||
declare global {
|
|
||||||
namespace Express {
|
|
||||||
interface Request {
|
|
||||||
user?: {
|
|
||||||
id: string;
|
|
||||||
email: string;
|
|
||||||
authentikSub: string;
|
|
||||||
role?: AppRole;
|
|
||||||
groups?: string[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the AppRole from Authentik groups attached to the JWT.
|
* Resolves the AppRole from Authentik groups attached to the JWT.
|
||||||
* Mutates req.user.role so downstream controllers can read it directly.
|
* Mutates req.user.role so downstream controllers can read it directly.
|
||||||
@@ -53,9 +38,9 @@ const resolveRole = (req: Request, _res: Response, next: NextFunction): void =>
|
|||||||
if (groups.includes('feuerwehr-admin')) {
|
if (groups.includes('feuerwehr-admin')) {
|
||||||
req.user.role = 'admin';
|
req.user.role = 'admin';
|
||||||
} else if (groups.includes('feuerwehr-kommandant')) {
|
} else if (groups.includes('feuerwehr-kommandant')) {
|
||||||
req.user.role = 'kommandant';
|
req.user.role = 'kommandant' as any;
|
||||||
} else {
|
} else {
|
||||||
req.user.role = 'mitglied';
|
req.user.role = 'mitglied' as any;
|
||||||
}
|
}
|
||||||
logger.debug('resolveRole', { userId: req.user.id, role: req.user.role });
|
logger.debug('resolveRole', { userId: req.user.id, role: req.user.role });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ class MemberService {
|
|||||||
await this.updateDienstgrad(userId, dienstgrad, updatedBy, dienstgrad_seit, client);
|
await this.updateDienstgrad(userId, dienstgrad, updatedBy, dienstgrad_seit, client);
|
||||||
} else if (dienstgrad_seit !== undefined) {
|
} else if (dienstgrad_seit !== undefined) {
|
||||||
// dienstgrad_seit can be updated independently
|
// dienstgrad_seit can be updated independently
|
||||||
rest.dienstgrad_seit = dienstgrad_seit;
|
(rest as any).dienstgrad_seit = dienstgrad_seit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build dynamic SET clause for remaining fields
|
// Build dynamic SET clause for remaining fields
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Server as SocketIOServer } from 'socket.io';
|
|
||||||
import pool from '../config/database';
|
import pool from '../config/database';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
import {
|
import {
|
||||||
@@ -282,7 +281,7 @@ class VehicleService {
|
|||||||
status: FahrzeugStatus,
|
status: FahrzeugStatus,
|
||||||
bemerkung: string,
|
bemerkung: string,
|
||||||
updatedBy: string,
|
updatedBy: string,
|
||||||
io?: SocketIOServer
|
io?: any
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// Fetch old status for Socket.IO payload and logging
|
// Fetch old status for Socket.IO payload and logging
|
||||||
|
|||||||
Reference in New Issue
Block a user