185 lines
7.2 KiB
HTML
185 lines
7.2 KiB
HTML
<!doctype html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Mi cuenta — HBOX</title>
|
|
<script src="js/tema.js"></script>
|
|
<link rel="stylesheet" href="formularios/acta.css">
|
|
<style>
|
|
.campo{margin:12px 0}
|
|
.quien{background:var(--hg-plano);border:1px solid var(--linea);border-radius:10px;
|
|
padding:12px 14px;margin-bottom:14px;font-size:15px}
|
|
.quien b{font-size:17px}
|
|
.fuerza{height:6px;border-radius:3px;background:var(--linea);margin-top:6px;overflow:hidden}
|
|
.fuerza i{display:block;height:100%;width:0;transition:width .2s,background .2s}
|
|
.pista{font-size:12.5px;color:var(--tinta2);margin-top:5px}
|
|
.admin{border:1px solid var(--linea)}
|
|
button.enviar{width:100%;margin-top:6px}
|
|
.ver{font-size:13px;color:var(--naranja);cursor:pointer;user-select:none;margin-top:6px;display:inline-block}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
<header class="top">
|
|
<h1>Mi cuenta</h1>
|
|
<p>Aquí cambias tu contraseña de acceso al sitio.</p>
|
|
</header>
|
|
<div style="display:flex;justify-content:space-between;margin:2px 0 10px">
|
|
<a class="volver" href="./">← Documentación</a>
|
|
<a class="volver" href="salir.html">Cerrar sesión</a>
|
|
</div>
|
|
|
|
<div class="quien" id="quien">Consultando quién eres…</div>
|
|
|
|
<section class="paso">
|
|
<h2>Cambiar mi contraseña</h2>
|
|
<p class="sub">Elige algo que recuerdes sin apuntarlo. Mínimo 8 caracteres.</p>
|
|
<div class="campo">
|
|
<label for="actual">Contraseña actual</label>
|
|
<input type="password" id="actual" autocomplete="current-password">
|
|
</div>
|
|
<div class="campo">
|
|
<label for="nueva">Contraseña nueva</label>
|
|
<input type="password" id="nueva" autocomplete="new-password">
|
|
<div class="fuerza"><i id="barra"></i></div>
|
|
<div class="pista" id="pista">Mientras más larga, mejor; una frase con espacios sirve.</div>
|
|
</div>
|
|
<div class="campo">
|
|
<label for="confirma">Repite la contraseña nueva</label>
|
|
<input type="password" id="confirma" autocomplete="new-password">
|
|
<span class="ver" id="ver">Ver lo que escribí</span>
|
|
</div>
|
|
<button class="enviar" id="guardar">Guardar contraseña nueva</button>
|
|
<div class="msg" id="msg"></div>
|
|
</section>
|
|
|
|
<section class="paso admin" id="bloqueAdmin" style="display:none">
|
|
<h2>Restablecer la contraseña de alguien más</h2>
|
|
<p class="sub">Solo administración. Úsalo cuando un técnico olvidó la suya: no necesitas la anterior.</p>
|
|
<div class="campo">
|
|
<label for="quienReset">Usuario</label>
|
|
<select id="quienReset"></select>
|
|
</div>
|
|
<div class="campo">
|
|
<label for="nuevaR">Contraseña nueva para esa persona</label>
|
|
<input type="text" id="nuevaR" autocomplete="off" placeholder="se la pasas en persona o por mensaje directo">
|
|
</div>
|
|
<button class="enviar" id="resetear">Restablecer</button>
|
|
<div class="msg" id="msgR"></div>
|
|
</section>
|
|
|
|
<section class="paso">
|
|
<h2>Si olvidaste tu contraseña</h2>
|
|
<p class="sub" style="margin:0">
|
|
No hay recuperación por correo: pídele a Leo que te la restablezca desde esta misma página.
|
|
Si todavía no tienes acceso, pídeselo a Leo (Administración → <a href="tableros/equipo/">Usuarios y equipo</a>).
|
|
</p>
|
|
</section>
|
|
</div>
|
|
|
|
<script>
|
|
const $ = id => document.getElementById(id);
|
|
let yo = '';
|
|
|
|
function aviso(el, texto, bien) {
|
|
el.className = 'msg ' + (bien ? 'ok' : 'err');
|
|
el.innerHTML = texto;
|
|
el.scrollIntoView({ block: 'nearest' });
|
|
}
|
|
|
|
// --- quién soy + si soy admin ---
|
|
(async () => {
|
|
try {
|
|
const j = await (await fetch('/api/whoami')).json();
|
|
yo = j.user || '';
|
|
$('quien').innerHTML = yo
|
|
? 'Entraste como <b>' + yo + '</b>' + (j.admin ? ' · administrador' : '')
|
|
: 'No puedo identificarte. Vuelve a entrar al sitio y recarga esta página.';
|
|
if (j.admin) {
|
|
$('bloqueAdmin').style.display = '';
|
|
try {
|
|
const u = await (await fetch('/api/usuarios')).json();
|
|
(u.usuarios || []).forEach(n => {
|
|
const o = document.createElement('option'); o.value = n; o.textContent = n;
|
|
if (n === yo) o.textContent = n + ' (tú)';
|
|
$('quienReset').append(o);
|
|
});
|
|
} catch (e) {}
|
|
}
|
|
} catch (e) {
|
|
$('quien').textContent = 'No pude contactar al servidor.';
|
|
}
|
|
})();
|
|
|
|
// --- medidor simple: la longitud es lo que más cuenta ---
|
|
$('nueva').addEventListener('input', () => {
|
|
const v = $('nueva').value;
|
|
let p = Math.min(100, v.length * 8);
|
|
if (/[^a-zA-Z0-9]/.test(v)) p += 10;
|
|
if (/[0-9]/.test(v) && /[a-zA-Z]/.test(v)) p += 10;
|
|
p = Math.min(100, p);
|
|
const b = $('barra');
|
|
b.style.width = p + '%';
|
|
b.style.background = p < 40 ? 'var(--falla)' : p < 70 ? 'var(--aviso)' : 'var(--ok)';
|
|
$('pista').textContent = v.length < 8
|
|
? 'Te faltan ' + (8 - v.length) + ' caracteres.'
|
|
: p < 70 ? 'Aceptable. Si la alargas un poco queda mucho mejor.'
|
|
: 'Buena contraseña.';
|
|
});
|
|
|
|
$('ver').addEventListener('click', () => {
|
|
const t = $('nueva').type === 'password' ? 'text' : 'password';
|
|
$('nueva').type = t; $('confirma').type = t; $('actual').type = t;
|
|
$('ver').textContent = t === 'text' ? 'Ocultar' : 'Ver lo que escribí';
|
|
});
|
|
|
|
const AVISO_SESION =
|
|
'<br><br>Tu navegador todavía recuerda la contraseña anterior, así que puedes seguir '
|
|
+ 'navegando sin problema. <b>La nueva la vas a necesitar la próxima vez que entres.</b> '
|
|
+ 'Si quieres probarla ahora, usa <a href="salir.html">Cerrar sesión</a>.';
|
|
|
|
$('guardar').addEventListener('click', async () => {
|
|
const b = $('guardar');
|
|
b.disabled = true; b.textContent = 'Guardando…';
|
|
try {
|
|
const r = await fetch('/api/password', {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ actual: $('actual').value, nueva: $('nueva').value, confirma: $('confirma').value })
|
|
});
|
|
const j = await r.json();
|
|
if (!r.ok || !j.ok) throw new Error(j.error || ('HTTP ' + r.status));
|
|
aviso($('msg'), '<b>Contraseña cambiada.</b>' + AVISO_SESION, true);
|
|
$('actual').value = $('nueva').value = $('confirma').value = '';
|
|
$('barra').style.width = '0';
|
|
} catch (e) {
|
|
aviso($('msg'), e.message, false);
|
|
}
|
|
b.disabled = false; b.textContent = 'Guardar contraseña nueva';
|
|
});
|
|
|
|
$('resetear').addEventListener('click', async () => {
|
|
const u = $('quienReset').value, nueva = $('nuevaR').value;
|
|
if (!u) return aviso($('msgR'), 'Elige a quién le vas a restablecer la contraseña.', false);
|
|
if (!confirm('¿Restablecer la contraseña de ' + u + '?')) return;
|
|
const b = $('resetear'); b.disabled = true; b.textContent = 'Restableciendo…';
|
|
try {
|
|
const r = await fetch('/api/password', {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ usuario: u, nueva: nueva, confirma: nueva })
|
|
});
|
|
const j = await r.json();
|
|
if (!r.ok || !j.ok) throw new Error(j.error || ('HTTP ' + r.status));
|
|
aviso($('msgR'), 'Contraseña de <b>' + u + '</b> restablecida. Pásasela en persona o por '
|
|
+ 'mensaje directo, y dile que la cambie aquí mismo cuando entre.'
|
|
+ (u === yo ? AVISO_SESION : ''), true);
|
|
$('nuevaR').value = '';
|
|
} catch (e) {
|
|
aviso($('msgR'), e.message, false);
|
|
}
|
|
b.disabled = false; b.textContent = 'Restablecer';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|