Beliebig viele Ziele je Konto, jedes mit eigenen Anlaessen. Jedes laesst sich einzeln testen und pausieren; Ergebnis und Zeitpunkt der letzten Zustellung stehen an der Karte. Der Weg laesst sich nach dem Anlegen nicht mehr aendern - ein Webhook-Ziel zu einer E-Mail-Adresse umzubiegen ergaebe keinen Sinn und muesste das Geheimnis mitwandern lassen. Ist kein SMTP hinterlegt, ist die Auswahl "E-Mail" gesperrt und erklaert, warum. targetSafeSelect liegt in lib/notify/types statt in der Route: Next laesst in route.ts nur bestimmte Exporte zu und bricht den Bau bei allem anderen ab. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { requireUserApi } from "@/lib/auth/guard";
|
||
import { prisma } from "@/lib/db";
|
||
import { deliver } from "@/lib/notify/channels";
|
||
import { testMessage } from "@/lib/notify";
|
||
import { LIMITS, rateLimit } from "@/lib/security/rateLimit";
|
||
import { clientIp, jsonError, tooManyRequests } from "@/lib/security/request";
|
||
|
||
export const dynamic = "force-dynamic";
|
||
|
||
type Params = { params: Promise<{ id: string }> };
|
||
|
||
/** Schickt eine Testnachricht an genau dieses Ziel. */
|
||
export async function POST(request: Request, { params }: Params) {
|
||
const auth = await requireUserApi();
|
||
if (!auth.ok) return auth.response;
|
||
|
||
// Loest einen ausgehenden Aufruf aus – entsprechend begrenzt.
|
||
const limited = rateLimit(
|
||
`notify-test:${auth.user.id}:${clientIp(request)}`,
|
||
LIMITS.outbound.limit,
|
||
LIMITS.outbound.windowMs,
|
||
);
|
||
if (!limited.ok) return tooManyRequests(limited.retryAfter);
|
||
|
||
const { id } = await params;
|
||
const target = await prisma.notificationTarget.findFirst({
|
||
where: { id, userId: auth.user.id },
|
||
});
|
||
if (!target) return jsonError("Ziel nicht gefunden", 404);
|
||
|
||
const result = await deliver(target, testMessage());
|
||
|
||
await prisma.notificationTarget.update({
|
||
where: { id },
|
||
data: { lastSentAt: new Date(), lastOk: result.ok, lastMessage: result.message },
|
||
});
|
||
|
||
return NextResponse.json(result, { status: result.ok ? 200 : 502 });
|
||
}
|