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>
80 lines
2.6 KiB
HTML
80 lines
2.6 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Backup{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h4 class="mb-0"><i class="bi bi-archive me-2"></i>Backup</h4>
|
|
<button class="btn btn-primary" onclick="createBackup(this)">
|
|
<i class="bi bi-plus-circle"></i> Napravi backup
|
|
</button>
|
|
</div>
|
|
|
|
<div class="alert alert-info small mb-4">
|
|
<i class="bi bi-info-circle me-1"></i>
|
|
Backup uključuje: Guacamole konfiguraciju, PostgreSQL bazu, nginx konfig,
|
|
Basic Auth korisnike, fail2ban pravila i SSL certifikate.
|
|
Sprema se u <code>/root/</code> (čitljivo samo root-u).
|
|
</div>
|
|
|
|
<!-- Lista backupa -->
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<span class="fw-semibold">Dostupni backupi</span>
|
|
<span class="badge bg-secondary">{{ backups|length }}</span>
|
|
</div>
|
|
{% if backups %}
|
|
<div class="list-group list-group-flush">
|
|
{% for b in backups %}
|
|
<div class="list-group-item d-flex justify-content-between align-items-center"
|
|
style="background:transparent; border-color:#30363d">
|
|
<div>
|
|
<i class="bi bi-file-zip me-2 text-muted"></i>
|
|
<span class="font-monospace small">{{ b }}</span>
|
|
</div>
|
|
<button class="btn btn-outline-danger btn-sm" onclick="deleteBackup('{{ b }}')">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="card-body text-muted">
|
|
<i class="bi bi-inbox me-1"></i> Nema dostupnih backupa
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Progress -->
|
|
<div id="backup-progress" class="card mt-4 d-none">
|
|
<div class="card-body d-flex align-items-center gap-3">
|
|
<div class="spinner-border spinner-border-sm text-primary"></div>
|
|
<span>Kreiranje backupa, molim pričekajte...</span>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
async function createBackup(btn) {
|
|
const orig = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Backup...';
|
|
document.getElementById('backup-progress').classList.remove('d-none');
|
|
|
|
const r = await api('/api/backup/create');
|
|
showToast(r.msg, r.ok);
|
|
btn.disabled = false;
|
|
btn.innerHTML = orig;
|
|
document.getElementById('backup-progress').classList.add('d-none');
|
|
if (r.ok) setTimeout(() => location.reload(), 1500);
|
|
}
|
|
|
|
async function deleteBackup(name) {
|
|
if (!confirm(`Obrisati backup "${name}"?`)) return;
|
|
const r = await api('/api/backup/delete', {name});
|
|
showToast(r.msg, r.ok);
|
|
if (r.ok) setTimeout(() => location.reload(), 800);
|
|
}
|
|
</script>
|
|
{% endblock %}
|