Files
insta-portal/scripts/revisar-codificacion.mjs
T
Uriel JarethandClaude Opus 5 0b9c9c1dc2 Portal interno INSTA: base de conocimiento con Magic Login y permisos por rol
Base de conocimiento para el personal del Instituto Santiago Tapia: oferta
educativa (en tarjetas y en tabla), requisitos y titulacion, becas y fechas
de inscripcion, links de clases de Google Meet, preguntas frecuentes,
mensajes listos y datos del instituto.

Acceso con Magic Login: enlace de un solo uso, 15 minutos de vigencia, y en
la base solo se guarda el SHA-256 del token. El canje es atomico, asi que dos
canjes simultaneos del mismo enlace no pueden crear dos sesiones.

Tres roles con 19 permisos. El catalogo lo edita direccion; los links de
clases, direccion y administracion; el resto del equipo consulta. El menu se
pinta con lo que el servidor autoriza y cada endpoint exige la misma clave,
asi que no hay pantallas alcanzables escribiendo la direccion a mano.

Toda edicion pasa por una lista blanca de campos validados y queda en la
bitacora. Un precio vacio no se guarda como cero, un link que no es una
direccion se rechaza, y no se puede marcar una validez oficial como
confirmada sin numero de acuerdo.

Pensado para leerse comodo: texto de 17 px, contraste AA, areas de toque de
44 px, tema claro y bloques plegados en telefono.

La oferta, los costos, las becas, los requisitos y el contacto son los reales
del instituto, tomados del CSV de oferta educativa y de la base de
conocimiento. Los usuarios de acceso y los links de Meet son de demostracion.

Verificado: 103 comprobaciones de API y 51 pruebas en WebKit escritorio y
iPhone 13.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-29 23:20:34 -06:00

53 lines
2.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// =====================================================================
// Detecta mojibake (UTF-8 leído como Latin-1) en los archivos del proyecto.
// node scripts/revisar-codificacion.mjs
// Se corre después de cualquier edición masiva: reemplazar con expresiones
// regulares desde PowerShell rompe los acentos y el daño es difícil de ver.
// =====================================================================
import { readFile, readdir } from 'node:fs/promises';
import path from 'node:path';
const RAIZ = path.resolve(import.meta.dirname, '..');
const EXTENSIONES = new Set(['.mjs', '.js', '.css', '.html', '.sql', '.md', '.json', '.yml', '.ps1']);
const IGNORAR = new Set(['node_modules', 'tests', '.git', 'capturas', 'test-results', 'reporte']);
// Secuencias típicas del doble encodeo: Ã seguida de otra letra acentuada, etc.
const SOSPECHAS = [/Ã[€-¿­]/, /Â[ -¿]/, /â€/, /Â/];
async function archivos(dir) {
const salida = [];
for (const e of await readdir(dir, { withFileTypes: true })) {
if (IGNORAR.has(e.name)) continue;
const p = path.join(dir, e.name);
if (e.isDirectory()) salida.push(...await archivos(p));
else if (EXTENSIONES.has(path.extname(e.name))) salida.push(p);
}
return salida;
}
const sospechosos = [];
for (const p of await archivos(RAIZ)) {
if (p === import.meta.filename) continue; // este archivo contiene los patrones a propósito
const texto = await readFile(p, 'utf8');
const lineas = texto.split('\n');
const malas = [];
lineas.forEach((l, i) => {
if (SOSPECHAS.some((re) => re.test(l))) malas.push({ n: i + 1, l: l.trim().slice(0, 90) });
});
if (malas.length) sospechosos.push({ archivo: path.relative(RAIZ, p), malas });
}
if (!sospechosos.length) {
console.log('\n ✔ Sin mojibake: los acentos están bien en todos los archivos.\n');
process.exit(0);
}
console.log('\n ✖ Se encontró texto mal codificado:\n');
for (const s of sospechosos) {
console.log(` ${s.archivo}`);
for (const m of s.malas.slice(0, 6)) console.log(` línea ${m.n}: ${m.l}`);
if (s.malas.length > 6) console.log(` …y ${s.malas.length - 6} líneas más`);
}
console.log('');
process.exit(1);