Skip to content
Snippets Groups Projects
Commit 2d6f3903 authored by migudel's avatar migudel :speech_balloon:
Browse files

Merge branch 'develop' into 'dev/monolith/split_services_hotel_and_user'

# Conflicts:
#   java/roomBooking/src/main/java/com/uva/monolith/services/users/controllers/UserController.java
parents 6b7f97b2 06f0d032
No related branches found
No related tags found
2 merge requests!26Revert "Funciona register",!23Integración de servicio usuarios
Showing
with 612 additions and 132 deletions
......@@ -3,3 +3,7 @@ taller
*.pdf
**/target/
**/.vscode
*.ln
*.tmp
**/tmp
*.log
\ No newline at end of file
......@@ -8,7 +8,7 @@ networks:
services:
Auth-API:
image: auth-api-image
hostname: ${AUTH_SERVICE_HOSTNAME}
hostname: $${AUTH_SERVICE_HOSTNAME}
build:
context: ./java/services/auth
dockerfile: Dockerfile
......@@ -18,13 +18,13 @@ services:
networks:
- kong-net
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
depends_on:
- RoomsBooking-database
Users-API:
image: users-api-image
hostname: "${USERS_SERVICE_HOSTNAME}"
hostname: "$${USERS_SERVICE_HOSTNAME}"
build:
context: ./java/services/users
dockerfile: Dockerfile
......@@ -34,13 +34,13 @@ services:
networks:
- kong-net
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
depends_on:
- RoomsBooking-database
Hotels-API:
image: hotels-api-image
hostname: ${HOTELS_SERVICE_HOSTNAME}
hostname: $${HOTELS_SERVICE_HOSTNAME}
build:
context: ./java/services/hotels
dockerfile: Dockerfile
......@@ -50,16 +50,16 @@ services:
networks:
- kong-net
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_USER: ${USER_DATABASE}
SPRING_DATASOURCE_PASSWORD: ${}
SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_USER: $${USER_DATABASE}
SPRING_DATASOURCE_PASSWORD: $${}
depends_on:
- RoomsBooking-database
- Bookings-API
Bookings-API:
image: bookings-api-image
hostname: ${BOOKINGS_SERVICE_HOSTNAME}
hostname: $${BOOKINGS_SERVICE_HOSTNAME}
build:
context: ./java/services/bookings
dockerfile: Dockerfile
......@@ -69,13 +69,13 @@ services:
networks:
- kong-net
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
depends_on:
- RoomsBooking-database
RoomsBooking-database:
image: mysql
hostname: ${DB_SERVICE_HOSTNAME}
hostname: $${DB_SERVICE_HOSTNAME}
cap_add:
- SYS_NICE
restart: unless-stopped
......@@ -103,6 +103,6 @@ services:
networks:
- kong-net
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://${DB_SERVICE_HOSTNAME}:3306/${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
SPRING_DATASOURCE_URL: jdbc:mysql://$${DB_SERVICE_HOSTNAME}:3306/$${DB_DATABASE_NAME}?createDatabaseIfNotExist=true
depends_on:
- RoomsBooking-database
......@@ -48,6 +48,32 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
......
package com.uva.monolith.services.auth;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import com.uva.monolith.services.users.controllers.UserService;
import com.uva.monolith.services.users.models.User;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
private final String SECRET_KEY = "clave_secreta";
@Autowired
private UserService userService;
@PostMapping("/login")
public Map<String, String> login(@RequestBody LoginRequest loginRequest) {
User user = userService.findByEmail(loginRequest.getEmail());
if (user != null && userService.verifyPassword(loginRequest.getPassword(), user.getPassword())) {
String token = Jwts.builder()
.setSubject(user.getEmail())
.signWith(new SecretKeySpec(SECRET_KEY.getBytes(), SignatureAlgorithm.HS256.getJcaName()))
.claim("email", user.getEmail())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hora
.compact();
Map<String, String> response = new HashMap<>();
response.put("token", token);
return response;
}
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Credenciales inválidas");
}
}
package com.uva.monolith.services.auth;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import com.uva.monolith.services.users.models.UserRol;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.Filter;
import java.io.IOException;
import java.security.Key;
import java.util.Collections;
import java.util.Date;
@Component
public class JwtAuthenticationFilter implements Filter {
private final String SECRET_KEY = "3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b";
private Key getSignInKey() {
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
return Keys.hmacShaKeyFor(keyBytes);
}
private String getTokenFromRequest(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer "))
return null;
return authHeader.substring(7);
}
private Claims getClaimsFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSignInKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private boolean validateToken(String token) {
if (token == null)
return false;// no token
try {
// Verifica y analiza el token
Claims claims = getClaimsFromToken(token);
// Verifica que el token no esté expirado
return claims.getExpiration().after(new Date());
} catch (ExpiredJwtException e) {
System.out.println("Token expirado: " + e.getMessage());
} catch (UnsupportedJwtException e) {
System.out.println("Token no soportado: " + e.getMessage());
} catch (MalformedJwtException e) {
System.out.println("Token malformado: " + e.getMessage());
} catch (SignatureException e) {
System.out.println("Firma inválida: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("Token vacío o nulo: " + e.getMessage());
}
return false; // Si ocurre cualquier excepción, el token es inválido
}
private String getEmailFromToken(String token) {
return getClaimsFromToken(token).getSubject();
}
private UserRol getRoleFromToken(String token) {
String rol = getClaimsFromToken(token).get("rol", String.class);
return UserRol.valueOf(rol);
}
public static String getRol(UserRol rol) {
return String.format("ROLE_%s", rol.toString());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = getTokenFromRequest(httpRequest);
if (validateToken(token)) {
String email = getEmailFromToken(token);
UserRol role = getRoleFromToken(token); // Extraer el rol del token
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
email, null, null);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
// Agregar el rol como autoridad
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(getRol(role));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(email, null,
Collections.singletonList(authority));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
package com.uva.monolith.services.auth;
public class LoginRequest {
private String email;
private String password;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.uva.monolith.services.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.uva.monolith.services.users.models.UserRol;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize -> authorize
// Permitir todas las conexiones
.requestMatchers("").permitAll()
// Acceso restringido a usuarios y administradores
.requestMatchers("users", "users/**")
.hasAnyRole(UserRol.ADMIN.toString(), UserRol.CLIENT.toString())
// Acceso restringido a gestores de hoteles y administradores
.requestMatchers("hotels", "hotels/**")
.hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString())
// Acceso restringido a cualquier usuario del sistema
.requestMatchers("bookings", "bookings/**")
.hasAnyRole(UserRol.ADMIN.toString(), UserRol.HOTEL_ADMIN.toString(), UserRol.CLIENT.toString())
// Rechazar el resto
.anyRequest().denyAll())
// Registra el filtro antes del filtro estándar de autenticación
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
// BookingController.java
package com.uva.monolith.services.bookings.controllers;
import jakarta.transaction.Transactional;
import com.uva.monolith.services.bookings.models.Booking;
import com.uva.monolith.services.bookings.services.BookingService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.uva.monolith.services.bookings.models.Booking;
import com.uva.monolith.services.bookings.repositories.BookingRepository;
import com.uva.monolith.services.hotels.models.Room;
import com.uva.monolith.services.hotels.repositories.RoomRepository;
import com.uva.monolith.services.users.models.User;
import com.uva.monolith.services.users.repositories.UserRepository;
import java.time.LocalDate;
import java.util.List;
......@@ -22,89 +14,38 @@ import java.util.List;
@CrossOrigin(origins = "*")
public class BookingController {
private final BookingRepository bookingRepository;
private final UserRepository userRepository;
private final RoomRepository roomRepository;
private final BookingService bookingService;
public BookingController(BookingRepository bookingRepository, UserRepository userRepository,
RoomRepository roomRepository) {
this.bookingRepository = bookingRepository;
this.userRepository = userRepository;
this.roomRepository = roomRepository;
public BookingController(BookingService bookingService) {
this.bookingService = bookingService;
}
@GetMapping()
@GetMapping
public List<Booking> getAllBookings(
@RequestParam(required = false) LocalDate start,
@RequestParam(required = false) LocalDate end,
@RequestParam(required = false) Integer roomId,
@RequestParam(required = false) Integer userId) {
List<Booking> bookings = null;
if (start != null && end != null) {
bookings = bookingRepository.findByDateRange(start, end);
}
if (roomId != null) {
if (bookings == null) {
bookings = bookingRepository.findByRoomId(roomId);
} else {
bookings = bookings.stream()
.filter(booking -> booking.getRoomId().getId() == roomId)
.toList();
}
}
if (userId != null) {
if (bookings == null) {
bookings = bookingRepository.findByUserId(userId);
} else {
bookings = bookings.stream()
.filter(booking -> booking.getUserId().getId() == userId)
.toList();
}
}
if (start == null & end == null && roomId == null && userId == null) {
bookings = bookingRepository.findAll();
}
return bookings;
return bookingService.getBookings(start, end, roomId, userId);
}
@PostMapping
public Booking createBooking(@RequestBody Booking booking) {
User user = userRepository.findById(booking.getUserId().getId())
.orElseThrow(() -> new RuntimeException("User not found"));
Room room = roomRepository.findById(booking.getRoomId().getId())
.orElseThrow(() -> new RuntimeException("Room not found"));
// Verificar disponibilidad
List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange(
room.getId(), booking.getStartDate(), booking.getEndDate());
if (!existingBookings.isEmpty()) {
throw new RuntimeException("Room is not available for the selected dates");
}
booking.setUserId(user);
booking.setRoomId(room);
return bookingRepository.save(booking);
return bookingService.createBooking(booking);
}
@GetMapping("/{id}")
public Booking getBookingById(@PathVariable Integer id) {
return bookingRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Booking not found"));
return bookingService.getBookingById(id);
}
@DeleteMapping("/{id}")
@Transactional
public ResponseEntity<Void> deleteBooking(@PathVariable Integer id) {
try {
if (!bookingRepository.existsById(id))
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
bookingRepository.deleteBookingById(id);
bookingService.deleteBooking(id);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} catch (RuntimeException e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
package com.uva.monolith.services.bookings.services;
import com.uva.monolith.services.bookings.models.Booking;
import com.uva.monolith.services.bookings.repositories.BookingRepository;
import com.uva.monolith.services.hotels.models.Room;
import com.uva.monolith.services.hotels.repositories.RoomRepository;
import com.uva.monolith.services.users.models.User;
import com.uva.monolith.services.users.repositories.UserRepository;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
@Service
public class BookingService {
private final BookingRepository bookingRepository;
private final UserRepository userRepository;
private final RoomRepository roomRepository;
public BookingService(BookingRepository bookingRepository, UserRepository userRepository, RoomRepository roomRepository) {
this.bookingRepository = bookingRepository;
this.userRepository = userRepository;
this.roomRepository = roomRepository;
}
public List<Booking> getBookings(LocalDate start, LocalDate end, Integer roomId, Integer userId) {
List<Booking> bookings = null;
if (start != null && end != null) {
bookings = bookingRepository.findByDateRange(start, end);
}
if (roomId != null) {
if (bookings == null) {
bookings = bookingRepository.findByRoomId(roomId);
} else {
bookings = bookings.stream()
.filter(booking -> booking.getRoomId().getId() == roomId)
.toList();
}
}
if (userId != null) {
if (bookings == null) {
bookings = bookingRepository.findByUserId(userId);
} else {
bookings = bookings.stream()
.filter(booking -> booking.getUserId().getId() == userId)
.toList();
}
}
if (start == null && end == null && roomId == null && userId == null) {
bookings = bookingRepository.findAll();
}
return bookings;
}
public Booking createBooking(Booking booking) {
User user = userRepository.findById(booking.getUserId().getId())
.orElseThrow(() -> new RuntimeException("User not found"));
Room room = roomRepository.findById(booking.getRoomId().getId())
.orElseThrow(() -> new RuntimeException("Room not found"));
// Check availability
List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange(
room.getId(), booking.getStartDate(), booking.getEndDate());
if (!existingBookings.isEmpty()) {
throw new RuntimeException("Room is not available for the selected dates");
}
booking.setUserId(user);
booking.setRoomId(room);
return bookingRepository.save(booking);
}
public Booking getBookingById(Integer id) {
return bookingRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Booking not found"));
}
public void deleteBooking(Integer id) {
if (!bookingRepository.existsById(id)) {
throw new RuntimeException("Booking not found");
}
bookingRepository.deleteBookingById(id);
}
}
package com.uva.monolith.services.hotels.models;
import java.util.List;
import org.hibernate.annotations.ManyToAny;
import com.uva.monolith.services.users.models.HotelManager;
import jakarta.persistence.Basic;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
......@@ -34,14 +41,19 @@ public class Hotel {
@OneToMany(mappedBy = "hotel", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Room> rooms;
@ManyToOne(optional = false)
@JoinColumn(name = "hotel_manager", referencedColumnName = "id")
private HotelManager hotelManager;
public Hotel() {
}
public Hotel(int id, String name, Address address, List<Room> rooms) {
public Hotel(int id, String name, Address address, List<Room> rooms, HotelManager hotelManager) {
setId(id);
setName(name);
setAddress(address);
setRooms(rooms);
setHotelManager(hotelManager);
}
public int getId() {
......@@ -77,4 +89,11 @@ public class Hotel {
rooms.forEach(room -> room.setHotel(this));
}
public void setHotelManager(HotelManager hotelManager) {
this.hotelManager = hotelManager;
}
public HotelManager getHotelManager() {
return hotelManager;
}
}
......@@ -106,4 +106,5 @@ public class UserController {
throw e;
}
}
}
package com.uva.monolith.services.users.controllers;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.ResponseStatusException;
import com.uva.monolith.services.users.models.User;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import com.uva.monolith.services.users.repositories.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public boolean verifyPassword(String rawPassword, String encodedPassword) {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
public String encodePassword(String password) {
return passwordEncoder.encode(password);
}
public User findByEmail(@RequestParam String email) {
return userRepository.findByEmail(email)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Usuario no encontrado"));
}
}
package com.uva.monolith.services.users.models;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.uva.monolith.services.bookings.models.Booking;
import jakarta.persistence.Basic;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@Entity
@Table(name = "user_client")
public class Client extends User {
@Basic(optional = false)
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserStatus status;
@JsonIgnore
@OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Booking> bookings;
public Client() {
super();
bookings = new ArrayList<>();
status = UserStatus.NO_BOOKINGS;
}
public Client(int id, String name, String email, String password, UserStatus status,
List<Booking> bookings) {
super(id, name, email, password, UserRol.CLIENT);
setStatus(status);
setBookings(bookings);
}
public UserStatus getStatus() {
if (getBookings() == null || getBookings().isEmpty())
return UserStatus.NO_BOOKINGS;
boolean activeBookings = getBookings().stream()
.anyMatch(booking -> !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora
return activeBookings ? UserStatus.WITH_ACTIVE_BOOKINGS : UserStatus.WITH_INACTIVE_BOOKINGS;
}
public void setStatus(UserStatus status) {
this.status = status;
}
public List<Booking> getBookings() {
return this.bookings;
}
public void setBookings(List<Booking> bookings) {
this.bookings = bookings;
}
}
package com.uva.monolith.services.users.models;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.uva.monolith.services.hotels.models.Hotel;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@Entity
@Table(name = "hotel_manager_user")
public class HotelManager extends User {
@JsonIgnore
@OneToMany(mappedBy = "hotelManager", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Hotel> hotels;
public HotelManager() {
super();
hotels = new ArrayList<>();
}
public HotelManager(int id, String name, String email, String password, List<Hotel> hotels) {
super(id, name, email, password, UserRol.HOTEL_ADMIN);
setHotels(hotels);
}
public List<Hotel> getHotels() {
return this.hotels;
}
public void setHotels(List<Hotel> hotels) {
this.hotels = hotels;
}
}
package com.uva.monolith.services.users.models;
import java.time.LocalDate;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.uva.monolith.services.bookings.models.Booking;
import jakarta.persistence.Basic;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.Table;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "users")
public class User {
// TODO extraer a dos clases hijas, una por cada tipo
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(nullable = false)
private int id;
@Basic(optional = false)
@Column(nullable = false)
private String name;
@Basic(optional = false)
@Column(nullable = false, unique = true)
private String email;
@JsonIgnore
@Basic(optional = false)
@Column(nullable = false)
private String password;
@Basic(optional = false)
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserRol rol = UserRol.CONSUMER;
@Basic(optional = false)
@Enumerated(EnumType.STRING)
private UserStatus status;
@JsonIgnore
@OneToMany(mappedBy = "userId", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Booking> bookings;
private UserRol rol = UserRol.CLIENT;
public User() {
}
public User(int id, String name, String email, String password, UserRol rol, UserStatus status,
List<Booking> bookings) {
public User(int id, String name, String email, String password, UserRol rol) {
setId(id);
setName(name);
setEmail(email);
setRol(rol);
setStatus(status);
setBookings(bookings);
}
public int getId() {
......@@ -89,8 +81,8 @@ public class User {
return password;
}
public void setPassword(String password) {
this.password = password;
public void setPassword(String rawPassword) {
this.password = rawPassword;
}
public UserRol getRol() {
......@@ -100,24 +92,4 @@ public class User {
public void setRol(UserRol rol) {
this.rol = rol;
}
public UserStatus getStatus() {
if (getBookings() == null || getBookings().isEmpty())
return UserStatus.NO_BOOKINGS;
boolean activeBookings = getBookings().stream()
.anyMatch(booking -> !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora
return activeBookings ? UserStatus.WITH_ACTIVE_BOOKINGS : UserStatus.WITH_INACTIVE_BOOKINGS;
}
public void setStatus(UserStatus status) {
this.status = status;
}
public List<Booking> getBookings() {
return this.bookings;
}
public void setBookings(List<Booking> bookings) {
this.bookings = bookings;
}
}
package com.uva.monolith.services.users.models;
public enum UserRol {
HOTEL_ADMIN, CONSUMER
ADMIN, HOTEL_ADMIN, CLIENT
}
package com.uva.monolith.services.users.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.uva.monolith.services.users.models.Client;
public interface ClientRepository extends JpaRepository<Client, Integer> {
Optional<Client> findByEmail(String email);
}
\ No newline at end of file
package com.uva.monolith.services.users.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.uva.monolith.services.users.models.HotelManager;
public interface HotelManagerRepository extends JpaRepository<HotelManager, Integer> {
Optional<HotelManager> findByEmail(String email);
}
\ No newline at end of file
......@@ -48,6 +48,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
......
// TODO eliminar si realmente no necesitamos comunicar un servicio con otro
package com.uva.authentication.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
......@@ -10,6 +14,8 @@ import org.springframework.web.client.RestTemplate;
import com.uva.authentication.models.RegisterRequest;
import com.uva.authentication.models.User;
import com.uva.authentication.models.UserRol;
import com.uva.authentication.utils.JwtUtil;
@Component
public class UserAPI {
......@@ -20,10 +26,30 @@ public class UserAPI {
@Value("${external.services.users.baseurl}")
private String USER_API_URL;
@Autowired
private JwtUtil jwtUtil;
private String token;
private final User USER = new User(-1, "admin", null, null, UserRol.ADMIN);
private String getAccessToken() {
if (token == null || token.isEmpty() || jwtUtil.isTokenValid(token, USER)) {
token = jwtUtil.generateToken(USER);
}
return token;
}
public User getUserByEmail(String email) {
String url = USER_API_URL + "?email={email}";
String token = getAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
HttpEntity<Void> entity = new HttpEntity<>(headers);
String url = USER_API_URL + "?email={" + email + "}";
try {
ResponseEntity<User> userResponse = restTemplate.getForEntity(url, User.class, email);
// restTemplate.exchange(url, HttpMethod.GET, entity, User.class);
return userResponse.getBody();
} catch (HttpClientErrorException e) {
if (e.getStatusCode() != HttpStatus.NOT_FOUND)
......@@ -33,8 +59,13 @@ public class UserAPI {
}
public User registerUser(RegisterRequest registerRequest) {
String token = getAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
String url = USER_API_URL;
ResponseEntity<User> userResponse = restTemplate.postForEntity(url, registerRequest, User.class);
ResponseEntity<User> userResponse = restTemplate.postForEntity(url, registerRequest, User.class, headers);
if (!userResponse.getStatusCode().is2xxSuccessful())
throw new RuntimeException("Failed to register user");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment