Berechtigungen werden nun beim Verbinden überprüft, Bannen wird nun im Piloten-fenster gelogt
This commit is contained in:
@@ -136,7 +136,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
const aircraft = await prisma.connectedAircraft.update({
|
const aircraft = await prisma.connectedAircraft.update({
|
||||||
where: { id: Number(id) },
|
where: { id: Number(id) },
|
||||||
data: { logoutTime: new Date() },
|
data: { logoutTime: new Date() },
|
||||||
include: bann ? { User: true } : undefined,
|
include: { User: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!aircraft) {
|
if (!aircraft) {
|
||||||
@@ -149,7 +149,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
io.to(`user:${aircraft.userId}`).emit("notification", {
|
io.to(`user:${aircraft.userId}`).emit("notification", {
|
||||||
type: "admin-message",
|
type: "admin-message",
|
||||||
message: `Du wurdest von ${getPublicUser(req.user).publicId} ${until ? `bis zum ${new Date(until).toLocaleString()} ` : ""} ${
|
message: `Du wurdest von ${getPublicUser(req.user).publicId} ${until ? `bis zum ${new Date(until).toLocaleString()} ` : ""} ${
|
||||||
status === "ban" ? "gebannt" : "gekickt"
|
status === "ban" ? "gekickt, deine Rechte wurden entzogen!" : "gekickt"
|
||||||
}`,
|
}`,
|
||||||
status,
|
status,
|
||||||
data: { admin: getPublicUser(req.user), reason },
|
data: { admin: getPublicUser(req.user), reason },
|
||||||
@@ -162,7 +162,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
where: { id: aircraft.userId },
|
where: { id: aircraft.userId },
|
||||||
data: {
|
data: {
|
||||||
permissions: {
|
permissions: {
|
||||||
set: req.user.permissions.filter((p) => p !== "PILOT"),
|
set: aircraft.User.permissions.filter((p) => p !== "PILOT"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -170,7 +170,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
await prisma.penalty.create({
|
await prisma.penalty.create({
|
||||||
data: {
|
data: {
|
||||||
userId: aircraft.userId,
|
userId: aircraft.userId,
|
||||||
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
type: bann ? (until ? "TIME_BAN" : "PERMISSIONS_REVOCED") : "KICK",
|
||||||
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
||||||
reason: reason,
|
reason: reason,
|
||||||
createdUserId: req.user.id,
|
createdUserId: req.user.id,
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ router.patch("/:id", async (req, res) => {
|
|||||||
res.json(newDispatcher);
|
res.json(newDispatcher);
|
||||||
});
|
});
|
||||||
|
|
||||||
import { Request, Response } from "express";
|
|
||||||
|
|
||||||
router.delete("/:id", async (req, res) => {
|
router.delete("/:id", async (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const bann = req.body?.bann as boolean;
|
const bann = req.body?.bann as boolean;
|
||||||
@@ -53,7 +51,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
const dispatcher = await prisma.connectedDispatcher.update({
|
const dispatcher = await prisma.connectedDispatcher.update({
|
||||||
where: { id: Number(id) },
|
where: { id: Number(id) },
|
||||||
data: { logoutTime: new Date() },
|
data: { logoutTime: new Date() },
|
||||||
include: bann ? { user: true } : undefined,
|
include: { user: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!dispatcher) {
|
if (!dispatcher) {
|
||||||
@@ -66,7 +64,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
io.to(`user:${dispatcher.userId}`).emit("notification", {
|
io.to(`user:${dispatcher.userId}`).emit("notification", {
|
||||||
type: "admin-message",
|
type: "admin-message",
|
||||||
message: `Du wurdest von ${getPublicUser(req.user).publicId} ${until ? `bis zum ${new Date(until).toLocaleString()} ` : ""} ${
|
message: `Du wurdest von ${getPublicUser(req.user).publicId} ${until ? `bis zum ${new Date(until).toLocaleString()} ` : ""} ${
|
||||||
status === "ban" ? "gebannt" : "gekickt"
|
status === "ban" ? "gekickt, deine Rechte wurden entzogen" : "gekickt"
|
||||||
}`,
|
}`,
|
||||||
status,
|
status,
|
||||||
data: { admin: getPublicUser(req.user), reason },
|
data: { admin: getPublicUser(req.user), reason },
|
||||||
@@ -79,7 +77,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
where: { id: dispatcher.userId },
|
where: { id: dispatcher.userId },
|
||||||
data: {
|
data: {
|
||||||
permissions: {
|
permissions: {
|
||||||
set: req.user.permissions.filter((p) => p !== "DISPO"),
|
set: dispatcher.user.permissions.filter((p) => p !== "DISPO"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -87,7 +85,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
await prisma.penalty.create({
|
await prisma.penalty.create({
|
||||||
data: {
|
data: {
|
||||||
userId: dispatcher.userId,
|
userId: dispatcher.userId,
|
||||||
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
type: bann ? (until ? "TIME_BAN" : "PERMISSIONS_REVOCED") : "KICK",
|
||||||
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
||||||
reason: reason,
|
reason: reason,
|
||||||
createdUserId: req.user.id,
|
createdUserId: req.user.id,
|
||||||
|
|||||||
@@ -10,7 +10,14 @@ export const handleConnectDispatch =
|
|||||||
const user: User = socket.data.user; // User ID aus dem JWT-Token
|
const user: User = socket.data.user; // User ID aus dem JWT-Token
|
||||||
|
|
||||||
if (!user) return Error("User not found");
|
if (!user) return Error("User not found");
|
||||||
console.log("Disponent connected:", user.publicId);
|
|
||||||
|
if (!user.permissions.includes("DISPO")) {
|
||||||
|
socket.emit("connect-message", {
|
||||||
|
message: "Fehlende Berechtigung",
|
||||||
|
});
|
||||||
|
socket.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!user.permissions?.includes("DISPO")) {
|
if (!user.permissions?.includes("DISPO")) {
|
||||||
socket.emit("error", "You do not have permission to connect to the dispatch server.");
|
socket.emit("error", "You do not have permission to connect to the dispatch server.");
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ export const handleConnectPilot =
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!user.permissions.includes("PILOT")) {
|
||||||
|
socket.emit("connect-message", {
|
||||||
|
message: "Fehlende Berechtigung",
|
||||||
|
});
|
||||||
|
socket.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) return Error("User not found");
|
if (!user) return Error("User not found");
|
||||||
|
|
||||||
const existingConnection = await prisma.connectedAircraft.findFirst({
|
const existingConnection = await prisma.connectedAircraft.findFirst({
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
Plane,
|
Plane,
|
||||||
RedoDot,
|
RedoDot,
|
||||||
Shield,
|
Shield,
|
||||||
ShieldAlert,
|
|
||||||
Speaker,
|
Speaker,
|
||||||
User,
|
User,
|
||||||
UserCheck,
|
UserCheck,
|
||||||
@@ -266,7 +265,7 @@ export default function AdminPanel() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PenaltyDropdown
|
<PenaltyDropdown
|
||||||
btnClassName="btn-error"
|
btnClassName="btn-error tooltip-error"
|
||||||
btnTip="Kick + Berechtigungen entfernen"
|
btnTip="Kick + Berechtigungen entfernen"
|
||||||
showDatePicker
|
showDatePicker
|
||||||
Icon={<LockKeyhole size={15} />}
|
Icon={<LockKeyhole size={15} />}
|
||||||
@@ -319,7 +318,7 @@ export default function AdminPanel() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PenaltyDropdown
|
<PenaltyDropdown
|
||||||
btnClassName="btn-error"
|
btnClassName="btn-error tooltip-error"
|
||||||
btnTip="Kick + Berechtigungen entfernen"
|
btnTip="Kick + Berechtigungen entfernen"
|
||||||
showDatePicker
|
showDatePicker
|
||||||
Icon={<LockKeyhole size={15} />}
|
Icon={<LockKeyhole size={15} />}
|
||||||
|
|||||||
@@ -56,8 +56,14 @@ dispatchSocket.on("connect_error", (err) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dispatchSocket.on("connect-message", (data) => {
|
||||||
|
useDispatchConnectionStore.setState({
|
||||||
|
message: data.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
dispatchSocket.on("disconnect", () => {
|
dispatchSocket.on("disconnect", () => {
|
||||||
useDispatchConnectionStore.setState({ status: "disconnected", message: "" });
|
useDispatchConnectionStore.setState({ status: "disconnected" });
|
||||||
useAudioStore.getState().disconnect();
|
useAudioStore.getState().disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,14 @@ pilotSocket.on("connect_error", (err) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pilotSocket.on("connect-message", (data) => {
|
||||||
|
usePilotConnectionStore.setState({
|
||||||
|
message: data.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
pilotSocket.on("disconnect", () => {
|
pilotSocket.on("disconnect", () => {
|
||||||
usePilotConnectionStore.setState({ status: "disconnected", message: "" });
|
usePilotConnectionStore.setState({ status: "disconnected" });
|
||||||
useAudioStore.getState().disconnect();
|
useAudioStore.getState().disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export default async function RootLayout({
|
|||||||
until: {
|
until: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
|
suspended: false,
|
||||||
|
|
||||||
type: { in: ["TIME_BAN", "BAN"] },
|
type: { in: ["TIME_BAN", "BAN"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default async function RootLayout({
|
|||||||
until: {
|
until: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
|
suspended: false,
|
||||||
type: { in: ["TIME_BAN", "BAN"] },
|
type: { in: ["TIME_BAN", "BAN"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
"use server";
|
"use server";
|
||||||
import { Prisma, prisma } from "@repo/db";
|
import { Prisma, prisma } from "@repo/db";
|
||||||
|
|
||||||
export const addPenalty = async (data: Prisma.PenaltyCreateInput) => {
|
export const addPenalty = async (
|
||||||
|
data: Prisma.Without<Prisma.PenaltyCreateInput, Prisma.PenaltyUncheckedCreateInput> &
|
||||||
|
Prisma.PenaltyUncheckedCreateInput,
|
||||||
|
) => {
|
||||||
return await prisma.penalty.create({
|
return await prisma.penalty.create({
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { ColumnDef } from "@tanstack/react-table";
|
|||||||
import { formatDistance } from "date-fns";
|
import { formatDistance } from "date-fns";
|
||||||
import { de } from "date-fns/locale";
|
import { de } from "date-fns/locale";
|
||||||
import { cn } from "../../../../helper/cn";
|
import { cn } from "../../../../helper/cn";
|
||||||
|
import { HobbyKnifeIcon } from "@radix-ui/react-icons";
|
||||||
|
|
||||||
export const penaltyColumns: ColumnDef<Penalty & { Report: Report }>[] = [
|
export const penaltyColumns: ColumnDef<Penalty & { Report: Report }>[] = [
|
||||||
{
|
{
|
||||||
@@ -39,10 +40,17 @@ export const penaltyColumns: ColumnDef<Penalty & { Report: Report }>[] = [
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "PERMISSIONS_REVOCED":
|
||||||
|
return (
|
||||||
|
<div className={cn("text-error flex gap-3", row.original.suspended && "text-gray-400")}>
|
||||||
|
<LockKeyhole /> Rechte entzogen {row.original.suspended && "(ausgesetzt)"}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
case "BAN":
|
case "BAN":
|
||||||
return (
|
return (
|
||||||
<div className={cn("text-error flex gap-3", row.original.suspended && "text-gray-400")}>
|
<div className={cn("text-error flex gap-3", row.original.suspended && "text-gray-400")}>
|
||||||
<LockKeyhole /> Bann {row.original.suspended && "(ausgesetzt)"}
|
<HobbyKnifeIcon /> Bann {row.original.suspended && "(ausgesetzt)"}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import { ReactNode, useState } from "react";
|
||||||
|
import { cn } from "../../../../../../helper/cn";
|
||||||
|
|
||||||
|
export const PenaltyDropdown = ({
|
||||||
|
onClick,
|
||||||
|
btnClassName,
|
||||||
|
showDatePicker,
|
||||||
|
btnTip,
|
||||||
|
Icon,
|
||||||
|
}: {
|
||||||
|
onClick: (data: { reason: string; until: Date | null }) => void;
|
||||||
|
showDatePicker?: boolean;
|
||||||
|
btnClassName?: string;
|
||||||
|
btnTip?: string;
|
||||||
|
Icon: ReactNode;
|
||||||
|
}) => {
|
||||||
|
const [reason, setReason] = useState("");
|
||||||
|
const [until, setUntil] = useState<string>("default");
|
||||||
|
return (
|
||||||
|
<details className="dropdown dropdown-left dropdown-center">
|
||||||
|
<summary className={cn("btn btn-xs btn-square btn-soft", btnClassName)}>{Icon}</summary>
|
||||||
|
<div className="dropdown-content flex gap-3 items-center bg-base-100 rounded-box z-1 p-2 mr-3 shadow-sm">
|
||||||
|
<input
|
||||||
|
value={reason}
|
||||||
|
onChange={(e) => setReason(e.target.value)}
|
||||||
|
type="text"
|
||||||
|
className="input min-w-[250px]"
|
||||||
|
placeholder="Begründung"
|
||||||
|
/>
|
||||||
|
{showDatePicker && (
|
||||||
|
<select
|
||||||
|
className="select min-w-[150px] select-bordered"
|
||||||
|
value={until}
|
||||||
|
onChange={(e) => setUntil(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="default" disabled>
|
||||||
|
Unbegrenzt
|
||||||
|
</option>
|
||||||
|
<option value="1h">1 Stunde</option>
|
||||||
|
<option value="6h">6 Stunden</option>
|
||||||
|
<option value="12h">12 Stunden</option>
|
||||||
|
<option value="24h">24 Stunden</option>
|
||||||
|
<option value="72h">72 Stunden</option>
|
||||||
|
<option value="1w">1 Woche</option>
|
||||||
|
<option value="2w">2 Wochen</option>
|
||||||
|
<option value="1m">1 Monat</option>
|
||||||
|
<option value="3m">3 Monate</option>
|
||||||
|
<option value="6m">6 Monate</option>
|
||||||
|
<option value="1y">1 Jahr</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
className={cn("btn btn-square btn-soft tooltip tooltip-bottom", btnClassName)}
|
||||||
|
data-tip={btnTip}
|
||||||
|
onClick={() => {
|
||||||
|
let untilDate: Date | null = null;
|
||||||
|
if (until !== "default") {
|
||||||
|
const now = new Date();
|
||||||
|
switch (until) {
|
||||||
|
case "1h":
|
||||||
|
untilDate = new Date(now.getTime() + 1 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "6h":
|
||||||
|
untilDate = new Date(now.getTime() + 6 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "12h":
|
||||||
|
untilDate = new Date(now.getTime() + 12 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "24h":
|
||||||
|
untilDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "72h":
|
||||||
|
untilDate = new Date(now.getTime() + 72 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "1w":
|
||||||
|
untilDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "2w":
|
||||||
|
untilDate = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000);
|
||||||
|
break;
|
||||||
|
case "1m":
|
||||||
|
untilDate = new Date(now.setMonth(now.getMonth() + 1));
|
||||||
|
break;
|
||||||
|
case "3m":
|
||||||
|
untilDate = new Date(now.setMonth(now.getMonth() + 3));
|
||||||
|
break;
|
||||||
|
case "6m":
|
||||||
|
untilDate = new Date(now.setMonth(now.getMonth() + 6));
|
||||||
|
break;
|
||||||
|
case "1y":
|
||||||
|
untilDate = new Date(now.setFullYear(now.getFullYear() + 1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
untilDate = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClick({ reason, until: untilDate });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Icon}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -33,13 +33,24 @@ import { UserOptionalDefaults, UserOptionalDefaultsSchema } from "@repo/db/zod";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
|
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
|
||||||
import { cn } from "../../../../../../helper/cn";
|
import { cn } from "../../../../../../helper/cn";
|
||||||
import { ChartBarBigIcon, Check, Eye, PlaneIcon, Timer, X } from "lucide-react";
|
import {
|
||||||
|
ChartBarBigIcon,
|
||||||
|
Check,
|
||||||
|
Eye,
|
||||||
|
LockKeyhole,
|
||||||
|
PlaneIcon,
|
||||||
|
RedoDot,
|
||||||
|
Timer,
|
||||||
|
X,
|
||||||
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { Error } from "_components/Error";
|
import { Error } from "_components/Error";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { setStandardName } from "../../../../../../helper/discord";
|
import { setStandardName } from "../../../../../../helper/discord";
|
||||||
import { penaltyColumns } from "(app)/admin/penalty/page";
|
import { penaltyColumns } from "(app)/admin/penalty/page";
|
||||||
|
import { PenaltyDropdown } from "(app)/admin/user/[id]/_components/AddPenaltyDropdown";
|
||||||
|
import { addPenalty } from "(app)/admin/penalty/actions";
|
||||||
|
|
||||||
interface ProfileFormProps {
|
interface ProfileFormProps {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -304,12 +315,60 @@ export const ConnectionHistory: React.FC<{ user: User }> = ({ user }: { user: Us
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const UserPenalties = ({ user }: { user: User }) => {
|
export const UserPenalties = ({ user }: { user: User }) => {
|
||||||
|
const createdUser = useSession().data?.user;
|
||||||
|
const penaltyTable = useRef<PaginatedTableRef>(null);
|
||||||
return (
|
return (
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title">
|
<h2 className="card-title flex justify-between">
|
||||||
<ExclamationTriangleIcon className="w-5 h-5" /> Nutzer Strafen
|
<span className="flex items-center gap-2">
|
||||||
|
<ExclamationTriangleIcon className="w-5 h-5" /> Audit-log
|
||||||
|
</span>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<PenaltyDropdown
|
||||||
|
Icon={<RedoDot size={15} />}
|
||||||
|
onClick={async ({ reason, until }) => {
|
||||||
|
if (!reason) return toast.error("Bitte gib einen Grund für die Strafe an.");
|
||||||
|
if (!until) return toast.error("Bitte gib eine Dauer für die Strafe ein.");
|
||||||
|
if (!createdUser)
|
||||||
|
return toast.error("Du musst eingeloggt sein, um eine Strafe zu erstellen.");
|
||||||
|
await addPenalty({
|
||||||
|
reason,
|
||||||
|
until,
|
||||||
|
type: "TIME_BAN",
|
||||||
|
userId: user.id,
|
||||||
|
createdUserId: createdUser.id,
|
||||||
|
});
|
||||||
|
penaltyTable.current?.refresh();
|
||||||
|
toast.success("Time-Ban wurde hinzugefügt!");
|
||||||
|
}}
|
||||||
|
btnClassName="btn btn-outline btn-warning tooltip-warning"
|
||||||
|
btnTip="Timeban hinzufügen"
|
||||||
|
showDatePicker={true}
|
||||||
|
/>
|
||||||
|
<PenaltyDropdown
|
||||||
|
Icon={<LockKeyhole size={15} />}
|
||||||
|
onClick={async ({ reason }) => {
|
||||||
|
if (!reason) return toast.error("Bitte gib einen Grund für die Strafe an.");
|
||||||
|
if (!createdUser)
|
||||||
|
return toast.error("Du musst eingeloggt sein, um eine Strafe zu erstellen.");
|
||||||
|
await addPenalty({
|
||||||
|
reason,
|
||||||
|
type: "BAN",
|
||||||
|
userId: user.id,
|
||||||
|
createdUserId: createdUser.id,
|
||||||
|
});
|
||||||
|
await editUser(user.id, { isBanned: true, permissions: [] });
|
||||||
|
penaltyTable.current?.refresh();
|
||||||
|
toast.success("Ban wurde hinzugefügt!");
|
||||||
|
}}
|
||||||
|
btnClassName="btn btn-outline btn-error tooltip-error"
|
||||||
|
btnTip="Rechte-entzug hinzufügen"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
|
initialOrderBy={[{ id: "timestamp", desc: true }]}
|
||||||
|
ref={penaltyTable}
|
||||||
prismaModel="penalty"
|
prismaModel="penalty"
|
||||||
include={{
|
include={{
|
||||||
CreatedUser: true,
|
CreatedUser: true,
|
||||||
@@ -443,24 +502,6 @@ export const AdminForm = ({
|
|||||||
>
|
>
|
||||||
<LockOpen1Icon /> Passwort zurücksetzen
|
<LockOpen1Icon /> Passwort zurücksetzen
|
||||||
</Button>
|
</Button>
|
||||||
{!user.isBanned && (
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
await editUser(user.id, { isBanned: true });
|
|
||||||
toast.success("Nutzer wurde gesperrt!", {
|
|
||||||
style: {
|
|
||||||
background: "var(--color-base-100)",
|
|
||||||
color: "var(--color-base-content)",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
router.refresh();
|
|
||||||
}}
|
|
||||||
role="submit"
|
|
||||||
className="btn-sm flex-1 min-w-[250px] btn-outline btn-error"
|
|
||||||
>
|
|
||||||
<HobbyKnifeIcon /> HUB zugang sperren
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{user.isBanned && (
|
{user.isBanned && (
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|||||||
@@ -21,5 +21,6 @@ model Penalty {
|
|||||||
enum PenaltyType {
|
enum PenaltyType {
|
||||||
KICK
|
KICK
|
||||||
TIME_BAN
|
TIME_BAN
|
||||||
|
PERMISSIONS_REVOCED
|
||||||
BAN
|
BAN
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user