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, }, }, }); const user = await prisma.user.findFirst({ where: { publicId: sdsMessage.data.user.publicId, firstname: sdsMessage.data.user.firstname }, }); if (!user) { res.status(404).json({ error: "User not found" }); return; } 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, userId: user.id, }, } 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;