refactor: remove obsolete member management API module
Some checks failed
Workflow / ʦ TypeScript (pull_request) Failing after 5m57s
Workflow / ⚫️ Test (pull_request) Has been skipped

This commit is contained in:
T. Zehetbauer
2026-04-03 14:08:31 +02:00
parent 124c6a632a
commit 5c5aaabae5
132 changed files with 10107 additions and 3442 deletions

View File

@@ -6,6 +6,7 @@ import {
emailSchema,
requiredString,
} from '@kit/next/route-helpers';
import { checkRateLimit, getClientIp } from '@kit/next/routes/rate-limit';
import { getLogger } from '@kit/shared/logger';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
@@ -20,12 +21,33 @@ const MembershipApplySchema = z.object({
city: z.string().optional(),
dateOfBirth: z.string().optional(),
message: z.string().optional(),
captchaToken: z.string().optional(),
});
// Rate limits
const MAX_PER_IP = 5;
const MAX_PER_ACCOUNT = 20;
const WINDOW_MS = 60 * 60 * 1000; // 1 hour
export async function POST(request: Request) {
const logger = await getLogger();
try {
// Rate limit by IP
const ip = getClientIp(request);
const ipLimit = checkRateLimit(
`membership-apply:ip:${ip}`,
MAX_PER_IP,
WINDOW_MS,
);
if (!ipLimit.allowed) {
return apiError(
'Zu viele Anfragen. Bitte versuchen Sie es später erneut.',
429,
);
}
const body = await request.json();
const parsed = MembershipApplySchema.safeParse(body);
@@ -44,10 +66,48 @@ export async function POST(request: Request) {
city,
dateOfBirth,
message,
captchaToken,
} = parsed.data;
// Rate limit by account
const accountLimit = checkRateLimit(
`membership-apply:account:${accountId}`,
MAX_PER_ACCOUNT,
WINDOW_MS,
);
if (!accountLimit.allowed) {
return apiError('Zu viele Bewerbungen für diese Organisation.', 429);
}
// Verify CAPTCHA when configured — token is required, not optional
if (process.env.CAPTCHA_SECRET_TOKEN) {
if (!captchaToken) {
return apiError('CAPTCHA-Überprüfung erforderlich.', 400);
}
const { verifyCaptchaToken } = await import('@kit/auth/captcha/server');
try {
await verifyCaptchaToken(captchaToken);
} catch {
return apiError('CAPTCHA-Überprüfung fehlgeschlagen.', 400);
}
}
const supabase = getSupabaseServerAdminClient();
// Validate that the account exists before inserting
const { data: account } = await supabase
.from('accounts')
.select('id')
.eq('id', accountId)
.single();
if (!account) {
return apiError('Ungültige Organisation.', 400);
}
const { error } = await supabase.from('membership_applications').insert({
account_id: accountId,
first_name: firstName,