Estado base antes de integración Cognito.

Incluye admin web Spring Boot, API JWT para escáner y app Flutter qrscanner con login y escaneo de pases.
This commit is contained in:
Alejandro Lara
2026-06-09 15:51:44 -06:00
commit f8468350d5
2162 changed files with 433376 additions and 0 deletions
@@ -0,0 +1,16 @@
package mx.gob.slp.baseadminweb.jar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication(scanBasePackages = "mx.gob.slp.baseadminweb")
@EntityScan(basePackages = "mx.gob.slp.baseadminweb.domain.model")
@EnableJpaRepositories(basePackages = "mx.gob.slp.baseadminweb.domain.repository")
public class BaseAdminWebApplication {
public static void main(String[] args) {
SpringApplication.run(BaseAdminWebApplication.class, args);
}
}
@@ -0,0 +1,7 @@
spring:
jpa:
show-sql: true
logging:
level:
org.hibernate.SQL: DEBUG
@@ -0,0 +1,19 @@
spring:
datasource:
url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/base_admin_web}
username: ${SPRING_DATASOURCE_USERNAME:postgres}
password: ${SPRING_DATASOURCE_PASSWORD:postgres}
driver-class-name: org.postgresql.Driver
h2:
console:
enabled: false
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
logging:
level:
org.hibernate.SQL: INFO
@@ -0,0 +1,12 @@
spring:
thymeleaf:
cache: true
h2:
console:
enabled: false
jpa:
show-sql: false
logging:
level:
org.hibernate.SQL: WARN
@@ -0,0 +1,13 @@
spring:
datasource:
url: jdbc:h2:mem:baseadminweb-test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
jpa:
hibernate:
ddl-auto: create-drop
show-sql: false
thymeleaf:
cache: false
logging:
level:
root: WARN
@@ -0,0 +1,48 @@
spring:
application:
name: ${APP_NAME:base-admin-web}
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
thymeleaf:
cache: ${SPRING_THYMELEAF_CACHE:false}
datasource:
url: ${SPRING_DATASOURCE_URL:jdbc:h2:file:./data/h2/baseadminweb;MODE=PostgreSQL;AUTO_SERVER=TRUE}
username: ${SPRING_DATASOURCE_USERNAME:sa}
password: ${SPRING_DATASOURCE_PASSWORD:}
driver-class-name: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME:org.h2.Driver}
jpa:
hibernate:
ddl-auto: ${SPRING_JPA_HIBERNATE_DDL_AUTO:update}
open-in-view: false
show-sql: ${SPRING_JPA_SHOW_SQL:false}
properties:
hibernate:
format_sql: true
h2:
console:
enabled: ${SPRING_H2_CONSOLE_ENABLED:true}
path: /h2-console
server:
port: ${SERVER_PORT:8080}
servlet:
session:
timeout: 30m
logging:
level:
org.springframework.security: INFO
app:
title: ${APP_TITLE:Base Admin Web}
jwt:
secret: ${APP_JWT_SECRET:base-admin-web-dev-secret-change-me-32chars!!}
expiration-hours: ${APP_JWT_EXPIRATION_HOURS:8}
admin:
username: ${APP_ADMIN_USERNAME:admin}
password: ${APP_ADMIN_PASSWORD:Admin123*}
display-name: ${APP_ADMIN_DISPLAY_NAME:Administrador Base}
scanner:
username: ${APP_SCANNER_USERNAME:scanner}
password: ${APP_SCANNER_PASSWORD:Scanner123*}
display-name: ${APP_SCANNER_DISPLAY_NAME:Escaneador}
@@ -0,0 +1,40 @@
package mx.gob.slp.baseadminweb.jar;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class BaseAdminWebApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
void contextLoads() {
}
@Test
void shouldRedirectAnonymousUserToLogin() throws Exception {
mockMvc.perform(get("/dashboard"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/login"));
}
@Test
void shouldLoginWithSeededAdminUser() throws Exception {
mockMvc.perform(formLogin("/login").user("admin").password("Admin123*"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/dashboard"));
}
}
@@ -0,0 +1,91 @@
package mx.gob.slp.baseadminweb.jar;
import com.jayway.jsonpath.JsonPath;
import mx.gob.slp.baseadminweb.application.service.PassCodeService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class PassCodeApiTests {
@Autowired
private MockMvc mockMvc;
@Autowired
private PassCodeService passCodeService;
private String accessToken;
@BeforeEach
void loginScanner() throws Exception {
MvcResult loginResult = mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"username\":\"scanner\",\"password\":\"Scanner123*\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andReturn();
accessToken = JsonPath.read(loginResult.getResponse().getContentAsString(), "$.accessToken");
}
@Test
void shouldScanCreatedPassCode() throws Exception {
var created = passCodeService.create("Pase prueba");
mockMvc.perform(post("/api/pass-codes/scan")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"code\":\"" + created.getCode() + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.passCode.scanned").value(true))
.andExpect(jsonPath("$.passCode.status").value("UTILIZADO"));
mockMvc.perform(post("/api/pass-codes/scan")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"code\":\"" + created.getCode() + "\"}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false));
}
@Test
void shouldRejectUnknownPassCode() throws Exception {
mockMvc.perform(post("/api/pass-codes/scan")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"code\":\"ZZZZZZZZZZ\"}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false));
}
@Test
void shouldRejectScanWithoutToken() throws Exception {
mockMvc.perform(post("/api/pass-codes/scan")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"code\":\"ZZZZZZZZZZ\"}"))
.andExpect(status().isUnauthorized());
}
@Test
void shouldRejectAdminLoginOnApi() throws Exception {
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"username\":\"admin\",\"password\":\"Admin123*\"}"))
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.success").value(false));
}
}