Compare commits

...

7 Commits

4 changed files with 47 additions and 25 deletions

View File

@@ -82,6 +82,12 @@ function isDomainActive(status: string | null) {
); );
} }
function getDomainHref(domainName: string) {
const normalized = domainName.trim();
if (/^https?:\/\//i.test(normalized)) return normalized;
return `https://${normalized}`;
}
export function DashboardControls({ export function DashboardControls({
instances, instances,
subscriptions, subscriptions,
@@ -589,7 +595,14 @@ export function DashboardControls({
filteredDomains.map((domain) => ( filteredDomains.map((domain) => (
<tr key={domain.id} className="border-b border-slate-100"> <tr key={domain.id} className="border-b border-slate-100">
<td className="px-2 py-2 font-medium text-slate-900"> <td className="px-2 py-2 font-medium text-slate-900">
<p>{domain.domain_name}</p> <a
href={getDomainHref(domain.domain_name)}
target="_blank"
rel="noopener noreferrer"
className="underline decoration-slate-300 underline-offset-2 hover:text-brand-700"
>
{domain.domain_name}
</a>
{domain.subscription_id ? ( {domain.subscription_id ? (
<p className="text-xs font-normal text-slate-500"> <p className="text-xs font-normal text-slate-500">
Subscription: {domain.subscription_id} Subscription: {domain.subscription_id}

View File

@@ -138,37 +138,24 @@ export async function testPleskConnection(connection: PleskConnection) {
} }
export async function listPleskSubscriptions(connection: PleskConnection) { export async function listPleskSubscriptions(connection: PleskConnection) {
const listOutput = await pleskCliCall(connection, "subscription", ["--list"]); const listResult = await pleskCliCall(connection, "subscription", ["--list"]);
const subscriptionNames = listOutput const subscriptionNames = (listResult.stdout ?? "")
.split(/\r?\n/) .split(/\r?\n/)
.map((line) => line.trim()) .map((line) => line.trim())
.filter(Boolean); .filter(Boolean);
const subscriptions: PleskSubscription[] = []; const subscriptions: PleskSubscription[] = [];
for (const subscriptionName of subscriptionNames) { for (const subscriptionName of subscriptionNames.slice(0, 500)) {
let status = "unknown"; let status: "active" | "suspended" | "unknown" = "unknown";
try { try {
const infoOutput = await pleskCliCall(connection, "subscription", [ const infoResult = await pleskCliCall(connection, "subscription", [
"--info", "--info",
subscriptionName, subscriptionName,
]); ]);
const normalizedInfo = infoOutput.toLowerCase(); status = parseSubscriptionStatusFromInfo(infoResult.stdout ?? "");
const hasSuspendedMarker =
normalizedInfo.includes("suspended") ||
normalizedInfo.includes("webspace-off") ||
normalizedInfo.includes("disabled");
const hasActiveMarker =
normalizedInfo.includes("active") ||
normalizedInfo.includes("enabled") ||
normalizedInfo.includes("ok");
if (hasSuspendedMarker) status = "suspended";
else if (hasActiveMarker || !hasSuspendedMarker) status = "active";
} catch { } catch {
status = "unknown"; status = "unknown";
} }
@@ -184,6 +171,29 @@ export async function listPleskSubscriptions(connection: PleskConnection) {
return subscriptions; return subscriptions;
} }
export function parseSubscriptionStatusFromInfo(
stdout: string,
): "active" | "suspended" | "unknown" {
const line = stdout
.split(/\r?\n/)
.map((entry) => entry.trim())
.find((entry) => /^domain\s+status\s*:/i.test(entry));
if (!line) return "unknown";
const value = line
.replace(/^domain\s+status\s*:/i, "")
.trim()
.toLowerCase();
if (value.includes("ok")) return "active";
if (value.includes("suspend") || value.includes("disabled")) {
return "suspended";
}
return "unknown";
}
export async function pleskCliCall( export async function pleskCliCall(
connection: PleskConnection, connection: PleskConnection,
command: string, command: string,
@@ -208,7 +218,7 @@ export async function pleskCliCall(
); );
} }
return stdout; return { code, stdout, stderr };
} }
export async function listPleskDomains(connection: PleskConnection) { export async function listPleskDomains(connection: PleskConnection) {

View File

@@ -94,7 +94,7 @@ export async function syncPleskInstance(
plesk_instance_id: instance.id, plesk_instance_id: instance.id,
plesk_subscription_id: String(sourceId), plesk_subscription_id: String(sourceId),
name: item?.name ? String(item.name) : String(sourceId), name: item?.name ? String(item.name) : String(sourceId),
status: item?.status ? String(item.status) : null, status: item?.status ? String(item.status) : "unknown",
owner_login: item?.owner_login owner_login: item?.owner_login
? String(item.owner_login) ? String(item.owner_login)
: item?.owner?.login : item?.owner?.login

View File

@@ -1,10 +1,9 @@
-- One-time backfill: align existing domain status with linked subscription status -- One-time backfill: align existing domain status with linked subscription status
update public.plesk_domains d update public.plesk_domains d
set status = s.status set status = coalesce(s.status, 'unknown')
from public.plesk_subscriptions s from public.plesk_subscriptions s
where d.subscription_id = s.id where d.subscription_id = s.id
and d.agency_id = s.agency_id and d.agency_id = s.agency_id;
and (d.status is null or d.status = 'unknown');
update public.plesk_subscriptions update public.plesk_subscriptions
set status = 'unknown' set status = 'unknown'