Commit 9636b320 by Rubén Ramírez

fix: [Capítulo]: Modificada la manera de tratar con los capítulos y sus fuentes…

fix: [Capítulo]: Modificada la manera de tratar con los capítulos y sus fuentes con booleano de visibilidad
parent ab607cc1
...@@ -4,14 +4,15 @@ import jakarta.persistence.*; ...@@ -4,14 +4,15 @@ import jakarta.persistence.*;
import lombok.*; import lombok.*;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.Positive;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Entity @Entity
@Table(name = "capitulos") @Table(name = "capitulos")
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor
public class Capitulo { public class Capitulo {
@Id @Id
...@@ -30,23 +31,22 @@ public class Capitulo { ...@@ -30,23 +31,22 @@ public class Capitulo {
@Column(nullable = false) @Column(nullable = false)
private TipoRecurso tipo; private TipoRecurso tipo;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @OneToMany(mappedBy = "capitulo", 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;
public Capitulo(int numero, String titulo, TipoRecurso tipo, List<FuenteCapitulo> fuentes, Recurso recurso) { @Column(nullable = true)
private Boolean activo;
public Capitulo(int numero, String titulo, TipoRecurso tipo, List<FuenteCapitulo> fuentes, Recurso recurso, Boolean activo) {
this.numero = numero; this.numero = numero;
this.titulo = titulo; this.titulo = titulo;
this.tipo = tipo; this.tipo = tipo;
this.fuentes = fuentes; this.fuentes = fuentes;
this.recurso = recurso; this.recurso = recurso;
this.activo = activo;
} }
} }
...@@ -18,7 +18,6 @@ import java.util.Set; ...@@ -18,7 +18,6 @@ import java.util.Set;
@NoArgsConstructor @NoArgsConstructor
public class Recurso { public class Recurso {
// Clave
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
...@@ -27,7 +26,6 @@ public class Recurso { ...@@ -27,7 +26,6 @@ public class Recurso {
@Column(nullable = false) @Column(nullable = false)
private String titulo; private String titulo;
//Descripciones largas
@Column(columnDefinition = "TEXT") @Column(columnDefinition = "TEXT")
private String descripcion; private String descripcion;
...@@ -39,8 +37,9 @@ public class Recurso { ...@@ -39,8 +37,9 @@ public class Recurso {
@Column(nullable = false) @Column(nullable = false)
private String autor; private String autor;
private String fotoUrl; @Lob
@Column(name = "foto", columnDefinition = "LONGBLOB")
private byte[] foto;
@ElementCollection(targetClass = Genero.class) @ElementCollection(targetClass = Genero.class)
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
...@@ -48,20 +47,19 @@ public class Recurso { ...@@ -48,20 +47,19 @@ public class Recurso {
@Column(name = "genero") @Column(name = "genero")
private Set<Genero> generos = new HashSet<>(); private Set<Genero> generos = new HashSet<>();
@OneToMany(mappedBy = "recurso", cascade = CascadeType.ALL, orphanRemoval = true) @OneToMany(mappedBy = "recurso", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Capitulo> capitulosManga = new ArrayList<>(); private List<Capitulo> capitulosManga = new ArrayList<>();
@OneToMany(mappedBy = "recurso", cascade = CascadeType.ALL, orphanRemoval = true) @OneToMany(mappedBy = "recurso", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Capitulo> capitulosAnime = new ArrayList<>(); private List<Capitulo> capitulosAnime = new ArrayList<>();
public Recurso(String titulo, String descripcion, LocalDate fechaPublicacion, String autor, String fotoUrl) { public Recurso(String titulo, String descripcion, LocalDate fechaPublicacion, String autor, byte[] foto) {
this.titulo = titulo; this.titulo = titulo;
this.descripcion = descripcion; this.descripcion = descripcion;
this.fechaPublicacion = fechaPublicacion; this.fechaPublicacion = fechaPublicacion;
this.autor = autor; this.autor = autor;
this.fotoUrl = fotoUrl; this.foto = foto;
} }
}
}
...@@ -3,12 +3,15 @@ package com.ujaen.tfg.mangaffinity.repositorios; ...@@ -3,12 +3,15 @@ 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.FuenteCapitulo;
import com.ujaen.tfg.mangaffinity.entidades.TipoRecurso; import com.ujaen.tfg.mangaffinity.entidades.TipoRecurso;
import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos;
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;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Repository @Repository
@Transactional @Transactional
...@@ -24,59 +27,108 @@ public class RepositorioCapitulo { ...@@ -24,59 +27,108 @@ public class RepositorioCapitulo {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Capitulo> obtenerCapitulosRecurso(Long recursoId) { public List<Capitulo> obtenerCapitulosRecurso(Long recursoId) {
return em.createQuery( return em.createQuery(
"SELECT c FROM Capitulo c WHERE c.recurso.id = :recursoId ORDER BY c.numero ASC", "SELECT c FROM Capitulo c WHERE c.recurso.id = :recursoId ORDER BY c.numero ASC",
Capitulo.class) Capitulo.class)
.setParameter("recursoId", recursoId) .setParameter("recursoId", recursoId)
.getResultList(); .getResultList();
} }
@Transactional public void actualizarCapitulo(Capitulo capituloModificado) {
public Capitulo actualizarCapitulo(Capitulo capitulo) { Capitulo capitulo = em.find(Capitulo.class, capituloModificado.getId());
return em.merge(capitulo);
if (capitulo != null) {
capitulo.setNumero(capituloModificado.getNumero());
capitulo.setTitulo(capituloModificado.getTitulo());
capitulo.setTipo(capituloModificado.getTipo());
capitulo.setActivo(capituloModificado.getActivo());
List<FuenteCapitulo> fuentesActuales = new ArrayList<>(capitulo.getFuentes());
for (FuenteCapitulo fuenteExistente : fuentesActuales) {
boolean sigueExistiendo = capituloModificado.getFuentes().stream()
.anyMatch(f -> f.getNombreFuente().equals(fuenteExistente.getNombreFuente()));
if (!sigueExistiendo) {
capitulo.getFuentes().remove(fuenteExistente);
em.remove(em.contains(fuenteExistente) ? fuenteExistente : em.merge(fuenteExistente));
}
}
for (FuenteCapitulo nuevaFuente : capituloModificado.getFuentes()) {
boolean existe = fuentesActuales.stream()
.anyMatch(f -> f.getNombreFuente().equals(nuevaFuente.getNombreFuente()));
if (!existe) {
nuevaFuente.setCapitulo(capitulo);
em.persist(nuevaFuente);
capitulo.getFuentes().add(nuevaFuente);
}
}
em.merge(capitulo);
em.flush();
}
}
public void eliminarFuente(FuenteCapitulo fuente) {
FuenteCapitulo fuenteEncontrada = em.find(FuenteCapitulo.class, fuente.getId());
if (fuenteEncontrada != null) {
em.remove(fuenteEncontrada);
}
} }
@Transactional @Transactional
public void borrarCapitulo(Capitulo capitulo) { public void borrarCapitulo(Capitulo capitulo) {
capitulo = em.merge(capitulo); // Asegurar que la entidad está en el contexto persistente capitulo = em.merge(capitulo);
// 🔴 Asegurar que el capítulo tiene fuentes antes de eliminarlas
List<FuenteCapitulo> fuentes = em.createQuery( List<FuenteCapitulo> fuentes = em.createQuery(
"SELECT f FROM FuenteCapitulo f WHERE f.capitulo = :capitulo", FuenteCapitulo.class) "SELECT f FROM FuenteCapitulo f WHERE f.capitulo = :capitulo", FuenteCapitulo.class)
.setParameter("capitulo", capitulo) .setParameter("capitulo", capitulo)
.getResultList(); .getResultList();
for (FuenteCapitulo fuente : fuentes) { for (FuenteCapitulo fuente : fuentes) {
em.remove(fuente); // 🔴 Eliminar cada fuente individualmente em.remove(fuente);
} }
em.flush();
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);
} }
public void actualizarFuente(FuenteCapitulo fuente) {
FuenteCapitulo existente = em.find(FuenteCapitulo.class, fuente.getId());
if (existente != null) {
existente.setUrlFuente(fuente.getUrlFuente());
em.merge(existente);
}
em.flush();
}
public void agregarFuente(FuenteCapitulo fuente) {
em.persist(fuente);
em.flush();
}
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Capitulo> obtenerCapitulosPorTipo(Long recursoId, TipoRecurso tipo) { public List<Capitulo> obtenerCapitulosPorTipo(Long recursoId, TipoRecurso tipo) {
return em.createQuery( return em.createQuery(
"SELECT c FROM Capitulo c WHERE c.recurso.id = :recursoId AND c.tipo = :tipo ORDER BY c.numero ASC", "SELECT c FROM Capitulo c WHERE c.recurso.id = :recursoId AND c.tipo = :tipo ORDER BY c.numero ASC",
Capitulo.class) Capitulo.class)
.setParameter("recursoId", recursoId) .setParameter("recursoId", recursoId)
.setParameter("tipo", tipo) .setParameter("tipo", tipo)
.getResultList(); .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);
} }
@Transactional(readOnly = true)
public FuenteCapitulo buscarFuentePorId(Long id) {
return em.find(FuenteCapitulo.class, id);
}
@Transactional
public void eliminarFuentePorId(Long id) {
FuenteCapitulo fuente = em.find(FuenteCapitulo.class, id);
if (fuente != null) {
em.remove(fuente);
}
}
} }
...@@ -17,4 +17,6 @@ public class DTOCapitulo { ...@@ -17,4 +17,6 @@ public class DTOCapitulo {
private String titulo; private String titulo;
private TipoRecurso tipo; private TipoRecurso tipo;
private List<DTOFuenteCapitulo> fuentes; private List<DTOFuenteCapitulo> fuentes;
private Boolean activo;
} }
...@@ -5,8 +5,8 @@ import com.ujaen.tfg.mangaffinity.entidades.FuenteCapitulo; ...@@ -5,8 +5,8 @@ import com.ujaen.tfg.mangaffinity.entidades.FuenteCapitulo;
import com.ujaen.tfg.mangaffinity.entidades.Recurso; import com.ujaen.tfg.mangaffinity.entidades.Recurso;
import com.ujaen.tfg.mangaffinity.entidades.Usuario; import com.ujaen.tfg.mangaffinity.entidades.Usuario;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -22,34 +22,35 @@ public class Mapper { ...@@ -22,34 +22,35 @@ public class Mapper {
} }
public DTORecurso dto(Recurso recurso) { public DTORecurso dto(Recurso recurso) {
String fotoBase64 = (recurso.getFoto() != null) ? Base64.getEncoder().encodeToString(recurso.getFoto()) : null;
return new DTORecurso( return new DTORecurso(
recurso.getId(), recurso.getId(),
recurso.getTitulo(), recurso.getTitulo(),
recurso.getDescripcion(), recurso.getDescripcion(),
recurso.getFechaPublicacion(), recurso.getFechaPublicacion(),
recurso.getAutor(), recurso.getAutor(),
recurso.getFotoUrl() , fotoBase64,
recurso.getGeneros() recurso.getGeneros()
); );
} }
public Recurso entity(DTORecurso dtoRecurso) { public Recurso entity(DTORecurso dtoRecurso) {
byte[] fotoBytes = (dtoRecurso.getFotoBase64() != null) ? Base64.getDecoder().decode(dtoRecurso.getFotoBase64()) : null;
Recurso recurso = new Recurso( Recurso recurso = new Recurso(
dtoRecurso.getTitulo(), dtoRecurso.getTitulo(),
dtoRecurso.getDescripcion(), dtoRecurso.getDescripcion(),
dtoRecurso.getFechaPublicacion(), dtoRecurso.getFechaPublicacion(),
dtoRecurso.getAutor(), dtoRecurso.getAutor(),
dtoRecurso.getFotoUrl() fotoBytes
); );
if (dtoRecurso.getGeneros() != null) { if (dtoRecurso.getGeneros() != null) {
recurso.getGeneros().addAll(dtoRecurso.getGeneros()); recurso.getGeneros().addAll(dtoRecurso.getGeneros());
} }
return recurso; return recurso;
} }
public DTOCapitulo dto(Capitulo capitulo) { public DTOCapitulo dto(Capitulo capitulo) {
return new DTOCapitulo( return new DTOCapitulo(
capitulo.getId(), capitulo.getId(),
...@@ -58,31 +59,34 @@ public class Mapper { ...@@ -58,31 +59,34 @@ public class Mapper {
capitulo.getTipo(), capitulo.getTipo(),
capitulo.getFuentes().stream() capitulo.getFuentes().stream()
.map(this::dto) .map(this::dto)
.collect(Collectors.toList()) .collect(Collectors.toList()),
capitulo.getActivo()
); );
} }
public Capitulo entity(DTOCapitulo dtoCapitulo, Recurso recurso) { public Capitulo entity(DTOCapitulo dtoCapitulo, Recurso recurso) {
Capitulo capitulo = new Capitulo( Capitulo capitulo = new Capitulo(
dtoCapitulo.getNumero(), dtoCapitulo.getNumero(),
dtoCapitulo.getTitulo(), dtoCapitulo.getTitulo(),
dtoCapitulo.getTipo(), dtoCapitulo.getTipo(),
new ArrayList<>(), new ArrayList<>(),
recurso recurso,
dtoCapitulo.getActivo() != null ? dtoCapitulo.getActivo() : Boolean.FALSE
); );
capitulo.setId(dtoCapitulo.getId());
if (dtoCapitulo.getFuentes() != null) { if (dtoCapitulo.getFuentes() != null) {
List<FuenteCapitulo> fuentes = dtoCapitulo.getFuentes().stream() for (DTOFuenteCapitulo dtoFuente : dtoCapitulo.getFuentes()) {
.map(dtoFuente -> entity(dtoFuente, capitulo)) // Llamamos al mapper de FuenteCapitulo FuenteCapitulo fuente = new FuenteCapitulo();
.toList(); fuente.setNombreFuente(dtoFuente.getNombreFuente());
capitulo.setFuentes(fuentes); fuente.setUrlFuente(dtoFuente.getUrlFuente());
fuente.setCapitulo(capitulo);
capitulo.getFuentes().add(fuente);
}
} }
return capitulo; return capitulo;
} }
public DTOFuenteCapitulo dto(FuenteCapitulo fuente) { public DTOFuenteCapitulo dto(FuenteCapitulo fuente) {
return new DTOFuenteCapitulo(fuente.getNombreFuente(), fuente.getUrlFuente()); return new DTOFuenteCapitulo(fuente.getNombreFuente(), fuente.getUrlFuente());
} }
...@@ -91,10 +95,7 @@ public class Mapper { ...@@ -91,10 +95,7 @@ public class Mapper {
return new FuenteCapitulo(null, dtoFuente.getNombreFuente(), dtoFuente.getUrlFuente(), capitulo); return new FuenteCapitulo(null, dtoFuente.getNombreFuente(), dtoFuente.getUrlFuente(), capitulo);
} }
public List<DTOCapitulo> dtoLista(List<Capitulo> capitulos) { public List<DTOCapitulo> dtoLista(List<Capitulo> capitulos) {
return capitulos.stream().map(this::dto).collect(Collectors.toList()); return capitulos.stream().map(this::dto).collect(Collectors.toList());
} }
} }
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