Commit ab607cc1 by Rubén Ramírez

fix: [Recursos]: Actualizada la manera de trabajar con las fotos para…

fix: [Recursos]: Actualizada la manera de trabajar con las fotos para almacenarlas también en la BBDD
parent 3a98e108
...@@ -6,7 +6,6 @@ import jakarta.persistence.EntityManager; ...@@ -6,7 +6,6 @@ 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.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
...@@ -28,17 +27,16 @@ public class RepositorioRecurso { ...@@ -28,17 +27,16 @@ public class RepositorioRecurso {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarPorTitulo(String titulo) { public List<Recurso> buscarPorTitulo(String titulo) {
return em.createQuery( return em.createQuery(
"SELECT r FROM Recurso r WHERE LOWER(r.titulo) LIKE LOWER(:titulo)", "SELECT r FROM Recurso r WHERE LOWER(r.titulo) LIKE LOWER(:titulo)",
Recurso.class) Recurso.class)
.setParameter("titulo", "%" + titulo + "%") .setParameter("titulo", "%" + titulo + "%")
.getResultList(); .getResultList();
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarPorAutor(String autor) { public List<Recurso> buscarPorAutor(String autor) {
return em.createQuery( return em.createQuery(
"SELECT r FROM Recurso r WHERE LOWER(r.autor) LIKE LOWER(:autor)", "SELECT r FROM Recurso r WHERE LOWER(r.autor) LIKE LOWER(:autor)",
Recurso.class) Recurso.class)
.setParameter("autor", "%" + autor + "%") .setParameter("autor", "%" + autor + "%")
.getResultList(); .getResultList();
...@@ -47,7 +45,7 @@ public class RepositorioRecurso { ...@@ -47,7 +45,7 @@ public class RepositorioRecurso {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarPorGenero(Genero genero) { public List<Recurso> buscarPorGenero(Genero genero) {
return em.createQuery( return em.createQuery(
"SELECT r FROM Recurso r JOIN r.generos g WHERE g = :genero", "SELECT r FROM Recurso r JOIN r.generos g WHERE g = :genero",
Recurso.class) Recurso.class)
.setParameter("genero", genero) .setParameter("genero", genero)
.getResultList(); .getResultList();
...@@ -56,7 +54,7 @@ public class RepositorioRecurso { ...@@ -56,7 +54,7 @@ public class RepositorioRecurso {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Recurso> buscarPorRangoFechas(LocalDate fechaInicio, LocalDate fechaFin) { public List<Recurso> buscarPorRangoFechas(LocalDate fechaInicio, LocalDate fechaFin) {
return em.createQuery( return em.createQuery(
"SELECT r FROM Recurso r WHERE r.fechaPublicacion BETWEEN :inicio AND :fin", "SELECT r FROM Recurso r WHERE r.fechaPublicacion BETWEEN :inicio AND :fin",
Recurso.class) Recurso.class)
.setParameter("inicio", fechaInicio) .setParameter("inicio", fechaInicio)
.setParameter("fin", fechaFin) .setParameter("fin", fechaFin)
......
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;
import com.ujaen.tfg.mangaffinity.entidades.Recurso; import com.ujaen.tfg.mangaffinity.entidades.Recurso;
import com.ujaen.tfg.mangaffinity.excepciones.RecursoNoExiste;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTORecursoEnBiblioteca; import com.ujaen.tfg.mangaffinity.rest.DTO.DTORecursoEnBiblioteca;
import com.ujaen.tfg.mangaffinity.rest.DTO.Mapper;
import com.ujaen.tfg.mangaffinity.servicios.ServicioBibliotecaPersonal; import com.ujaen.tfg.mangaffinity.servicios.ServicioBibliotecaPersonal;
import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos; import com.ujaen.tfg.mangaffinity.servicios.ServicioRecursos;
import com.ujaen.tfg.mangaffinity.servicios.ServicioUsuarios; import com.ujaen.tfg.mangaffinity.servicios.ServicioUsuarios;
...@@ -15,14 +12,14 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -15,14 +12,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; 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;
...@@ -32,9 +29,6 @@ public class BibliotecaPersonalController { ...@@ -32,9 +29,6 @@ public class BibliotecaPersonalController {
@Autowired @Autowired
private ServicioUsuarios servicioUsuarios; private ServicioUsuarios servicioUsuarios;
@Autowired
private Mapper mapper;
@PostMapping("/{usuarioId}/recursos/{recursoId}/categoria") @PostMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> anadirRecursoBiblioteca( public ResponseEntity<String> anadirRecursoBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -51,7 +45,6 @@ public class BibliotecaPersonalController { ...@@ -51,7 +45,6 @@ public class BibliotecaPersonalController {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} }
boolean yaExiste = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), dtoRecursoEnBiblioteca.getCategoria()) boolean yaExiste = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), dtoRecursoEnBiblioteca.getCategoria())
.stream() .stream()
.anyMatch(bpr -> bpr.getRecurso().getId().equals(recursoId)); .anyMatch(bpr -> bpr.getRecurso().getId().equals(recursoId));
...@@ -67,11 +60,9 @@ public class BibliotecaPersonalController { ...@@ -67,11 +60,9 @@ public class BibliotecaPersonalController {
} }
} }
@GetMapping("/{usuarioId}/recursos/categoria/{categoria}") @GetMapping("/{usuarioId}/recursos/categoria/{categoria}")
public ResponseEntity<List<DTORecursoEnBiblioteca>> listarRecursosPorCategoria( public ResponseEntity<List<DTORecursoEnBiblioteca>> listarRecursosPorCategoria(
@PathVariable Long usuarioId, @PathVariable String categoria) { // 🔥 Ahora es String @PathVariable Long usuarioId, @PathVariable String categoria) {
try { try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId); BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) { if (biblioteca == null) {
...@@ -82,17 +73,23 @@ public class BibliotecaPersonalController { ...@@ -82,17 +73,23 @@ public class BibliotecaPersonalController {
try { try {
categoriaEnum = Categoria.valueOf(categoria.toUpperCase()); categoriaEnum = Categoria.valueOf(categoria.toUpperCase());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // ⚠ Si la categoría no es válida return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
} }
List<BibliotecaPersonalRecurso> recursos = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), categoriaEnum); List<BibliotecaPersonalRecurso> recursos = servicioBibliotecaPersonal.listarPorCategoria(biblioteca.getId(), categoriaEnum);
List<DTORecursoEnBiblioteca> dtoRecursos = recursos.stream() List<DTORecursoEnBiblioteca> dtoRecursos = recursos.stream()
.map(bpr -> new DTORecursoEnBiblioteca( .map(bpr -> {
bpr.getRecurso().getId(), String fotoBase64 = (bpr.getRecurso().getFoto() != null && bpr.getRecurso().getFoto().length > 0)
bpr.getRecurso().getTitulo(), ? "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(bpr.getRecurso().getFoto())
bpr.getCategoria(), : null;
bpr.getRecurso().getFotoUrl() // 🔥 Aquí añadimos la imagen
)) return new DTORecursoEnBiblioteca(
bpr.getRecurso().getId(),
bpr.getRecurso().getTitulo(),
bpr.getCategoria(),
fotoBase64
);
})
.collect(Collectors.toList()); .collect(Collectors.toList());
...@@ -102,22 +99,6 @@ public class BibliotecaPersonalController { ...@@ -102,22 +99,6 @@ public class BibliotecaPersonalController {
} }
} }
@PutMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> cambiarCategoria(
@PathVariable Long usuarioId,
@PathVariable Long recursoId,
@RequestBody DTORecursoEnBiblioteca dtoRecurso) {
try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.cambiarCategoriaRecurso(biblioteca.getId(), recursoId, dtoRecurso.getCategoria());
return ResponseEntity.status(HttpStatus.OK).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@DeleteMapping("/{usuarioId}/recursos/{recursoId}") @DeleteMapping("/{usuarioId}/recursos/{recursoId}")
public ResponseEntity<String> eliminarRecursoDeBiblioteca( public ResponseEntity<String> eliminarRecursoDeBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -127,7 +108,7 @@ public class BibliotecaPersonalController { ...@@ -127,7 +108,7 @@ public class BibliotecaPersonalController {
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.eliminarRecursoDeBiblioteca(biblioteca.getId(), recursoId); servicioBibliotecaPersonal.eliminarRecursoDeBiblioteca(biblioteca.getId(), recursoId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); // Código 204 para eliminación exitosa return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
...@@ -137,38 +118,44 @@ public class BibliotecaPersonalController { ...@@ -137,38 +118,44 @@ public class BibliotecaPersonalController {
public ResponseEntity<DTORecursoEnBiblioteca> obtenerRecursoEnBiblioteca( public ResponseEntity<DTORecursoEnBiblioteca> obtenerRecursoEnBiblioteca(
@PathVariable Long usuarioId, @PathVariable Long recursoId) { @PathVariable Long usuarioId, @PathVariable Long recursoId) {
try { 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); BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) { if (biblioteca == null) {
logger.warn("No se encontró la biblioteca para el usuario con ID: {}", usuarioId); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
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); BibliotecaPersonalRecurso bibliotecaPersonalRecurso = servicioBibliotecaPersonal.buscarRecursoEnBiblioteca(biblioteca.getId(), recursoId);
if (bibliotecaPersonalRecurso == null) { 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);
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( DTORecursoEnBiblioteca dtoRecursoEnBiblioteca = new DTORecursoEnBiblioteca(
bibliotecaPersonalRecurso.getRecurso().getId(), bibliotecaPersonalRecurso.getRecurso().getId(),
bibliotecaPersonalRecurso.getRecurso().getTitulo(), bibliotecaPersonalRecurso.getRecurso().getTitulo(),
bibliotecaPersonalRecurso.getCategoria(), bibliotecaPersonalRecurso.getCategoria(),
bibliotecaPersonalRecurso.getRecurso().getFotoUrl() (bibliotecaPersonalRecurso.getRecurso().getFoto() != null)
? Base64.getEncoder().encodeToString(bibliotecaPersonalRecurso.getRecurso().getFoto())
: null
); );
logger.info("Recurso con ID: {} encontrado para el usuario con ID: {}", recursoId, usuarioId);
return ResponseEntity.ok(dtoRecursoEnBiblioteca); return ResponseEntity.ok(dtoRecursoEnBiblioteca);
} catch (Exception e) { } 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();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // Si ocurre algún error inesperado
} }
} }
@PutMapping("/{usuarioId}/recursos/{recursoId}/categoria")
public ResponseEntity<String> cambiarCategoria(
@PathVariable Long usuarioId,
@PathVariable Long recursoId,
@RequestBody DTORecursoEnBiblioteca dtoRecurso) {
try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
servicioBibliotecaPersonal.cambiarCategoriaRecurso(biblioteca.getId(), recursoId, dtoRecurso.getCategoria());
} return ResponseEntity.status(HttpStatus.OK).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
package com.ujaen.tfg.mangaffinity.rest.DTO; package com.ujaen.tfg.mangaffinity.rest.DTO;
import com.ujaen.tfg.mangaffinity.entidades.Genero; import com.ujaen.tfg.mangaffinity.entidades.Genero;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
@Getter @Getter
...@@ -17,19 +15,11 @@ import java.util.Set; ...@@ -17,19 +15,11 @@ import java.util.Set;
@AllArgsConstructor @AllArgsConstructor
public class DTORecurso { public class DTORecurso {
private Long id; private Long id;
@NotBlank
private String titulo; private String titulo;
private String descripcion; private String descripcion;
@NotNull
private LocalDate fechaPublicacion; private LocalDate fechaPublicacion;
@NotBlank
private String autor; private String autor;
private String fotoBase64;
private String fotoUrl; private Set<Genero> generos;
private Set<Genero> generos = new HashSet<>();
} }
...@@ -11,16 +11,8 @@ import lombok.Setter; ...@@ -11,16 +11,8 @@ import lombok.Setter;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class DTORecursoEnBiblioteca { public class DTORecursoEnBiblioteca {
private Long usuarioId;
private Long recursoId; private Long recursoId;
private String titulo; private String titulo;
private Categoria categoria; private Categoria categoria;
private String fotoUrl; private String fotoBase64;
public DTORecursoEnBiblioteca(Long recursoId, String titulo, Categoria categoria, String fotoUrl) {
this.recursoId = recursoId;
this.titulo = titulo;
this.categoria = categoria;
this.fotoUrl = fotoUrl;
}
} }
package com.ujaen.tfg.mangaffinity.rest;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.MalformedURLException;
import java.nio.file.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/uploads")
public class UploadController {
private final Path uploadDir = Paths.get("uploads");
@GetMapping("/{filename:.+}")
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
try {
Path file = uploadDir.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
String contentType = "application/octet-stream";
if (filename.endsWith(".png")) contentType = "image/png";
else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) contentType = "image/jpeg";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resource.getFilename() + "\"")
.header(HttpHeaders.CONTENT_TYPE, contentType)
.body(resource);
} else {
return ResponseEntity.notFound().build();
}
} catch (MalformedURLException e) {
return ResponseEntity.badRequest().build();
}
}
@PostMapping
public ResponseEntity<String> uploadFile(@RequestParam("foto") MultipartFile foto) {
try {
if (foto.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
String contentType = foto.getContentType();
if (contentType == null || (!contentType.equals("image/jpeg") && !contentType.equals("image/png"))) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
Path path = uploadDir.resolve(foto.getOriginalFilename());
Files.copy(foto.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
return ResponseEntity.ok(foto.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
...@@ -37,8 +37,7 @@ public class ServicioSeguridad { ...@@ -37,8 +37,7 @@ public class ServicioSeguridad {
return config; return config;
})) }))
.authorizeHttpRequests(request -> request .authorizeHttpRequests(request -> request
.requestMatchers(HttpMethod.GET, "/uploads/**").permitAll() .requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll() // Permitir login sin autenticación
.requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll() .requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/").permitAll() .requestMatchers(HttpMethod.POST, "/usuarios/").permitAll()
.requestMatchers(HttpMethod.GET, "/actuator/health").permitAll() .requestMatchers(HttpMethod.GET, "/actuator/health").permitAll()
...@@ -65,7 +64,7 @@ public class ServicioSeguridad { ...@@ -65,7 +64,7 @@ public class ServicioSeguridad {
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) // Usar solo JWT .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
.build(); .build();
} }
......
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