feat: Let's Encrypt SSL on site creation
This commit is contained in:
@@ -68,6 +68,11 @@ const baseCSS = `
|
||||
.badge { display: inline-block; padding: .15rem .5rem; border-radius: 999px; font-size: .75rem; background: #14532d; color: #bbf7d0; }
|
||||
.center-card { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1rem; }
|
||||
.center-card .card { width: 100%; max-width: 420px; }
|
||||
label.check { display: flex; align-items: center; gap: .5rem; margin-bottom: 1rem; font-size: .9rem; color: #cbd5e1; }
|
||||
label.check input { width: auto; margin: 0; }
|
||||
.badge.ssl-pending { background: #713f12; color: #fde68a; }
|
||||
.badge.ssl-active { background: #14532d; color: #bbf7d0; }
|
||||
.badge.ssl-error { background: #7f1d1d; color: #fecaca; }
|
||||
`
|
||||
|
||||
const setupPageHTML = `<!DOCTYPE html>
|
||||
@@ -119,17 +124,20 @@ func dashboardPageHTML(username string) string {
|
||||
<div><label>Имя сайта</label><input id="name" required pattern="[a-z0-9][a-z0-9-]{1,62}[a-z0-9]" placeholder="mysite"></div>
|
||||
<div><label>Домен</label><input id="domain" required placeholder="example.com"></div>
|
||||
</div><label>PHP версия</label><select id="php_version" required></select>
|
||||
<label class="check"><input type="checkbox" id="issue_ssl" checked> Выпустить SSL (Let's Encrypt)</label>
|
||||
<button type="submit" id="createBtn">Создать сайт</button></form>
|
||||
<div id="formMsg" class="msg"></div></div>
|
||||
<div class="card"><h2>Сайты</h2>
|
||||
<table><thead><tr><th>Имя</th><th>Домен</th><th>PHP</th><th>Статус</th><th>Путь</th></tr></thead>
|
||||
<table><thead><tr><th>Имя</th><th>Домен</th><th>PHP</th><th>SSL</th><th>Статус</th><th>Путь</th><th></th></tr></thead>
|
||||
<tbody id="sites"></tbody></table></div>
|
||||
</div>
|
||||
<script>
|
||||
async function loadPHP(){const fallback=['8.1','8.2','8.3','8.4'];let versions=fallback;try{const r=await fetch('/api/v1/php-versions');const d=await r.json();if(r.ok&&d.versions&&d.versions.length)versions=d.versions;}catch(e){}const s=document.getElementById('php_version');s.innerHTML='';versions.forEach(v=>{const o=document.createElement('option');o.value=v;o.textContent='PHP '+v;s.appendChild(o);});if(versions.length)s.value=versions[versions.length-1];}
|
||||
async function loadSites(){const r=await fetch('/api/v1/sites');const d=await r.json();const tb=document.getElementById('sites');tb.innerHTML='';
|
||||
(d.sites||[]).forEach(site=>{const tr=document.createElement('tr');
|
||||
tr.innerHTML='<td>'+site.name+'</td><td>'+site.primary_domain+'</td><td>'+(site.php_version||'-')+'</td><td><span class="badge">'+site.status+'</span></td><td><code>'+site.document_root+'</code></td>';
|
||||
(d.sites||[]).forEach(site=>{const tr=document.createElement('tr');const ssl=site.ssl_status||'none';const sslCls=ssl==='active'?'ssl-active':(ssl==='error'?'ssl-error':'ssl-pending');
|
||||
let actions='';if(ssl==='error'||ssl==='pending'){actions='<button class="secondary" data-id="'+site.id+'">SSL</button>';}
|
||||
tr.innerHTML='<td>'+site.name+'</td><td>'+site.primary_domain+'</td><td>'+(site.php_version||'-')+'</td><td><span class="badge '+sslCls+'">'+ssl+'</span></td><td><span class="badge">'+site.status+'</span></td><td><code>'+site.document_root+'</code></td><td>'+actions+'</td>';
|
||||
if(actions){tr.querySelector('button').onclick=async()=>{await fetch('/api/v1/sites/'+site.id+'/ssl/issue',{method:'POST'});setTimeout(loadSites,2000);};}
|
||||
tb.appendChild(tr);});}
|
||||
document.getElementById('logout').onclick=async()=>{await fetch('/api/v1/auth/logout',{method:'POST'});location.reload();};
|
||||
document.getElementById('siteForm').onsubmit=async e=>{
|
||||
@@ -138,7 +146,7 @@ const btn=document.getElementById('createBtn'),msg=document.getElementById('form
|
||||
const siteName=document.getElementById('name'),siteDomain=document.getElementById('domain'),phpSelect=document.getElementById('php_version');
|
||||
btn.disabled=true;msg.className='msg';msg.textContent='';
|
||||
try{
|
||||
const res=await fetch('/api/v1/sites',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:siteName.value.trim().toLowerCase(),domain:siteDomain.value.trim().toLowerCase(),php_version:phpSelect.value})});
|
||||
const res=await fetch('/api/v1/sites',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:siteName.value.trim().toLowerCase(),domain:siteDomain.value.trim().toLowerCase(),php_version:phpSelect.value,issue_ssl:document.getElementById('issue_ssl').checked})});
|
||||
const d=await res.json().catch(()=>({}));
|
||||
if(!res.ok){msg.className='msg error';msg.textContent=d.error||'Ошибка';btn.disabled=false;return;}
|
||||
msg.className='msg ok';msg.textContent='Сайт создан';
|
||||
|
||||
Reference in New Issue
Block a user