Fix: services and controllers argument type discordance. Add: totally revamped request system, easier to manager than older pre-user based one. Remove: old views no longer necessary to have.

This commit is contained in:
Jose
2026-01-29 10:58:55 +01:00
parent 2627267391
commit a46ab8635c
69 changed files with 1124 additions and 2403 deletions

View File

@@ -58,7 +58,9 @@ public class CredentialController {
@RequestBody CredentialDto dto
) {
dto.setCredentialId(credentialId);
return ResponseEntity.ok(credentialService.update(credentialId, dto));
return ResponseEntity.ok(
credentialService.update(
credentialId, CredentialMapper.toEntity(dto)));
}
@DeleteMapping("/{credential_id}")

View File

@@ -54,27 +54,17 @@ public class FileController {
@PostMapping
@PreAuthorize("hasRole('ADMIN') or #uploadedBy == authentication.principal.userId")
public ResponseEntity<FileDto.Response> create(
@RequestParam String fileName,
@RequestParam String mimeType,
@RequestParam UUID uploadedBy,
@RequestParam Byte context,
@RequestBody FileDto.Request dto,
@RequestPart("file") MultipartFile file
) throws IOException {
FileDto.Request dto = new FileDto.Request();
dto.setFileName(fileName);
dto.setMimeType(mimeType);
dto.setUploadedBy(uploadedBy);
dto.setContext(context);
File created = fileService.create(dto, file.getBytes());
File created = fileService.create(FileMapper.toEntity(dto), file.getBytes());
return ResponseEntity.status(HttpStatus.CREATED).body(FileMapper.toResponse(created));
}
@PutMapping("/{fileId}")
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
public ResponseEntity<File> update(@PathVariable("fileId") UUID fileId, @RequestBody File file) {
file.setFileId(fileId);
File updated = fileService.update(file);
public ResponseEntity<File> update(@PathVariable("fileId") UUID fileId, @RequestBody FileDto.Request request) {
File updated = fileService.update(fileId, FileMapper.toEntity(request));
return ResponseEntity.ok(updated);
}

View File

@@ -44,9 +44,11 @@ public class UserController {
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<UserDto> create(@RequestBody UserDto dto) {
public ResponseEntity<UserDto> create(@RequestBody CreateUserDto dto) {
return ResponseEntity.ok(
UserMapper.toDto(userService.create(dto))
UserMapper.toDto(
userService.create(
UserMapper.fromCreateDto(dto)))
);
}
@@ -89,13 +91,17 @@ public class UserController {
)
);
}
@PutMapping("/{user_id}")
@PreAuthorize("hasRole('ADMIN') or #userId == principal.userId")
public ResponseEntity<UserDto> update(@PathVariable("user_id") UUID userId, @RequestBody UserDto dto) {
return ResponseEntity.ok(UserMapper.toDto(userService.update(userId, dto)));
}
public ResponseEntity<UserDto> update(
@PathVariable("user_id") UUID userId,
@RequestBody UserDto dto
) {
User updated = userService.update(userId, UserMapper.fromDto(dto));
return ResponseEntity.ok(UserMapper.toDto(updated));
}
@GetMapping("/{user_id}/avatar")
public ResponseEntity<String> getAvatar(@PathVariable("user_id") UUID userId) {
return ResponseEntity.ok(userService.getById(userId).getAvatar());

View File

@@ -1,11 +1,35 @@
package net.miarma.backend.core.mapper;
import net.miarma.backend.core.model.User;
import net.miarma.backlib.dto.CreateUserDto;
import net.miarma.backlib.dto.CredentialDto;
import net.miarma.backlib.dto.UserDto;
import net.miarma.backlib.dto.UserWithCredentialDto;
import java.util.UUID;
public class UserMapper {
public static User fromDto(UserDto dto) {
if (dto == null) return null;
User user = new User();
user.setDisplayName(dto.getDisplayName());
user.setAvatar(dto.getAvatar());
user.setGlobalRole(dto.getGlobalRole());
user.setGlobalStatus(dto.getGlobalStatus());
return user;
}
public static User fromCreateDto(CreateUserDto dto) {
User user = new User();
user.setUserId(UUID.randomUUID());
user.setDisplayName(dto.displayName());
user.setAvatar(dto.avatar() != null ? dto.avatar() : null);
user.setGlobalRole((byte)0);
user.setGlobalStatus((byte)1);
return user;
}
public static UserDto toDto(User u) {
if (u == null) return null;

View File

@@ -2,6 +2,7 @@ package net.miarma.backend.core.service;
import java.util.UUID;
import net.miarma.backlib.dto.*;
import net.miarma.backlib.exception.ConflictException;
import net.miarma.backlib.exception.ForbiddenException;
import net.miarma.backlib.exception.UnauthorizedException;
@@ -12,11 +13,6 @@ import net.miarma.backend.core.mapper.CredentialMapper;
import net.miarma.backend.core.mapper.UserMapper;
import net.miarma.backend.core.model.Credential;
import net.miarma.backend.core.model.User;
import net.miarma.backlib.dto.CredentialDto;
import net.miarma.backlib.dto.LoginRequest;
import net.miarma.backlib.dto.LoginResponse;
import net.miarma.backlib.dto.RegisterRequest;
import net.miarma.backlib.dto.UserDto;
import tools.jackson.databind.JsonNode;
@Service
@@ -39,11 +35,11 @@ public class AuthService {
Credential cred = credentialService.getForLogin(request.serviceId(), request.username());
if (!passwordEncoder.matches(request.password(), cred.getPassword())) {
throw new UnauthorizedException("Invalid credentials");
throw new UnauthorizedException("Credenciales no válidas");
}
if (cred.getStatus() == 0) {
throw new ForbiddenException("This account is inactive");
throw new ForbiddenException("Esa cuenta está desactivada");
}
String token = jwtService.generateToken(cred.getUserId(), request.serviceId());
@@ -55,17 +51,15 @@ public class AuthService {
public LoginResponse register(RegisterRequest request) {
if (credentialService.existsByUsernameAndService(request.username(), request.serviceId())) {
throw new ConflictException("Username already taken");
throw new ConflictException("Ese usuario ya existe");
}
User user;
try {
user = credentialService.getByEmail(request.email());
} catch (Exception e) {
UserDto dto = new UserDto();
dto.setUserId(UUID.randomUUID());
dto.setDisplayName(request.displayName());
user = userService.create(dto);
CreateUserDto dto = new CreateUserDto(request.displayName(), null);
user = userService.create(UserMapper.fromCreateDto(dto));
}
Credential cred = new Credential();

View File

@@ -33,30 +33,30 @@ public class CredentialService {
public Credential getById(UUID credentialId) {
byte[] idBytes = UuidUtil.uuidToBin(credentialId);
return credentialRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("Credential not found"));
.orElseThrow(() -> new NotFoundException("Cuenta no encontrada"));
}
public Credential create(Credential credential) {
if (credential.getUsername() == null || credential.getUsername().isBlank()) {
throw new ValidationException("userName", "Username cannot be blank");
throw new ValidationException("userName", "El usuario no puede estar vacío");
}
if (credential.getEmail() == null || !credential.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
throw new ValidationException("email", "Invalid email format");
throw new ValidationException("email", "Formato de email no válido");
}
if (credential.getPassword() == null || credential.getPassword().length() < 6) {
throw new ValidationException("password", "Password must be at least 6 characters");
throw new ValidationException("password", "La contraseña tiene que tener al menos 6 caracteres");
}
if (credential.getServiceId() == null || credential.getServiceId() < 0) {
throw new ValidationException("serviceId", "ServiceId must be positive");
throw new ValidationException("serviceId", "El identificador de servicio debe ser positivo");
}
boolean existsUsername = credentialRepository.existsByUsernameAndServiceId(
credential.getUsername(), credential.getServiceId());
if (existsUsername) throw new ConflictException("Username already exists for this service");
if (existsUsername) throw new ConflictException("El usuario ya existe para este servicio");
boolean existsEmail = credentialRepository.existsByEmailAndServiceId(
credential.getEmail(), credential.getServiceId());
if (existsEmail) throw new ConflictException("Email already exists for this service");
if (existsEmail) throw new ConflictException("El email ya existe para este servicio");
credential.setCredentialId(UUID.randomUUID());
credential.setPassword(passwordEncoder.encode(credential.getPassword()));
@@ -78,25 +78,25 @@ public class CredentialService {
public List<Credential> getByUserId(UUID userId) {
List<Credential> creds = credentialRepository.findByUserId(UuidUtil.uuidToBin(userId));
if (creds.isEmpty()) {
throw new NotFoundException("User has no credentials");
throw new NotFoundException("El usuario no tiene cuenta");
}
return creds;
}
public User getByEmail(String email) {
return credentialRepository.findByEmail(email)
.orElseThrow(() -> new NotFoundException("No credential found for email"))
.orElseThrow(() -> new NotFoundException("No hay cuenta asociada a ese email"))
.getUser();
}
public Credential getByUserIdAndService(UUID userId, Byte serviceId) {
return credentialRepository.findByUserIdAndServiceId(UuidUtil.uuidToBin(userId), serviceId)
.orElseThrow(() -> new NotFoundException("Credential not found in this site"));
.orElseThrow(() -> new NotFoundException("El usuario no tiene cuenta en este sitio"));
}
public Credential getForLogin(Byte serviceId, String username) {
return credentialRepository.findByServiceIdAndUsername(serviceId, username)
.orElseThrow(() -> new BadRequestException("Invalid credentials"));
.orElseThrow(() -> new BadRequestException("Credenciales no válidas"));
}
public boolean existsByUsernameAndService(String username, int serviceId) {
@@ -106,30 +106,30 @@ public class CredentialService {
public boolean isOwner(UUID credentialId, UUID userId) {
byte[] idBytes = UuidUtil.uuidToBin(credentialId);
Credential c = credentialRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("Credential not found"));
.orElseThrow(() -> new NotFoundException("Cuenta no encontrada"));
return c.getUserId().equals(userId);
}
public Credential update(UUID credentialId, CredentialDto dto) {
public Credential update(UUID credentialId, Credential changes) {
byte[] idBytes = UuidUtil.uuidToBin(credentialId);
Credential cred = credentialRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("Credential not found"));
.orElseThrow(() -> new NotFoundException("Cuenta no encontrada"));
if (dto.getUsername() != null && dto.getUsername().isBlank()) {
throw new ValidationException("userName", "Username cannot be blank");
if (changes.getUsername() != null && changes.getUsername().isBlank()) {
throw new ValidationException("userName", "El usuario no puede estar vacío");
}
if (dto.getEmail() != null && !dto.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
throw new ValidationException("email", "Invalid email format");
if (changes.getEmail() != null && !changes.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
throw new ValidationException("email", "Formato de email no válido");
}
if (dto.getServiceId() != null && dto.getServiceId() < 0) {
throw new ValidationException("serviceId", "ServiceId must be positive");
if (changes.getServiceId() != null && changes.getServiceId() < 0) {
throw new ValidationException("serviceId", "El identificador de servicio debe ser positivo");
}
if (dto.getUsername() != null) cred.setUsername(dto.getUsername());
if (dto.getEmail() != null) cred.setEmail(dto.getEmail());
if (dto.getServiceId() != null) cred.setServiceId(dto.getServiceId());
if (dto.getStatus() != null) cred.setStatus(dto.getStatus());
if (changes.getUsername() != null) cred.setUsername(changes.getUsername());
if (changes.getEmail() != null) cred.setEmail(changes.getEmail());
if (changes.getServiceId() != null) cred.setServiceId(changes.getServiceId());
if (changes.getStatus() != null) cred.setStatus(changes.getStatus());
return credentialRepository.save(cred);
}
@@ -138,10 +138,10 @@ public class CredentialService {
byte[] idBytes = UuidUtil.uuidToBin(credentialId);
Credential cred = credentialRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("Credential not found"));
.orElseThrow(() -> new NotFoundException("Cuenta no encontrada"));
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
throw new ValidationException("oldPassword", "Old password is incorrect");
throw new ValidationException("oldPassword", "La contraseña actual es incorrecta");
}
cred.setPassword(passwordEncoder.encode(request.newPassword()));
@@ -151,19 +151,19 @@ public class CredentialService {
public void delete(UUID credentialId) {
byte[] idBytes = UuidUtil.uuidToBin(credentialId);
if(!credentialRepository.existsById(idBytes))
throw new NotFoundException("Credential not found");
throw new NotFoundException("Cuenta no encontrada");
credentialRepository.deleteById(idBytes);
}
public Byte getStatus(UUID credentialId) {
Credential credential = credentialRepository.findById(UuidUtil.uuidToBin(credentialId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
return credential.getStatus();
}
public void updateStatus(UUID credentialId, Byte status) {
Credential credential = credentialRepository.findById(UuidUtil.uuidToBin(credentialId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
credential.setStatus(status);
credentialRepository.save(credential);
}

View File

@@ -36,7 +36,7 @@ public class FileService {
public File getById(UUID fileId) {
byte[] idBytes = UuidUtil.uuidToBin(fileId);
return fileRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("File not found"));
.orElseThrow(() -> new NotFoundException("Archivo no encontrado"));
}
public List<File> getAll() {
@@ -47,26 +47,26 @@ public class FileService {
return fileRepository.findByUploadedBy(userId);
}
public File create(FileDto.Request dto, byte[] fileBinary) throws IOException {
Path dirPath = Paths.get(filesDir, String.valueOf(dto.getContext()));
public File create(File file, byte[] fileBinary) throws IOException {
Path dirPath = Paths.get(filesDir, String.valueOf(file.getContext()));
if (!Files.exists(dirPath)) {
Files.createDirectories(dirPath);
}
Path filePath = dirPath.resolve(dto.getFileName());
Path filePath = dirPath.resolve(file.getFileName());
try (FileOutputStream fos = new FileOutputStream(filePath.toFile())) {
fos.write(fileBinary);
}
dto.setFilePath(filePath.toString());
file.setFilePath(filePath.toString());
return fileRepository.save(FileMapper.toEntity(dto));
return fileRepository.save(file);
}
public File update(File file) {
byte[] idBytes = UuidUtil.uuidToBin(file.getFileId());
public File update(UUID fileId, File file) {
byte[] idBytes = UuidUtil.uuidToBin(fileId);
if (!fileRepository.existsById(idBytes)) {
throw new NotFoundException("File not found");
throw new NotFoundException("Archivo no encontrado");
}
return fileRepository.save(file);
}
@@ -74,7 +74,7 @@ public class FileService {
public void delete(UUID fileId) {
byte[] idBytes = UuidUtil.uuidToBin(fileId);
if (!fileRepository.existsById(idBytes)) {
throw new NotFoundException("File not found");
throw new NotFoundException("Archivo no encontrado");
}
fileRepository.deleteById(idBytes);
}

View File

@@ -31,58 +31,49 @@ public class UserService {
public User getById(UUID userId) {
byte[] idBytes = UuidUtil.uuidToBin(userId);
return userRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("User not found"));
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));
}
public User create(UserDto dto) {
if(dto.getDisplayName() == null || dto.getDisplayName().isBlank()) {
throw new ValidationException("displayName", "Display name is required");
public User create(User user) {
if(user.getDisplayName() == null || user.getDisplayName().isBlank()) {
throw new ValidationException("displayName", "El nombre a mostrar es necesario");
}
return userRepository.save(user);
}
public User update(UUID userId, User changes) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));
if (changes.getDisplayName() != null) {
String dn = changes.getDisplayName().trim();
if (dn.isEmpty()) throw new ValidationException("displayName", "No puede estar vacío");
if (dn.length() > 50) throw new ValidationException("displayName", "Máx 50 caracteres");
user.setDisplayName(dn);
}
User user = new User();
user.setUserId(UUID.randomUUID());
user.setDisplayName(dto.getDisplayName());
user.setAvatar(dto.getAvatar());
user.setGlobalRole(dto.getGlobalRole() != null ? dto.getGlobalRole() : 0);
user.setGlobalStatus(dto.getGlobalStatus() != null ? dto.getGlobalStatus() : 1);
if (changes.getAvatar() != null)
user.setAvatar(changes.getAvatar());
if (changes.getGlobalRole() != null)
user.setGlobalRole(changes.getGlobalRole());
if (changes.getGlobalStatus() != null)
user.setGlobalStatus(changes.getGlobalStatus());
return userRepository.save(user);
}
public User update(UUID userId, UserDto dto) {
byte[] idBytes = UuidUtil.uuidToBin(userId);
User user = userRepository.findById(idBytes)
.orElseThrow(() -> new NotFoundException("User not found"));
if (dto.getDisplayName() != null) {
String displayName = dto.getDisplayName().trim();
if (displayName.isEmpty()) {
throw new IllegalArgumentException("Display name cannot be empty");
}
if (displayName.length() > 50) {
throw new IllegalArgumentException("Display name too long (max 50 chars)");
}
user.setDisplayName(displayName);
}
if(dto.getDisplayName() != null) user.setDisplayName(dto.getDisplayName());
if(dto.getAvatar() != null) user.setAvatar(dto.getAvatar());
if(dto.getGlobalRole() != null) user.setGlobalRole(dto.getGlobalRole());
if(dto.getGlobalStatus() != null) user.setGlobalStatus(dto.getGlobalStatus());
return userRepository.save(user);
}
public void delete(UUID userId) {
public void delete(UUID userId) {
byte[] idBytes = UuidUtil.uuidToBin(userId);
if(!userRepository.existsById(idBytes))
throw new NotFoundException("User not found");
throw new NotFoundException("Usuario no encontrado");
userRepository.deleteById(idBytes);
}
public UserDto updateAvatar(UUID userId, ChangeAvatarRequest req) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("User not found"));
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));
user.setAvatar(req.avatar());
userRepository.save(user);
return UserMapper.toDto(user);
@@ -90,26 +81,26 @@ public class UserService {
public Byte getStatus(UUID userId) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
return user.getGlobalStatus();
}
public void updateStatus(UUID userId, Byte status) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
user.setGlobalStatus(status);
userRepository.save(user);
}
public Byte getRole(UUID userId) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
return user.getGlobalRole();
}
public void updateRole(UUID userId, Byte role) {
User user = userRepository.findById(UuidUtil.uuidToBin(userId))
.orElseThrow(() -> new NotFoundException("User not found"));;
.orElseThrow(() -> new NotFoundException("Usuario no encontrado"));;
user.setGlobalRole(role);
userRepository.save(user);
}