Files
wevads-platform/scripts/namecheap-setup.php
2026-02-26 04:53:11 +01:00

717 lines
28 KiB
PHP
Executable File

<?php
/**
* WEVAL Namecheap Setup
* - Stocker credentials
* - Activer API et récupérer domaines
* - Configurer DNS tracking
*/
session_start();
function getDB() {
static $pdo = null;
if ($pdo === null) {
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
}
return $pdo;
}
function getServerIP() {
return trim(file_get_contents('https://api.ipify.org') ?: '89.167.40.150');
}
function namecheapAPI($command, $params, $username, $apiKey) {
$baseUrl = "https://api.namecheap.com/xml.response";
$defaultParams = [
'ApiUser' => $username,
'ApiKey' => $apiKey,
'UserName' => $username,
'ClientIp' => getServerIP(),
'Command' => $command
];
$allParams = array_merge($defaultParams, $params);
$url = $baseUrl . '?' . http_build_query($allParams);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return ['success' => false, 'error' => $error];
}
$xml = @simplexml_load_string($response);
if (!$xml) {
return ['success' => false, 'error' => 'Invalid XML response'];
}
$status = (string)$xml['Status'];
if ($status === 'ERROR') {
$errors = [];
foreach ($xml->Errors->Error as $err) {
$errors[] = (string)$err;
}
return ['success' => false, 'error' => implode(', ', $errors)];
}
return ['success' => true, 'xml' => $xml, 'raw' => $response];
}
// Créer la table si nécessaire
function ensureTable() {
$pdo = getDB();
$pdo->exec("
CREATE TABLE IF NOT EXISTS admin.namecheap_accounts (
id SERIAL PRIMARY KEY,
username VARCHAR(255) NOT NULL,
password VARCHAR(255),
api_key VARCHAR(255),
api_user VARCHAR(255),
whitelisted_ip VARCHAR(50),
status VARCHAR(50) DEFAULT 'pending',
domains_count INTEGER DEFAULT 0,
last_sync TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(username)
);
CREATE TABLE IF NOT EXISTS admin.namecheap_domains (
id SERIAL PRIMARY KEY,
account_id INTEGER,
domain VARCHAR(255) NOT NULL,
expires_at DATE,
is_locked BOOLEAN DEFAULT FALSE,
auto_renew BOOLEAN DEFAULT FALSE,
nameservers TEXT,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(domain)
);
");
}
// AJAX Handler
if (isset($_REQUEST['action'])) {
header('Content-Type: application/json');
ensureTable();
$pdo = getDB();
switch ($_REQUEST['action']) {
case 'get_ip':
echo json_encode(['ip' => getServerIP()]);
break;
case 'accounts':
$stmt = $pdo->query("
SELECT id, username, password, api_key IS NOT NULL AND api_key != '' as has_api,
whitelisted_ip, status, domains_count, last_sync
FROM admin.namecheap_accounts
ORDER BY id
");
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
break;
case 'add_account':
$username = trim($_POST['username'] ?? '');
$password = trim($_POST['password'] ?? '');
if (!$username) {
echo json_encode(['success' => false, 'error' => 'Username required']);
break;
}
$stmt = $pdo->prepare("
INSERT INTO admin.namecheap_accounts (username, password, status)
VALUES (?, ?, 'pending')
ON CONFLICT (username) DO UPDATE SET password = EXCLUDED.password
RETURNING id
");
$stmt->execute([$username, $password]);
$id = $stmt->fetchColumn();
echo json_encode(['success' => true, 'id' => $id]);
break;
case 'save_api':
$id = $_POST['id'] ?? 0;
$apiKey = trim($_POST['api_key'] ?? '');
$apiUser = trim($_POST['api_user'] ?? '');
$stmt = $pdo->prepare("
UPDATE admin.namecheap_accounts
SET api_key = ?, api_user = COALESCE(NULLIF(?, ''), username),
whitelisted_ip = ?, status = 'active'
WHERE id = ?
");
$stmt->execute([$apiKey, $apiUser, getServerIP(), $id]);
echo json_encode(['success' => true]);
break;
case 'test_api':
$username = $_POST['username'] ?? '';
$apiKey = $_POST['api_key'] ?? '';
$apiUser = $_POST['api_user'] ?? $username;
$result = namecheapAPI('namecheap.domains.getList', ['PageSize' => 1], $apiUser, $apiKey);
echo json_encode($result);
break;
case 'fetch_domains':
$id = $_POST['id'] ?? 0;
$stmt = $pdo->prepare("SELECT username, api_key, api_user FROM admin.namecheap_accounts WHERE id = ?");
$stmt->execute([$id]);
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$acc || !$acc['api_key']) {
echo json_encode(['success' => false, 'error' => 'No API key']);
break;
}
$apiUser = $acc['api_user'] ?: $acc['username'];
$result = namecheapAPI('namecheap.domains.getList', ['PageSize' => 100], $apiUser, $acc['api_key']);
if (!$result['success']) {
echo json_encode($result);
break;
}
$domains = [];
$xml = $result['xml'];
if (isset($xml->CommandResponse->DomainGetListResult->Domain)) {
foreach ($xml->CommandResponse->DomainGetListResult->Domain as $domain) {
$domainName = (string)$domain['Name'];
$expires = (string)$domain['Expires'];
$isLocked = ((string)$domain['IsLocked']) === 'true';
$autoRenew = ((string)$domain['AutoRenew']) === 'true';
// Insert into namecheap_domains
$stmt = $pdo->prepare("
INSERT INTO admin.namecheap_domains (account_id, domain, expires_at, is_locked, auto_renew)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (domain) DO UPDATE SET
expires_at = EXCLUDED.expires_at,
is_locked = EXCLUDED.is_locked,
auto_renew = EXCLUDED.auto_renew
");
$stmt->execute([$id, $domainName, $expires, $isLocked, $autoRenew]);
// Also add to domains_pool
$stmt = $pdo->prepare("
INSERT INTO admin.domains_pool (domain, provider, status)
VALUES (?, 'namecheap', 'FREE')
ON CONFLICT DO NOTHING
");
$stmt->execute([$domainName]);
$domains[] = [
'domain' => $domainName,
'expires' => $expires,
'locked' => $isLocked
];
}
}
// Update account
$pdo->prepare("UPDATE admin.namecheap_accounts SET domains_count = ?, last_sync = NOW() WHERE id = ?")
->execute([count($domains), $id]);
echo json_encode(['success' => true, 'domains' => $domains, 'count' => count($domains)]);
break;
case 'get_domains':
$id = $_POST['id'] ?? 0;
$stmt = $pdo->prepare("SELECT domain, expires_at, is_locked, auto_renew FROM admin.namecheap_domains WHERE account_id = ? ORDER BY domain");
$stmt->execute([$id]);
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
break;
case 'get_dns':
$id = $_POST['account_id'] ?? 0;
$domain = $_POST['domain'] ?? '';
$stmt = $pdo->prepare("SELECT api_key, api_user, username FROM admin.namecheap_accounts WHERE id = ?");
$stmt->execute([$id]);
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$acc || !$acc['api_key']) {
echo json_encode(['success' => false, 'error' => 'No API key']);
break;
}
// Split domain into SLD and TLD
$parts = explode('.', $domain);
$tld = array_pop($parts);
$sld = implode('.', $parts);
$apiUser = $acc['api_user'] ?: $acc['username'];
$result = namecheapAPI('namecheap.domains.dns.getHosts', [
'SLD' => $sld,
'TLD' => $tld
], $apiUser, $acc['api_key']);
if (!$result['success']) {
echo json_encode($result);
break;
}
$records = [];
if (isset($result['xml']->CommandResponse->DomainDNSGetHostsResult->host)) {
foreach ($result['xml']->CommandResponse->DomainDNSGetHostsResult->host as $host) {
$records[] = [
'id' => (string)$host['HostId'],
'name' => (string)$host['Name'],
'type' => (string)$host['Type'],
'address' => (string)$host['Address'],
'ttl' => (string)$host['TTL']
];
}
}
echo json_encode(['success' => true, 'records' => $records]);
break;
case 'set_dns':
$id = $_POST['account_id'] ?? 0;
$domain = $_POST['domain'] ?? '';
$ip = $_POST['ip'] ?? '151.80.235.110';
$stmt = $pdo->prepare("SELECT api_key, api_user, username FROM admin.namecheap_accounts WHERE id = ?");
$stmt->execute([$id]);
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$acc || !$acc['api_key']) {
echo json_encode(['success' => false, 'error' => 'No API key']);
break;
}
// Split domain
$parts = explode('.', $domain);
$tld = array_pop($parts);
$sld = implode('.', $parts);
$apiUser = $acc['api_user'] ?: $acc['username'];
// First get existing records
$existing = namecheapAPI('namecheap.domains.dns.getHosts', [
'SLD' => $sld,
'TLD' => $tld
], $apiUser, $acc['api_key']);
// Build new records array (keep existing + add/update @ A record)
$params = [
'SLD' => $sld,
'TLD' => $tld
];
$recordNum = 1;
$foundRoot = false;
if ($existing['success'] && isset($existing['xml']->CommandResponse->DomainDNSGetHostsResult->host)) {
foreach ($existing['xml']->CommandResponse->DomainDNSGetHostsResult->host as $host) {
$name = (string)$host['Name'];
$type = (string)$host['Type'];
// Skip root A record (we'll add our own)
if ($name === '@' && $type === 'A') {
continue;
}
$params["HostName{$recordNum}"] = $name;
$params["RecordType{$recordNum}"] = $type;
$params["Address{$recordNum}"] = (string)$host['Address'];
$params["TTL{$recordNum}"] = (string)$host['TTL'];
$recordNum++;
}
}
// Add our tracking A record
$params["HostName{$recordNum}"] = '@';
$params["RecordType{$recordNum}"] = 'A';
$params["Address{$recordNum}"] = $ip;
$params["TTL{$recordNum}"] = '300';
$result = namecheapAPI('namecheap.domains.dns.setHosts', $params, $apiUser, $acc['api_key']);
if ($result['success']) {
// Update domains_pool
$pdo->prepare("UPDATE admin.domains_pool SET status = 'TRACKING', usage_type = 'tracking', tracking_ip = ? WHERE domain = ?")
->execute([$ip, $domain]);
}
echo json_encode($result);
break;
case 'delete_account':
$id = $_POST['id'] ?? 0;
$pdo->prepare("DELETE FROM admin.namecheap_domains WHERE account_id = ?")->execute([$id]);
$pdo->prepare("DELETE FROM admin.namecheap_accounts WHERE id = ?")->execute([$id]);
echo json_encode(['success' => true]);
break;
}
exit;
}
ensureTable();
$serverIP = getServerIP();
?>
<!DOCTYPE html>
<html>
<head>
<title>WEVAL | Namecheap Setup</title>
<link href="plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<style>
body { background: #0a0e17; color: #f1f5f9; font-family: 'Segoe UI', sans-serif; }
.container-main { max-width: 1400px; margin: 30px auto; padding: 20px; }
.card-dark { background: #1a2332; border: 1px solid #2a3a50; border-radius: 12px; margin-bottom: 20px; }
.card-header { background: #111827; border-bottom: 1px solid #2a3a50; padding: 15px 20px; font-weight: 600; }
.card-body { padding: 20px; }
.form-control-dark { background: #0d1219; border: 1px solid #2a3a50; color: #fff; border-radius: 8px; padding: 10px; width: 100%; margin-bottom: 10px; }
.form-control-dark:focus { border-color: #f97316; outline: none; }
.btn-cyber { padding: 8px 16px; border-radius: 8px; font-weight: 600; border: none; cursor: pointer; margin: 2px; }
.btn-primary-cyber { background: linear-gradient(135deg, #f97316, #ea580c); color: #fff; }
.btn-success-cyber { background: linear-gradient(135deg, #10b981, #059669); color: #fff; }
.btn-warning-cyber { background: linear-gradient(135deg, #f59e0b, #d97706); color: #000; }
.btn-danger-cyber { background: linear-gradient(135deg, #ef4444, #dc2626); color: #fff; }
.btn-info-cyber { background: linear-gradient(135deg, #3b82f6, #2563eb); color: #fff; }
table { width: 100%; border-collapse: collapse; }
th { color: #64748b; font-weight: 500; padding: 10px; text-align: left; border-bottom: 1px solid #2a3a50; }
td { padding: 10px; border-bottom: 1px solid #1e293b; font-size: 13px; }
.badge { padding: 4px 10px; border-radius: 12px; font-size: 11px; }
.badge-ok { background: #10b981; color: #fff; }
.badge-warn { background: #f59e0b; color: #000; }
.badge-error { background: #ef4444; color: #fff; }
.badge-nc { background: #f97316; color: #fff; }
h1 { color: #f97316; margin-bottom: 5px; }
.subtitle { color: #64748b; margin-bottom: 25px; }
code { background: #0d1219; padding: 2px 6px; border-radius: 4px; color: #f97316; }
.info-box { background: rgba(249,115,22,0.1); border: 1px solid rgba(249,115,22,0.3); border-radius: 8px; padding: 15px; margin-bottom: 20px; }
.info-box h4 { color: #f97316; margin-bottom: 10px; }
.step { background: #111827; border-radius: 8px; padding: 15px; margin-bottom: 10px; }
.step-num { display: inline-block; width: 28px; height: 28px; background: #f97316; color: #fff; border-radius: 50%; text-align: center; line-height: 28px; margin-right: 10px; font-weight: 600; }
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 1000; }
.modal-content { background: #1a2332; border-radius: 12px; max-width: 700px; margin: 50px auto; padding: 25px; max-height: 80vh; overflow-y: auto; }
.modal-header { display: flex; justify-content: space-between; margin-bottom: 20px; }
.modal-close { background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; }
.domain-item { background: #111827; padding: 10px 15px; border-radius: 6px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
.copy-btn { cursor: pointer; color: #64748b; }
.copy-btn:hover { color: #f97316; }
</style>
</head>
<body>
<div class="container-main">
<h1><i class="fa fa-globe"></i> Namecheap Setup</h1>
<p class="subtitle">Configurer les comptes Namecheap et récupérer les domaines</p>
<div class="info-box">
<h4><i class="fa fa-info-circle"></i> Comment activer l'API Namecheap</h4>
<div class="step">
<span class="step-num">1</span>
Connectez-vous sur <a href="https://www.namecheap.com/myaccount/login" target="_blank" style="color:#f97316;">namecheap.com</a>
</div>
<div class="step">
<span class="step-num">2</span>
Allez dans <strong>Profile → Tools → API Access</strong>
</div>
<div class="step">
<span class="step-num">3</span>
Activez l'API et ajoutez cette IP dans la whitelist: <code id="server-ip"><?= $serverIP ?></code>
<i class="fa fa-copy copy-btn" onclick="copyIP()"></i>
</div>
<div class="step">
<span class="step-num">4</span>
Copiez l'<strong>API Key</strong> générée
</div>
</div>
<!-- Add Account -->
<div class="card-dark">
<div class="card-header"><i class="fa fa-plus"></i> Ajouter un compte</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<input type="text" class="form-control form-control-dark" id="new-username" placeholder="Username Namecheap">
</div>
<div class="col-md-4">
<input type="password" class="form-control form-control-dark" id="new-password" placeholder="Password (optionnel)">
</div>
<div class="col-md-4">
<button class="btn btn-cyber btn-primary-cyber" onclick="addAccount()"><i class="fa fa-plus"></i> Ajouter</button>
</div>
</div>
</div>
</div>
<!-- Accounts List -->
<div class="card-dark">
<div class="card-header">
<i class="fa fa-list"></i> Comptes Namecheap
<button class="btn btn-cyber btn-primary-cyber btn-sm float-right" onclick="loadAccounts()"><i class="fa fa-refresh"></i></button>
</div>
<div class="card-body">
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Password</th>
<th>API</th>
<th>Whitelisted IP</th>
<th>Domains</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="accounts-table"></tbody>
</table>
</div>
</div>
<!-- Quick DNS Setup -->
<div class="card-dark">
<div class="card-header"><i class="fa fa-crosshairs"></i> Quick Tracking DNS</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<label>Account ID</label>
<input type="number" class="form-control form-control-dark" id="dns-account" value="1">
</div>
<div class="col-md-4">
<label>Domain</label>
<input type="text" class="form-control form-control-dark" id="dns-domain" placeholder="example.com">
</div>
<div class="col-md-3">
<label>Tracking IP</label>
<input type="text" class="form-control form-control-dark" id="dns-ip" value="151.80.235.110">
</div>
<div class="col-md-2">
<label>&nbsp;</label>
<button class="btn btn-cyber btn-success-cyber" style="width:100%" onclick="setDNS()"><i class="fa fa-save"></i> Set</button>
</div>
</div>
<div id="dns-result" class="mt-3"></div>
</div>
</div>
</div>
<!-- Modal API Key -->
<div class="modal" id="modal-api">
<div class="modal-content">
<div class="modal-header">
<h4><i class="fa fa-key"></i> Configure API Key</h4>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
<div id="modal-body">
<p>Username: <strong id="modal-username"></strong></p>
<p>Password: <code id="modal-password"></code></p>
<p style="color:#f97316"><i class="fa fa-exclamation-triangle"></i> N'oubliez pas d'ajouter <code><?= $serverIP ?></code> dans la whitelist API!</p>
<div class="form-group">
<label>API User (généralement = username)</label>
<input type="text" class="form-control form-control-dark" id="modal-apiuser" placeholder="Laisser vide si = username">
</div>
<div class="form-group">
<label>API Key</label>
<input type="text" class="form-control form-control-dark" id="modal-apikey" placeholder="Coller l'API Key ici">
</div>
<button class="btn btn-cyber btn-success-cyber" onclick="saveApiKey()"><i class="fa fa-check"></i> Test & Save</button>
<span id="modal-status" class="ml-3"></span>
</div>
</div>
</div>
<!-- Modal Domains -->
<div class="modal" id="modal-domains">
<div class="modal-content">
<div class="modal-header">
<h4><i class="fa fa-globe"></i> Domaines</h4>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
<div id="domains-list"></div>
</div>
</div>
<script src="plugins/jquery.min.js"></script>
<script>
var currentAccountId = 0;
function copyIP() {
navigator.clipboard.writeText($('#server-ip').text());
alert('IP copiée!');
}
function loadAccounts() {
$.post('?action=accounts', function(data) {
var html = '';
data.forEach(function(a) {
var apiStatus = a.has_api ? '<span class="badge badge-ok">✓</span>' : '<span class="badge badge-error">✗</span>';
html += '<tr>';
html += '<td>' + a.id + '</td>';
html += '<td><span class="badge badge-nc"><i class="fa fa-globe"></i></span> ' + a.username + '</td>';
html += '<td><code>' + (a.password || '-') + '</code></td>';
html += '<td>' + apiStatus + '</td>';
html += '<td>' + (a.whitelisted_ip || '-') + '</td>';
html += '<td>' + a.domains_count + '</td>';
html += '<td>';
html += '<button class="btn btn-cyber btn-primary-cyber btn-sm" onclick="openApiModal(' + a.id + ',\'' + a.username + '\',\'' + (a.password||'') + '\')"><i class="fa fa-key"></i></button> ';
if (a.has_api) {
html += '<button class="btn btn-cyber btn-warning-cyber btn-sm" onclick="fetchDomains(' + a.id + ')"><i class="fa fa-download"></i></button> ';
html += '<button class="btn btn-cyber btn-info-cyber btn-sm" onclick="viewDomains(' + a.id + ')"><i class="fa fa-list"></i></button> ';
}
html += '<button class="btn btn-cyber btn-danger-cyber btn-sm" onclick="deleteAccount(' + a.id + ')"><i class="fa fa-trash"></i></button>';
html += '</td>';
html += '</tr>';
});
$('#accounts-table').html(html || '<tr><td colspan="7">Aucun compte</td></tr>');
});
}
function addAccount() {
var username = $('#new-username').val().trim();
var password = $('#new-password').val().trim();
if (!username) return alert('Username requis');
$.post('?action=add_account', {username: username, password: password}, function(r) {
if (r.success) {
$('#new-username').val('');
$('#new-password').val('');
loadAccounts();
alert('Compte ajouté! Configurez maintenant l\'API key.');
} else {
alert('Erreur: ' + r.error);
}
});
}
function openApiModal(id, username, password) {
currentAccountId = id;
$('#modal-username').text(username);
$('#modal-password').text(password || '-');
$('#modal-apiuser').val('');
$('#modal-apikey').val('');
$('#modal-status').html('');
$('#modal-api').show();
}
function closeModal() {
$('.modal').hide();
}
function saveApiKey() {
var apiKey = $('#modal-apikey').val().trim();
var apiUser = $('#modal-apiuser').val().trim() || $('#modal-username').text();
if (!apiKey) return alert('API Key requise');
$('#modal-status').html('<i class="fa fa-spinner fa-spin"></i> Test en cours...');
$.post('?action=test_api', {
username: apiUser,
api_key: apiKey,
api_user: apiUser
}, function(r) {
if (r.success) {
$.post('?action=save_api', {
id: currentAccountId,
api_key: apiKey,
api_user: apiUser
}, function() {
$('#modal-status').html('<span style="color:#10b981"><i class="fa fa-check"></i> Sauvegardé!</span>');
setTimeout(function() {
closeModal();
loadAccounts();
}, 1000);
});
} else {
$('#modal-status').html('<span style="color:#ef4444"><i class="fa fa-times"></i> ' + (r.error || 'API invalide') + '</span>');
}
});
}
function fetchDomains(id) {
if (!confirm('Récupérer tous les domaines?')) return;
$.post('?action=fetch_domains', {id: id}, function(r) {
if (r.success) {
alert('Importé: ' + r.count + ' domaines');
loadAccounts();
} else {
alert('Erreur: ' + r.error);
}
});
}
function viewDomains(id) {
$.post('?action=get_domains', {id: id}, function(data) {
var html = '';
data.forEach(function(d) {
html += '<div class="domain-item">';
html += '<div><strong>' + d.domain + '</strong><br><small style="color:#64748b">Expire: ' + (d.expires_at || 'N/A') + '</small></div>';
html += '<div>';
html += '<button class="btn btn-cyber btn-success-cyber btn-sm" onclick="setTrackingDomain(\'' + d.domain + '\',' + id + ')"><i class="fa fa-crosshairs"></i></button>';
html += '</div>';
html += '</div>';
});
$('#domains-list').html(html || '<p>Aucun domaine</p>');
$('#modal-domains').show();
});
}
function setTrackingDomain(domain, accountId) {
closeModal();
$('#dns-domain').val(domain);
$('#dns-account').val(accountId);
}
function deleteAccount(id) {
if (!confirm('Supprimer ce compte?')) return;
$.post('?action=delete_account', {id: id}, function() {
loadAccounts();
});
}
function setDNS() {
var domain = $('#dns-domain').val().trim();
var ip = $('#dns-ip').val().trim();
var accountId = $('#dns-account').val();
if (!domain) return alert('Domain requis');
$('#dns-result').html('<i class="fa fa-spinner fa-spin"></i> Configuration DNS...');
$.post('?action=set_dns', {
account_id: accountId,
domain: domain,
ip: ip
}, function(r) {
if (r.success) {
$('#dns-result').html('<span style="color:#10b981"><i class="fa fa-check"></i> DNS configuré: ' + domain + ' → ' + ip + '</span>');
} else {
$('#dns-result').html('<span style="color:#ef4444"><i class="fa fa-times"></i> Erreur: ' + (r.error || 'Failed') + '</span>');
}
});
}
$(document).ready(function() {
loadAccounts();
});
</script>
</body>
</html>