268 lines
7.2 KiB
TypeScript
268 lines
7.2 KiB
TypeScript
import { DISCORD_ROLES, MissionLog, NotificationPayload, prisma } from "@repo/db";
|
|
import { io } from "index";
|
|
import cron from "node-cron";
|
|
import { setUserStandardNamePermissions } from "routes/helper";
|
|
import { changeMemberRoles } from "routes/member";
|
|
import client from "./discord";
|
|
|
|
const removeMission = async (id: number, reason: string) => {
|
|
const log: MissionLog = {
|
|
type: "completed-log",
|
|
auto: true,
|
|
timeStamp: new Date().toISOString(),
|
|
data: {},
|
|
};
|
|
|
|
const updatedMission = await prisma.mission.update({
|
|
where: {
|
|
id: id,
|
|
},
|
|
data: {
|
|
state: "finished",
|
|
missionLog: {
|
|
push: log as any,
|
|
},
|
|
},
|
|
});
|
|
io.to("dispatchers").emit("new-mission", { updatedMission });
|
|
io.to("dispatchers").emit("notification", {
|
|
type: "mission-auto-close",
|
|
status: "chron",
|
|
message: `Einsatz ${updatedMission.publicId} wurde aufgrund ${reason} geschlossen.`,
|
|
data: {
|
|
missionId: updatedMission.id,
|
|
publicMissionId: updatedMission.publicId,
|
|
},
|
|
} as NotificationPayload);
|
|
|
|
console.log(`Mission ${updatedMission.id} closed due to inactivity.`);
|
|
};
|
|
const removeClosedMissions = async () => {
|
|
const oldMissions = await prisma.mission.findMany({
|
|
where: {
|
|
state: "running",
|
|
},
|
|
});
|
|
oldMissions.forEach(async (mission) => {
|
|
const lastAlert = (mission.missionLog as unknown as MissionLog[]).find((l) => {
|
|
return l.type === "alert-log";
|
|
});
|
|
|
|
const lastAlertTime = lastAlert ? new Date(lastAlert.timeStamp) : null;
|
|
|
|
const allStationsInMissionChangedFromStatus4to1Or8to1 = mission.missionStationIds.every(
|
|
(stationId) => {
|
|
const status4Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
|
|
return (
|
|
l.type === "station-log" &&
|
|
l.data?.stationId === stationId &&
|
|
l.data?.newFMSstatus === "4"
|
|
);
|
|
});
|
|
const status8Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
|
|
return (
|
|
l.type === "station-log" &&
|
|
l.data?.stationId === stationId &&
|
|
l.data?.newFMSstatus === "8"
|
|
);
|
|
});
|
|
|
|
const status1Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
|
|
return (
|
|
l.type === "station-log" &&
|
|
l.data?.stationId === stationId &&
|
|
l.data?.newFMSstatus === "1"
|
|
);
|
|
});
|
|
const status6Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
|
|
return (
|
|
l.type === "station-log" &&
|
|
l.data?.stationId === stationId &&
|
|
l.data?.newFMSstatus === "6"
|
|
);
|
|
});
|
|
return (
|
|
(status4Log !== -1 || status8Log !== -1) &&
|
|
(status1Log !== -1 || status6Log !== -1) &&
|
|
(status4Log < status1Log ||
|
|
status8Log < status1Log ||
|
|
status8Log < status6Log ||
|
|
status1Log < status6Log)
|
|
);
|
|
},
|
|
);
|
|
|
|
const missionHasManualReactivation = (mission.missionLog as unknown as MissionLog[]).some(
|
|
(l) => l.type === "reopened-log",
|
|
);
|
|
|
|
if (missionHasManualReactivation) return;
|
|
|
|
if (!lastAlertTime) return;
|
|
|
|
const lastStatus1or6Log = (mission.missionLog as unknown as MissionLog[])
|
|
.filter((l) => {
|
|
return (
|
|
l.type === "station-log" && (l.data?.newFMSstatus === "1" || l.data?.newFMSstatus === "6")
|
|
);
|
|
})
|
|
.sort((a, b) => new Date(b.timeStamp).getTime() - new Date(a.timeStamp).getTime())[0];
|
|
|
|
// Case 1: Forgotten Mission, last alert more than 3 Hours ago
|
|
const now = new Date();
|
|
if (now.getTime() - lastAlertTime.getTime() > 1000 * 60 * 180)
|
|
return removeMission(mission.id, "inaktivität");
|
|
|
|
// Case 2: All stations in mission changed from status 4 to 1/6 or from status 8 to 1/6, Status 1/6 change less more 5 minutes ago
|
|
if (
|
|
allStationsInMissionChangedFromStatus4to1Or8to1 &&
|
|
lastStatus1or6Log &&
|
|
now.getTime() - new Date(lastStatus1or6Log.timeStamp).getTime() > 1000 * 60 * 5
|
|
)
|
|
return removeMission(mission.id, "dem freimelden aller Stationen");
|
|
});
|
|
};
|
|
|
|
const syncDiscordImgUrls = async () => {
|
|
try {
|
|
const discordAccounts = await prisma.discordAccount.findMany({
|
|
where: {
|
|
updatedAt: {
|
|
lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
|
|
},
|
|
User: {
|
|
isNot: null,
|
|
},
|
|
},
|
|
});
|
|
for (const account of discordAccounts) {
|
|
client.users.fetch(account.discordId).then((discordUser) => {
|
|
const nextAvatar = discordUser?.avatar ?? null;
|
|
if (typeof nextAvatar !== "string") return;
|
|
if (nextAvatar === account.avatar) return;
|
|
prisma.discordAccount.update({
|
|
where: {
|
|
id: account.id,
|
|
},
|
|
data: {
|
|
avatar: nextAvatar,
|
|
},
|
|
});
|
|
});
|
|
}
|
|
} catch (error) {}
|
|
};
|
|
|
|
const removeConnectedAircrafts = async () => {
|
|
const connectedAircrafts = await prisma.connectedAircraft.findMany({
|
|
where: {
|
|
logoutTime: null,
|
|
},
|
|
});
|
|
|
|
connectedAircrafts.forEach(async (aircraft) => {
|
|
const lastUpdate = new Date(aircraft.lastHeartbeat);
|
|
const now = new Date();
|
|
if (now.getTime() - lastUpdate.getTime() > 12 * 60 * 60 * 1000) {
|
|
await prisma.connectedAircraft.update({
|
|
where: { id: aircraft.id },
|
|
data: { logoutTime: now },
|
|
});
|
|
|
|
console.log(`Aircraft ${aircraft.id} disconnected due to inactivity.`);
|
|
}
|
|
});
|
|
};
|
|
const removePermissionsForBannedUsers = async () => {
|
|
try {
|
|
const removePermissionsPenaltys = await prisma.penalty.findMany({
|
|
where: {
|
|
removePermissionApplied: false,
|
|
User: {
|
|
DiscordAccount: { isNot: null },
|
|
},
|
|
},
|
|
include: {
|
|
User: {
|
|
include: {
|
|
DiscordAccount: true,
|
|
FormerDiscordAccounts: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
const addPermissionsPenaltys = await prisma.penalty.findMany({
|
|
where: {
|
|
addPermissionApplied: false,
|
|
User: {
|
|
DiscordAccount: { isNot: null },
|
|
},
|
|
OR: [{ suspended: true }, { until: { lt: new Date().toISOString() } }],
|
|
},
|
|
include: {
|
|
User: {
|
|
include: {
|
|
DiscordAccount: true,
|
|
FormerDiscordAccounts: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
for (const penalty of removePermissionsPenaltys) {
|
|
const user = penalty.User;
|
|
console.log(`Removing roles for user ${user.id} due to penalty ${penalty.id}`);
|
|
|
|
await changeMemberRoles(
|
|
user.DiscordAccount!.discordId,
|
|
[DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
|
|
"remove",
|
|
);
|
|
|
|
for (const formerAccount of user.FormerDiscordAccounts) {
|
|
await changeMemberRoles(
|
|
formerAccount.discordId,
|
|
[DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
|
|
"remove",
|
|
);
|
|
}
|
|
await prisma.penalty.update({
|
|
where: { id: penalty.id },
|
|
data: { removePermissionApplied: true },
|
|
});
|
|
}
|
|
for (const penalty of addPermissionsPenaltys) {
|
|
console.log(`Restoring roles for user ${penalty.userId} due to penalty ${penalty.id}`);
|
|
await setUserStandardNamePermissions({
|
|
memberId: penalty.User.DiscordAccount!.discordId,
|
|
userId: penalty.userId,
|
|
});
|
|
await prisma.penalty.update({
|
|
where: { id: penalty.id },
|
|
data: { addPermissionApplied: true },
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error("Error removing permissions for banned users:", error);
|
|
}
|
|
};
|
|
|
|
cron.schedule("0 0 * * *", async () => {
|
|
try {
|
|
await syncDiscordImgUrls();
|
|
} catch (error) {
|
|
console.error("Error on daily cron job:", error);
|
|
}
|
|
});
|
|
|
|
cron.schedule("*/1 * * * *", async () => {
|
|
try {
|
|
await removePermissionsForBannedUsers();
|
|
await removeClosedMissions();
|
|
await removeConnectedAircrafts();
|
|
} catch (error) {
|
|
console.error("Error on cron job:", error);
|
|
}
|
|
});
|