Commit 069bc18e by Rubén Ramírez

fix: [ServicioRecursos]: Corregidoel servicio debido a la incorrecta división por capas

parent 945fe127
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.*;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste;
import com.ujaen.tfg.mangaffinity.repositorios.RepositorioCapitulo; import com.ujaen.tfg.mangaffinity.repositorios.RepositorioCapitulo;
import com.ujaen.tfg.mangaffinity.repositorios.RepositorioRecurso; import com.ujaen.tfg.mangaffinity.repositorios.RepositorioRecurso;
import jakarta.validation.Valid; import jakarta.validation.Valid;
...@@ -13,6 +12,7 @@ import java.time.LocalDate; ...@@ -13,6 +12,7 @@ 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.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
...@@ -24,162 +24,246 @@ public class ServicioRecursos { ...@@ -24,162 +24,246 @@ public class ServicioRecursos {
@Autowired @Autowired
RepositorioCapitulo repositorioCapitulo; RepositorioCapitulo repositorioCapitulo;
/**
* @brief Crea un nuevo recurso en el sistema.
* @param recurso Objeto Recurso con los datos a registrar.
* @throws RecursoYaExiste Si el recurso ya está registrado con el mismo título, autor y fecha de publicación.
*/
@Transactional @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 if (repositorioRecurso.existeRecurso(recurso.getTitulo(), recurso.getAutor(), recurso.getFechaPublicacion())) {
List<Recurso> recursosExistentes = repositorioRecurso.buscarPorTitulo(recurso.getTitulo()); throw new RecursoYaExiste();
for (Recurso r : recursosExistentes) {
if (r.getAutor().equals(recurso.getAutor()) &&
r.getFechaPublicacion().equals(recurso.getFechaPublicacion())) {
return;
}
} }
repositorioRecurso.crear(recurso); repositorioRecurso.crear(recurso);
} }
public Recurso buscarRecursoPorId(Long id) {return repositorioRecurso.buscarPorId(id);} /**
* @brief Busca un recurso por su ID.
* @param id Identificador del recurso.
* @return Optional con el recurso si existe, vacío si no se encuentra.
*/
public Recurso buscarRecursoPorId(Long id) {
return repositorioRecurso.buscarPorId(id)
.orElseThrow(RecursoNoExiste::new);
}
/**
* @brief Busca recursos por título.
* @param titulo Título del recurso a buscar.
* @return Lista de recursos que coinciden con el título, hasta un máximo de 50.
* Devuelve una lista vacía si el título es nulo o vacío.
*/
public List<Recurso> buscarRecursoPorTitulo(String titulo) { public List<Recurso> buscarRecursoPorTitulo(String titulo) {
return repositorioRecurso.buscarPorTitulo(titulo); if (titulo == null || titulo.trim().isEmpty()) {
return List.of();
}
return repositorioRecurso.buscarPorTitulo(titulo, 50);
} }
/**
* @brief Busca recursos por autor.
* @param autor Nombre del autor a buscar.
* @return Lista de recursos del autor, hasta un máximo de 50.
* Devuelve una lista vacía si el autor es nulo o vacío.
*/
public List<Recurso> buscarRecursoPorAutor(String autor) { public List<Recurso> buscarRecursoPorAutor(String autor) {
return repositorioRecurso.buscarPorAutor(autor); if (autor == null || autor.trim().isEmpty()) {
return List.of();
}
return repositorioRecurso.buscarPorAutor(autor, 50);
} }
/**
* @brief Busca recursos por género.
* @param genero Género del recurso a buscar.
* @return Lista de recursos que pertenecen al género especificado. Devuelve una lista vacía si el género es nulo.
*/
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarRecursoPorGenero(Genero genero) { public List<Recurso> buscarRecursoPorGenero(Genero genero) {
List<Recurso> recursos = repositorioRecurso.buscarPorGenero(genero); if (genero == null) {
return List.of();
for (int i = 0; i < recursos.size(); i++) {
recursos.set(i, repositorioRecurso.merge(recursos.get(i)));
recursos.get(i).getGeneros().size();
} }
return repositorioRecurso.buscarPorGenero(genero);
return recursos;
} }
/**
* @brief Busca recursos publicados dentro de un rango de fechas.
* @param fechaInicio Fecha de inicio del rango (opcional, por defecto 01/01/1900).
* @param fechaFin Fecha de fin del rango (opcional, por defecto la fecha actual).
* @return Lista de recursos publicados en el rango especificado, hasta un máximo de 50.
*/
public List<Recurso> buscarRecursoPorRangoFechas(LocalDate fechaInicio, LocalDate fechaFin) { public List<Recurso> buscarRecursoPorRangoFechas(LocalDate fechaInicio, LocalDate fechaFin) {
return repositorioRecurso.buscarPorRangoFechas(fechaInicio, fechaFin); if (fechaInicio == null) fechaInicio = LocalDate.of(1900, 1, 1);
if (fechaFin == null) fechaFin = LocalDate.now();
return repositorioRecurso.buscarPorRangoFechas(fechaInicio, fechaFin, 50);
} }
/**
* @brief Elimina un recurso del sistema por su ID.
* @param id Identificador del recurso a eliminar.
* @throws RecursoNoExiste Si el recurso no se encuentra en la base de datos.
*/
@Transactional @Transactional
public boolean borrarRecurso(Long id) { public void borrarRecurso(Long id) {
Recurso recurso = buscarRecursoPorId(id); Recurso recurso = repositorioRecurso.buscarPorId(id)
if (recurso != null) { .orElseThrow(RecursoNoExiste::new);
repositorioRecurso.borrarRecurso(recurso);
return true; repositorioRecurso.borrarRecurso(recurso);
}
return false;
} }
/**
* @brief Modifica los datos de un recurso existente.
* @param id Identificador del recurso a modificar.
* @param nuevosDatos Objeto Recurso con los nuevos datos a actualizar.
* @return Recurso actualizado.
* @throws RecursoNoExiste Si el recurso no se encuentra en la base de datos.
* Solo se actualizan los campos no nulos proporcionados en nuevosDatos.
*/
@Transactional @Transactional
public Recurso modificarRecurso(Long id, Recurso nuevosDatos) { public Recurso modificarRecurso(Long id, Recurso nuevosDatos, byte[] fotoBytes) {
Recurso recursoExistente = repositorioRecurso.buscarPorId(id); Recurso recursoExistente = repositorioRecurso.buscarPorId(id)
if (recursoExistente == null) { .orElseThrow(RecursoNoExiste::new);
throw new RecursoNoExiste();
}
if (nuevosDatos.getTitulo() != null) { Optional.ofNullable(nuevosDatos.getTitulo()).ifPresent(recursoExistente::setTitulo);
recursoExistente.setTitulo(nuevosDatos.getTitulo()); Optional.ofNullable(nuevosDatos.getDescripcion()).ifPresent(recursoExistente::setDescripcion);
} Optional.ofNullable(nuevosDatos.getFechaPublicacion()).ifPresent(recursoExistente::setFechaPublicacion);
if (nuevosDatos.getDescripcion() != null) { Optional.ofNullable(nuevosDatos.getAutor()).ifPresent(recursoExistente::setAutor);
recursoExistente.setDescripcion(nuevosDatos.getDescripcion()); Optional.ofNullable(nuevosDatos.getGeneros()).ifPresent(recursoExistente::setGeneros);
}
if (nuevosDatos.getFechaPublicacion() != null) { if (fotoBytes != null && fotoBytes.length > 0) recursoExistente.setFoto(fotoBytes);
recursoExistente.setFechaPublicacion(nuevosDatos.getFechaPublicacion());
}
if (nuevosDatos.getAutor() != null) {
recursoExistente.setAutor(nuevosDatos.getAutor());
}
if (nuevosDatos.getGeneros() != null ) {
recursoExistente.setGeneros(nuevosDatos.getGeneros());
}
return repositorioRecurso.modificarRecurso(recursoExistente); return repositorioRecurso.modificarRecurso(recursoExistente);
} }
/**
* @brief Obtiene la lista completa de recursos.
* @return Lista de todos los recursos almacenados en el sistema.
*/
public List<Recurso> obtenerListadoRecursos() { public List<Recurso> obtenerListadoRecursos() {
return repositorioRecurso.listarRecursos(); return repositorioRecurso.listarRecursos();
} }
/**
* @brief Actualiza la foto de un recurso.
* @param recursoId Identificador del recurso a modificar.
* @param nuevaFoto Array de bytes con la nueva imagen del recurso.
* @throws IllegalArgumentException Si la foto es nula o está vacía.
* @throws RecursoNoExiste Si el recurso no se encuentra en la base de datos.
*/
@Transactional @Transactional
public void actualizarFotoRecurso(Long recursoId, byte[] nuevaFoto) { public void actualizarFotoRecurso(Long recursoId, byte[] nuevaFoto) {
Recurso recurso = repositorioRecurso.buscarPorId(recursoId); if (nuevaFoto == null || nuevaFoto.length == 0) {
if (recurso != null) { throw new FotoInvalida();
recurso.setFoto(nuevaFoto);
repositorioRecurso.modificarRecurso(recurso);
} }
Recurso recurso = repositorioRecurso.buscarPorId(recursoId)
.orElseThrow(RecursoNoExiste::new);
recurso.setFoto(nuevaFoto);
repositorioRecurso.modificarRecurso(recurso);
} }
/**
* @brief Obtiene los capítulos de un recurso según su tipo.
* @param recursoId Identificador del recurso.
* @param tipo Tipo de recurso a filtrar.
* @return Lista de capítulos del recurso para el tipo especificado. Devuelve una lista vacía si no hay capítulos.
* @throws RecursoSinTipo Si el tipo de recurso es nulo.
*/
@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); if (tipo == null) {
throw new RecursoSinTipo();
}
return Optional.ofNullable(repositorioCapitulo.obtenerCapitulosPorTipo(recursoId, tipo))
.orElse(List.of());
} }
/**
* @brief Obtiene todos los capítulos de un recurso.
* @param recursoId Identificador del recurso.
* @return Lista de capítulos asociados al recurso. Devuelve una lista vacía si no hay capítulos.
* Inicializa las fuentes de cada capítulo si la relación es Lazy.
*/
@Transactional @Transactional
public List<Capitulo> obtenerCapitulosDeRecurso(Long recursoId) { public List<Capitulo> obtenerCapitulosDeRecurso(Long recursoId) {
List<Capitulo> capitulos = repositorioCapitulo.obtenerCapitulosRecurso(recursoId); List<Capitulo> capitulos = Optional.ofNullable(repositorioCapitulo.obtenerCapitulosRecurso(recursoId))
.orElse(List.of());
capitulos.forEach(capitulo -> capitulo.getFuentes().size()); capitulos.forEach(capitulo -> capitulo.getFuentes().size());
return capitulos; return capitulos;
} }
/**
* @brief Obtiene la lista de todos los géneros disponibles.
* @return Lista de nombres de los géneros en formato de cadena.
*/
public List<String> obtenerGeneros() { public List<String> obtenerGeneros() {
return Arrays.stream(Genero.values()) return List.of(Genero.values()).stream()
.map(Enum::name) .map(Enum::name)
.collect(Collectors.toList()); .toList();
} }
/**
* @brief Añade un nuevo capítulo a un recurso.
* @param recursoId Identificador del recurso al que se añadirá el capítulo.
* @param nuevoCapitulo Objeto Capitulo con los datos a registrar.
* @throws IllegalArgumentException Si el recursoId es nulo o negativo.
* @throws IllegalArgumentException Si el capítulo es nulo.
* @throws RecursoNoExiste Si el recurso no se encuentra en la base de datos.
* Asigna el recurso al capítulo y establece las relaciones con sus fuentes antes de guardarlo.
*/
@Transactional @Transactional
public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) { public void anadirCapitulo(Long recursoId, Capitulo nuevoCapitulo) {
Recurso recurso = repositorioRecurso.buscarPorId(recursoId); if (recursoId == null || recursoId < 1) {
if (recurso == null) { throw new IllegalArgumentException("El ID del recurso no puede ser nulo o negativo.");
throw new RecursoNoExiste(); }
if (nuevoCapitulo == null) {
throw new CapituloInvalido();
} }
Recurso recurso = repositorioRecurso.buscarPorId(recursoId)
.orElseThrow(RecursoNoExiste::new);
nuevoCapitulo.setRecurso(recurso); nuevoCapitulo.setRecurso(recurso);
if (nuevoCapitulo.getFuentes() != null) { Optional.ofNullable(nuevoCapitulo.getFuentes()).ifPresent(fuentes ->
for (FuenteCapitulo fuente : nuevoCapitulo.getFuentes()) { fuentes.forEach(fuente -> fuente.setCapitulo(nuevoCapitulo))
fuente.setCapitulo(nuevoCapitulo); );
}
}
repositorioCapitulo.crearCapitulo(nuevoCapitulo); repositorioCapitulo.crearCapitulo(nuevoCapitulo);
} }
/**
* Modifica un capítulo existente dentro de un recurso.
* @param recursoId ID del recurso al que pertenece el capítulo.
* @param capituloModificado Entidad Capitulo con los nuevos datos.
* @return Capítulo actualizado.
* @throws RecursoNoExiste Si el recurso no existe.
* @throws CapituloNoExiste Si el capítulo no existe.
*/
@Transactional @Transactional
public void modificarCapitulo(Capitulo capituloModificado) { public void modificarCapitulo(Long recursoId, Capitulo capituloModificado) {
Capitulo capitulo = repositorioCapitulo.buscarPorId(capituloModificado.getId()); Recurso recurso = repositorioRecurso.buscarPorId(recursoId)
if (capitulo == null) { .orElseThrow(RecursoNoExiste::new);
throw new CapituloNoExiste();
} Capitulo capitulo = repositorioCapitulo.buscarPorId(capituloModificado.getId())
.orElseThrow(CapituloNoExiste::new);
capitulo.setNumero(capituloModificado.getNumero()); capitulo.setNumero(capituloModificado.getNumero());
capitulo.setTitulo(capituloModificado.getTitulo()); capitulo.setTitulo(capituloModificado.getTitulo());
capitulo.setTipo(capituloModificado.getTipo()); capitulo.setTipo(capituloModificado.getTipo());
capitulo.setActivo(capituloModificado.getActivo()); capitulo.setActivo(capituloModificado.getActivo());
List<FuenteCapitulo> fuentesActuales = new ArrayList<>(capitulo.getFuentes()); List<FuenteCapitulo> fuentesNuevas = capituloModificado.getFuentes() != null ? capituloModificado.getFuentes() : new ArrayList<>();
List<FuenteCapitulo> fuentesAEliminar = new ArrayList<>();
for (FuenteCapitulo fuenteExistente : fuentesActuales) {
boolean sigueExistiendo = capituloModificado.getFuentes().stream()
.anyMatch(f -> f.getNombreFuente().equals(fuenteExistente.getNombreFuente()));
if (!sigueExistiendo) { capitulo.getFuentes().removeIf(fuenteExistente ->
fuentesAEliminar.add(fuenteExistente); fuentesNuevas.stream().noneMatch(f -> f.getNombreFuente().equals(fuenteExistente.getNombreFuente()))
} );
}
for (FuenteCapitulo fuente : fuentesAEliminar) { for (FuenteCapitulo nuevaFuente : fuentesNuevas) {
repositorioCapitulo.eliminarFuente(fuente); boolean existe = capitulo.getFuentes().stream()
capitulo.getFuentes().remove(fuente);
}
for (FuenteCapitulo nuevaFuente : capituloModificado.getFuentes()) {
boolean existe = fuentesActuales.stream()
.anyMatch(f -> f.getNombreFuente().equals(nuevaFuente.getNombreFuente())); .anyMatch(f -> f.getNombreFuente().equals(nuevaFuente.getNombreFuente()));
if (!existe) { if (!existe) {
...@@ -191,42 +275,76 @@ public class ServicioRecursos { ...@@ -191,42 +275,76 @@ public class ServicioRecursos {
repositorioCapitulo.actualizarCapitulo(capitulo); repositorioCapitulo.actualizarCapitulo(capitulo);
} }
/**
* @brief Busca un capítulo por su ID.
* @param id Identificador del capítulo.
* @return Capitulo encontrado.
* @throws CapituloNoExiste Si el capítulo no se encuentra en la base de datos.
*/
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Capitulo buscarCapituloPorId(Long id) { public Capitulo buscarCapituloPorId(Long id) {
Capitulo capitulo = repositorioCapitulo.buscarPorId(id); return repositorioCapitulo.buscarPorId(id)
if (capitulo == null) { .orElseThrow(CapituloNoExiste::new);
throw new CapituloNoExiste();
}
return capitulo;
} }
/**
* @brief Actualiza la información de una fuente de un capítulo.
* @param fuente Objeto FuenteCapitulo con los datos actualizados.
* @throws IllegalArgumentException Si la fuente no existe en la base de datos.
*/
@Transactional @Transactional
public void actualizarFuente(FuenteCapitulo fuente) { public void actualizarFuente(FuenteCapitulo fuente) {
FuenteCapitulo fuenteExistente = repositorioCapitulo.buscarFuentePorId(fuente.getId()); FuenteCapitulo fuenteExistente = repositorioCapitulo.buscarFuentePorId(fuente.getId())
if (fuenteExistente != null) { .orElseThrow(FuenteNoExiste::new);
fuenteExistente.setUrlFuente(fuente.getUrlFuente());
repositorioCapitulo.actualizarFuente(fuenteExistente); fuenteExistente.setUrlFuente(fuente.getUrlFuente());
} repositorioCapitulo.actualizarFuente(fuenteExistente);
} }
/**
* @brief Elimina una fuente de un capítulo por su ID.
* @param id Identificador de la fuente a eliminar.
* Si la fuente existe, se elimina; en caso contrario, no realiza ninguna acción.
*/
@Transactional @Transactional
public void eliminarFuentePorId(Long id) { public void eliminarFuentePorId(Long id) {
FuenteCapitulo fuente = repositorioCapitulo.buscarFuentePorId(id); repositorioCapitulo.buscarFuentePorId(id)
if (fuente != null) { .ifPresent(fuente -> repositorioCapitulo.eliminarFuentePorId(id));
repositorioCapitulo.eliminarFuentePorId(id);
}
} }
/**
* @brief Agrega una nueva fuente a un capítulo.
* @param fuente Objeto FuenteCapitulo con la información de la nueva fuente.
* @throws IllegalArgumentException Si la fuente o su capítulo son nulos.
*/
@Transactional @Transactional
public void agregarFuente(FuenteCapitulo fuente) { public void agregarFuente(FuenteCapitulo fuente) {
if (fuente == null || fuente.getCapitulo() == null) {
throw new IllegalArgumentException("La fuente y su capítulo no pueden ser nulos.");
}
repositorioCapitulo.agregarFuente(fuente); repositorioCapitulo.agregarFuente(fuente);
} }
/**
* @brief Elimina una fuente de un capítulo por su ID.
* @param id Identificador de la fuente a eliminar.
* @throws IllegalArgumentException Si la fuente no existe en la base de datos.
*/
@Transactional @Transactional
public void eliminarFuente(Long id) { public void eliminarFuente(Long id) {
FuenteCapitulo fuente = repositorioCapitulo.buscarFuentePorId(id); repositorioCapitulo.buscarFuentePorId(id)
if (fuente != null) { .ifPresentOrElse(
repositorioCapitulo.eliminarFuentePorId(id); fuente -> repositorioCapitulo.eliminarFuentePorId(id),
} () -> { throw new FuenteNoExiste(); }
);
}
/**
* @brief Verifica si un recurso existe en la base de datos.
* @param id Identificador del recurso a buscar.
* @return true si el recurso existe, false si no.
*/
public boolean existeRecurso(Long id) {
return repositorioRecurso.buscarPorId(id).isPresent();
} }
} }
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