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:
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>mx.gob.slp.baseadminweb</groupId>
|
||||
<artifactId>base-admin-web</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>base-admin-web-application</artifactId>
|
||||
<name>base-admin-web-application</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>mx.gob.slp.baseadminweb</groupId>
|
||||
<artifactId>base-admin-web-domain</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package mx.gob.slp.baseadminweb.application.config;
|
||||
|
||||
import mx.gob.slp.baseadminweb.domain.model.AppUser;
|
||||
import mx.gob.slp.baseadminweb.domain.model.Role;
|
||||
import mx.gob.slp.baseadminweb.domain.repository.AppUserRepository;
|
||||
import mx.gob.slp.baseadminweb.domain.repository.RoleRepository;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class InitialDataLoader implements CommandLineRunner {
|
||||
|
||||
private static final String ADMIN_ROLE = "ROLE_ADMIN";
|
||||
private static final String SCANNER_ROLE = "ROLE_SCANNER";
|
||||
|
||||
private final RoleRepository roleRepository;
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final String adminUsername;
|
||||
private final String adminPassword;
|
||||
private final String adminDisplayName;
|
||||
private final String scannerUsername;
|
||||
private final String scannerPassword;
|
||||
private final String scannerDisplayName;
|
||||
|
||||
public InitialDataLoader(RoleRepository roleRepository,
|
||||
AppUserRepository appUserRepository,
|
||||
PasswordEncoder passwordEncoder,
|
||||
@Value("${app.admin.username:admin}") String adminUsername,
|
||||
@Value("${app.admin.password:Admin123*}") String adminPassword,
|
||||
@Value("${app.admin.display-name:Administrador Base}") String adminDisplayName,
|
||||
@Value("${app.scanner.username:scanner}") String scannerUsername,
|
||||
@Value("${app.scanner.password:Scanner123*}") String scannerPassword,
|
||||
@Value("${app.scanner.display-name:Escaneador}") String scannerDisplayName) {
|
||||
this.roleRepository = roleRepository;
|
||||
this.appUserRepository = appUserRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.adminUsername = adminUsername;
|
||||
this.adminPassword = adminPassword;
|
||||
this.adminDisplayName = adminDisplayName;
|
||||
this.scannerUsername = scannerUsername;
|
||||
this.scannerPassword = scannerPassword;
|
||||
this.scannerDisplayName = scannerDisplayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
Role adminRole = roleRepository.findByName(ADMIN_ROLE)
|
||||
.orElseGet(() -> roleRepository.save(new Role(ADMIN_ROLE, "Administrador del sistema")));
|
||||
|
||||
appUserRepository.findByUsername(adminUsername).orElseGet(() -> {
|
||||
AppUser admin = new AppUser(
|
||||
adminUsername,
|
||||
passwordEncoder.encode(adminPassword),
|
||||
adminDisplayName,
|
||||
true
|
||||
);
|
||||
admin.addRole(adminRole);
|
||||
return appUserRepository.save(admin);
|
||||
});
|
||||
|
||||
Role scannerRole = roleRepository.findByName(SCANNER_ROLE)
|
||||
.orElseGet(() -> roleRepository.save(new Role(SCANNER_ROLE, "Escaneo de codigos pase")));
|
||||
|
||||
appUserRepository.findByUsername(scannerUsername).orElseGet(() -> {
|
||||
AppUser scanner = new AppUser(
|
||||
scannerUsername,
|
||||
passwordEncoder.encode(scannerPassword),
|
||||
scannerDisplayName,
|
||||
true
|
||||
);
|
||||
scanner.addRole(scannerRole);
|
||||
return appUserRepository.save(scanner);
|
||||
});
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package mx.gob.slp.baseadminweb.application.service;
|
||||
|
||||
import mx.gob.slp.baseadminweb.domain.repository.AppUserRepository;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AppUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final AppUserRepository appUserRepository;
|
||||
|
||||
public AppUserDetailsService(AppUserRepository appUserRepository) {
|
||||
this.appUserRepository = appUserRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
return appUserRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("Usuario no encontrado: " + username));
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package mx.gob.slp.baseadminweb.application.service;
|
||||
|
||||
import mx.gob.slp.baseadminweb.domain.model.PassCode;
|
||||
import mx.gob.slp.baseadminweb.domain.repository.PassCodeRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class PassCodeService {
|
||||
|
||||
private static final String CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
private static final int CODE_LENGTH = 10;
|
||||
private static final int MAX_GENERATION_ATTEMPTS = 20;
|
||||
|
||||
private final PassCodeRepository passCodeRepository;
|
||||
private final SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
public PassCodeService(PassCodeRepository passCodeRepository) {
|
||||
this.passCodeRepository = passCodeRepository;
|
||||
}
|
||||
|
||||
public List<PassCode> findAll() {
|
||||
return passCodeRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public PassCode create(String name) {
|
||||
String trimmedName = name == null ? "" : name.trim();
|
||||
if (trimmedName.isEmpty()) {
|
||||
throw new IllegalArgumentException("El nombre del codigo pase es obligatorio.");
|
||||
}
|
||||
|
||||
PassCode passCode = new PassCode(trimmedName, generateUniqueCode(), Instant.now());
|
||||
return passCodeRepository.save(passCode);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public PassCode scan(String code) {
|
||||
String trimmedCode = code == null ? "" : code.trim().toUpperCase();
|
||||
if (trimmedCode.isEmpty()) {
|
||||
throw new IllegalArgumentException("El codigo es obligatorio.");
|
||||
}
|
||||
|
||||
PassCode passCode = passCodeRepository.findByCode(trimmedCode)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Codigo pase no encontrado."));
|
||||
|
||||
if (passCode.isScanned()) {
|
||||
throw new IllegalStateException("El codigo pase ya fue escaneado.");
|
||||
}
|
||||
|
||||
passCode.markAsUsed(Instant.now());
|
||||
return passCodeRepository.save(passCode);
|
||||
}
|
||||
|
||||
private String generateUniqueCode() {
|
||||
for (int attempt = 0; attempt < MAX_GENERATION_ATTEMPTS; attempt++) {
|
||||
String candidate = randomCode();
|
||||
if (!passCodeRepository.existsByCode(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("No fue posible generar un codigo unico.");
|
||||
}
|
||||
|
||||
private String randomCode() {
|
||||
StringBuilder builder = new StringBuilder(CODE_LENGTH);
|
||||
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||
int index = secureRandom.nextInt(CODE_ALPHABET.length());
|
||||
builder.append(CODE_ALPHABET.charAt(index));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user