feat: api mii list route

This commit is contained in:
trafficlunar 2025-04-12 17:00:42 +01:00
parent 9f50c3e720
commit 626016d689

View file

@ -0,0 +1,93 @@
import { NextRequest, NextResponse } from "next/server";
import { Prisma } from "@prisma/client";
import { z } from "zod";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { nameSchema, tagsSchema } from "@/lib/schemas";
const searchSchema = z.object({
query: nameSchema.optional(),
sort: z.enum(["newest", "likes"], { message: "Sort must be either 'newest' or 'likes'" }).default("newest"),
tags: z
.string()
.optional()
.transform((value) =>
value
?.split(",")
.map((tag) => tag.trim())
.filter((tag) => tag.length > 0)
),
userId: z.coerce
.number({ message: "User ID must be valid" })
.int({ message: "User ID must be an integer" })
.positive({ message: "User ID must be valid" })
.optional(),
});
export async function GET(request: NextRequest) {
const session = await auth();
const parsed = searchSchema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
if (!parsed.success) return NextResponse.json({ error: parsed.error.errors[0].message }, { status: 400 });
const { query, sort, tags, userId } = parsed.data;
const where: Prisma.MiiWhereInput = {
// Searching
...(query && {
OR: [{ name: { contains: query, mode: "insensitive" } }, { tags: { has: query } }],
}),
// Tag filtering
...(tags && tags.length > 0 && { tags: { hasEvery: tags } }),
// Profiles
...(userId && { userId }),
};
// Sorting by likes or newest
const orderBy: Prisma.MiiOrderByWithRelationInput = sort === "likes" ? { likedBy: { _count: "desc" } } : { createdAt: "desc" };
const select: Prisma.MiiSelect = {
id: true,
// Don't show when userId is specified
...(!userId && {
user: {
select: {
id: true,
username: true,
},
},
}),
name: true,
imageCount: true,
tags: true,
createdAt: true,
// Mii liked check
likedBy: {
where: session && session.user?.id ? { userId: Number(session.user.id) } : {},
select: {
userId: true,
},
},
// Like count
_count: {
select: { likedBy: true },
},
};
const [totalCount, filteredCount, list] = await Promise.all([
prisma.mii.count({ where: userId ? { userId } : {} }),
prisma.mii.count({ where }),
prisma.mii.findMany({ where, orderBy, select }),
]);
return NextResponse.json({
total: totalCount,
filtered: filteredCount,
miis: list.map(({ _count, likedBy, ...rest }) => ({
...rest,
likes: _count.likedBy,
isLiked: likedBy.length > 0,
})),
});
}