Initial commit
This commit is contained in:
54
functions/api/reports/complete.ts
Normal file
54
functions/api/reports/complete.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export async function onRequestPost(context: RequestContext) {
|
||||
const { id } = context.data.body;
|
||||
|
||||
if (!id)
|
||||
return new Response('{"error":"No ID provided"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
|
||||
const userId = await context.env.DATA.get(`reportprocessing_${id}`);
|
||||
|
||||
if (!userId || userId !== context.data.current_user.id)
|
||||
return new Response('{"error":"No report with that ID is processing"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 404,
|
||||
});
|
||||
|
||||
await context.env.DATA.delete(`reportprocessing_${id}`);
|
||||
|
||||
const {
|
||||
metadata,
|
||||
value,
|
||||
}: KVNamespaceGetWithMetadataResult<string, { [k: string]: any }> =
|
||||
await context.env.DATA.getWithMetadata(`report_${id}`);
|
||||
|
||||
delete metadata?.p;
|
||||
await context.env.DATA.put(`report_${id}`, value as string, { metadata });
|
||||
|
||||
if (context.env.REPORTS_WEBHOOK) {
|
||||
await fetch(context.env.REPORTS_WEBHOOK, {
|
||||
body: JSON.stringify({
|
||||
embeds: [
|
||||
{
|
||||
title: "Report Submitted",
|
||||
color: 3756250,
|
||||
description: `View this report at https://carcrushers.cc/mod-queue?id=${id}&type=game-report`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
});
|
||||
}
|
27
functions/api/reports/recall.ts
Normal file
27
functions/api/reports/recall.ts
Normal file
@ -0,0 +1,27 @@
|
||||
export async function onRequestPost(context: RequestContext) {
|
||||
const { id } = context.data.body;
|
||||
|
||||
if (!id)
|
||||
return new Response('{"error":"No ID provided"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
|
||||
const reportUserId = await context.env.DATA.get(`reportprocessing_${id}`);
|
||||
|
||||
if (!reportUserId || context.data.current_user.id !== reportUserId)
|
||||
return new Response('{"error":"No processing report with that ID found"}', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status: 404,
|
||||
});
|
||||
|
||||
await context.env.DATA.delete(`report_${id}`);
|
||||
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
});
|
||||
}
|
154
functions/api/reports/submit.ts
Normal file
154
functions/api/reports/submit.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import { GenerateUploadURL } from "../../gcloud";
|
||||
|
||||
function errorResponse(error: string, status: number): Response {
|
||||
return new Response(JSON.stringify({ error }), {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
status,
|
||||
});
|
||||
}
|
||||
|
||||
export async function onRequestPost(context: RequestContext) {
|
||||
const { filename, filesize, usernames } = context.data.body;
|
||||
|
||||
if (!Array.isArray(usernames))
|
||||
return errorResponse("Usernames must be type of array", 400);
|
||||
|
||||
if (typeof filename !== "string")
|
||||
return errorResponse("Invalid file name", 400);
|
||||
|
||||
if (typeof filesize !== "number" || filesize < 0 || filesize > 536870912)
|
||||
return errorResponse("Invalid file size", 400);
|
||||
|
||||
if (!usernames.length || usernames.length > 20)
|
||||
return errorResponse(
|
||||
"Number of usernames provided must be between 1 and 20",
|
||||
400
|
||||
);
|
||||
|
||||
for (const username of usernames) {
|
||||
if (
|
||||
username.length < 3 ||
|
||||
username.length > 20 ||
|
||||
username.match(/_/g)?.length > 1
|
||||
)
|
||||
return errorResponse(`Username "${username}" is invalid`, 400);
|
||||
}
|
||||
|
||||
const rbxSearchReq = await fetch(
|
||||
"https://users.roblox.com/v1/usernames/users",
|
||||
{
|
||||
body: JSON.stringify({
|
||||
usernames,
|
||||
excludeBannedUsers: true,
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
}
|
||||
);
|
||||
|
||||
if (!rbxSearchReq.ok)
|
||||
return errorResponse(
|
||||
"Failed to locate Roblox users due to upstream error",
|
||||
500
|
||||
);
|
||||
|
||||
const rbxSearchData: { data: { [k: string]: any }[] } =
|
||||
await rbxSearchReq.json();
|
||||
|
||||
if (rbxSearchData.data.length < usernames.length) {
|
||||
const missingUsers = [];
|
||||
|
||||
for (const userData of rbxSearchData.data) {
|
||||
if (!usernames.includes(userData.requestedUsername))
|
||||
missingUsers.push(userData.requestedUsername);
|
||||
}
|
||||
|
||||
return errorResponse(
|
||||
`The following users do not exist or are banned from Roblox: ${missingUsers.toString()}`,
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
const metaIDs = [];
|
||||
const metaNames = [];
|
||||
|
||||
for (const data of rbxSearchData.data) {
|
||||
metaIDs.push(data.id);
|
||||
metaNames.push(data.name);
|
||||
}
|
||||
|
||||
const fileParts = filename.split(".");
|
||||
let fileExt = fileParts[fileParts.length - 1];
|
||||
|
||||
if (
|
||||
fileParts.length < 2 ||
|
||||
![
|
||||
"mkv",
|
||||
"mp4",
|
||||
"wmv",
|
||||
"jpg",
|
||||
"png",
|
||||
"m4v",
|
||||
"jpeg",
|
||||
"jfif",
|
||||
"gif",
|
||||
"webm",
|
||||
"heif",
|
||||
"heic",
|
||||
"webp",
|
||||
"mov",
|
||||
].includes(fileExt.toLowerCase())
|
||||
)
|
||||
return errorResponse("This type of file cannot be uploaded", 415);
|
||||
|
||||
const fileKey = `${crypto.randomUUID().replaceAll("-", "")}/${crypto
|
||||
.randomUUID()
|
||||
.replaceAll("-", "")}${context.request.headers.get("cf-ray")}${Date.now()}`;
|
||||
|
||||
const reportId = `${Date.now()}${context.request.headers.get(
|
||||
"cf-ray"
|
||||
)}${crypto.randomUUID().replaceAll("-", "")}`;
|
||||
|
||||
const uploadUrl = await GenerateUploadURL(
|
||||
context.env,
|
||||
fileKey,
|
||||
filesize,
|
||||
fileExt
|
||||
);
|
||||
|
||||
await context.env.DATA.put(
|
||||
`reportprocessing_${reportId}`,
|
||||
context.data.current_user.id,
|
||||
{ expirationTtl: 3600 }
|
||||
);
|
||||
await context.env.DATA.put(
|
||||
`report_${reportId}`,
|
||||
JSON.stringify({
|
||||
attachment: `${fileKey}.${
|
||||
["mkv", "mov", "wmv"].includes(fileExt.toLowerCase()) ? "mp4" : fileExt
|
||||
}`,
|
||||
reporter: context.data.current_user,
|
||||
target_ids: metaIDs,
|
||||
target_usernames: metaNames,
|
||||
}),
|
||||
{
|
||||
metadata: {
|
||||
i: context.data.current_user.id,
|
||||
r: metaIDs.toString(),
|
||||
p: true,
|
||||
s: `${context.data.current_user.username}#${context.data.current_user.discriminator}`,
|
||||
u: metaNames.toString(),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return new Response(JSON.stringify({ id: reportId, upload_url: uploadUrl }), {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user