Files
var-monorepo/apps/dispatch-server/routes/mission.ts

339 lines
8.1 KiB
TypeScript

import {
getPublicUser,
HpgValidationState,
MissionSdsLog,
NotificationPayload,
prisma,
User,
} from "@repo/db";
import { Router } from "express";
import { io } from "../index";
import { sendAlert } from "modules/mission";
const router: Router = Router();
// Get all missions
router.post("/", async (req, res) => {
try {
const filter = req.body?.filter || {};
const missions = await prisma.mission.findMany({
where: filter,
});
res.json(missions);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to fetch missions" });
}
});
// Get a single mission by ID
router.get("/:id", async (req, res) => {
const { id } = req.params;
try {
const mission = await prisma.mission.findUnique({
where: { id: Number(id) },
});
if (mission) {
res.json(mission);
} else {
res.status(404).json({ error: "Mission not found" });
}
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to fetch mission" });
}
});
// Create a new mission
router.put("/", async (req, res) => {
try {
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const missionsTodayCount = await prisma.mission.count({
where: {
createdAt: {
gte: startOfToday,
},
},
});
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are zero-based
const day = String(date.getDate()).padStart(2, "0");
const publicId = `__${year}${month}${day}${missionsTodayCount ? missionsTodayCount + 1 : 1}`;
const newMission = await prisma.mission.create({
data: {
...req.body,
publicId,
},
});
io.to("dispatchers").emit("new-mission", { newMission });
res.status(201).json(newMission);
} catch (error) {
res.status(500).json({ error: "Failed to create mission" });
}
});
// Update a mission by ID
router.patch("/:id", async (req, res) => {
const { id } = req.params;
try {
const updatedMission = await prisma.mission.update({
where: { id: Number(id) },
data: req.body,
});
io.to("dispatchers").emit("update-mission", updatedMission);
res.json(updatedMission);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to update mission" });
}
});
// Delete a mission by ID
router.delete("/:id", async (req, res) => {
const { id } = req.params;
try {
await prisma.mission.delete({
where: { id: Number(id) },
});
io.to("dispatchers").emit("delete-mission", id);
res.status(204).send();
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to delete mission" });
}
});
// Send mission
router.post("/:id/send-alert", async (req, res) => {
const { id } = req.params;
const { stationId, vehicleName } = req.body as {
stationId?: number;
vehicleName?: "RTW" | "POL" | "FW";
};
if (!req.user) {
res.status(401).json({ error: "Unauthorized" });
return;
}
try {
if (vehicleName) {
const hpgAircrafts = await prisma.connectedAircraft.findMany({
where: {
stationId: Number(id),
logoutTime: null,
posH145active: true,
},
});
const updateData: any = {
missionLog: {
push: {
type: "alert-log",
auto: false,
timeStamp: new Date().toISOString(),
data: {
vehicle: vehicleName,
user: getPublicUser(req.user as User, { ignorePrivacy: true }),
},
},
},
};
if (vehicleName === "RTW") updateData.hpgAmbulanceState = "DISPATCHED";
if (vehicleName === "FW") updateData.hpgFireEngineState = "DISPATCHED";
if (vehicleName === "POL") updateData.hpgPoliceState = "DISPATCHED";
const newMission = await prisma.mission.update({
where: { id: Number(id) },
data: updateData,
});
hpgAircrafts.forEach((aircraft) => {
io.to(`desktop:${aircraft.userId}`).emit("hpg-vehicle-update", {
missionId: id,
ambulanceState: newMission.hpgAmbulanceState,
fireEngineState: newMission.hpgFireEngineState,
policeState: newMission.hpgPoliceState,
});
});
io.to("dispatchers").emit("update-mission", newMission);
res.status(200).json({
message: `Rettungsmittel disponiert (${hpgAircrafts.length} Nutzer)`,
});
return;
}
const { connectedAircrafts, mission } = await sendAlert(Number(id), { stationId }, req.user);
io.to("dispatchers").emit("update-mission", mission);
res.status(200).json({
message: `Einsatz gesendet (${connectedAircrafts.length} Nutzer)`,
});
return;
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to send mission" });
return;
}
});
router.post("/send-sds", async (req, res) => {
const { sdsMessage, missionId } = req.body as {
missionId?: number;
sdsMessage: MissionSdsLog;
};
io.to(`station:${sdsMessage.data.stationId}`).emit("sds-message", sdsMessage);
if (missionId) {
const newMission = await prisma.mission.update({
where: {
id: Number(missionId),
},
data: {
missionLog: {
push: sdsMessage as any,
},
},
});
res.json({
message: "SDS message sent",
mission: newMission,
});
io.to("dispatchers").emit("update-mission", newMission);
} else {
res.json({
message: "SDS message sent",
});
}
});
router.post("/:id/hpg-validation-result", async (req, res) => {
try {
const missionId = req.params.id;
const result = req.body as {
state: HpgValidationState;
lat: number;
lng: number;
alertWhenValid?: boolean;
userId?: number;
};
if (!result) return;
const newMission = await prisma.mission.update({
where: { id: Number(missionId) },
data: {
// save position of new mission
addressLat: result.state === "POSITION_AMANDED" ? result.lat : undefined,
addressLng: result.state === "POSITION_AMANDED" ? result.lng : undefined,
hpgLocationLat: result.lat,
hpgLocationLng: result.lng,
hpgValidationState: result.state,
},
});
io.to("dispatchers").emit("update-mission", newMission);
const noActionRequired = result.state === "VALID";
if (noActionRequired) {
io.to(`user:${result.userId}`).emit("notification", {
type: "hpg-validation",
status: "success",
message: `HPG Validierung erfolgreich`,
} as NotificationPayload);
if (result.alertWhenValid) {
if (!req.user) return;
sendAlert(Number(missionId), {}, req.user);
}
} else {
io.to(`user:${result.userId}`).emit("notification", {
type: "hpg-validation",
status: "failed",
message: result.state,
} as NotificationPayload);
}
res.json({
message: `HPG Validation result processed`,
});
} catch (error) {
console.error("Error in HPG validation result:", error);
res.status(500).json({ error: "Failed to process HPG validation result" });
return;
}
});
router.post("/:id/validate-hpg", async (req, res) => {
try {
const { id } = req.params;
const config = req.body as
| {
alertWhenValid?: boolean;
}
| undefined;
const mission = await prisma.mission.findFirstOrThrow({
where: {
id: Number(id),
},
});
const activeAircraftinMission = await prisma.connectedAircraft.findFirst({
where: {
stationId: {
in: mission?.missionStationIds,
},
posH145active: true,
logoutTime: null,
},
include: {
Station: true,
},
});
const user = await prisma.user.findFirst({
where: {
id: activeAircraftinMission?.userId,
},
});
const clients = await io.in(`desktop:${activeAircraftinMission?.userId}`).fetchSockets();
if (!clients.length) {
res.status(400).json({
error: `Keine Desktop Verbindung für ${user?.publicId} gefunden`,
});
return;
}
const newMission = await prisma.mission.update({
where: {
id: Number(id),
},
data: {
hpgValidationState: "PENDING",
},
});
io.to("dispatchers").emit("update-mission", newMission);
res.json({
message: "HPG validierung gestartet",
});
io.to(`desktop:${activeAircraftinMission?.userId}`).emit("hpg-validation", {
missionId: parseInt(id),
userId: req.user?.id,
alertWhenValid: config?.alertWhenValid || false,
});
} catch (error) {
console.error(error);
res.json({ error: (error as Error).message || "Failed to validate HPG" });
}
});
export default router;