Compare commits
15 Commits
cae1b523f5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
017ce48835
|
|||
|
72f8791276
|
|||
|
63b1926056
|
|||
|
25dc50e05c
|
|||
|
a403832735
|
|||
|
e1f1093d84
|
|||
|
243a4d1ceb
|
|||
|
54d9bd5e82
|
|||
|
a1f4b4eabe
|
|||
|
64edc6169b
|
|||
|
cf84722418
|
|||
|
102b29c54f
|
|||
|
42f13612b1
|
|||
|
b1448ac30e
|
|||
|
bd053908a4
|
@@ -1 +1 @@
|
|||||||
v22.19.0
|
v22.20.0
|
||||||
|
|||||||
209
app/routes/gmm.tsx
Normal file
209
app/routes/gmm.tsx
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
|
Table,
|
||||||
|
TableCaption,
|
||||||
|
TableContainer,
|
||||||
|
Tbody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
Thead,
|
||||||
|
Tr,
|
||||||
|
useDisclosure,
|
||||||
|
useToast,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useLoaderData } from "@remix-run/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export async function loader({ context }: { context: RequestContext }) {
|
||||||
|
if (!context.data.current_user)
|
||||||
|
throw new Response(null, {
|
||||||
|
status: 401,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
![
|
||||||
|
"165594923586945025",
|
||||||
|
"289372404541554689",
|
||||||
|
"396347223736057866",
|
||||||
|
].includes(context.data.current_user.id)
|
||||||
|
)
|
||||||
|
throw new Response(null, {
|
||||||
|
status: 403,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (await context.env.DATA.list({ prefix: "gamemod_" }))?.keys ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const data: { [k: string]: any }[] = useLoaderData<typeof loader>();
|
||||||
|
const [gameModData, setGameModData] = useState(data);
|
||||||
|
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||||
|
const [idToAdd, setIdToAdd] = useState<string>("");
|
||||||
|
const [nameToAdd, setNameToAdd] = useState<string>("");
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
async function addMod(id: string, name: string) {
|
||||||
|
const response = await fetch("/api/gme/add", {
|
||||||
|
body: JSON.stringify({ name, user: id }),
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
let msg = "Unknown error";
|
||||||
|
|
||||||
|
try {
|
||||||
|
msg = ((await response.json()) as { error: string }).error;
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
toast({
|
||||||
|
description: msg,
|
||||||
|
status: "error",
|
||||||
|
title: "Cannot add game mod",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onClose();
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
setIdToAdd("");
|
||||||
|
setNameToAdd("");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeMod(user: string) {
|
||||||
|
const response = await fetch("/api/gme/remove", {
|
||||||
|
body: JSON.stringify({ user }),
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
let msg = "Unknown error";
|
||||||
|
|
||||||
|
try {
|
||||||
|
msg = ((await response.json()) as { error: string }).error;
|
||||||
|
} catch {}
|
||||||
|
toast({
|
||||||
|
description: msg,
|
||||||
|
status: "error",
|
||||||
|
title: "Cannot remove game mod",
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast({
|
||||||
|
description: `${data.find((i) => i.metadata.id === user)?.name} was removed as a game mod`,
|
||||||
|
status: "success",
|
||||||
|
title: "Game mod removed",
|
||||||
|
});
|
||||||
|
|
||||||
|
setGameModData(gameModData.filter((i) => i.metadata.id !== user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container maxW="container.lg">
|
||||||
|
<TableContainer>
|
||||||
|
<Table variant="simple">
|
||||||
|
<TableCaption>Currently active game mods</TableCaption>
|
||||||
|
<Thead>
|
||||||
|
<Tr>
|
||||||
|
<Th>ID</Th>
|
||||||
|
<Th>Name</Th>
|
||||||
|
<Th>Added At</Th>
|
||||||
|
<Th>Added By</Th>
|
||||||
|
<Th>Remove</Th>
|
||||||
|
</Tr>
|
||||||
|
</Thead>
|
||||||
|
<Tbody>
|
||||||
|
{gameModData.map((item) => {
|
||||||
|
return (
|
||||||
|
<Tr key={item.metadata.id}>
|
||||||
|
<Td>{item.metadata.id}</Td>
|
||||||
|
<Td>{item.metadata.name}</Td>
|
||||||
|
<Td>{item.metadata.created_at}</Td>
|
||||||
|
<Td>{item.metadata.created_by}</Td>
|
||||||
|
<Td>
|
||||||
|
<Button
|
||||||
|
onClick={async () => await removeMod(item.metadata.id)}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Tbody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
<Button alignSelf="end" mt="16px" onClick={onOpen}>
|
||||||
|
Add
|
||||||
|
</Button>
|
||||||
|
<Modal isOpen={isOpen} onClose={onClose}>
|
||||||
|
<ModalOverlay />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader>Add Game Mod</ModalHeader>
|
||||||
|
<ModalCloseButton />
|
||||||
|
<ModalBody>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Name</FormLabel>
|
||||||
|
<Input
|
||||||
|
maxLength={32}
|
||||||
|
onChange={(e) => setNameToAdd(e.target.value)}
|
||||||
|
value={nameToAdd}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<br />
|
||||||
|
<FormControl pt="16px">
|
||||||
|
<FormLabel>ID</FormLabel>
|
||||||
|
<Input
|
||||||
|
maxLength={19}
|
||||||
|
onChange={(e) => setIdToAdd(e.target.value)}
|
||||||
|
value={idToAdd}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter gap="8px">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
onClose();
|
||||||
|
setIdToAdd("");
|
||||||
|
setNameToAdd("");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
colorScheme="blue"
|
||||||
|
disabled={
|
||||||
|
!idToAdd.match(/\d{17,19}/) ||
|
||||||
|
nameToAdd.length < 1 ||
|
||||||
|
nameToAdd.length > 32
|
||||||
|
}
|
||||||
|
onClick={async () => {
|
||||||
|
await addMod(idToAdd, nameToAdd);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -169,20 +169,22 @@ export default function () {
|
|||||||
Decisions:
|
Decisions:
|
||||||
<br />
|
<br />
|
||||||
Approved:
|
Approved:
|
||||||
{Object.keys(currentInactivity.decisions ?? {}).filter(
|
{Object.keys(currentInactivity.decisions ?? {})
|
||||||
(d) => currentInactivity.decisions[d],
|
.filter((d) => currentInactivity.decisions[d])
|
||||||
)}
|
.join(", ")}
|
||||||
<br />
|
<br />
|
||||||
Denied:
|
Denied:
|
||||||
{Object.keys(currentInactivity.decisions ?? {}).filter(
|
{Object.keys(currentInactivity.decisions ?? {})
|
||||||
(d) => !currentInactivity.decisions[d],
|
.filter((d) => !currentInactivity.decisions[d])
|
||||||
)}
|
.join(", ")}
|
||||||
<br />
|
<br />
|
||||||
Pending:
|
Pending:
|
||||||
{currentInactivity.departments?.filter(
|
{currentInactivity.departments
|
||||||
(d: "DM" | "ET" | "FM" | "WM") =>
|
?.filter(
|
||||||
typeof currentInactivity.decisions[d] === "undefined",
|
(d: "DM" | "ET" | "FM" | "WM") =>
|
||||||
)}
|
typeof currentInactivity.decisions[d] === "undefined",
|
||||||
|
)
|
||||||
|
.join(", ")}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</UnorderedList>
|
</UnorderedList>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import { useLoaderData } from "@remix-run/react";
|
|||||||
import AppealBans from "../../components/AppealBans.js";
|
import AppealBans from "../../components/AppealBans.js";
|
||||||
import AppealCard from "../../components/AppealCard.js";
|
import AppealCard from "../../components/AppealCard.js";
|
||||||
import GameAppealCard from "../../components/GameAppealCard.js";
|
import GameAppealCard from "../../components/GameAppealCard.js";
|
||||||
import GameModManagementModal from "../../components/GameModManagementModal.js";
|
|
||||||
import NewGameBan from "../../components/NewGameBan.js";
|
import NewGameBan from "../../components/NewGameBan.js";
|
||||||
import NewInfractionModal from "../../components/NewInfractionModal.js";
|
import NewInfractionModal from "../../components/NewInfractionModal.js";
|
||||||
import ReportCard from "../../components/ReportCard.js";
|
import ReportCard from "../../components/ReportCard.js";
|
||||||
@@ -151,7 +150,7 @@ export default function () {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messageChannel.current) {
|
if (messageChannel.current) {
|
||||||
messageChannel.current.port1.onmessage = function (ev) {
|
messageChannel.current.port1.onmessage = function (ev: any) {
|
||||||
const { data }: { data: string } = ev;
|
const { data }: { data: string } = ev;
|
||||||
|
|
||||||
setEntries([...entries].filter((entry) => entry.id !== data));
|
setEntries([...entries].filter((entry) => entry.id !== data));
|
||||||
@@ -337,7 +336,11 @@ export default function () {
|
|||||||
},
|
},
|
||||||
appeal_bans: useDisclosure(),
|
appeal_bans: useDisclosure(),
|
||||||
game_ban: useDisclosure(),
|
game_ban: useDisclosure(),
|
||||||
gme: useDisclosure(),
|
gme: {
|
||||||
|
isOpen: false,
|
||||||
|
onClose: () => {},
|
||||||
|
onOpen: () => location.assign("/gmm"),
|
||||||
|
},
|
||||||
inactivity: useDisclosure(),
|
inactivity: useDisclosure(),
|
||||||
infraction: useDisclosure(),
|
infraction: useDisclosure(),
|
||||||
user_lookup: {
|
user_lookup: {
|
||||||
@@ -431,10 +434,6 @@ export default function () {
|
|||||||
isOpen={itemModals.appeal_bans.isOpen}
|
isOpen={itemModals.appeal_bans.isOpen}
|
||||||
onClose={itemModals.appeal_bans.onClose}
|
onClose={itemModals.appeal_bans.onClose}
|
||||||
/>
|
/>
|
||||||
<GameModManagementModal
|
|
||||||
isOpen={itemModals.gme.isOpen}
|
|
||||||
onClose={itemModals.gme.onClose}
|
|
||||||
/>
|
|
||||||
<NewGameBan
|
<NewGameBan
|
||||||
isOpen={itemModals.game_ban.isOpen}
|
isOpen={itemModals.game_ban.isOpen}
|
||||||
onClose={itemModals.game_ban.onClose}
|
onClose={itemModals.game_ban.onClose}
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
import {
|
|
||||||
Button,
|
|
||||||
HStack,
|
|
||||||
Input,
|
|
||||||
Link,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Table,
|
|
||||||
TableContainer,
|
|
||||||
Tbody,
|
|
||||||
Td,
|
|
||||||
Th,
|
|
||||||
Thead,
|
|
||||||
Tr,
|
|
||||||
useToast,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
export default function (props: { isOpen: boolean; onClose: () => void }) {
|
|
||||||
const [mods, setMods] = useState([]);
|
|
||||||
const [userToAdd, setUserToAdd] = useState("");
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!props.isOpen) return;
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
const gmeResp = await fetch("/api/gme/list");
|
|
||||||
|
|
||||||
if (!gmeResp.ok) {
|
|
||||||
toast({
|
|
||||||
description: "Failed to load GME data",
|
|
||||||
status: "error",
|
|
||||||
title: "Oops",
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMods(await gmeResp.json());
|
|
||||||
})();
|
|
||||||
}, [props.isOpen]);
|
|
||||||
|
|
||||||
async function addUser() {
|
|
||||||
if (!userToAdd || !userToAdd.match(/^\d{17,19}$/)) {
|
|
||||||
toast({
|
|
||||||
description: "Please check your input and try again",
|
|
||||||
status: "error",
|
|
||||||
title: "Invalid user",
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addResp = await fetch("/api/gme/add", {
|
|
||||||
body: JSON.stringify({ user: userToAdd }),
|
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!addResp.ok) {
|
|
||||||
toast({
|
|
||||||
description: ((await addResp.json()) as { error: string }).error,
|
|
||||||
status: "error",
|
|
||||||
title: "Oops",
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
|
||||||
description: `User ${userToAdd} added`,
|
|
||||||
status: "success",
|
|
||||||
title: "Success",
|
|
||||||
});
|
|
||||||
|
|
||||||
props.onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeUser(user: string) {
|
|
||||||
const removeResp = await fetch("/api/gme/remove", {
|
|
||||||
body: JSON.stringify({ user }),
|
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!removeResp.ok) {
|
|
||||||
toast({
|
|
||||||
description: ((await removeResp.json()) as { error: string }).error,
|
|
||||||
status: "error",
|
|
||||||
title: "Oops",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
description: `User ${user} removed`,
|
|
||||||
status: "success",
|
|
||||||
title: "Success",
|
|
||||||
});
|
|
||||||
|
|
||||||
setMods(mods.filter((mod: any) => mod.user !== user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal isCentered isOpen={props.isOpen} onClose={props.onClose}>
|
|
||||||
<ModalOverlay />
|
|
||||||
<ModalContent>
|
|
||||||
<ModalHeader>Game Moderators</ModalHeader>
|
|
||||||
<ModalCloseButton />
|
|
||||||
<ModalBody>
|
|
||||||
<TableContainer>
|
|
||||||
<Table variant="simple">
|
|
||||||
<Thead>
|
|
||||||
<Tr>
|
|
||||||
<Th>User</Th>
|
|
||||||
<Th>Added At</Th>
|
|
||||||
<Th>Added By</Th>
|
|
||||||
<Th>Remove</Th>
|
|
||||||
</Tr>
|
|
||||||
</Thead>
|
|
||||||
<Tbody>
|
|
||||||
{mods.map((mod: any) => (
|
|
||||||
<Tr>
|
|
||||||
<Td>{mod.user}</Td>
|
|
||||||
<Td>{new Date(mod.metadata.time).toLocaleString()}</Td>
|
|
||||||
<Td>{mod.metadata.user}</Td>
|
|
||||||
<Td>
|
|
||||||
<Link onClick={async () => await removeUser(mod.user)}>
|
|
||||||
Remove
|
|
||||||
</Link>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
))}
|
|
||||||
</Tbody>
|
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
<HStack mt="8px">
|
|
||||||
<Input
|
|
||||||
maxLength={19}
|
|
||||||
onChange={(e) => setUserToAdd(e.target.value)}
|
|
||||||
placeholder="1234567890987654321"
|
|
||||||
/>
|
|
||||||
<Button onClick={async () => await addUser()}>Add</Button>
|
|
||||||
</HStack>
|
|
||||||
</ModalBody>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
39
functions/api/game-bans/notes/[id].ts
Normal file
39
functions/api/game-bans/notes/[id].ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { jsonError, jsonResponse } from "../../../common.js";
|
||||||
|
|
||||||
|
export async function onRequestDelete(context: RequestContext) {
|
||||||
|
const noteId = context.params.id as string;
|
||||||
|
const creatorIdResult: null | Record<string, string> =
|
||||||
|
await context.env.D1.prepare(
|
||||||
|
"SELECT created_by FROM game_mod_logs WHERE id = ?;",
|
||||||
|
)
|
||||||
|
.bind(noteId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (creatorIdResult?.created_by !== context.data.current_user.id)
|
||||||
|
return jsonError("Cannot delete notes that are not your own", 403);
|
||||||
|
|
||||||
|
await context.env.D1.prepare("DELETE FROM game_mod_logs WHERE id = ?;")
|
||||||
|
.bind(noteId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
return new Response(null, { status: 204 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function onRequestGet(context: RequestContext) {
|
||||||
|
const noteId = context.params.id as string;
|
||||||
|
const result = await context.env.D1.prepare(
|
||||||
|
"SELECT * FROM game_mod_notes WHERE id = ?;",
|
||||||
|
)
|
||||||
|
.bind(noteId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!result) return jsonError("Note not found", 404);
|
||||||
|
|
||||||
|
const noteData = structuredClone(result);
|
||||||
|
const gmeEntry: null | { time: number; user: string; name: string } =
|
||||||
|
await context.env.DATA.get(`gamemod_${result.created_by}`, "json");
|
||||||
|
|
||||||
|
if (gmeEntry) noteData.creator_name = gmeEntry.name;
|
||||||
|
|
||||||
|
return jsonResponse(JSON.stringify(noteData));
|
||||||
|
}
|
||||||
8
functions/api/game-bans/notes/_middleware.ts
Normal file
8
functions/api/game-bans/notes/_middleware.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { jsonError } from "../../../common.js";
|
||||||
|
|
||||||
|
export async function onRequest(context: RequestContext) {
|
||||||
|
if (!(context.data.current_user?.permissions & (1 << 5)))
|
||||||
|
return jsonError("Forbidden", 403);
|
||||||
|
|
||||||
|
return await context.next();
|
||||||
|
}
|
||||||
23
functions/api/game-bans/notes/create.ts
Normal file
23
functions/api/game-bans/notes/create.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { jsonError } from "../../../common.js";
|
||||||
|
|
||||||
|
export async function onRequestPost(context: RequestContext) {
|
||||||
|
const { content, target } = context.data.body;
|
||||||
|
|
||||||
|
if (typeof content !== "string")
|
||||||
|
return jsonError("'content' property is not a string", 400);
|
||||||
|
|
||||||
|
if (typeof target !== "number" || !Number.isSafeInteger(target))
|
||||||
|
return jsonError("'target' property is not a valid number", 400);
|
||||||
|
|
||||||
|
if (content.length > 1000)
|
||||||
|
return jsonError(
|
||||||
|
"'content' property must be less than 1000 characters",
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
|
||||||
|
const id = `${Date.now()}${crypto.randomUUID().replaceAll("-", "")}`;
|
||||||
|
|
||||||
|
await context.env.D1.prepare(
|
||||||
|
"INSERT INTO game_mod_notes (content, created_at, created_by, id, target) VALUES (?, ?, ?, ?, ?);",
|
||||||
|
).bind(content, Date.now(), context.data.current_user.id, id, target).first();
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
import { jsonError } from "../../common.js";
|
import { jsonError } from "../../common.js";
|
||||||
|
|
||||||
export async function onRequestPost(context: RequestContext) {
|
export async function onRequestPost(context: RequestContext) {
|
||||||
const { user } = context.data.body;
|
const { user, name } = context.data.body;
|
||||||
|
|
||||||
if (!user) return jsonError("No user provided", 400);
|
if (!user) return jsonError("No user provided", 400);
|
||||||
|
|
||||||
|
if (typeof name !== "string" || name.length > 32)
|
||||||
|
return jsonError("Invalid name", 400);
|
||||||
|
|
||||||
const existingUser = await context.env.DATA.get(`gamemod_${user}`);
|
const existingUser = await context.env.DATA.get(`gamemod_${user}`);
|
||||||
|
|
||||||
if (existingUser) return jsonError("Cannot add an existing user", 400);
|
if (existingUser) return jsonError("Cannot add an existing user", 400);
|
||||||
@@ -20,7 +23,12 @@ export async function onRequestPost(context: RequestContext) {
|
|||||||
|
|
||||||
if (!user.match(/^\d{17,19}$/)) return jsonError("Invalid User ID", 400);
|
if (!user.match(/^\d{17,19}$/)) return jsonError("Invalid User ID", 400);
|
||||||
|
|
||||||
const data = { time: Date.now(), user: context.data.current_user.id };
|
const data = {
|
||||||
|
created_at: Date.now(),
|
||||||
|
created_by: context.data.current_user.id,
|
||||||
|
id: user,
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
|
||||||
await context.env.DATA.put(`gamemod_${user}`, JSON.stringify(data), {
|
await context.env.DATA.put(`gamemod_${user}`, JSON.stringify(data), {
|
||||||
metadata: data,
|
metadata: data,
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import { jsonResponse } from "../../common.js";
|
|
||||||
|
|
||||||
export async function onRequestGet(context: RequestContext) {
|
|
||||||
const list = await context.env.DATA.list({ prefix: "gamemod_" });
|
|
||||||
const entries = [];
|
|
||||||
|
|
||||||
for (const key of list.keys)
|
|
||||||
entries.push({
|
|
||||||
metadata: key.metadata,
|
|
||||||
user: key.name.replace("gamemod_", ""),
|
|
||||||
});
|
|
||||||
|
|
||||||
return jsonResponse(JSON.stringify(entries));
|
|
||||||
}
|
|
||||||
@@ -91,8 +91,10 @@ export async function onRequestPost(context: RequestContext) {
|
|||||||
requestedNotice.decisions,
|
requestedNotice.decisions,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const department of userAdminDepartments)
|
for (const department of userAdminDepartments) {
|
||||||
|
if (!JSON.parse(requestedNotice.departments).includes(department)) continue;
|
||||||
decisions[department] = accepted;
|
decisions[department] = accepted;
|
||||||
|
}
|
||||||
|
|
||||||
const applicableDepartments = JSON.parse(requestedNotice.departments).length;
|
const applicableDepartments = JSON.parse(requestedNotice.departments).length;
|
||||||
|
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ export async function onRequestPost(context: RequestContext) {
|
|||||||
|
|
||||||
// If not a ban action
|
// If not a ban action
|
||||||
if (v === 1) {
|
if (v === 1) {
|
||||||
newActions[user].hidden_from_leaderboards = true;
|
newActions[k].hidden_from_leaderboards = true;
|
||||||
} else if (v === 3) {
|
} else if (v === 3) {
|
||||||
newActions[user].serverconfigurator_blacklist = true;
|
newActions[k].serverconfigurator_blacklist = true;
|
||||||
newActions[user].BanType = 1;
|
newActions[k].BanType = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,9 +183,10 @@ export async function onRequestPost(context: RequestContext) {
|
|||||||
|
|
||||||
const uploadUrlResults = await Promise.allSettled(uploadUrlPromises);
|
const uploadUrlResults = await Promise.allSettled(uploadUrlPromises);
|
||||||
|
|
||||||
const reportId = `${Date.now()}${context.request.headers.get(
|
const reportId = `${Date.now()}${context.request.headers
|
||||||
"cf-ray",
|
.get("cf-ray")
|
||||||
)}${crypto.randomUUID().replaceAll("-", "")}`;
|
?.split("-")
|
||||||
|
?.at(0)}${crypto.randomUUID().replaceAll("-", "")}`;
|
||||||
|
|
||||||
const { current_user: currentUser } = context.data;
|
const { current_user: currentUser } = context.data;
|
||||||
if (filesToProcess.length)
|
if (filesToProcess.length)
|
||||||
|
|||||||
92
package-lock.json
generated
92
package-lock.json
generated
@@ -15,7 +15,7 @@
|
|||||||
"@remix-run/cloudflare": "^2.17.1",
|
"@remix-run/cloudflare": "^2.17.1",
|
||||||
"@remix-run/cloudflare-pages": "^2.17.1",
|
"@remix-run/cloudflare-pages": "^2.17.1",
|
||||||
"@remix-run/react": "^2.17.1",
|
"@remix-run/react": "^2.17.1",
|
||||||
"@sentry/react": "^10.19.0",
|
"@sentry/react": "^10.21.0",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"framer-motion": "^12.23.24",
|
"framer-motion": "^12.23.24",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@remix-run/dev": "^2.17.1",
|
"@remix-run/dev": "^2.17.1",
|
||||||
"@types/node": "^24.7.2",
|
"@types/node": "^24.9.1",
|
||||||
"@types/react": "^18.3.26",
|
"@types/react": "^18.3.26",
|
||||||
"@types/react-big-calendar": "^1.16.3",
|
"@types/react-big-calendar": "^1.16.3",
|
||||||
"@types/react-dom": "^18.3.7",
|
"@types/react-dom": "^18.3.7",
|
||||||
@@ -649,9 +649,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cloudflare/workers-types": {
|
"node_modules/@cloudflare/workers-types": {
|
||||||
"version": "4.20251011.0",
|
"version": "4.20251014.0",
|
||||||
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251011.0.tgz",
|
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251014.0.tgz",
|
||||||
"integrity": "sha512-gQpih+pbq3sP4uXltUeCSbPgZxTNp2gQd8639SaIbQMwgA6oJNHLhIART1fWy6DQACngiRzDVULA2x0ohmkGTQ==",
|
"integrity": "sha512-tEW98J/kOa0TdylIUOrLKRdwkUw0rvvYVlo+Ce0mqRH3c8kSoxLzUH9gfCvwLe0M89z1RkzFovSKAW2Nwtyn3w==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
@@ -2065,88 +2065,88 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/browser-utils": {
|
"node_modules/@sentry-internal/browser-utils": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.21.0.tgz",
|
||||||
"integrity": "sha512-E3H6R+tX7sYMIjfCRAMO0qIH43dtUqv2rSo0vv6eHDi4lDXtlDc+Vb67n4VIesT7YVxQD7GIkNhMk3hmRDIwww==",
|
"integrity": "sha512-QRHpCBheLd/88Z2m3ABMriV0MweW+pcGKuVsH61/UdziKcQLdoQpOSvGg0/0CuqFm2UjL7237ZzLdZrWaCOlfQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "10.19.0"
|
"@sentry/core": "10.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/feedback": {
|
"node_modules/@sentry-internal/feedback": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.21.0.tgz",
|
||||||
"integrity": "sha512-AJ8rpzNYgfmWzovmFss51q9FtBaa2qYTLwkbVdTf58fZbLMUrgZ6qf9qMk0ePiS3nB87w9+mpbLzRObYOsK9RA==",
|
"integrity": "sha512-6SnRR2FiW6TMwCE0PqbueHkkpeVnjOjz00R+/mX25Dp1U5BU5TzbXHzn9Y4wKnaD3Rzz4+nnzVkpHAOL3SppGw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "10.19.0"
|
"@sentry/core": "10.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/replay": {
|
"node_modules/@sentry-internal/replay": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.21.0.tgz",
|
||||||
"integrity": "sha512-bOWsm/t+d2LCYa3gUjgwFds6kKSW+K6i4pssgDY4XiV/MxHsQtQ2rbHX80chLRQe2HFCX2njvjVSJN+Nsdjmpg==",
|
"integrity": "sha512-5tfiKZJzZf9+Xk8SyvoC4ZEVLNmjBZZEaKhVyNo53CLWUWfWOqDc3DB9fj85i/yHFQ0ImdRnaPBc0CIeN00CcA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/browser-utils": "10.19.0",
|
"@sentry-internal/browser-utils": "10.21.0",
|
||||||
"@sentry/core": "10.19.0"
|
"@sentry/core": "10.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/replay-canvas": {
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.21.0.tgz",
|
||||||
"integrity": "sha512-DulLU4lvtrGPExKtpbCveLxPACrFmGx4eEYhzIn35UH8iIx6ONRSLemQyiUJQoLau7KXJy0I8AWxN+SagfebEA==",
|
"integrity": "sha512-TOLo5mAjJSOuJId8Po44d1hwJ5bIZDtRSoupWpYWqLw1tuUh1tc4vqID11ZXsw9pBzjVIK653BPDX/z/9+Um+Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/replay": "10.19.0",
|
"@sentry-internal/replay": "10.21.0",
|
||||||
"@sentry/core": "10.19.0"
|
"@sentry/core": "10.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/browser": {
|
"node_modules/@sentry/browser": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.21.0.tgz",
|
||||||
"integrity": "sha512-/+B84qFOLg1vJhg4YSA4a7Pneq5Pbt1BXEdrp/UW4tJmtGPZb28qXlMdoPfmFWZgVezrawaPkxLmbu+47/+rsQ==",
|
"integrity": "sha512-z/63bUFBQkTfJ5ElhWTYvomz+gZ1GsoH16v4/RGoPY5qZgYxcVO3fkp0opnu3gcbXS0ZW7TLRiHpqhvipDdP6g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/browser-utils": "10.19.0",
|
"@sentry-internal/browser-utils": "10.21.0",
|
||||||
"@sentry-internal/feedback": "10.19.0",
|
"@sentry-internal/feedback": "10.21.0",
|
||||||
"@sentry-internal/replay": "10.19.0",
|
"@sentry-internal/replay": "10.21.0",
|
||||||
"@sentry-internal/replay-canvas": "10.19.0",
|
"@sentry-internal/replay-canvas": "10.21.0",
|
||||||
"@sentry/core": "10.19.0"
|
"@sentry/core": "10.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/core": {
|
"node_modules/@sentry/core": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.21.0.tgz",
|
||||||
"integrity": "sha512-OqZjYDYsK6ZmBG5UzML0uKiKq//G6mMwPcszfuCsFgPt+pg5giUCrCUbt5VIVkHdN1qEEBk321JO2haU5n2Eig==",
|
"integrity": "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/react": {
|
"node_modules/@sentry/react": {
|
||||||
"version": "10.19.0",
|
"version": "10.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.21.0.tgz",
|
||||||
"integrity": "sha512-LgADcXfJ4hVVtOSW6IkY3Wsefw4xPHIQpiEux28GHf2EAYkWxyCWWb9uQH4voAacG+FcX63XfJkpUMZjadE9qw==",
|
"integrity": "sha512-BSCGKkepg9QPJRS8AUjtSAFd4lYJLmz3+P+oehViEHQDtRqqmXbVIBLhqwPc05KvRGIl4/kIDjyfDuHCFCJigQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/browser": "10.19.0",
|
"@sentry/browser": "10.21.0",
|
||||||
"@sentry/core": "10.19.0",
|
"@sentry/core": "10.21.0",
|
||||||
"hoist-non-react-statics": "^3.3.2"
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2256,13 +2256,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.7.2",
|
"version": "24.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
|
||||||
"integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
|
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.14.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
@@ -8918,9 +8918,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.14.0",
|
"version": "7.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||||
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
|
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"@remix-run/cloudflare": "^2.17.1",
|
"@remix-run/cloudflare": "^2.17.1",
|
||||||
"@remix-run/cloudflare-pages": "^2.17.1",
|
"@remix-run/cloudflare-pages": "^2.17.1",
|
||||||
"@remix-run/react": "^2.17.1",
|
"@remix-run/react": "^2.17.1",
|
||||||
"@sentry/react": "^10.19.0",
|
"@sentry/react": "^10.21.0",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"framer-motion": "^12.23.24",
|
"framer-motion": "^12.23.24",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@remix-run/dev": "^2.17.1",
|
"@remix-run/dev": "^2.17.1",
|
||||||
"@types/node": "^24.7.2",
|
"@types/node": "^24.9.1",
|
||||||
"@types/react": "^18.3.26",
|
"@types/react": "^18.3.26",
|
||||||
"@types/react-big-calendar": "^1.16.3",
|
"@types/react-big-calendar": "^1.16.3",
|
||||||
"@types/react-dom": "^18.3.7",
|
"@types/react-dom": "^18.3.7",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@cloudflare/workers-types": "^4.20251011.0"
|
"@cloudflare/workers-types": "^4.20251014.0"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"endOfLine": "auto"
|
"endOfLine": "auto"
|
||||||
|
|||||||
Reference in New Issue
Block a user