Add: missing create methods in controllers. Fix: SYSTEM token gets the refresh now. Add: CORS. Add: HTTP to core.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>backlib</artifactId>
|
||||
<groupId>net.miarma</groupId>
|
||||
<version>1.0.0</version>
|
||||
<version>1.0.1</version>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.miarma.backlib.dto;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ApiValidationErrorDto {
|
||||
private Map<String,String> errors;
|
||||
private Instant timestamp;
|
||||
|
||||
public ApiValidationErrorDto(Map<String,String> errors) {
|
||||
this.errors = errors;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
|
||||
public Map<String,String> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void setErrors(Map<String,String> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public Instant getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Instant timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,21 @@
|
||||
package net.miarma.backlib.exception;
|
||||
|
||||
public class ValidationException extends RuntimeException {
|
||||
public ValidationException(String message) {
|
||||
private final String field;
|
||||
private final String message;
|
||||
|
||||
public ValidationException(String field, String message) {
|
||||
super(message);
|
||||
this.field = field;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ package net.miarma.backlib.http;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import net.miarma.backlib.dto.ApiErrorDto;
|
||||
import net.miarma.backlib.dto.ApiValidationErrorDto;
|
||||
import net.miarma.backlib.exception.*;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
@@ -81,17 +84,9 @@ public class GlobalExceptionHandler {
|
||||
}
|
||||
|
||||
@ExceptionHandler(ValidationException.class)
|
||||
public ResponseEntity<ApiErrorDto> handleValidation(
|
||||
ValidationException ex, HttpServletRequest req) {
|
||||
|
||||
ApiErrorDto error = new ApiErrorDto(
|
||||
HttpStatus.UNPROCESSABLE_CONTENT.value(),
|
||||
HttpStatus.UNPROCESSABLE_CONTENT.getReasonPhrase(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(error);
|
||||
public ResponseEntity<ApiValidationErrorDto> handleValidation(ValidationException ex) {
|
||||
Map<String, String> errors = Map.of(ex.getField(), ex.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(new ApiValidationErrorDto(errors));
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
|
||||
@@ -2,15 +2,23 @@ package net.miarma.backlib.security;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Component
|
||||
public class CoreAuthTokenHolder {
|
||||
private volatile String token;
|
||||
private volatile Instant expiresAt;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
public boolean isExpired() {
|
||||
return expiresAt == null || Instant.now().isAfter(expiresAt.minusSeconds(30));
|
||||
}
|
||||
|
||||
public void setToken(String token, Instant expiresAt) {
|
||||
this.token = token;
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<dependency>
|
||||
<groupId>net.miarma</groupId>
|
||||
<artifactId>backlib</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import net.miarma.backlib.http.RestAuthEntryPoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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.web.builders.HttpSecurity;
|
||||
@@ -15,6 +16,11 @@ 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.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -34,9 +40,23 @@ public class SecurityConfig {
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
}
|
||||
|
||||
@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
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.cors(Customizer.withDefaults())
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(ex -> ex
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package net.miarma.backend.core.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import net.miarma.backend.core.model.Credential;
|
||||
@@ -106,4 +104,10 @@ public class AuthController {
|
||||
|
||||
return ResponseEntity.ok(Map.of("message", "Password changed successfully"));
|
||||
}
|
||||
|
||||
@GetMapping("/validate")
|
||||
public ResponseEntity<Boolean> validate(@RequestHeader("Authorization") String authHeader) {
|
||||
String token = authHeader.substring(7);
|
||||
return ResponseEntity.ok(jwtService.validateToken(token));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FileController {
|
||||
|
||||
@PutMapping("/{fileId}")
|
||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
||||
public ResponseEntity<File> update(@PathVariable("file_id") UUID fileId, @RequestBody File file) {
|
||||
public ResponseEntity<File> update(@PathVariable("fileId") UUID fileId, @RequestBody File file) {
|
||||
file.setFileId(fileId);
|
||||
File updated = fileService.update(file);
|
||||
return ResponseEntity.ok(updated);
|
||||
@@ -80,7 +80,7 @@ public class FileController {
|
||||
|
||||
@DeleteMapping("/{fileId}")
|
||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
||||
public ResponseEntity<Void> delete(@PathVariable("file_id") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
||||
public ResponseEntity<Void> delete(@PathVariable("fileId") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
||||
String filePath = body.get("file_path");
|
||||
Files.deleteIfExists(Paths.get(filePath));
|
||||
fileService.delete(fileId);
|
||||
|
||||
@@ -28,7 +28,8 @@ public interface CredentialRepository extends JpaRepository<Credential, byte[]>
|
||||
|
||||
Optional<Credential> findByServiceIdAndEmail(Byte serviceId, String email);
|
||||
|
||||
Optional<Credential> findByUserIdAndServiceId(UUID userId, Byte serviceId);
|
||||
@Query("SELECT c FROM Credential c WHERE c.userIdBin = :userIdBin AND c.serviceId = :serviceId")
|
||||
Optional<Credential> findByUserIdAndServiceId(@Param("userIdBin") byte[] userIdBin, @Param("serviceId") Byte serviceId);
|
||||
|
||||
Optional<Credential> findByUsernameAndServiceId(String username, int serviceId);
|
||||
|
||||
|
||||
@@ -38,16 +38,16 @@ public class CredentialService {
|
||||
|
||||
public Credential create(Credential credential) {
|
||||
if (credential.getUsername() == null || credential.getUsername().isBlank()) {
|
||||
throw new ValidationException("Username cannot be blank");
|
||||
throw new ValidationException("userName", "Username cannot be blank");
|
||||
}
|
||||
if (credential.getEmail() == null || !credential.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
|
||||
throw new ValidationException("Invalid email format");
|
||||
throw new ValidationException("email", "Invalid email format");
|
||||
}
|
||||
if (credential.getPassword() == null || credential.getPassword().length() < 6) {
|
||||
throw new ValidationException("Password must be at least 6 characters");
|
||||
throw new ValidationException("password", "Password must be at least 6 characters");
|
||||
}
|
||||
if (credential.getServiceId() == null || credential.getServiceId() < 0) {
|
||||
throw new ValidationException("ServiceId must be positive");
|
||||
throw new ValidationException("serviceId", "ServiceId must be positive");
|
||||
}
|
||||
|
||||
boolean existsUsername = credentialRepository.existsByUsernameAndServiceId(
|
||||
@@ -90,7 +90,7 @@ public class CredentialService {
|
||||
}
|
||||
|
||||
public Credential getByUserIdAndService(UUID userId, Byte serviceId) {
|
||||
return credentialRepository.findByUserIdAndServiceId(userId, serviceId)
|
||||
return credentialRepository.findByUserIdAndServiceId(UuidUtil.uuidToBin(userId), serviceId)
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found in this site"));
|
||||
}
|
||||
|
||||
@@ -117,13 +117,13 @@ public class CredentialService {
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||
|
||||
if (dto.getUsername() != null && dto.getUsername().isBlank()) {
|
||||
throw new ValidationException("Username cannot be blank");
|
||||
throw new ValidationException("userName", "Username cannot be blank");
|
||||
}
|
||||
if (dto.getEmail() != null && !dto.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
|
||||
throw new ValidationException("Invalid email format");
|
||||
throw new ValidationException("email", "Invalid email format");
|
||||
}
|
||||
if (dto.getServiceId() != null && dto.getServiceId() < 0) {
|
||||
throw new ValidationException("ServiceId must be positive");
|
||||
throw new ValidationException("serviceId", "ServiceId must be positive");
|
||||
}
|
||||
|
||||
if (dto.getUsername() != null) cred.setUsername(dto.getUsername());
|
||||
@@ -141,7 +141,7 @@ public class CredentialService {
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||
|
||||
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
|
||||
throw new ValidationException("Old password is incorrect");
|
||||
throw new ValidationException("oldPassword", "Old password is incorrect");
|
||||
}
|
||||
|
||||
cred.setPassword(passwordEncoder.encode(request.newPassword()));
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.UUID;
|
||||
import net.miarma.backend.core.mapper.FileMapper;
|
||||
import net.miarma.backlib.dto.FileDto;
|
||||
import net.miarma.backlib.exception.NotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -24,7 +25,9 @@ import net.miarma.backlib.util.UuidUtil;
|
||||
public class FileService {
|
||||
|
||||
private final FileRepository fileRepository;
|
||||
private final String basePath = "/var/www/files";
|
||||
|
||||
@Value("${filesDir}")
|
||||
private String filesDir;
|
||||
|
||||
public FileService(FileRepository fileRepository) {
|
||||
this.fileRepository = fileRepository;
|
||||
@@ -45,7 +48,7 @@ public class FileService {
|
||||
}
|
||||
|
||||
public File create(FileDto.Request dto, byte[] fileBinary) throws IOException {
|
||||
Path dirPath = Paths.get(basePath, String.valueOf(dto.getContext()));
|
||||
Path dirPath = Paths.get(filesDir, String.valueOf(dto.getContext()));
|
||||
if (!Files.exists(dirPath)) {
|
||||
Files.createDirectories(dirPath);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class UserService {
|
||||
|
||||
public User create(UserDto dto) {
|
||||
if(dto.getDisplayName() == null || dto.getDisplayName().isBlank()) {
|
||||
throw new ValidationException("Display name is required");
|
||||
throw new ValidationException("displayName", "Display name is required");
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
|
||||
@@ -16,6 +16,8 @@ logging:
|
||||
org.hibernate.orm.jdbc.bind: TRACE
|
||||
org.springframework.security: DEBUG
|
||||
|
||||
filesDir: "/home/jomaa/.config/miarma-backend/files"
|
||||
|
||||
jwt:
|
||||
private-key-path: /home/jomaa/.config/miarma-backend/private.pem
|
||||
public-key-path: /home/jomaa/.config/miarma-backend/public.pem
|
||||
|
||||
@@ -15,6 +15,8 @@ logging:
|
||||
org.springframework.security: INFO
|
||||
org.hibernate.SQL: WARN
|
||||
|
||||
filesDir: "/files"
|
||||
|
||||
jwt:
|
||||
private-key-path: ${JWT_PRIVATE_KEY}
|
||||
public-key-path: ${JWT_PUBLIC_KEY}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<dependency>
|
||||
<groupId>net.miarma</groupId>
|
||||
<artifactId>backlib</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<version>1.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.miarma.backend.huertos;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"net.miarma.backend.huertos",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.miarma.backend.huertos.client;
|
||||
|
||||
import net.miarma.backlib.dto.LoginRequest;
|
||||
import net.miarma.backlib.dto.LoginResponse;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Component
|
||||
public class CoreAuthClient {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final String coreUrl;
|
||||
|
||||
public CoreAuthClient(
|
||||
@Qualifier("authRestTemplate") RestTemplate restTemplate,
|
||||
@Value("${core.url}") String coreUrl
|
||||
) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.coreUrl = coreUrl;
|
||||
}
|
||||
|
||||
|
||||
public LoginResponse login(LoginRequest req) {
|
||||
return restTemplate.postForObject(
|
||||
coreUrl + "/auth/login",
|
||||
req,
|
||||
LoginResponse.class
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package net.miarma.backend.huertos.client;
|
||||
import net.miarma.backlib.dto.LoginRequest;
|
||||
import net.miarma.backlib.dto.LoginResponse;
|
||||
import net.miarma.backlib.dto.UserWithCredentialDto;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -17,22 +18,12 @@ public class HuertosWebClient {
|
||||
private final RestTemplate restTemplate;
|
||||
private final String coreUrl;
|
||||
|
||||
public HuertosWebClient(RestTemplate restTemplate,
|
||||
public HuertosWebClient(@Qualifier("secureRestTemplate") RestTemplate restTemplate,
|
||||
@Value("${core.url}") String coreUrl) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.coreUrl = coreUrl;
|
||||
}
|
||||
|
||||
public LoginResponse login(String username, String password) {
|
||||
LoginRequest req = new LoginRequest(username, password, (byte) 1);
|
||||
LoginResponse resp = restTemplate.postForObject(
|
||||
coreUrl + "/auth/login",
|
||||
req,
|
||||
LoginResponse.class
|
||||
);
|
||||
return resp;
|
||||
}
|
||||
|
||||
public UserWithCredentialDto getUserWithCredential(UUID userId, Byte serviceId) {
|
||||
return restTemplate.getForObject(
|
||||
coreUrl + "/users/{user_id}/service/{service_id}",
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.miarma.backend.huertos.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"
|
||||
)
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package net.miarma.backend.huertos.config;
|
||||
|
||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||
import net.miarma.backlib.security.CoreAuthTokenHolder;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class HuertosStartup implements ApplicationRunner {
|
||||
|
||||
private final HuertosWebClient client;
|
||||
private final CoreAuthTokenHolder tokenHolder;
|
||||
private final String user;
|
||||
private final String pass;
|
||||
|
||||
public HuertosStartup(
|
||||
HuertosWebClient client,
|
||||
CoreAuthTokenHolder tokenHolder,
|
||||
@Value("${huertos.user}") String user,
|
||||
@Value("${huertos.password}") String pass
|
||||
) {
|
||||
this.client = client;
|
||||
this.tokenHolder = tokenHolder;
|
||||
this.user = user;
|
||||
this.pass = pass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
String token = client.login(user, pass).token();
|
||||
tokenHolder.setToken(token);
|
||||
System.out.println("TOKEN recibido: " + token);
|
||||
System.out.println("HUERTOS CLIENT has been authenticated in CORE");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.miarma.backend.huertos.config;
|
||||
|
||||
import net.miarma.backend.huertos.service.CoreAuthService;
|
||||
import net.miarma.backlib.security.CoreAuthTokenHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -13,23 +14,21 @@ import java.util.List;
|
||||
public class RestTemplateConfig {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(CoreAuthTokenHolder tokenHolder) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
|
||||
interceptors.add(authInterceptor(tokenHolder));
|
||||
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
return restTemplate;
|
||||
public RestTemplate authRestTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
private ClientHttpRequestInterceptor authInterceptor(CoreAuthTokenHolder tokenHolder) {
|
||||
return (request, body, execution) -> {
|
||||
String token = tokenHolder.getToken();
|
||||
if (token != null) {
|
||||
request.getHeaders().add("Authorization", "Bearer " + token);
|
||||
}
|
||||
@Bean
|
||||
public RestTemplate secureRestTemplate(CoreAuthService coreAuthService) {
|
||||
RestTemplate rt = new RestTemplate();
|
||||
|
||||
rt.getInterceptors().add((request, body, execution) -> {
|
||||
String token = coreAuthService.getToken();
|
||||
request.getHeaders().setBearerAuth(token);
|
||||
return execution.execute(request, body);
|
||||
};
|
||||
});
|
||||
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,18 @@ import net.miarma.backlib.http.RestAccessDeniedHandler;
|
||||
import net.miarma.backlib.http.RestAuthEntryPoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
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.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -31,9 +37,23 @@ public class SecurityConfig {
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
}
|
||||
|
||||
@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
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.cors(Customizer.withDefaults())
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(ex -> ex
|
||||
@@ -43,10 +63,9 @@ public class SecurityConfig {
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
// PUBLICAS
|
||||
.requestMatchers("/auth/login").permitAll()
|
||||
.requestMatchers("/announcements").permitAll()
|
||||
.requestMatchers("/requests/mine").permitAll()
|
||||
.requestMatchers("/users/waitlist/limited").permitAll()
|
||||
.requestMatchers("/users/latest-number").permitAll()
|
||||
.requestMatchers("/pre-users/validate").permitAll()
|
||||
// PRIVADAS
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
|
||||
@@ -50,6 +50,16 @@ public class AnnouncementController {
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<AnnouncementDto.Response> create(@RequestBody AnnouncementDto.Request dto) {
|
||||
return ResponseEntity.ok(
|
||||
AnnouncementMapper.toResponse(
|
||||
announcementService.create(
|
||||
AnnouncementMapper.toEntity(dto)
|
||||
)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{announce_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<Map<String, String>> delete(@PathVariable("announce_id") UUID announcementId) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.miarma.backend.huertos.service.BalanceService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -25,4 +26,14 @@ public class BalanceController {
|
||||
Balance balance = balanceService.get();
|
||||
return ResponseEntity.ok(BalanceMapper.toDto(balance));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<BalanceDto> setBalance(BalanceDto dto) {
|
||||
return ResponseEntity.ok(
|
||||
BalanceMapper.toDto(
|
||||
balanceService.create(BalanceMapper.toEntity(dto))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,16 @@ public class ExpenseController {
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<ExpenseDto.Response> create(ExpenseDto.Request dto) {
|
||||
return ResponseEntity.ok(
|
||||
ExpenseMapper.toResponse(
|
||||
expenseService.create(
|
||||
ExpenseMapper.toEntity(dto)
|
||||
)));
|
||||
}
|
||||
|
||||
@GetMapping("/{expense_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<ExpenseDto.Response> getById(@PathVariable("expense_id") UUID expenseId) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.miarma.backend.huertos.controller;
|
||||
|
||||
import net.miarma.backend.huertos.client.CoreAuthClient;
|
||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||
import net.miarma.backend.huertos.dto.HuertosLoginResponse;
|
||||
import net.miarma.backend.huertos.dto.HuertosUserMetadataDto;
|
||||
@@ -18,17 +19,17 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/auth")
|
||||
public class HuertosAuthController {
|
||||
private final HuertosUserMetadataService metadataService;
|
||||
private final HuertosWebClient webClient;
|
||||
private final CoreAuthClient authClient;
|
||||
|
||||
public HuertosAuthController(HuertosUserMetadataService metadataService,
|
||||
HuertosWebClient webClient) {
|
||||
CoreAuthClient authClient) {
|
||||
this.metadataService = metadataService;
|
||||
this.webClient = webClient;
|
||||
this.authClient = authClient;
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<HuertosLoginResponse> login(@RequestBody LoginRequest req) {
|
||||
LoginResponse coreResponse = webClient.login(req.username(), req.password());
|
||||
LoginResponse coreResponse = authClient.login(req);
|
||||
HuertosUserMetadata metadata = metadataService.getById(coreResponse.user().getUserId());
|
||||
return ResponseEntity.ok(
|
||||
new HuertosLoginResponse(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.miarma.backend.huertos.controller;
|
||||
|
||||
import net.miarma.backend.huertos.dto.ExpenseDto;
|
||||
import net.miarma.backend.huertos.dto.IncomeDto;
|
||||
import net.miarma.backend.huertos.dto.view.VIncomesWithFullNamesDto;
|
||||
import net.miarma.backend.huertos.mapper.ExpenseMapper;
|
||||
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||
import net.miarma.backend.huertos.mapper.view.VIncomesWithFullNamesMapper;
|
||||
import net.miarma.backend.huertos.model.Income;
|
||||
@@ -75,6 +77,16 @@ public class IncomeController {
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<IncomeDto.Response> create(IncomeDto.Request dto) {
|
||||
return ResponseEntity.ok(
|
||||
IncomeMapper.toResponse(
|
||||
incomeService.create(
|
||||
IncomeMapper.toEntity(dto)
|
||||
)));
|
||||
}
|
||||
|
||||
@GetMapping("/{income_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<IncomeDto.Response> getById(@PathVariable("income_id") UUID incomeId) {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package net.miarma.backend.huertos.controller;
|
||||
|
||||
import net.miarma.backend.huertos.dto.MemberDto;
|
||||
import net.miarma.backend.huertos.dto.WaitlistCensoredDto;
|
||||
import net.miarma.backend.huertos.dto.*;
|
||||
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||
import net.miarma.backend.huertos.security.HuertosPrincipal;
|
||||
import net.miarma.backend.huertos.service.IncomeService;
|
||||
import net.miarma.backend.huertos.service.MemberService;
|
||||
import net.miarma.backend.huertos.service.RequestService;
|
||||
import net.miarma.backlib.security.JwtService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -17,106 +23,130 @@ import java.util.UUID;
|
||||
public class MemberController {
|
||||
|
||||
private final MemberService memberService;
|
||||
private final RequestService requestService;
|
||||
private final IncomeService incomeService;
|
||||
private final JwtService jwtService;
|
||||
|
||||
public MemberController(MemberService memberService) {
|
||||
public MemberController(MemberService memberService, RequestService requestService, IncomeService incomeService, JwtService jwtService) {
|
||||
this.memberService = memberService;
|
||||
}
|
||||
|
||||
private Byte getServiceIdFromToken() {
|
||||
var auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (auth == null || !(auth.getPrincipal() instanceof HuertosPrincipal principal)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return principal.getServiceId();
|
||||
this.requestService = requestService;
|
||||
this.incomeService = incomeService;
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public List<MemberDto> getAll() {
|
||||
return memberService.getAll(getServiceIdFromToken());
|
||||
}
|
||||
|
||||
@GetMapping("/{user_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public MemberDto getById(@PathVariable("user_id") UUID userId) {
|
||||
return memberService.getById(userId, getServiceIdFromToken());
|
||||
public ResponseEntity<List<MemberDto>> getAll() {
|
||||
return ResponseEntity.ok(memberService.getAll((byte)1));
|
||||
}
|
||||
|
||||
@GetMapping("/me")
|
||||
public MemberDto getMe() {
|
||||
HuertosPrincipal principal =
|
||||
(HuertosPrincipal) SecurityContextHolder
|
||||
.getContext()
|
||||
.getAuthentication()
|
||||
.getPrincipal();
|
||||
public ResponseEntity<MemberProfileDto> getMe() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
return memberService.getById(principal.getUserId(), getServiceIdFromToken());
|
||||
if (!(authentication.getPrincipal() instanceof HuertosPrincipal principal)) {
|
||||
throw new IllegalStateException("Invalid principal type");
|
||||
}
|
||||
|
||||
UUID userId = principal.getUserId();
|
||||
Byte serviceId = principal.getServiceId();
|
||||
|
||||
if (serviceId == null) {
|
||||
throw new IllegalStateException("ServiceId missing in token");
|
||||
}
|
||||
|
||||
MemberDto member = memberService.getById(userId);
|
||||
Integer memberNumber = member.metadata().getMemberNumber();
|
||||
List<RequestDto.Response> requests = requestService.getByUserId(userId).stream()
|
||||
.map(RequestMapper::toResponse)
|
||||
.toList();
|
||||
List<IncomeDto.Response> payments = incomeService.getByMemberNumber(memberNumber).stream()
|
||||
.map(IncomeMapper::toResponse)
|
||||
.toList();
|
||||
|
||||
return ResponseEntity.ok(
|
||||
new MemberProfileDto(
|
||||
member.user(),
|
||||
member.account(),
|
||||
member.metadata(),
|
||||
requests,
|
||||
payments,
|
||||
memberService.hasCollaborator(memberNumber),
|
||||
memberService.hasGreenhouse(memberNumber),
|
||||
memberService.hasCollaboratorRequest(memberNumber),
|
||||
memberService.hasGreenhouseRequest(memberNumber)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/{user_id:[0-9a-fA-F\\-]{36}}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<MemberDto> getById(@PathVariable("user_id") UUID userId) {
|
||||
return ResponseEntity.ok(memberService.getById(userId));
|
||||
}
|
||||
|
||||
@GetMapping("/latest-number")
|
||||
public Integer getLatestNumber() {
|
||||
return memberService.getLatestMemberNumber();
|
||||
public ResponseEntity<Integer> getLatestNumber() {
|
||||
return ResponseEntity.ok(memberService.getLatestMemberNumber());
|
||||
}
|
||||
|
||||
@GetMapping("/waitlist")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public List<MemberDto> getWaitlist() {
|
||||
return memberService.getWaitlist();
|
||||
public ResponseEntity<List<MemberDto>> getWaitlist() {
|
||||
return ResponseEntity.ok(memberService.getWaitlist());
|
||||
}
|
||||
|
||||
@GetMapping("/waitlist/limited")
|
||||
public List<WaitlistCensoredDto> getWaitlistLimited() {
|
||||
return memberService.getWaitlistLimited();
|
||||
public ResponseEntity<List<WaitlistCensoredDto>> getWaitlistLimited() {
|
||||
return ResponseEntity.ok(memberService.getWaitlistLimited());
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public MemberDto getByMemberNumber(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.getByMemberNumber(memberNumber);
|
||||
public ResponseEntity<MemberDto> getByMemberNumber(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.getByMemberNumber(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/incomes")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public Boolean getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasIncomes(memberNumber);
|
||||
public ResponseEntity<List<IncomeDto.Response>> getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.getIncomes(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/has-paid")
|
||||
public Boolean getMemberHasPaid(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasPaid(memberNumber);
|
||||
public ResponseEntity<Boolean> getMemberHasPaid(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.hasPaid(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/has-collaborator")
|
||||
public Boolean getMemberHasCollaborator(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasCollaborator(memberNumber);
|
||||
public ResponseEntity<Boolean> getMemberHasCollaborator(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.hasCollaborator(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/has-greenhouse")
|
||||
public Boolean getMemberHasGreenhouse(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasGreenhouse(memberNumber);
|
||||
public ResponseEntity<Boolean> getMemberHasGreenhouse(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.hasGreenhouse(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/has-collaborator-request")
|
||||
public Boolean getMemberHasCollaboratorRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasCollaboratorRequest(memberNumber);
|
||||
public ResponseEntity<Boolean> getMemberHasCollaboratorRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.hasCollaboratorRequest(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/number/{member_number}/has-greenhouse-request")
|
||||
public Boolean getMemberHasGreenhouseRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||
return memberService.hasGreenhouseRequest(memberNumber);
|
||||
public ResponseEntity<Boolean> getMemberHasGreenhouseRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||
return ResponseEntity.ok(memberService.hasGreenhouseRequest(memberNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/plot/{plot_number}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public MemberDto getByPlotNumber(@PathVariable("plot_number") Integer plotNumber) {
|
||||
return memberService.getByPlotNumber(plotNumber);
|
||||
public ResponseEntity<MemberDto> getByPlotNumber(@PathVariable("plot_number") Integer plotNumber) {
|
||||
return ResponseEntity.ok(memberService.getByPlotNumber(plotNumber));
|
||||
}
|
||||
|
||||
@GetMapping("/dni/{dni}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public MemberDto getByDni(@PathVariable("dni") String dni) {
|
||||
return memberService.getByDni(dni);
|
||||
public ResponseEntity<MemberDto> getByDni(@PathVariable("dni") String dni) {
|
||||
return ResponseEntity.ok(memberService.getByDni(dni));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import net.miarma.backend.huertos.dto.PreUserDto;
|
||||
import net.miarma.backend.huertos.mapper.PreUserMapper;
|
||||
import net.miarma.backend.huertos.model.PreUser;
|
||||
import net.miarma.backend.huertos.service.PreUserService;
|
||||
import net.miarma.backlib.dto.ApiValidationErrorDto;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -13,7 +15,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/pre_users")
|
||||
@RequestMapping("/pre-users")
|
||||
public class PreUserController {
|
||||
|
||||
private final PreUserService preUserService;
|
||||
@@ -40,6 +42,14 @@ public class PreUserController {
|
||||
return ResponseEntity.ok(PreUserMapper.toResponse(preUser));
|
||||
}
|
||||
|
||||
@PostMapping("/validate")
|
||||
public ResponseEntity<ApiValidationErrorDto> validate(@RequestBody PreUserDto.Request request) {
|
||||
Map<String, String> errors = preUserService.validate(request);
|
||||
if(!errors.isEmpty())
|
||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(new ApiValidationErrorDto(errors));
|
||||
return ResponseEntity.ok(new ApiValidationErrorDto(Map.of()));
|
||||
}
|
||||
|
||||
@PutMapping("/{pre_user_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<PreUserDto.Response> update(
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package net.miarma.backend.huertos.controller;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import net.miarma.backend.huertos.dto.CreateWaitlistDto;
|
||||
import net.miarma.backend.huertos.dto.PreUserDto;
|
||||
import net.miarma.backend.huertos.dto.RequestCountDto;
|
||||
import net.miarma.backend.huertos.dto.RequestDto;
|
||||
import net.miarma.backend.huertos.dto.*;
|
||||
import net.miarma.backend.huertos.dto.view.VRequestsWithPreUsersDto;
|
||||
import net.miarma.backend.huertos.mapper.PreUserMapper;
|
||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||
import net.miarma.backend.huertos.mapper.view.VIncomesWithFullNamesMapper;
|
||||
import net.miarma.backend.huertos.mapper.view.VRequestsWithPreUsersMapper;
|
||||
import net.miarma.backend.huertos.model.PreUser;
|
||||
import net.miarma.backend.huertos.model.Request;
|
||||
import net.miarma.backend.huertos.model.view.VRequestsWithPreUsers;
|
||||
import net.miarma.backend.huertos.service.PreUserService;
|
||||
@@ -57,6 +51,23 @@ public class RequestController {
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<RequestDto.Response> create(RequestDto.Request dto) {
|
||||
return ResponseEntity.ok(
|
||||
RequestMapper.toResponse(
|
||||
requestService.createWaitlist(
|
||||
RequestMapper.toEntity(dto)
|
||||
)));
|
||||
}
|
||||
|
||||
@PostMapping("/waitlist")
|
||||
@Transactional
|
||||
public ResponseEntity<RequestDto.Response> createWaitlist(
|
||||
@RequestBody CreateWaitlistDto body) {
|
||||
RequestDto.Response response = requestService.createWaitlist(body.request(), body.preUser());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@GetMapping("/count")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<RequestCountDto> getRequestCount() {
|
||||
@@ -119,14 +130,6 @@ public class RequestController {
|
||||
return ResponseEntity.ok(RequestMapper.toResponse(request));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public ResponseEntity<RequestDto.Response> create(
|
||||
@RequestBody CreateWaitlistDto body) {
|
||||
RequestDto.Response response = requestService.create(body.request(), body.preUser());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@PutMapping("/{request_id}")
|
||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||
public ResponseEntity<RequestDto.Response> update(
|
||||
|
||||
@@ -39,6 +39,7 @@ public class AnnouncementDto {
|
||||
private String body;
|
||||
private Byte priority;
|
||||
private UUID publishedBy;
|
||||
private String publishedByName;
|
||||
private Instant createdAt;
|
||||
|
||||
public UUID getAnnounceId() {
|
||||
@@ -73,6 +74,10 @@ public class AnnouncementDto {
|
||||
this.publishedBy = publishedBy;
|
||||
}
|
||||
|
||||
public String getPublishedByName() { return publishedByName; }
|
||||
|
||||
public void setPublishedByName(String publishedByName) { this.publishedByName = publishedByName; }
|
||||
|
||||
public Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.miarma.backend.huertos.dto;
|
||||
|
||||
import net.miarma.backlib.dto.CredentialDto;
|
||||
import net.miarma.backlib.dto.UserDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record MemberProfileDto(
|
||||
UserDto user,
|
||||
CredentialDto account,
|
||||
HuertosUserMetadataDto metadata,
|
||||
List<RequestDto.Response> requests,
|
||||
List<IncomeDto.Response> payments,
|
||||
boolean hasCollaborator,
|
||||
boolean hasGreenhouse,
|
||||
boolean hasCollaboratorRequest,
|
||||
boolean hasGreenhouseRequest
|
||||
) {
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.miarma.backend.huertos.dto;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -33,15 +35,15 @@ public class RequestDto {
|
||||
this.requestedBy = requestedBy;
|
||||
}
|
||||
|
||||
public UUID getTargetUserId() {
|
||||
public @Nullable UUID getTargetUserId() {
|
||||
return targetUserId;
|
||||
}
|
||||
|
||||
public void setTargetUserId(UUID targetUserId) {
|
||||
public void setTargetUserId(@Nullable UUID targetUserId) {
|
||||
this.targetUserId = targetUserId;
|
||||
}
|
||||
|
||||
private UUID targetUserId;
|
||||
@Nullable private UUID targetUserId;
|
||||
}
|
||||
|
||||
public static class Response {
|
||||
|
||||
@@ -14,6 +14,7 @@ public class AnnouncementMapper {
|
||||
dto.setBody(entity.getBody());
|
||||
dto.setPriority(entity.getPriority());
|
||||
dto.setPublishedBy(entity.getPublishedBy());
|
||||
dto.setPublishedByName(entity.getPublishedByName());
|
||||
dto.setCreatedAt(entity.getCreatedAt());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,14 @@ public class Announcement {
|
||||
@Column(name = "priority", nullable = false)
|
||||
private Byte priority;
|
||||
|
||||
@Column(name = "published_by", columnDefinition = "BINARY(16)", nullable = false)
|
||||
private UUID publishedBy;
|
||||
@Column(name = "published_by", columnDefinition = "BINARY(16)", nullable = false)
|
||||
private byte[] publishedByBin;
|
||||
|
||||
@Transient
|
||||
private UUID publishedBy;
|
||||
|
||||
@Column(name = "published_by_name", nullable = false)
|
||||
private String publishedByName;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private Instant createdAt;
|
||||
@@ -35,6 +41,10 @@ public class Announcement {
|
||||
if (announceId != null) {
|
||||
announceIdBin = UuidUtil.uuidToBin(announceId);
|
||||
}
|
||||
|
||||
if (publishedBy != null) {
|
||||
publishedByBin = UuidUtil.uuidToBin(publishedBy);
|
||||
}
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
@@ -42,6 +52,10 @@ public class Announcement {
|
||||
if (announceIdBin != null) {
|
||||
announceId = UuidUtil.binToUUID(announceIdBin);
|
||||
}
|
||||
|
||||
if (publishedByBin != null) {
|
||||
publishedBy = UuidUtil.binToUUID(publishedByBin);
|
||||
}
|
||||
}
|
||||
|
||||
public UUID getAnnounceId() {
|
||||
@@ -76,6 +90,14 @@ public class Announcement {
|
||||
this.publishedBy = publishedBy;
|
||||
}
|
||||
|
||||
public String getPublishedByName() {
|
||||
return publishedByName;
|
||||
}
|
||||
|
||||
public void setPublishedByName(String publishedByName) {
|
||||
this.publishedByName = publishedByName;
|
||||
}
|
||||
|
||||
public Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@@ -4,4 +4,7 @@ import net.miarma.backend.huertos.model.PreUser;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PreUserRepository extends JpaRepository<PreUser, byte[]> {
|
||||
boolean existsByDni(String dni);
|
||||
|
||||
boolean existsByEmail(String email);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ import java.util.UUID;
|
||||
public class AnnouncementService {
|
||||
|
||||
private final AnnouncementRepository announcementRepository;
|
||||
private final MemberService memberService;
|
||||
|
||||
public AnnouncementService(AnnouncementRepository announcementRepository) {
|
||||
public AnnouncementService(AnnouncementRepository announcementRepository, MemberService memberService) {
|
||||
this.announcementRepository = announcementRepository;
|
||||
this.memberService = memberService;
|
||||
}
|
||||
|
||||
public List<Announcement> getAll() {
|
||||
@@ -36,6 +38,7 @@ public class AnnouncementService {
|
||||
if (announcement.getAnnounceId() == null) {
|
||||
announcement.setAnnounceId(UUID.randomUUID());
|
||||
}
|
||||
announcement.setPublishedByName(memberService.getById(announcement.getPublishedBy()).user().getDisplayName());
|
||||
announcement.setCreatedAt(Instant.now());
|
||||
return announcementRepository.save(announcement);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package net.miarma.backend.huertos.service;
|
||||
|
||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||
import net.miarma.backlib.dto.LoginRequest;
|
||||
import net.miarma.backlib.dto.LoginResponse;
|
||||
import net.miarma.backlib.security.CoreAuthTokenHolder;
|
||||
import net.miarma.backlib.security.JwtService;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Service
|
||||
public class CoreAuthService {
|
||||
|
||||
private final RestTemplate authRestTemplate;
|
||||
private final CoreAuthTokenHolder tokenHolder;
|
||||
private final JwtService jwtService;
|
||||
|
||||
@Value("${huertos.user}")
|
||||
private String username;
|
||||
|
||||
@Value("${huertos.password}")
|
||||
private String password;
|
||||
|
||||
@Value("${core.url}")
|
||||
private String coreUrl;
|
||||
|
||||
public CoreAuthService(@Qualifier("authRestTemplate") RestTemplate authRestTemplate,
|
||||
CoreAuthTokenHolder tokenHolder,
|
||||
JwtService jwtService) {
|
||||
this.authRestTemplate = authRestTemplate;
|
||||
this.tokenHolder = tokenHolder;
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
public synchronized String getToken() {
|
||||
if (tokenHolder.getToken() == null || tokenHolder.isExpired()) {
|
||||
refreshToken();
|
||||
}
|
||||
return tokenHolder.getToken();
|
||||
}
|
||||
|
||||
private void refreshToken() {
|
||||
var req = new LoginRequest(username, password, (byte) 1);
|
||||
|
||||
LoginResponse resp = authRestTemplate.postForObject(
|
||||
coreUrl + "/auth/login",
|
||||
req,
|
||||
LoginResponse.class
|
||||
);
|
||||
|
||||
String token = resp.token();
|
||||
Instant exp = jwtService.getExpiration(token).toInstant();
|
||||
tokenHolder.setToken(token, exp);
|
||||
}
|
||||
}
|
||||
@@ -35,16 +35,16 @@ public class ExpenseService {
|
||||
|
||||
public Expense create(Expense expense) {
|
||||
if (expense.getConcept() == null || expense.getConcept().isBlank()) {
|
||||
throw new ValidationException("Concept is required");
|
||||
throw new ValidationException("concept", "Concept is required");
|
||||
}
|
||||
if (expense.getAmount() == null) {
|
||||
throw new ValidationException("Amount is required");
|
||||
throw new ValidationException("amount", "Amount is required");
|
||||
}
|
||||
if (expense.getSupplier() == null || expense.getSupplier().isBlank()) {
|
||||
throw new ValidationException("Supplier is required");
|
||||
throw new ValidationException("supplier", "Supplier is required");
|
||||
}
|
||||
if (expense.getInvoice() == null || expense.getInvoice().isBlank()) {
|
||||
throw new ValidationException("Invoice is required");
|
||||
throw new ValidationException("invoice", "Invoice is required");
|
||||
}
|
||||
|
||||
expense.setExpenseId(UUID.randomUUID());
|
||||
|
||||
@@ -54,7 +54,7 @@ public class IncomeService {
|
||||
throw new BadRequestException("concept is required");
|
||||
}
|
||||
if (income.getAmount() == null || income.getAmount().signum() <= 0) {
|
||||
throw new ValidationException("amount must be positive");
|
||||
throw new ValidationException("amount", "amount must be positive");
|
||||
}
|
||||
|
||||
income.setIncomeId(UUID.randomUUID());
|
||||
@@ -72,7 +72,7 @@ public class IncomeService {
|
||||
if (dto.getConcept() != null) income.setConcept(dto.getConcept());
|
||||
if (dto.getAmount() != null) {
|
||||
if (dto.getAmount().signum() <= 0) {
|
||||
throw new ValidationException("amount must be positive");
|
||||
throw new ValidationException("amount", "amount must be positive");
|
||||
}
|
||||
income.setAmount(dto.getAmount());
|
||||
}
|
||||
@@ -106,4 +106,9 @@ public class IncomeService {
|
||||
List<Income> incomes = getByUserId(userId);
|
||||
return !incomes.isEmpty() && incomes.stream().allMatch(Income::isPaid);
|
||||
}
|
||||
|
||||
public List<Income> getByMemberNumber(Integer memberNumber) {
|
||||
UUID userId = metadataService.getByMemberNumber(memberNumber).getUserId();
|
||||
return getByUserId(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package net.miarma.backend.huertos.service;
|
||||
|
||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
||||
import net.miarma.backend.huertos.dto.IncomeDto;
|
||||
import net.miarma.backend.huertos.dto.MemberDto;
|
||||
import net.miarma.backend.huertos.dto.WaitlistCensoredDto;
|
||||
import net.miarma.backend.huertos.mapper.HuertosUserMetadataMapper;
|
||||
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||
import net.miarma.backend.huertos.security.NameCensorer;
|
||||
import net.miarma.backlib.dto.UserWithCredentialDto;
|
||||
import net.miarma.backlib.exception.NotFoundException;
|
||||
@@ -31,12 +33,22 @@ public class MemberService {
|
||||
this.metadataService = metadataService;
|
||||
}
|
||||
|
||||
public MemberDto getById(UUID userId, Byte serviceId) {
|
||||
var uwc = huertosWebClient.getUserWithCredential(userId, serviceId);
|
||||
var meta = metadataService.getById(userId);
|
||||
public MemberDto getById(UUID userId) {
|
||||
var uwc = huertosWebClient.getUserWithCredential(userId, (byte)1);
|
||||
if (uwc == null) {
|
||||
throw new NotFoundException("User not found in core");
|
||||
}
|
||||
|
||||
return new MemberDto(uwc.user(), uwc.account(),
|
||||
HuertosUserMetadataMapper.toDto(meta));
|
||||
var meta = metadataService.getById(userId);
|
||||
if (meta == null) {
|
||||
throw new NotFoundException("User metadata not found");
|
||||
}
|
||||
|
||||
return new MemberDto(
|
||||
uwc.user(),
|
||||
uwc.account(),
|
||||
HuertosUserMetadataMapper.toDto(meta)
|
||||
);
|
||||
}
|
||||
|
||||
public List<MemberDto> getAll(Byte serviceId) {
|
||||
@@ -106,8 +118,10 @@ public class MemberService {
|
||||
.orElseThrow(() -> new NotFoundException("Member not found"));
|
||||
}
|
||||
|
||||
public Boolean hasIncomes(Integer memberNumber) {
|
||||
return incomeService.existsByMemberNumber(memberNumber);
|
||||
public List<IncomeDto.Response> getIncomes(Integer memberNumber) {
|
||||
return incomeService.getByMemberNumber(memberNumber).stream()
|
||||
.map(IncomeMapper::toResponse)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Boolean hasPaid(Integer memberNumber) {
|
||||
@@ -132,11 +146,11 @@ public class MemberService {
|
||||
.toList();
|
||||
|
||||
return plotMembers.stream()
|
||||
.anyMatch(dto -> dto.metadata().getType().equals((byte)2));
|
||||
.anyMatch(dto -> dto.metadata().getType().equals((byte)3));
|
||||
}
|
||||
|
||||
public Boolean hasGreenhouse(Integer memberNumber) {
|
||||
return metadataService.existsByMemberNumber(memberNumber);
|
||||
return metadataService.getByMemberNumber(memberNumber).getType().equals((byte)2);
|
||||
}
|
||||
|
||||
public Boolean hasCollaboratorRequest(Integer memberNumber) {
|
||||
|
||||
@@ -2,9 +2,11 @@ package net.miarma.backend.huertos.service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.miarma.backend.huertos.dto.PreUserDto;
|
||||
import net.miarma.backend.huertos.validation.PreUserValidator;
|
||||
import net.miarma.backlib.exception.BadRequestException;
|
||||
import net.miarma.backlib.exception.NotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -100,4 +102,18 @@ public class PreUserService {
|
||||
|
||||
repository.deleteById(idBytes);
|
||||
}
|
||||
|
||||
public Map<String, String> validate(PreUserDto.Request request) {
|
||||
Map<String, String> errors = PreUserValidator.validate(request);
|
||||
|
||||
if (request.getDni() != null && repository.existsByDni(request.getDni())) {
|
||||
errors.put("dni", "There is already an user with that NIF/NIE");
|
||||
}
|
||||
|
||||
if (request.getEmail() != null && repository.existsByEmail(request.getEmail())) {
|
||||
errors.put("email", "There is already an user with that email");
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import net.miarma.backend.huertos.dto.PreUserDto;
|
||||
import net.miarma.backend.huertos.dto.RequestDto;
|
||||
import net.miarma.backend.huertos.mapper.PreUserMapper;
|
||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
||||
import net.miarma.backend.huertos.model.HuertosUserMetadata;
|
||||
import net.miarma.backend.huertos.model.PreUser;
|
||||
import net.miarma.backend.huertos.repository.PreUserRepository;
|
||||
import net.miarma.backlib.exception.BadRequestException;
|
||||
@@ -64,7 +63,7 @@ public class RequestService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Request create(Request request) {
|
||||
public Request createWaitlist(Request request) {
|
||||
if (request.getType() == null) {
|
||||
throw new BadRequestException("type is required");
|
||||
}
|
||||
@@ -82,8 +81,8 @@ public class RequestService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public RequestDto.Response create(RequestDto.Request requestDto,
|
||||
PreUserDto.Request preUserDto) {
|
||||
public RequestDto.Response createWaitlist(RequestDto.Request requestDto,
|
||||
PreUserDto.Request preUserDto) {
|
||||
PreUser preUser = preUserRepository.save(PreUserMapper.toEntity(preUserDto));
|
||||
Request request = requestRepository.save(RequestMapper.toEntity(requestDto));
|
||||
return RequestMapper.toResponse(request);
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package net.miarma.backend.huertos.validation;
|
||||
|
||||
/**
|
||||
* Validador de DNI/NIE español.
|
||||
* <p>
|
||||
* Este validador comprueba si un DNI o NIE es válido según las reglas establecidas por la legislación española.
|
||||
* Un DNI debe tener 8 dígitos seguidos de una letra, y un NIE debe comenzar con X, Y o Z seguido de 7 dígitos y una letra.
|
||||
*
|
||||
* @author José Manuel Amador Gallardo
|
||||
*/
|
||||
public class DniValidator {
|
||||
|
||||
/**
|
||||
* Valida un DNI o NIE español.
|
||||
*
|
||||
* @param id El DNI o NIE a validar.
|
||||
* @return true si el DNI/NIE es válido, false en caso contrario.
|
||||
*/
|
||||
public static boolean isValid(String id) {
|
||||
if (id == null || id.length() != 9) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id = id.toUpperCase(); // Pa evitar problemas con minúsculas
|
||||
String numberPart;
|
||||
char letterPart = id.charAt(8);
|
||||
|
||||
if (id.startsWith("X") || id.startsWith("Y") || id.startsWith("Z")) {
|
||||
// NIE
|
||||
char prefix = id.charAt(0);
|
||||
String numericPrefix = switch (prefix) {
|
||||
case 'X' -> "0";
|
||||
case 'Y' -> "1";
|
||||
case 'Z' -> "2";
|
||||
default -> null;
|
||||
};
|
||||
|
||||
if (numericPrefix == null) return false;
|
||||
|
||||
numberPart = numericPrefix + id.substring(1, 8);
|
||||
} else {
|
||||
// DNI
|
||||
numberPart = id.substring(0, 8);
|
||||
}
|
||||
|
||||
if (!numberPart.matches("\\d{8}")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int number = Integer.parseInt(numberPart);
|
||||
char expectedLetter = calculateLetter(number);
|
||||
|
||||
return letterPart == expectedLetter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcula la letra correspondiente a un número de DNI.
|
||||
*
|
||||
* @param number El número del DNI (8 dígitos).
|
||||
* @return La letra correspondiente.
|
||||
*/
|
||||
private static char calculateLetter(int number) {
|
||||
String letters = "TRWAGMYFPDXBNJZSQVHLCKE";
|
||||
return letters.charAt(number % 23);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.miarma.backend.huertos.validation;
|
||||
|
||||
import net.miarma.backend.huertos.dto.PreUserDto;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PreUserValidator {
|
||||
|
||||
public static Map<String, String> validate(PreUserDto.Request dto) {
|
||||
Map<String, String> errors = new HashMap<>();
|
||||
|
||||
if (dto.getUserName() == null || dto.getUserName().isBlank()) {
|
||||
errors.put("userName", "El nombre de usuario es obligatorio");
|
||||
} else if (dto.getUserName().length() < 3) {
|
||||
errors.put("userName", "El nombre de usuario debe tener al menos 3 caracteres");
|
||||
}
|
||||
|
||||
if (dto.getDisplayName() == null || dto.getDisplayName().isBlank()) {
|
||||
errors.put("displayName", "El nombre visible es obligatorio");
|
||||
}
|
||||
|
||||
if (dto.getDni() == null || dto.getDni().isBlank()) {
|
||||
errors.put("dni", "El DNI es obligatorio");
|
||||
} else if (!dto.getDni().matches("^[0-9]{8}[A-Za-z]$")) {
|
||||
errors.put("dni", "DNI inválido");
|
||||
}
|
||||
|
||||
if (dto.getEmail() == null || dto.getEmail().isBlank()) {
|
||||
errors.put("email", "El email es obligatorio");
|
||||
} else if (!dto.getEmail().matches("^[\\w-.]+@([\\w-]+\\.)+[\\w-]{2,4}$")) {
|
||||
errors.put("email", "Email inválido");
|
||||
}
|
||||
|
||||
if (dto.getPhone() == null || dto.getPhone().isBlank()) {
|
||||
errors.put("phone", "El teléfono es obligatorio");
|
||||
} else if (!dto.getPhone().matches("^[0-9]{9}$")) {
|
||||
errors.put("phone", "Teléfono inválido");
|
||||
}
|
||||
|
||||
if (dto.getAddress() == null || dto.getAddress().isBlank()) {
|
||||
errors.put("address", "La dirección es obligatoria");
|
||||
}
|
||||
|
||||
if (dto.getZipCode() == null || dto.getZipCode().isBlank()) {
|
||||
errors.put("zipCode", "El código postal es obligatorio");
|
||||
}
|
||||
|
||||
if (dto.getCity() == null || dto.getCity().isBlank()) {
|
||||
errors.put("city", "La ciudad es obligatoria");
|
||||
}
|
||||
|
||||
if (dto.getPassword() == null || dto.getPassword().isBlank()) {
|
||||
errors.put("password", "La contraseña es obligatoria");
|
||||
} else if (dto.getPassword().length() < 6) {
|
||||
errors.put("password", "La contraseña debe tener al menos 6 caracteres");
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user