Commit ab607cc1 by Rubén Ramírez

fix: [Recursos]: Actualizada la manera de trabajar con las fotos para…

fix: [Recursos]: Actualizada la manera de trabajar con las fotos para almacenarlas también en la BBDD
parent 3a98e108
...@@ -6,7 +6,6 @@ import jakarta.persistence.EntityManager; ...@@ -6,7 +6,6 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
...@@ -34,7 +33,6 @@ public class RepositorioRecurso { ...@@ -34,7 +33,6 @@ public class RepositorioRecurso {
.getResultList(); .getResultList();
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarPorAutor(String autor) { public List<Recurso> buscarPorAutor(String autor) {
return em.createQuery( return em.createQuery(
......
package com.ujaen.tfg.mangaffinity.rest; package com.ujaen.tfg.mangaffinity.rest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ujaen.tfg.mangaffinity.entidades.BibliotecaPersonal; import com.ujaen.tfg.mangaffinity.entidades.BibliotecaPersonal;
import com.ujaen.tfg.mangaffinity.entidades.BibliotecaPersonalRecurso; import com.ujaen.tfg.mangaffinity.entidades.BibliotecaPersonalRecurso;
import com.ujaen.tfg.mangaffinity.entidades.Categoria; import com.ujaen.tfg.mangaffinity.entidades.Categoria;
import com.ujaen.tfg.mangaffinity.entidades.Recurso; import com.ujaen.tfg.mangaffinity.entidades.Recurso;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTORecursoEnBiblioteca; import com.ujaen.tfg.mangaffinity.rest.DTO.DTORecursoEnBiblioteca;
import com.ujaen.tfg.mangaffinity.rest.DTO.Mapper;
import com.ujaen.tfg.mangaffinity.servicios.ServicioBibliotecaPersonal; import com.ujaen.tfg.mangaffinity.servicios.ServicioBibliotecaPersonal;
import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos; import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos;
import com.ujaen.tfg.mangaffinity.servicios.ServicioUsuarios; import com.ujaen.tfg.mangaffinity.servicios.ServicioUsuarios;
...@@ -15,14 +12,14 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -15,14 +12,14 @@ import org.springframework.beans.factory.annotation.Autowired;
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.*; import org.springframework.web.bind.annotation.*;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/biblioteca") @RequestMapping("/biblioteca")
public class BibliotecaPersonalController { public class BibliotecaPersonalController {
private static final Logger logger = LoggerFactory.getLogger(BibliotecaPersonalController.class);
@Autowired @Autowired
private ServicioBibliotecaPersonal servicioBibliotecaPersonal; private ServicioBibliotecaPersonal servicioBibliotecaPersonal;
...@@ -32,9 +29,6 @@ public class BibliotecaPersonalController { ...@@ -32,9 +29,6 @@ public class BibliotecaPersonalController {
@Autowired @Autowired
private ServicioUsuarios servicioUsuarios; private ServicioUsuarios servicioUsuarios;
@Autowired
private Mapper mapper;
@PostMapping("/{usuarioId}/recursos/{recursoId}/categoria") @PostMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> anadirRecursoBiblioteca( public ResponseEntity<String> anadirRecursoBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -51,7 +45,6 @@ public class BibliotecaPersonalController { ...@@ -51,7 +45,6 @@ public class BibliotecaPersonalController {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} }
boolean yaExiste = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), dtoRecursoEnBiblioteca.getCategoria()) boolean yaExiste = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), dtoRecursoEnBiblioteca.getCategoria())
.stream() .stream()
.anyMatch(bpr -> bpr.getRecurso().getId().equals(recursoId)); .anyMatch(bpr -> bpr.getRecurso().getId().equals(recursoId));
...@@ -67,11 +60,9 @@ public class BibliotecaPersonalController { ...@@ -67,11 +60,9 @@ public class BibliotecaPersonalController {
} }
} }
@GetMapping("/{usuarioId}/recursos/categoria/{categoria}") @GetMapping("/{usuarioId}/recursos/categoria/{categoria}")
public ResponseEntity<List<DTORecursoEnBiblioteca>> listarRecursosPorCategoria( public ResponseEntity<List<DTORecursoEnBiblioteca>> listarRecursosPorCategoria(
@PathVariable Long usuarioId, @PathVariable String categoria) { // 🔥 Ahora es String @PathVariable Long usuarioId, @PathVariable String categoria) {
try { try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId); BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) { if (biblioteca == null) {
...@@ -82,17 +73,23 @@ public class BibliotecaPersonalController { ...@@ -82,17 +73,23 @@ public class BibliotecaPersonalController {
try { try {
categoriaEnum = Categoria.valueOf(categoria.toUpperCase()); categoriaEnum = Categoria.valueOf(categoria.toUpperCase());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // ⚠ Si la categoría no es válida return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
} }
List<BibliotecaPersonalRecurso> recursos = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), categoriaEnum); List<BibliotecaPersonalRecurso> recursos = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), categoriaEnum);
List<DTORecursoEnBiblioteca> dtoRecursos = recursos.stream() List<DTORecursoEnBiblioteca> dtoRecursos = recursos.stream()
.map(bpr -> new DTORecursoEnBiblioteca( .map(bpr -> {
String fotoBase64 = (bpr.getRecurso().getFoto() != null && bpr.getRecurso().getFoto().length > 0)
? "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(bpr.getRecurso().getFoto())
: null;
return new DTORecursoEnBiblioteca(
bpr.getRecurso().getId(), bpr.getRecurso().getId(),
bpr.getRecurso().getTitulo(), bpr.getRecurso().getTitulo(),
bpr.getCategoria(), bpr.getCategoria(),
bpr.getRecurso().getFotoUrl() // 🔥 Aquí añadimos la imagen fotoBase64
)) );
})
.collect(Collectors.toList()); .collect(Collectors.toList());
...@@ -102,22 +99,6 @@ public class BibliotecaPersonalController { ...@@ -102,22 +99,6 @@ public class BibliotecaPersonalController {
} }
} }
@PutMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> cambiarCategoria(
@PathVariable Long usuarioId,
@PathVariable Long recursoId,
@RequestBody DTORecursoEnBiblioteca dtoRecurso) {
try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.cambiarCategoriaRecurso(biblioteca.getId(), recursoId, dtoRecurso.getCategoria());
return ResponseEntity.status(HttpStatus.OK).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@DeleteMapping("/{usuarioId}/recursos/{recursoId}") @DeleteMapping("/{usuarioId}/recursos/{recursoId}")
public ResponseEntity<String> eliminarRecursoDeBiblioteca( public ResponseEntity<String> eliminarRecursoDeBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -127,7 +108,7 @@ public class BibliotecaPersonalController { ...@@ -127,7 +108,7 @@ public class BibliotecaPersonalController {
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.eliminarRecursoDeBiblioteca(biblioteca.getId(), recursoId); servicioBibliotecaPersonal.eliminarRecursoDeBiblioteca(biblioteca.getId(), recursoId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); // Código 204 para eliminación exitosa return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
...@@ -137,38 +118,44 @@ public class BibliotecaPersonalController { ...@@ -137,38 +118,44 @@ public class BibliotecaPersonalController {
public ResponseEntity<DTORecursoEnBiblioteca> obtenerRecursoEnBiblioteca( public ResponseEntity<DTORecursoEnBiblioteca> obtenerRecursoEnBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long recursoId) { @PathVariable Long usuarioId, @PathVariable Long recursoId) {
try { try {
logger.info("Recibiendo solicitud para obtener recurso con ID: {} para usuario con ID: {}", recursoId, usuarioId);
// Obtener la biblioteca personal del usuario
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId); BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) { if (biblioteca == null) {
logger.warn("No se encontró la biblioteca para el usuario con ID: {}", usuarioId); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); // Si no existe la biblioteca del usuario
} }
// Buscar el recurso dentro de la biblioteca del usuario
BibliotecaPersonalRecurso bibliotecaPersonalRecurso = servicioBibliotecaPersonal.buscarRecursoEnBiblioteca(biblioteca.getId(), recursoId); BibliotecaPersonalRecurso bibliotecaPersonalRecurso = servicioBibliotecaPersonal.buscarRecursoEnBiblioteca(biblioteca.getId(), recursoId);
if (bibliotecaPersonalRecurso == null) { if (bibliotecaPersonalRecurso == null) {
logger.warn("No se encontró el recurso con ID: {} en la biblioteca del usuario con ID: {}", recursoId, usuarioId); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); // Si no se encuentra el recurso en la biblioteca
} }
// Mapear el recurso encontrado al DTO para retornar
DTORecursoEnBiblioteca dtoRecursoEnBiblioteca = new DTORecursoEnBiblioteca( DTORecursoEnBiblioteca dtoRecursoEnBiblioteca = new DTORecursoEnBiblioteca(
bibliotecaPersonalRecurso.getRecurso().getId(), bibliotecaPersonalRecurso.getRecurso().getId(),
bibliotecaPersonalRecurso.getRecurso().getTitulo(), bibliotecaPersonalRecurso.getRecurso().getTitulo(),
bibliotecaPersonalRecurso.getCategoria(), bibliotecaPersonalRecurso.getCategoria(),
bibliotecaPersonalRecurso.getRecurso().getFotoUrl() (bibliotecaPersonalRecurso.getRecurso().getFoto() != null)
? Base64.getEncoder().encodeToString(bibliotecaPersonalRecurso.getRecurso().getFoto())
: null
); );
logger.info("Recurso con ID: {} encontrado para el usuario con ID: {}", recursoId, usuarioId);
return ResponseEntity.ok(dtoRecursoEnBiblioteca); return ResponseEntity.ok(dtoRecursoEnBiblioteca);
} catch (Exception e) { } catch (Exception e) {
logger.error("Error inesperado al obtener el recurso con ID: {} para el usuario con ID: {}", recursoId, usuarioId, e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // Si ocurre algún error inesperado
} }
} }
@PutMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> cambiarCategoria(
@PathVariable Long usuarioId,
@PathVariable Long recursoId,
@RequestBody DTORecursoEnBiblioteca dtoRecurso) {
try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.cambiarCategoriaRecurso(biblioteca.getId(), recursoId, dtoRecurso.getCategoria());
} return ResponseEntity.status(HttpStatus.OK).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
package com.ujaen.tfg.mangaffinity.rest.DTO; package com.ujaen.tfg.mangaffinity.rest.DTO;
import com.ujaen.tfg.mangaffinity.entidades.Genero; import com.ujaen.tfg.mangaffinity.entidades.Genero;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
@Getter @Getter
...@@ -17,19 +15,11 @@ import java.util.Set; ...@@ -17,19 +15,11 @@ import java.util.Set;
@AllArgsConstructor @AllArgsConstructor
public class DTORecurso { public class DTORecurso {
private Long id; private Long id;
@NotBlank
private String titulo; private String titulo;
private String descripcion; private String descripcion;
@NotNull
private LocalDate fechaPublicacion; private LocalDate fechaPublicacion;
@NotBlank
private String autor; private String autor;
private String fotoBase64;
private String fotoUrl; private Set<Genero> generos;
private Set<Genero> generos = new HashSet<>();
} }
...@@ -11,16 +11,8 @@ import lombok.Setter; ...@@ -11,16 +11,8 @@ import lombok.Setter;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DTORecursoEnBiblioteca { public class DTORecursoEnBiblioteca {
private Long usuarioId;
private Long recursoId; private Long recursoId;
private String titulo; private String titulo;
private Categoria categoria; private Categoria categoria;
private String fotoUrl; private String fotoBase64;
public DTORecursoEnBiblioteca(Long recursoId, String titulo, Categoria categoria, String fotoUrl) {
this.recursoId = recursoId;
this.titulo = titulo;
this.categoria = categoria;
this.fotoUrl = fotoUrl;
}
} }
package com.ujaen.tfg.mangaffinity.rest;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.MalformedURLException;
import java.nio.file.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/uploads")
public class UploadController {
private final Path uploadDir = Paths.get("uploads");
@GetMapping("/{filename:.+}")
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
try {
Path file = uploadDir.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
String contentType = "application/octet-stream";
if (filename.endsWith(".png")) contentType = "image/png";
else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) contentType = "image/jpeg";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resource.getFilename() + "\"")
.header(HttpHeaders.CONTENT_TYPE, contentType)
.body(resource);
} else {
return ResponseEntity.notFound().build();
}
} catch (MalformedURLException e) {
return ResponseEntity.badRequest().build();
}
}
@PostMapping
public ResponseEntity<String> uploadFile(@RequestParam("foto") MultipartFile foto) {
try {
if (foto.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
String contentType = foto.getContentType();
if (contentType == null || (!contentType.equals("image/jpeg") && !contentType.equals("image/png"))) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
Path path = uploadDir.resolve(foto.getOriginalFilename());
Files.copy(foto.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
return ResponseEntity.ok(foto.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
...@@ -37,8 +37,7 @@ public class ServicioSeguridad { ...@@ -37,8 +37,7 @@ public class ServicioSeguridad {
return config; return config;
})) }))
.authorizeHttpRequests(request -> request .authorizeHttpRequests(request -> request
.requestMatchers(HttpMethod.GET, "/uploads/**").permitAll() .requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll() // Permitir login sin autenticación
.requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll() .requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/").permitAll() .requestMatchers(HttpMethod.POST, "/usuarios/").permitAll()
.requestMatchers(HttpMethod.GET, "/actuator/health").permitAll() .requestMatchers(HttpMethod.GET, "/actuator/health").permitAll()
...@@ -65,7 +64,7 @@ public class ServicioSeguridad { ...@@ -65,7 +64,7 @@ public class ServicioSeguridad {
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) // Usar solo JWT .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
.build(); .build();
} }
......
package com.ujaen.tfg.mangaffinity.servicios; package com.ujaen.tfg.mangaffinity.servicios;
import com.ujaen.tfg.mangaffinity.entidades.*; import com.ujaen.tfg.mangaffinity.entidades.*;
import com.ujaen.tfg.mangaffinity.excepciones.CapituloNoExiste; import com.ujaen.tfg.mangaffinity.excepciones.CapituloNoExiste;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste; import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste;
...@@ -10,24 +9,33 @@ import jakarta.validation.Valid; ...@@ -10,24 +9,33 @@ import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.stream.Collectors;
import java.util.stream.Collectors;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class ServicioRecursos { public class ServicioRecursos {
@Autowired @Autowired
RepositorioRecurso repositorioRecurso; RepositorioRecurso repositorioRecurso;
@Autowired @Autowired
RepositorioCapitulo repositorioCapitulo; RepositorioCapitulo repositorioCapitulo;
@Transactional
public void crearRecurso(@Valid Recurso recurso) { public void crearRecurso(@Valid Recurso recurso) {
// Verifica si ya existe un recurso con el mismo título y autor
List<Recurso> recursosExistentes = repositorioRecurso.buscarPorTitulo(recurso.getTitulo());
for (Recurso r : recursosExistentes) {
if (r.getAutor().equals(recurso.getAutor()) &&
r.getFechaPublicacion().equals(recurso.getFechaPublicacion())) {
return;
}
}
repositorioRecurso.crear(recurso); repositorioRecurso.crear(recurso);
} }
...@@ -74,7 +82,6 @@ public class ServicioRecursos { ...@@ -74,7 +82,6 @@ public class ServicioRecursos {
throw new RecursoNoExiste(); throw new RecursoNoExiste();
} }
if (nuevosDatos.getTitulo() != null) { if (nuevosDatos.getTitulo() != null) {
recursoExistente.setTitulo(nuevosDatos.getTitulo()); recursoExistente.setTitulo(nuevosDatos.getTitulo());
} }
...@@ -99,66 +106,19 @@ public class ServicioRecursos { ...@@ -99,66 +106,19 @@ public class ServicioRecursos {
} }
@Transactional @Transactional
public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) { public void actualizarFotoRecurso(Long recursoId, byte[] nuevaFoto) {
Logger logger = LoggerFactory.getLogger(ServicioRecursos.class);
Recurso recurso = repositorioRecurso.buscarPorId(recursoId); Recurso recurso = repositorioRecurso.buscarPorId(recursoId);
if (recurso == null) { if (recurso != null) {
logger.error("❌ Recurso con ID {} no encontrado.", recursoId); recurso.setFoto(nuevaFoto);
throw new RecursoNoExiste(); repositorioRecurso.modificarRecurso(recurso);
}
List<Capitulo> listaCapitulos = (nuevoCapitulo.getTipo() == TipoRecurso.MANGA)
? recurso.getCapitulosManga()
: recurso.getCapitulosAnime();
logger.info("🔍 Lista actual de capítulos para recurso {}: {} capítulos", recursoId, listaCapitulos.size());
if (listaCapitulos.size() < 4) {
logger.info("✅ Espacio disponible, agregando capítulo: {}", nuevoCapitulo.getTitulo());
listaCapitulos.add(nuevoCapitulo);
} else {
logger.warn("⚠️ Lista llena, reemplazando el capítulo más antiguo...");
if (!listaCapitulos.isEmpty()) {
Capitulo capituloAEliminar = listaCapitulos.get(0); // Tomamos el más antiguo
logger.info("📝 Eliminando el capítulo más antiguo: '{}'", capituloAEliminar.getTitulo());
// 🔴 Primero eliminar sus fuentes antes de eliminar el capítulo
repositorioCapitulo.borrarCapitulo(capituloAEliminar);
// ✅ Ahora removerlo de la lista
listaCapitulos.remove(capituloAEliminar);
logger.info("🗑️ Capítulo '{}' eliminado correctamente", capituloAEliminar.getTitulo());
// ✅ Agregar el nuevo capítulo
listaCapitulos.add(nuevoCapitulo);
}
} }
logger.info("✅ Capítulo '{}' añadido correctamente al recurso {}", nuevoCapitulo.getTitulo(), recursoId);
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Capitulo> obtenerCapitulosDeRecursoPorTipo(Long recursoId, TipoRecurso tipo) { public List<Capitulo> obtenerCapitulosDeRecursoPorTipo(Long recursoId, TipoRecurso tipo) {
return repositorioCapitulo.obtenerCapitulosPorTipo(recursoId, tipo); return repositorioCapitulo.obtenerCapitulosPorTipo(recursoId, tipo);
} }
@Transactional @Transactional
public List<Capitulo> obtenerCapitulosDeRecurso(Long recursoId) { public List<Capitulo> obtenerCapitulosDeRecurso(Long recursoId) {
List<Capitulo> capitulos = repositorioCapitulo.obtenerCapitulosRecurso(recursoId); List<Capitulo> capitulos = repositorioCapitulo.obtenerCapitulosRecurso(recursoId);
...@@ -167,66 +127,70 @@ public class ServicioRecursos { ...@@ -167,66 +127,70 @@ public class ServicioRecursos {
} }
public List<String> obtenerGeneros() { public List<String> obtenerGeneros() {
return Arrays.stream(Genero.values()) return Arrays.stream(Genero.values())
.map(Enum::name) .map(Enum::name)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Transactional @Transactional
public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) {
Recurso recurso = repositorioRecurso.buscarPorId(recursoId);
if (recurso == null) {
throw new RecursoNoExiste();
}
nuevoCapitulo.setRecurso(recurso);
if (nuevoCapitulo.getFuentes() != null) {
for (FuenteCapitulo fuente : nuevoCapitulo.getFuentes()) {
fuente.setCapitulo(nuevoCapitulo);
}
}
repositorioCapitulo.crearCapitulo(nuevoCapitulo);
}
@Transactional
public void modificarCapitulo(Capitulo capituloModificado) { public void modificarCapitulo(Capitulo capituloModificado) {
Capitulo capitulo = repositorioCapitulo.buscarPorId(capituloModificado.getId()); Capitulo capitulo = repositorioCapitulo.buscarPorId(capituloModificado.getId());
if (capitulo == null) { if (capitulo == null) {
throw new CapituloNoExiste(); throw new CapituloNoExiste();
} }
// Asegurar que el capítulo pertenece a un recurso antes de modificarlo
if (capitulo.getRecurso() == null) {
throw new IllegalStateException("El capítulo no está asociado a ningún recurso.");
}
// Modificar solo si los valores no son nulos o inválidos
if (capituloModificado.getNumero() > 0) {
capitulo.setNumero(capituloModificado.getNumero()); capitulo.setNumero(capituloModificado.getNumero());
}
if (capituloModificado.getTitulo() != null && !capituloModificado.getTitulo().isBlank()) {
capitulo.setTitulo(capituloModificado.getTitulo()); capitulo.setTitulo(capituloModificado.getTitulo());
}
if (capituloModificado.getTipo() != null) {
capitulo.setTipo(capituloModificado.getTipo()); capitulo.setTipo(capituloModificado.getTipo());
} capitulo.setActivo(capituloModificado.getActivo());
if (capituloModificado.getFuentes() != null) { List<FuenteCapitulo> fuentesActuales = new ArrayList<>(capitulo.getFuentes());
// Crear un mapa con las fuentes existentes para facilitar la comparación List<FuenteCapitulo> fuentesAEliminar = new ArrayList<>();
Map<Long, FuenteCapitulo> fuentesExistentes = capitulo.getFuentes().stream()
.collect(Collectors.toMap(FuenteCapitulo::getId, f -> f));
List<FuenteCapitulo> nuevasFuentes = new ArrayList<>(); for (FuenteCapitulo fuenteExistente : fuentesActuales) {
boolean sigueExistiendo = capituloModificado.getFuentes().stream()
.anyMatch(f -> f.getNombreFuente().equals(fuenteExistente.getNombreFuente()));
for (FuenteCapitulo fuenteNueva : capituloModificado.getFuentes()) { if (!sigueExistiendo) {
if (fuenteNueva.getId() != null && fuentesExistentes.containsKey(fuenteNueva.getId())) { fuentesAEliminar.add(fuenteExistente);
// Si la fuente ya existe, actualizamos su información
FuenteCapitulo fuenteExistente = fuentesExistentes.get(fuenteNueva.getId());
fuenteExistente.setNombreFuente(fuenteNueva.getNombreFuente());
fuenteExistente.setUrlFuente(fuenteNueva.getUrlFuente());
nuevasFuentes.add(fuenteExistente);
} else {
// Si la fuente es nueva, simplemente la agregamos a la lista del capítulo
nuevasFuentes.add(fuenteNueva);
} }
} }
// 🔴 Remover las fuentes que ya no están en la lista for (FuenteCapitulo fuente : fuentesAEliminar) {
capitulo.getFuentes().clear(); repositorioCapitulo.eliminarFuente(fuente);
capitulo.getFuentes().addAll(nuevasFuentes); capitulo.getFuentes().remove(fuente);
} }
for (FuenteCapitulo nuevaFuente : capituloModificado.getFuentes()) {
boolean existe = fuentesActuales.stream()
.anyMatch(f -> f.getNombreFuente().equals(nuevaFuente.getNombreFuente()));
if (!existe) {
nuevaFuente.setCapitulo(capitulo);
repositorioCapitulo.agregarFuente(nuevaFuente);
capitulo.getFuentes().add(nuevaFuente);
}
}
repositorioCapitulo.actualizarCapitulo(capitulo); repositorioCapitulo.actualizarCapitulo(capitulo);
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Capitulo buscarCapituloPorId(Long id) { public Capitulo buscarCapituloPorId(Long id) {
Capitulo capitulo = repositorioCapitulo.buscarPorId(id); Capitulo capitulo = repositorioCapitulo.buscarPorId(id);
...@@ -236,6 +200,33 @@ public class ServicioRecursos { ...@@ -236,6 +200,33 @@ public class ServicioRecursos {
return capitulo; return capitulo;
} }
@Transactional
public void actualizarFuente(FuenteCapitulo fuente) {
FuenteCapitulo fuenteExistente = repositorioCapitulo.buscarFuentePorId(fuente.getId());
if (fuenteExistente != null) {
fuenteExistente.setUrlFuente(fuente.getUrlFuente());
repositorioCapitulo.actualizarFuente(fuenteExistente);
}
}
@Transactional
public void eliminarFuentePorId(Long id) {
FuenteCapitulo fuente = repositorioCapitulo.buscarFuentePorId(id);
if (fuente != null) {
repositorioCapitulo.eliminarFuentePorId(id);
}
}
@Transactional
public void agregarFuente(FuenteCapitulo fuente) {
repositorioCapitulo.agregarFuente(fuente);
}
@Transactional
public void eliminarFuente(Long id) {
FuenteCapitulo fuente = repositorioCapitulo.buscarFuentePorId(id);
if (fuente != null) {
repositorioCapitulo.eliminarFuentePorId(id);
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment