import { NextResponse } from "next/server"; import { z } from "zod"; import { assertAgencyAdmin, getRouteAgencyContextOrThrow } from "@/lib/agency"; import { assertRateLimit } from "@/lib/api/rate-limit"; import { assertSameOrigin } from "@/lib/api/security"; import { parseSubscriptionStatusDetailsFromInfo, pleskCliCall, suspendPleskSubscription, unsuspendPleskSubscription, } from "@/lib/plesk/client"; import { createSupabaseRouteClient } from "@/lib/supabase/route"; const actionSchema = z.object({ action: z.enum(["suspend", "unsuspend"]), subscription_id: z.string().uuid().optional(), }); export async function POST( req: Request, { params }: { params: { id: string } }, ) { const supabase = createSupabaseRouteClient() as any; let context: Awaited> | null = null; let domain: { id: string; subscription_id: string | null } | null = null; let subscription: { id: string; plesk_subscription_id: string; plesk_instance_id: string; } | null = null; let requestedAction: "suspend" | "unsuspend" | null = null; try { assertSameOrigin(req); context = await getRouteAgencyContextOrThrow(); assertAgencyAdmin(context); assertRateLimit(`plesk-domain-action:${context.userId}`, 10, 60_000); const payload = actionSchema.parse(await req.json()); const { action } = payload; requestedAction = action; const { data: domainRow, error: domainError } = await supabase .from("plesk_domains") .select("id, agency_id, plesk_instance_id, subscription_id") .eq("id", params.id) .eq("agency_id", context.agencyId) .single(); if (domainError || !domainRow) { throw new Error("Domain not found"); } const resolvedSubscriptionId = payload.subscription_id ?? (domainRow.subscription_id ? String(domainRow.subscription_id) : null); domain = { id: String(domainRow.id), subscription_id: resolvedSubscriptionId, }; if (!resolvedSubscriptionId) { throw new Error("Domain is not linked to a subscription"); } const { data: subscriptionRow, error: subscriptionError } = await supabase .from("plesk_subscriptions") .select("id, plesk_subscription_id, plesk_instance_id") .eq("id", resolvedSubscriptionId) .eq("agency_id", context.agencyId) .single(); if (subscriptionError || !subscriptionRow) { throw new Error("Subscription not found"); } subscription = { id: String(subscriptionRow.id), plesk_subscription_id: String(subscriptionRow.plesk_subscription_id), plesk_instance_id: String(subscriptionRow.plesk_instance_id), }; const { data: instance, error: instanceError } = await supabase .from("plesk_instances") .select("id, base_url, auth_type, encrypted_secret") .eq("id", subscriptionRow.plesk_instance_id) .eq("agency_id", context.agencyId) .single(); if (instanceError || !instance) { throw new Error("Plesk instance not found"); } const connection = { baseUrl: instance.base_url, authType: instance.auth_type, encryptedSecret: instance.encrypted_secret, } as const; if (action === "suspend") { await suspendPleskSubscription( connection, subscription.plesk_subscription_id, ); } else { await unsuspendPleskSubscription( connection, subscription.plesk_subscription_id, ); } const fallbackStatus = action === "suspend" ? "suspended" : "active"; let refreshedStatus = fallbackStatus; let refreshedStatusRaw: string | null = null; let refreshErrorMessage: string | null = null; try { const infoResult = await pleskCliCall(connection, "subscription", [ "--info", subscription.plesk_subscription_id, ]); const parsed = parseSubscriptionStatusDetailsFromInfo( infoResult.stdout ?? "", ); refreshedStatus = parsed.status; refreshedStatusRaw = parsed.statusRaw; } catch (refreshError) { refreshErrorMessage = refreshError instanceof Error ? refreshError.message.slice(0, 1000) : "subscription_status_refresh_failed"; await supabase.from("actions_log").insert({ agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_subscription", target_id: subscription.id, action: "subscription_status_refresh_failed", status: "failed", error_message: refreshErrorMessage, metadata: { subscription_id: subscription.id, plesk_subscription_id: subscription.plesk_subscription_id, plesk_instance_id: subscription.plesk_instance_id, source: "domain_action", domain_id: domain.id, }, }); } await supabase .from("plesk_subscriptions") .update({ status: refreshedStatus, status_raw: refreshedStatusRaw, last_status_sync_at: new Date().toISOString(), }) .eq("id", subscription.id) .eq("agency_id", context.agencyId); await supabase .from("plesk_domains") .update({ status: refreshedStatus }) .eq("agency_id", context.agencyId) .eq("subscription_id", subscription.id); await supabase.from("actions_log").insert({ agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_domain", target_id: domain.id, action: `domain_${action}`, status: "success", metadata: { domain_id: domain.id, subscription_id: subscription.id, plesk_subscription_id: subscription.plesk_subscription_id, refreshed_status: refreshedStatus, refresh_error: refreshErrorMessage, }, }); return NextResponse.json({ ok: true }); } catch (error) { if (context && domain) { const message = error instanceof Error ? error.message : "Domain action failed"; await supabase.from("actions_log").insert({ agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_domain", target_id: domain.id, action: requestedAction ? `domain_${requestedAction}` : "domain_action", status: "failed", error_message: message, metadata: { domain_id: domain.id, subscription_id: subscription?.id ?? domain.subscription_id, plesk_subscription_id: subscription?.plesk_subscription_id ?? null, }, }); } return NextResponse.json( { error: error instanceof Error ? error.message : "Domain action failed", }, { status: 400 }, ); } }