Your Name 53ddb7e585
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Initial commit - clean repository
2025-12-17 20:15:18 +08:00

162 lines
4.2 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { db } from "@/lib/db";
import { navLinks } from "@/lib/db/schema";
import { eq } from "drizzle-orm";
import { auth } from "@/app/(auth)/auth";
// GET /api/nav-links - 获取所有导航链接 (公开)
export async function GET() {
try {
const links = await db
.select()
.from(navLinks)
.where(eq(navLinks.isEnabled, true))
.orderBy(navLinks.order);
return NextResponse.json({ links });
} catch (error) {
console.error("[Nav Links API] Get error:", error);
return NextResponse.json(
{ error: "Failed to fetch nav links" },
{ status: 500 }
);
}
}
const createSchema = z.object({
name: z.string().min(1).max(64),
url: z.string().url(),
order: z.number().int().default(0),
isEnabled: z.boolean().default(true),
});
// POST /api/nav-links - 创建导航链接(仅管理员)
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (session.user.type !== "admin") {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
const data = createSchema.parse(body);
const [created] = await db
.insert(navLinks)
.values({
...data,
createdBy: session.user.id,
})
.returning();
return NextResponse.json(created);
} catch (error) {
console.error("[Nav Links API] Create error:", error);
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid request data", details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: "Failed to create nav link" },
{ status: 500 }
);
}
}
const updateSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(64).optional(),
url: z.string().url().optional(),
order: z.number().int().optional(),
isEnabled: z.boolean().optional(),
});
// PUT /api/nav-links - 更新导航链接(仅管理员)
export async function PUT(request: NextRequest) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (session.user.type !== "admin") {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
const { id, ...data } = updateSchema.parse(body);
const [updated] = await db
.update(navLinks)
.set({
...data,
updatedAt: new Date(),
})
.where(eq(navLinks.id, id))
.returning();
if (!updated) {
return NextResponse.json({ error: "Nav link not found" }, { status: 404 });
}
return NextResponse.json(updated);
} catch (error) {
console.error("[Nav Links API] Update error:", error);
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid request data", details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: "Failed to update nav link" },
{ status: 500 }
);
}
}
// DELETE /api/nav-links - 删除导航链接(仅管理员)
export async function DELETE(request: NextRequest) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (session.user.type !== "admin") {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");
if (!id) {
return NextResponse.json({ error: "ID is required" }, { status: 400 });
}
await db.delete(navLinks).where(eq(navLinks.id, id));
return NextResponse.json({ success: true });
} catch (error) {
console.error("[Nav Links API] Delete error:", error);
return NextResponse.json(
{ error: "Failed to delete nav link" },
{ status: 500 }
);
}
}