Commit d91eb063 by Rubén Ramírez

fix: [RecursosController]: Corregido el controlador debido a la incorrecta división por capas

parent 069bc18e
......@@ -3,6 +3,7 @@ package com.ujaen.tfg.mangaffinity.rest;
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.excepciones.RecursoYaExiste;
import com.ujaen.tfg.mangaffinity.rest.DTO.*;
import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -26,8 +27,17 @@ public class RecursosController {
@Autowired
private Mapper mapper;
/**
* Crea un nuevo recurso en el sistema.
* Devuelve:
* - 201 CREATED si el recurso se crea correctamente.
* - 400 BAD REQUEST si el formato de la imagen no es válido.
* - 409 CONFLICT si el recurso ya existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
* Permite cargar una imagen opcional en formato JPEG o PNG junto con los datos del recurso.
*/
@PostMapping(value = "/", consumes = {"multipart/form-data"})
public ResponseEntity<String> crearRecurso(
public ResponseEntity<Void> crearRecurso(
@RequestPart("recurso") DTORecurso recursoDTO,
@RequestPart(value = "foto", required = false) MultipartFile foto) {
try {
......@@ -36,89 +46,146 @@ public class RecursosController {
if (foto != null && !foto.isEmpty()) {
String mimeType = foto.getContentType();
if (mimeType == null || (!mimeType.equals("image/jpeg") && !mimeType.equals("image/png"))) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Solo se permiten imágenes JPEG o PNG.");
return ResponseEntity.badRequest().build();
}
fotoBytes = foto.getBytes();
}
Recurso nuevoRecurso = new Recurso(
recursoDTO.getTitulo(),
recursoDTO.getDescripcion(),
recursoDTO.getFechaPublicacion(),
recursoDTO.getAutor(),
fotoBytes
);
nuevoRecurso.setGeneros(recursoDTO.getGeneros());
Recurso nuevoRecurso = mapper.entity(recursoDTO);
nuevoRecurso.setFoto(fotoBytes);
servicioRecursos.crearRecurso(nuevoRecurso);
return ResponseEntity.status(HttpStatus.CREATED).build();
} catch (RecursoYaExiste e) {
return ResponseEntity.status(HttpStatus.CONFLICT).build();
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Busca recursos por título.
* Devuelve:
* - 200 OK con la lista de recursos si hay coincidencias.
* - 204 NO CONTENT si no se encuentran recursos con ese título.
* Convierte los recursos encontrados a DTO antes de retornarlos.
*/
@GetMapping("/titulo/{titulo}")
public ResponseEntity<List<DTORecurso>> buscarPorTitulo(@PathVariable String titulo) {
try {
List<Recurso> recursos = servicioRecursos.buscarRecursoPorTitulo(titulo);
if (recursos.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Collections.emptyList());
}
if (recursos.isEmpty()) return ResponseEntity.noContent().build();
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Obtiene los capítulos de un recurso separados por tipo (MANGA o ANIME).
* Devuelve:
* - 200 OK con los capítulos organizados en un mapa por tipo.
* - 204 NO CONTENT si el recurso no tiene capítulos de ningún tipo.
* - 404 NOT FOUND si el recurso no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{id}/capitulos/tipos")
public ResponseEntity<Map<String, List<DTOCapitulo>>> obtenerCapitulosPorTipo(@PathVariable Long id) {
try {
if (!servicioRecursos.existeRecurso(id)) return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); // 404 Not Found
List<Capitulo> capitulosManga = servicioRecursos.obtenerCapitulosDeRecursoPorTipo(id, TipoRecurso.MANGA);
List<Capitulo> capitulosAnime = servicioRecursos.obtenerCapitulosDeRecursoPorTipo(id, TipoRecurso.ANIME);
if (capitulosManga.isEmpty() && capitulosAnime.isEmpty()) return ResponseEntity.noContent().build();
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 (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Busca recursos por género.
* Devuelve:
* - 200 OK con la lista de recursos si hay coincidencias.
* - 204 NO CONTENT si no se encuentran recursos en el género especificado.
* - 400 BAD REQUEST si el género proporcionado no es válido.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/genero/{genero}")
public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) {
public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable String genero) {
try {
Genero generoEnum;
try {
List<Recurso> recursos = servicioRecursos.buscarRecursoPorGenero(genero);
generoEnum = Genero.valueOf(genero.toUpperCase());
} catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
List<Recurso> recursos = servicioRecursos.buscarRecursoPorGenero(generoEnum);
if (recursos.isEmpty()) return ResponseEntity.noContent().build();
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Busca recursos publicados dentro de un rango de fechas.
* Devuelve:
* - 200 OK con la lista de recursos si hay coincidencias.
* - 204 NO CONTENT si no se encuentran recursos en el rango especificado.
* - 400 BAD REQUEST si la fecha de inicio es posterior a la fecha de fin.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/fecha")
public ResponseEntity<List<DTORecurso>> buscarPorRangoFechas(@RequestParam LocalDate inicio, @RequestParam LocalDate fin) {
public ResponseEntity<List<DTORecurso>> buscarPorRangoFechas(
@RequestParam(required = false) LocalDate inicio,
@RequestParam(required = false) LocalDate fin) {
try {
if (inicio == null) inicio = LocalDate.of(1900, 1, 1);
if (fin == null) fin = LocalDate.now();
if (inicio.isAfter(fin)) return ResponseEntity.badRequest().build();
List<Recurso> recursos = servicioRecursos.buscarRecursoPorRangoFechas(inicio, fin);
if (recursos.isEmpty()) return ResponseEntity.noContent().build();
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Busca recursos por autor.
* Devuelve:
* - 200 OK con la lista de recursos si hay coincidencias.
* - 204 NO CONTENT si no se encuentran recursos del autor especificado.
* - 400 BAD REQUEST si el nombre del autor es nulo o vacío.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/autor/{autor}")
public ResponseEntity<List<DTORecurso>> buscarPorAutor(@PathVariable String autor) {
try {
if (autor == null || autor.trim().isEmpty()) return ResponseEntity.badRequest().build();
List<Recurso> recursos = servicioRecursos.buscarRecursoPorAutor(autor);
if (recursos.isEmpty()) return ResponseEntity.noContent().build();
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) {
......@@ -126,78 +193,99 @@ public class RecursosController {
}
}
/**
* Busca un recurso por su ID.
* Devuelve:
* - 200 OK con el recurso si existe.
* - 404 NOT FOUND si el recurso no está registrado.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{id}")
public ResponseEntity<DTORecurso> buscarRecursoPorId(@PathVariable Long id) {
try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(id);
if (recurso == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
return ResponseEntity.ok(mapper.dto(recurso));
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Elimina un recurso del sistema por su ID.
* Devuelve:
* - 204 NO CONTENT si el recurso se elimina correctamente.
* - 404 NOT FOUND si el recurso no existe.
* - 403 FORBIDDEN si el usuario no tiene permisos para eliminarlo.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> borrarRecurso(@PathVariable Long id) {
try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(id);
if (recurso == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
servicioRecursos.borrarRecurso(id);
return ResponseEntity.noContent().build();
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (SecurityException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Modifica un recurso existente en el sistema.
* Devuelve:
* - 200 OK con el recurso modificado si la actualización es exitosa.
* - 400 BAD REQUEST si el formato de la imagen no es válido.
* - 404 NOT FOUND si el recurso no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@PutMapping(value = "/{id}", consumes = {"multipart/form-data"})
public ResponseEntity<DTORecurso> modificarRecurso(
@PathVariable Long id,
@RequestPart("recurso") DTORecurso dtoRecurso,
@RequestPart(value = "foto", required = false) MultipartFile foto) {
try {
Recurso recursoExistente = servicioRecursos.buscarRecursoPorId(id);
if (recursoExistente == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
byte[] fotoBytes = null;
// Si hay una nueva imagen, actualizarla
if (foto != null && !foto.isEmpty()) {
String mimeType = foto.getContentType();
if (mimeType == null || (!mimeType.equals("image/jpeg") && !mimeType.equals("image/png"))) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
String mimeType = Optional.ofNullable(foto.getContentType()).orElse("");
if (!mimeType.equals("image/jpeg") && !mimeType.equals("image/png")) {
return ResponseEntity.badRequest().build();
}
recursoExistente.setFoto(foto.getBytes());
fotoBytes = foto.getBytes();
}
// Actualizar otros campos
recursoExistente.setTitulo(dtoRecurso.getTitulo());
recursoExistente.setDescripcion(dtoRecurso.getDescripcion());
recursoExistente.setFechaPublicacion(dtoRecurso.getFechaPublicacion());
recursoExistente.setAutor(dtoRecurso.getAutor());
recursoExistente.setGeneros(dtoRecurso.getGeneros());
// Guardar cambios en la BD
Recurso recursoModificado = servicioRecursos.modificarRecurso(id, recursoExistente);
Recurso recursoModificado = servicioRecursos.modificarRecurso(
id,
mapper.entity(dtoRecurso),
fotoBytes
);
return ResponseEntity.ok(mapper.dto(recursoModificado));
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.notFound().build();
}
}
/**
* Obtiene la lista de todos los recursos disponibles.
* Devuelve:
* - 200 OK con la lista de recursos si existen.
* - 204 NO CONTENT si no hay recursos disponibles.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping
public ResponseEntity<List<DTORecurso>> obtenerRecursos() {
try {
List<Recurso> recursos = servicioRecursos.obtenerListadoRecursos();
if (recursos.isEmpty()) return ResponseEntity.noContent().build();
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) {
......@@ -205,33 +293,46 @@ public class RecursosController {
}
}
/**
* Añade un nuevo capítulo a un recurso.
* Devuelve:
* - 201 CREATED si el capítulo se añade correctamente.
* - 404 NOT FOUND si el recurso no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@PostMapping("/{id}/capitulos")
public ResponseEntity<String> anadirCapitulo(@PathVariable Long id, @RequestBody DTOCapitulo dtoCapitulo) {
public ResponseEntity<Void> anadirCapitulo(@PathVariable Long id, @RequestBody DTOCapitulo dtoCapitulo) {
try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(id);
if (recurso == null) {
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).body("Capítulo añadido correctamente");
return ResponseEntity.status(HttpStatus.CREATED).build();
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Recurso no existe");
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error interno del servidor: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Obtiene la lista de capítulos de un recurso.
* Devuelve:
* - 200 OK con la lista de capítulos si existen.
* - 204 NO CONTENT si el recurso no tiene capítulos.
* - 404 NOT FOUND si el recurso no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{id}/capitulos")
public ResponseEntity<List<DTOCapitulo>> obtenerCapitulosDeRecurso(@PathVariable Long id) {
try {
List<Capitulo> capitulos = servicioRecursos.obtenerCapitulosDeRecurso(id);
List<DTOCapitulo> dtoCapitulos = capitulos.stream().map(mapper::dto).toList();
if (capitulos.isEmpty()) return ResponseEntity.noContent().build();
List<DTOCapitulo> dtoCapitulos = capitulos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoCapitulos);
} catch (RecursoNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Collections.emptyList());
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
......@@ -242,113 +343,61 @@ public class RecursosController {
@PathVariable Long recursoId,
@PathVariable Long id,
@RequestBody DTOCapitulo dtoCapitulo) {
if (!id.equals(dtoCapitulo.getId())) {
return ResponseEntity.badRequest().build();
}
if (!id.equals(dtoCapitulo.getId())) return ResponseEntity.badRequest().build();
try {
Recurso recurso = servicioRecursos.buscarRecursoPorId(recursoId);
if (recurso == null) {
return ResponseEntity.notFound().build();
}
Capitulo capitulo = servicioRecursos.buscarCapituloPorId(id);
capitulo.setNumero(dtoCapitulo.getNumero());
capitulo.setTitulo(dtoCapitulo.getTitulo());
capitulo.setTipo(dtoCapitulo.getTipo());
capitulo.setActivo(dtoCapitulo.getActivo());
List<FuenteCapitulo> fuentesActuales = new ArrayList<>(capitulo.getFuentes());
List<FuenteCapitulo> fuentesAEliminar = new ArrayList<>();
for (FuenteCapitulo fuenteExistente : fuentesActuales) {
boolean sigueExistiendo = dtoCapitulo.getFuentes().stream()
.anyMatch(f -> f.getNombreFuente().equals(fuenteExistente.getNombreFuente()));
if (!sigueExistiendo) {
fuentesAEliminar.add(fuenteExistente);
}
}
for (FuenteCapitulo fuente : fuentesAEliminar) {
capitulo.getFuentes().remove(fuente);
servicioRecursos.eliminarFuente(fuente.getId());
}
for (DTOFuenteCapitulo dtoFuente : dtoCapitulo.getFuentes()) {
FuenteCapitulo fuenteExistente = fuentesActuales.stream()
.filter(f -> f.getNombreFuente().equals(dtoFuente.getNombreFuente()))
.findFirst()
.orElse(null);
if (fuenteExistente != null) {
if (!fuenteExistente.getUrlFuente().equals(dtoFuente.getUrlFuente())) {
fuenteExistente.setUrlFuente(dtoFuente.getUrlFuente());
servicioRecursos.actualizarFuente(fuenteExistente);
}
} else {
FuenteCapitulo nuevaFuente = new FuenteCapitulo();
nuevaFuente.setNombreFuente(dtoFuente.getNombreFuente());
nuevaFuente.setUrlFuente(dtoFuente.getUrlFuente());
nuevaFuente.setCapitulo(capitulo);
servicioRecursos.agregarFuente(nuevaFuente);
capitulo.getFuentes().add(nuevaFuente);
}
}
servicioRecursos.modificarCapitulo(capitulo);
return ResponseEntity.ok(mapper.dto(capitulo));
} catch (CapituloNoExiste e) {
Capitulo capituloModificado = mapper.entity(dtoCapitulo, servicioRecursos.buscarRecursoPorId(recursoId));
servicioRecursos.modificarCapitulo(recursoId, capituloModificado);
return ResponseEntity.ok(mapper.dto(capituloModificado));
} catch (RecursoNoExiste | CapituloNoExiste e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Obtiene un capítulo específico de un recurso por su ID.
* Devuelve:
* - 200 OK con el capítulo si existe.
* - 404 NOT FOUND si el recurso o el capítulo no existen, o si el capítulo no pertenece al recurso indicado.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{recursoId}/capitulos/{capituloId}")
public ResponseEntity<DTOCapitulo> obtenerCapituloPorId(
@PathVariable Long recursoId,
@PathVariable Long capituloId) {
try {
// Verificar si el recurso existe
Recurso recurso = servicioRecursos.buscarRecursoPorId(recursoId);
if (recurso == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.build(); // Recurso no encontrado
}
Capitulo capitulo = servicioRecursos.buscarCapituloPorId(capituloId);
if (capitulo == null || !capitulo.getRecurso().getId().equals(recursoId)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.build(); // Capítulo no encontrado o no pertenece al recurso
}
if (!capitulo.getRecurso().getId().equals(recursoId)) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.ok(mapper.dto(capitulo));
} catch (RecursoNoExiste | CapituloNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // Error interno del servidor
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* Obtiene la lista de todos los géneros disponibles.
* Devuelve:
* - 200 OK con la lista de géneros si existen.
* - 204 NO CONTENT si no hay géneros disponibles.
* - 500 INTERNAL SERVER ERROR en caso de fallo inesperado.
*/
@GetMapping("/generos")
public ResponseEntity<List<String>> obtenerGeneros() {
try {
List<String> generos = servicioRecursos.obtenerGeneros();
if (generos.isEmpty()) return ResponseEntity.noContent().build();
return ResponseEntity.ok(generos);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
\ No newline at end of file
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