diff --git a/pom.xml b/pom.xml
index 08cbbf2..830b8eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,4 +1,3 @@
-
4.0.0
@@ -6,39 +5,23 @@
org.springframework.boot
spring-boot-starter-parent
3.3.5
-
+
ie.atu
BookingService
0.0.1-SNAPSHOT
BookingService
BookingService
-
-
-
-
-
-
-
-
-
-
-
-
-
17
2023.0.3
+
org.springframework.boot
spring-boot-starter-validation
-
- org.springframework.cloud
- spring-cloud-starter-openfeign
-
org.springframework.boot
spring-boot-starter-data-mongodb
@@ -47,18 +30,54 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
- org.projectlombok
- lombok
- true
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+ runtime
+
+
org.springframework.boot
spring-boot-starter-test
test
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
@@ -71,22 +90,12 @@
-
org.springframework.boot
spring-boot-maven-plugin
-
-
-
- org.projectlombok
- lombok
-
-
-
-
diff --git a/src/main/java/ie/atu/bookingservice/BookingController.java b/src/main/java/ie/atu/bookingservice/BookingController.java
index 6fbfd7a..bbcdf02 100644
--- a/src/main/java/ie/atu/bookingservice/BookingController.java
+++ b/src/main/java/ie/atu/bookingservice/BookingController.java
@@ -1,5 +1,6 @@
package ie.atu.bookingservice;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@@ -23,13 +24,6 @@ public ResponseEntity createBooking(@RequestBody BookingDetails
return ResponseEntity.ok(createdBooking);
}
- // Endpoint to get all available bookings (those that are not yet booked)
- @GetMapping("/available")
- public ResponseEntity> getAvailableBookings() {
- List availableBookings = bookingService.getAvailableBookings();
- return ResponseEntity.ok(availableBookings);
- }
-
// Endpoint to get all bookings
@GetMapping
public ResponseEntity> getAllBookings() {
@@ -37,20 +31,6 @@ public ResponseEntity> getAllBookings() {
return ResponseEntity.ok(bookings);
}
- // Endpoint to get a booking by its ID
- @GetMapping("getbooking/{id}")
- public ResponseEntity getBookingById(@PathVariable String id) {
- Optional bookingDetails = bookingService.getBookingById(id);
- return bookingDetails.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
- }
-
- // Endpoint to get bookings by user ID
- @GetMapping("/user/{userId}")
- public ResponseEntity> getBookingByUserId(@PathVariable String userId) {
- List bookings = bookingService.getByBookingUserId(userId);
- return ResponseEntity.ok(bookings);
- }
-
// Endpoint for updating a booking
@PutMapping("update/{id}")
public ResponseEntity updateBooking(@PathVariable String id, @RequestBody BookingDetails bookingDetails) {
@@ -61,6 +41,23 @@ public ResponseEntity updateBooking(@PathVariable String id, @Re
return ResponseEntity.notFound().build();
}
+ @PostMapping("/confirmBooking")
+ public ResponseEntity confirmBooking(@RequestBody BookingDetails bookingDetails) {
+ String authToken = bookingDetails.getToken();
+
+ if (authToken == null || authToken.isEmpty()) {
+ return ResponseEntity.badRequest().body("Auth token is required.");
+ }
+
+ boolean isConfirmed = bookingService.confirmBooking(bookingDetails.getId());
+
+ if (isConfirmed) {
+ return ResponseEntity.ok("Booking confirmed successfully.");
+ } else {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Booking could not be confirmed.");
+ }
+ }
+
// Endpoint for deleting a booking
@DeleteMapping("delete/{id}")
public ResponseEntity deleteBooking(@PathVariable String id) {
diff --git a/src/main/java/ie/atu/bookingservice/BookingDetails.java b/src/main/java/ie/atu/bookingservice/BookingDetails.java
index e49abb8..d987d6e 100644
--- a/src/main/java/ie/atu/bookingservice/BookingDetails.java
+++ b/src/main/java/ie/atu/bookingservice/BookingDetails.java
@@ -14,6 +14,7 @@ public class BookingDetails {
private String serviceType;
private String status;
private Date bookingDate;
+ private String token = null;
public String getId() {
return id;
@@ -62,4 +63,22 @@ public Date getBookingDate() {
public void setBookingDate(Date bookingDate) {
this.bookingDate = bookingDate;
}
+
+ public void setBookedBy(String username) {
+ }
+
+ public void setBooked(boolean b) {
+ }
+
+ public boolean isBooked() {
+ return false;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
}
diff --git a/src/main/java/ie/atu/bookingservice/BookingService.java b/src/main/java/ie/atu/bookingservice/BookingService.java
index 73be71f..585f698 100644
--- a/src/main/java/ie/atu/bookingservice/BookingService.java
+++ b/src/main/java/ie/atu/bookingservice/BookingService.java
@@ -47,5 +47,19 @@ public List getAllBookings() {
public List getAvailableBookings() {
return bookingRepository.findByStatus("AVAILABLE");
}
+ public boolean confirmBooking(String id) {
+ Optional bookingOptional = bookingRepository.findById(id);
+ if (bookingOptional.isPresent()) {
+ BookingDetails booking = bookingOptional.get();
+ // Check if the status is "AVAILABLE"
+ if ("AVAILABLE".equals(booking.getStatus())) {
+ // If AVAILABLE, update status to "BOOKED"
+ booking.setStatus("BOOKED");
+ bookingRepository.save(booking); // Save the updated booking
+ return true;
+ }
+ }
+ return false; // Return false if the booking is not available or doesn't exist
+ }
}
diff --git a/src/main/java/ie/atu/bookingservice/SecurityConfig.java b/src/main/java/ie/atu/bookingservice/SecurityConfig.java
new file mode 100644
index 0000000..30fcf46
--- /dev/null
+++ b/src/main/java/ie/atu/bookingservice/SecurityConfig.java
@@ -0,0 +1,31 @@
+package ie.atu.bookingservice;
+
+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.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+
+@Configuration
+public class SecurityConfig {
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .csrf(csrf -> csrf.disable())
+ .authorizeHttpRequests(auth -> auth
+ .requestMatchers("/api/booking/confirmBooking").permitAll()
+ .anyRequest().authenticated() // Protect all other endpoints
+ )
+ .httpBasic(httpBasic -> httpBasic.disable())
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // Stateless JWT auth
+ return http.build();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ie/atu/bookingservice/BookingControllerTest.java b/src/test/java/ie/atu/bookingservice/BookingControllerTest.java
index 84a7280..274ddbc 100644
--- a/src/test/java/ie/atu/bookingservice/BookingControllerTest.java
+++ b/src/test/java/ie/atu/bookingservice/BookingControllerTest.java
@@ -1,4 +1,5 @@
package ie.atu.bookingservice;
+
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -9,17 +10,17 @@
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
-import java.util.Arrays;
import java.util.Date;
-import java.util.List;
-import java.util.Optional;
import static org.mockito.Mockito.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(BookingController.class)
class BookingControllerTest {
+
@Autowired
private MockMvc mockMvc;
@@ -47,7 +48,9 @@ void createBooking_ShouldReturnCreatedBooking() throws Exception {
mockMvc.perform(post("/api/booking/createBooking")
.contentType(MediaType.APPLICATION_JSON)
- .content(objectMapper.writeValueAsString(bookingDetails)))
+ .content(objectMapper.writeValueAsString(bookingDetails))
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value("1"))
.andExpect(jsonPath("$.userId").value("User1"));
@@ -56,68 +59,63 @@ void createBooking_ShouldReturnCreatedBooking() throws Exception {
}
@Test
- void getAvailableBookings_ShouldReturnAvailableBookings() throws Exception {
- List availableBookings = Arrays.asList(bookingDetails);
- when(bookingService.getAvailableBookings()).thenReturn(availableBookings);
+ void confirmBooking_ShouldReturnBookingNotConfirmed() throws Exception {
+ bookingDetails.setToken("mock-token"); // Mock valid token
- mockMvc.perform(get("/api/booking/available")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.size()").value(1))
- .andExpect(jsonPath("$[0].id").value("1"));
-
- verify(bookingService, times(1)).getAvailableBookings();
- }
+ when(bookingService.confirmBooking(bookingDetails.getId())).thenReturn(false);
- @Test
- void getAllBookings_ShouldReturnAllBookings() throws Exception {
- List allBookings = Arrays.asList(bookingDetails);
- when(bookingService.getAllBookings()).thenReturn(allBookings);
-
- mockMvc.perform(get("/api/booking")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.size()").value(1))
- .andExpect(jsonPath("$[0].id").value("1"));
+ mockMvc.perform(post("/api/booking/confirmBooking")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(bookingDetails))
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
+ .andExpect(status().isBadRequest())
+ .andExpect(content().string("Booking could not be confirmed."));
- verify(bookingService, times(1)).getAllBookings();
+ verify(bookingService, times(1)).confirmBooking(bookingDetails.getId());
}
@Test
- void getBookingById_ShouldReturnBookingWhenFound() throws Exception {
- when(bookingService.getBookingById("1")).thenReturn(Optional.of(bookingDetails));
+ void confirmBooking_ShouldReturnBookingConfirmed() throws Exception {
+ bookingDetails.setToken("mock-token"); // Mock valid token
- mockMvc.perform(get("/api/booking/getbooking/1")
- .contentType(MediaType.APPLICATION_JSON))
+ when(bookingService.confirmBooking(bookingDetails.getId())).thenReturn(true);
+
+ mockMvc.perform(post("/api/booking/confirmBooking")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(bookingDetails))
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
.andExpect(status().isOk())
- .andExpect(jsonPath("$.id").value("1"));
+ .andExpect(content().string("Booking confirmed successfully."));
- verify(bookingService, times(1)).getBookingById("1");
+ verify(bookingService, times(1)).confirmBooking(bookingDetails.getId());
}
@Test
- void getBookingById_ShouldReturnNotFoundWhenNotFound() throws Exception {
- when(bookingService.getBookingById("2")).thenReturn(Optional.empty());
-
- mockMvc.perform(get("/api/booking/getbooking/2")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isNotFound());
+ void confirmBooking_ShouldReturnUnauthorizedIfInvalidToken() throws Exception {
+ bookingDetails.setToken("invalid-token"); // Mock invalid token
- verify(bookingService, times(1)).getBookingById("2");
+ mockMvc.perform(post("/api/booking/confirmBooking")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(bookingDetails))
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
+ .andExpect(status().isUnauthorized())
+ .andExpect(content().string("Invalid or expired auth token."));
}
@Test
- void getBookingByUserId_ShouldReturnBookingsForUser() throws Exception {
- List userBookings = Arrays.asList(bookingDetails);
- when(bookingService.getByBookingUserId("User1")).thenReturn(userBookings);
+ void deleteBooking_ShouldReturnOk() throws Exception {
+ doNothing().when(bookingService).deleteBooking("1");
- mockMvc.perform(get("/api/booking/user/User1")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.size()").value(1))
- .andExpect(jsonPath("$[0].id").value("1"));
+ mockMvc.perform(delete("/api/booking/delete/1")
+ .contentType(MediaType.APPLICATION_JSON)
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
+ .andExpect(status().isOk());
- verify(bookingService, times(1)).getByBookingUserId("User1");
+ verify(bookingService, times(1)).deleteBooking("1");
}
@Test
@@ -134,34 +132,13 @@ void updateBooking_ShouldReturnUpdatedBooking() throws Exception {
mockMvc.perform(put("/api/booking/update/1")
.contentType(MediaType.APPLICATION_JSON)
- .content(objectMapper.writeValueAsString(updatedBooking)))
+ .content(objectMapper.writeValueAsString(updatedBooking))
+ .with(csrf()) // Add CSRF token
+ .with(user("mockUser").roles("USER"))) // Mock user authentication
.andExpect(status().isOk())
.andExpect(jsonPath("$.userId").value("User2"))
.andExpect(jsonPath("$.status").value("BOOKED"));
verify(bookingService, times(1)).updateBooking(eq("1"), Mockito.any(BookingDetails.class));
}
-
- @Test
- void updateBooking_ShouldReturnNotFoundWhenNotFound() throws Exception {
- when(bookingService.updateBooking(eq("2"), Mockito.any(BookingDetails.class))).thenReturn(null);
-
- mockMvc.perform(put("/api/booking/update/2")
- .contentType(MediaType.APPLICATION_JSON)
- .content(objectMapper.writeValueAsString(bookingDetails)))
- .andExpect(status().isNotFound());
-
- verify(bookingService, times(1)).updateBooking(eq("2"), Mockito.any(BookingDetails.class));
- }
-
- @Test
- void deleteBooking_ShouldReturnOk() throws Exception {
- doNothing().when(bookingService).deleteBooking("1");
-
- mockMvc.perform(delete("/api/booking/delete/1")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
-
- verify(bookingService, times(1)).deleteBooking("1");
- }
-}
\ No newline at end of file
+}