diff --git a/prisma/migrations/20250507200121_mii_descriptions/migration.sql b/prisma/migrations/20250507200121_mii_descriptions/migration.sql new file mode 100644 index 0000000..c2f9279 --- /dev/null +++ b/prisma/migrations/20250507200121_mii_descriptions/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "miis" ADD COLUMN "description" VARCHAR(256); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e6009f5..6a5bfac 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -64,11 +64,12 @@ model Session { } model Mii { - id Int @id @default(autoincrement()) - userId Int - name String @db.VarChar(64) - imageCount Int @default(0) - tags String[] + id Int @id @default(autoincrement()) + userId Int + name String @db.VarChar(64) + imageCount Int @default(0) + tags String[] + description String? @db.VarChar(256) firstName String lastName String diff --git a/src/app/api/submit/route.ts b/src/app/api/submit/route.ts index cf80c9a..8bdf4d2 100644 --- a/src/app/api/submit/route.ts +++ b/src/app/api/submit/route.ts @@ -24,6 +24,7 @@ const uploadsDirectory = path.join(process.cwd(), "uploads"); const submitSchema = z.object({ name: nameSchema, tags: tagsSchema, + description: z.string().trim().max(256).optional(), qrBytesRaw: z .array(z.number(), { required_error: "A QR code is required" }) .length(372, { message: "QR code size is not a valid Tomodachi Life QR code" }), @@ -54,6 +55,7 @@ export async function POST(request: NextRequest) { const parsed = submitSchema.safeParse({ name: formData.get("name"), tags: rawTags, + description: formData.get("description"), qrBytesRaw: rawQrBytesRaw, image1: formData.get("image1"), image2: formData.get("image2"), @@ -61,11 +63,12 @@ export async function POST(request: NextRequest) { }); if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400); - const { name: uncensoredName, tags: uncensoredTags, qrBytesRaw, image1, image2, image3 } = parsed.data; + const { name: uncensoredName, tags: uncensoredTags, description: uncensoredDescription, qrBytesRaw, image1, image2, image3 } = parsed.data; // Censor potential inappropriate words const name = profanity.censor(uncensoredName); const tags = uncensoredTags.map((t) => profanity.censor(t)); + const description = uncensoredDescription && profanity.censor(uncensoredDescription); // Validate image files const images: File[] = []; @@ -97,6 +100,7 @@ export async function POST(request: NextRequest) { userId: Number(session.user.id), name, tags, + description, firstName: conversion.tomodachiLifeMii.firstName, lastName: conversion.tomodachiLifeMii.lastName, diff --git a/src/app/mii/[id]/page.tsx b/src/app/mii/[id]/page.tsx index d94206a..b821dea 100644 --- a/src/app/mii/[id]/page.tsx +++ b/src/app/mii/[id]/page.tsx @@ -200,6 +200,9 @@ export default async function MiiPage({ params }: Props) { {mii.createdAt.toLocaleTimeString("en-GB", { timeZone: "UTC" })} UTC + + {/* Description */} + {mii.description &&

{mii.description}

} {/* Buttons */} diff --git a/src/components/report/mii-form.tsx b/src/components/report/mii-form.tsx index 0379050..cd4647f 100644 --- a/src/components/report/mii-form.tsx +++ b/src/components/report/mii-form.tsx @@ -65,6 +65,7 @@ export default function ReportMiiForm({ mii, likes }: Props) {