Commit 95359e1d by Rubén Ramírez

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

parent e15ce02d
......@@ -106,6 +106,7 @@
</dependencies>
<build>
......
......@@ -30,10 +30,12 @@ public class Capitulo {
@Column(nullable = false)
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<>();
@ManyToOne
@JoinColumn(name = "recurso_id", nullable = false)
private Recurso recurso;
......
......@@ -6,7 +6,9 @@ import com.ujaen.tfg.mangaffinity.entidades.Categoria;
import com.ujaen.tfg.mangaffinity.entidades.Recurso;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoSinCategoria;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.PersistenceContext;
import org.hibernate.NonUniqueResultException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
......@@ -64,5 +66,25 @@ public class RepositorioBibliotecaPersonalRecurso {
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;
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.PersistenceContext;
import org.springframework.stereotype.Repository;
......@@ -35,10 +37,43 @@ public class RepositorioCapitulo {
@Transactional
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);
}
@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)
public Capitulo buscarPorId(Long id) {
return em.find(Capitulo.class, id);
......
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.BibliotecaPersonalRecurso;
import com.ujaen.tfg.mangaffinity.entidades.Categoria;
......@@ -21,7 +22,7 @@ import java.util.stream.Collectors;
@RestController
@RequestMapping("/biblioteca")
public class BibliotecaPersonalController {
private static final Logger logger = LoggerFactory.getLogger(BibliotecaPersonalController.class);
@Autowired
private ServicioBibliotecaPersonal servicioBibliotecaPersonal;
......@@ -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;
import com.ujaen.tfg.mangaffinity.entidades.Capitulo;
import com.ujaen.tfg.mangaffinity.entidades.Genero;
import com.ujaen.tfg.mangaffinity.entidades.Recurso;
import com.ujaen.tfg.mangaffinity.entidades.*;
import com.ujaen.tfg.mangaffinity.excepciones.CapituloNoExiste;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOCapitulo;
......@@ -128,6 +126,22 @@ 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}")
public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) {
......@@ -297,19 +311,21 @@ public class RecursosController {
try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(id);
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);
servicioRecursos.anadirCapitulo(id, nuevoCapitulo);
return ResponseEntity.status(HttpStatus.CREATED).build();
return ResponseEntity.status(HttpStatus.CREATED).body("Capítulo añadido correctamente");
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Recurso no existe");
} 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")
public ResponseEntity<List<DTOCapitulo>> obtenerCapitulosDeRecurso(@PathVariable Long id) {
try {
......
......@@ -61,6 +61,7 @@ public class ServicioSeguridad {
.requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/capitulos/{capituloId}").permitAll()
.requestMatchers(HttpMethod.PUT, "/recursos/{recursoId}/capitulos/{capituloId}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated()
.anyRequest().authenticated()
)
......
......@@ -60,5 +60,10 @@ public class ServicioBibliotecaPersonal {
repositorioBibliotecaPersonalRecurso.eliminarRecursoDeBiblioteca(bibliotecaPersonalId, recursoId);
}
public BibliotecaPersonalRecurso buscarRecursoEnBiblioteca(Long bibliotecaPersonalId, Long recursoId) {
return repositorioBibliotecaPersonalRecurso.buscarRecursoEnBiblioteca(bibliotecaPersonalId, recursoId);
}
}
......@@ -16,7 +16,9 @@ import java.util.ArrayList;
import java.util.Arrays;
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
public class ServicioRecursos {
......@@ -98,8 +100,11 @@ public class ServicioRecursos {
@Transactional
public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) {
Logger logger = LoggerFactory.getLogger(ServicioRecursos.class);
Recurso recurso = repositorioRecurso.buscarPorId(recursoId);
if (recurso == null) {
logger.error("❌ Recurso con ID {} no encontrado.", recursoId);
throw new RecursoNoExiste();
}
......@@ -107,37 +112,53 @@ public class ServicioRecursos {
? recurso.getCapitulosManga()
: recurso.getCapitulosAnime();
// Asociar fuentes al capítulo
for (FuenteCapitulo fuente : nuevoCapitulo.getFuentes()) {
fuente.setCapitulo(nuevoCapitulo);
}
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 {
Capitulo penultimo = listaCapitulos.get(2);
Capitulo ultimo = listaCapitulos.get(3);
logger.warn("⚠️ Lista llena, reemplazando el capítulo más antiguo...");
List<FuenteCapitulo> nuevasFuentes = new ArrayList<>();
for (FuenteCapitulo fuente : ultimo.getFuentes()) {
FuenteCapitulo nuevaFuente = new FuenteCapitulo(null, fuente.getNombreFuente(), fuente.getUrlFuente(), penultimo);
nuevasFuentes.add(nuevaFuente);
}
if (!listaCapitulos.isEmpty()) {
Capitulo capituloAEliminar = listaCapitulos.get(0); // Tomamos el más antiguo
logger.info("📝 Eliminando el capítulo más antiguo: '{}'", capituloAEliminar.getTitulo());
penultimo.setNumero(ultimo.getNumero());
penultimo.setTitulo(ultimo.getTitulo());
penultimo.setTipo(ultimo.getTipo());
penultimo.setFuentes(nuevasFuentes);
// 🔴 Primero eliminar sus fuentes antes de eliminar el capítulo
repositorioCapitulo.borrarCapitulo(capituloAEliminar);
listaCapitulos.remove(ultimo);
// ✅ 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
public List<Capitulo> obtenerCapitulosDeRecurso(Long recursoId) {
List<Capitulo> capitulos = repositorioCapitulo.obtenerCapitulosRecurso(recursoId);
......@@ -192,13 +213,12 @@ public class ServicioRecursos {
fuenteExistente.setUrlFuente(fuenteNueva.getUrlFuente());
nuevasFuentes.add(fuenteExistente);
} else {
// Si la fuente es nueva, la agregamos correctamente
fuenteNueva.setCapitulo(capitulo);
// Si la fuente es nueva, simplemente la agregamos a la lista del capítulo
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().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