utn-cli 2.0.89 → 2.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utn-cli",
3
- "version": "2.0.89",
3
+ "version": "2.0.91",
4
4
  "description": "Herramienta CLI unificada para la gestión de plantillas en SIGU.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -461,6 +461,68 @@ class Miscelaneo {
461
461
  return;
462
462
  }
463
463
 
464
+ async AutenticarConGoogle(Solicitud) {
465
+ const { OAuth2Client } = require('google-auth-library');
466
+ const jwt = require('jsonwebtoken');
467
+ const clientId = await this.googleClientId();
468
+ const client = new OAuth2Client(clientId);
469
+ const ConexionSigu = await crearObjetoConexionSIGU();
470
+ const LastUser = await this.generarLastUser(Solicitud);
471
+
472
+ try {
473
+ const ticket = await client.verifyIdToken({
474
+ idToken: Solicitud.body.token,
475
+ audience: clientId,
476
+ });
477
+ const payload = ticket.getPayload();
478
+ const email = payload['email'];
479
+
480
+ const resultadosEmail = await ConexionSigu.query("SELECT `Identificador` FROM `SIGU`.`SIGU_CorreosPersona` WHERE `CorreoElectronico` = ? AND `Principal` = TRUE LIMIT 1", [email]);
481
+
482
+ if (resultadosEmail[0].length === 0) {
483
+ console.log("El correo de Google", email, "no está registrado como principal en SIGU");
484
+ return { error: "Su cuenta de Google no está vinculada a ningún usuario de SIGU." };
485
+ }
486
+
487
+ const Identificador = resultadosEmail[0][0]['Identificador'];
488
+ const resultadosUsuario = await ConexionSigu.query("SELECT `Identificacion` FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` = ? AND `Activo` = TRUE", [Identificador]);
489
+
490
+ if (resultadosUsuario[0].length === 0) {
491
+ return { error: "El usuario asociado a esta cuenta no está activo." };
492
+ }
493
+
494
+ const Identificacion = resultadosUsuario[0][0]['Identificacion'];
495
+
496
+ // Generar Token
497
+ const Token = await jwt.sign({ Identificador: Identificador, uid: Identificador }, await this.palabraSecretaParaTokens(), { expiresIn: '2h' });
498
+ await ConexionSigu.query("INSERT INTO `SIGU`.`SIGU_Sesiones` VALUES (?, ?, ?, NOW(4), ?) ON DUPLICATE KEY UPDATE `Token` = ?, `LastUser` = ?", [Identificador, Solicitud.headers.host.trim(), Token, LastUser, Token, LastUser]);
499
+ await ConexionSigu.query("DELETE FROM `SIGU`.`SIGU_SesionesFallidas` WHERE `Identificador` = ?", [Identificador]);
500
+
501
+ // OBTENER IP DEL USUARIO
502
+ const ipUsuario = (Solicitud.headers['x-forwarded-for'] || '').split(',').shift() || Solicitud.socket?.remoteAddress || Solicitud.connection?.remoteAddress || '-';
503
+
504
+ // SI LA IP YA EXISTE CONTINUA
505
+ await ConexionSigu.query("\
506
+ INSERT INTO `SIGU`.`SIGU_DireccionesUsadasPorLosUsuarios` \
507
+ (`DireccionUsadaPorElUsuario`, `Identificador`, `LastUpdate`, `LastUser`) \
508
+ VALUES (?, ?, NOW(4), ?) \
509
+ ON DUPLICATE KEY UPDATE `LastUpdate` = NOW(4), `LastUser` = ?;", [
510
+ ipUsuario,
511
+ Identificador,
512
+ LastUser,
513
+ LastUser
514
+ ]);
515
+
516
+ return { Token, Dominio: ((process.env.ENV || 'local') === 'production' ? '.sigu.utn.ac.cr' : '.181.193.85.44.nip.io') };
517
+
518
+ } catch (error) {
519
+ console.error("Error en AutenticarConGoogle:", error);
520
+ return { error: "Error al autenticar con Google" };
521
+ } finally {
522
+ if (ConexionSigu) await ConexionSigu.end();
523
+ }
524
+ }
525
+
464
526
  async Autenticar(Solicitud) {
465
527
  const crypto = require('crypto');
466
528
  const bcrypt = require('bcryptjs');
@@ -696,7 +758,7 @@ class Miscelaneo {
696
758
  `a`.`Tipo`, IF(`a`.`Icono` <> '', CONCAT('https://storage.sigu.utn.ac.cr/images/cards/', `a`.`Icono`), '') AS `Icono`, `a`.`Color`, `a`.`Correo`,\
697
759
  `a`.`Version`, `a`.`FechaDePublicacion`, `a`.`AcuerdoDeNivelDeServicio`, `a`.`DiccionarioDeDatos`, `a`.`Repositorios`,\
698
760
  `a`.`EnlaceDelVideo`,`a`.`EnlaceDelManual`\
699
- , `a`.`Estado`, REGEXP_SUBSTR(`a`.`Repositorios`, '[^,]*front[^,]*') AS `Frontend`\
761
+ , `a`.`Estado`, REGEXP_SUBSTR(SUBSTRING_INDEX(`a`.`Repositorios`, '/', -1), '[^,]*front[^,]*') AS `Frontend`\
700
762
  FROM `SIGU`.`SIGU_ModulosV2` `a`\
701
763
  WHERE `a`.`Nombre` = ?", [this.NombreCanonicoDelModulo]);
702
764
  return Modulos.map((linea) => {
@@ -890,10 +952,10 @@ class Miscelaneo {
890
952
  const Version = this.Version + "$$" + this.versionDelNucleo().split(' ')[0];
891
953
  await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_ModulosV2` VALUES\
892
954
  (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(4), ?, 'DiccionarioDeDatos'\
893
- , ?, '-', '-', 'Activo', NOW(4), USER()) ON DUPLICATE KEY UPDATE `Version` = ?"
955
+ , ?, '-', '-', 'Activo', NOW(4), USER()) ON DUPLICATE KEY UPDATE `Version` = ?, `Repositorios` = ?"
894
956
  , [this.NombreCanonicoDelModulo, this.MenuPadre, this.DescripcionDelModulo, this.DetalleDelModulo
895
957
  , this.TipoDeCard, this.IconoDelModulo, this.ColorDelModulo, this.CorreoParaReportes, Version, this.versionDelNucleo().split(' ')[0], this.Repositorios
896
- , Version]);
958
+ , Version, this.Repositorios]);
897
959
  await ejecutarConsultaSIGU("SELECT IFNULL(MAX(`PermisoId`), 0) + 1 INTO @`SiguientePermisoId` FROM `SIGU`.`SIGU_PermisosV2`;\
898
960
  INSERT INTO `SIGU`.`SIGU_PermisosV2` VALUES\
899
961
  (@`SiguientePermisoId`, ?, ?, ?, NOW(4), USER()) ON DUPLICATE KEY UPDATE `LastUser` = USER(), `Nombre` = ?, `Descripcion` = ?;"
@@ -1192,7 +1254,7 @@ class Miscelaneo {
1192
1254
  }
1193
1255
 
1194
1256
  versionDelNucleo() {
1195
- return "2.0.82" + " " + this.NombreCanonicoDelModulo;
1257
+ return "VERSION_DEL_NUCLEO" + " " + this.NombreCanonicoDelModulo;
1196
1258
  }
1197
1259
 
1198
1260
  async destinatarioDeInformesDeError() {
@@ -1257,49 +1319,54 @@ class Miscelaneo {
1257
1319
  console.log(error);
1258
1320
  return;
1259
1321
  }
1260
- return ejecutarConsultaSIGU("SELECT `a`.`Identificador`, `a`.`Identificacion`\
1322
+ return await ejecutarConsultaSIGU("SELECT `a`.`Identificador`, `a`.`Identificacion`\
1261
1323
  , `a`.`Nombre`, `a`.`PrimerApellido`, `a`.`SegundoApellido`\
1262
1324
  , (SELECT GROUP_CONCAT(`b`.`CuentaIBAN`) FROM `SIGU`.`SIGU_CuentasBancariasPersonas` `b` WHERE `b`.`Estado` = TRUE AND `a`.`Identificador` = `b`.`Identificador`) AS `CuentasIBAN`\
1263
1325
  FROM `SIGU`.`SIGU_Personas` `a` WHERE `a`.`Identificador` = ?"
1264
1326
  , [Resultado.uid]);
1265
1327
  }
1266
1328
 
1267
- obtenerDatosDeLaPersonaPorIdentificacion(Identificacion) {
1268
- return ejecutarConsultaSIGU("SELECT `a`.`Identificador`, `a`.`Identificacion`\
1329
+ async obtenerDatosDeLaPersonaPorIdentificacion(Identificacion) {
1330
+ return await ejecutarConsultaSIGU("SELECT `a`.`Identificador`, `a`.`Identificacion`\
1269
1331
  , `a`.`Nombre`, `a`.`PrimerApellido`, `a`.`SegundoApellido`\
1270
1332
  , (SELECT GROUP_CONCAT(`b`.`CuentaIBAN`) FROM `SIGU`.`SIGU_CuentasBancariasPersonas` `b` WHERE `b`.`Estado` = TRUE AND `a`.`Identificador` = `b`.`Identificador`) AS `CuentasIBAN`\
1271
1333
  FROM `SIGU`.`SIGU_Personas` `a` WHERE `a`.`Identificacion` = ?"
1272
1334
  , [Identificacion]);
1273
1335
  }
1274
1336
 
1275
- obtenerEstudiantes() {
1276
- return ejecutarConsultaSIGU("SELECT `Identificador`, `Identificacion`, `Nombre`, `PrimerApellido`,\
1337
+ async obtenerEstudiantes() {
1338
+ return await ejecutarConsultaSIGU("SELECT `Identificador`, `Identificacion`, `Nombre`, `PrimerApellido`,\
1277
1339
  `SegundoApellido` FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` IN\
1278
1340
  (SELECT `Identificador` FROM `SIGU`.`SIGU_RolesPersonas` WHERE `PerfilGeneralId` = 1 /*El perfil 1 parece ser para Estudiantes*/)");
1279
1341
  }
1280
1342
 
1281
- obtenerBeneficios() {
1282
- return ejecutarConsultaSIGU("SELECT `BeneficioId`, `Beneficio`, `Estado` FROM `SIGU`.`SIGU_Beneficios`");
1343
+ async obtenerBeneficios() {
1344
+ return await ejecutarConsultaSIGU("SELECT `BeneficioId`, `Beneficio`, `Estado` FROM `SIGU`.`SIGU_Beneficios`");
1345
+ }
1346
+
1347
+ async obtenerIdentificacion(Identificador) {
1348
+ return await ejecutarConsultaSIGU("SELECT `Identificacion` FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` = ?", [Identificador]);
1283
1349
  }
1284
1350
 
1285
- obtenerIdentificacion(Identificador) {
1286
- return ejecutarConsultaSIGU("SELECT `Identificacion` FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` = ?", [Identificador]);
1351
+ async obtenerPeriodos() {
1352
+ return await ejecutarConsultaSIGU("SELECT `PeriodoId`, `CodigoPeriodo`, `Anio`, `Periodo`, `FechaInicio`, `FechaFinal`, `Tipo`, `Estado` FROM `SIGU`.`SIGU_Periodos` ORDER BY `Anio` DESC, `CodigoPeriodo` DESC");
1287
1353
  }
1288
1354
 
1289
- obtenerPeriodos() {
1290
- return ejecutarConsultaSIGU("SELECT `PeriodoId`, `CodigoPeriodo`, `Anio`, `Periodo`, `FechaInicio`, `FechaFinal`, `Tipo`, `Estado` FROM `SIGU`.`SIGU_Periodos` ORDER BY `Anio` DESC, `CodigoPeriodo` DESC");
1355
+ async obtenerAnios() {
1356
+ return await ejecutarConsultaSIGU("SELECT DISTINCT `Anio` FROM `SIGU`.`SIGU_Periodos`");
1291
1357
  }
1292
1358
 
1293
- obtenerAnios() {
1294
- return ejecutarConsultaSIGU("SELECT DISTINCT `Anio` FROM `SIGU`.`SIGU_Periodos`");
1359
+ async obtenerSedes() {
1360
+ return await ejecutarConsultaSIGU("SELECT `SedesId`, `CodigoAvatar`, `Descripcion`, `Siglas` FROM `SIGU`.`SIGU_Sedes` ORDER BY `Descripcion`");
1295
1361
  }
1296
1362
 
1297
- obtenerSedes() {
1298
- return ejecutarConsultaSIGU("SELECT `SedesId`, `CodigoAvatar`, `Descripcion`, `Siglas` FROM `SIGU`.`SIGU_Sedes` ORDER BY `Descripcion`");
1363
+ async obtenerRecintos() {
1364
+ return await ejecutarConsultaSIGU("SELECT `a`.`RecintoId`, CONCAT(`b`.`Descripcion`, '/', `a`.`Recinto`) AS `Recinto` FROM `SIGU`.`SIGU_Recintos` `a` LEFT JOIN `SIGU`.`SIGU_Sedes` `b` ON (`a`.`SedeId` = `b`.`SedesId`) ORDER BY `Recinto`");
1299
1365
  }
1300
1366
 
1301
- obtenerRecintos() {
1302
- return ejecutarConsultaSIGU("SELECT `a`.`RecintoId`, CONCAT(`b`.`Descripcion`, '/', `a`.`Recinto`) AS `Recinto` FROM `SIGU`.`SIGU_Recintos` `a` LEFT JOIN `SIGU`.`SIGU_Sedes` `b` ON (`a`.`SedeId` = `b`.`SedesId`) ORDER BY `Recinto`");
1367
+ async googleClientId() {
1368
+ const clientId = await ejecutarConsultaSIGU("SELECT `Valor` FROM `SIGU`.`SIGU_VariablesDeSistema` WHERE `Nombre` = 'Google-ClientId'");
1369
+ return clientId[0]?.['Valor'] || '';
1303
1370
  }
1304
1371
 
1305
1372
  async palabraSecretaParaTokens() {
@@ -377,6 +377,23 @@ class ReportePDF {
377
377
  // Como el texto de la izquierda tiene 2 líneas, alineamos la paginación un poco más abajo para que quede centrado
378
378
  doc.text(paginacion, centerX + 15, footerY + 14, { width: (pageWidth / 2) - margin - 15, align: 'right' });
379
379
 
380
+ // Si el documento tiene firmas y estamos en la última página, agregar la leyenda de seguridad
381
+ if (doc._tieneFirmas && i === range.start + range.count - 1) {
382
+ const leyenda = "Documento firmado electrónicamente con firma digital interna de la Universidad Técnica Nacional. Incluye un código de verificación único validable en el sistema SIGU. Cualquier modificación invalida su autenticidad.";
383
+ doc.fillColor("black").fontSize(6).font(this.config.fuenteBase);
384
+
385
+ // Calculamos la posición Y para que esté inmediatamente por encima de la línea del footer (footerY)
386
+ // Estimamos un alto aproximado dependiendo de cuantas líneas abarque el texto,
387
+ // pdfkit calculará la altura si usamos heightOfString, pero podemos darle un espacio fijo.
388
+ const alturaLeyenda = doc.heightOfString(leyenda, { width: pageWidth - 2 * margin, align: 'center' });
389
+ const yPosLeyenda = footerY - alturaLeyenda - 5;
390
+
391
+ doc.text(leyenda, margin, yPosLeyenda, {
392
+ width: pageWidth - 2 * margin,
393
+ align: 'center'
394
+ });
395
+ }
396
+
380
397
  // Restaurar el margen inferior original
381
398
  doc.page.margins.bottom = bottomMargin;
382
399
  }
@@ -682,6 +699,8 @@ class ReportePDF {
682
699
  generarFirmas(doc, firmas) {
683
700
  if (!firmas || !Array.isArray(firmas) || firmas.length === 0) return;
684
701
 
702
+ doc._tieneFirmas = true; // Marcar el documento como firmado para el pie de página
703
+
685
704
  const margin = this.config.margin;
686
705
  const pageWidth = doc.page.width;
687
706
  const availableWidth = pageWidth - 2 * margin;
@@ -86,7 +86,6 @@ class Servicio1 {
86
86
  // Resultados = await ejecutarConsultaSIGU(SELECTBase + " SELECT * FROM Datos WHERE " + WHERE + ORDERBY + " LIMIT ? OFFSET ?", [parseInt(Parametros.PaginadorTamanio), parseInt(Parametros.PaginadorIndice)]);
87
87
  // return { Registros: Resultados, TotalDeRegistros: Total[0]['Total'] };
88
88
  // }
89
- // const ss = "";
90
89
  // }
91
90
  // // Predeterminadamente se retornan los datos paginados pero sin filtrar
92
91
  // // Los símbolos &&&& se usan como valor predeterminado
@@ -172,6 +172,18 @@ export class GestionTablaXYZComponent {
172
172
  }
173
173
 
174
174
  obtenerDatosParaPoblarLaTabla() {
175
+ // let Filtrado = undefined
176
+ // if (this.PaginarResultados) {
177
+ // if (this.PaginadorTamanio === 0) {
178
+ // const pageSize = localStorage.getItem('pageSize');
179
+ // if (pageSize) {
180
+ // this.PaginadorTamanio = parseInt(pageSize);
181
+ // }
182
+ // }
183
+ // Filtrado = `/${this.PaginadorAccion}/${this.PaginadorIndice}/${this.PaginadorTamanio}/${this.PaginadorFiltro}/${this.PaginadorColumnaParaFiltrar}/${this.PaginadorColumnasParaFiltrar}/${this.ColumnaParaOrdenar}/${this.TipoDeOrden}`;
184
+ // } else {
185
+ // Filtrado = `/TablaSinFiltro/-/-/-/-/-/-/-`;
186
+ // }
175
187
  this.http.get(`${this.datosGlobalesService.ObtenerURL()}XYZ/listar`).subscribe({
176
188
  next: (datos: any) => {
177
189
  if (datos.error) {
@@ -17,6 +17,7 @@
17
17
  <link rel="icon" type="image/x-icon" href="favicon.ico">
18
18
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
19
19
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
20
+ <script src="https://accounts.google.com/gsi/client" async defer></script>
20
21
  </head>
21
22
 
22
23
  <body>