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"]), }); const LOG_EXCERPT_LIMIT = 500; const SUBSCRIPTION_ACTION_EVENTS = { suspend: { requested: "subscription_suspend_requested", succeeded: "subscription_suspend_succeeded", failed: "subscription_suspend_failed", }, unsuspend: { requested: "subscription_unsuspend_requested", succeeded: "subscription_unsuspend_succeeded", failed: "subscription_unsuspend_failed", }, } as const; function excerpt(value: string | null | undefined) { if (!value) return null; const trimmed = value.trim(); if (!trimmed) return null; return trimmed.length > LOG_EXCERPT_LIMIT ? `${trimmed.slice(0, LOG_EXCERPT_LIMIT)}…` : trimmed; } async function insertActionLogBestEffort( supabase: any, payload: Record, ) { try { const { error } = await supabase.from("actions_log").insert(payload); if (error) { console.error("[actions_log] insert failed", error.message); } } catch (error) { console.error("[actions_log] insert threw", error); } } export async function POST( req: Request, { params }: { params: { id: string } }, ) { let requestedAction: "suspend" | "unsuspend" | null = null; const supabase = createSupabaseRouteClient() as any; let context: Awaited> | null = null; let subscription: { id: string; plesk_subscription_id: string; plesk_instance_id: string; } | null = null; const startedAt = Date.now(); try { assertSameOrigin(req); context = await getRouteAgencyContextOrThrow(); assertAgencyAdmin(context); assertRateLimit(`plesk-subscription-action:${context.userId}`, 20, 60_000); const payload = actionSchema.parse(await req.json()); requestedAction = payload.action; const { data, error } = await supabase .from("plesk_subscriptions") .select("id, plesk_subscription_id, plesk_instance_id") .eq("id", params.id) .eq("agency_id", context.agencyId) .single(); subscription = data; if (error || !subscription) { throw new Error("Subscription not found"); } const { data: instance, error: instanceError } = await supabase .from("plesk_instances") .select("id, base_url, auth_type, encrypted_secret") .eq("id", subscription.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; const cliArgs = payload.action === "suspend" ? ["--webspace-off", subscription.plesk_subscription_id] : ["--unsuspend", subscription.plesk_subscription_id]; await insertActionLogBestEffort(supabase, { agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_subscription", target_id: subscription.id, action: SUBSCRIPTION_ACTION_EVENTS[payload.action].requested, status: "pending", metadata: { subscription_id: subscription.id, plesk_instance_id: subscription.plesk_instance_id, plesk_subscription_id: subscription.plesk_subscription_id, cli_command: "subscription", cli_args: cliArgs, }, }); const actionCliResult = payload.action === "suspend" ? await suspendPleskSubscription( connection, subscription.plesk_subscription_id, ) : await unsuspendPleskSubscription( connection, subscription.plesk_subscription_id, ); const fallbackStatus = payload.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 insertActionLogBestEffort(supabase, { 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, }, }); } const { error: updateError } = await supabase .from("plesk_subscriptions") .update({ status: refreshedStatus, status_raw: refreshedStatusRaw, last_status_sync_at: new Date().toISOString(), }) .eq("id", subscription.id); await supabase .from("plesk_domains") .update({ status: refreshedStatus }) .eq("agency_id", context.agencyId) .eq("subscription_id", subscription.id); await insertActionLogBestEffort(supabase, { agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_subscription", target_id: subscription.id, action: SUBSCRIPTION_ACTION_EVENTS[payload.action].succeeded, status: "success", metadata: { duration_ms: Date.now() - startedAt, cli_command: "subscription", cli_args: cliArgs, plesk_subscription_id: subscription.plesk_subscription_id, refreshed_status: refreshedStatus, refresh_error: refreshErrorMessage, cli_exit_code: actionCliResult.code, cli_stdout_excerpt: excerpt(actionCliResult.stdout), cli_stderr_excerpt: excerpt(actionCliResult.stderr), db_status_update_error: updateError?.message ?? null, }, }); return NextResponse.json({ ok: true, status: refreshedStatus, dbStatusUpdated: !updateError, refreshError: refreshErrorMessage, }); } catch (error) { if (supabase && context && subscription) { const message = error instanceof Error ? error.message : "Subscription action failed"; if (requestedAction) { await insertActionLogBestEffort(supabase, { agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_subscription", target_id: subscription.id, action: SUBSCRIPTION_ACTION_EVENTS[requestedAction].failed, status: "failed", error_message: message, metadata: { duration_ms: Date.now() - startedAt, plesk_subscription_id: subscription.plesk_subscription_id, plesk_instance_id: subscription.plesk_instance_id, }, }); } else { await insertActionLogBestEffort(supabase, { agency_id: context.agencyId, actor_user_id: context.userId, target_type: "plesk_subscription", target_id: subscription.id, action: "subscription_action_failed", status: "failed", error_message: message, metadata: { duration_ms: Date.now() - startedAt, plesk_subscription_id: subscription.plesk_subscription_id, plesk_instance_id: subscription.plesk_instance_id, }, }); } } return NextResponse.json( { error: error instanceof Error ? error.message : "Subscription action failed", }, { status: 400 }, ); } }