import { NextRequest, NextResponse } from "next/server"; import { auth, getAuthSession } from "@/lib/auth"; import { db } from "@/lib/db"; import { scheduledTasks } from "@/lib/db/schema"; import { scheduleTask, stopTask } from "@/lib/scheduler"; import { checkRateLimit, getClientIp } from "@/lib/security/rateLimit"; import { eq } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; import cron from "node-cron"; const TaskSchema = z.object({ name: z.string().min(1).max(100), description: z.string().max(500).optional(), cronExpression: z.string().max(100), command: z.string().min(1).max(500), isEnabled: z.boolean().default(true), }); export async function GET(req: NextRequest) { const session = await getAuthSession(req.headers); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); const tasks = await db.select().from(scheduledTasks).orderBy(scheduledTasks.createdAt); return NextResponse.json({ tasks }); } export async function POST(req: NextRequest) { const session = await getAuthSession(req.headers); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!["superadmin", "admin"].includes(session.user.role ?? "")) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const ip = getClientIp(req); const { allowed } = checkRateLimit(ip); if (!allowed) return NextResponse.json({ error: "Too many requests" }, { status: 429 }); let body: z.infer; try { body = TaskSchema.parse(await req.json()); } catch { return NextResponse.json({ error: "Invalid request" }, { status: 400 }); } if (!cron.validate(body.cronExpression)) { return NextResponse.json({ error: "Invalid cron expression" }, { status: 400 }); } const id = nanoid(); await db.insert(scheduledTasks).values({ id, name: body.name, description: body.description ?? null, cronExpression: body.cronExpression, command: body.command, isEnabled: body.isEnabled, createdAt: Date.now(), updatedAt: Date.now(), }); if (body.isEnabled) { scheduleTask(id, body.cronExpression, body.command); } return NextResponse.json({ success: true, id }, { status: 201 }); }