v0.1.0 — Moon Base initial scaffold: auth, garden plant registry + log
This commit is contained in:
5
src/app/api/auth/[...nextauth]/route.ts
Normal file
5
src/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
export { handler as GET, handler as POST };
|
||||
55
src/app/api/plants/[id]/logs/route.ts
Normal file
55
src/app/api/plants/[id]/logs/route.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { db } from "@/lib/db";
|
||||
import { requireAuth } from "@/lib/auth";
|
||||
import { PlantLogType } from "@prisma/client";
|
||||
|
||||
const createSchema = z.object({
|
||||
type: z.nativeEnum(PlantLogType),
|
||||
date: z.string().optional(),
|
||||
notes: z.string().optional(),
|
||||
quantity: z.string().optional(),
|
||||
});
|
||||
|
||||
export async function POST(req: Request, { params }: { params: { id: string } }) {
|
||||
try {
|
||||
const session = await requireAuth();
|
||||
|
||||
const plant = await db.plant.findUnique({ where: { id: params.id }, select: { id: true } });
|
||||
if (!plant) return NextResponse.json({ error: "Plant not found" }, { status: 404 });
|
||||
|
||||
const body = await req.json();
|
||||
const data = createSchema.parse(body);
|
||||
|
||||
const log = await db.plantLog.create({
|
||||
data: {
|
||||
plantId: params.id,
|
||||
type: data.type,
|
||||
date: data.date ? new Date(data.date) : new Date(),
|
||||
notes: data.notes?.trim() || null,
|
||||
quantity: data.quantity?.trim() || null,
|
||||
actorId: session.user.id,
|
||||
},
|
||||
});
|
||||
|
||||
await db.auditEvent.create({
|
||||
data: {
|
||||
action: "plant.log.add",
|
||||
entityId: params.id,
|
||||
actorId: session.user.id,
|
||||
payload: { logId: log.id, type: log.type },
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(log, { status: 201 });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return NextResponse.json({ error: err.issues }, { status: 400 });
|
||||
}
|
||||
if (err instanceof Error && err.message === "Unauthorized") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
console.error(err);
|
||||
return NextResponse.json({ error: "Server error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
57
src/app/api/plants/route.ts
Normal file
57
src/app/api/plants/route.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { db } from "@/lib/db";
|
||||
import { requireAuth } from "@/lib/auth";
|
||||
import { PlantCategory } from "@prisma/client";
|
||||
|
||||
const createSchema = z.object({
|
||||
commonName: z.string().min(1),
|
||||
species: z.string().optional(),
|
||||
variety: z.string().optional(),
|
||||
category: z.nativeEnum(PlantCategory),
|
||||
zone: z.string().optional(),
|
||||
plantedAt: z.string().optional(), // ISO date string
|
||||
source: z.string().optional(),
|
||||
notes: z.string().optional(),
|
||||
});
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const session = await requireAuth();
|
||||
const body = await req.json();
|
||||
const data = createSchema.parse(body);
|
||||
|
||||
const plant = await db.plant.create({
|
||||
data: {
|
||||
commonName: data.commonName.trim(),
|
||||
species: data.species?.trim() || null,
|
||||
variety: data.variety?.trim() || null,
|
||||
category: data.category,
|
||||
zone: data.zone?.trim() || null,
|
||||
plantedAt: data.plantedAt ? new Date(data.plantedAt) : null,
|
||||
source: data.source?.trim() || null,
|
||||
notes: data.notes?.trim() || null,
|
||||
},
|
||||
});
|
||||
|
||||
await db.auditEvent.create({
|
||||
data: {
|
||||
action: "plant.create",
|
||||
entityId: plant.id,
|
||||
actorId: session.user.id,
|
||||
payload: { commonName: plant.commonName, category: plant.category },
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(plant, { status: 201 });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return NextResponse.json({ error: err.issues }, { status: 400 });
|
||||
}
|
||||
if (err instanceof Error && err.message === "Unauthorized") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
console.error(err);
|
||||
return NextResponse.json({ error: "Server error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user