mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 13:17:45 +00:00
fix: profile picture points to mii pictures
i copy pasted the wrong thing
This commit is contained in:
parent
7f87a42b11
commit
61cbdad812
1 changed files with 7 additions and 95 deletions
|
|
@ -1,115 +1,27 @@
|
||||||
import { NextRequest } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { Prisma } from "@prisma/client";
|
|
||||||
|
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { idSchema } from "@tomodachi-share/shared/schemas";
|
import { idSchema } from "@tomodachi-share/shared/schemas";
|
||||||
import { RateLimit } from "@/lib/rate-limit";
|
import { RateLimit } from "@/lib/rate-limit";
|
||||||
import { generateMetadataImage } from "@/lib/images";
|
|
||||||
import { prisma } from "@/lib/prisma";
|
|
||||||
|
|
||||||
const searchParamsSchema = z.object({
|
|
||||||
type: z
|
|
||||||
.enum(["mii", "qr-code", "features", "image0", "image1", "image2", "metadata"], {
|
|
||||||
message: "Image type must be either 'mii', 'qr-code', 'features', 'image[number from 0 to 2]' or 'metadata'",
|
|
||||||
})
|
|
||||||
.default("mii"),
|
|
||||||
});
|
|
||||||
|
|
||||||
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, 200, "/mii/image");
|
const rateLimit = new RateLimit(request, 16, "/profile/picture");
|
||||||
const check = await rateLimit.handle();
|
const check = await rateLimit.handle();
|
||||||
if (check) return check;
|
if (check) return check;
|
||||||
|
|
||||||
const { id: slugId } = await params;
|
const { id: slugId } = await params;
|
||||||
const parsed = idSchema.safeParse(slugId);
|
const parsed = idSchema.safeParse(slugId);
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400);
|
||||||
const miiId = parsed.data;
|
const userId = parsed.data;
|
||||||
|
|
||||||
const searchParamsParsed = searchParamsSchema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
|
const filePath = path.join(process.cwd(), "uploads", "user", `${userId}.png`);
|
||||||
if (!searchParamsParsed.success) return rateLimit.sendResponse({ error: searchParamsParsed.error.issues[0].message }, 400);
|
|
||||||
const { type: imageType } = searchParamsParsed.data;
|
|
||||||
|
|
||||||
const filePath = path.join(process.cwd(), "uploads", "mii", miiId.toString(), `${imageType}.png`);
|
|
||||||
|
|
||||||
let buffer: Buffer | undefined;
|
|
||||||
// Only find Mii if image type is 'metadata'
|
|
||||||
let mii: Prisma.MiiGetPayload<{
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
name: true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}> | null = null;
|
|
||||||
|
|
||||||
if (imageType === "metadata") {
|
|
||||||
mii = await prisma.mii.findUnique({
|
|
||||||
where: {
|
|
||||||
id: miiId,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!mii) {
|
|
||||||
return rateLimit.sendResponse({ error: "Mii not found" }, 404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to read file
|
const buffer = await fs.readFile(filePath);
|
||||||
buffer = await fs.readFile(filePath);
|
return new NextResponse(new Uint8Array(buffer)); // convert to Uint8Array due to weird types issue
|
||||||
} catch {
|
} catch {
|
||||||
// If the readFile() fails, that probably means it doesn't exist
|
|
||||||
if (imageType === "metadata" && mii) {
|
|
||||||
// Metadata images were added after 1274 Miis were submitted, so we generate it on-the-fly
|
|
||||||
console.log(`Metadata image not found for mii ID ${miiId}, generating metadata image...`);
|
|
||||||
const { buffer: metadataBuffer, error, status } = await generateMetadataImage(mii, mii.user.name!);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return rateLimit.sendResponse({ error }, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = metadataBuffer;
|
|
||||||
} else {
|
|
||||||
return rateLimit.sendResponse({ error: "Image not found" }, 404);
|
return rateLimit.sendResponse({ error: "Image not found" }, 404);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!buffer) return rateLimit.sendResponse({ error: "Image not found" }, 404);
|
|
||||||
|
|
||||||
// Set the file name for the metadata image in the response for SEO
|
|
||||||
if (mii && imageType === "metadata") {
|
|
||||||
const slugify = (str: string) =>
|
|
||||||
str
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9]+/g, "-") // replace non-alphanumeric with hyphens
|
|
||||||
.replace(/^-+|-+$/g, "");
|
|
||||||
|
|
||||||
const name = slugify(mii.name);
|
|
||||||
const tags = mii.tags.map(slugify).join("-");
|
|
||||||
|
|
||||||
const filename = `${name}-mii-${tags}.png`;
|
|
||||||
|
|
||||||
return rateLimit.sendResponse(buffer, 200, {
|
|
||||||
"Content-Type": "image/png",
|
|
||||||
"Content-Disposition": `inline; filename="${filename}"`,
|
|
||||||
"Cache-Control": "public, max-age=31536000",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return rateLimit.sendResponse(buffer, 200, {
|
|
||||||
"Content-Type": "image/png",
|
|
||||||
"X-Robots-Tag": "noindex, noimageindex, nofollow",
|
|
||||||
"Cache-Control": "public, max-age=60, stale-while-revalidate=30",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue