Files
veritas-suite/crates/veritas-server/static/app.js
T

473 lines
19 KiB
JavaScript

// Veritas Suite Web Portal App Logic
const API_BASE = "";
document.addEventListener("DOMContentLoaded", () => {
checkServerHealth();
restoreSession();
fetchDownloads();
// Check if we are on admin page
if (window.location.pathname === "/admin" || window.location.pathname.endsWith("admin.html")) {
checkAdminPageSession();
}
});
// Check Server Connection
async function checkServerHealth() {
const indicator = document.querySelector(".status-indicator");
const statusText = document.getElementById("status-text");
try {
const response = await fetch(`${API_BASE}/health`);
if (response.ok) {
if (indicator) indicator.classList.add("online");
if (statusText) statusText.textContent = "VPS Server: Online (200 OK)";
} else {
if (statusText) statusText.textContent = "VPS Server: Fehler";
}
} catch (e) {
if (statusText) statusText.textContent = "VPS Server: Offline";
}
}
// Filter Sparten Tools
function filterSparten(category) {
document.querySelectorAll(".filter-btn").forEach(btn => btn.classList.remove("active"));
const activeBtn = Array.from(document.querySelectorAll(".filter-btn")).find(btn =>
btn.getAttribute("onclick") && btn.getAttribute("onclick").includes(`'${category}'`)
);
if (activeBtn) activeBtn.classList.add("active");
const cards = document.querySelectorAll(".tool-card");
cards.forEach(card => {
if (category === "all" || card.getAttribute("data-sparte") === category) {
card.style.display = "flex";
} else {
card.style.display = "none";
}
});
}
// Restore Session from LocalStorage
function restoreSession() {
const sessionStr = localStorage.getItem("veritas_session");
if (sessionStr) {
try {
const session = JSON.parse(sessionStr);
if (session && session.user_id) {
showLoggedInState(session);
} else {
showLoggedOutState();
}
} catch (e) {
localStorage.removeItem("veritas_session");
showLoggedOutState();
}
} else {
showLoggedOutState();
}
}
function showLoggedInState(session) {
const loggedOutDiv = document.getElementById("dash-logged-out");
const loggedInDiv = document.getElementById("dash-logged-in");
const userEmailSpan = document.getElementById("dash-user-email");
const userStatusBar = document.getElementById("user-status-bar");
const authForms = document.getElementById("auth-forms-container");
const navAdminLink = document.getElementById("nav-admin-link");
const btnAdminPanel = document.getElementById("btn-admin-panel");
if (loggedOutDiv) loggedOutDiv.style.display = "none";
if (loggedInDiv) loggedInDiv.style.display = "block";
if (userEmailSpan) userEmailSpan.textContent = session.email;
if (userStatusBar) userStatusBar.style.display = "inline-flex";
if (authForms) authForms.style.display = "none";
// Show Admin Buttons ONLY if logged-in user is an Admin
if (session.is_admin) {
if (navAdminLink) navAdminLink.style.display = "inline-flex";
if (btnAdminPanel) btnAdminPanel.style.display = "inline-block";
} else {
if (navAdminLink) navAdminLink.style.display = "none";
if (btnAdminPanel) btnAdminPanel.style.display = "none";
}
refreshDashboard();
}
function showLoggedOutState() {
const loggedOutDiv = document.getElementById("dash-logged-out");
const loggedInDiv = document.getElementById("dash-logged-in");
const userStatusBar = document.getElementById("user-status-bar");
const authForms = document.getElementById("auth-forms-container");
const navAdminLink = document.getElementById("nav-admin-link");
const btnAdminPanel = document.getElementById("btn-admin-panel");
if (loggedOutDiv) loggedOutDiv.style.display = "block";
if (loggedInDiv) loggedInDiv.style.display = "none";
if (userStatusBar) userStatusBar.style.display = "none";
if (authForms) authForms.style.display = "grid";
if (navAdminLink) navAdminLink.style.display = "none";
if (btnAdminPanel) btnAdminPanel.style.display = "none";
}
function logout() {
localStorage.removeItem("veritas_session");
showLoggedOutState();
showAlert("Erfolgreich abgemeldet.", "success");
if (window.location.pathname === "/admin" || window.location.pathname.endsWith("admin.html")) {
window.location.href = "/portal";
}
}
// Handle Customer Registration
async function handleRegister(event) {
event.preventDefault();
const email = document.getElementById("reg-email").value;
const password = document.getElementById("reg-password").value;
try {
const response = await fetch(`${API_BASE}/api/v1/auth/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (data.success) {
showAlert(data.message, "success");
const session = { user_id: data.user_id, email: data.email, token: data.auth_token, is_admin: data.is_admin };
localStorage.setItem("veritas_session", JSON.stringify(session));
showLoggedInState(session);
} else {
showAlert(data.message, "error");
}
} catch (e) {
showAlert("Netzwerkfehler bei der Registrierung.", "error");
}
}
// Handle Customer & Admin Login in Portal
async function handleLogin(event) {
event.preventDefault();
const email = document.getElementById("login-email").value;
const password = document.getElementById("login-password").value;
try {
const response = await fetch(`${API_BASE}/api/v1/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (data.success) {
showAlert(data.message, "success");
const session = { user_id: data.user_id, email: data.email, token: data.auth_token, is_admin: data.is_admin };
localStorage.setItem("veritas_session", JSON.stringify(session));
showLoggedInState(session);
if (data.is_admin) {
showAlert("👑 Willkommen Admin! Du hast Zugriff auf die Admin-Zentrale.", "success");
}
} else {
showAlert(data.message, "error");
}
} catch (e) {
showAlert("Netzwerkfehler beim Anmelden.", "error");
}
}
// Check Admin Page Session (Requires Admin Login in Customer Portal)
function checkAdminPageSession() {
const sessionStr = localStorage.getItem("veritas_session");
const loggedOutState = document.getElementById("admin-logged-out-state");
const loggedInState = document.getElementById("admin-logged-in-state");
const userEmailDisplay = document.getElementById("admin-user-email-display");
if (sessionStr) {
try {
const session = JSON.parse(sessionStr);
if (session && session.is_admin) {
if (loggedOutState) loggedOutState.style.display = "none";
if (loggedInState) loggedInState.style.display = "block";
if (userEmailDisplay) userEmailDisplay.textContent = session.email;
fetchAdminStats();
return;
}
} catch (e) {}
}
if (loggedOutState) loggedOutState.style.display = "block";
if (loggedInState) loggedInState.style.display = "none";
}
function logoutAdmin() {
logout();
}
// Refresh Customer Dashboard Data
async function refreshDashboard() {
const sessionStr = localStorage.getItem("veritas_session");
if (!sessionStr) return;
const session = JSON.parse(sessionStr);
const container = document.getElementById("license-list");
if (!container) return;
container.innerHTML = "<p style='color:#94a3b8;'>Lizenzen werden geladen...</p>";
try {
const response = await fetch(`${API_BASE}/api/v1/account/dashboard?user_id=${session.user_id}`);
const data = await response.json();
if (data.success && data.licenses && data.licenses.length > 0) {
container.innerHTML = "";
data.licenses.forEach(lic => {
const percent = Math.min(100, (lic.activated_devices / lic.max_devices) * 100);
const cardHtml = `
<div class="lic-card glass-panel" style="background: rgba(24, 34, 53, 0.7); padding: 1.25rem; border-radius: 12px; border: 1px solid rgba(255,255,255,0.08); margin-bottom: 1rem;">
<div class="lic-top" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
<span class="lic-plan" style="font-weight: 700; color: #fff; font-size: 1.1rem;">🛡️ ${lic.plan_name}</span>
<span class="status-badge ${lic.active ? 'badge-active' : 'badge-planned'}" style="padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 600;">${lic.active ? '🟢 AKTIV' : '🔴 GESPERRT'}</span>
</div>
<div class="lic-key-row" style="display: flex; align-items: center; justify-content: space-between; background: rgba(3, 7, 18, 0.6); padding: 10px 14px; border-radius: 8px; margin-bottom: 0.75rem;">
<code style="font-family: monospace; color: #38bdf8; font-size: 1.05rem;">${lic.license_key}</code>
<button class="btn btn-glass btn-small" onclick="copyKey('${lic.license_key}')">📋 Kopieren</button>
</div>
<div>
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
<small style="color: #94a3b8;">Aktivierte Geräte</small>
<small style="color: #6366f1; font-weight: 600;">${lic.activated_devices} / ${lic.max_devices} Geräte</small>
</div>
<div class="progress-bg" style="background: rgba(255,255,255,0.1); height: 8px; border-radius: 4px; overflow: hidden;">
<div class="progress-fill" style="width: ${percent}%; background: linear-gradient(90deg, #6366f1, #34d399); height: 100%;"></div>
</div>
</div>
</div>
`;
container.innerHTML += cardHtml;
const simKeyInput = document.getElementById("sim-key");
if (simKeyInput) simKeyInput.value = lic.license_key;
});
} else {
container.innerHTML = "<p style='color:#94a3b8;'>Keine aktiven Lizenzen für dieses Konto gefunden.</p>";
}
} catch (e) {
container.innerHTML = "<p class='error' style='color:#f87171;'>Fehler beim Laden des Dashboards.</p>";
}
}
// Fetch Software Downloads
async function fetchDownloads() {
const container = document.getElementById("downloads-container");
if (!container) return;
try {
const response = await fetch(`${API_BASE}/api/v1/downloads/list`);
const items = await response.json();
container.innerHTML = "";
items.forEach(item => {
const card = `
<div class="tool-card glass-panel">
<div class="card-top">
<span class="sparte-tag tag-cura">${item.category}</span>
<span class="status-badge ${item.is_available ? 'badge-active' : 'badge-planned'}">${item.version}</span>
</div>
<h3>${item.name}</h3>
<p class="tool-desc">${item.description}</p>
<div class="card-footer" style="justify-content: space-between; align-items: center;">
<span class="tech-tag">Größe: ${item.file_size}</span>
${item.is_available ?
`<a class="btn btn-emerald btn-small" href="${item.download_url}" download>📥 Download .exe</a>` :
`<button class="btn btn-glass btn-small" disabled style="opacity:0.5">Demnächst</button>`}
</div>
</div>
`;
container.innerHTML += card;
});
} catch (e) {
container.innerHTML = "<p>Fehler beim Laden der Download-Liste.</p>";
}
}
// Fetch Admin Stats (Sends Authorization Bearer token)
async function fetchAdminStats() {
const sessionStr = localStorage.getItem("veritas_session");
if (!sessionStr) return;
const session = JSON.parse(sessionStr);
try {
const response = await fetch(`${API_BASE}/api/v1/admin/stats`, {
headers: {
"Authorization": `Bearer ${session.token}`
}
});
const data = await response.json();
if (data.success) {
const usersEl = document.getElementById("admin-stat-users");
const licsEl = document.getElementById("admin-stat-licenses");
const actsEl = document.getElementById("admin-stat-activations");
if (usersEl) usersEl.textContent = data.total_users;
if (licsEl) licsEl.textContent = data.total_licenses;
if (actsEl) actsEl.textContent = data.total_activations;
const tbody = document.getElementById("admin-licenses-table-body");
if (tbody) {
tbody.innerHTML = "";
data.licenses.forEach(lic => {
const tr = `
<tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
<td style="padding: 12px;">#${lic.id}</td>
<td style="padding: 12px;"><code style="color:#38bdf8">${lic.license_key}</code></td>
<td style="padding: 12px;">${lic.user_email || 'Gast / System'}</td>
<td style="padding: 12px;">${lic.plan_name}</td>
<td style="padding: 12px;">${lic.activated_devices} / ${lic.max_devices}</td>
<td style="padding: 12px;"><span class="status-badge ${lic.active ? 'badge-active' : 'badge-planned'}">${lic.active ? '🟢 AKTIV' : '🔴 GESPERRT'}</span></td>
<td style="padding: 12px;">
<button class="btn btn-small ${lic.active ? 'btn-outline-danger' : 'btn-emerald'}" onclick="toggleLicense('${lic.license_key}', ${!lic.active})">
${lic.active ? '🚫 Sperren' : '✅ Freischalten'}
</button>
</td>
</tr>
`;
tbody.innerHTML += tr;
});
}
} else {
showAdminAlert("Zugriff verweigert: " + (data.message || "Admin Privilegien erforderlich"), "error");
}
} catch (e) {
console.error("Admin stats fetch failed", e);
}
}
// Admin Create License Handler (Sends Authorization Bearer token)
async function handleAdminCreateLicense(event) {
event.preventDefault();
const sessionStr = localStorage.getItem("veritas_session");
if (!sessionStr) return;
const session = JSON.parse(sessionStr);
const userId = parseInt(document.getElementById("admin-create-uid").value);
const planName = document.getElementById("admin-create-plan").value;
const maxDevices = parseInt(document.getElementById("admin-create-max").value);
try {
const response = await fetch(`${API_BASE}/api/v1/admin/create-license`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${session.token}`
},
body: JSON.stringify({ user_id: userId, plan_name: planName, max_devices: maxDevices })
});
const data = await response.json();
if (data.success) {
showAdminAlert("Lizenz erfolgreich erstellt: " + data.message, "success");
fetchAdminStats();
} else {
showAdminAlert("Fehler: " + data.message, "error");
}
} catch (e) {
showAdminAlert("Netzwerkfehler beim Erstellen der Lizenz.", "error");
}
}
// Admin Toggle License Active/Deactive (Sends Authorization Bearer token)
async function toggleLicense(licenseKey, newActiveState) {
const sessionStr = localStorage.getItem("veritas_session");
if (!sessionStr) return;
const session = JSON.parse(sessionStr);
try {
const response = await fetch(`${API_BASE}/api/v1/admin/toggle-license`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${session.token}`
},
body: JSON.stringify({ license_key: licenseKey, active: newActiveState })
});
const data = await response.json();
if (data.success) {
showAdminAlert("Lizenz-Status aktualisiert.", "success");
fetchAdminStats();
} else {
showAdminAlert("Fehler: " + data.message, "error");
}
} catch (e) {
showAdminAlert("Netzwerkfehler beim Ändern des Lizenzstatus.", "error");
}
}
// Handle Activation Test
async function handleTestActivation(event) {
event.preventDefault();
const licenseKey = document.getElementById("sim-key").value;
const hardwareId = document.getElementById("sim-hwid").value;
const appName = document.getElementById("sim-app").value;
const outputBox = document.getElementById("sim-output-box");
const jsonText = document.getElementById("sim-json-text");
try {
const response = await fetch(`${API_BASE}/api/v1/activate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
license_key: licenseKey,
hardware_id: hardwareId,
app_name: appName
})
});
const data = await response.json();
outputBox.style.display = "block";
jsonText.textContent = JSON.stringify(data, null, 2);
refreshDashboard();
} catch (e) {
outputBox.style.display = "block";
jsonText.textContent = "Fehler bei der Kommunikation mit dem VPS Server.";
}
}
// Helper: Show Alert for Customer Portal
function showAlert(msg, type) {
const box = document.getElementById("auth-alert");
if (!box) return;
box.textContent = msg;
box.className = `alert-box ${type}`;
box.style.display = "block";
setTimeout(() => {
box.style.display = "none";
}, 5000);
}
// Helper: Show Alert for Admin Portal
function showAdminAlert(msg, type) {
const box = document.getElementById("admin-alert");
if (!box) return;
box.textContent = msg;
box.className = `alert-box ${type}`;
box.style.display = "block";
setTimeout(() => {
box.style.display = "none";
}, 5000);
}
// Helper: Copy Key
function copyKey(text) {
navigator.clipboard.writeText(text).then(() => {
alert("Lizenzschlüssel in die Zwischenablage kopiert!");
});
}