Initial working state: CL3.5 complete (Plesk sync + suspend/unsuspend)
This commit is contained in:
218
lib/plesk/sync.ts
Normal file
218
lib/plesk/sync.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import type { Database } from "@/lib/types";
|
||||
import { listPleskDomains, listPleskSubscriptions } from "@/lib/plesk/client";
|
||||
|
||||
type SupabaseLike = any;
|
||||
|
||||
type SyncResult = {
|
||||
instanceId: string;
|
||||
agencyId: string;
|
||||
skipped: boolean;
|
||||
reason?: string;
|
||||
subscriptionsUpserted: number;
|
||||
domainsUpserted: number;
|
||||
};
|
||||
|
||||
type InstanceRow = Pick<
|
||||
Database["public"]["Tables"]["plesk_instances"]["Row"],
|
||||
| "id"
|
||||
| "agency_id"
|
||||
| "base_url"
|
||||
| "auth_type"
|
||||
| "encrypted_secret"
|
||||
| "last_connected_at"
|
||||
>;
|
||||
|
||||
const MIN_INTERVAL_MS = 3 * 60 * 1000;
|
||||
|
||||
export async function syncPleskInstance(
|
||||
supabase: SupabaseLike,
|
||||
instance: InstanceRow,
|
||||
actorUserId?: string | null,
|
||||
action = "sync",
|
||||
): Promise<SyncResult> {
|
||||
const startedAtIso = new Date().toISOString();
|
||||
|
||||
await supabase
|
||||
.from("plesk_instances")
|
||||
.update({
|
||||
status: "syncing",
|
||||
last_sync_error: null,
|
||||
})
|
||||
.eq("id", instance.id)
|
||||
.eq("agency_id", instance.agency_id);
|
||||
|
||||
const last = instance.last_connected_at
|
||||
? new Date(instance.last_connected_at).getTime()
|
||||
: 0;
|
||||
if (last && Date.now() - last < MIN_INTERVAL_MS) {
|
||||
await supabase
|
||||
.from("plesk_instances")
|
||||
.update({
|
||||
status: "connected",
|
||||
last_sync_at: startedAtIso,
|
||||
last_sync_status: "skipped",
|
||||
last_sync_error: "recently_synced",
|
||||
})
|
||||
.eq("id", instance.id)
|
||||
.eq("agency_id", instance.agency_id);
|
||||
|
||||
return {
|
||||
instanceId: instance.id,
|
||||
agencyId: instance.agency_id,
|
||||
skipped: true,
|
||||
reason: "recently_synced",
|
||||
subscriptionsUpserted: 0,
|
||||
domainsUpserted: 0,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const [subscriptionsRaw, domainsRaw] = await Promise.all([
|
||||
listPleskSubscriptions({
|
||||
baseUrl: instance.base_url,
|
||||
authType: instance.auth_type,
|
||||
encryptedSecret: instance.encrypted_secret,
|
||||
}),
|
||||
listPleskDomains({
|
||||
baseUrl: instance.base_url,
|
||||
authType: instance.auth_type,
|
||||
encryptedSecret: instance.encrypted_secret,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionsForUpsert = subscriptionsRaw
|
||||
.map((item: any) => {
|
||||
const sourceId = item?.id ?? item?.guid ?? item?.subscription_id;
|
||||
if (!sourceId) return null;
|
||||
return {
|
||||
agency_id: instance.agency_id,
|
||||
plesk_instance_id: instance.id,
|
||||
plesk_subscription_id: String(sourceId),
|
||||
name: item?.name ? String(item.name) : null,
|
||||
status: item?.status ? String(item.status) : null,
|
||||
owner_login: item?.owner_login
|
||||
? String(item.owner_login)
|
||||
: item?.owner?.login
|
||||
? String(item.owner.login)
|
||||
: null,
|
||||
plan_name: item?.plan_name
|
||||
? String(item.plan_name)
|
||||
: item?.service_plan?.name
|
||||
? String(item.service_plan.name)
|
||||
: null,
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as Array<Record<string, unknown>>;
|
||||
|
||||
if (subscriptionsForUpsert.length > 0) {
|
||||
const { error } = await supabase
|
||||
.from("plesk_subscriptions")
|
||||
.upsert(subscriptionsForUpsert, {
|
||||
onConflict: "agency_id,plesk_subscription_id",
|
||||
});
|
||||
if (error) throw new Error(error.message);
|
||||
}
|
||||
|
||||
const domainsForUpsert = domainsRaw
|
||||
.map((item: any) => {
|
||||
const domainId = item?.id ?? item?.guid ?? item?.name;
|
||||
const domainName = item?.name ?? item?.domain_name ?? item?.domain;
|
||||
const externalSubscriptionId =
|
||||
item?.subscription?.id ?? item?.subscription_id ?? item?.webspace_id;
|
||||
const rawCreated = item?.created_at ?? item?.created;
|
||||
const sourceCreatedAt = rawCreated
|
||||
? new Date(String(rawCreated)).toISOString()
|
||||
: null;
|
||||
const aliasesCount =
|
||||
typeof item?.aliases_count === "number"
|
||||
? item.aliases_count
|
||||
: Array.isArray(item?.aliases)
|
||||
? item.aliases.length
|
||||
: null;
|
||||
|
||||
if (!domainId || !domainName) return null;
|
||||
|
||||
return {
|
||||
agency_id: instance.agency_id,
|
||||
plesk_instance_id: instance.id,
|
||||
subscription_id: null,
|
||||
external_subscription_id: externalSubscriptionId
|
||||
? String(externalSubscriptionId)
|
||||
: null,
|
||||
plesk_domain_id: String(domainId),
|
||||
domain_name: String(domainName),
|
||||
status: item?.status ? String(item.status) : null,
|
||||
hosting_type: item?.hosting_type
|
||||
? String(item.hosting_type)
|
||||
: item?.hosting?.type
|
||||
? String(item.hosting.type)
|
||||
: null,
|
||||
source_created_at: sourceCreatedAt,
|
||||
aliases_count: aliasesCount,
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as Array<Record<string, unknown>>;
|
||||
|
||||
if (domainsForUpsert.length > 0) {
|
||||
const { error } = await supabase
|
||||
.from("plesk_domains")
|
||||
.upsert(domainsForUpsert, {
|
||||
onConflict: "agency_id,plesk_domain_id",
|
||||
});
|
||||
if (error) throw new Error(error.message);
|
||||
}
|
||||
|
||||
await supabase
|
||||
.from("plesk_instances")
|
||||
.update({
|
||||
last_connected_at: new Date().toISOString(),
|
||||
status: "connected",
|
||||
error_message: null,
|
||||
last_sync_at: startedAtIso,
|
||||
last_sync_status: "success",
|
||||
last_sync_error: null,
|
||||
last_sync_subscriptions: subscriptionsForUpsert.length,
|
||||
last_sync_domains: domainsForUpsert.length,
|
||||
})
|
||||
.eq("id", instance.id)
|
||||
.eq("agency_id", instance.agency_id);
|
||||
|
||||
await supabase.from("actions_log").insert({
|
||||
agency_id: instance.agency_id,
|
||||
actor_user_id: actorUserId ?? null,
|
||||
target_type: "plesk_instance",
|
||||
target_id: instance.id,
|
||||
action,
|
||||
status: "success",
|
||||
metadata: {
|
||||
subscriptions_seen: subscriptionsRaw.length,
|
||||
domains_seen: domainsRaw.length,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
instanceId: instance.id,
|
||||
agencyId: instance.agency_id,
|
||||
skipped: false,
|
||||
subscriptionsUpserted: subscriptionsForUpsert.length,
|
||||
domainsUpserted: domainsForUpsert.length,
|
||||
};
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message.slice(0, 1000) : "Sync failed";
|
||||
|
||||
await supabase
|
||||
.from("plesk_instances")
|
||||
.update({
|
||||
status: "error",
|
||||
error_message: message,
|
||||
last_sync_at: startedAtIso,
|
||||
last_sync_status: "failed",
|
||||
last_sync_error: message,
|
||||
})
|
||||
.eq("id", instance.id)
|
||||
.eq("agency_id", instance.agency_id);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user