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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.1</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>25</java.version>
|
<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;
|
package net.miarma.backlib.exception;
|
||||||
|
|
||||||
public class ValidationException extends RuntimeException {
|
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);
|
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 jakarta.servlet.http.HttpServletRequest;
|
||||||
import net.miarma.backlib.dto.ApiErrorDto;
|
import net.miarma.backlib.dto.ApiErrorDto;
|
||||||
|
import net.miarma.backlib.dto.ApiValidationErrorDto;
|
||||||
import net.miarma.backlib.exception.*;
|
import net.miarma.backlib.exception.*;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
@ExceptionHandler(NotFoundException.class)
|
@ExceptionHandler(NotFoundException.class)
|
||||||
@@ -81,17 +84,9 @@ public class GlobalExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ValidationException.class)
|
@ExceptionHandler(ValidationException.class)
|
||||||
public ResponseEntity<ApiErrorDto> handleValidation(
|
public ResponseEntity<ApiValidationErrorDto> handleValidation(ValidationException ex) {
|
||||||
ValidationException ex, HttpServletRequest req) {
|
Map<String, String> errors = Map.of(ex.getField(), ex.getMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(new ApiValidationErrorDto(errors));
|
||||||
ApiErrorDto error = new ApiErrorDto(
|
|
||||||
HttpStatus.UNPROCESSABLE_CONTENT.value(),
|
|
||||||
HttpStatus.UNPROCESSABLE_CONTENT.getReasonPhrase(),
|
|
||||||
ex.getMessage(),
|
|
||||||
req.getRequestURI()
|
|
||||||
);
|
|
||||||
|
|
||||||
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_CONTENT).body(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
|
|||||||
@@ -2,15 +2,23 @@ package net.miarma.backlib.security;
|
|||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class CoreAuthTokenHolder {
|
public class CoreAuthTokenHolder {
|
||||||
private volatile String token;
|
private volatile String token;
|
||||||
|
private volatile Instant expiresAt;
|
||||||
|
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
return token;
|
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.token = token;
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
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.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;
|
||||||
@@ -15,6 +16,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
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.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -34,9 +40,23 @@ public class SecurityConfig {
|
|||||||
this.accessDeniedHandler = accessDeniedHandler;
|
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
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
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
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
package net.miarma.backend.core.controller;
|
package net.miarma.backend.core.controller;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
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;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
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 jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import net.miarma.backend.core.model.Credential;
|
import net.miarma.backend.core.model.Credential;
|
||||||
@@ -106,4 +104,10 @@ public class AuthController {
|
|||||||
|
|
||||||
return ResponseEntity.ok(Map.of("message", "Password changed successfully"));
|
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}")
|
@PutMapping("/{fileId}")
|
||||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
@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.setFileId(fileId);
|
||||||
File updated = fileService.update(file);
|
File updated = fileService.update(file);
|
||||||
return ResponseEntity.ok(updated);
|
return ResponseEntity.ok(updated);
|
||||||
@@ -80,7 +80,7 @@ public class FileController {
|
|||||||
|
|
||||||
@DeleteMapping("/{fileId}")
|
@DeleteMapping("/{fileId}")
|
||||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
@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");
|
String filePath = body.get("file_path");
|
||||||
Files.deleteIfExists(Paths.get(filePath));
|
Files.deleteIfExists(Paths.get(filePath));
|
||||||
fileService.delete(fileId);
|
fileService.delete(fileId);
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ public interface CredentialRepository extends JpaRepository<Credential, byte[]>
|
|||||||
|
|
||||||
Optional<Credential> findByServiceIdAndEmail(Byte serviceId, String email);
|
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);
|
Optional<Credential> findByUsernameAndServiceId(String username, int serviceId);
|
||||||
|
|
||||||
|
|||||||
@@ -38,16 +38,16 @@ public class CredentialService {
|
|||||||
|
|
||||||
public Credential create(Credential credential) {
|
public Credential create(Credential credential) {
|
||||||
if (credential.getUsername() == null || credential.getUsername().isBlank()) {
|
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]+$")) {
|
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) {
|
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) {
|
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(
|
boolean existsUsername = credentialRepository.existsByUsernameAndServiceId(
|
||||||
@@ -90,7 +90,7 @@ public class CredentialService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Credential getByUserIdAndService(UUID userId, Byte serviceId) {
|
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"));
|
.orElseThrow(() -> new NotFoundException("Credential not found in this site"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +117,13 @@ public class CredentialService {
|
|||||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||||
|
|
||||||
if (dto.getUsername() != null && dto.getUsername().isBlank()) {
|
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]+$")) {
|
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) {
|
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());
|
if (dto.getUsername() != null) cred.setUsername(dto.getUsername());
|
||||||
@@ -141,7 +141,7 @@ public class CredentialService {
|
|||||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||||
|
|
||||||
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
|
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()));
|
cred.setPassword(passwordEncoder.encode(request.newPassword()));
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.util.UUID;
|
|||||||
import net.miarma.backend.core.mapper.FileMapper;
|
import net.miarma.backend.core.mapper.FileMapper;
|
||||||
import net.miarma.backlib.dto.FileDto;
|
import net.miarma.backlib.dto.FileDto;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -24,7 +25,9 @@ import net.miarma.backlib.util.UuidUtil;
|
|||||||
public class FileService {
|
public class FileService {
|
||||||
|
|
||||||
private final FileRepository fileRepository;
|
private final FileRepository fileRepository;
|
||||||
private final String basePath = "/var/www/files";
|
|
||||||
|
@Value("${filesDir}")
|
||||||
|
private String filesDir;
|
||||||
|
|
||||||
public FileService(FileRepository fileRepository) {
|
public FileService(FileRepository fileRepository) {
|
||||||
this.fileRepository = fileRepository;
|
this.fileRepository = fileRepository;
|
||||||
@@ -45,7 +48,7 @@ public class FileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public File create(FileDto.Request dto, byte[] fileBinary) throws IOException {
|
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)) {
|
if (!Files.exists(dirPath)) {
|
||||||
Files.createDirectories(dirPath);
|
Files.createDirectories(dirPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class UserService {
|
|||||||
|
|
||||||
public User create(UserDto dto) {
|
public User create(UserDto dto) {
|
||||||
if(dto.getDisplayName() == null || dto.getDisplayName().isBlank()) {
|
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();
|
User user = new User();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ logging:
|
|||||||
org.hibernate.orm.jdbc.bind: TRACE
|
org.hibernate.orm.jdbc.bind: TRACE
|
||||||
org.springframework.security: DEBUG
|
org.springframework.security: DEBUG
|
||||||
|
|
||||||
|
filesDir: "/home/jomaa/.config/miarma-backend/files"
|
||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
private-key-path: /home/jomaa/.config/miarma-backend/private.pem
|
private-key-path: /home/jomaa/.config/miarma-backend/private.pem
|
||||||
public-key-path: /home/jomaa/.config/miarma-backend/public.pem
|
public-key-path: /home/jomaa/.config/miarma-backend/public.pem
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ logging:
|
|||||||
org.springframework.security: INFO
|
org.springframework.security: INFO
|
||||||
org.hibernate.SQL: WARN
|
org.hibernate.SQL: WARN
|
||||||
|
|
||||||
|
filesDir: "/files"
|
||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
private-key-path: ${JWT_PRIVATE_KEY}
|
private-key-path: ${JWT_PRIVATE_KEY}
|
||||||
public-key-path: ${JWT_PUBLIC_KEY}
|
public-key-path: ${JWT_PUBLIC_KEY}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.miarma</groupId>
|
<groupId>net.miarma</groupId>
|
||||||
<artifactId>backlib</artifactId>
|
<artifactId>backlib</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.miarma.backend.huertos;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {
|
@SpringBootApplication(scanBasePackages = {
|
||||||
"net.miarma.backend.huertos",
|
"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.LoginRequest;
|
||||||
import net.miarma.backlib.dto.LoginResponse;
|
import net.miarma.backlib.dto.LoginResponse;
|
||||||
import net.miarma.backlib.dto.UserWithCredentialDto;
|
import net.miarma.backlib.dto.UserWithCredentialDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
@@ -17,22 +18,12 @@ public class HuertosWebClient {
|
|||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private final String coreUrl;
|
private final String coreUrl;
|
||||||
|
|
||||||
public HuertosWebClient(RestTemplate restTemplate,
|
public HuertosWebClient(@Qualifier("secureRestTemplate") RestTemplate restTemplate,
|
||||||
@Value("${core.url}") String coreUrl) {
|
@Value("${core.url}") String coreUrl) {
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
this.coreUrl = coreUrl;
|
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) {
|
public UserWithCredentialDto getUserWithCredential(UUID userId, Byte serviceId) {
|
||||||
return restTemplate.getForObject(
|
return restTemplate.getForObject(
|
||||||
coreUrl + "/users/{user_id}/service/{service_id}",
|
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;
|
package net.miarma.backend.huertos.config;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -13,23 +14,21 @@ import java.util.List;
|
|||||||
public class RestTemplateConfig {
|
public class RestTemplateConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestTemplate restTemplate(CoreAuthTokenHolder tokenHolder) {
|
public RestTemplate authRestTemplate() {
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
return new RestTemplate();
|
||||||
|
|
||||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
|
|
||||||
interceptors.add(authInterceptor(tokenHolder));
|
|
||||||
|
|
||||||
restTemplate.setInterceptors(interceptors);
|
|
||||||
return restTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientHttpRequestInterceptor authInterceptor(CoreAuthTokenHolder tokenHolder) {
|
@Bean
|
||||||
return (request, body, execution) -> {
|
public RestTemplate secureRestTemplate(CoreAuthService coreAuthService) {
|
||||||
String token = tokenHolder.getToken();
|
RestTemplate rt = new RestTemplate();
|
||||||
if (token != null) {
|
|
||||||
request.getHeaders().add("Authorization", "Bearer " + token);
|
rt.getInterceptors().add((request, body, execution) -> {
|
||||||
}
|
String token = coreAuthService.getToken();
|
||||||
|
request.getHeaders().setBearerAuth(token);
|
||||||
return execution.execute(request, body);
|
return execution.execute(request, body);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
return rt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,18 @@ 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.config.Customizer;
|
||||||
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.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.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -31,9 +37,23 @@ public class SecurityConfig {
|
|||||||
this.accessDeniedHandler = accessDeniedHandler;
|
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
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
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
|
||||||
@@ -43,10 +63,9 @@ public class SecurityConfig {
|
|||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
// PUBLICAS
|
// PUBLICAS
|
||||||
.requestMatchers("/auth/login").permitAll()
|
.requestMatchers("/auth/login").permitAll()
|
||||||
.requestMatchers("/announcements").permitAll()
|
|
||||||
.requestMatchers("/requests/mine").permitAll()
|
|
||||||
.requestMatchers("/users/waitlist/limited").permitAll()
|
.requestMatchers("/users/waitlist/limited").permitAll()
|
||||||
.requestMatchers("/users/latest-number").permitAll()
|
.requestMatchers("/users/latest-number").permitAll()
|
||||||
|
.requestMatchers("/pre-users/validate").permitAll()
|
||||||
// PRIVADAS
|
// PRIVADAS
|
||||||
.anyRequest().authenticated()
|
.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}")
|
@DeleteMapping("/{announce_id}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<Map<String, String>> delete(@PathVariable("announce_id") UUID announcementId) {
|
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.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@@ -25,4 +26,14 @@ public class BalanceController {
|
|||||||
Balance balance = balanceService.get();
|
Balance balance = balanceService.get();
|
||||||
return ResponseEntity.ok(BalanceMapper.toDto(balance));
|
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}")
|
@GetMapping("/{expense_id}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<ExpenseDto.Response> getById(@PathVariable("expense_id") UUID expenseId) {
|
public ResponseEntity<ExpenseDto.Response> getById(@PathVariable("expense_id") UUID expenseId) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.miarma.backend.huertos.controller;
|
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.client.HuertosWebClient;
|
||||||
import net.miarma.backend.huertos.dto.HuertosLoginResponse;
|
import net.miarma.backend.huertos.dto.HuertosLoginResponse;
|
||||||
import net.miarma.backend.huertos.dto.HuertosUserMetadataDto;
|
import net.miarma.backend.huertos.dto.HuertosUserMetadataDto;
|
||||||
@@ -18,17 +19,17 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/auth")
|
@RequestMapping("/auth")
|
||||||
public class HuertosAuthController {
|
public class HuertosAuthController {
|
||||||
private final HuertosUserMetadataService metadataService;
|
private final HuertosUserMetadataService metadataService;
|
||||||
private final HuertosWebClient webClient;
|
private final CoreAuthClient authClient;
|
||||||
|
|
||||||
public HuertosAuthController(HuertosUserMetadataService metadataService,
|
public HuertosAuthController(HuertosUserMetadataService metadataService,
|
||||||
HuertosWebClient webClient) {
|
CoreAuthClient authClient) {
|
||||||
this.metadataService = metadataService;
|
this.metadataService = metadataService;
|
||||||
this.webClient = webClient;
|
this.authClient = authClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<HuertosLoginResponse> login(@RequestBody LoginRequest req) {
|
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());
|
HuertosUserMetadata metadata = metadataService.getById(coreResponse.user().getUserId());
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
new HuertosLoginResponse(
|
new HuertosLoginResponse(
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package net.miarma.backend.huertos.controller;
|
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.IncomeDto;
|
||||||
import net.miarma.backend.huertos.dto.view.VIncomesWithFullNamesDto;
|
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.IncomeMapper;
|
||||||
import net.miarma.backend.huertos.mapper.view.VIncomesWithFullNamesMapper;
|
import net.miarma.backend.huertos.mapper.view.VIncomesWithFullNamesMapper;
|
||||||
import net.miarma.backend.huertos.model.Income;
|
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}")
|
@GetMapping("/{income_id}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<IncomeDto.Response> getById(@PathVariable("income_id") UUID incomeId) {
|
public ResponseEntity<IncomeDto.Response> getById(@PathVariable("income_id") UUID incomeId) {
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
package net.miarma.backend.huertos.controller;
|
package net.miarma.backend.huertos.controller;
|
||||||
|
|
||||||
import net.miarma.backend.huertos.dto.MemberDto;
|
import net.miarma.backend.huertos.dto.*;
|
||||||
import net.miarma.backend.huertos.dto.WaitlistCensoredDto;
|
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.security.HuertosPrincipal;
|
||||||
|
import net.miarma.backend.huertos.service.IncomeService;
|
||||||
import net.miarma.backend.huertos.service.MemberService;
|
import net.miarma.backend.huertos.service.MemberService;
|
||||||
|
import net.miarma.backend.huertos.service.RequestService;
|
||||||
import net.miarma.backlib.security.JwtService;
|
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.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -17,106 +23,130 @@ import java.util.UUID;
|
|||||||
public class MemberController {
|
public class MemberController {
|
||||||
|
|
||||||
private final MemberService memberService;
|
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;
|
this.memberService = memberService;
|
||||||
}
|
this.requestService = requestService;
|
||||||
|
this.incomeService = incomeService;
|
||||||
private Byte getServiceIdFromToken() {
|
this.jwtService = jwtService;
|
||||||
var auth = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
if (auth == null || !(auth.getPrincipal() instanceof HuertosPrincipal principal)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return principal.getServiceId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public List<MemberDto> getAll() {
|
public ResponseEntity<List<MemberDto>> getAll() {
|
||||||
return memberService.getAll(getServiceIdFromToken());
|
return ResponseEntity.ok(memberService.getAll((byte)1));
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{user_id}")
|
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
|
||||||
public MemberDto getById(@PathVariable("user_id") UUID userId) {
|
|
||||||
return memberService.getById(userId, getServiceIdFromToken());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
public MemberDto getMe() {
|
public ResponseEntity<MemberProfileDto> getMe() {
|
||||||
HuertosPrincipal principal =
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
(HuertosPrincipal) SecurityContextHolder
|
|
||||||
.getContext()
|
|
||||||
.getAuthentication()
|
|
||||||
.getPrincipal();
|
|
||||||
|
|
||||||
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")
|
@GetMapping("/latest-number")
|
||||||
public Integer getLatestNumber() {
|
public ResponseEntity<Integer> getLatestNumber() {
|
||||||
return memberService.getLatestMemberNumber();
|
return ResponseEntity.ok(memberService.getLatestMemberNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/waitlist")
|
@GetMapping("/waitlist")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public List<MemberDto> getWaitlist() {
|
public ResponseEntity<List<MemberDto>> getWaitlist() {
|
||||||
return memberService.getWaitlist();
|
return ResponseEntity.ok(memberService.getWaitlist());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/waitlist/limited")
|
@GetMapping("/waitlist/limited")
|
||||||
public List<WaitlistCensoredDto> getWaitlistLimited() {
|
public ResponseEntity<List<WaitlistCensoredDto>> getWaitlistLimited() {
|
||||||
return memberService.getWaitlistLimited();
|
return ResponseEntity.ok(memberService.getWaitlistLimited());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}")
|
@GetMapping("/number/{member_number}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public MemberDto getByMemberNumber(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<MemberDto> getByMemberNumber(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.getByMemberNumber(memberNumber);
|
return ResponseEntity.ok(memberService.getByMemberNumber(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 Boolean getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<List<IncomeDto.Response>> getMemberIncomes(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasIncomes(memberNumber);
|
return ResponseEntity.ok(memberService.getIncomes(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}/has-paid")
|
@GetMapping("/number/{member_number}/has-paid")
|
||||||
public Boolean getMemberHasPaid(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<Boolean> getMemberHasPaid(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasPaid(memberNumber);
|
return ResponseEntity.ok(memberService.hasPaid(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}/has-collaborator")
|
@GetMapping("/number/{member_number}/has-collaborator")
|
||||||
public Boolean getMemberHasCollaborator(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<Boolean> getMemberHasCollaborator(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasCollaborator(memberNumber);
|
return ResponseEntity.ok(memberService.hasCollaborator(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}/has-greenhouse")
|
@GetMapping("/number/{member_number}/has-greenhouse")
|
||||||
public Boolean getMemberHasGreenhouse(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<Boolean> getMemberHasGreenhouse(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasGreenhouse(memberNumber);
|
return ResponseEntity.ok(memberService.hasGreenhouse(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}/has-collaborator-request")
|
@GetMapping("/number/{member_number}/has-collaborator-request")
|
||||||
public Boolean getMemberHasCollaboratorRequest(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<Boolean> getMemberHasCollaboratorRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasCollaboratorRequest(memberNumber);
|
return ResponseEntity.ok(memberService.hasCollaboratorRequest(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/number/{member_number}/has-greenhouse-request")
|
@GetMapping("/number/{member_number}/has-greenhouse-request")
|
||||||
public Boolean getMemberHasGreenhouseRequest(@PathVariable("member_number") Integer memberNumber) {
|
public ResponseEntity<Boolean> getMemberHasGreenhouseRequest(@PathVariable("member_number") Integer memberNumber) {
|
||||||
return memberService.hasGreenhouseRequest(memberNumber);
|
return ResponseEntity.ok(memberService.hasGreenhouseRequest(memberNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/plot/{plot_number}")
|
@GetMapping("/plot/{plot_number}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public MemberDto getByPlotNumber(@PathVariable("plot_number") Integer plotNumber) {
|
public ResponseEntity<MemberDto> getByPlotNumber(@PathVariable("plot_number") Integer plotNumber) {
|
||||||
return memberService.getByPlotNumber(plotNumber);
|
return ResponseEntity.ok(memberService.getByPlotNumber(plotNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/dni/{dni}")
|
@GetMapping("/dni/{dni}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public MemberDto getByDni(@PathVariable("dni") String dni) {
|
public ResponseEntity<MemberDto> getByDni(@PathVariable("dni") String dni) {
|
||||||
return memberService.getByDni(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.mapper.PreUserMapper;
|
||||||
import net.miarma.backend.huertos.model.PreUser;
|
import net.miarma.backend.huertos.model.PreUser;
|
||||||
import net.miarma.backend.huertos.service.PreUserService;
|
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.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -13,7 +15,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/pre_users")
|
@RequestMapping("/pre-users")
|
||||||
public class PreUserController {
|
public class PreUserController {
|
||||||
|
|
||||||
private final PreUserService preUserService;
|
private final PreUserService preUserService;
|
||||||
@@ -40,6 +42,14 @@ public class PreUserController {
|
|||||||
return ResponseEntity.ok(PreUserMapper.toResponse(preUser));
|
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}")
|
@PutMapping("/{pre_user_id}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<PreUserDto.Response> update(
|
public ResponseEntity<PreUserDto.Response> update(
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
package net.miarma.backend.huertos.controller;
|
package net.miarma.backend.huertos.controller;
|
||||||
|
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import net.miarma.backend.huertos.dto.CreateWaitlistDto;
|
import net.miarma.backend.huertos.dto.*;
|
||||||
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.view.VRequestsWithPreUsersDto;
|
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.RequestMapper;
|
||||||
import net.miarma.backend.huertos.mapper.view.VIncomesWithFullNamesMapper;
|
|
||||||
import net.miarma.backend.huertos.mapper.view.VRequestsWithPreUsersMapper;
|
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.Request;
|
||||||
import net.miarma.backend.huertos.model.view.VRequestsWithPreUsers;
|
import net.miarma.backend.huertos.model.view.VRequestsWithPreUsers;
|
||||||
import net.miarma.backend.huertos.service.PreUserService;
|
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")
|
@GetMapping("/count")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<RequestCountDto> getRequestCount() {
|
public ResponseEntity<RequestCountDto> getRequestCount() {
|
||||||
@@ -119,14 +130,6 @@ public class RequestController {
|
|||||||
return ResponseEntity.ok(RequestMapper.toResponse(request));
|
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}")
|
@PutMapping("/{request_id}")
|
||||||
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
@PreAuthorize("hasAnyRole('HUERTOS_ROLE_ADMIN', 'HUERTOS_ROLE_DEV')")
|
||||||
public ResponseEntity<RequestDto.Response> update(
|
public ResponseEntity<RequestDto.Response> update(
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public class AnnouncementDto {
|
|||||||
private String body;
|
private String body;
|
||||||
private Byte priority;
|
private Byte priority;
|
||||||
private UUID publishedBy;
|
private UUID publishedBy;
|
||||||
|
private String publishedByName;
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
public UUID getAnnounceId() {
|
public UUID getAnnounceId() {
|
||||||
@@ -73,6 +74,10 @@ public class AnnouncementDto {
|
|||||||
this.publishedBy = publishedBy;
|
this.publishedBy = publishedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPublishedByName() { return publishedByName; }
|
||||||
|
|
||||||
|
public void setPublishedByName(String publishedByName) { this.publishedByName = publishedByName; }
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
public Instant getCreatedAt() {
|
||||||
return createdAt;
|
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;
|
package net.miarma.backend.huertos.dto;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -33,15 +35,15 @@ public class RequestDto {
|
|||||||
this.requestedBy = requestedBy;
|
this.requestedBy = requestedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTargetUserId() {
|
public @Nullable UUID getTargetUserId() {
|
||||||
return targetUserId;
|
return targetUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTargetUserId(UUID targetUserId) {
|
public void setTargetUserId(@Nullable UUID targetUserId) {
|
||||||
this.targetUserId = targetUserId;
|
this.targetUserId = targetUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UUID targetUserId;
|
@Nullable private UUID targetUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class AnnouncementMapper {
|
|||||||
dto.setBody(entity.getBody());
|
dto.setBody(entity.getBody());
|
||||||
dto.setPriority(entity.getPriority());
|
dto.setPriority(entity.getPriority());
|
||||||
dto.setPublishedBy(entity.getPublishedBy());
|
dto.setPublishedBy(entity.getPublishedBy());
|
||||||
|
dto.setPublishedByName(entity.getPublishedByName());
|
||||||
dto.setCreatedAt(entity.getCreatedAt());
|
dto.setCreatedAt(entity.getCreatedAt());
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ public class Announcement {
|
|||||||
private Byte priority;
|
private Byte priority;
|
||||||
|
|
||||||
@Column(name = "published_by", columnDefinition = "BINARY(16)", nullable = false)
|
@Column(name = "published_by", columnDefinition = "BINARY(16)", nullable = false)
|
||||||
|
private byte[] publishedByBin;
|
||||||
|
|
||||||
|
@Transient
|
||||||
private UUID publishedBy;
|
private UUID publishedBy;
|
||||||
|
|
||||||
|
@Column(name = "published_by_name", nullable = false)
|
||||||
|
private String publishedByName;
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
@@ -35,6 +41,10 @@ public class Announcement {
|
|||||||
if (announceId != null) {
|
if (announceId != null) {
|
||||||
announceIdBin = UuidUtil.uuidToBin(announceId);
|
announceIdBin = UuidUtil.uuidToBin(announceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (publishedBy != null) {
|
||||||
|
publishedByBin = UuidUtil.uuidToBin(publishedBy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostLoad
|
@PostLoad
|
||||||
@@ -42,6 +52,10 @@ public class Announcement {
|
|||||||
if (announceIdBin != null) {
|
if (announceIdBin != null) {
|
||||||
announceId = UuidUtil.binToUUID(announceIdBin);
|
announceId = UuidUtil.binToUUID(announceIdBin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (publishedByBin != null) {
|
||||||
|
publishedBy = UuidUtil.binToUUID(publishedByBin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getAnnounceId() {
|
public UUID getAnnounceId() {
|
||||||
@@ -76,6 +90,14 @@ public class Announcement {
|
|||||||
this.publishedBy = publishedBy;
|
this.publishedBy = publishedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPublishedByName() {
|
||||||
|
return publishedByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPublishedByName(String publishedByName) {
|
||||||
|
this.publishedByName = publishedByName;
|
||||||
|
}
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
public Instant getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,7 @@ import net.miarma.backend.huertos.model.PreUser;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface PreUserRepository extends JpaRepository<PreUser, byte[]> {
|
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 {
|
public class AnnouncementService {
|
||||||
|
|
||||||
private final AnnouncementRepository announcementRepository;
|
private final AnnouncementRepository announcementRepository;
|
||||||
|
private final MemberService memberService;
|
||||||
|
|
||||||
public AnnouncementService(AnnouncementRepository announcementRepository) {
|
public AnnouncementService(AnnouncementRepository announcementRepository, MemberService memberService) {
|
||||||
this.announcementRepository = announcementRepository;
|
this.announcementRepository = announcementRepository;
|
||||||
|
this.memberService = memberService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Announcement> getAll() {
|
public List<Announcement> getAll() {
|
||||||
@@ -36,6 +38,7 @@ public class AnnouncementService {
|
|||||||
if (announcement.getAnnounceId() == null) {
|
if (announcement.getAnnounceId() == null) {
|
||||||
announcement.setAnnounceId(UUID.randomUUID());
|
announcement.setAnnounceId(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
announcement.setPublishedByName(memberService.getById(announcement.getPublishedBy()).user().getDisplayName());
|
||||||
announcement.setCreatedAt(Instant.now());
|
announcement.setCreatedAt(Instant.now());
|
||||||
return announcementRepository.save(announcement);
|
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) {
|
public Expense create(Expense expense) {
|
||||||
if (expense.getConcept() == null || expense.getConcept().isBlank()) {
|
if (expense.getConcept() == null || expense.getConcept().isBlank()) {
|
||||||
throw new ValidationException("Concept is required");
|
throw new ValidationException("concept", "Concept is required");
|
||||||
}
|
}
|
||||||
if (expense.getAmount() == null) {
|
if (expense.getAmount() == null) {
|
||||||
throw new ValidationException("Amount is required");
|
throw new ValidationException("amount", "Amount is required");
|
||||||
}
|
}
|
||||||
if (expense.getSupplier() == null || expense.getSupplier().isBlank()) {
|
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()) {
|
if (expense.getInvoice() == null || expense.getInvoice().isBlank()) {
|
||||||
throw new ValidationException("Invoice is required");
|
throw new ValidationException("invoice", "Invoice is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
expense.setExpenseId(UUID.randomUUID());
|
expense.setExpenseId(UUID.randomUUID());
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class IncomeService {
|
|||||||
throw new BadRequestException("concept is required");
|
throw new BadRequestException("concept is required");
|
||||||
}
|
}
|
||||||
if (income.getAmount() == null || income.getAmount().signum() <= 0) {
|
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());
|
income.setIncomeId(UUID.randomUUID());
|
||||||
@@ -72,7 +72,7 @@ public class IncomeService {
|
|||||||
if (dto.getConcept() != null) income.setConcept(dto.getConcept());
|
if (dto.getConcept() != null) income.setConcept(dto.getConcept());
|
||||||
if (dto.getAmount() != null) {
|
if (dto.getAmount() != null) {
|
||||||
if (dto.getAmount().signum() <= 0) {
|
if (dto.getAmount().signum() <= 0) {
|
||||||
throw new ValidationException("amount must be positive");
|
throw new ValidationException("amount", "amount must be positive");
|
||||||
}
|
}
|
||||||
income.setAmount(dto.getAmount());
|
income.setAmount(dto.getAmount());
|
||||||
}
|
}
|
||||||
@@ -106,4 +106,9 @@ public class IncomeService {
|
|||||||
List<Income> incomes = getByUserId(userId);
|
List<Income> incomes = getByUserId(userId);
|
||||||
return !incomes.isEmpty() && incomes.stream().allMatch(Income::isPaid);
|
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;
|
package net.miarma.backend.huertos.service;
|
||||||
|
|
||||||
import net.miarma.backend.huertos.client.HuertosWebClient;
|
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.MemberDto;
|
||||||
import net.miarma.backend.huertos.dto.WaitlistCensoredDto;
|
import net.miarma.backend.huertos.dto.WaitlistCensoredDto;
|
||||||
import net.miarma.backend.huertos.mapper.HuertosUserMetadataMapper;
|
import net.miarma.backend.huertos.mapper.HuertosUserMetadataMapper;
|
||||||
|
import net.miarma.backend.huertos.mapper.IncomeMapper;
|
||||||
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;
|
||||||
@@ -31,12 +33,22 @@ public class MemberService {
|
|||||||
this.metadataService = metadataService;
|
this.metadataService = metadataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemberDto getById(UUID userId, Byte serviceId) {
|
public MemberDto getById(UUID userId) {
|
||||||
var uwc = huertosWebClient.getUserWithCredential(userId, serviceId);
|
var uwc = huertosWebClient.getUserWithCredential(userId, (byte)1);
|
||||||
var meta = metadataService.getById(userId);
|
if (uwc == null) {
|
||||||
|
throw new NotFoundException("User not found in core");
|
||||||
|
}
|
||||||
|
|
||||||
return new MemberDto(uwc.user(), uwc.account(),
|
var meta = metadataService.getById(userId);
|
||||||
HuertosUserMetadataMapper.toDto(meta));
|
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) {
|
public List<MemberDto> getAll(Byte serviceId) {
|
||||||
@@ -106,8 +118,10 @@ public class MemberService {
|
|||||||
.orElseThrow(() -> new NotFoundException("Member not found"));
|
.orElseThrow(() -> new NotFoundException("Member not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasIncomes(Integer memberNumber) {
|
public List<IncomeDto.Response> getIncomes(Integer memberNumber) {
|
||||||
return incomeService.existsByMemberNumber(memberNumber);
|
return incomeService.getByMemberNumber(memberNumber).stream()
|
||||||
|
.map(IncomeMapper::toResponse)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasPaid(Integer memberNumber) {
|
public Boolean hasPaid(Integer memberNumber) {
|
||||||
@@ -132,11 +146,11 @@ public class MemberService {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return plotMembers.stream()
|
return plotMembers.stream()
|
||||||
.anyMatch(dto -> dto.metadata().getType().equals((byte)2));
|
.anyMatch(dto -> dto.metadata().getType().equals((byte)3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasGreenhouse(Integer memberNumber) {
|
public Boolean hasGreenhouse(Integer memberNumber) {
|
||||||
return metadataService.existsByMemberNumber(memberNumber);
|
return metadataService.getByMemberNumber(memberNumber).getType().equals((byte)2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean hasCollaboratorRequest(Integer memberNumber) {
|
public Boolean hasCollaboratorRequest(Integer memberNumber) {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package net.miarma.backend.huertos.service;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import net.miarma.backend.huertos.dto.PreUserDto;
|
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.BadRequestException;
|
||||||
import net.miarma.backlib.exception.NotFoundException;
|
import net.miarma.backlib.exception.NotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -100,4 +102,18 @@ public class PreUserService {
|
|||||||
|
|
||||||
repository.deleteById(idBytes);
|
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.dto.RequestDto;
|
||||||
import net.miarma.backend.huertos.mapper.PreUserMapper;
|
import net.miarma.backend.huertos.mapper.PreUserMapper;
|
||||||
import net.miarma.backend.huertos.mapper.RequestMapper;
|
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.model.PreUser;
|
||||||
import net.miarma.backend.huertos.repository.PreUserRepository;
|
import net.miarma.backend.huertos.repository.PreUserRepository;
|
||||||
import net.miarma.backlib.exception.BadRequestException;
|
import net.miarma.backlib.exception.BadRequestException;
|
||||||
@@ -64,7 +63,7 @@ public class RequestService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request create(Request request) {
|
public Request createWaitlist(Request request) {
|
||||||
if (request.getType() == null) {
|
if (request.getType() == null) {
|
||||||
throw new BadRequestException("type is required");
|
throw new BadRequestException("type is required");
|
||||||
}
|
}
|
||||||
@@ -82,7 +81,7 @@ public class RequestService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public RequestDto.Response create(RequestDto.Request requestDto,
|
public RequestDto.Response createWaitlist(RequestDto.Request requestDto,
|
||||||
PreUserDto.Request preUserDto) {
|
PreUserDto.Request preUserDto) {
|
||||||
PreUser preUser = preUserRepository.save(PreUserMapper.toEntity(preUserDto));
|
PreUser preUser = preUserRepository.save(PreUserMapper.toEntity(preUserDto));
|
||||||
Request request = requestRepository.save(RequestMapper.toEntity(requestDto));
|
Request request = requestRepository.save(RequestMapper.toEntity(requestDto));
|
||||||
|
|||||||
@@ -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