Files
insta-portal/scripts/revisar-codificacion.mjs
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 Permalink 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);