50c125e0db
All-in-one installer za Apache Guacamole s Nginx reverse proxy, fail2ban, SSL (Let's Encrypt / Self-signed), GeoIP blokiranjem i Flask web GUI za upravljanje. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
208 lines
6.7 KiB
HTML
208 lines
6.7 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Ažuriranja{% endblock %}
|
|
|
|
{% block content %}
|
|
<h4 class="mb-4"><i class="bi bi-arrow-up-circle me-2"></i>Ažuriranja</h4>
|
|
|
|
<!-- Trenutne verzije -->
|
|
<div class="card mb-4">
|
|
<div class="card-header fw-semibold"><i class="bi bi-info-circle me-1"></i> Trenutne verzije</div>
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
{% for name, ver in versions.items() %}
|
|
<div class="col-md-4">
|
|
<div class="p-3 rounded" style="background:#0d1117; border:1px solid #30363d">
|
|
<div class="small text-muted text-uppercase mb-1">{{ name }}</div>
|
|
<div class="fw-semibold font-monospace">{{ ver }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Akcije ažuriranja -->
|
|
<div class="row g-4">
|
|
|
|
<!-- Guacamole -->
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header fw-semibold">
|
|
<i class="bi bi-display me-1"></i> Guacamole
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">
|
|
Preuzima najnovije Docker image-e za Guacamole, guacd i PostgreSQL
|
|
te restarta kontejnere. Konfiguracija i podaci se čuvaju.
|
|
</p>
|
|
<button class="btn btn-primary" onclick="startUpdate('guacamole', this)">
|
|
<i class="bi bi-cloud-download"></i> Ažuriraj Guacamole
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Nginx -->
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header fw-semibold">
|
|
<i class="bi bi-server me-1"></i> Nginx
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">
|
|
Ažurira nginx paket putem sistemskog package managera
|
|
({{ pkg }}) i automatski reloada konfiguraciju.
|
|
</p>
|
|
<button class="btn btn-primary" onclick="startUpdate('nginx', this)">
|
|
<i class="bi bi-arrow-up-circle"></i> Ažuriraj Nginx
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- fail2ban -->
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header fw-semibold">
|
|
<i class="bi bi-shield me-1"></i> fail2ban
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">
|
|
Ažurira fail2ban paket i restarta servis.
|
|
Jail konfiguracije ostaju netaknute.
|
|
</p>
|
|
<button class="btn btn-primary" onclick="updateFail2ban(this)">
|
|
<i class="bi bi-arrow-up-circle"></i> Ažuriraj fail2ban
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sistem -->
|
|
<div class="col-md-6">
|
|
<div class="card h-100">
|
|
<div class="card-header fw-semibold">
|
|
<i class="bi bi-hdd me-1"></i> Sistemske nadogradnje
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">
|
|
Ažurira sve instalirane sistemske pakete putem <code>{{ pkg }}</code>.
|
|
Može potrajati nekoliko minuta.
|
|
</p>
|
|
<div class="alert alert-warning py-2 small mb-3">
|
|
<i class="bi bi-exclamation-triangle me-1"></i>
|
|
Nakon sistemske nadogradnje može biti potreban restart servera.
|
|
</div>
|
|
<button class="btn btn-warning" onclick="startUpdate('system', this)">
|
|
<i class="bi bi-hdd-rack"></i> Ažuriraj sistem
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Output konzola -->
|
|
<div id="output-panel" class="card mt-4 d-none">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<span class="fw-semibold">
|
|
<i class="bi bi-terminal me-1"></i>
|
|
Output: <span id="output-title">—</span>
|
|
</span>
|
|
<div>
|
|
<span id="output-status" class="badge bg-warning me-2">U tijeku...</span>
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearOutput()">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="log-output"></div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
let activeSource = null;
|
|
|
|
function startUpdate(type, btn) {
|
|
const titles = {
|
|
guacamole: 'Guacamole',
|
|
nginx: 'Nginx',
|
|
system: 'Sistemske nadogradnje'
|
|
};
|
|
|
|
if (activeSource) {
|
|
activeSource.close();
|
|
activeSource = null;
|
|
}
|
|
|
|
document.getElementById('output-panel').classList.remove('d-none');
|
|
document.getElementById('output-title').textContent = titles[type] || type;
|
|
document.getElementById('output-status').textContent = 'U tijeku...';
|
|
document.getElementById('output-status').className = 'badge bg-warning me-2';
|
|
|
|
const out = document.getElementById('log-output');
|
|
out.innerHTML = '';
|
|
|
|
const origHtml = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Ažuriranje...';
|
|
|
|
activeSource = new EventSource(`/api/update/${type}`);
|
|
activeSource.onmessage = e => {
|
|
const data = JSON.parse(e.data);
|
|
if (data === '__DONE__') {
|
|
activeSource.close();
|
|
activeSource = null;
|
|
btn.disabled = false;
|
|
btn.innerHTML = origHtml;
|
|
document.getElementById('output-status').textContent = 'Završeno';
|
|
document.getElementById('output-status').className = 'badge bg-success me-2';
|
|
return;
|
|
}
|
|
const line = document.createElement('div');
|
|
line.textContent = data;
|
|
if (data.startsWith('✓')) line.style.color = '#3fb950';
|
|
out.appendChild(line);
|
|
out.scrollTop = out.scrollHeight;
|
|
};
|
|
activeSource.onerror = () => {
|
|
activeSource.close();
|
|
activeSource = null;
|
|
btn.disabled = false;
|
|
btn.innerHTML = origHtml;
|
|
document.getElementById('output-status').textContent = 'Greška';
|
|
document.getElementById('output-status').className = 'badge bg-danger me-2';
|
|
};
|
|
}
|
|
|
|
async function updateFail2ban(btn) {
|
|
const orig = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Ažuriranje...';
|
|
|
|
document.getElementById('output-panel').classList.remove('d-none');
|
|
document.getElementById('output-title').textContent = 'fail2ban';
|
|
document.getElementById('output-status').textContent = 'U tijeku...';
|
|
document.getElementById('output-status').className = 'badge bg-warning me-2';
|
|
|
|
const r = await api('/api/update/fail2ban');
|
|
const out = document.getElementById('log-output');
|
|
out.innerHTML = '';
|
|
const line = document.createElement('div');
|
|
line.textContent = r.msg;
|
|
out.appendChild(line);
|
|
|
|
btn.disabled = false;
|
|
btn.innerHTML = orig;
|
|
document.getElementById('output-status').textContent = r.ok ? 'Završeno' : 'Greška';
|
|
document.getElementById('output-status').className = `badge ${r.ok ? 'bg-success' : 'bg-danger'} me-2`;
|
|
showToast(r.ok ? 'fail2ban ažuriran' : r.msg, r.ok);
|
|
}
|
|
|
|
function clearOutput() {
|
|
document.getElementById('log-output').innerHTML = '';
|
|
document.getElementById('output-panel').classList.add('d-none');
|
|
}
|
|
</script>
|
|
{% endblock %}
|