Files
var-monorepo/apps/dispatch-server/routes/aircraft.ts
2026-01-15 23:45:06 +01:00

244 lines
6.3 KiB
TypeScript

import {
AdminMessage,
getPublicUser,
MissionLog,
MissionSdsStatusLog,
NotificationPayload,
Prisma,
prisma,
} from "@repo/db";
import { Router } from "express";
import { io } from "../index";
const router: Router = Router();
// Get all connectedAircrafts
router.post("/", async (req, res) => {
try {
const filter = req.body?.filter || {};
const connectedAircrafts = await prisma.connectedAircraft.findMany({
where: filter,
});
res.json(connectedAircrafts);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to fetch connectedAircrafts" });
}
});
// Get a single connectedAircraft by ID
router.get("/:id", async (req, res) => {
const { id } = req.params;
try {
const connectedAircraft = await prisma.connectedAircraft.findUnique({
where: { id: Number(id) },
});
if (connectedAircraft) {
res.json(connectedAircraft);
} else {
res.status(404).json({ error: "ConnectedAircraft not found" });
}
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to fetch connectedAircraft" });
}
});
// Update a connectedAircraft by ID
router.patch("/:id", async (req, res) => {
const { id } = req.params;
const aircraftUpdate = req.body as Prisma.ConnectedAircraftUpdateInput;
try {
const oldConnectedAircraft = await prisma.connectedAircraft.findUnique({
where: { id: Number(id) },
include: {
Station: true,
User: true,
},
});
const updatedConnectedAircraft = await prisma.connectedAircraft.update({
where: { id: Number(id) },
data: {
...aircraftUpdate,
},
});
const mission = await prisma.mission.findFirst({
where: {
state: "running",
missionStationIds: {
has: updatedConnectedAircraft.stationId,
},
},
});
if (
oldConnectedAircraft &&
updatedConnectedAircraft &&
oldConnectedAircraft.fmsStatus !== updatedConnectedAircraft.fmsStatus
) {
io.to("dispatchers").emit("notification", {
type: "station-status",
status: updatedConnectedAircraft.fmsStatus,
message: "FMS status changed",
data: {
stationId: updatedConnectedAircraft.stationId,
aircraftId: updatedConnectedAircraft.id,
userId: updatedConnectedAircraft.userId,
},
} as NotificationPayload);
}
if (
mission &&
aircraftUpdate.fmsStatus &&
oldConnectedAircraft &&
updatedConnectedAircraft &&
oldConnectedAircraft.fmsStatus !== updatedConnectedAircraft.fmsStatus
) {
const newMissionLog = mission.missionLog as any as MissionLog[];
newMissionLog.push({
type: "station-log",
auto: true,
data: {
oldFMSstatus: oldConnectedAircraft.fmsStatus,
newFMSstatus: updatedConnectedAircraft.fmsStatus,
station: oldConnectedAircraft.Station,
stationId: updatedConnectedAircraft.stationId,
user: getPublicUser(oldConnectedAircraft.User),
},
timeStamp: new Date().toISOString(),
});
await prisma.mission.update({
where: { id: mission.id },
data: {
missionLog: newMissionLog as any,
},
});
}
res.json(updatedConnectedAircraft);
// When change is only the estimated logout time, we don't need to emit an event
if (Object.keys(aircraftUpdate).length === 1 && aircraftUpdate.esimatedLogoutTime) return;
io.to("dispatchers").emit("update-connectedAircraft", updatedConnectedAircraft);
io.to(`user:${updatedConnectedAircraft.userId}`).emit(
"aircraft-update",
updatedConnectedAircraft,
);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to update connectedAircraft" });
}
});
router.post("/:id/send-sds-message", async (req, res) => {
const { id } = req.params;
const { sdsMessage } = req.body as { sdsMessage: MissionSdsStatusLog };
if (!sdsMessage.data.stationId || !id) {
res.status(400).json({ error: "Missing aircraftId or stationId" });
return;
}
await prisma.mission.updateMany({
where: {
state: "running",
missionStationIds: {
has: sdsMessage.data.stationId,
},
},
data: {
missionLog: {
push: sdsMessage as unknown as Prisma.InputJsonValue,
},
},
});
io.to(
sdsMessage.data.direction === "to-lst" ? "dispatchers" : `station:${sdsMessage.data.stationId}`,
).emit(sdsMessage.data.direction === "to-lst" ? "notification" : "sds-status", {
type: "station-status",
status: sdsMessage.data.status,
message: "SDS Status Message",
data: {
aircraftId: parseInt(id),
stationId: sdsMessage.data.stationId,
},
} as NotificationPayload);
res.sendStatus(204);
});
// Kick a connectedAircraft by ID
router.delete("/:id", async (req, res) => {
const { id } = req.params;
const bann = req.body?.bann as boolean;
const reason = req.body?.reason as string;
const until = req.body?.until as Date | null;
const requiredPermission = bann ? "ADMIN_USER" : "ADMIN_KICK";
if (!req.user) {
res.status(401).json({ error: "Unauthorized" });
return;
}
if (!req.user.permissions.includes(requiredPermission)) {
res.status(403).json({ error: "Forbidden" });
return;
}
try {
const aircraft = await prisma.connectedAircraft.update({
where: { id: Number(id) },
data: { logoutTime: new Date() },
include: { User: true },
});
if (!aircraft) {
res.status(404).json({ error: "ConnectedAircraft not found" });
return;
}
const status = bann ? "ban" : "kick";
io.to(`user:${aircraft.userId}`).emit("notification", {
type: "admin-message",
message: `Du wurdest von ${getPublicUser(req.user).publicId} ${until ? `bis zum ${new Date(until).toLocaleString()} ` : ""} ${
status === "ban" ? "gekickt, deine Rechte wurden entzogen!" : "gekickt"
}`,
status,
data: { admin: getPublicUser(req.user), reason },
} as AdminMessage);
io.in(`user:${aircraft.userId}`).disconnectSockets(true);
if (bann && !until) {
await prisma.user.update({
where: { id: aircraft.userId },
data: {
permissions: {
set: aircraft.User.permissions.filter((p) => p !== "PILOT"),
},
},
});
}
await prisma.penalty.create({
data: {
userId: aircraft.userId,
type: bann ? (until ? "TIME_BAN" : "PERMISSIONS_REVOCED") : "KICK",
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
reason: reason,
createdUserId: req.user.id,
},
});
res.status(204).send();
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to disconnect pilot" });
}
});
export default router;