Entrega read-only de apontamentos DNS (Cloudflare, OpenPanel BIND, público) no Desk e Console /admin/dominio, com spec, scripts de rollback e patches VM112 para painel lateral no passo DNS do onboarding (deploy wizard pendente). Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
6.3 KiB
Python
165 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Frontend Spec 037b — provision-zone cria zona cliente na CF Ligbox."""
|
|
from pathlib import Path
|
|
|
|
APP = Path("/opt/ligbox-wizard/frontend/src/App.jsx")
|
|
text = APP.read_text(encoding="utf-8")
|
|
|
|
OLD = """ async function choosePortalDns() {
|
|
setDnsChoice('portal')
|
|
setError(null)
|
|
startBusy('dns_zone')
|
|
try {
|
|
const resolved = dnsResolve || (await api(`/onboarding/dns/resolve/${domain}`))
|
|
setDnsResolve(resolved)
|
|
if (!resolved.matched) {
|
|
throw new Error(
|
|
resolved.message ||
|
|
'Domínio não está nas contas Ligbox (ligit, itecnologys, ibytera).',
|
|
)
|
|
}
|
|
const cf = await refreshCfStatus()
|
|
setCfStatus(cf)
|
|
markActionDone('choosePortalDns')
|
|
markActionDone('verifyZone')
|
|
const data = await api('/onboarding/dns/cloudflare/apply', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
domain,
|
|
zone_id: resolved.zone_id,
|
|
mail_aliases: sanitizeMailAliases(mailAliasInputs, domain),
|
|
}),
|
|
})
|
|
setPortalGuide({
|
|
message: resolved.message,
|
|
nameservers: cf?.nameservers || [],
|
|
status: cf,
|
|
ligbox_account_id: resolved.account_id,
|
|
})
|
|
setVerification(data.verification)
|
|
setResult({ type: 'dns', data })
|
|
markActionDone('applyPortalDns')
|
|
} catch (e) {
|
|
setError(e.message)
|
|
setDnsChoice(null)
|
|
setActionsDone((prev) => ({ ...prev, choosePortalDns: false }))
|
|
} finally {
|
|
stopBusy()
|
|
}
|
|
}"""
|
|
|
|
NEW = """ async function choosePortalDns() {
|
|
setDnsChoice('portal')
|
|
setError(null)
|
|
startBusy('dns_zone')
|
|
try {
|
|
const resolved = dnsResolve || (await api(`/onboarding/dns/resolve/${domain}`))
|
|
setDnsResolve(resolved)
|
|
const guide = await api('/onboarding/dns/cloudflare/provision-zone', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ domain }),
|
|
})
|
|
setPortalGuide(guide)
|
|
const cf = guide.status || (await refreshCfStatus())
|
|
setCfStatus(cf)
|
|
markActionDone('choosePortalDns')
|
|
if (guide.verification) {
|
|
setVerification(guide.verification)
|
|
setResult({ type: 'dns', data: { verification: guide.verification } })
|
|
markActionDone('verifyZone')
|
|
markActionDone('applyPortalDns')
|
|
} else if (cf?.zone_in_account && cf?.can_apply_mail_records) {
|
|
markActionDone('verifyZone')
|
|
const data = await api('/onboarding/dns/cloudflare/apply', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
domain,
|
|
zone_id: guide.zone_id || resolved.zone_id,
|
|
mail_aliases: sanitizeMailAliases(mailAliasInputs, domain),
|
|
}),
|
|
})
|
|
setVerification(data.verification)
|
|
setResult({ type: 'dns', data })
|
|
markActionDone('applyPortalDns')
|
|
}
|
|
} catch (e) {
|
|
setError(e.message)
|
|
setDnsChoice(null)
|
|
setActionsDone((prev) => ({ ...prev, choosePortalDns: false }))
|
|
} finally {
|
|
stopBusy()
|
|
}
|
|
}"""
|
|
|
|
if "provision-zone" in text and "if (!resolved.matched)" in text:
|
|
text = text.replace(OLD, NEW)
|
|
print("choosePortalDns restored with provision-zone")
|
|
|
|
# Auto mode: allow for new domains too
|
|
text = text.replace(
|
|
" const resolve = instructions?.resolve || dnsResolve\n if (resolve && !resolve.matched) return\n autoDnsAttempted.current = true",
|
|
" autoDnsAttempted.current = true",
|
|
)
|
|
|
|
# Ligbox button always enabled when can provision
|
|
text = text.replace(
|
|
""" label={
|
|
dnsResolve?.matched
|
|
? `Cloudflare Ligbox (${dnsResolve.account_id})`
|
|
: 'Cloudflare Ligbox (indisponível)'
|
|
}
|
|
hint={
|
|
dnsResolve?.matched
|
|
? dnsResolve.message
|
|
: 'Domínio não está nas contas ligit / itecnologys / ibytera.'
|
|
}
|
|
disabled={
|
|
loading ||
|
|
actionsDone.chooseExternalDns ||
|
|
actionsDone.chooseByoDns ||
|
|
!dnsResolve?.matched
|
|
}""",
|
|
""" label={
|
|
dnsResolve?.matched
|
|
? `Cloudflare Ligbox (${dnsResolve.account_id})`
|
|
: `Cloudflare Ligbox (${dnsResolve?.provision_account_id || 'nova zona'})`
|
|
}
|
|
hint={
|
|
dnsResolve?.matched
|
|
? dnsResolve.message
|
|
: 'Criar zona do seu domínio na Cloudflare gerenciada pela Ligbox.'
|
|
}
|
|
disabled={
|
|
loading ||
|
|
actionsDone.chooseExternalDns ||
|
|
actionsDone.chooseByoDns ||
|
|
dnsResolve?.can_provision_ligbox === false
|
|
}""",
|
|
)
|
|
|
|
# Simple mode warning
|
|
text = text.replace(
|
|
""" {!dnsResolve?.matched && !portalDnsApplied && (
|
|
<WizardStatusPanel variant="warn" icon={ShieldCheck} title="Escolha como apontar o DNS">
|
|
<p>
|
|
Este domínio não está nas contas Cloudflare Ligbox. Use{' '}
|
|
<strong>Minha conta Cloudflare</strong> ou{' '}
|
|
<strong>Registrador / DNS externo</strong> (botão técnico abaixo).
|
|
</p>
|
|
</WizardStatusPanel>
|
|
)}""",
|
|
""" {!dnsResolve?.matched && !portalDnsApplied && (
|
|
<WizardStatusPanel variant="info" icon={ShieldCheck} title="Domínio novo na Cloudflare Ligbox">
|
|
<p>
|
|
Vamos criar a zona do seu domínio na Cloudflare gerenciada pela Ligbox
|
|
{dnsResolve?.provision_account_id
|
|
? ` (conta ${dnsResolve.provision_account_id})`
|
|
: ''}
|
|
. Depois altere os nameservers no registrador.
|
|
</p>
|
|
</WizardStatusPanel>
|
|
)}""",
|
|
)
|
|
|
|
APP.write_text(text, encoding="utf-8")
|
|
print("App.jsx 037b patched OK")
|