48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
/**
|
|
* convex/http.ts
|
|
*
|
|
* Öffentliche HTTP-Routen. /abmelden ist der frictionless Opt-out aus dem
|
|
* Pflicht-Footer jeder Outreach-Mail (UWG/DSGVO).
|
|
*/
|
|
import { httpRouter } from "convex/server";
|
|
import { httpAction } from "./_generated/server";
|
|
import { internal } from "./_generated/api";
|
|
import type { Id } from "./_generated/dataModel";
|
|
|
|
const http = httpRouter();
|
|
|
|
http.route({
|
|
path: "/abmelden",
|
|
method: "GET",
|
|
handler: httpAction(async (ctx, req) => {
|
|
const o = new URL(req.url).searchParams.get("o");
|
|
if (o) {
|
|
try {
|
|
const target = await ctx.runQuery(internal.outreach.getOptOutTarget, {
|
|
outreachId: o as Id<"outreach">,
|
|
});
|
|
if (target) {
|
|
await ctx.runMutation(internal.outreach.recordOptOut, {
|
|
orgId: target.orgId,
|
|
email: target.email,
|
|
domain: target.domain,
|
|
outreachId: o as Id<"outreach">,
|
|
});
|
|
}
|
|
} catch {
|
|
// ungültiger Link → trotzdem freundlich bestätigen
|
|
}
|
|
}
|
|
return new Response(
|
|
`<!doctype html><html lang="de"><meta charset="utf-8">
|
|
<body style="font-family:Arial,sans-serif;max-width:480px;margin:80px auto;color:#222">
|
|
<h1 style="font-size:20px">Sie wurden abgemeldet.</h1>
|
|
<p>Sie erhalten keine weitere Nachricht. Entschuldigen Sie die Störung.</p>
|
|
</body></html>`,
|
|
{ headers: { "Content-Type": "text/html; charset=utf-8" } },
|
|
);
|
|
}),
|
|
});
|
|
|
|
export default http;
|