Create initial new infraction endpoint
This commit is contained in:
parent
58822f8ea1
commit
98f00d5a4c
139
functions/api/infractions/new.ts
Normal file
139
functions/api/infractions/new.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { GenerateUploadURL } from "../../gcloud.js";
|
||||
|
||||
const allowedFileTypes = [
|
||||
"image/gif",
|
||||
"image/heic",
|
||||
"image/heif",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"video/mp4",
|
||||
"video/webm",
|
||||
];
|
||||
|
||||
export async function onRequestPost(context: RequestContext) {
|
||||
if (
|
||||
!context.data.current_user?.permissions ||
|
||||
![1 << 0, 1 << 2, 1 << 11].find(
|
||||
(p) => context.data.current_user.permissions & p
|
||||
)
|
||||
)
|
||||
return new Response('{"error":"Forbidden"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 403,
|
||||
});
|
||||
|
||||
if (
|
||||
context.request.headers
|
||||
.get("content-type")
|
||||
?.startsWith("multipart/form-data; boundary=")
|
||||
)
|
||||
return new Response('{"error":"Invalid content type"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
|
||||
let body: FormData;
|
||||
|
||||
try {
|
||||
body = await context.request.formData();
|
||||
} catch {
|
||||
return new Response('{"error":"Invalid form data"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
![
|
||||
"verbal",
|
||||
"warn",
|
||||
"mute",
|
||||
"ban_temp",
|
||||
"ban_perm",
|
||||
"ban_unappealable",
|
||||
].includes(body.get("punishment") as string)
|
||||
)
|
||||
return new Response('{"error":"Invalid punishment"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
|
||||
if (!(body.get("user") as string).match(/^\d{17,19}$/))
|
||||
return new Response('{"error":"Invalid user"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
|
||||
// @ts-expect-error
|
||||
const files: File[] = body.keys().find((key) => key.match(/^files\[\d]$/));
|
||||
const urlPromises = [];
|
||||
|
||||
for (const file of files) {
|
||||
if (!allowedFileTypes.includes(file.type))
|
||||
return new Response(`{"error":"File ${file.name} is not valid"}`, {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 415,
|
||||
});
|
||||
|
||||
const attachmentKey = `${Date.now()}${Math.round(
|
||||
Math.random() * 10000000
|
||||
).toString()}/${file.name}`;
|
||||
|
||||
urlPromises.push(
|
||||
GenerateUploadURL(
|
||||
context.env,
|
||||
attachmentKey,
|
||||
file.size,
|
||||
(allowedFileTypes.find((t) => t === file.type) as string).split("/")[1]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const settledURLPromises = await Promise.allSettled(urlPromises);
|
||||
|
||||
if (settledURLPromises.find((p) => p.status === "rejected"))
|
||||
return new Response('{"error":"Failed to process one or more files"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 500,
|
||||
});
|
||||
|
||||
const infractionId = `${body.get("user")}${Date.now()}${
|
||||
context.request.headers.get("cf-ray")?.split("-")[0]
|
||||
}`;
|
||||
const uploadReqs = [];
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
uploadReqs.push(
|
||||
fetch(settledURLPromises[i] as unknown as string, {
|
||||
body: files[i],
|
||||
method: "PUT",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
await context.env.DATA.put(
|
||||
infractionId,
|
||||
JSON.stringify({
|
||||
created_at: Date.now(),
|
||||
moderator: context.data.current_user.id,
|
||||
})
|
||||
);
|
||||
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user