Commit cfb55e05 by Rubén Ramírez

feat: [Servicios+Controladores]: Comentadas las funciones que no tenían doxygen

parent 63651ab7
...@@ -200,6 +200,15 @@ public class BibliotecaPersonalController { ...@@ -200,6 +200,15 @@ public class BibliotecaPersonalController {
} }
} }
/**
* Añade un recurso a la lista de favoritos de la biblioteca personal del usuario.
*
* Devuelve:
* - 200 OK si se añade correctamente.
* - 404 NOT FOUND si la biblioteca del usuario no existe.
* - 409 CONFLICT si se ha alcanzado el número máximo de favoritos permitidos.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@PutMapping("/{usuarioId}/favoritos/{recursoId}") @PutMapping("/{usuarioId}/favoritos/{recursoId}")
public ResponseEntity<Void> anadirAFavoritos( public ResponseEntity<Void> anadirAFavoritos(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -217,6 +226,14 @@ public class BibliotecaPersonalController { ...@@ -217,6 +226,14 @@ public class BibliotecaPersonalController {
} }
} }
/**
* Elimina un recurso de la lista de favoritos de la biblioteca personal del usuario.
*
* Devuelve:
* - 204 NO CONTENT si se elimina correctamente.
* - 404 NOT FOUND si la biblioteca del usuario no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@DeleteMapping("/{usuarioId}/favoritos/{recursoId}") @DeleteMapping("/{usuarioId}/favoritos/{recursoId}")
public ResponseEntity<Void> eliminarDeFavoritos( public ResponseEntity<Void> eliminarDeFavoritos(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -232,6 +249,14 @@ public class BibliotecaPersonalController { ...@@ -232,6 +249,14 @@ public class BibliotecaPersonalController {
} }
} }
/**
* Obtiene la lista de recursos marcados como favoritos por el usuario.
*
* Devuelve:
* - 200 OK con la lista de recursos favoritos (vacía o no).
* - 404 NOT FOUND si la biblioteca del usuario no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{usuarioId}/favoritos") @GetMapping("/{usuarioId}/favoritos")
public ResponseEntity<List<DTORecurso>> obtenerFavoritos( public ResponseEntity<List<DTORecurso>> obtenerFavoritos(
@PathVariable Long usuarioId) { @PathVariable Long usuarioId) {
......
...@@ -52,9 +52,8 @@ public class RecursosController { ...@@ -52,9 +52,8 @@ public class RecursosController {
if (foto != null && !foto.isEmpty()) { if (foto != null && !foto.isEmpty()) {
String mimeType = foto.getContentType(); String mimeType = foto.getContentType();
if (mimeType == null || (!mimeType.equals("image/jpeg") && !mimeType.equals("image/png"))) { if (mimeType == null || (!mimeType.equals("image/jpeg") && !mimeType.equals("image/png"))) return ResponseEntity.badRequest().build();
return ResponseEntity.badRequest().build();
}
fotoBytes = foto.getBytes(); fotoBytes = foto.getBytes();
} }
...@@ -428,13 +427,9 @@ public class RecursosController { ...@@ -428,13 +427,9 @@ public class RecursosController {
public ResponseEntity<List<DTORecurso>> obtenerRanking() { public ResponseEntity<List<DTORecurso>> obtenerRanking() {
List<Recurso> recursosTop = servicioRecursos.obtenerTopRecursosUltimaSemana(); List<Recurso> recursosTop = servicioRecursos.obtenerTopRecursosUltimaSemana();
if (recursosTop.isEmpty()) { if (recursosTop.isEmpty()) recursosTop = servicioRecursos.obtenerListadoRecursos();
recursosTop = servicioRecursos.obtenerListadoRecursos();
}
if (recursosTop.isEmpty()) { if (recursosTop.isEmpty()) return ResponseEntity.noContent().build();
return ResponseEntity.noContent().build();
}
List<DTORecurso> dtoRecursosTop = recursosTop.stream() List<DTORecurso> dtoRecursosTop = recursosTop.stream()
.map(mapper::dto) .map(mapper::dto)
...@@ -480,9 +475,8 @@ public class RecursosController { ...@@ -480,9 +475,8 @@ public class RecursosController {
public ResponseEntity<List<DTOResena>> obtenerResenasDeRecurso(@PathVariable Long recursoId) { public ResponseEntity<List<DTOResena>> obtenerResenasDeRecurso(@PathVariable Long recursoId) {
try { try {
List<Resena> resenas = servicioRecursos.obtenerResenasDeRecurso(recursoId); List<Resena> resenas = servicioRecursos.obtenerResenasDeRecurso(recursoId);
if (resenas.isEmpty()) { if (resenas.isEmpty()) return ResponseEntity.noContent().build();
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(mapper.dtoListaResenas(resenas)); return ResponseEntity.ok(mapper.dtoListaResenas(resenas));
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
......
...@@ -26,6 +26,12 @@ public class SeguimientoController { ...@@ -26,6 +26,12 @@ public class SeguimientoController {
/** /**
* Permite a un usuario seguir a otro. * Permite a un usuario seguir a otro.
*
* Devuelve:
* - 201 CREATED si el seguimiento se realiza correctamente.
* - 409 CONFLICT si ya existe el seguimiento.
* - 404 NOT FOUND si alguno de los usuarios no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/ */
@PostMapping("/{nombreSeguido}") @PostMapping("/{nombreSeguido}")
public ResponseEntity<?> seguir(@RequestHeader("nombreUsuario") String nombreSeguidor, public ResponseEntity<?> seguir(@RequestHeader("nombreUsuario") String nombreSeguidor,
...@@ -43,7 +49,12 @@ public class SeguimientoController { ...@@ -43,7 +49,12 @@ public class SeguimientoController {
} }
/** /**
* Permite dejar de seguir a un usuario. * Permite a un usuario dejar de seguir a otro.
*
* Devuelve:
* - 204 NO CONTENT si el seguimiento se elimina correctamente.
* - 404 NOT FOUND si el seguimiento no existe o algún usuario no se encuentra.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/ */
@DeleteMapping("/{nombreSeguido}") @DeleteMapping("/{nombreSeguido}")
public ResponseEntity<?> dejarDeSeguir(@RequestHeader("nombreUsuario") String nombreSeguidor, public ResponseEntity<?> dejarDeSeguir(@RequestHeader("nombreUsuario") String nombreSeguidor,
...@@ -51,9 +62,7 @@ public class SeguimientoController { ...@@ -51,9 +62,7 @@ public class SeguimientoController {
try { try {
servicioSeguimientos.dejarDeSeguir(nombreSeguidor, nombreSeguido); servicioSeguimientos.dejarDeSeguir(nombreSeguidor, nombreSeguido);
return ResponseEntity.noContent().build(); return ResponseEntity.noContent().build();
} catch (SeguimientoNoExiste e) { } catch (SeguimientoNoExiste | UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
...@@ -61,7 +70,11 @@ public class SeguimientoController { ...@@ -61,7 +70,11 @@ public class SeguimientoController {
} }
/** /**
* Lista de usuarios que sigue un usuario. * Recupera la lista de usuarios que son seguidos por un usuario específico.
*
* - 200 OK y la lista de usuarios seguidos si la operación tiene éxito.
* - 404 NOT FOUND si el usuario no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/ */
@GetMapping("/seguidos/{nombreUsuario}") @GetMapping("/seguidos/{nombreUsuario}")
public ResponseEntity<List<DTOUsuario>> obtenerSeguidos(@PathVariable String nombreUsuario) { public ResponseEntity<List<DTOUsuario>> obtenerSeguidos(@PathVariable String nombreUsuario) {
...@@ -71,11 +84,18 @@ public class SeguimientoController { ...@@ -71,11 +84,18 @@ public class SeguimientoController {
return ResponseEntity.ok(dto); return ResponseEntity.ok(dto);
} catch (UsuarioNoExiste e) { } catch (UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
/** /**
* Lista de seguidores de un usuario. * Recupera la lista de usuarios que siguen a un usuario específico.
*
* - 200 OK y la lista de seguidores si la operación tiene éxito.
* - 404 NOT FOUND si el usuario no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/ */
@GetMapping("/seguidores/{nombreUsuario}") @GetMapping("/seguidores/{nombreUsuario}")
public ResponseEntity<List<DTOUsuario>> obtenerSeguidores(@PathVariable String nombreUsuario) { public ResponseEntity<List<DTOUsuario>> obtenerSeguidores(@PathVariable String nombreUsuario) {
...@@ -85,11 +105,17 @@ public class SeguimientoController { ...@@ -85,11 +105,17 @@ public class SeguimientoController {
return ResponseEntity.ok(dto); return ResponseEntity.ok(dto);
} catch (UsuarioNoExiste e) { } catch (UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
/** /**
* Verifica si un usuario sigue a otro. * Verifica si un usuario está siguiendo a otro.
*
* - 200 OK y un valor booleano indicando si existe el seguimiento.
* - 404 NOT FOUND si alguno de los usuarios no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/ */
@GetMapping("/existe") @GetMapping("/existe")
public ResponseEntity<Boolean> estaSiguiendo(@RequestParam String seguidor, public ResponseEntity<Boolean> estaSiguiendo(@RequestParam String seguidor,
...@@ -99,6 +125,8 @@ public class SeguimientoController { ...@@ -99,6 +125,8 @@ public class SeguimientoController {
return ResponseEntity.ok(resultado); return ResponseEntity.ok(resultado);
} catch (UsuarioNoExiste e) { } catch (UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
} }
...@@ -96,9 +96,8 @@ public class UsuariosController { ...@@ -96,9 +96,8 @@ public class UsuariosController {
public ResponseEntity<?> obtenerBiblioteca(@PathVariable Long usuarioId) { public ResponseEntity<?> obtenerBiblioteca(@PathVariable Long usuarioId) {
try { try {
BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId); BibliotecaPersonal biblioteca = servicioUsuarios.obtenerBibliotecaDeUsuario(usuarioId);
if (biblioteca == null) { if (biblioteca == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No se encontró la biblioteca");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No se encontró la biblioteca");
}
return ResponseEntity.ok(new DTOBibliotecaPersonal(biblioteca)); return ResponseEntity.ok(new DTOBibliotecaPersonal(biblioteca));
} catch (RuntimeException e) { } catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error inesperado"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error inesperado");
...@@ -125,6 +124,15 @@ public class UsuariosController { ...@@ -125,6 +124,15 @@ public class UsuariosController {
} }
} }
/**
* Modifica los datos de un usuario autenticado a partir del token JWT proporcionado.
*
* - 200 OK y DTOLoginRespuesta si la modificación se realiza correctamente.
* - 409 CONFLICT si el correo electrónico o el nombre de usuario ya están registrados.
* - 404 NOT FOUND si el usuario no existe.
* - 403 FORBIDDEN si la contraseña actual es incorrecta.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@PutMapping("/") @PutMapping("/")
public ResponseEntity<?> modificarUsuario(@Valid @RequestBody DTOModificarUsuario dto, public ResponseEntity<?> modificarUsuario(@Valid @RequestBody DTOModificarUsuario dto,
@RequestHeader("Authorization") String token) { @RequestHeader("Authorization") String token) {
...@@ -150,6 +158,12 @@ public class UsuariosController { ...@@ -150,6 +158,12 @@ public class UsuariosController {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("error inesperado"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("error inesperado");
} }
} }
/**
* Devuelve una lista de recursos recomendados para un usuario específico.
*
* - 200 OK y la lista de recursos recomendados en formato DTORecurso si la operación es exitosa.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado durante el proceso de recomendación.
*/
@GetMapping("/{usuarioId}/recomendaciones") @GetMapping("/{usuarioId}/recomendaciones")
public ResponseEntity<List<DTORecurso>> obtenerRecomendaciones(@PathVariable Long usuarioId) { public ResponseEntity<List<DTORecurso>> obtenerRecomendaciones(@PathVariable Long usuarioId) {
try { try {
...@@ -176,6 +190,14 @@ public class UsuariosController { ...@@ -176,6 +190,14 @@ public class UsuariosController {
} }
} }
/**
* Actualiza la descripción y/o la foto de perfil de un usuario concreto.
*
* - 204 NO CONTENT si la actualización se realiza correctamente.
* - 400 BAD REQUEST si los datos proporcionados no son válidos.
* - 404 NOT FOUND si el usuario no existe.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@PutMapping("/{usuarioId}/perfil") @PutMapping("/{usuarioId}/perfil")
public ResponseEntity<Void> actualizarPerfilUsuario( public ResponseEntity<Void> actualizarPerfilUsuario(
@PathVariable Long usuarioId, @PathVariable Long usuarioId,
...@@ -187,8 +209,20 @@ public class UsuariosController { ...@@ -187,8 +209,20 @@ public class UsuariosController {
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
/**
* Recupera la información de un usuario a partir de su ID.
*
* @param usuarioId ID del usuario que se desea consultar.
* @return ResponseEntity con:
* - 200 OK y los datos del usuario en formato DTOUsuario si se encuentra correctamente.
* - 404 NOT FOUND si no existe ningún usuario con el ID proporcionado.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping("/{usuarioId}") @GetMapping("/{usuarioId}")
public ResponseEntity<DTOUsuario> obtenerUsuarioPorId(@PathVariable Long usuarioId) { public ResponseEntity<DTOUsuario> obtenerUsuarioPorId(@PathVariable Long usuarioId) {
try { try {
...@@ -196,9 +230,19 @@ public class UsuariosController { ...@@ -196,9 +230,19 @@ public class UsuariosController {
return ResponseEntity.ok(mapper.dto(usuario)); return ResponseEntity.ok(mapper.dto(usuario));
} catch (UsuarioNoExiste e) { } catch (UsuarioNoExiste e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} }
} }
/**
* Filtra y devuelve una lista de usuarios cuyo nombre coincide (parcial o totalmente) con el valor indicado.
*
* - 200 OK y la lista de usuarios coincidentes si se encuentran resultados.
* - 204 NO CONTENT si no se encuentran usuarios con ese nombre.
* - 400 BAD REQUEST si no se proporciona el parámetro o está vacío.
* - 500 INTERNAL SERVER ERROR en caso de error inesperado.
*/
@GetMapping @GetMapping
public ResponseEntity<List<DTOUsuario>> filtrarUsuarios(@RequestParam(required = false) String nombre) { public ResponseEntity<List<DTOUsuario>> filtrarUsuarios(@RequestParam(required = false) String nombre) {
try { try {
......
...@@ -37,46 +37,55 @@ public class ServicioSeguridad { ...@@ -37,46 +37,55 @@ public class ServicioSeguridad {
return config; return config;
})) }))
.authorizeHttpRequests(request -> request .authorizeHttpRequests(request -> request
// Rutas públicas
.requestMatchers(HttpMethod.GET, "/actuator/health").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll() .requestMatchers(HttpMethod.POST, "/usuarios/{email}").permitAll()
.requestMatchers(HttpMethod.GET, "/usuarios").authenticated()
.requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll() .requestMatchers(HttpMethod.GET, "/usuarios/email/{email}").permitAll()
.requestMatchers(HttpMethod.POST, "/usuarios/").permitAll() .requestMatchers(HttpMethod.GET, "/recursos").permitAll()
.requestMatchers(HttpMethod.PUT, "/usuarios/").authenticated()
.requestMatchers(HttpMethod.PUT, "/usuarios/{usuarioId}/perfil").authenticated()
.requestMatchers(HttpMethod.GET, "/usuarios/*").authenticated()
.requestMatchers(HttpMethod.GET, "/actuator/health").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/generos").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/generos").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos").permitAll() .requestMatchers(HttpMethod.GET, "/recursos/ranking").permitAll()
.requestMatchers(HttpMethod.POST, "/recursos/").hasAuthority("ROLE_ADMIN") .requestMatchers(HttpMethod.GET, "/recursos/{id}").permitAll()
.requestMatchers(HttpMethod.PUT, "/recursos/{id}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.DELETE, "/recursos/{id}").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, "/recursos/{recursoId}/capitulos/{capituloId}").permitAll()
.requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/resenas").permitAll()
.requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/biblioteca").permitAll() .requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/biblioteca").permitAll()
// Rutas autenticadas (usuarios registrados)
.requestMatchers(HttpMethod.GET, "/usuarios").authenticated()
.requestMatchers(HttpMethod.PUT, "/usuarios/").authenticated()
.requestMatchers(HttpMethod.PUT, "/usuarios/{usuarioId}/perfil").authenticated()
.requestMatchers(HttpMethod.GET, "/usuarios/*").authenticated()
.requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/recomendaciones").authenticated()
// Biblioteca personal
.requestMatchers(HttpMethod.POST, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated() .requestMatchers(HttpMethod.POST, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/categoria/{categoria}").authenticated() .requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/categoria/{categoria}").authenticated()
.requestMatchers(HttpMethod.DELETE, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated() .requestMatchers(HttpMethod.DELETE, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated()
.requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated() .requestMatchers(HttpMethod.PUT, "/biblioteca/{usuarioId}/recursos/{recursoId}/categoria").authenticated()
.requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/capitulos/{capituloId}").permitAll()
.requestMatchers(HttpMethod.PUT, "/recursos/{recursoId}/capitulos/{capituloId}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated() .requestMatchers(HttpMethod.GET, "/biblioteca/{usuarioId}/recursos/{recursoId}").authenticated()
.requestMatchers(HttpMethod.GET, "/recursos/ranking").permitAll() .requestMatchers(HttpMethod.PUT, "/usuarios/{usuarioId}/perfil").authenticated()
.requestMatchers(HttpMethod.POST, "/recursos/{recursoId}/resenas").authenticated() .requestMatchers(HttpMethod.POST, "/recursos/{recursoId}/resenas").authenticated()
.requestMatchers(HttpMethod.GET, "/recursos/{recursoId}/resenas").permitAll()
.requestMatchers(HttpMethod.GET, "/usuarios/{usuarioId}/recomendaciones").authenticated() // Seguimientos
// Endpoints de seguimiento
.requestMatchers(HttpMethod.POST, "/seguimientos/{nombreSeguido}").authenticated() .requestMatchers(HttpMethod.POST, "/seguimientos/{nombreSeguido}").authenticated()
.requestMatchers(HttpMethod.DELETE, "/seguimientos/{nombreSeguido}").authenticated() .requestMatchers(HttpMethod.DELETE, "/seguimientos/{nombreSeguido}").authenticated()
.requestMatchers(HttpMethod.GET, "/seguimientos/seguidos/{nombreUsuario}").authenticated() .requestMatchers(HttpMethod.GET, "/seguimientos/seguidos/{nombreUsuario}").authenticated()
.requestMatchers(HttpMethod.GET, "/seguimientos/seguidores/{nombreUsuario}").authenticated() .requestMatchers(HttpMethod.GET, "/seguimientos/seguidores/{nombreUsuario}").authenticated()
.requestMatchers(HttpMethod.GET, "/seguimientos/existe").authenticated() .requestMatchers(HttpMethod.GET, "/seguimientos/existe").authenticated()
// Rutas ADMIN
.requestMatchers(HttpMethod.POST, "/recursos/").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.PUT, "/recursos/{id}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.DELETE, "/recursos/{id}").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.POST, "/recursos/{id}/capitulos").hasAuthority("ROLE_ADMIN")
.requestMatchers(HttpMethod.PUT, "/recursos/{recursoId}/capitulos/{capituloId}").hasAuthority("ROLE_ADMIN")
// Cualquier otra petición
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
......
...@@ -115,6 +115,13 @@ public class ServicioBibliotecaPersonal { ...@@ -115,6 +115,13 @@ public class ServicioBibliotecaPersonal {
return repositorioBibliotecaPersonalRecurso.buscarRecursoEnBiblioteca(bibliotecaPersonalId, recursoId); return repositorioBibliotecaPersonalRecurso.buscarRecursoEnBiblioteca(bibliotecaPersonalId, recursoId);
} }
/**
* @brief Añade un recurso a la lista de favoritos del usuario.
* @param bibliotecaPersonalId ID de la biblioteca personal del usuario.
* @param recursoId ID del recurso que se desea marcar como favorito.
* @throws UsuarioSinBiblioteca Si no existe una biblioteca asociada al usuario.
* @throws RecursoNoExiste Si el recurso no existe en la base de datos.
*/
@Transactional @Transactional
public void anadirFavorito(Long bibliotecaPersonalId, Long recursoId) { public void anadirFavorito(Long bibliotecaPersonalId, Long recursoId) {
BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso
...@@ -128,6 +135,13 @@ public class ServicioBibliotecaPersonal { ...@@ -128,6 +135,13 @@ public class ServicioBibliotecaPersonal {
biblioteca.anadirFavorito(recurso.getId()); biblioteca.anadirFavorito(recurso.getId());
} }
/**
* @brief Elimina un recurso de la lista de favoritos del usuario.
*
* @param bibliotecaPersonalId ID de la biblioteca personal del usuario.
* @param recursoId ID del recurso que se desea eliminar de favoritos.
* @throws UsuarioSinBiblioteca Si no existe una biblioteca asociada al usuario.
*/
@Transactional @Transactional
public void eliminarFavorito(Long bibliotecaPersonalId, Long recursoId) { public void eliminarFavorito(Long bibliotecaPersonalId, Long recursoId) {
BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso
...@@ -137,6 +151,12 @@ public class ServicioBibliotecaPersonal { ...@@ -137,6 +151,12 @@ public class ServicioBibliotecaPersonal {
biblioteca.eliminarFavorito(recursoId); biblioteca.eliminarFavorito(recursoId);
} }
/**
* @brief Obtiene la lista de IDs de los recursos marcados como favoritos por el usuario.
* @param bibliotecaPersonalId ID de la biblioteca personal del usuario.
* @return Lista de IDs de recursos que el usuario ha marcado como favoritos.
* @throws UsuarioSinBiblioteca Si no existe una biblioteca asociada al usuario.
*/
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Long> obtenerFavoritos(Long bibliotecaPersonalId) { public List<Long> obtenerFavoritos(Long bibliotecaPersonalId) {
BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso
......
...@@ -231,7 +231,7 @@ public class ServicioRecursos { ...@@ -231,7 +231,7 @@ public class ServicioRecursos {
} }
/** /**
* Modifica un capítulo existente dentro de un recurso. * @brief Modifica un capítulo existente dentro de un recurso.
* @param recursoId ID del recurso al que pertenece el capítulo. * @param recursoId ID del recurso al que pertenece el capítulo.
* @param capituloModificado Entidad Capitulo con los nuevos datos. * @param capituloModificado Entidad Capitulo con los nuevos datos.
* @return Capítulo actualizado. * @return Capítulo actualizado.
...@@ -299,7 +299,6 @@ public class ServicioRecursos { ...@@ -299,7 +299,6 @@ public class ServicioRecursos {
/** /**
* @brief Elimina una fuente de un capítulo por su ID. * @brief Elimina una fuente de un capítulo por su ID.
* @param id Identificador de la fuente a eliminar. * @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) {
...@@ -381,7 +380,7 @@ public class ServicioRecursos { ...@@ -381,7 +380,7 @@ public class ServicioRecursos {
} }
/** /**
* Añade una nueva reseña a un recurso. * @brief Añade una nueva reseña a un recurso.
* @param resena Objeto Resena con los datos de la reseña a añadir. * @param resena Objeto Resena con los datos de la reseña a añadir.
*/ */
@Transactional @Transactional
...@@ -401,10 +400,8 @@ public class ServicioRecursos { ...@@ -401,10 +400,8 @@ public class ServicioRecursos {
repositorioRecurso.actualiza(recurso); repositorioRecurso.actualiza(recurso);
} }
/** /**
* Obtiene las reseñas de un recurso específico, ordenadas por fecha de publicación de manera descendente. * @brief Obtiene las reseñas de un recurso específico, ordenadas por fecha de publicación de manera descendente.
* @param recursoId Identificador del recurso cuyo listado de reseñas se desea obtener. * @param recursoId Identificador del recurso cuyo listado de reseñas se desea obtener.
* @return Lista de reseñas del recurso, ordenadas por fecha de publicación. * @return Lista de reseñas del recurso, ordenadas por fecha de publicación.
*/ */
...@@ -415,6 +412,12 @@ public class ServicioRecursos { ...@@ -415,6 +412,12 @@ public class ServicioRecursos {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* @brief Genera una lista de recomendaciones personalizadas de recursos para un usuario,
* @param usuarioId ID del usuario para el que se desean obtener recomendaciones.
* @return Lista de hasta 4 recursos recomendados que no estén ni en la biblioteca ni en favoritos.
* @throws UsuarioSinBiblioteca Si el usuario no tiene una biblioteca personal asociada.
*/
public List<Recurso> obtenerRecomendacionesParaUsuario(Long usuarioId) { public List<Recurso> obtenerRecomendacionesParaUsuario(Long usuarioId) {
BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso BibliotecaPersonal biblioteca = repositorioBibliotecaPersonalRecurso
.obtenerBibliotecaPorUsuarioId(usuarioId) .obtenerBibliotecaPorUsuarioId(usuarioId)
......
...@@ -27,11 +27,11 @@ public class ServicioSeguimiento { ...@@ -27,11 +27,11 @@ public class ServicioSeguimiento {
private RepositorioUsuario repositorioUsuario; private RepositorioUsuario repositorioUsuario;
/** /**
* @brief Permite a un usuario seguir a otro.
* @param nombreSeguidor nombre de usuario que realiza el seguimiento. * @param nombreSeguidor nombre de usuario que realiza el seguimiento.
* @param nombreSeguido nombre de usuario que será seguido. * @param nombreSeguido nombre de usuario que será seguido.
* @throws UsuarioNoExiste si alguno de los dos usuarios no existe. * @throws UsuarioNoExiste si alguno de los dos usuarios no existe.
* @throws SeguimientoExiste si ya existe el seguimiento. * @throws SeguimientoExiste si ya existe el seguimiento.
* @brief Permite a un usuario seguir a otro.
*/ */
@Transactional @Transactional
public void seguir(String nombreSeguidor, String nombreSeguido) { public void seguir(String nombreSeguidor, String nombreSeguido) {
...@@ -57,11 +57,11 @@ public class ServicioSeguimiento { ...@@ -57,11 +57,11 @@ public class ServicioSeguimiento {
} }
/** /**
* @brief Permite dejar de seguir a un usuario.
* @param nombreSeguidor nombre de usuario que dejará de seguir. * @param nombreSeguidor nombre de usuario que dejará de seguir.
* @param nombreSeguido nombre del usuario seguido. * @param nombreSeguido nombre del usuario seguido.
* @throws UsuarioNoExiste si alguno no existe. * @throws UsuarioNoExiste si alguno no existe.
* @throws SeguimientoNoExiste si la relación no existe. * @throws SeguimientoNoExiste si la relación no existe.
* @brief Permite dejar de seguir a un usuario.
*/ */
@Transactional @Transactional
public void dejarDeSeguir(String nombreSeguidor, String nombreSeguido) { public void dejarDeSeguir(String nombreSeguidor, String nombreSeguido) {
...@@ -78,10 +78,10 @@ public class ServicioSeguimiento { ...@@ -78,10 +78,10 @@ public class ServicioSeguimiento {
} }
/** /**
* @brief Obtiene los usuarios que sigue un usuario dado.
* @param nombreSeguidor nombre de usuario que realiza seguimientos. * @param nombreSeguidor nombre de usuario que realiza seguimientos.
* @return Lista de usuarios seguidos. * @return Lista de usuarios seguidos.
* @throws UsuarioNoExiste si el usuario no existe. * @throws UsuarioNoExiste si el usuario no existe.
* @brief Obtiene los usuarios que sigue un usuario dado.
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<Usuario> obtenerSeguidos(String nombreSeguidor) { public List<Usuario> obtenerSeguidos(String nombreSeguidor) {
...@@ -110,11 +110,11 @@ public class ServicioSeguimiento { ...@@ -110,11 +110,11 @@ public class ServicioSeguimiento {
} }
/** /**
* @brief Verifica si un usuario sigue a otro.
* @param nombreSeguidor quien realiza el seguimiento. * @param nombreSeguidor quien realiza el seguimiento.
* @param nombreSeguido quien es seguido. * @param nombreSeguido quien es seguido.
* @return true si lo sigue, false si no. * @return true si lo sigue, false si no.
* @throws UsuarioNoExiste si no existe alguno de los usuarios. * @throws UsuarioNoExiste si no existe alguno de los usuarios.
* @brief Verifica si un usuario sigue a otro.
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
public boolean estaSiguiendo(String nombreSeguidor, String nombreSeguido) { public boolean estaSiguiendo(String nombreSeguidor, String nombreSeguido) {
......
...@@ -55,7 +55,6 @@ public class ServicioUsuarios { ...@@ -55,7 +55,6 @@ public class ServicioUsuarios {
* @return DTOLoginRespuesta con el token, email y nombre de usuario. * @return DTOLoginRespuesta con el token, email y nombre de usuario.
* @throws UsuarioYaRegistrado Si el email ya está registrado o es del admin. * @throws UsuarioYaRegistrado Si el email ya está registrado o es del admin.
* @throws NombreUsuarioYaCogido Si el nombre de usuario ya está en uso. * @throws NombreUsuarioYaCogido Si el nombre de usuario ya está en uso.
* Encripta la contraseña, asigna una biblioteca personal y genera un token JWT.
*/ */
public DTOLoginRespuesta crearUsuario(Usuario usuario) { public DTOLoginRespuesta crearUsuario(Usuario usuario) {
usuario.setContrasenia(passwordEncoder.encode(usuario.getContrasenia())); usuario.setContrasenia(passwordEncoder.encode(usuario.getContrasenia()));
...@@ -85,7 +84,6 @@ public class ServicioUsuarios { ...@@ -85,7 +84,6 @@ public class ServicioUsuarios {
* @param email Correo electrónico del usuario. * @param email Correo electrónico del usuario.
* @param contrasenia Contraseña en texto plano. * @param contrasenia Contraseña en texto plano.
* @return DTOLoginRespuesta con el token, email y nombre de usuario, o null si falla la autenticación. * @return DTOLoginRespuesta con el token, email y nombre de usuario, o null si falla la autenticación.
* Devuelve null si el usuario no existe, la contraseña es incorrecta o no tiene permisos de administrador.
*/ */
public DTOLoginRespuesta autenticarUsuario(String email, String contrasenia) { public DTOLoginRespuesta autenticarUsuario(String email, String contrasenia) {
Optional<Usuario> usuarioOpt = repositorioUsuario.findByEmail(email); Optional<Usuario> usuarioOpt = repositorioUsuario.findByEmail(email);
...@@ -111,7 +109,6 @@ public class ServicioUsuarios { ...@@ -111,7 +109,6 @@ public class ServicioUsuarios {
* @param email Correo electrónico del usuario. * @param email Correo electrónico del usuario.
* @return Usuario encontrado. * @return Usuario encontrado.
* @throws UsuarioNoExiste Si el usuario no está registrado. * @throws UsuarioNoExiste Si el usuario no está registrado.
* Devuelve el usuario administrador si el email coincide con el del admin.
*/ */
public Usuario buscaUsuario(String email) { public Usuario buscaUsuario(String email) {
if (email.equals(admin.getEmail())) return admin; if (email.equals(admin.getEmail())) return admin;
...@@ -136,7 +133,6 @@ public class ServicioUsuarios { ...@@ -136,7 +133,6 @@ public class ServicioUsuarios {
* @param id ID del usuario. * @param id ID del usuario.
* @return Usuario encontrado. * @return Usuario encontrado.
* @throws UsuarioNoExiste Si el usuario no está registrado. * @throws UsuarioNoExiste Si el usuario no está registrado.
* Devuelve el usuario administrador si el ID coincide con el del admin.
*/ */
public Usuario buscaUsuario(Long id) { public Usuario buscaUsuario(Long id) {
if (id.equals(admin.getId())) return admin; if (id.equals(admin.getId())) return admin;
...@@ -144,6 +140,19 @@ public class ServicioUsuarios { ...@@ -144,6 +140,19 @@ public class ServicioUsuarios {
return repositorioUsuario.findById(id).orElseThrow(UsuarioNoExiste::new); return repositorioUsuario.findById(id).orElseThrow(UsuarioNoExiste::new);
} }
/**
* @brief Modifica los datos básicos de un usuario (email, nombre de usuario y/o contraseña).
* @param emailActual Email actual del usuario.
* @param nuevoEmail Nuevo email propuesto.
* @param nuevoNombreUsuario Nuevo nombre de usuario propuesto.
* @param nuevaContrasenia Nueva contraseña (puede ser null o vacía si no se desea cambiar).
* @param contraseniaActual Contraseña actual del usuario, necesaria para validar el cambio.
* @return DTOLoginRespuesta con un nuevo token JWT y los datos actualizados.
* @throws UsuarioNoExiste Si el usuario no está registrado.
* @throws UsuarioYaRegistrado Si el nuevo email ya está en uso por otro usuario.
* @throws NombreUsuarioYaCogido Si el nuevo nombre de usuario ya está en uso.
* @throws IllegalArgumentException Si la contraseña actual es incorrecta.
*/
public DTOLoginRespuesta modificarUsuario(String emailActual, String nuevoEmail, String nuevoNombreUsuario, String nuevaContrasenia, String contraseniaActual) { public DTOLoginRespuesta modificarUsuario(String emailActual, String nuevoEmail, String nuevoNombreUsuario, String nuevaContrasenia, String contraseniaActual) {
Usuario usuario = repositorioUsuario.findByEmail(emailActual) Usuario usuario = repositorioUsuario.findByEmail(emailActual)
.orElseThrow(UsuarioNoExiste::new); .orElseThrow(UsuarioNoExiste::new);
...@@ -190,11 +199,31 @@ public class ServicioUsuarios { ...@@ -190,11 +199,31 @@ public class ServicioUsuarios {
return new DTOLoginRespuesta(token, usuario.getEmail(), usuario.getNombreUsuario()); return new DTOLoginRespuesta(token, usuario.getEmail(), usuario.getNombreUsuario());
} }
/**
* @brief Modifica los datos de un usuario autenticado, utilizando un token JWT como identificador.
* @param token Token JWT del usuario autenticado.
* @param nuevoEmail Nuevo correo electrónico (puede ser el mismo o diferente).
* @param nuevoNombreUsuario Nuevo nombre de usuario (puede ser el mismo o diferente).
* @param nuevaContrasenia Nueva contraseña en texto plano (puede ser null o vacía si no se desea modificar).
* @param contraseniaActual Contraseña actual del usuario para validación.
* @return DTOLoginRespuesta con un nuevo token JWT, el email y el nombre de usuario actualizados.
* @throws UsuarioNoExiste Si el usuario no existe.
* @throws UsuarioYaRegistrado Si el nuevo email ya está en uso.
* @throws NombreUsuarioYaCogido Si el nuevo nombre de usuario ya está en uso.
* @throws IllegalArgumentException Si la contraseña actual no es válida.
*/
public DTOLoginRespuesta modificarUsuarioDesdeToken(String token, String nuevoEmail, String nuevoNombreUsuario, String nuevaContrasenia, String contraseniaActual) { public DTOLoginRespuesta modificarUsuarioDesdeToken(String token, String nuevoEmail, String nuevoNombreUsuario, String nuevaContrasenia, String contraseniaActual) {
String emailActual = jwtUtil.extractUsername(token.replace("Bearer ", "")); String emailActual = jwtUtil.extractUsername(token.replace("Bearer ", ""));
return modificarUsuario(emailActual, nuevoEmail, nuevoNombreUsuario, nuevaContrasenia, contraseniaActual); return modificarUsuario(emailActual, nuevoEmail, nuevoNombreUsuario, nuevaContrasenia, contraseniaActual);
} }
/**
* @brief Actualiza la descripción y/o la foto de perfil de un usuario.
* @param id ID del usuario que desea actualizar su perfil.
* @param nuevaDescripcion Nueva descripción textual para el perfil del usuario.
* @param fotoBase64 Imagen en formato base64 para la nueva foto de perfil (puede ser null o vacía si no se actualiza).
* @throws UsuarioNoExiste Si el usuario no se encuentra registrado en el sistema.
*/
public void actualizarPerfil(Long id, String nuevaDescripcion, String fotoBase64) { public void actualizarPerfil(Long id, String nuevaDescripcion, String fotoBase64) {
Usuario usuario = repositorioUsuario.findById(id) Usuario usuario = repositorioUsuario.findById(id)
.orElseThrow(UsuarioNoExiste::new); .orElseThrow(UsuarioNoExiste::new);
...@@ -205,6 +234,11 @@ public class ServicioUsuarios { ...@@ -205,6 +234,11 @@ public class ServicioUsuarios {
repositorioUsuario.actualizar(usuario); repositorioUsuario.actualizar(usuario);
} }
/**
* @brief Busca una lista de usuarios cuyo nombre de usuario contenga una subcadena dada.
* @param filtro Cadena parcial a buscar dentro del nombre de usuario.
* @return Lista de usuarios cuyo nombre coincide parcial o totalmente con el filtro.
*/
public List<Usuario> buscarPorNombre(String filtro) { public List<Usuario> buscarPorNombre(String filtro) {
return repositorioUsuario.buscarPorNombreParcial(filtro); return repositorioUsuario.buscarPorNombreParcial(filtro);
} }
......
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