Files
Agora/views/setup.ejs
T
2026-09-15 21:56:10 +02:00

283 lines
13 KiB
Plaintext

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Agora — Installation</title>
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#1a1a1a">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Agora">
<link rel="apple-touch-icon" href="/images/icone-192.png">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/style.css">
<script src="/lucide.min.js"></script>
<script src="/app.auth.js"></script>
<style>
.setup-container {
min-height: 100vh;
width: 100%;
display: flex;
align-items: flex-start;
justify-content: center;
padding: 2rem 1rem;
background: var(--bg-main);
overflow-y: auto;
}
.setup-box {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 2.5rem;
width: 100%;
max-width: 480px;
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
margin: auto;
}
.setup-logo {
text-align: center;
margin-bottom: 2rem;
}
.setup-logo img {
width: 80px;
height: 80px;
margin-bottom: 1rem;
}
.setup-logo h1 {
font-size: 1.8rem;
font-weight: 700;
color: white;
margin: 0;
}
.setup-logo p {
color: var(--text-sec);
font-size: 0.9rem;
margin-top: 0.5rem;
}
.setup-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: rgba(229, 9, 20, 0.15);
color: var(--primary);
font-size: 0.75rem;
font-weight: 600;
padding: 4px 12px;
border-radius: 20px;
margin-bottom: 1.5rem;
border: 1px solid rgba(229, 9, 20, 0.3);
}
.setup-form { display: flex; flex-direction: column; gap: 1rem; }
.setup-form label {
display: block;
font-size: 0.8rem;
font-weight: 600;
color: var(--text-sec);
margin-bottom: 6px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.setup-form input {
width: 100%;
padding: 12px 16px;
background: var(--bg-main);
border: 1px solid var(--border);
border-radius: 10px;
color: white;
font-size: 1rem;
transition: border-color 0.2s, box-shadow 0.2s;
box-sizing: border-box;
}
.setup-form input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(229, 9, 20, 0.15);
}
.setup-form button[type="submit"] {
width: 100%;
padding: 14px;
background: var(--primary);
color: white;
border: none;
border-radius: 10px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
margin-top: 0.5rem;
}
.setup-form button[type="submit"]:hover { background: #c40812; }
.setup-form button[type="submit"]:active { transform: scale(0.98); }
.setup-form button[type="submit"]:disabled {
background: #4b5563;
color: #9ca3af;
cursor: not-allowed;
transform: none;
}
.setup-error {
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.3);
color: #ef4444;
padding: 10px 14px;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 500;
}
</style>
<link rel="icon" type="image/svg+xml" href="/logo_svg.svg">
</head>
<body>
<div class="setup-container">
<div class="setup-box">
<div class="setup-logo">
<img src="/images/logo_svg.svg" alt="Logo">
<h1>Agora</h1>
<p>Configuration initiale</p>
</div>
<div style="text-align: center;">
<span class="setup-badge">
<i data-lucide="shield" style="width: 14px; height: 14px;"></i>
Création du compte administrateur
</span>
</div>
<% if (error) { %>
<div class="setup-error" style="margin-bottom: 1rem;">
<%= error %>
</div>
<% } %>
<div id="setup-client-error" class="setup-error" style="margin-bottom: 1rem; display: none;"></div>
<form class="setup-form" id="setup-form" action="/setup" method="POST">
<div>
<label for="setup-username">Nom d'utilisateur</label>
<input type="text" id="setup-username" name="username" placeholder="admin" required
minlength="3" maxlength="32" pattern="[a-zA-Z0-9_.\-]+" autofocus autocomplete="username">
</div>
<div class="password-requirements" style="text-align: left;">
<strong>Exigences du mot de passe :</strong>
<ul style="margin-top: 8px;">
<li id="req-length" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins 8 caractères</li>
<li id="req-upper" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins une majuscule (A-Z)</li>
<li id="req-number" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins un chiffre (0-9)</li>
<li id="req-special" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins un caractère spécial</li>
<li id="req-match" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Mots de passe identiques</li>
</ul>
</div>
<div>
<label for="setup-password">Mot de passe</label>
<div class="password-container">
<input type="password" id="setup-password" name="password" placeholder="Faut sécuriser le compte !"
required minlength="8" maxlength="128" autocomplete="new-password">
<button type="button" class="toggle-password" tabindex="-1">
<i data-lucide="eye" class="eye-icon"></i>
</button>
</div>
</div>
<div>
<label for="setup-confirm">Confirmer le mot de passe</label>
<div class="password-container">
<input type="password" id="setup-confirm" name="confirmPassword" placeholder="Retapez le mot de passe"
required minlength="8" maxlength="128" autocomplete="new-password">
<button type="button" class="toggle-password" tabindex="-1">
<i data-lucide="eye" class="eye-icon"></i>
</button>
</div>
</div>
<% if (typeof pluginsToConfigure !== 'undefined' && pluginsToConfigure.length > 0) { %>
<div style="margin: 2rem 0; border-top: 1px solid var(--border); padding-top: 1.5rem; text-align: left;">
<h3 style="margin-bottom: 1rem; color: var(--text-main); font-size: 1.1rem; display: flex; align-items: center; gap: 8px;">
<i data-lucide="plug" style="width: 18px; height: 18px; color: var(--primary);"></i>
Configuration des Plugins (Optionnel)
</h3>
<p style="font-size: 0.85rem; color: var(--text-sec); margin-bottom: 1.5rem; line-height: 1.4;">
Des sources ont été détectées. Vous pouvez les configurer maintenant ou plus tard dans les paramètres.
</p>
<% pluginsToConfigure.forEach(function(plugin) { %>
<div style="background: rgba(255,255,255,0.03); border: 1px solid var(--border); border-radius: 8px; padding: 1rem; margin-bottom: 1rem;">
<strong style="display: flex; align-items: center; gap: 6px; margin-bottom: 0.8rem; color: var(--text-main); font-size: 0.95rem; text-transform: capitalize;">
<i data-lucide="box" style="width: 14px; height: 14px; color: var(--text-sec);"></i>
<%= plugin.name %>
</strong>
<% plugin.fields.forEach(function(field) { %>
<div style="margin-bottom: 0.8rem;">
<label for="config_<%= field.key %>" style="font-size: 0.8rem; color: var(--text-sec); margin-bottom: 4px; display: block;"><%= field.label %></label>
<input type="text" id="config_<%= field.key %>" name="config[<%= field.key %>]"
placeholder="<%= field.placeholder %>" value="<%= field.default || '' %>"
style="padding: 8px; font-size: 0.9rem; width: 100%; border: 1px solid var(--border); background: var(--bg-main); color: var(--text-main); border-radius: 6px;">
</div>
<% }); %>
</div>
<% }); %>
</div>
<% } %>
<button type="submit" id="setup-submit-btn" disabled>Créer le compte administrateur</button>
<div style="text-align: center; margin-top: 3rem; margin-bottom: 1rem;">
<p style="font-size: 0.85rem; color: var(--text-sec); display: inline-flex; align-items: center; gap: 6px; background: var(--bg-card); padding: 6px 12px; border-radius: 20px; border: 1px solid var(--border);">
<i data-lucide="info" style="width: 14px; height: 14px;"></i>
Agora v<%= appVersion %>
</p>
</div>
</form>
</div>
</div>
<script>
if (typeof lucide !== 'undefined') lucide.createIcons();
// Initialize password visibility toggles using the shared library
if (window.AuthHelpers) {
AuthHelpers.initPasswordToggles();
}
const passwordInput = document.getElementById('setup-password');
const confirmInput = document.getElementById('setup-confirm');
const submitBtn = document.getElementById('setup-submit-btn');
const validateSetupInputs = () => {
if (!window.AuthHelpers) return;
const val = passwordInput.value;
const confirmVal = confirmInput.value;
// Use the shared library validation logic
const statuses = AuthHelpers.validateComplexity(val, confirmVal);
// Use the shared library UI updater
AuthHelpers.updateRequirementsUI(document.getElementById('setup-form'), statuses);
submitBtn.disabled = !statuses.allValid;
};
passwordInput.addEventListener('input', validateSetupInputs);
confirmInput.addEventListener('input', validateSetupInputs);
document.getElementById('setup-form').addEventListener('submit', function(e) {
const password = passwordInput.value;
const confirm = confirmInput.value;
const errorDiv = document.getElementById('setup-client-error');
errorDiv.style.display = 'none';
if (password !== confirm) {
e.preventDefault();
errorDiv.textContent = 'Les mots de passe ne correspondent pas.';
errorDiv.style.display = 'block';
return;
}
});
</script>
</body>
</html>