Commit cd4796b5 by Rubén Ramírez

fix: [Recurso]: Correcciones al comprobar con PostMan

parent bcbc02e5
...@@ -28,13 +28,13 @@ public class RepositorioRecurso { ...@@ -28,13 +28,13 @@ 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(TRANSLATE(r.titulo, 'ÁÉÍÓÚáéíóú', 'AEIOUaeiou')) " + "SELECT r FROM Recurso r WHERE LOWER(r.titulo) LIKE LOWER(:titulo)",
"LIKE LOWER(TRANSLATE(:titulo, 'ÁÉÍÓÚáéíóú', 'AEIOUaeiou'))",
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(
......
...@@ -8,6 +8,7 @@ import lombok.Getter; ...@@ -8,6 +8,7 @@ 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
...@@ -28,5 +29,5 @@ public class DTORecurso { ...@@ -28,5 +29,5 @@ public class DTORecurso {
@NotBlank @NotBlank
private String autor; private String autor;
private Set<Genero> generos; private Set<Genero> generos = new HashSet<>();
} }
...@@ -39,10 +39,15 @@ public class Mapper { ...@@ -39,10 +39,15 @@ public class Mapper {
dtoRecurso.getFechaPublicacion(), dtoRecurso.getFechaPublicacion(),
dtoRecurso.getAutor() dtoRecurso.getAutor()
); );
recurso.getGeneros().addAll(dtoRecurso.getGeneros());
if (dtoRecurso.getGeneros() != null) {
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(),
......
...@@ -18,6 +18,8 @@ import java.time.LocalDate; ...@@ -18,6 +18,8 @@ import java.time.LocalDate;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController @RestController
@RequestMapping("/recursos") @RequestMapping("/recursos")
...@@ -27,6 +29,8 @@ public class RecursosController { ...@@ -27,6 +29,8 @@ public class RecursosController {
private ServicioRecursos servicioRecursos; private ServicioRecursos servicioRecursos;
@Autowired @Autowired
private Mapper mapper; private Mapper mapper;
private static final Logger log = LoggerFactory.getLogger(RecursosController.class);
@PostMapping("/") @PostMapping("/")
public ResponseEntity<String> crearRecurso(@RequestBody DTORecurso recurso) { public ResponseEntity<String> crearRecurso(@RequestBody DTORecurso recurso) {
...@@ -41,20 +45,26 @@ public class RecursosController { ...@@ -41,20 +45,26 @@ public class RecursosController {
@GetMapping("/titulo/{titulo}") @GetMapping("/titulo/{titulo}")
public ResponseEntity<List<DTORecurso>> buscarPorTitulo(@PathVariable String titulo) { public ResponseEntity<List<DTORecurso>> buscarPorTitulo(@PathVariable String titulo) {
log.info("🔍 Buscando recurso con título: " + titulo);
try { try {
List<Recurso> recursos = servicioRecursos.buscarRecursoPorTitulo(titulo); List<Recurso> recursos = servicioRecursos.buscarRecursoPorTitulo(titulo);
log.info("📋 Recursos encontrados: " + recursos.size());
if (recursos.isEmpty()) { if (recursos.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Collections.emptyList()); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Collections.emptyList());
} }
List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList(); List<DTORecurso> dtoRecursos = recursos.stream().map(mapper::dto).toList();
return ResponseEntity.ok(dtoRecursos); return ResponseEntity.ok(dtoRecursos);
} catch (Exception e) { } catch (Exception e) {
log.error("❌ Error al buscar recurso: ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
@GetMapping("/genero/{genero}") @GetMapping("/genero/{genero}")
public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) { public ResponseEntity<List<DTORecurso>> buscarPorGenero(@PathVariable Genero genero) {
try { try {
......
...@@ -20,39 +20,35 @@ public class ServicioSeguridad { ...@@ -20,39 +20,35 @@ public class ServicioSeguridad {
this.jwtUtil = jwtUtil; this.jwtUtil = jwtUtil;
} }
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http return http
.csrf(csrf -> csrf.disable()) .csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.disable()) .sessionManagement(session -> session.disable()) // Desactivar sesiones
.httpBasic(httpBasic -> httpBasic.realmName("mangaffinity")) .authorizeHttpRequests(request -> request
.authorizeHttpRequests(request -> request .requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll() // Permitir login sin autenticación
.requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll() .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, "/recursos/titulo/**").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/titulo/**").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/autor/**").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/autor/**").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/genero/**").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/genero/**").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/fecha").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/fecha").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/{id}").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/{id}").permitAll() .requestMatchers(HttpMethod.GET, "/recursos").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.GET, "/recursos").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.POST, "/recursos/").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.POST, "/recursos/").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.PUT, "/recursos/{id}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.PUT, "/recursos/{id}").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.DELETE, "/recursos/{id}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.DELETE, "/recursos/{id}").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.POST, "/recursos/{id}/capitulos").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.POST, "/recursos/{id}/capitulos").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.GET, "/recursos/{id}/capitulos").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/{id}/capitulos").permitAll() .requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/biblioteca").permitAll()
.requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/biblioteca").permitAll() .requestMatchers(HttpMethod.POST, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/categoria/{categoria}").authenticated()
.requestMatchers(HttpMethod.DELETE, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated()
.requestMatchers(HttpMethod.POST, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated() .requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/categoria/{categoria}").authenticated() .anyRequest().authenticated() // Todo lo demás requiere autenticación
.requestMatchers(HttpMethod.DELETE, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated() )
.requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated() .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) // Usar solo JWT
.build();
.anyRequest().authenticated()
)
.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
.build();
} }
@Bean public PasswordEncoder passwordEncoder() { @Bean public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
......
...@@ -54,7 +54,7 @@ public class TestRecursosController { ...@@ -54,7 +54,7 @@ public class TestRecursosController {
// Caso 1: Intento crear un recurso sin autenticación // Caso 1: Intento crear un recurso sin autenticación
Recurso nuevoRecurso = new Recurso("Titulo Prueba", "Descripción de prueba", LocalDate.now(), "Autor Prueba"); Recurso nuevoRecurso = new Recurso("Titulo Prueba", "Descripción de prueba", LocalDate.now(), "Autor Prueba");
var respuestaNoAutenticado = restTemplate.postForEntity("/recursos/", nuevoRecurso, Void.class); var respuestaNoAutenticado = restTemplate.postForEntity("/recursos/", nuevoRecurso, Void.class);
assertThat(respuestaNoAutenticado.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(respuestaNoAutenticado.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
// Caso 2: Intento crear un recurso correctamente con autenticación de admin // Caso 2: Intento crear un recurso correctamente con autenticación de admin
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
...@@ -328,7 +328,7 @@ public class TestRecursosController { ...@@ -328,7 +328,7 @@ public class TestRecursosController {
ResponseEntity<Void> deleteUnauthorized = restTemplate.exchange( ResponseEntity<Void> deleteUnauthorized = restTemplate.exchange(
"/recursos/" + recursoId, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class "/recursos/" + recursoId, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class
); );
assertThat(deleteUnauthorized.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(deleteUnauthorized.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
//Caso 2: Intento borrar el recurso con autenticación //Caso 2: Intento borrar el recurso con autenticación
HttpHeaders authHeaders = new HttpHeaders(); HttpHeaders authHeaders = new HttpHeaders();
...@@ -411,7 +411,7 @@ public class TestRecursosController { ...@@ -411,7 +411,7 @@ public class TestRecursosController {
"/recursos/{id}", HttpMethod.PUT, noAuthRequest, Void.class, recursoId "/recursos/{id}", HttpMethod.PUT, noAuthRequest, Void.class, recursoId
); );
assertThat(respuestaNoAutenticado.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(respuestaNoAutenticado.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
} }
@Test @Test
...@@ -455,7 +455,7 @@ public class TestRecursosController { ...@@ -455,7 +455,7 @@ public class TestRecursosController {
ResponseEntity<Void> respuestaNoAuth = restTemplate.exchange( ResponseEntity<Void> respuestaNoAuth = restTemplate.exchange(
"/recursos", HttpMethod.GET, HttpEntity.EMPTY, Void.class "/recursos", HttpMethod.GET, HttpEntity.EMPTY, Void.class
); );
assertThat(respuestaNoAuth.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(respuestaNoAuth.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
} }
@Test @Test
...@@ -527,7 +527,7 @@ public class TestRecursosController { ...@@ -527,7 +527,7 @@ public class TestRecursosController {
"/recursos/{id}/capitulos", HttpMethod.POST, capituloRequestUser, Void.class, recursoId "/recursos/{id}/capitulos", HttpMethod.POST, capituloRequestUser, Void.class, recursoId
); );
assertThat(respuestaCapituloUser.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(respuestaCapituloUser.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
} }
@Test @Test
......
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