Added Discord message for reports, Fixed type on docs

This commit is contained in:
PxlLoewe
2025-06-13 23:50:19 -07:00
parent 999daf17ad
commit 98cc1d6089
9 changed files with 114 additions and 11 deletions

View File

@@ -0,0 +1,67 @@
import { prisma } from "@repo/db";
import { Embed, EmbedBuilder } from "discord.js";
import { Router } from "express";
import client from "modules/discord";
if (!process.env.DISCORD_REPORT_CHANNEL)
throw new Error("DISCORD_REPORT_CHANNEL environment variable is not set.");
const router: Router = Router();
router.post("/admin-embed", async (req, res) => {
const { reportId } = req.body;
if (!reportId) {
res.status(400).json({ error: "reportId is required" });
return;
}
const report = await prisma.report.findUnique({
where: {
id: Number(reportId),
},
include: {
Reported: true,
Sender: true,
},
});
if (!report) {
res.status(404).json({ error: "Report not found" });
return;
}
const embed = new EmbedBuilder()
.setTitle(`Report #${report.id}`)
.setURL(`${process.env.NEXT_PUBLIC_HUB_URL}/admin/report/${report.id}`)
.setDescription(report.text)
.addFields(
{
name: "gemeldeter Nutzer",
value: `${report.Reported?.firstname} ${report.Reported?.lastname} (${report.Reported?.publicId})`,
inline: true,
},
{ name: "angemeldet als", value: report.reportedUserRole, inline: true },
{
name: "gemeldet von",
value: `${report.Sender?.firstname} ${report.Sender?.lastname} (${report.Sender?.publicId})`,
},
)
.setFooter({
text: "",
})
.setTimestamp(new Date(report.timestamp))
.setColor("DarkRed");
const reportsChannel = await client.channels.fetch(process.env.DISCORD_REPORT_CHANNEL!);
if (!reportsChannel || !reportsChannel.isSendable()) {
res.status(500).json({ error: "Reports channel not found or is not a text channel" });
return;
}
const message = await reportsChannel.send({ embeds: [embed] });
message.react("🫡").catch(console.error);
message.react("✅").catch(console.error);
res.json({
message: "Report embed sent to Discord channel",
});
});
export default router;

View File

@@ -1,10 +1,12 @@
import { Router } from "express";
import memberRouter from "./member";
import helperRouter from "./helper";
import reportRouter from "./report";
const router: Router = Router();
router.use("/member", memberRouter);
router.use("/helper", helperRouter);
router.use("/report", reportRouter);
export default router;

View File

@@ -36,3 +36,13 @@ export const removeRolesFromMember = async (memberId: string, roleIds: string[])
console.error("Error removing roles from member:", error);
});
};
export const sendReportEmbed = async (reportId: number) => {
discordAxiosClient
.post("/report/admin-embed", {
reportId,
})
.catch((error) => {
console.error("Error removing roles from member:", error);
});
};

View File

@@ -1,6 +1,7 @@
import { Router } from "express";
import { prisma } from "@repo/db";
import { sendReportEmbed } from "modules/discord";
const router: Router = Router();
@@ -11,6 +12,9 @@ router.put("/", async (req, res) => {
});
// TODO: send link to report on admin page to user
sendReportEmbed(report.id).catch((error) => {
console.error("Error sending report embed to Discord:", error);
});
res.json(report);
} catch (error) {

View File

@@ -109,12 +109,16 @@ export const Report = () => {
onClick={(e) => {
e.preventDefault();
if (message.length < 1 || !selectedPlayer) return;
const dispatcher = filteredDispatcher?.find((d) => d.userId === selectedPlayer)
? "Disponent"
: null;
const pilot = filteredAircrafts?.find((a) => a.userId === selectedPlayer)
? "Pilot"
: null;
const selectedDispatcher = filteredDispatcher?.find(
(d) => d.userId === selectedPlayer,
);
const dispatcher = selectedDispatcher ? selectedDispatcher.zone : null;
const selectedAircraft = filteredAircrafts?.find(
(a) => a.userId === selectedPlayer,
);
const pilot = selectedAircraft ? selectedAircraft.Station.bosCallsignShort : null;
setSending(true);
sendReportAPI({
text: message,

View File

@@ -3,7 +3,7 @@
Was ist neu? Quasi alles.
Nicht nur die Leitstelle erhält eine V2, nahezu alle Systeme und Vorgänge wurden überarbeitet.
In diesem Beitrag gehen wir auf die wchtigsten einzelheiten ein.
In diesem Beitrag gehen wir auf die wichtigsten einzelheiten ein.
### Das neue HUB

View File

@@ -25,7 +25,8 @@ export const ReportSenderInfo = ({
return (
<div className="card-body">
<Link href={`/admin/user/${Reported?.id}`} className="card-title link link-hover">
{Reported?.firstname} {Reported?.lastname} ({Reported?.publicId})
{Reported?.firstname} {Reported?.lastname} ({Reported?.publicId}) als{" "}
<span className="text-primary">{report.reportedUserRole}</span>
</Link>
<div className="textarea w-full text-left">{report.text}</div>
<Link

View File

@@ -1,9 +1,10 @@
"use client";
import { Check, Eye, X } from "lucide-react";
import { Check, Eye, ShieldQuestion, X } from "lucide-react";
import Link from "next/link";
import { PaginatedTable } from "_components/PaginatedTable";
import { Report, User } from "@repo/db";
import { ColumnDef } from "@tanstack/react-table";
import { Workflow, Plane } from "lucide-react";
export default function ReportPage() {
return (
@@ -40,6 +41,20 @@ export default function ReportPage() {
return `${user.firstname} ${user.lastname} (${user.publicId})`;
},
},
{
accessorKey: "reportedUserRole",
header: "Rolle des gemeldeten Nutzers",
cell: ({ row }) => {
const role = row.getValue("reportedUserRole") as string | undefined;
const Icon = role ? (role.startsWith("LST") ? Workflow : Plane) : ShieldQuestion;
return (
<span className="flex items-center gap-2">
<Icon className="w-4 h-4" />
{role || "Unbekannt"}
</span>
);
},
},
{
accessorKey: "Reported",
header: "Reported",

View File

@@ -74,8 +74,8 @@ export const PasswortReset = () => {
: ""}
</p>
<span className="text-sm font-medium flex justify-end">
<Link href="/passwort-reset" className="link link-accent link-hover ">
neues Passwort anfordern
<Link href="/login" className="link link-accent link-hover ">
zum Login
</Link>
</span>
<div className="card-actions mt-6">