46 lines
1.3 KiB
TypeScript

import { ActionError, defineAction } from "astro:actions";
import { z } from "astro/zod";
import { createAppeal, getLatestAppealsByClientIp } from "../queries";
const CREATE_APPEAL_LIMIT_HRS = 1;
const APPEALS_LAST_HRS_LIMIT = 2;
export const server = {
appeal: defineAction({
accept: "form",
input: z.object({
name: z.string(),
email: z.string().email(),
website_url: z.string().optional(), // honeypot field
subject: z.string(),
message: z.string(),
}),
handler: async (data, ctx) => {
if (data.website_url && data.website_url.trim() !== "") return true;
const currentDate = new Date();
const latestAppeals = await getLatestAppealsByClientIp(ctx.clientAddress, 5);
const appealsLastHrs = latestAppeals.filter((a) => {
const hourDiff = (currentDate.getTime() - new Date(a.date_created).getTime()) / (1000 * 60 * 60);
return hourDiff <= CREATE_APPEAL_LIMIT_HRS;
});
if (appealsLastHrs.length >= APPEALS_LAST_HRS_LIMIT) {
throw new ActionError({
code: "TOO_MANY_REQUESTS",
message: "Appeal create limit exceeded.",
});
}
const appeal = await createAppeal({ ...data, client_ip: ctx.clientAddress });
if (appeal) return true;
throw new ActionError({
code: "INTERNAL_SERVER_ERROR",
message: "Unable to create appeal.",
});
},
}),
};