import { jsonError, jsonResponse } from "../../common.js"; export async function onRequestGet(context: RequestContext) { const { current_user: currentUser } = context.data; if ( !currentUser.email || (await context.env.DATA.get("appeal_disabled")) || (await context.env.D1.prepare( "SELECT id FROM appeals WHERE open = 1 AND user = ?;", ) .bind(currentUser.id) .first()) || (await context.env.DATA.get(`blockedappeal_${currentUser.id}`)) ) return jsonResponse('{"can_appeal":false}'); return jsonResponse('{"can_appeal":true}'); } export async function onRequestPost(context: RequestContext) { if (await context.env.DATA.get("appeal_disabled")) return jsonError("Appeals are disabled", 403); const { learned, senderTokenId, whyBanned, whyUnban } = context.data.body; if ( typeof learned !== "string" || typeof whyBanned !== "string" || typeof whyUnban !== "string" || !learned.length || learned.length > 2000 || !whyBanned.length || whyBanned.length > 500 || !whyUnban.length || whyUnban.length > 2000 ) return jsonError("One or more fields are missing or invalid", 400); const { current_user: currentUser } = context.data; if (!currentUser.email) return jsonError("No email for this session", 403); const existingBlockedAppeal = await context.env.DATA.get( `blockedappeal_${currentUser.id}`, ); if ( existingBlockedAppeal || (await context.env.D1.prepare( "SELECT approved FROM appeals WHERE approved IS NULL AND json_extract(user, '$.id') = ?;", ) .bind(currentUser.id) .first()) ) return jsonError("Appeal already submitted", 403); if ( await context.env.D1.prepare("SELECT * FROM appeal_bans WHERE user = ?;") .bind(currentUser.id) .first() ) { await context.env.DATA.put(`blockedappeal_${currentUser.id}`, "1", { metadata: { email: currentUser.email }, }); return new Response(null, { status: 204, }); } const appealId = `${currentUser.id}${Date.now()}${crypto .randomUUID() .replaceAll("-", "")}`; await context.env.D1.prepare( "INSERT INTO appeals (ban_reason, created_at, id, learned, reason_for_unban, user) VALUES (?, ?, ?, ?, ?, ?);", ) .bind( whyBanned, Date.now(), appealId, learned, whyUnban, JSON.stringify({ email: currentUser.email, id: currentUser.id, username: currentUser.username, }), ) .run(); if (typeof senderTokenId === "string") { await context.env.D1.prepare( "INSERT INTO push_notifications (created_at, event_id, event_type, token) VALUES (?, ?, 'appeal', ?)", ) .bind(Date.now(), appealId, senderTokenId) .run(); } await fetch(context.env.APPEALS_WEBHOOK, { body: JSON.stringify({ embeds: [ { title: "Appeal Submitted", color: 3756250, description: `View this appeal at https://carcrushers.cc/mod-queue?id=${appealId}&type=appeal`, fields: [ { name: "Submitter", value: `${currentUser.username} (${currentUser.id})`, }, ], }, ], }), headers: { "content-type": "application/json", }, method: "POST", }); return new Response(null, { status: 204, }); }