Compare commits

...

4 commits

8 changed files with 37 additions and 22 deletions

View file

@ -6,6 +6,9 @@ REDIS_URL="redis://localhost:6379/0"
# Used for metadata, sitemaps, etc. # Used for metadata, sitemaps, etc.
NEXT_PUBLIC_BASE_URL=http://localhost:3000 NEXT_PUBLIC_BASE_URL=http://localhost:3000
CLOUDFLARE_ZONE_ID=XXXXXXXXXXXXXXXX
CLOUDFLARE_API_TOKEN=XXXXXXXXXXXXXXXX
# Used for error tracking # Used for error tracking
NEXT_PUBLIC_SENTRY_DSN="" NEXT_PUBLIC_SENTRY_DSN=""
SENTRY_URL="" SENTRY_URL=""

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "miis" ADD COLUMN "in_queue" BOOLEAN NOT NULL DEFAULT false;

View file

@ -76,6 +76,7 @@ model Mii {
description String? @db.VarChar(512) description String? @db.VarChar(512)
platform MiiPlatform @default(THREE_DS) platform MiiPlatform @default(THREE_DS)
quarantined Boolean @default(false) quarantined Boolean @default(false)
in_queue Boolean @default(false)
instructions Json? instructions Json?
gender MiiGender? gender MiiGender?

View file

@ -123,7 +123,8 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
} }
// Prevent non-admins from quarantining Miis // Prevent non-admins from quarantining Miis
if (quarantined && session.user?.id != process.env.NEXT_PUBLIC_ADMIN_USER_ID) return rateLimit.sendResponse({ error: `You're not an admin!` }, 401); if (quarantined && session.user?.id?.toString() !== process.env.NEXT_PUBLIC_ADMIN_USER_ID)
return rateLimit.sendResponse({ error: `You're not an admin!` }, 401);
// Edit Mii in database // Edit Mii in database
const updateData: Prisma.MiiUpdateInput = {}; const updateData: Prisma.MiiUpdateInput = {};
@ -136,7 +137,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
if (instructions !== undefined) updateData.instructions = instructions; if (instructions !== undefined) updateData.instructions = instructions;
if (images.length > 0) updateData.imageCount = images.length; if (images.length > 0) updateData.imageCount = images.length;
if (Object.keys(updateData).length == 0) return rateLimit.sendResponse({ error: "Nothing was changed" }, 400); if (Object.keys(updateData).length === 0) return rateLimit.sendResponse({ error: "Nothing was changed" }, 400);
const updatedMii = await prisma.mii.update({ const updatedMii = await prisma.mii.update({
where: { where: {
id: miiId, id: miiId,
@ -230,15 +231,28 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
} }
} }
if (description === undefined) {
// If images or description were not changed, regenerate the metadata image
try { try {
await generateMetadataImage(updatedMii, updatedMii.user.name!); await generateMetadataImage(updatedMii, updatedMii.user.name!);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
return rateLimit.sendResponse({ error: `Failed to generate 'metadata' type image for mii ${miiId}` }, 500); return rateLimit.sendResponse({ error: `Failed to generate 'metadata' type image for mii ${miiId}` }, 500);
} }
}
// Tell Cloudflare to purge cache for the changed pages
fetch(`https://api.cloudflare.com/client/v4/zones/${process.env.CLOUDFLARE_ZONE_ID}/purge_cache`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
files: [
`${process.env.NEXT_PUBLIC_BASE_URL}/mii/${miiId}`,
`${process.env.NEXT_PUBLIC_BASE_URL}/mii/${miiId}/image?type=mii`,
`${process.env.NEXT_PUBLIC_BASE_URL}/mii/${miiId}/image?type=features`,
],
}),
}).catch((err) => {
console.error("Cloudflare cache purge failed:", err);
Sentry.captureException(err, { extra: { stage: "cloudflare-purge", miiId } });
});
return rateLimit.sendResponse({ success: true }); return rateLimit.sendResponse({ success: true });
} }

View file

@ -200,6 +200,7 @@ export async function POST(request: NextRequest) {
tags, tags,
description, description,
gender: gender ?? "MALE", gender: gender ?? "MALE",
in_queue: true,
// Automatically detect certain information if on 3DS // Automatically detect certain information if on 3DS
...(platform === "THREE_DS" ...(platform === "THREE_DS"

View file

@ -19,7 +19,7 @@ const searchParamsSchema = z.object({
}); });
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const rateLimit = new RateLimit(request, 20000, "/mii/image"); const rateLimit = new RateLimit(request, 200, "/mii/image");
const check = await rateLimit.handle(); const check = await rateLimit.handle();
if (check) return check; if (check) return check;

View file

@ -38,15 +38,8 @@ export default async function SubmitPage() {
} catch (error) { } catch (error) {
return <p>An error occurred!</p>; return <p>An error occurred!</p>;
} }
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/admin/can-submit`);
value = await response.json();
} catch (error) {
return <p>An error occurred!</p>;
}
if (!value) if (!value) return (
return (
<div className="grow flex items-center justify-center"> <div className="grow flex items-center justify-center">
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-8 max-w-xs w-full text-center flex flex-col"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg p-8 max-w-xs w-full text-center flex flex-col">
<h2 className="text-5xl font-black">Sorry</h2> <h2 className="text-5xl font-black">Sorry</h2>

View file

@ -37,6 +37,7 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro
} }
const where: Prisma.MiiWhereInput = { const where: Prisma.MiiWhereInput = {
in_queue: false,
// Only show liked miis on likes page // Only show liked miis on likes page
...(inLikesPage && miiIdsLiked && { id: { in: miiIdsLiked } }), ...(inLikesPage && miiIdsLiked && { id: { in: miiIdsLiked } }),
// Searching // Searching