Skip to content
Snippets Groups Projects
Commit 56e2c695 authored by hugcubi's avatar hugcubi
Browse files

Avance en la correcta comunicación de los servicios, JWT integrado y algunas conexiones planteadas

parent 28d00e19
No related branches found
No related tags found
1 merge request!36Develop
Showing
with 292 additions and 146 deletions
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
## AUTH ## AUTH
API_AUTH_ENDPOINT=/users API_AUTH_ENDPOINT=/users
API_AUTH_HOSTNAME=auth-api API_AUTH_HOSTNAME=auth-api
API_AUTH_PORT=8201 API_AUTH_PORT=8101
API_AUTH_URL=http://$API_AUTH_HOSTNAME:$API_AUTH_PORT$API_AUTH_ENDPOINT API_AUTH_URL=http://$API_AUTH_HOSTNAME:$API_AUTH_PORT$API_AUTH_ENDPOINT
## Bookings ## Bookings
API_BOOKINGS_ENDPOINT=/bookings API_BOOKINGS_ENDPOINT=/bookings
API_BOOKINGS_HOSTNAME=bookings-api API_BOOKINGS_HOSTNAME=bookings-api
API_BOOKINGS_PORT=4201 API_BOOKINGS_PORT=8401
API_BOOKINGS_URL=http://$API_BOOKINGS_HOSTNAME:$API_BOOKINGS_PORT$API_BOOKINGS_ENDPOINT API_BOOKINGS_URL=http://$API_BOOKINGS_HOSTNAME:$API_BOOKINGS_PORT$API_BOOKINGS_ENDPOINT
## Hotels ## Hotels
API_HOTELS_ENDPOINT=/hotels API_HOTELS_ENDPOINT=/hotels
......
...@@ -48,4 +48,15 @@ public class BookingController { ...@@ -48,4 +48,15 @@ public class BookingController {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} }
} }
@DeleteMapping("/hotel/{hotelId}")
public ResponseEntity<Void> deleteBookingsByHotelId(@PathVariable Integer hotelId) {
try {
bookingService.deleteBookingsByHotelId(hotelId);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
} catch (RuntimeException e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
} }
...@@ -86,4 +86,8 @@ public class BookingService { ...@@ -86,4 +86,8 @@ public class BookingService {
} }
bookingRepository.deleteBookingById(id); bookingRepository.deleteBookingById(id);
} }
public void deleteBookingsByHotelId(int hotelId) {
bookingRepository.deleteAllByHotelId(hotelId);
}
} }
...@@ -30,19 +30,10 @@ ...@@ -30,19 +30,10 @@
<java.version>17</java.version> <java.version>17</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId> <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
......
spring.application.name=authService spring.application.name=authService
server.port=8101 server.port=8101
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/RoomsBooking?createDatabaseIfNotExist=true
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone
# spring.data.rest.base-path=false
security.jwt.secret-key=MiClaveDeSeguridadMuyLargaParaQueNoFalleSpringBoot security.jwt.secret-key=MiClaveDeSeguridadMuyLargaParaQueNoFalleSpringBoot
# 1h in millisecond # 1h in millisecond
security.jwt.expiration-time=3600000 security.jwt.expiration-time=3600000
security.jwt.kid=cYz3kNRLAirxVhHXQ5rh5xKrOwHwZVui security.jwt.kid=cYz3kNRLAirxVhHXQ5rh5xKrOwHwZVui
external.services.users.url=http://localhost:8080/users external.services.users.url=http://localhost:8201/users
\ No newline at end of file \ No newline at end of file
...@@ -4,18 +4,20 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -4,18 +4,20 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@Component
public class ClientApi { public class ClientApi {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Value("${external.services.users.url}") @Value("${external.services.clients.url}")
private String USER_API_URL; private String CLIENTS_API_URL;
public boolean existsById(int id) { public boolean existsById(int id) {
String url = USER_API_URL + "/client/{id}"; String url = CLIENTS_API_URL + "/{id}";
ResponseEntity<Void> response = restTemplate.getForEntity(url, Void.class, id); ResponseEntity<Void> response = restTemplate.getForEntity(url, Void.class, id);
return response.getStatusCode() == HttpStatus.OK; return response.getStatusCode() == HttpStatus.OK;
} }
......
...@@ -4,8 +4,10 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -4,8 +4,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@Component
public class HotelApi { public class HotelApi {
@Autowired @Autowired
......
package com.uva.apis.bookings.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
package com.uva.apis.bookings.controllers; package com.uva.apis.bookings.controllers;
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.*;
...@@ -15,19 +16,17 @@ import java.util.List; ...@@ -15,19 +16,17 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
public class BookingController { public class BookingController {
private final BookingService bookingService; @Autowired
private BookingService bookingService;
public BookingController(BookingService bookingService) {
this.bookingService = bookingService;
}
@GetMapping @GetMapping
public List<Booking> getAllBookings( public List<Booking> getAllBookings(
@RequestParam(required = false) LocalDate start, @RequestParam(required = false) LocalDate start,
@RequestParam(required = false) LocalDate end, @RequestParam(required = false) LocalDate end,
@RequestParam(required = false) Integer hotelId,
@RequestParam(required = false) Integer roomId, @RequestParam(required = false) Integer roomId,
@RequestParam(required = false) Integer userId) { @RequestParam(required = false) Integer userId) {
return bookingService.getBookings(start, end, roomId, userId); return bookingService.getBookings(start, end, hotelId, roomId, userId);
} }
@PostMapping @PostMapping
......
...@@ -32,12 +32,6 @@ public class JwtAuthenticationFilter implements Filter { ...@@ -32,12 +32,6 @@ public class JwtAuthenticationFilter implements Filter {
@Value("${security.jwt.secret-key}") @Value("${security.jwt.secret-key}")
private String secretKey; private String secretKey;
@Value("${security.jwt.kid}")
private String kid;
@Value("${security.jwt.expiration-time}")
private long jwtExpiration;
private Algorithm getSigningAlgorithm() { private Algorithm getSigningAlgorithm() {
return Algorithm.HMAC256(secretKey); // Usar HMAC256 con la clave secreta return Algorithm.HMAC256(secretKey); // Usar HMAC256 con la clave secreta
} }
......
package com.uva.apis.bookings.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.stereotype.Component;
import com.uva.apis.bookings.models.external.users.UserRol;
import com.uva.apis.bookings.utils.JwtUtil;
import java.io.IOException;
@Component
public class AuthHttpInterceptor implements ClientHttpRequestInterceptor {
@Autowired
private JwtUtil jwtUtil;
private String token;
private String getAccessToken() {
if (token == null || token.isEmpty()) {
// TODO cambiar también si el token ha caducado
token = jwtUtil.generateToken("auth", "auth@dev.com", UserRol.ADMIN);
}
return token;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
// Generar o cargar el JWT token desde el bean JwtUtil
String jwtToken = getAccessToken();
// System.out.println("Using token " + jwtToken);
// Agregar el token al encabezado Authorization
request.getHeaders().add("Authorization", "Bearer " + jwtToken);
// Continuar con la ejecución de la solicitud
return execution.execute(request, body);
}
}
// BookingRepository.java // BookingRepository.java
package com.uva.apis.bookings.repositories; package com.uva.apis.bookings.repositories;
import jakarta.transaction.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import com.uva.apis.bookings.models.Booking; import com.uva.apis.bookings.models.Booking;
public interface BookingRepository extends JpaRepository<Booking, Integer> { public interface BookingRepository extends JpaRepository<Booking, Integer> {
@Query("SELECT b FROM Booking b WHERE b.userId.id = ?1")
List<Booking> findByUserId(int userId); List<Booking> findByUserId(int userId);
@Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1")
List<Booking> findByRoomId(int roomId); List<Booking> findByRoomId(int roomId);
@Query("SELECT b FROM Booking b WHERE b.startDate >= ?1 AND b.endDate <= ?2") @Query("SELECT b FROM Booking b WHERE b.startDate >= ?1 AND b.endDate <= ?2")
List<Booking> findByDateRange(@Param("startDate") LocalDate startDate, List<Booking> findByDateRange(@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate); @Param("endDate") LocalDate endDate);
@Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1 AND b.startDate < ?2 AND b.endDate > ?3") @Query("SELECT b FROM Booking b WHERE b.roomId = ?1 AND b.startDate < ?2 AND b.endDate > ?3")
List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate); @Param("endDate") LocalDate endDate);
@Transactional
@Modifying
void deleteById(int id); void deleteById(int id);
@Transactional
@Modifying
void deleteAllByHotelId(int hotelId); void deleteAllByHotelId(int hotelId);
List<Booking> findByHotelId(Integer roomId);
} }
...@@ -25,12 +25,28 @@ public class BookingService { ...@@ -25,12 +25,28 @@ public class BookingService {
@Autowired @Autowired
private ClientApi managerApi; private ClientApi managerApi;
public List<Booking> getBookings(LocalDate start, LocalDate end, Integer roomId, Integer userId) { /**
* Consulta por bloques filtrados
* - fechas
* - roomId/hotelId
* - userId
*
* @param start
* @param end
* @param hotelId
* @param roomId
* @param userId
* @return
*/
public List<Booking> getBookings(
LocalDate start, LocalDate end, Integer hotelId,
Integer roomId, Integer userId) {
List<Booking> bookings = null; List<Booking> bookings = null;
if (start != null && end != null) { if (start != null && end != null) {
bookings = bookingRepository.findByDateRange(start, end); bookings = bookingRepository.findByDateRange(start, end);
} }
if (roomId != null) { if (roomId != null) {
if (bookings == null) { if (bookings == null) {
bookings = bookingRepository.findByRoomId(roomId); bookings = bookingRepository.findByRoomId(roomId);
...@@ -39,7 +55,16 @@ public class BookingService { ...@@ -39,7 +55,16 @@ public class BookingService {
.filter(booking -> booking.getRoomId() == roomId) .filter(booking -> booking.getRoomId() == roomId)
.toList(); .toList();
} }
} else if (hotelId != null) {
if (bookings == null) {
bookings = bookingRepository.findByHotelId(roomId);
} else {
bookings = bookings.stream()
.filter(booking -> booking.getHotelId() == hotelId)
.toList();
}
} }
if (userId != null) { if (userId != null) {
if (bookings == null) { if (bookings == null) {
bookings = bookingRepository.findByUserId(userId); bookings = bookingRepository.findByUserId(userId);
...@@ -49,6 +74,7 @@ public class BookingService { ...@@ -49,6 +74,7 @@ public class BookingService {
.toList(); .toList();
} }
} }
if (start == null && end == null && roomId == null && userId == null) { if (start == null && end == null && roomId == null && userId == null) {
bookings = bookingRepository.findAll(); bookings = bookingRepository.findAll();
} }
......
package com.uva.apis.bookings.utils;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.uva.apis.bookings.models.external.users.UserRol;
@Component
public class JwtUtil {
@Value("${security.jwt.secret-key}")
private String secretKey;
@Value("${security.jwt.kid}")
private String kid;
@Value("${security.jwt.expiration-time}")
private long jwtExpiration;
public long getExpirationTime() {
return jwtExpiration;
}
public String generateToken(String name, String email, UserRol rol) {
Algorithm algorithm = Algorithm.HMAC256(secretKey);
return JWT
.create()
.withKeyId(kid)
.withClaim("name", name)
.withClaim("email", email)
.withClaim("rol", rol.toString())
.withIssuedAt(new Date())
.withExpiresAt(new Date(System.currentTimeMillis() + jwtExpiration * 1000))
.sign(algorithm);
}
// TODO estaría guapo recuperar métodos de validación para el token de petición
// para este servicio
}
spring.application.name=roomBooking spring.application.name=bookings
server.port=8401
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/RoomsBooking?createDatabaseIfNotExist=true spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/Bookings?createDatabaseIfNotExist=true
spring.datasource.username=user spring.datasource.username=user
spring.datasource.password=password spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.security.user.name=admin
spring.security.user.password=admin
# Usar esto para alternar entre las exposición del room repository ya que no es necesario su uso pero por defecto, al no cubrir su ruta, se expone security.jwt.secret-key=MiClaveDeSeguridadMuyLargaParaQueNoFalleSpringBoot
# spring.data.rest.base-path=false # 1h in millisecond
external.services.auth.host=localhost:8101 security.jwt.expiration-time=3600000
security.jwt.kid=cYz3kNRLAirxVhHXQ5rh5xKrOwHwZVui
external.services.clients.url=localhost:8201/users/clients
external.services.hotels.url=localhost:8301/hotels
\ No newline at end of file
package com.uva.monolith.api; package com.uva.monolith.api;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@Component @Component
public class BookingAPI { public class BookingAPI {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Value("${external.services.users.url}") @Value("${external.services.bookings.url}")
private String BOOKING_API_URL; private String BOOKING_API_URL;
public void deleteAllByHotelId(Integer id) { public void deleteAllByHotelId(Integer id) {
try {
String url = BOOKING_API_URL + "?hotelId={id}"; String url = BOOKING_API_URL + "?hotelId={id}";
restTemplate.delete(url, id); restTemplate.delete(url, id);
} catch (HttpClientErrorException e) {
throw e;
} }
}
public Set<Integer> getNotAvailableRooms(LocalDate start, LocalDate end) {
String url = BOOKING_API_URL + "?start={start}&end={end}";
Map<?, ?>[] bookingsArray = restTemplate
.getForObject(url, Map[].class, start, end);
Set<Integer> notAvailableRooms = new HashSet<>();
for (Map<?, ?> booking : bookingsArray)
notAvailableRooms.add((Integer) booking.get("roomId"));
return notAvailableRooms;
} }
public Set<Integer> getNotAvailableRooms(int hotelId, LocalDate start, LocalDate end) {
String url = BOOKING_API_URL + "?hotelId={hotelId}&start={start}&end={end}";
Map<?, ?>[] bookingsArray = restTemplate
.getForObject(url, Map[].class, hotelId, start, end);
Set<Integer> notAvailableRooms = new HashSet<>();
for (Map<?, ?> booking : bookingsArray)
notAvailableRooms.add((Integer) booking.get("roomId"));
return notAvailableRooms;
}
//restTemplate.getForEntity(url, User.class, email) }
\ No newline at end of file \ No newline at end of file
...@@ -15,12 +15,12 @@ public class HotelManagerAPI { ...@@ -15,12 +15,12 @@ public class HotelManagerAPI {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Value("${external.services.users.url}") @Value("${external.services.managers.url}")
private String HOTELMANAGER_API_URL; private String MANAGERS_API_URL;
public Boolean existsHotelManagerById(int id) { public Boolean existsHotelManagerById(int id) {
try { try {
String url = HOTELMANAGER_API_URL + "/{id}"; String url = MANAGERS_API_URL + "/{id}";
return restTemplate.getForEntity(url, Map.class, id).getBody().containsKey("id"); return restTemplate.getForEntity(url, Map.class, id).getBody().containsKey("id");
} catch (HttpClientErrorException e) { } catch (HttpClientErrorException e) {
if (e.getStatusCode() != HttpStatus.NOT_FOUND) if (e.getStatusCode() != HttpStatus.NOT_FOUND)
...@@ -29,5 +29,4 @@ public class HotelManagerAPI { ...@@ -29,5 +29,4 @@ public class HotelManagerAPI {
} }
} }
} }
package com.uva.monolith.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment