From a3050e01d5f5687036af2b6114d0a38d46be2011 Mon Sep 17 00:00:00 2001 From: Antigravity AI Date: Tue, 7 Apr 2026 22:27:50 -0300 Subject: [PATCH] Hito: Login Dinámico (.254), Logos Base64 y Responsables en Navbar --- VERSION.txt | 2 +- src/main/java/com/sigem/gis/security/AuthController.java | 52 ++++++++++++++++++++++++++++++++++++++++++---------- src/main/java/com/sigem/gis/security/AuthResponse.java | 18 +++++++++++++++++- src/main/resources/static/landing.html | 38 ++++++++++++++++++++++++++++++++++++-- src/main/resources/static/login.html | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------- src/main/resources/static/widgets.html | 6 +++--- 6 files changed, 185 insertions(+), 76 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 3030fb3..f9e4f05 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -9,4 +9,4 @@ PROYECTO GIS-GEOSERVER - 2026.04.06.01.13.00 ID DOCKER: d983a409769d. Observacià PROYECTO GIS-GEOSERVER - 2026.04.06.12.44.00 ID DOCKER: d983a409769d. Observación: Backup completo preventivo de la versión con estructura de Git corregida y Landing Page AdminLTE. PROYECTO GIS-GEOSERVER - 2026.04.06.13.31.00 ID DOCKER: d983a409769d. Observación: Prueba de funcionamiento del Manual v1.1 tras estandarización de prefijos y manual de recuperación. PROYECTO GIS-GEOSERVER - 2026.04.07.08.18.07 ID DOCKER: d983a409769d. Observación: Optimización visual de interfaz completada: unificación de anchos al 100%, limpieza de barra superior, traslado de controles al sidebar y registro legal SIGEM-MIC/DINAPI. -PROYECTO GIS-GEOSERVER - 2026.04.07.20.37.47 ID DOCKER: d983a409769d. Observación: Modernización definitiva del Dashboard completada: Replicación de bloque de bienvenida legado, integración de mapa embebido en modo limpio y reestructuración de la fila inferior de gestión al 100% de ancho. Versión estable validada. \ No newline at end of file +PROYECTO GIS-GEOSERVER - 2026.04.07.20.37.47 ID DOCKER: d983a409769d. Observación: Modernización definitiva del Dashboard completada: Replicación de bloque de bienvenida legado, integración de mapa embebido en modo limpio y reestructuración de la fila inferior de gestión al 100% de ancho. Versión estable validada.Version SIG (Abril 2026) - 2026.04.07.22.30.00 ID DOCKER: d983a409769d. Observación: Éxito en implementación de Login Dinámico (SaaS), integración de logos binarios, eslóganes y responsables desde el servidor .254. diff --git a/src/main/java/com/sigem/gis/security/AuthController.java b/src/main/java/com/sigem/gis/security/AuthController.java index 92a538a..acdbb90 100644 --- a/src/main/java/com/sigem/gis/security/AuthController.java +++ b/src/main/java/com/sigem/gis/security/AuthController.java @@ -8,6 +8,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.*; import com.sigem.gis.service.FdwService; +import java.util.Base64; import java.util.List; import java.util.Map; @@ -29,18 +30,38 @@ public class AuthController { @Autowired private FdwService fdwService; + @GetMapping("/entidades") + public ResponseEntity getEntidadesActivas() { + try { + String sql = "select entidad, nombre, entidad_logo, responsable, eslogan from public.entidades WHERE activo = TRUE ORDER BY entidad ASC"; + List> entidades = masterJdbcTemplate.queryForList(sql); + return ResponseEntity.ok(entidades); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error al cargar entidades"); + } + } + @PostMapping("/login") public ResponseEntity login(@RequestBody AuthRequest request) { try { // 1. Validar existencia de entidad en directorio maestro (en el .254) - String sqlEntidades = "SELECT sigem_site, sigem_dbname, lat, lng, zoom, minzoom, maxzoom, mapa_base, boundno, boundse FROM public.entidades WHERE activo= TRUE AND entidad = ?"; + String sqlEntidades = "SELECT sigem_site, sigem_dbname, lat, lng, zoom, minzoom, maxzoom, mapa_base, boundno, boundse, nombre, eslogan, entidad_logo, responsable FROM public.entidades WHERE activo= TRUE AND entidad = ?"; List> entidades = masterJdbcTemplate.queryForList(sqlEntidades, Integer.parseInt(request.getEntidad())); if (entidades.isEmpty()) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new AuthResponse(null, null, "Entidad Inactiva o No Encontrada")); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new AuthResponse(null, null, "La MUNICIPALIDAD con código " + request.getEntidad() + " no existe o está inactiva.")); } Map entidadData = entidades.get(0); + String nombreEntidad = convertObjectToString(entidadData.get("nombre")); + String eslogan = convertObjectToString(entidadData.get("eslogan")); + + // Tratamiento especial para el logo (Binario -> Base64) + Object logoObj = entidadData.get("entidad_logo"); + String logo = (logoObj instanceof byte[]) ? Base64.getEncoder().encodeToString((byte[]) logoObj) : convertObjectToString(logoObj); + + String responsable = convertObjectToString(entidadData.get("responsable")); // 2. Asegurar Infraestructura FDW (Regla 16: Solo crea si no existe) fdwService.setupFdw(request.getEntidad()); @@ -58,12 +79,12 @@ public class AuthController { if (!usuarios.isEmpty()) { Map userData = usuarios.get(0); boolean isActivo = (boolean) userData.get("activo"); - String claveDesencriptada = (String) userData.get("clave_desencriptada"); + String claveDesencriptada = convertObjectToString(userData.get("clave_desencriptada")); // 4. Validación Final y Generación de Token if (isActivo && request.getPassword().equals(claveDesencriptada)) { String token = jwtUtil.generateToken(request.getUsername(), request.getEntidad()); - String nombreCompleto = userData.get("usu_nom") + " " + userData.get("usu_ape"); + String nombreCompleto = convertObjectToString(userData.get("usu_nom")) + " " + convertObjectToString(userData.get("usu_ape")); // Metadatos georreferenciados de la entidad Double lat = parseDouble(entidadData.get("lat"), -25.456443); @@ -71,12 +92,13 @@ public class AuthController { Integer zoom = parseInteger(entidadData.get("zoom"), 14); Integer minZoom = parseInteger(entidadData.get("minzoom"), 5); Integer maxZoom = parseInteger(entidadData.get("maxzoom"), 20); - String mapaBase = String.valueOf(entidadData.getOrDefault("mapa_base", "osm")); - String bounds = String.valueOf(entidadData.getOrDefault("boundno", "")) + "|" + - String.valueOf(entidadData.getOrDefault("boundse", "")); + String mapaBase = convertObjectToString(entidadData.getOrDefault("mapa_base", "osm")); + String bounds = convertObjectToString(entidadData.getOrDefault("boundno", "")) + "|" + + convertObjectToString(entidadData.getOrDefault("boundse", "")); return ResponseEntity.ok(new AuthResponse(token, nombreCompleto, "Login Exitoso", - lat, lng, zoom, minZoom, maxZoom, mapaBase, bounds)); + lat, lng, zoom, minZoom, maxZoom, mapaBase, bounds, + nombreEntidad, eslogan, logo, responsable)); } } @@ -88,10 +110,19 @@ public class AuthController { } } + private String convertObjectToString(Object val) { + if (val == null) return null; + if (val instanceof byte[]) { + return new String((byte[]) val); + } + return String.valueOf(val); + } + private Double parseDouble(Object val, Double def) { if (val == null) return def; try { - return Double.parseDouble(String.valueOf(val).trim()); + String str = convertObjectToString(val); + return Double.parseDouble(str.trim()); } catch (Exception e) { return def; } @@ -100,7 +131,8 @@ public class AuthController { private Integer parseInteger(Object val, Integer def) { if (val == null) return def; try { - return Integer.parseInt(String.valueOf(val)); + String str = convertObjectToString(val); + return Integer.parseInt(str.trim()); } catch (Exception e) { return def; } diff --git a/src/main/java/com/sigem/gis/security/AuthResponse.java b/src/main/java/com/sigem/gis/security/AuthResponse.java index ede2a5a..a3f80e1 100644 --- a/src/main/java/com/sigem/gis/security/AuthResponse.java +++ b/src/main/java/com/sigem/gis/security/AuthResponse.java @@ -5,7 +5,7 @@ public class AuthResponse { private String nombre; private String message; - // Metadatos Cartográficos (Nuevos) + // Metadatos Cartográficos private Double lat; private Double lng; private Integer zoom; @@ -13,6 +13,10 @@ public class AuthResponse { private Integer maxZoom; private String mapaBase; private String bounds; + private String entidadNombre; + private String eslogan; + private String entidadLogo; + private String responsable; public AuthResponse(String token, String nombre, String message) { this.token = token; @@ -33,6 +37,14 @@ public class AuthResponse { this.bounds = bounds; } + public AuthResponse(String token, String nombre, String message, Double lat, Double lng, Integer zoom, Integer minZoom, Integer maxZoom, String mapaBase, String bounds, String entidadNombre, String eslogan, String entidadLogo, String responsable) { + this(token, nombre, message, lat, lng, zoom, minZoom, maxZoom, mapaBase, bounds); + this.entidadNombre = entidadNombre; + this.eslogan = eslogan; + this.entidadLogo = entidadLogo; + this.responsable = responsable; + } + // Getters y Setters public String getToken() { return token; } public String getNombre() { return nombre; } @@ -44,4 +56,8 @@ public class AuthResponse { public Integer getMaxZoom() { return maxZoom; } public String getMapaBase() { return mapaBase; } public String getBounds() { return bounds; } + public String getEntidadNombre() { return entidadNombre; } + public String getEslogan() { return eslogan; } + public String getEntidadLogo() { return entidadLogo; } + public String getResponsable() { return responsable; } } diff --git a/src/main/resources/static/landing.html b/src/main/resources/static/landing.html index b6f3065..892f8c9 100644 --- a/src/main/resources/static/landing.html +++ b/src/main/resources/static/landing.html @@ -35,7 +35,19 @@ @@ -163,7 +175,29 @@ } document.getElementById('nav-user-text').innerText = userName || 'Operador Local'; - document.getElementById('nav-entidad-text').innerText = entidad || 'N/D'; + const entNombre = localStorage.getItem('entidad_nombre') || (entidad || 'N/D'); + const entEslogan = localStorage.getItem('eslogan') || ''; + const entResponsable = localStorage.getItem('responsable') || 'Gestión Municipal'; + const entLogoBase64 = localStorage.getItem('entidad_logo'); + + document.getElementById('nav-entidad-text').innerText = entNombre; + document.getElementById('nav-responsable-text').innerText = `Administración: ${entResponsable}`; + + // Configurar Logo + const logoImg = document.getElementById('nav-entidad-logo'); + if (entLogoBase64 && entLogoBase64 !== 'null' && entLogoBase64.length > 100) { + // Si no tiene el prefijo de data image, se lo agregamos + logoImg.src = entLogoBase64.startsWith('data:') ? entLogoBase64 : `data:image/png;base64,${entLogoBase64}`; + logoImg.style.display = 'block'; + } + + // Si el eslogan no está ya contenido en el nombre (para evitar duplicados), mostrarlo + const navEslogan = document.getElementById('nav-eslogan-text'); + if (entEslogan && !entNombre.toLowerCase().includes(entEslogan.toLowerCase())) { + navEslogan.innerText = entEslogan; + } else { + navEslogan.innerText = ''; + } function notImplemented() { alert("OPCIÓN NO IMPLEMENTADA"); diff --git a/src/main/resources/static/login.html b/src/main/resources/static/login.html index 312e629..6a05e72 100644 --- a/src/main/resources/static/login.html +++ b/src/main/resources/static/login.html @@ -5,7 +5,7 @@ Inicie Sesión - Ecosistema SIGEM - + @@ -29,14 +29,16 @@ .login-logo a { color: #333 !important; } + #municipioSearch::placeholder { + font-size: 0.85rem; + } -