Discord Permissions will be revoked, when under a penalty

This commit is contained in:
PxlLoewe
2026-01-31 22:48:26 +01:00
parent d1c49a3208
commit ac441e908d
7 changed files with 94 additions and 40 deletions

View File

@@ -1,6 +1,7 @@
import { DISCORD_ROLES, MissionLog, NotificationPayload, prisma } from "@repo/db"; import { DISCORD_ROLES, MissionLog, NotificationPayload, prisma } from "@repo/db";
import { io } from "index"; import { io } from "index";
import cron from "node-cron"; import cron from "node-cron";
import { setUserStandardNamePermissions } from "routes/helper";
import { changeMemberRoles } from "routes/member"; import { changeMemberRoles } from "routes/member";
const removeMission = async (id: number, reason: string) => { const removeMission = async (id: number, reason: string) => {
@@ -141,21 +142,12 @@ const removeConnectedAircrafts = async () => {
}); });
}; };
const removePermissionsForBannedUsers = async () => { const removePermissionsForBannedUsers = async () => {
const activePenalties = await prisma.penalty.findMany({ const removePermissionsPenaltys = await prisma.penalty.findMany({
where: { where: {
OR: [ removePermissionApplied: false,
{ User: {
type: "BAN", DiscordAccount: { isNot: null },
suspended: false, },
},
{
type: "TIME_BAN",
suspended: false,
until: {
gt: new Date().toISOString(),
},
},
],
}, },
include: { include: {
User: { User: {
@@ -167,16 +159,33 @@ const removePermissionsForBannedUsers = async () => {
}, },
}); });
for (const penalty of activePenalties) { const addPermissionsPenaltys = await prisma.penalty.findMany({
const user = penalty.User; where: {
addPermissionApplied: false,
User: {
DiscordAccount: { isNot: null },
},
OR: [{ suspended: true }, { until: { lt: new Date().toISOString() } }],
},
include: {
User: {
include: {
DiscordAccount: true,
FormerDiscordAccounts: true,
},
},
},
});
if (user.DiscordAccount) { for (const penalty of removePermissionsPenaltys) {
await changeMemberRoles( const user = penalty.User;
user.DiscordAccount.discordId, console.log(`Removing roles for user ${user.id} due to penalty ${penalty.id}`);
[DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
"remove", await changeMemberRoles(
); user.DiscordAccount!.discordId,
} [DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
"remove",
);
for (const formerAccount of user.FormerDiscordAccounts) { for (const formerAccount of user.FormerDiscordAccounts) {
await changeMemberRoles( await changeMemberRoles(
@@ -185,15 +194,29 @@ const removePermissionsForBannedUsers = async () => {
"remove", "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 },
});
} }
}; };
cron.schedule("*/5 * * * *", async () => { removePermissionsForBannedUsers();
await removePermissionsForBannedUsers();
});
cron.schedule("*/1 * * * *", async () => { cron.schedule("*/1 * * * *", async () => {
try { try {
await removePermissionsForBannedUsers();
await removeClosedMissions(); await removeClosedMissions();
await removeConnectedAircrafts(); await removeConnectedAircrafts();
} catch (error) { } catch (error) {

View File

@@ -10,18 +10,22 @@ export const eventCompleted = (event: Event, participant?: Participant) => {
return true; return true;
}; };
router.post("/set-standard-name", async (req, res) => { export const setUserStandardNamePermissions = async ({
const { memberId, userId } = req.body; memberId,
userId,
}: {
memberId: string;
userId: string;
}) => {
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
where: { where: {
id: userId, id: userId,
}, },
}); });
if (!user) { if (!user) {
res.status(404).json({ error: "User not found" });
return; return;
} }
const participant = await prisma.participant.findMany({ const participant = await prisma.participant.findMany({
where: { where: {
userId: user.id, userId: user.id,
@@ -72,6 +76,13 @@ router.post("/set-standard-name", async (req, res) => {
await changeMemberRoles(memberId, [DISCORD_ROLES.PILOT], isPilot ? "add" : "remove"); await changeMemberRoles(memberId, [DISCORD_ROLES.PILOT], isPilot ? "add" : "remove");
await changeMemberRoles(memberId, [DISCORD_ROLES.DISPATCHER], isDispatcher ? "add" : "remove"); await changeMemberRoles(memberId, [DISCORD_ROLES.DISPATCHER], isDispatcher ? "add" : "remove");
} }
};
router.post("/set-standard-name", async (req, res) => {
const { memberId, userId } = req.body;
await setUserStandardNamePermissions({ memberId, userId });
res.status(200).json({ message: "Standard name and permissions set" });
}); });
export default router; export default router;

View File

@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "Penalty" ADD COLUMN "addPermissionApplied" BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN "removePermissionApplied" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -0,0 +1,13 @@
/*
Warnings:
- The primary key for the `FormerDiscordAccount` table will be changed. If it partially fails, the table could be left without primary key constraint.
*/
-- DropIndex
DROP INDEX "FormerDiscordAccount_discord_id_key";
-- AlterTable
ALTER TABLE "FormerDiscordAccount" DROP CONSTRAINT "FormerDiscordAccount_pkey",
ADD COLUMN "id" SERIAL NOT NULL,
ADD CONSTRAINT "FormerDiscordAccount_pkey" PRIMARY KEY ("id");

View File

@@ -10,6 +10,10 @@ model Penalty {
suspended Boolean @default(false) suspended Boolean @default(false)
// For Chronjob to know if permissions were already applied/removed
removePermissionApplied Boolean @default(false)
addPermissionApplied Boolean @default(false)
timestamp DateTime @default(now()) timestamp DateTime @default(now())
// relations: // relations:

View File

@@ -94,14 +94,13 @@ model User {
} }
model FormerDiscordAccount { model FormerDiscordAccount {
discordId String @unique @map(name: "discord_id") id Int @id @default(autoincrement())
discordId String @map(name: "discord_id")
userId String @map(name: "user_id") userId String @map(name: "user_id")
removedAt DateTime @default(now()) @map(name: "removed_at") removedAt DateTime @default(now()) @map(name: "removed_at")
DiscordAccount DiscordAccount? @relation(fields: [discordId], references: [discordId], onDelete: SetNull) DiscordAccount DiscordAccount? @relation(fields: [discordId], references: [discordId], onDelete: SetNull)
User User @relation(fields: [userId], references: [id], onDelete: Cascade) User User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([discordId, userId])
} }
model DiscordAccount { model DiscordAccount {
@@ -119,9 +118,9 @@ model DiscordAccount {
updatedAt DateTime @default(now()) @map(name: "updated_at") updatedAt DateTime @default(now()) @map(name: "updated_at")
// Related User // Related User
userId String? @unique userId String? @unique
User User? @relation(fields: [userId], references: [id], onDelete: SetNull) User User? @relation(fields: [userId], references: [id], onDelete: SetNull)
formerDiscordAccount FormerDiscordAccount? formerDiscordAccount FormerDiscordAccount[]
@@map(name: "discord_accounts") @@map(name: "discord_accounts")
} }

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import { ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
import { cn } from "../helper/cn"; import { cn } from "../helper/cn";
import { Button } from "./Button";
export const PenaltyDropdown = ({ export const PenaltyDropdown = ({
onClick, onClick,
@@ -79,10 +80,10 @@ export const PenaltyDropdown = ({
<option value="1y">1 Jahr</option> <option value="1y">1 Jahr</option>
</select> </select>
)} )}
<button <Button
className={cn("btn btn-square btn-soft tooltip tooltip-bottom w-full", btnClassName)} className={cn("btn btn-square btn-soft tooltip tooltip-bottom w-full", btnClassName)}
data-tip={btnTip} data-tip={btnTip}
onClick={() => { onClick={async () => {
let untilDate: Date | null = null; let untilDate: Date | null = null;
if (until !== "default") { if (until !== "default") {
const now = new Date(); const now = new Date();
@@ -124,11 +125,11 @@ export const PenaltyDropdown = ({
untilDate = null; untilDate = null;
} }
} }
onClick({ reason, until: untilDate }); await onClick({ reason, until: untilDate });
}} }}
> >
{Icon} {btnName} {Icon} {btnName}
</button> </Button>
</div> </div>
)} )}
</div> </div>