Commit 95359e1d by Rubén Ramírez

fix: [Capitulos]: último commit antes de tutoría TFG

parent e15ce02d
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
</dependencies> </dependencies>
<build> <build>
......
...@@ -30,10 +30,12 @@ public class Capitulo { ...@@ -30,10 +30,12 @@ public class Capitulo {
@Column(nullable = false) @Column(nullable = false)
private TipoRecurso tipo; private TipoRecurso tipo;
@OneToMany(mappedBy = "capitulo", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(name = "capitulo_id") // Indica la clave foránea sin mappedBy
private List<FuenteCapitulo> fuentes = new ArrayList<>(); private List<FuenteCapitulo> fuentes = new ArrayList<>();
@ManyToOne @ManyToOne
@JoinColumn(name = "recurso_id", nullable = false) @JoinColumn(name = "recurso_id", nullable = false)
private Recurso recurso; private Recurso recurso;
......
...@@ -6,7 +6,9 @@ import com.ujaen.tfg.mangaffinity.entidades.Categoria; ...@@ -6,7 +6,9 @@ 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.RecursoSinCategoria; import com.ujaen.tfg.mangaffinity.excepciones.RecursoSinCategoria;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import org.hibernate.NonUniqueResultException;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -64,5 +66,25 @@ public class RepositorioBibliotecaPersonalRecurso { ...@@ -64,5 +66,25 @@ public class RepositorioBibliotecaPersonalRecurso {
return em.find(Recurso.class, recursoId); return em.find(Recurso.class, recursoId);
} }
public BibliotecaPersonalRecurso buscarRecursoEnBiblioteca(Long bibliotecaPersonalId, Long recursoId) {
List<BibliotecaPersonalRecurso> resultList = em.createQuery(
"SELECT bpr FROM BibliotecaPersonalRecurso bpr WHERE bpr.bibliotecaPersonal.id = :bibliotecaPersonalId AND bpr.recurso.id = :recursoId",
BibliotecaPersonalRecurso.class)
.setParameter("bibliotecaPersonalId", bibliotecaPersonalId)
.setParameter("recursoId", recursoId)
.getResultList(); // Usamos getResultList() para obtener todos los resultados
if (resultList.size() == 1) {
return resultList.get(0); // Devuelve el único resultado
} else if (resultList.size() > 1) {
// Aquí puedes decidir qué hacer si hay más de un resultado
throw new IllegalStateException("Se encontraron múltiples recursos para esta biblioteca y recurso.");
} else {
return null; // Si no hay resultados, devuelve null
}
}
} }
package com.ujaen.tfg.mangaffinity.repositorios; package com.ujaen.tfg.mangaffinity.repositorios;
import com.ujaen.tfg.mangaffinity.entidades.Capitulo; import com.ujaen.tfg.mangaffinity.entidades.Capitulo;
import com.ujaen.tfg.mangaffinity.entidades.FuenteCapitulo;
import com.ujaen.tfg.mangaffinity.entidades.TipoRecurso;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
...@@ -35,10 +37,43 @@ public class RepositorioCapitulo { ...@@ -35,10 +37,43 @@ public class RepositorioCapitulo {
@Transactional @Transactional
public void borrarCapitulo(Capitulo capitulo) { public void borrarCapitulo(Capitulo capitulo) {
capitulo = em.merge(capitulo); capitulo = em.merge(capitulo); // Asegurar que la entidad está en el contexto persistente
// 🔴 Asegurar que el capítulo tiene fuentes antes de eliminarlas
List<FuenteCapitulo> fuentes = em.createQuery(
"SELECT f FROM FuenteCapitulo f WHERE f.capitulo = :capitulo", FuenteCapitulo.class)
.setParameter("capitulo", capitulo)
.getResultList();
for (FuenteCapitulo fuente : fuentes) {
em.remove(fuente); // 🔴 Eliminar cada fuente individualmente
}
em.flush(); // 🔄 Sincronizar con la base de datos antes de eliminar el capítulo
// 🔴 Finalmente, eliminar el capítulo
em.remove(capitulo); em.remove(capitulo);
} }
@Transactional(readOnly = true)
public List<Capitulo> obtenerCapitulosPorTipo(Long recursoId, TipoRecurso tipo) {
return em.createQuery(
"SELECT c FROM Capitulo c WHERE c.recurso.id = :recursoId AND c.tipo = :tipo ORDER BY c.numero ASC",
Capitulo.class)
.setParameter("recursoId", recursoId)
.setParameter("tipo", tipo)
.getResultList();
}
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Capitulo buscarPorId(Long id) { public Capitulo buscarPorId(Long id) {
return em.find(Capitulo.class, id); return em.find(Capitulo.class, id);
......
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;
...@@ -21,7 +22,7 @@ import java.util.stream.Collectors; ...@@ -21,7 +22,7 @@ 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;
...@@ -132,4 +133,42 @@ public class BibliotecaPersonalController { ...@@ -132,4 +133,42 @@ public class BibliotecaPersonalController {
} }
} }
@GetMapping("/{usuarioId}/recursos/{recursoId}")
public ResponseEntity<DTORecursoEnBiblioteca> obtenerRecursoEnBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long recursoId) {
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);
if (biblioteca == null) {
logger.warn("No se encontró la biblioteca para el usuario con ID: {}", usuarioId);
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);
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); // Si no se encuentra el recurso en la biblioteca
}
// Mapear el recurso encontrado al DTO para retornar
DTORecursoEnBiblioteca dtoRecursoEnBiblioteca = new DTORecursoEnBiblioteca(
bibliotecaPersonalRecurso.getRecurso().getId(),
bibliotecaPersonalRecurso.getRecurso().getTitulo(),
bibliotecaPersonalRecurso.getCategoria(),
bibliotecaPersonalRecurso.getRecurso().getFotoUrl()
);
logger.info("Recurso con ID: {} encontrado para el usuario con ID: {}", recursoId, usuarioId);
return ResponseEntity.ok(dtoRecursoEnBiblioteca);
} 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(); // Si ocurre algún error inesperado
}
}
} }
package com.ujaen.tfg.mangaffinity.rest; package com.ujaen.tfg.mangaffinity.rest;
import com.ujaen.tfg.mangaffinity.entidades.Capitulo; import com.ujaen.tfg.mangaffinity.entidades.*;
import com.ujaen.tfg.mangaffinity.entidades.Genero;
import com.ujaen.tfg.mangaffinity.entidades.Recurso;
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;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOCapitulo; import com.ujaen.tfg.mangaffinity.rest.DTO.DTOCapitulo;
...@@ -128,7 +126,23 @@ public class RecursosController { ...@@ -128,7 +126,23 @@ public class RecursosController {
} }
@GetMapping("/{id}/capitulos/tipos")
public ResponseEntity<Map<String, List<DTOCapitulo>>> obtenerCapitulosPorTipo(@PathVariable Long id) {
try {
List<Capitulo> capitulosManga = servicioRecursos.obtenerCapitulosDeRecursoPorTipo(id, TipoRecurso.MANGA);
List<Capitulo> capitulosAnime = servicioRecursos.obtenerCapitulosDeRecursoPorTipo(id, TipoRecurso.ANIME);
Map<String, List<DTOCapitulo>> response = Map.of(
"MANGA", capitulosManga.stream().map(mapper::dto).toList(),
"ANIME", capitulosAnime.stream().map(mapper::dto).toList()
);
return ResponseEntity.ok(response);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@GetMapping("/genero/{genero}") @GetMapping("/genero/{genero}")
public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) { public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) {
try { try {
...@@ -297,19 +311,21 @@ public class RecursosController { ...@@ -297,19 +311,21 @@ public class RecursosController {
try { try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(id); Recurso recurso = servicioRecursos.buscarRecursoPorId(id);
if (recurso == null) { if (recurso == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Recurso no encontrado");
} }
Capitulo nuevoCapitulo = mapper.entity(dtoCapitulo, recurso); Capitulo nuevoCapitulo = mapper.entity(dtoCapitulo, recurso);
servicioRecursos.anadirCapitulo(id, nuevoCapitulo); servicioRecursos.anadirCapitulo(id, nuevoCapitulo);
return ResponseEntity.status(HttpStatus.CREATED).build(); return ResponseEntity.status(HttpStatus.CREATED).body("Capítulo añadido correctamente");
} catch (RecursoNoExiste e) { } catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Recurso no existe");
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); e.printStackTrace(); // Imprime la traza completa del error en la consola
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error interno del servidor: " + e.getMessage());
} }
} }
@GetMapping("/{id}/capitulos") @GetMapping("/{id}/capitulos")
public ResponseEntity<List<DTOCapitulo>> obtenerCapitulosDeRecurso(@PathVariable Long id) { public ResponseEntity<List<DTOCapitulo>> obtenerCapitulosDeRecurso(@PathVariable Long id) {
try { try {
......
...@@ -61,6 +61,7 @@ public class ServicioSeguridad { ...@@ -61,6 +61,7 @@ public class ServicioSeguridad {
.requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated() .requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/capitulos/{capituloId}").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/capitulos/{capituloId}").permitAll()
.requestMatchers(HttpMethod.PUT, "/recursos/{recursoId}/capitulos/{capituloId}").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.PUT, "/recursos/{recursoId}/capitulos/{capituloId}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated()
.anyRequest().authenticated() .anyRequest().authenticated()
) )
......
...@@ -60,5 +60,10 @@ public class ServicioBibliotecaPersonal { ...@@ -60,5 +60,10 @@ public class ServicioBibliotecaPersonal {
repositorioBibliotecaPersonalRecurso.eliminarRecursoDeBiblioteca(bibliotecaPersonalId, recursoId); repositorioBibliotecaPersonalRecurso.eliminarRecursoDeBiblioteca(bibliotecaPersonalId, recursoId);
} }
public BibliotecaPersonalRecurso buscarRecursoEnBiblioteca(Long bibliotecaPersonalId, Long recursoId) {
return repositorioBibliotecaPersonalRecurso.buscarRecursoEnBiblioteca(bibliotecaPersonalId, recursoId);
}
} }
...@@ -16,7 +16,9 @@ import java.util.ArrayList; ...@@ -16,7 +16,9 @@ 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.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 {
...@@ -98,8 +100,11 @@ public class ServicioRecursos { ...@@ -98,8 +100,11 @@ public class ServicioRecursos {
@Transactional @Transactional
public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) { public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) {
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);
throw new RecursoNoExiste(); throw new RecursoNoExiste();
} }
...@@ -107,37 +112,53 @@ public class ServicioRecursos { ...@@ -107,37 +112,53 @@ public class ServicioRecursos {
? recurso.getCapitulosManga() ? recurso.getCapitulosManga()
: recurso.getCapitulosAnime(); : recurso.getCapitulosAnime();
// Asociar fuentes al capítulo logger.info("🔍 Lista actual de capítulos para recurso {}: {} capítulos", recursoId, listaCapitulos.size());
for (FuenteCapitulo fuente : nuevoCapitulo.getFuentes()) {
fuente.setCapitulo(nuevoCapitulo);
}
if (listaCapitulos.size() < 4) { if (listaCapitulos.size() < 4) {
logger.info("✅ Espacio disponible, agregando capítulo: {}", nuevoCapitulo.getTitulo());
listaCapitulos.add(nuevoCapitulo); listaCapitulos.add(nuevoCapitulo);
} else { } else {
Capitulo penultimo = listaCapitulos.get(2); logger.warn("⚠️ Lista llena, reemplazando el capítulo más antiguo...");
Capitulo ultimo = listaCapitulos.get(3);
List<FuenteCapitulo> nuevasFuentes = new ArrayList<>(); if (!listaCapitulos.isEmpty()) {
for (FuenteCapitulo fuente : ultimo.getFuentes()) { Capitulo capituloAEliminar = listaCapitulos.get(0); // Tomamos el más antiguo
FuenteCapitulo nuevaFuente = new FuenteCapitulo(null, fuente.getNombreFuente(), fuente.getUrlFuente(), penultimo);
nuevasFuentes.add(nuevaFuente);
}
penultimo.setNumero(ultimo.getNumero()); logger.info("📝 Eliminando el capítulo más antiguo: '{}'", capituloAEliminar.getTitulo());
penultimo.setTitulo(ultimo.getTitulo());
penultimo.setTipo(ultimo.getTipo());
penultimo.setFuentes(nuevasFuentes);
listaCapitulos.remove(ultimo); // 🔴 Primero eliminar sus fuentes antes de eliminar el capítulo
listaCapitulos.add(nuevoCapitulo); 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);
}
} }
repositorioRecurso.merge(recurso); logger.info("✅ Capítulo '{}' añadido correctamente al recurso {}", nuevoCapitulo.getTitulo(), recursoId);
}
@Transactional(readOnly = true)
public List<Capitulo> obtenerCapitulosDeRecursoPorTipo(Long recursoId, TipoRecurso 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);
...@@ -192,13 +213,12 @@ public class ServicioRecursos { ...@@ -192,13 +213,12 @@ public class ServicioRecursos {
fuenteExistente.setUrlFuente(fuenteNueva.getUrlFuente()); fuenteExistente.setUrlFuente(fuenteNueva.getUrlFuente());
nuevasFuentes.add(fuenteExistente); nuevasFuentes.add(fuenteExistente);
} else { } else {
// Si la fuente es nueva, la agregamos correctamente // Si la fuente es nueva, simplemente la agregamos a la lista del capítulo
fuenteNueva.setCapitulo(capitulo);
nuevasFuentes.add(fuenteNueva); nuevasFuentes.add(fuenteNueva);
} }
} }
// Remover las fuentes que no están en la nueva lista // 🔴 Remover las fuentes que ya no están en la lista
capitulo.getFuentes().clear(); capitulo.getFuentes().clear();
capitulo.getFuentes().addAll(nuevasFuentes); capitulo.getFuentes().addAll(nuevasFuentes);
} }
......
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