Compare commits
7 Commits
82f41c9219
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dead14b1bd | ||
|
|
6a5a4b6871 | ||
|
|
d3c19a6186 | ||
|
|
681b6a3ba2 | ||
|
|
4303caaf74 | ||
|
|
33b3a460ca | ||
|
|
704ab79d7d |
20
TODO
20
TODO
@@ -1,14 +1,18 @@
|
|||||||
POR HACER --------------------------------
|
POR HACER --------------------------------
|
||||||
|
- implementar urlParams para filtros
|
||||||
|
- documentación
|
||||||
|
- mail wrapper
|
||||||
|
|
||||||
|
RESUELTO ---------------------------------
|
||||||
- añadir colaborador desde perfil
|
- añadir colaborador desde perfil
|
||||||
- apuntarse lista espera
|
- apuntarse lista espera
|
||||||
- aceptar solicitudes LE/Colab (sobre todo por crear preusers)
|
- aceptar solicitudes LE/Colab (sobre todo por crear preusers)
|
||||||
- mail wrapper
|
|
||||||
- documentación
|
|
||||||
- cambiar contraseña (?)
|
|
||||||
- implementar urlParams para filtros
|
|
||||||
- sistema comun de errores en back & front
|
|
||||||
|
|
||||||
|
|
||||||
RESUELTO ---------------------------------
|
|
||||||
- mejorar queries para no filtrar en memoria -> IMPOSIBLE CON ENDPOINTS INTERNOS DE CORE: RESUELTO CON CACHING
|
- mejorar queries para no filtrar en memoria -> IMPOSIBLE CON ENDPOINTS INTERNOS DE CORE: RESUELTO CON CACHING
|
||||||
- normalizar el uso de services y repositories desde otros services y repositories
|
- normalizar el uso de services y repositories desde otros services y repositories
|
||||||
|
- sistema comun de errores en back & front
|
||||||
|
- nombre del requester
|
||||||
|
- cambiar contraseña (?)
|
||||||
|
- todos los socios en dropdown ingresos
|
||||||
|
- validacion LE/COlab
|
||||||
|
- createdAt custom en ing,gastos
|
||||||
|
- editar createdAt
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>25</java.version>
|
<java.version>25</java.version>
|
||||||
|
|||||||
@@ -7,11 +7,15 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ApiValidationErrorDto {
|
public class ApiValidationErrorDto {
|
||||||
|
private int status;
|
||||||
private Map<String,String> errors;
|
private Map<String,String> errors;
|
||||||
|
private String path;
|
||||||
private Instant timestamp;
|
private Instant timestamp;
|
||||||
|
|
||||||
public ApiValidationErrorDto(Map<String,String> errors) {
|
public ApiValidationErrorDto(Map<String,String> errors, String path) {
|
||||||
|
this.status = 422;
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
|
this.path = path;
|
||||||
this.timestamp = Instant.now();
|
this.timestamp = Instant.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +23,22 @@ public class ApiValidationErrorDto {
|
|||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
public void setErrors(Map<String,String> errors) {
|
public void setErrors(Map<String,String> errors) {
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package net.miarma.backlib.filter;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class RequestLoggingFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain filterChain
|
||||||
|
) throws ServletException, IOException {
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
|
||||||
|
long duration = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
|
log.info("({}) {} {} -> {} ({} ms)",
|
||||||
|
request.getRemoteAddr(),
|
||||||
|
request.getMethod(),
|
||||||
|
request.getRequestURI(),
|
||||||
|
response.getStatus(),
|
||||||
|
duration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
package net.miarma.backend.huertos.config;
|
package net.miarma.backlib.http;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class CorsConfig {
|
@Profile("dev") // esto asegura que solo se cargue en dev
|
||||||
|
public class DevCorsConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebMvcConfigurer corsConfigurer() {
|
public WebMvcConfigurer corsConfigurer() {
|
||||||
@@ -14,12 +16,10 @@ public class CorsConfig {
|
|||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**")
|
registry.addMapping("/**")
|
||||||
.allowedOrigins(
|
.allowedOrigins("http://localhost:3000") // tu frontend React
|
||||||
"http://localhost:3000"
|
|
||||||
)
|
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
.allowedHeaders("*")
|
.allowCredentials(true)
|
||||||
.allowCredentials(true);
|
.allowedHeaders("*");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -84,9 +84,10 @@ public class GlobalExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ValidationException.class)
|
@ExceptionHandler(ValidationException.class)
|
||||||
public ResponseEntity<ApiValidationErrorDto> handleValidation(ValidationException ex) {
|
public ResponseEntity<ApiValidationErrorDto> handleValidation(
|
||||||
|
ValidationException ex, HttpServletRequest req) {
|
||||||
Map<String, String> errors = Map.of(ex.getField(), ex.getMessage());
|
Map<String, String> errors = Map.of(ex.getField(), ex.getMessage());
|
||||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(new ApiValidationErrorDto(errors));
|
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(new ApiValidationErrorDto(errors, req.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
artifactId=backlib
|
artifactId=backlib
|
||||||
groupId=net.miarma
|
groupId=net.miarma
|
||||||
version=1.0.1
|
version=1.1.0
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/config/SecurityCommonConfig.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/config/SecurityCommonConfig.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ApiErrorDto.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ApiErrorDto.java
|
||||||
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ApiValidationErrorDto.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeAvatarRequest.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeAvatarRequest.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangePasswordRequest.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangePasswordRequest.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeRoleRequest.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeRoleRequest.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeStatusRequest.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/ChangeStatusRequest.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/CreateCredentialDto.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/CreateCredentialDto.java
|
||||||
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/CreateUserDto.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/CredentialDto.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/CredentialDto.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/FileDto.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/FileDto.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/LoginRequest.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/dto/LoginRequest.java
|
||||||
@@ -19,10 +21,13 @@
|
|||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/NotFoundException.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/NotFoundException.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/UnauthorizedException.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/UnauthorizedException.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/ValidationException.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/exception/ValidationException.java
|
||||||
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/filter/RequestLoggingFilter.java
|
||||||
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/DevCorsConfig.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/GlobalExceptionHandler.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/GlobalExceptionHandler.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/RestAccessDeniedHandler.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/RestAccessDeniedHandler.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/RestAuthEntryPoint.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/http/RestAuthEntryPoint.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/CoreAuthTokenHolder.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/CoreAuthTokenHolder.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/JwtService.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/JwtService.java
|
||||||
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/PasswordGenerator.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/ServiceAuthFilter.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/security/ServiceAuthFilter.java
|
||||||
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/util/UuidUtil.java
|
/home/jomaa/git/miarma-backend/backlib/src/main/java/net/miarma/backlib/util/UuidUtil.java
|
||||||
|
|||||||
10
build-upload.sh
Executable file
10
build-upload.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd core/
|
||||||
|
mvn clean package
|
||||||
|
cd ..
|
||||||
|
cd huertos/
|
||||||
|
mvn clean package
|
||||||
|
cd ..
|
||||||
|
scp core/target/core-1.0.0.jar jomaa@10.0.0.254:/home/jomaa/transfer
|
||||||
|
scp huertos/target/huertos-1.0.0.jar jomaa@10.0.0.254:/home/jomaa/transfer
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package net.miarma.backend.core.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class CorsConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebMvcConfigurer corsConfigurer() {
|
|
||||||
return new WebMvcConfigurer() {
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/**")
|
|
||||||
.allowedOrigins(
|
|
||||||
"http://localhost:3000",
|
|
||||||
"http://localhost:8081",
|
|
||||||
"http://huertos:8081"
|
|
||||||
)
|
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
|
||||||
.allowedHeaders("*")
|
|
||||||
.allowCredentials(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,22 +5,16 @@ import net.miarma.backlib.http.RestAccessDeniedHandler;
|
|||||||
import net.miarma.backlib.http.RestAuthEntryPoint;
|
import net.miarma.backlib.http.RestAuthEntryPoint;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -29,34 +23,27 @@ public class SecurityConfig {
|
|||||||
private final JwtFilter jwtFilter;
|
private final JwtFilter jwtFilter;
|
||||||
private final RestAuthEntryPoint authEntryPoint;
|
private final RestAuthEntryPoint authEntryPoint;
|
||||||
private final RestAccessDeniedHandler accessDeniedHandler;
|
private final RestAccessDeniedHandler accessDeniedHandler;
|
||||||
|
private final CorsConfigurationSource corsConfigurationSource;
|
||||||
|
|
||||||
public SecurityConfig(
|
public SecurityConfig(
|
||||||
JwtFilter jwtFilter,
|
JwtFilter jwtFilter,
|
||||||
RestAuthEntryPoint authEntryPoint,
|
RestAuthEntryPoint authEntryPoint,
|
||||||
RestAccessDeniedHandler accessDeniedHandler
|
RestAccessDeniedHandler accessDeniedHandler,
|
||||||
|
Optional<CorsConfigurationSource> corsConfigurationSource
|
||||||
) {
|
) {
|
||||||
this.jwtFilter = jwtFilter;
|
this.jwtFilter = jwtFilter;
|
||||||
this.authEntryPoint = authEntryPoint;
|
this.authEntryPoint = authEntryPoint;
|
||||||
this.accessDeniedHandler = accessDeniedHandler;
|
this.accessDeniedHandler = accessDeniedHandler;
|
||||||
}
|
this.corsConfigurationSource = corsConfigurationSource.orElse(null);
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CorsConfigurationSource corsConfigurationSource() {
|
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
|
||||||
config.setAllowedOrigins(List.of("http://localhost:3000"));
|
|
||||||
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
|
|
||||||
config.setAllowedHeaders(List.of("*"));
|
|
||||||
config.setAllowCredentials(true);
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
source.registerCorsConfiguration("/**", config);
|
|
||||||
return source;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
if (corsConfigurationSource != null) {
|
||||||
|
http.cors(Customizer.withDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
http
|
http
|
||||||
.cors(Customizer.withDefaults())
|
|
||||||
.csrf(csrf -> csrf.disable())
|
.csrf(csrf -> csrf.disable())
|
||||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.exceptionHandling(ex -> ex
|
.exceptionHandling(ex -> ex
|
||||||
@@ -64,7 +51,10 @@ public class SecurityConfig {
|
|||||||
.accessDeniedHandler(accessDeniedHandler)
|
.accessDeniedHandler(accessDeniedHandler)
|
||||||
)
|
)
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/auth/**", "/screenshot").permitAll()
|
.requestMatchers("/auth/login").permitAll()
|
||||||
|
.requestMatchers("/auth/refresh").permitAll()
|
||||||
|
.requestMatchers("/auth/change-password").permitAll()
|
||||||
|
.requestMatchers("/screenshot").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import net.miarma.backlib.dto.*;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@@ -14,25 +15,16 @@ import net.miarma.backend.core.model.Credential;
|
|||||||
import net.miarma.backend.core.service.AuthService;
|
import net.miarma.backend.core.service.AuthService;
|
||||||
import net.miarma.backend.core.service.CredentialService;
|
import net.miarma.backend.core.service.CredentialService;
|
||||||
import net.miarma.backlib.security.JwtService;
|
import net.miarma.backlib.security.JwtService;
|
||||||
import net.miarma.backlib.dto.ChangePasswordRequest;
|
|
||||||
import net.miarma.backlib.dto.LoginRequest;
|
|
||||||
import net.miarma.backlib.dto.LoginResponse;
|
|
||||||
import net.miarma.backlib.dto.RegisterRequest;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/auth")
|
@RequestMapping("/auth")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
private final CredentialService credentialService;
|
|
||||||
private final JwtService jwtService;
|
private final JwtService jwtService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
private final AuthService authService;
|
private final AuthService authService;
|
||||||
|
|
||||||
public AuthController(CredentialService credentialService, JwtService jwtService,
|
public AuthController(JwtService jwtService, AuthService authService) {
|
||||||
PasswordEncoder passwordEncoder, AuthService authService) {
|
|
||||||
this.credentialService = credentialService;
|
|
||||||
this.jwtService = jwtService;
|
this.jwtService = jwtService;
|
||||||
this.passwordEncoder = passwordEncoder;
|
|
||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,15 +41,29 @@ public class AuthController {
|
|||||||
return ResponseEntity.ok(authService.register(request));
|
return ResponseEntity.ok(authService.register(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/refresh")
|
@GetMapping("/refresh")
|
||||||
public ResponseEntity<?> refreshToken(@RequestHeader("Authorization") String authHeader) {
|
public ResponseEntity<?> refreshToken(@RequestHeader("Authorization") String authHeader) {
|
||||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
return ResponseEntity.status(401).body("Token missing");
|
return ResponseEntity.status(401).body(
|
||||||
|
new ApiErrorDto(
|
||||||
|
401,
|
||||||
|
"Unauthorized",
|
||||||
|
"No hay token",
|
||||||
|
"/v2/core/auth/change-password"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String token = authHeader.substring(7);
|
String token = authHeader.substring(7);
|
||||||
if (!jwtService.validateToken(token)) {
|
if (!jwtService.validateToken(token)) {
|
||||||
return ResponseEntity.status(401).body("Invalid token");
|
return ResponseEntity.status(401).body(
|
||||||
|
new ApiErrorDto(
|
||||||
|
401,
|
||||||
|
"Unauthorized",
|
||||||
|
"Invalid token",
|
||||||
|
"/v2/core/auth/change-password"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID userId = jwtService.getUserId(token);
|
UUID userId = jwtService.getUserId(token);
|
||||||
@@ -75,35 +81,37 @@ public class AuthController {
|
|||||||
@PostMapping("/change-password")
|
@PostMapping("/change-password")
|
||||||
public ResponseEntity<?> changePassword(
|
public ResponseEntity<?> changePassword(
|
||||||
@RequestHeader("Authorization") String authHeader,
|
@RequestHeader("Authorization") String authHeader,
|
||||||
@Valid @RequestBody ChangePasswordRequest request
|
@RequestBody ChangePasswordRequest request
|
||||||
) {
|
) {
|
||||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
return ResponseEntity.status(401).body("Token missing");
|
return ResponseEntity.status(401).body(
|
||||||
|
new ApiErrorDto(
|
||||||
|
401,
|
||||||
|
"Unauthorized",
|
||||||
|
"No hay token",
|
||||||
|
"/v2/core/auth/change-password"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String token = authHeader.substring(7);
|
String token = authHeader.substring(7);
|
||||||
if (!jwtService.validateToken(token)) {
|
if (!jwtService.validateToken(token)) {
|
||||||
return ResponseEntity.status(401).body("Invalid token");
|
return ResponseEntity.status(401).body(
|
||||||
|
new ApiErrorDto(
|
||||||
|
401,
|
||||||
|
"Unauthorized",
|
||||||
|
"Invalid token",
|
||||||
|
"/v2/core/auth/change-password"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID userId = jwtService.getUserId(token);
|
UUID userId = jwtService.getUserId(token);
|
||||||
|
|
||||||
Credential cred = credentialService.getByUserId(userId)
|
authService.changePassword(userId, request);
|
||||||
.stream()
|
return ResponseEntity.ok(Map.of("message", "Contraseña cambiada correctamente"));
|
||||||
.filter(c -> c.getServiceId().equals(request.serviceId()))
|
|
||||||
.findFirst().get();
|
|
||||||
if (cred == null) {
|
|
||||||
return ResponseEntity.status(404).body("Credential not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
|
|
||||||
return ResponseEntity.status(400).body("Old password is incorrect");
|
|
||||||
}
|
|
||||||
|
|
||||||
credentialService.updatePassword(cred.getCredentialId(), request);
|
|
||||||
|
|
||||||
return ResponseEntity.ok(Map.of("message", "Password changed successfully"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/validate")
|
@GetMapping("/validate")
|
||||||
public ResponseEntity<Boolean> validate(@RequestHeader("Authorization") String authHeader) {
|
public ResponseEntity<Boolean> validate(@RequestHeader("Authorization") String authHeader) {
|
||||||
|
|||||||
@@ -70,17 +70,18 @@ public class CredentialController {
|
|||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{credential_id}/status")
|
@GetMapping("/{service_id}/{user_id}/status")
|
||||||
public ResponseEntity<Byte> getStatus(@PathVariable("credential_id") UUID credentialId) {
|
public ResponseEntity<Byte> getStatus(@PathVariable("user_id") UUID userId, @PathVariable("service_id") Byte serviceId) {
|
||||||
return ResponseEntity.ok(credentialService.getStatus(credentialId));
|
return ResponseEntity.ok(credentialService.getStatus(userId, serviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{credential_id}/status")
|
@PutMapping("/{service_id}/{user_id}/status")
|
||||||
public ResponseEntity<Void> updateStatus(
|
public ResponseEntity<Void> updateStatus(
|
||||||
@PathVariable("credential_id") UUID credentialId,
|
@PathVariable("user_id") UUID userId,
|
||||||
|
@PathVariable("service_id") Byte serviceId,
|
||||||
@RequestBody ChangeStatusRequest req
|
@RequestBody ChangeStatusRequest req
|
||||||
) {
|
) {
|
||||||
credentialService.updateStatus(credentialId, req.status());
|
credentialService.updateStatus(userId, serviceId, req.status());
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,33 +44,44 @@ public class FileController {
|
|||||||
return ResponseEntity.ok(files);
|
return ResponseEntity.ok(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{fileId}")
|
@GetMapping("/{file_id}")
|
||||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#file_id, authentication.principal.userId)")
|
||||||
public ResponseEntity<File> getById(@PathVariable("file_id") UUID fileId) {
|
public ResponseEntity<File> getById(@PathVariable("file_id") UUID fileId) {
|
||||||
File file = fileService.getById(fileId);
|
File file = fileService.getById(fileId);
|
||||||
return ResponseEntity.ok(file);
|
return ResponseEntity.ok(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping(consumes = "multipart/form-data")
|
||||||
@PreAuthorize("hasRole('ADMIN') or #uploadedBy == authentication.principal.userId")
|
@PreAuthorize("hasRole('ADMIN') or #uploadedBy == authentication.principal.userId")
|
||||||
public ResponseEntity<FileDto.Response> create(
|
public ResponseEntity<FileDto.Response> create(
|
||||||
@RequestBody FileDto.Request dto,
|
@RequestPart("file") MultipartFile file,
|
||||||
@RequestPart("file") MultipartFile file
|
@RequestPart("fileName") String fileName,
|
||||||
|
@RequestPart("mimeType") String mimeType,
|
||||||
|
@RequestPart("uploadedBy") UUID uploadedBy,
|
||||||
|
@RequestPart("context") Integer context
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
File created = fileService.create(FileMapper.toEntity(dto), file.getBytes());
|
|
||||||
return ResponseEntity.status(HttpStatus.CREATED).body(FileMapper.toResponse(created));
|
File entity = new File();
|
||||||
|
entity.setFileName(fileName);
|
||||||
|
entity.setMimeType(mimeType);
|
||||||
|
entity.setUploadedBy(uploadedBy);
|
||||||
|
entity.setContext(context.byteValue());
|
||||||
|
|
||||||
|
File created = fileService.create(entity, file.getBytes());
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
|
.body(FileMapper.toResponse(created));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{fileId}")
|
@PutMapping("/{file_id}")
|
||||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#file_id, authentication.principal.userId)")
|
||||||
public ResponseEntity<File> update(@PathVariable("fileId") UUID fileId, @RequestBody FileDto.Request request) {
|
public ResponseEntity<File> update(@PathVariable("file_id") UUID fileId, @RequestBody FileDto.Request request) {
|
||||||
File updated = fileService.update(fileId, FileMapper.toEntity(request));
|
File updated = fileService.update(fileId, FileMapper.toEntity(request));
|
||||||
return ResponseEntity.ok(updated);
|
return ResponseEntity.ok(updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{fileId}")
|
@DeleteMapping("/{file_id}")
|
||||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#file_id, authentication.principal.userId)")
|
||||||
public ResponseEntity<Void> delete(@PathVariable("fileId") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
public ResponseEntity<Void> delete(@PathVariable("file_id") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
||||||
String filePath = body.get("file_path");
|
String filePath = body.get("file_path");
|
||||||
Files.deleteIfExists(Paths.get(filePath));
|
Files.deleteIfExists(Paths.get(filePath));
|
||||||
fileService.delete(fileId);
|
fileService.delete(fileId);
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ package net.miarma.backend.core.service;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import net.miarma.backlib.dto.*;
|
import net.miarma.backlib.dto.*;
|
||||||
import net.miarma.backlib.exception.ConflictException;
|
import net.miarma.backlib.exception.*;
|
||||||
import net.miarma.backlib.exception.ForbiddenException;
|
|
||||||
import net.miarma.backlib.exception.UnauthorizedException;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -75,4 +73,22 @@ public class AuthService {
|
|||||||
|
|
||||||
return new LoginResponse(token, UserMapper.toDto(user), CredentialMapper.toDto(cred));
|
return new LoginResponse(token, UserMapper.toDto(user), CredentialMapper.toDto(cred));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void changePassword(UUID userId, ChangePasswordRequest request) {
|
||||||
|
Credential cred = credentialService.getByUserId(userId)
|
||||||
|
.stream()
|
||||||
|
.filter(c -> c.getServiceId().equals(request.serviceId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NotFoundException("Cuenta no encontrada"));
|
||||||
|
|
||||||
|
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
|
||||||
|
throw new ValidationException("oldPassword", "La contraseña actual es incorrecta");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.newPassword().length() < 8) {
|
||||||
|
throw new ValidationException("newPassword", "La nueva contraseña debe tener al menos 8 caracteres");
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialService.updatePassword(cred.getCredentialId(), request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ import net.miarma.backlib.util.UuidUtil;
|
|||||||
public class CredentialService {
|
public class CredentialService {
|
||||||
|
|
||||||
private final CredentialRepository credentialRepository;
|
private final CredentialRepository credentialRepository;
|
||||||
|
private final UserService userService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
public CredentialService(CredentialRepository credentialRepository, PasswordEncoder passwordEncoder) {
|
public CredentialService(CredentialRepository credentialRepository, UserService userService, PasswordEncoder passwordEncoder) {
|
||||||
this.credentialRepository = credentialRepository;
|
this.credentialRepository = credentialRepository;
|
||||||
|
this.userService = userService;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,15 +157,13 @@ public class CredentialService {
|
|||||||
credentialRepository.deleteById(idBytes);
|
credentialRepository.deleteById(idBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Byte getStatus(UUID credentialId) {
|
public Byte getStatus(UUID userId, Byte serviceId) {
|
||||||
Credential credential = credentialRepository.findById(UuidUtil.uuidToBin(credentialId))
|
Credential credential = getByUserIdAndService(userId, serviceId);
|
||||||
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
|
|
||||||
return credential.getStatus();
|
return credential.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateStatus(UUID credentialId, Byte status) {
|
public void updateStatus(UUID userId, Byte serviceId, Byte status) {
|
||||||
Credential credential = credentialRepository.findById(UuidUtil.uuidToBin(credentialId))
|
Credential credential = getByUserIdAndService(userId, serviceId);
|
||||||
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
|
|
||||||
credential.setStatus(status);
|
credential.setStatus(status);
|
||||||
credentialRepository.save(credential);
|
credentialRepository.save(credential);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package net.miarma.backend.huertos.client;
|
package net.miarma.backend.huertos.client;
|
||||||
|
|
||||||
|
import net.miarma.backlib.dto.ApiErrorDto;
|
||||||
import net.miarma.backlib.dto.LoginRequest;
|
import net.miarma.backlib.dto.LoginRequest;
|
||||||
import net.miarma.backlib.dto.LoginResponse;
|
import net.miarma.backlib.dto.LoginResponse;
|
||||||
|
import net.miarma.backlib.exception.*;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.HttpClientErrorException;
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.HttpServerErrorException;
|
import org.springframework.web.client.HttpServerErrorException;
|
||||||
@@ -25,10 +28,46 @@ public class CoreAuthClient {
|
|||||||
|
|
||||||
|
|
||||||
public LoginResponse login(LoginRequest req) {
|
public LoginResponse login(LoginRequest req) {
|
||||||
return restTemplate.postForObject(
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
HttpEntity<LoginRequest> requestEntity = new HttpEntity<>(req, headers);
|
||||||
|
|
||||||
|
ResponseEntity<LoginResponse> response = restTemplate.exchange(
|
||||||
coreUrl + "/auth/login",
|
coreUrl + "/auth/login",
|
||||||
req,
|
HttpMethod.POST,
|
||||||
|
requestEntity,
|
||||||
LoginResponse.class
|
LoginResponse.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleError(ResponseEntity<?> response) {
|
||||||
|
HttpStatusCode statusCode = response.getStatusCode();
|
||||||
|
|
||||||
|
if (statusCode.equals(HttpStatus.UNAUTHORIZED)) {
|
||||||
|
throw new UnauthorizedException("Credenciales no válidas");
|
||||||
|
} else if (statusCode.equals(HttpStatus.FORBIDDEN)) {
|
||||||
|
throw new ForbiddenException("Esa cuenta está desactivada");
|
||||||
|
} else if (statusCode.equals(HttpStatus.NOT_FOUND)) {
|
||||||
|
throw new NotFoundException("No encontrado");
|
||||||
|
} else if (statusCode.equals(HttpStatus.BAD_REQUEST)) {
|
||||||
|
throw new BadRequestException("Datos de solicitud faltantes");
|
||||||
|
} else if (statusCode.equals(HttpStatus.CONFLICT)) {
|
||||||
|
throw new ConflictException("Ya existe");
|
||||||
|
} else if (statusCode.equals(HttpStatus.UNPROCESSABLE_CONTENT)) {
|
||||||
|
throw new ValidationException("general", "Los datos no tienen formato válido");
|
||||||
|
} else {
|
||||||
|
if (statusCode.is4xxClientError()) {
|
||||||
|
throw new BadRequestException(response.getBody().toString());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error desconocido");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import net.miarma.backend.huertos.dto.RequestMetadataDto;
|
|||||||
import net.miarma.backend.huertos.model.RequestMetadata;
|
import net.miarma.backend.huertos.model.RequestMetadata;
|
||||||
import net.miarma.backend.huertos.util.UsernameGenerator;
|
import net.miarma.backend.huertos.util.UsernameGenerator;
|
||||||
import net.miarma.backlib.dto.*;
|
import net.miarma.backlib.dto.*;
|
||||||
|
import net.miarma.backlib.exception.*;
|
||||||
import net.miarma.backlib.security.PasswordGenerator;
|
import net.miarma.backlib.security.PasswordGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -19,44 +22,69 @@ public class HuertosWebClient {
|
|||||||
|
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private final String coreUrl;
|
private final String coreUrl;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
public HuertosWebClient(@Qualifier("secureRestTemplate") RestTemplate restTemplate,
|
public HuertosWebClient(@Qualifier("secureRestTemplate") RestTemplate restTemplate,
|
||||||
@Value("${core.url}") String coreUrl) {
|
@Value("${core.url}") String coreUrl,
|
||||||
|
ObjectMapper objectMapper) {
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
this.coreUrl = coreUrl;
|
this.coreUrl = coreUrl;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserWithCredentialDto getUserWithCredential(UUID userId, Byte serviceId) {
|
public UserWithCredentialDto getUserWithCredential(UUID userId, Byte serviceId) {
|
||||||
return restTemplate.getForObject(
|
ResponseEntity<UserWithCredentialDto> response = restTemplate.exchange(
|
||||||
coreUrl + "/users/{user_id}/service/{service_id}",
|
coreUrl + "/users/{user_id}/service/{service_id}",
|
||||||
|
HttpMethod.GET,
|
||||||
|
null,
|
||||||
UserWithCredentialDto.class,
|
UserWithCredentialDto.class,
|
||||||
userId, serviceId
|
userId, serviceId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserWithCredentialDto> getAllUsersWithCredentials(Byte serviceId) {
|
public List<UserWithCredentialDto> getAllUsersWithCredentials(Byte serviceId) {
|
||||||
UserWithCredentialDto[] arr = restTemplate.getForObject(
|
ResponseEntity<UserWithCredentialDto[]> response = restTemplate.exchange(
|
||||||
coreUrl + "/users/service/{service_id}",
|
coreUrl + "/users/service/{service_id}",
|
||||||
|
HttpMethod.GET,
|
||||||
|
null,
|
||||||
UserWithCredentialDto[].class,
|
UserWithCredentialDto[].class,
|
||||||
serviceId
|
serviceId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserWithCredentialDto[] arr = response.getBody();
|
||||||
return arr == null ? List.of() : Arrays.asList(arr);
|
return arr == null ? List.of() : Arrays.asList(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserWithCredentialDto createUser(
|
public UserWithCredentialDto createUser(RequestMetadataDto metadataDto) {
|
||||||
RequestMetadataDto metadataDto
|
// 1. Crear el usuario
|
||||||
) {
|
|
||||||
|
|
||||||
CreateUserDto userDto = new CreateUserDto(metadataDto.displayName(), null);
|
CreateUserDto userDto = new CreateUserDto(metadataDto.displayName(), null);
|
||||||
UserDto createdUser = restTemplate.postForObject(
|
HttpEntity<CreateUserDto> userRequestEntity = new HttpEntity<>(userDto);
|
||||||
|
|
||||||
|
ResponseEntity<UserDto> userResponse = restTemplate.exchange(
|
||||||
coreUrl + "/users",
|
coreUrl + "/users",
|
||||||
userDto,
|
HttpMethod.POST,
|
||||||
|
userRequestEntity,
|
||||||
UserDto.class
|
UserDto.class
|
||||||
);
|
);
|
||||||
|
|
||||||
if (createdUser == null)
|
if (!userResponse.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(userResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserDto createdUser = userResponse.getBody();
|
||||||
|
if (createdUser == null) {
|
||||||
throw new RuntimeException("No se pudo crear al usuario");
|
throw new RuntimeException("No se pudo crear al usuario");
|
||||||
|
}
|
||||||
|
|
||||||
CreateCredentialDto credDto = new CreateCredentialDto(
|
CreateCredentialDto credDto = new CreateCredentialDto(
|
||||||
createdUser.getUserId(),
|
createdUser.getUserId(),
|
||||||
@@ -66,21 +94,98 @@ public class HuertosWebClient {
|
|||||||
PasswordGenerator.generate(8),
|
PasswordGenerator.generate(8),
|
||||||
(byte) 1
|
(byte) 1
|
||||||
);
|
);
|
||||||
CredentialDto createdCred = restTemplate.postForObject(
|
|
||||||
|
HttpEntity<CreateCredentialDto> credRequestEntity = new HttpEntity<>(credDto);
|
||||||
|
|
||||||
|
ResponseEntity<CredentialDto> credResponse = restTemplate.exchange(
|
||||||
coreUrl + "/credentials",
|
coreUrl + "/credentials",
|
||||||
credDto,
|
HttpMethod.POST,
|
||||||
|
credRequestEntity,
|
||||||
CredentialDto.class
|
CredentialDto.class
|
||||||
);
|
);
|
||||||
|
|
||||||
if (createdCred == null)
|
if (!credResponse.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(credResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
CredentialDto createdCred = credResponse.getBody();
|
||||||
|
if (createdCred == null) {
|
||||||
throw new RuntimeException("No se pudo crear la cuenta del usuario");
|
throw new RuntimeException("No se pudo crear la cuenta del usuario");
|
||||||
|
}
|
||||||
|
|
||||||
return new UserWithCredentialDto(createdUser, createdCred);
|
return new UserWithCredentialDto(createdUser, createdCred);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUser(UUID userId) {
|
public void deleteUser(UUID userId) {
|
||||||
try {
|
ResponseEntity<Void> response = restTemplate.exchange(
|
||||||
restTemplate.delete(coreUrl + "/users/{user_id}", userId);
|
coreUrl + "/users/{user_id}",
|
||||||
} catch (Exception e) { }
|
HttpMethod.DELETE,
|
||||||
|
null,
|
||||||
|
Void.class,
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
if (response.getStatusCode() != HttpStatus.NOT_FOUND) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Byte getCredentialStatus(UUID userId, Byte serviceId) {
|
||||||
|
ResponseEntity<Byte> response = restTemplate.exchange(
|
||||||
|
coreUrl + "/credentials/{service_id}/{user_id}/status",
|
||||||
|
HttpMethod.GET,
|
||||||
|
null,
|
||||||
|
Byte.class,
|
||||||
|
serviceId, userId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCredentialStatus(UUID userId, Byte serviceId, Byte newStatus) {
|
||||||
|
ChangeStatusRequest req = new ChangeStatusRequest(newStatus);
|
||||||
|
HttpEntity<ChangeStatusRequest> requestEntity = new HttpEntity<>(req);
|
||||||
|
|
||||||
|
ResponseEntity<Void> response = restTemplate.exchange(
|
||||||
|
coreUrl + "/credentials/{service_id}/{user_id}/status",
|
||||||
|
HttpMethod.PUT,
|
||||||
|
requestEntity,
|
||||||
|
Void.class,
|
||||||
|
serviceId, userId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
handleError(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleError(ResponseEntity<?> response) {
|
||||||
|
HttpStatusCode statusCode = response.getStatusCode();
|
||||||
|
|
||||||
|
if (statusCode.equals(HttpStatus.UNAUTHORIZED)) {
|
||||||
|
throw new UnauthorizedException("Credenciales no válidas");
|
||||||
|
} else if (statusCode.equals(HttpStatus.FORBIDDEN)) {
|
||||||
|
throw new ForbiddenException("Esa cuenta está desactivada");
|
||||||
|
} else if (statusCode.equals(HttpStatus.NOT_FOUND)) {
|
||||||
|
throw new NotFoundException("No encontrado");
|
||||||
|
} else if (statusCode.equals(HttpStatus.BAD_REQUEST)) {
|
||||||
|
throw new BadRequestException("Datos de solicitud faltantes");
|
||||||
|
} else if (statusCode.equals(HttpStatus.CONFLICT)) {
|
||||||
|
throw new ConflictException("Ya existe");
|
||||||
|
} else if (statusCode.equals(HttpStatus.UNPROCESSABLE_CONTENT)) {
|
||||||
|
throw new ValidationException("general", "Los datos no tienen formato válido");
|
||||||
|
} else {
|
||||||
|
if (statusCode.is4xxClientError()) {
|
||||||
|
throw new BadRequestException(response.getBody().toString());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Error desconocido");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package net.miarma.backend.huertos.config;
|
package net.miarma.backend.huertos.config;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.io.IOException;
|
||||||
import net.miarma.backend.huertos.service.CoreAuthService;
|
import net.miarma.backend.huertos.service.CoreAuthService;
|
||||||
import net.miarma.backlib.security.CoreAuthTokenHolder;
|
import net.miarma.backlib.security.CoreAuthTokenHolder;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.web.client.ResponseErrorHandler;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -15,20 +18,31 @@ public class RestTemplateConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestTemplate authRestTemplate() {
|
public RestTemplate authRestTemplate() {
|
||||||
return new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
restTemplate.setErrorHandler(new NoOpResponseErrorHandler());
|
||||||
|
return restTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestTemplate secureRestTemplate(CoreAuthService coreAuthService) {
|
public RestTemplate secureRestTemplate(CoreAuthService coreAuthService) {
|
||||||
RestTemplate rt = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
rt.getInterceptors().add((request, body, execution) -> {
|
restTemplate.getInterceptors().add((request, body, execution) -> {
|
||||||
String token = coreAuthService.getToken();
|
String token = coreAuthService.getToken();
|
||||||
request.getHeaders().setBearerAuth(token);
|
request.getHeaders().setBearerAuth(token);
|
||||||
return execution.execute(request, body);
|
return execution.execute(request, body);
|
||||||
});
|
});
|
||||||
|
|
||||||
return rt;
|
restTemplate.setErrorHandler(new NoOpResponseErrorHandler());
|
||||||
|
|
||||||
|
return restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoOpResponseErrorHandler implements ResponseErrorHandler {
|
||||||
|
@Override
|
||||||
|
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
|||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -26,34 +24,27 @@ public class SecurityConfig {
|
|||||||
private final HuertosJwtFilter jwtFilter;
|
private final HuertosJwtFilter jwtFilter;
|
||||||
private final RestAuthEntryPoint authEntryPoint;
|
private final RestAuthEntryPoint authEntryPoint;
|
||||||
private final RestAccessDeniedHandler accessDeniedHandler;
|
private final RestAccessDeniedHandler accessDeniedHandler;
|
||||||
|
private final CorsConfigurationSource corsConfigurationSource;
|
||||||
|
|
||||||
public SecurityConfig(
|
public SecurityConfig(
|
||||||
HuertosJwtFilter jwtFilter,
|
HuertosJwtFilter jwtFilter,
|
||||||
RestAuthEntryPoint authEntryPoint,
|
RestAuthEntryPoint authEntryPoint,
|
||||||
RestAccessDeniedHandler accessDeniedHandler
|
RestAccessDeniedHandler accessDeniedHandler,
|
||||||
|
Optional<CorsConfigurationSource> corsConfigurationSource
|
||||||
) {
|
) {
|
||||||
this.jwtFilter = jwtFilter;
|
this.jwtFilter = jwtFilter;
|
||||||
this.authEntryPoint = authEntryPoint;
|
this.authEntryPoint = authEntryPoint;
|
||||||
this.accessDeniedHandler = accessDeniedHandler;
|
this.accessDeniedHandler = accessDeniedHandler;
|
||||||
}
|
this.corsConfigurationSource = corsConfigurationSource.orElse(null);
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CorsConfigurationSource corsConfigurationSource() {
|
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
|
||||||
config.setAllowedOrigins(List.of("http://localhost:3000"));
|
|
||||||
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
|
|
||||||
config.setAllowedHeaders(List.of("*"));
|
|
||||||
config.setAllowCredentials(true);
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
source.registerCorsConfiguration("/**", config);
|
|
||||||
return source;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
if (corsConfigurationSource != null) {
|
||||||
|
http.cors(Customizer.withDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
http
|
http
|
||||||
.cors(Customizer.withDefaults())
|
|
||||||
.csrf(csrf -> csrf.disable())
|
.csrf(csrf -> csrf.disable())
|
||||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.exceptionHandling(ex -> ex
|
.exceptionHandling(ex -> ex
|
||||||
@@ -65,9 +56,7 @@ public class SecurityConfig {
|
|||||||
.requestMatchers("/auth/login").permitAll()
|
.requestMatchers("/auth/login").permitAll()
|
||||||
.requestMatchers("/users/waitlist/limited").permitAll()
|
.requestMatchers("/users/waitlist/limited").permitAll()
|
||||||
.requestMatchers("/requests").permitAll()
|
.requestMatchers("/requests").permitAll()
|
||||||
.requestMatchers("/pre-users").permitAll()
|
|
||||||
.requestMatchers("/users/latest-number").permitAll()
|
.requestMatchers("/users/latest-number").permitAll()
|
||||||
.requestMatchers("/pre-users/validate").permitAll()
|
|
||||||
// PRIVADAS
|
// PRIVADAS
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public class IncomeController {
|
|||||||
@PathVariable("income_id") UUID incomeId,
|
@PathVariable("income_id") UUID incomeId,
|
||||||
@RequestBody IncomeDto.Request dto
|
@RequestBody IncomeDto.Request dto
|
||||||
) {
|
) {
|
||||||
|
IO.println(dto.getCreatedAt());
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
IncomeMapper.toResponse(
|
IncomeMapper.toResponse(
|
||||||
incomeService.update(
|
incomeService.update(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.miarma.backend.huertos.controller;
|
package net.miarma.backend.huertos.controller;
|
||||||
|
|
||||||
import net.miarma.backend.huertos.dto.*;
|
import net.miarma.backend.huertos.dto.*;
|
||||||
|
import net.miarma.backend.huertos.dto.view.VIncomesWithInfoDto;
|
||||||
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||||
import net.miarma.backend.huertos.security.HuertosPrincipal;
|
import net.miarma.backend.huertos.security.HuertosPrincipal;
|
||||||
@@ -31,7 +32,7 @@ public class MemberController {
|
|||||||
@GetMapping
|
@GetMapping
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<List<MemberDto>> getAll() {
|
public ResponseEntity<List<MemberDto>> getAll() {
|
||||||
return ResponseEntity.ok(memberService.getAll((byte)1));
|
return ResponseEntity.ok(memberService.getAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
@@ -45,6 +46,12 @@ public class MemberController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/dropdown")
|
||||||
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
|
public ResponseEntity<List<DropdownDto>> getDropdown() {
|
||||||
|
return ResponseEntity.ok(memberService.getDropdown());
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/{user_id:[0-9a-fA-F\\-]{36}}")
|
@GetMapping("/{user_id:[0-9a-fA-F\\-]{36}}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<MemberDto> getById(@PathVariable("user_id") UUID userId) {
|
public ResponseEntity<MemberDto> getById(@PathVariable("user_id") UUID userId) {
|
||||||
@@ -75,7 +82,7 @@ public class MemberController {
|
|||||||
|
|
||||||
@GetMapping("/number/{member_number}/incomes")
|
@GetMapping("/number/{member_number}/incomes")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<List<IncomeDto.Response>> getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<List<VIncomesWithInfoDto>> getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return ResponseEntity.ok(memberService.getIncomes(memberNumber));
|
return ResponseEntity.ok(memberService.getIncomes(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.miarma.backend.huertos.controller;
|
|||||||
|
|
||||||
import net.miarma.backend.huertos.dto.*;
|
import net.miarma.backend.huertos.dto.*;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||||
|
import net.miarma.backend.huertos.mapper.RequestMetadataMapper;
|
||||||
import net.miarma.backend.huertos.mapper.RequestWithMetadataMapper;
|
import net.miarma.backend.huertos.mapper.RequestWithMetadataMapper;
|
||||||
import net.miarma.backend.huertos.model.Request;
|
import net.miarma.backend.huertos.model.Request;
|
||||||
import net.miarma.backend.huertos.service.RequestAcceptanceService;
|
import net.miarma.backend.huertos.service.RequestAcceptanceService;
|
||||||
@@ -131,6 +132,7 @@ public class RequestController {
|
|||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<Map<String, String>> acceptRequest(@PathVariable("request_id") UUID requestId) {
|
public ResponseEntity<Map<String, String>> acceptRequest(@PathVariable("request_id") UUID requestId) {
|
||||||
Request r = requestAcceptanceService.acceptRequest(requestId);
|
Request r = requestAcceptanceService.acceptRequest(requestId);
|
||||||
|
requestAcceptanceService.handleSideEffects(r);
|
||||||
return ResponseEntity.ok(Map.of("message", "Accepted request: " + r.getRequestId()));
|
return ResponseEntity.ok(Map.of("message", "Accepted request: " + r.getRequestId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package net.miarma.backend.huertos.dto;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record DropdownDto(UUID userId, Integer memberNumber, String displayName) {
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ public class ExpenseDto {
|
|||||||
private String supplier;
|
private String supplier;
|
||||||
private String invoice;
|
private String invoice;
|
||||||
private Byte type;
|
private Byte type;
|
||||||
|
private Instant createdAt;
|
||||||
|
|
||||||
public String getConcept() {
|
public String getConcept() {
|
||||||
return concept;
|
return concept;
|
||||||
@@ -51,6 +52,14 @@ public class ExpenseDto {
|
|||||||
public void setType(Byte type) {
|
public void setType(Byte type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Instant getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Instant createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Response {
|
public static class Response {
|
||||||
@@ -59,6 +68,8 @@ public class ExpenseDto {
|
|||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
private String supplier;
|
private String supplier;
|
||||||
private String invoice;
|
private String invoice;
|
||||||
|
private Byte type;
|
||||||
|
private Instant createdAt;
|
||||||
|
|
||||||
public UUID getExpenseId() {
|
public UUID getExpenseId() {
|
||||||
return expenseId;
|
return expenseId;
|
||||||
@@ -115,8 +126,5 @@ public class ExpenseDto {
|
|||||||
public void setCreatedAt(Instant createdAt) {
|
public void setCreatedAt(Instant createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Byte type;
|
|
||||||
private Instant createdAt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class IncomeDto {
|
|||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
private Byte type;
|
private Byte type;
|
||||||
private Byte frequency;
|
private Byte frequency;
|
||||||
|
private Instant createdAt;
|
||||||
|
|
||||||
public Integer getMemberNumber() {
|
public Integer getMemberNumber() {
|
||||||
return memberNumber;
|
return memberNumber;
|
||||||
@@ -60,6 +61,14 @@ public class IncomeDto {
|
|||||||
public void setFrequency(Byte frequency) {
|
public void setFrequency(Byte frequency) {
|
||||||
this.frequency = frequency;
|
this.frequency = frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Instant getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Instant createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.miarma.backend.huertos.dto;
|
package net.miarma.backend.huertos.dto;
|
||||||
|
|
||||||
|
import net.miarma.backend.huertos.dto.view.VIncomesWithInfoDto;
|
||||||
import net.miarma.backlib.dto.CredentialDto;
|
import net.miarma.backlib.dto.CredentialDto;
|
||||||
import net.miarma.backlib.dto.UserDto;
|
import net.miarma.backlib.dto.UserDto;
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ public record MemberProfileDto(
|
|||||||
CredentialDto account,
|
CredentialDto account,
|
||||||
UserMetadataDto metadata,
|
UserMetadataDto metadata,
|
||||||
List<RequestDto.Response> requests,
|
List<RequestDto.Response> requests,
|
||||||
List<IncomeDto.Response> payments,
|
List<VIncomesWithInfoDto> payments,
|
||||||
boolean hasCollaborator,
|
boolean hasCollaborator,
|
||||||
boolean hasGreenhouse,
|
boolean hasGreenhouse,
|
||||||
boolean hasCollaboratorRequest,
|
boolean hasCollaboratorRequest,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class RequestDto {
|
|||||||
public static class Request {
|
public static class Request {
|
||||||
private Byte type;
|
private Byte type;
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
private String name;
|
||||||
private RequestMetadataDto metadata;
|
private RequestMetadataDto metadata;
|
||||||
|
|
||||||
public Byte getType() {
|
public Byte getType() {
|
||||||
@@ -27,6 +28,14 @@ public class RequestDto {
|
|||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
public RequestMetadataDto getMetadata() {
|
public RequestMetadataDto getMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
@@ -41,6 +50,7 @@ public class RequestDto {
|
|||||||
private Byte type;
|
private Byte type;
|
||||||
private Byte status;
|
private Byte status;
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
private String name;
|
||||||
private RequestMetadataDto metadata;
|
private RequestMetadataDto metadata;
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
@@ -76,6 +86,14 @@ public class RequestDto {
|
|||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
public RequestMetadataDto getMetadata() {
|
public RequestMetadataDto getMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.UUID;
|
|||||||
public record RequestWithMetadataDto(
|
public record RequestWithMetadataDto(
|
||||||
UUID requestId,
|
UUID requestId,
|
||||||
UUID userId,
|
UUID userId,
|
||||||
|
String name,
|
||||||
Byte type,
|
Byte type,
|
||||||
Byte status,
|
Byte status,
|
||||||
Instant createdAt,
|
Instant createdAt,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.miarma.backend.huertos.mapper;
|
||||||
|
|
||||||
|
import net.miarma.backend.huertos.dto.DropdownDto;
|
||||||
|
import net.miarma.backend.huertos.dto.MemberDto;
|
||||||
|
|
||||||
|
public class DropdownDtoMapper {
|
||||||
|
public static DropdownDto toDto(MemberDto dto) {
|
||||||
|
return new DropdownDto(dto.user().getUserId(), dto.metadata().getMemberNumber(), dto.user().getDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ public class ExpenseMapper {
|
|||||||
entity.setSupplier(dto.getSupplier());
|
entity.setSupplier(dto.getSupplier());
|
||||||
entity.setInvoice(dto.getInvoice());
|
entity.setInvoice(dto.getInvoice());
|
||||||
entity.setType(dto.getType());
|
entity.setType(dto.getType());
|
||||||
|
entity.setCreatedAt(dto.getCreatedAt());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class IncomeMapper {
|
|||||||
entity.setAmount(dto.getAmount());
|
entity.setAmount(dto.getAmount());
|
||||||
entity.setType(dto.getType());
|
entity.setType(dto.getType());
|
||||||
entity.setFrequency(dto.getFrequency());
|
entity.setFrequency(dto.getFrequency());
|
||||||
|
entity.setCreatedAt(dto.getCreatedAt());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public class RequestMapper {
|
|||||||
Request entity = new Request();
|
Request entity = new Request();
|
||||||
entity.setType(dto.getType());
|
entity.setType(dto.getType());
|
||||||
entity.setUserId(dto.getUserId());
|
entity.setUserId(dto.getUserId());
|
||||||
|
entity.setName(dto.getName());
|
||||||
entity.setStatus((byte) 0);
|
entity.setStatus((byte) 0);
|
||||||
|
|
||||||
if (dto.getMetadata() != null) {
|
if (dto.getMetadata() != null) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class RequestWithMetadataMapper {
|
|||||||
return new RequestWithMetadataDto(
|
return new RequestWithMetadataDto(
|
||||||
r.getRequestId(),
|
r.getRequestId(),
|
||||||
r.getUserId(),
|
r.getUserId(),
|
||||||
|
r.getName(),
|
||||||
r.getType(),
|
r.getType(),
|
||||||
r.getStatus(),
|
r.getStatus(),
|
||||||
r.getCreatedAt(),
|
r.getCreatedAt(),
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class Income {
|
|||||||
@Column(name = "frequency")
|
@Column(name = "frequency")
|
||||||
private Byte frequency;
|
private Byte frequency;
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false, updatable = true)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package net.miarma.backend.huertos.model;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import net.miarma.backlib.util.UuidUtil;
|
import net.miarma.backlib.util.UuidUtil;
|
||||||
|
|
||||||
@@ -18,103 +17,60 @@ public class Request {
|
|||||||
private UUID requestId;
|
private UUID requestId;
|
||||||
|
|
||||||
@Column(name = "user_id", columnDefinition = "BINARY(16)")
|
@Column(name = "user_id", columnDefinition = "BINARY(16)")
|
||||||
private byte[] userIdBin; // usuario que hace la solicitud (puede ser null si anon)
|
private byte[] userIdBin;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
|
||||||
@Column(name = "type", nullable = false)
|
private String name;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private Byte type;
|
private Byte type;
|
||||||
|
|
||||||
@Column(name = "status", nullable = false)
|
@Column(nullable = false)
|
||||||
private Byte status;
|
private Byte status;
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.ALL)
|
@OneToOne(mappedBy = "request", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
|
||||||
@JoinColumn(name = "metadata_id")
|
|
||||||
private RequestMetadata metadata;
|
private RequestMetadata metadata;
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
private void prePersist() {
|
private void prePersist() {
|
||||||
if (requestId != null) {
|
if (requestId != null) requestIdBin = UuidUtil.uuidToBin(requestId);
|
||||||
requestIdBin = net.miarma.backlib.util.UuidUtil.uuidToBin(requestId);
|
if (userId != null) userIdBin = UuidUtil.uuidToBin(userId);
|
||||||
}
|
|
||||||
createdAt = Instant.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostLoad
|
@PostLoad
|
||||||
private void postLoad() {
|
private void postLoad() {
|
||||||
if (requestIdBin != null) {
|
if (requestIdBin != null) requestId = UuidUtil.binToUUID(requestIdBin);
|
||||||
requestId = net.miarma.backlib.util.UuidUtil.binToUUID(requestIdBin);
|
if (userIdBin != null) userId = UuidUtil.binToUUID(userIdBin);
|
||||||
}
|
|
||||||
if (userIdBin != null) {
|
|
||||||
userId = net.miarma.backlib.util.UuidUtil.binToUUID(userIdBin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRequestIdBin() {
|
public UUID getRequestId() { return requestId; }
|
||||||
return requestIdBin;
|
public void setRequestId(UUID requestId) { this.requestId = requestId; }
|
||||||
|
|
||||||
|
public UUID getUserId() { return userId; }
|
||||||
|
public void setUserId(UUID userId) { this.userId = userId; }
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRequestIdBin(byte[] requestIdBin) {
|
public void setName(String name) {
|
||||||
this.requestIdBin = requestIdBin;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getRequestId() {
|
public Byte getType() { return type; }
|
||||||
return requestId;
|
public void setType(Byte type) { this.type = type; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setRequestId(UUID requestId) {
|
public Byte getStatus() { return status; }
|
||||||
this.requestId = requestId;
|
public void setStatus(Byte status) { this.status = status; }
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getUserIdBin() {
|
public Instant getCreatedAt() { return createdAt; }
|
||||||
return userIdBin;
|
public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserIdBin(byte[] userIdBin) {
|
public RequestMetadata getMetadata() { return metadata; }
|
||||||
this.userIdBin = userIdBin;
|
public void setMetadata(RequestMetadata metadata) { this.metadata = metadata; }
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Byte getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(Byte type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Byte getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(Byte status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RequestMetadata getMetadata() {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMetadata(RequestMetadata metadata) {
|
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package net.miarma.backend.huertos.model;
|
package net.miarma.backend.huertos.model;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import net.miarma.backlib.util.UuidUtil;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "huertos_request_metadata")
|
@Table(name = "huertos_request_metadata")
|
||||||
@@ -12,6 +14,16 @@ public class RequestMetadata {
|
|||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "request_id", columnDefinition = "BINARY(16)", nullable = false, unique = true)
|
||||||
|
private byte[] requestIdBin;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private UUID requestId;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "request_id", referencedColumnName = "request_id", insertable = false, updatable = false)
|
||||||
|
private Request request;
|
||||||
|
|
||||||
@Column(name = "display_name", nullable = false, length = 150)
|
@Column(name = "display_name", nullable = false, length = 150)
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
||||||
@@ -39,17 +51,22 @@ public class RequestMetadata {
|
|||||||
@Column(name = "plot_number")
|
@Column(name = "plot_number")
|
||||||
private Integer plotNumber;
|
private Integer plotNumber;
|
||||||
|
|
||||||
private Byte type;
|
|
||||||
|
|
||||||
@Column(nullable = false, length = 100)
|
@Column(nullable = false, length = 100)
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
|
private Byte type;
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false)
|
@Column(name = "created_at", nullable = false, updatable = false)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
private void prePersist() {
|
private void prePersist() {
|
||||||
createdAt = Instant.now();
|
if (requestId != null) requestIdBin = UuidUtil.uuidToBin(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostLoad
|
||||||
|
private void postLoad() {
|
||||||
|
if (requestIdBin != null) requestId = UuidUtil.binToUUID(requestIdBin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
@@ -60,6 +77,30 @@ public class RequestMetadata {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getRequestIdBin() {
|
||||||
|
return requestIdBin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestIdBin(byte[] requestIdBin) {
|
||||||
|
this.requestIdBin = requestIdBin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getRequestId() {
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestId(UUID requestId) {
|
||||||
|
this.requestId = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request getRequest() {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequest(Request request) {
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
@@ -140,14 +181,6 @@ public class RequestMetadata {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
public Instant getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
@@ -155,5 +188,12 @@ public class RequestMetadata {
|
|||||||
public void setCreatedAt(Instant createdAt) {
|
public void setCreatedAt(Instant createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,17 @@ package net.miarma.backend.huertos.repository;
|
|||||||
|
|
||||||
import net.miarma.backend.huertos.model.Request;
|
import net.miarma.backend.huertos.model.Request;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface RequestRepository extends JpaRepository<Request, byte[]> {
|
public interface RequestRepository extends JpaRepository<Request, byte[]> {
|
||||||
|
@Query("""
|
||||||
|
SELECT r FROM Request r
|
||||||
|
LEFT JOIN FETCH r.metadata
|
||||||
|
WHERE r.requestIdBin = :id
|
||||||
|
""")
|
||||||
|
Optional<Request> findByIdWithMetadata(@Param("id") byte[] id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package net.miarma.backend.huertos.service;
|
|||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import net.miarma.backend.huertos.dto.AnnouncementDto;
|
import net.miarma.backend.huertos.dto.AnnouncementDto;
|
||||||
import net.miarma.backend.huertos.model.Announcement;
|
import net.miarma.backend.huertos.model.Announcement;
|
||||||
|
import net.miarma.backend.huertos.model.Income;
|
||||||
import net.miarma.backend.huertos.repository.AnnouncementRepository;
|
import net.miarma.backend.huertos.repository.AnnouncementRepository;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
import net.miarma.backlib.util.UuidUtil;
|
import net.miarma.backlib.util.UuidUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -25,7 +27,9 @@ public class AnnouncementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Announcement> getAll() {
|
public List<Announcement> getAll() {
|
||||||
return announcementRepository.findAll();
|
return announcementRepository.findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(Announcement::getCreatedAt).reversed())
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Announcement getById(UUID announceId) {
|
public Announcement getById(UUID announceId) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.miarma.backend.huertos.service;
|
|||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import net.miarma.backend.huertos.dto.ExpenseDto;
|
import net.miarma.backend.huertos.dto.ExpenseDto;
|
||||||
import net.miarma.backend.huertos.model.Expense;
|
import net.miarma.backend.huertos.model.Expense;
|
||||||
|
import net.miarma.backend.huertos.model.Income;
|
||||||
import net.miarma.backend.huertos.repository.ExpenseRepository;
|
import net.miarma.backend.huertos.repository.ExpenseRepository;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
import net.miarma.backlib.exception.ValidationException;
|
import net.miarma.backlib.exception.ValidationException;
|
||||||
@@ -10,6 +11,7 @@ import net.miarma.backlib.util.UuidUtil;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -24,7 +26,9 @@ public class ExpenseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Expense> getAll() {
|
public List<Expense> getAll() {
|
||||||
return expenseRepository.findAll();
|
return expenseRepository.findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(Expense::getCreatedAt).reversed())
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expense getById(UUID expenseId) {
|
public Expense getById(UUID expenseId) {
|
||||||
@@ -46,9 +50,11 @@ public class ExpenseService {
|
|||||||
if (expense.getInvoice() == null || expense.getInvoice().isBlank()) {
|
if (expense.getInvoice() == null || expense.getInvoice().isBlank()) {
|
||||||
throw new ValidationException("invoice", "La factura es obligatoria");
|
throw new ValidationException("invoice", "La factura es obligatoria");
|
||||||
}
|
}
|
||||||
|
if (expense.getCreatedAt() == null) {
|
||||||
|
expense.setCreatedAt(Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
expense.setExpenseId(UUID.randomUUID());
|
expense.setExpenseId(UUID.randomUUID());
|
||||||
expense.setCreatedAt(Instant.now());
|
|
||||||
|
|
||||||
return expenseRepository.save(expense);
|
return expenseRepository.save(expense);
|
||||||
}
|
}
|
||||||
@@ -74,6 +80,9 @@ public class ExpenseService {
|
|||||||
if (changes.getType() != null)
|
if (changes.getType() != null)
|
||||||
expense.setType(changes.getType());
|
expense.setType(changes.getType());
|
||||||
|
|
||||||
|
if (changes.getCreatedAt() != null)
|
||||||
|
expense.setCreatedAt(changes.getCreatedAt());
|
||||||
|
|
||||||
return expenseRepository.save(expense);
|
return expenseRepository.save(expense);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package net.miarma.backend.huertos.service;
|
package net.miarma.backend.huertos.service;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.TemporalAmount;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import net.miarma.backend.huertos.model.view.VIncomesWithInfo;
|
||||||
|
import net.miarma.backend.huertos.service.view.VIncomesWithInfoService;
|
||||||
import net.miarma.backlib.exception.BadRequestException;
|
import net.miarma.backlib.exception.BadRequestException;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
import net.miarma.backlib.exception.ValidationException;
|
import net.miarma.backlib.exception.ValidationException;
|
||||||
@@ -19,16 +23,21 @@ import net.miarma.backlib.util.UuidUtil;
|
|||||||
public class IncomeService {
|
public class IncomeService {
|
||||||
|
|
||||||
private final IncomeRepository incomeRepository;
|
private final IncomeRepository incomeRepository;
|
||||||
|
private final VIncomesWithInfoService incomesWithInfoService;
|
||||||
private final UserMetadataService metadataService;
|
private final UserMetadataService metadataService;
|
||||||
|
|
||||||
public IncomeService(IncomeRepository incomeRepository,
|
public IncomeService(IncomeRepository incomeRepository,
|
||||||
|
VIncomesWithInfoService incomesWithInfoService,
|
||||||
UserMetadataService metadataService) {
|
UserMetadataService metadataService) {
|
||||||
this.incomeRepository = incomeRepository;
|
this.incomeRepository = incomeRepository;
|
||||||
|
this.incomesWithInfoService = incomesWithInfoService;
|
||||||
this.metadataService = metadataService;
|
this.metadataService = metadataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Income> getAll() {
|
public List<Income> getAll() {
|
||||||
return incomeRepository.findAll();
|
return incomeRepository.findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(Income::getCreatedAt).reversed())
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Income getById(UUID incomeId) {
|
public Income getById(UUID incomeId) {
|
||||||
@@ -47,15 +56,20 @@ public class IncomeService {
|
|||||||
if (income.getUserId() == null) {
|
if (income.getUserId() == null) {
|
||||||
throw new BadRequestException("El identificador de usuario es obligatorio");
|
throw new BadRequestException("El identificador de usuario es obligatorio");
|
||||||
}
|
}
|
||||||
if (income.getConcept() == null || income.getConcept().isBlank()) {
|
if (income.getConcept() == null) {
|
||||||
throw new BadRequestException("El concepto es obligatorio");
|
throw new BadRequestException("El concepto es obligatorio");
|
||||||
}
|
}
|
||||||
|
if (income.getConcept().isBlank() || income.getConcept().isEmpty()) {
|
||||||
|
throw new ValidationException("concept", "El concepto no puede ir vacío");
|
||||||
|
}
|
||||||
if (income.getAmount() == null || income.getAmount().signum() <= 0) {
|
if (income.getAmount() == null || income.getAmount().signum() <= 0) {
|
||||||
throw new ValidationException("amount", "La cantidad debe ser positiva");
|
throw new ValidationException("amount", "La cantidad debe ser positiva");
|
||||||
}
|
}
|
||||||
|
if (income.getCreatedAt() == null) {
|
||||||
|
income.setCreatedAt(Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
income.setIncomeId(UUID.randomUUID());
|
income.setIncomeId(UUID.randomUUID());
|
||||||
income.setCreatedAt(Instant.now());
|
|
||||||
|
|
||||||
return incomeRepository.save(income);
|
return incomeRepository.save(income);
|
||||||
}
|
}
|
||||||
@@ -75,6 +89,9 @@ public class IncomeService {
|
|||||||
}
|
}
|
||||||
if (changes.getType() != null) income.setType(changes.getType());
|
if (changes.getType() != null) income.setType(changes.getType());
|
||||||
if (changes.getFrequency() != null) income.setFrequency(changes.getFrequency());
|
if (changes.getFrequency() != null) income.setFrequency(changes.getFrequency());
|
||||||
|
if (changes.getCreatedAt() != null && !changes.getCreatedAt().equals(income.getCreatedAt())) {
|
||||||
|
income.setCreatedAt(changes.getCreatedAt());
|
||||||
|
}
|
||||||
|
|
||||||
return incomeRepository.save(income);
|
return incomeRepository.save(income);
|
||||||
}
|
}
|
||||||
@@ -104,8 +121,8 @@ public class IncomeService {
|
|||||||
return !incomes.isEmpty() && incomes.stream().allMatch(Income::isPaid);
|
return !incomes.isEmpty() && incomes.stream().allMatch(Income::isPaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Income> getByMemberNumber(Integer memberNumber) {
|
public List<VIncomesWithInfo> getByMemberNumber(Integer memberNumber) {
|
||||||
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
||||||
return getByUserId(userId);
|
return incomesWithInfoService.getByUserId(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||||
import net.miarma.backend.huertos.dto.*;
|
import net.miarma.backend.huertos.dto.*;
|
||||||
|
import net.miarma.backend.huertos.dto.view.VIncomesWithInfoDto;
|
||||||
|
import net.miarma.backend.huertos.mapper.DropdownDtoMapper;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||||
import net.miarma.backend.huertos.mapper.UserMetadataMapper;
|
import net.miarma.backend.huertos.mapper.UserMetadataMapper;
|
||||||
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||||
|
import net.miarma.backend.huertos.mapper.view.VIncomesWithInfoMapper;
|
||||||
import net.miarma.backend.huertos.security.NameCensorer;
|
import net.miarma.backend.huertos.security.NameCensorer;
|
||||||
import net.miarma.backlib.dto.UserWithCredentialDto;
|
import net.miarma.backlib.dto.UserWithCredentialDto;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
@@ -52,8 +55,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Cacheable("members")
|
@Cacheable("members")
|
||||||
public List<MemberDto> getAll(Byte serviceId) {
|
public List<MemberDto> getAll() {
|
||||||
List<UserWithCredentialDto> all = huertosWebClient.getAllUsersWithCredentials(serviceId);
|
List<UserWithCredentialDto> all = huertosWebClient.getAllUsersWithCredentials((byte)1);
|
||||||
|
|
||||||
return all.stream()
|
return all.stream()
|
||||||
.filter(uwc -> metadataService.existsById(uwc.user().getUserId()))
|
.filter(uwc -> metadataService.existsById(uwc.user().getUserId()))
|
||||||
@@ -65,6 +68,7 @@
|
|||||||
UserMetadataMapper.toDto(meta)
|
UserMetadataMapper.toDto(meta)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.sorted(Comparator.comparing(dto -> dto.metadata().getMemberNumber()))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +80,8 @@
|
|||||||
.map(RequestMapper::toResponse)
|
.map(RequestMapper::toResponse)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
List<IncomeDto.Response> payments = incomeService.getByMemberNumber(memberNumber).stream()
|
List<VIncomesWithInfoDto> payments = incomeService.getByMemberNumber(memberNumber).stream()
|
||||||
.map(IncomeMapper::toResponse)
|
.map(VIncomesWithInfoMapper::toResponse)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return new MemberProfileDto(
|
return new MemberProfileDto(
|
||||||
@@ -125,29 +129,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MemberDto getByMemberNumber(Integer memberNumber) {
|
public MemberDto getByMemberNumber(Integer memberNumber) {
|
||||||
return getAll((byte)1).stream()
|
return getAll().stream()
|
||||||
.filter(dto -> dto.metadata().getMemberNumber().equals(memberNumber))
|
.filter(dto -> dto.metadata().getMemberNumber().equals(memberNumber))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new NotFoundException("No hay socio con ese número"));
|
.orElseThrow(() -> new NotFoundException("No hay socio con ese número"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemberDto getByPlotNumber(Integer plotNumber) {
|
public MemberDto getByPlotNumber(Integer plotNumber) {
|
||||||
return getAll((byte)1).stream()
|
return getAll().stream()
|
||||||
.filter(dto -> dto.metadata().getPlotNumber().equals(plotNumber))
|
.filter(dto -> dto.metadata().getPlotNumber().equals(plotNumber))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new NotFoundException("No hay socio con ese huerto"));
|
.orElseThrow(() -> new NotFoundException("No hay socio con ese huerto"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemberDto getByDni(String dni) {
|
public MemberDto getByDni(String dni) {
|
||||||
return getAll((byte)1).stream()
|
return getAll().stream()
|
||||||
.filter(dto -> dni.equals(dto.metadata().getDni()))
|
.filter(dto -> dni.equals(dto.metadata().getDni()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new NotFoundException("No hay socio con ese DNI"));
|
.orElseThrow(() -> new NotFoundException("No hay socio con ese DNI"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IncomeDto.Response> getIncomes(Integer memberNumber) {
|
public List<VIncomesWithInfoDto> getIncomes(Integer memberNumber) {
|
||||||
return incomeService.getByMemberNumber(memberNumber).stream()
|
return incomeService.getByMemberNumber(memberNumber).stream()
|
||||||
.map(IncomeMapper::toResponse)
|
.map(VIncomesWithInfoMapper::toResponse)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +160,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasCollaborator(Integer memberNumber) {
|
public Boolean hasCollaborator(Integer memberNumber) {
|
||||||
List<MemberDto> all = getAll((byte)1);
|
List<MemberDto> all = getAll();
|
||||||
|
|
||||||
var member = all.stream()
|
var member = all.stream()
|
||||||
.filter(dto -> dto.metadata().getMemberNumber().equals(memberNumber))
|
.filter(dto -> dto.metadata().getMemberNumber().equals(memberNumber))
|
||||||
@@ -182,11 +186,17 @@
|
|||||||
|
|
||||||
public Boolean hasCollaboratorRequest(Integer memberNumber) {
|
public Boolean hasCollaboratorRequest(Integer memberNumber) {
|
||||||
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
||||||
return requestService.hasPendingCollaboratorRequest(userId);
|
return requestService.hasCollaboratorRequest(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasGreenhouseRequest(Integer memberNumber) {
|
public Boolean hasGreenhouseRequest(Integer memberNumber) {
|
||||||
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
||||||
return requestService.hasPendingGreenhouseRequest(userId);
|
return requestService.hasGreenhouseRequest(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownDto> getDropdown() {
|
||||||
|
return getAll().stream()
|
||||||
|
.map(DropdownDtoMapper::toDto)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package net.miarma.backend.huertos.service;
|
|||||||
|
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
|
||||||
import net.miarma.backend.huertos.mapper.RequestMetadataMapper;
|
import net.miarma.backend.huertos.mapper.RequestMetadataMapper;
|
||||||
import net.miarma.backend.huertos.model.Request;
|
import net.miarma.backend.huertos.model.Request;
|
||||||
import net.miarma.backend.huertos.model.RequestMetadata;
|
import net.miarma.backend.huertos.model.RequestMetadata;
|
||||||
@@ -11,88 +10,131 @@ import net.miarma.backlib.dto.UserWithCredentialDto;
|
|||||||
import net.miarma.backlib.exception.BadRequestException;
|
import net.miarma.backlib.exception.BadRequestException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
|
||||||
public class RequestAcceptanceService {
|
public class RequestAcceptanceService {
|
||||||
|
|
||||||
private final RequestService requestService;
|
private final RequestService requestService;
|
||||||
private final UserMetadataService metadataService;
|
private final UserMetadataService metadataService;
|
||||||
private final HuertosWebClient huertosWebClient;
|
private final HuertosWebClient huertosWebClient;
|
||||||
|
private final MemberService memberService;
|
||||||
|
|
||||||
public RequestAcceptanceService(RequestService requestService, UserMetadataService metadataService, HuertosWebClient huertosWebClient) {
|
public RequestAcceptanceService(
|
||||||
|
RequestService requestService,
|
||||||
|
UserMetadataService metadataService,
|
||||||
|
HuertosWebClient huertosWebClient,
|
||||||
|
MemberService memberService
|
||||||
|
) {
|
||||||
this.requestService = requestService;
|
this.requestService = requestService;
|
||||||
this.metadataService = metadataService;
|
this.metadataService = metadataService;
|
||||||
this.huertosWebClient = huertosWebClient;
|
this.huertosWebClient = huertosWebClient;
|
||||||
|
this.memberService = memberService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
public Request acceptRequest(UUID requestId) {
|
public Request acceptRequest(UUID requestId) {
|
||||||
Request request = requestService.accept(requestId);
|
Request request = requestService.accept(requestId);
|
||||||
RequestMetadata metadata = request.getMetadata();
|
|
||||||
|
|
||||||
if (metadata == null) throw new BadRequestException("No hay metadata asociada");
|
if (request.getMetadata() == null) {
|
||||||
|
throw new BadRequestException("No hay metadata asociada");
|
||||||
switch (request.getType()) {
|
|
||||||
case 0: // REGISTER
|
|
||||||
UserWithCredentialDto createdUser = huertosWebClient.createUser(
|
|
||||||
RequestMetadataMapper.toDto(metadata)
|
|
||||||
);
|
|
||||||
|
|
||||||
UserMetadata userMetadata = new UserMetadata();
|
|
||||||
userMetadata.setUserId(createdUser.user().getUserId());
|
|
||||||
userMetadata.setMemberNumber(metadata.getMemberNumber());
|
|
||||||
userMetadata.setPlotNumber(metadata.getPlotNumber());
|
|
||||||
userMetadata.setDni(metadata.getDni());
|
|
||||||
userMetadata.setPhone(metadata.getPhone());
|
|
||||||
userMetadata.setType((byte)0);
|
|
||||||
userMetadata.setRole((byte)0);
|
|
||||||
metadataService.create(userMetadata);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // UNREGISTER
|
|
||||||
UserMetadata toRemove = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
|
||||||
huertosWebClient.deleteUser(toRemove.getUserId()); // borramos User + Credential + Metadata
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // ADD_COLLABORATOR
|
|
||||||
UserWithCredentialDto newCollab = huertosWebClient.createUser(
|
|
||||||
RequestMetadataMapper.toDto(metadata)
|
|
||||||
);
|
|
||||||
|
|
||||||
UserMetadata collabMeta = new UserMetadata();
|
|
||||||
collabMeta.setUserId(newCollab.user().getUserId());
|
|
||||||
collabMeta.setMemberNumber(metadata.getMemberNumber());
|
|
||||||
collabMeta.setPlotNumber(metadata.getPlotNumber());
|
|
||||||
collabMeta.setDni(metadata.getDni());
|
|
||||||
collabMeta.setPhone(metadata.getPhone());
|
|
||||||
collabMeta.setType((byte)3); // colaborador
|
|
||||||
collabMeta.setRole((byte)0);
|
|
||||||
metadataService.create(collabMeta);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: // REMOVE_COLLABORATOR
|
|
||||||
UserMetadata collabToRemove = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
|
||||||
huertosWebClient.deleteUser(collabToRemove.getUserId());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: // ADD_GREENHOUSE
|
|
||||||
UserMetadata greenhouseMeta = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
|
||||||
greenhouseMeta.setType((byte)2); // invernadero
|
|
||||||
metadataService.update(greenhouseMeta.getUserId(), greenhouseMeta);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5: // REMOVE_GREENHOUSE
|
|
||||||
UserMetadata ghToRemove = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
|
||||||
ghToRemove.setType((byte)1); // socio normal
|
|
||||||
metadataService.update(ghToRemove.getUserId(), ghToRemove);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new BadRequestException("Tipo de solicitud no soportado para aceptar");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleSideEffects(Request request) {
|
||||||
|
RequestMetadata metadata = request.getMetadata();
|
||||||
|
|
||||||
|
switch (request.getType()) {
|
||||||
|
|
||||||
|
case 0: // REGISTER
|
||||||
|
handleRegister(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // UNREGISTER
|
||||||
|
handleUnregister(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // ADD_COLLABORATOR
|
||||||
|
handleAddCollaborator(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // REMOVE_COLLABORATOR
|
||||||
|
handleRemoveCollaborator(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // ADD_GREENHOUSE
|
||||||
|
handleAddGreenhouse(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // REMOVE_GREENHOUSE
|
||||||
|
handleRemoveGreenhouse(metadata);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new BadRequestException("Tipo de solicitud no soportado");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRegister(RequestMetadata metadata) {
|
||||||
|
UserWithCredentialDto createdUser =
|
||||||
|
huertosWebClient.createUser(RequestMetadataMapper.toDto(metadata));
|
||||||
|
|
||||||
|
UserMetadata userMetadata = buildBaseUserMetadata(metadata, createdUser.user().getUserId());
|
||||||
|
userMetadata.setType((byte) 0); // socio
|
||||||
|
userMetadata.setRole((byte) 0);
|
||||||
|
|
||||||
|
metadataService.create(userMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUnregister(RequestMetadata metadata) {
|
||||||
|
UserMetadata toRemove = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
||||||
|
huertosWebClient.updateCredentialStatus(toRemove.getUserId(), (byte)1, (byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleAddCollaborator(RequestMetadata metadata) {
|
||||||
|
UserWithCredentialDto newCollab =
|
||||||
|
huertosWebClient.createUser(RequestMetadataMapper.toDto(metadata));
|
||||||
|
|
||||||
|
UserMetadata collabMeta = buildBaseUserMetadata(
|
||||||
|
metadata,
|
||||||
|
newCollab.user().getUserId()
|
||||||
|
);
|
||||||
|
|
||||||
|
collabMeta.setType((byte) 3); // colaborador
|
||||||
|
collabMeta.setRole((byte) 0);
|
||||||
|
|
||||||
|
metadataService.create(collabMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRemoveCollaborator(RequestMetadata metadata) {
|
||||||
|
UserMetadata collab = metadataService.getByMemberNumber(metadata.getMemberNumber());
|
||||||
|
huertosWebClient.updateCredentialStatus(collab.getUserId(), (byte)1, (byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleAddGreenhouse(RequestMetadata metadata) {
|
||||||
|
UserMetadata user =
|
||||||
|
metadataService.getByMemberNumber(metadata.getMemberNumber());
|
||||||
|
|
||||||
|
user.setType((byte) 2); // invernadero
|
||||||
|
metadataService.update(user.getUserId(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRemoveGreenhouse(RequestMetadata metadata) {
|
||||||
|
UserMetadata user =
|
||||||
|
metadataService.getByMemberNumber(metadata.getMemberNumber());
|
||||||
|
|
||||||
|
user.setType((byte) 1); // socio normal
|
||||||
|
metadataService.update(user.getUserId(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserMetadata buildBaseUserMetadata(RequestMetadata metadata, UUID userId) {
|
||||||
|
UserMetadata um = new UserMetadata();
|
||||||
|
um.setUserId(userId);
|
||||||
|
um.setMemberNumber(metadata.getMemberNumber());
|
||||||
|
um.setPlotNumber(metadata.getPlotNumber());
|
||||||
|
um.setDni(metadata.getDni());
|
||||||
|
um.setPhone(metadata.getPhone());
|
||||||
|
return um;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import net.miarma.backend.huertos.dto.RequestDto;
|
|||||||
import net.miarma.backend.huertos.dto.RequestMetadataDto;
|
import net.miarma.backend.huertos.dto.RequestMetadataDto;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMetadataMapper;
|
import net.miarma.backend.huertos.mapper.RequestMetadataMapper;
|
||||||
|
import net.miarma.backend.huertos.validation.RequestValidator;
|
||||||
|
import net.miarma.backlib.exception.ConflictException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
|
|
||||||
@@ -47,24 +49,41 @@ public class RequestService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request create(Request request) {
|
|
||||||
if (request.getType() == null) throw new BadRequestException("Tipo de solicitud obligatorio");
|
|
||||||
request.setRequestId(UUID.randomUUID());
|
|
||||||
request.setCreatedAt(Instant.now());
|
|
||||||
return requestRepository.save(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Request createWithMetadata(RequestDto.Request requestDto,
|
public Request create(Request request) {
|
||||||
RequestMetadataDto metadataDto) {
|
|
||||||
Request request = RequestMapper.toEntity(requestDto);
|
if (request == null) {
|
||||||
RequestMetadata metadata = RequestMetadataMapper.fromDto(metadataDto);
|
throw new BadRequestException("La solicitud es obligatoria");
|
||||||
request.setMetadata(metadata);
|
|
||||||
request.setRequestId(UUID.randomUUID());
|
|
||||||
request.setCreatedAt(Instant.now());
|
|
||||||
return requestRepository.save(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.getType() == null) {
|
||||||
|
throw new BadRequestException("El tipo de solicitud es obligatorio");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getType() == 1 && hasUnregisterRequest(request.getUserId())) {
|
||||||
|
throw new ConflictException("Ya tienes una solicitud, espera que se acepte o se elimine al ser rechazada");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((request.getType() == 2 || request.getType() == 3) &&
|
||||||
|
hasCollaboratorRequest(request.getUserId())) { // tiene soli de collab
|
||||||
|
throw new ConflictException("Ya tienes una solicitud, espera que se acepte o se elimine al ser rechazada");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((request.getType() == 4 || request.getType() == 5) &&
|
||||||
|
hasGreenhouseRequest(request.getUserId())) { // tiene soli de invernadero
|
||||||
|
throw new ConflictException("Ya tienes una solicitud, espera que se acepte o se elimine al ser rechazada");
|
||||||
|
}
|
||||||
|
|
||||||
|
request.setRequestId(UUID.randomUUID());
|
||||||
|
request.setCreatedAt(Instant.now());
|
||||||
|
request.getMetadata().setRequestId(request.getRequestId());
|
||||||
|
|
||||||
|
if (request.getMetadata() != null) {
|
||||||
|
RequestValidator.validate(request.getMetadata(), request.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestRepository.save(request);
|
||||||
|
}
|
||||||
|
|
||||||
public Request update(UUID requestId, Request changes) {
|
public Request update(UUID requestId, Request changes) {
|
||||||
Request request = getById(requestId);
|
Request request = getById(requestId);
|
||||||
@@ -77,13 +96,21 @@ public class RequestService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Request accept(UUID requestId) {
|
public Request accept(UUID requestId) {
|
||||||
Request request = getById(requestId);
|
byte[] bin = UuidUtil.uuidToBin(requestId);
|
||||||
|
Request request = requestRepository.findByIdWithMetadata(bin)
|
||||||
|
.orElseThrow(() -> new NotFoundException("Request no encontrada"));
|
||||||
|
if (request.getStatus() != 0) {
|
||||||
|
throw new BadRequestException("La solicitud ya ha sido procesada");
|
||||||
|
}
|
||||||
request.setStatus((byte)1);
|
request.setStatus((byte)1);
|
||||||
return requestRepository.save(request);
|
return requestRepository.save(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request reject(UUID requestId) {
|
public Request reject(UUID requestId) {
|
||||||
Request request = getById(requestId);
|
Request request = getById(requestId);
|
||||||
|
if (request.getStatus() != 0) {
|
||||||
|
throw new BadRequestException("La solicitud ya ha sido procesada");
|
||||||
|
}
|
||||||
request.setStatus((byte)2);
|
request.setStatus((byte)2);
|
||||||
return requestRepository.save(request);
|
return requestRepository.save(request);
|
||||||
}
|
}
|
||||||
@@ -96,13 +123,18 @@ public class RequestService {
|
|||||||
requestRepository.deleteById(UuidUtil.uuidToBin(id));
|
requestRepository.deleteById(UuidUtil.uuidToBin(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPendingGreenhouseRequest(UUID userId) {
|
public boolean hasGreenhouseRequest(UUID userId) {
|
||||||
|
return getByUserId(userId).stream()
|
||||||
|
.anyMatch(r -> r.getType() == 4 || r.getType() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCollaboratorRequest(UUID userId) {
|
||||||
|
return getByUserId(userId).stream()
|
||||||
|
.anyMatch(r -> r.getType() == 2 || r.getType() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasUnregisterRequest(UUID userId) {
|
||||||
return getByUserId(userId).stream()
|
return getByUserId(userId).stream()
|
||||||
.anyMatch(r -> r.getType() == 1);
|
.anyMatch(r -> r.getType() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPendingCollaboratorRequest(UUID userId) {
|
|
||||||
return getByUserId(userId).stream()
|
|
||||||
.anyMatch(r -> r.getType() == 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ public class UserMetadataService {
|
|||||||
"metadataByMemberNumber",
|
"metadataByMemberNumber",
|
||||||
"metadataExists"
|
"metadataExists"
|
||||||
},
|
},
|
||||||
key = "#userId"
|
key = "#p0"
|
||||||
)
|
)
|
||||||
public UserMetadata update(UUID userId, UserMetadata changes) {
|
public UserMetadata update(UUID userId, UserMetadata changes) {
|
||||||
byte[] idBytes = UuidUtil.uuidToBin(userId);
|
byte[] idBytes = UuidUtil.uuidToBin(userId);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package net.miarma.backend.huertos.service.view;
|
package net.miarma.backend.huertos.service.view;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import net.miarma.backend.huertos.model.Income;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -22,7 +24,9 @@ public class VIncomesWithInfoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<VIncomesWithInfo> getAll() {
|
public List<VIncomesWithInfo> getAll() {
|
||||||
return repository.findAll();
|
return repository.findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(VIncomesWithInfo::getCreatedAt).reversed())
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public VIncomesWithInfo getById(UUID incomeId) {
|
public VIncomesWithInfo getById(UUID incomeId) {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package net.miarma.backend.huertos.util;
|
package net.miarma.backend.huertos.util;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class UsernameGenerator {
|
public class UsernameGenerator {
|
||||||
public static String generate(String name, Integer number) {
|
public static String generate(String name, Integer number) {
|
||||||
return name.split(" ")[0] + number;
|
return name.split(" ")[0].toLowerCase() + number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package net.miarma.backend.huertos.validation;
|
||||||
|
|
||||||
|
import net.miarma.backend.huertos.model.RequestMetadata;
|
||||||
|
import net.miarma.backlib.exception.BadRequestException;
|
||||||
|
import net.miarma.backlib.exception.ValidationException;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class RequestValidator {
|
||||||
|
|
||||||
|
private static final Pattern DNI_PATTERN = Pattern.compile("\\d{8}[A-Za-z]");
|
||||||
|
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$");
|
||||||
|
private static final Pattern PHONE_PATTERN = Pattern.compile("^\\+?\\d{9,15}$");
|
||||||
|
|
||||||
|
public static void validate(RequestMetadata metadata, Byte requestType) {
|
||||||
|
if (metadata.getRequestId() == null) {
|
||||||
|
throw new BadRequestException("Estos metadatos deben pertenecer a una solicitud (falta ID)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(metadata.getDisplayName())) {
|
||||||
|
throw new BadRequestException("El nombre a mostrar es obligatorio");
|
||||||
|
} else if (metadata.getDisplayName().length() < 3) {
|
||||||
|
throw new ValidationException("displayName", "El nombre a mostrar debe tener al menos 3 caracteres");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(metadata.getDni())) {
|
||||||
|
throw new BadRequestException("El DNI es obligatorio");
|
||||||
|
} else if (!DNI_PATTERN.matcher(metadata.getDni()).matches()) {
|
||||||
|
throw new ValidationException("dni", "Formato de DNI inválido (ej: 12345678A)");
|
||||||
|
} else if (!DniValidator.isValid(metadata.getDni())) {
|
||||||
|
throw new ValidationException("dni", "Este DNI no es un DNI real");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(metadata.getEmail())) {
|
||||||
|
throw new BadRequestException("El email es obligatorio");
|
||||||
|
} else if (!EMAIL_PATTERN.matcher(metadata.getEmail()).matches()) {
|
||||||
|
throw new ValidationException("email", "Email inválido");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(metadata.getUsername())) {
|
||||||
|
throw new BadRequestException("El usuario es obligatorio");
|
||||||
|
} else if (metadata.getUsername().length() < 3) {
|
||||||
|
throw new ValidationException("username", "El usuario debe tener al menos 3 caracteres");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.getType() == null) {
|
||||||
|
throw new BadRequestException("El tipo de usuario es obligatorio");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == 2) {
|
||||||
|
if (metadata.getPlotNumber() == null) {
|
||||||
|
throw new BadRequestException("El colaborador debe tener huerto");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == 0 || requestType == 1) {
|
||||||
|
if (metadata.getMemberNumber() == null) {
|
||||||
|
throw new BadRequestException("El número de socio es obligatorio");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == 0) {
|
||||||
|
if (metadata.getAddress() == null || metadata.getZipCode() == null || metadata.getCity() == null) {
|
||||||
|
throw new BadRequestException("La dirección, código postal y ciudad son obligatorios");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == 0) {
|
||||||
|
if (isBlank(metadata.getAddress())) {
|
||||||
|
throw new ValidationException("address", "La dirección es obligatoria");
|
||||||
|
}
|
||||||
|
if (isBlank(metadata.getZipCode())) {
|
||||||
|
throw new ValidationException("zipCode", "El código postal es obligatorio");
|
||||||
|
} else if(metadata.getZipCode().length() < 5) {
|
||||||
|
throw new ValidationException("zipCode", "El código postal debe tener 5 dígitos");
|
||||||
|
}
|
||||||
|
if (isBlank(metadata.getCity())) {
|
||||||
|
throw new ValidationException("city", "La ciudad es obligatoria");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.getPhone() != null && !PHONE_PATTERN.matcher(metadata.getPhone()).matches()) {
|
||||||
|
throw new ValidationException("phone", "Teléfono inválido (debe tener 9 dígitos)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBlank(String s) {
|
||||||
|
return s == null || s.trim().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user