From a9921243a29e9eacff7bd0616b6daf559bdf7b0f Mon Sep 17 00:00:00 2001 From: EnesBaserr Date: Mon, 13 May 2024 23:07:52 +0300 Subject: [PATCH 1/2] Formatting responses for /search (dishes) --- .../controllers/AuthenticationController.java | 13 +++++++-- .../controllers/SearchController.java | 7 +++-- .../group1/cuisines/dto/DishResponseDto.java | 19 ++++++++++++ .../exceptions/GlobalExceptionHandler.java | 26 +++++++++++++++++ .../exceptions/ResourceNotFoundException.java | 7 +++++ .../services/AuthenticationService.java | 2 +- .../cuisines/services/SearchService.java | 29 +++++++++++++++++-- 7 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/com/group1/cuisines/dto/DishResponseDto.java create mode 100644 backend/src/main/java/com/group1/cuisines/exceptions/GlobalExceptionHandler.java create mode 100644 backend/src/main/java/com/group1/cuisines/exceptions/ResourceNotFoundException.java diff --git a/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java b/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java index 0ffe909b..9efcd63c 100644 --- a/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java +++ b/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java @@ -6,6 +6,7 @@ import com.group1.cuisines.dao.response.AuthenticationTokenResponse; import com.group1.cuisines.services.AuthenticationService; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -20,10 +21,18 @@ public class AuthenticationController { private final AuthenticationService authenticationService; // Authentication service @PostMapping("/signup") // Sign up endpoint - public ResponseEntity> signup( + public ResponseEntity signup( @RequestBody SignUpRequest request ) { - return ResponseEntity.ok(authenticationService.signup(request)); // Return response + ApiResponse response = authenticationService.signup(request); + + if (response.getStatus() == 409) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(response); + } else if (response.getStatus() == 400) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } else { + return ResponseEntity.status(HttpStatus.CREATED).body(response); + } } @PostMapping("/login") // Sign in endpoint diff --git a/backend/src/main/java/com/group1/cuisines/controllers/SearchController.java b/backend/src/main/java/com/group1/cuisines/controllers/SearchController.java index 05799f48..77bb7669 100644 --- a/backend/src/main/java/com/group1/cuisines/controllers/SearchController.java +++ b/backend/src/main/java/com/group1/cuisines/controllers/SearchController.java @@ -1,6 +1,7 @@ package com.group1.cuisines.controllers; import com.group1.cuisines.dao.response.ApiResponse; +import com.group1.cuisines.dto.DishResponseDto; import com.group1.cuisines.entities.Dish; import com.group1.cuisines.entities.User; import com.group1.cuisines.services.SearchService; @@ -34,9 +35,9 @@ public ResponseEntity searchUsers(@RequestParam(required = false) String q) { } @GetMapping("/dishes") - public ApiResponse> searchDishes(@RequestParam(required = false) String q, - @RequestParam(required = false) String cuisine, - @RequestParam(required = false) String foodType) { + public ApiResponse> searchDishes(@RequestParam(required = false) String q, + @RequestParam(required = false) String cuisine, + @RequestParam(required = false) String foodType) { return new ApiResponse<>( 200, "Search completed", diff --git a/backend/src/main/java/com/group1/cuisines/dto/DishResponseDto.java b/backend/src/main/java/com/group1/cuisines/dto/DishResponseDto.java new file mode 100644 index 00000000..6eb4915e --- /dev/null +++ b/backend/src/main/java/com/group1/cuisines/dto/DishResponseDto.java @@ -0,0 +1,19 @@ +package com.group1.cuisines.dto; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DishResponseDto { + private String id; + private String name; + private String image; + private String description; + private String countries; + private String ingredients; + private String foodTypes; + private String cuisines; +} diff --git a/backend/src/main/java/com/group1/cuisines/exceptions/GlobalExceptionHandler.java b/backend/src/main/java/com/group1/cuisines/exceptions/GlobalExceptionHandler.java new file mode 100644 index 00000000..bff8d299 --- /dev/null +++ b/backend/src/main/java/com/group1/cuisines/exceptions/GlobalExceptionHandler.java @@ -0,0 +1,26 @@ +package com.group1.cuisines.exceptions; + +import com.group1.cuisines.dao.response.ApiResponse; +import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleException(Exception e) { + ApiResponse response = new ApiResponse<>(500, "An unexpected error occurred: " + e.getMessage(), null); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity> handleResourceNotFoundException(ResourceNotFoundException e) { + ApiResponse response = new ApiResponse<>(400, e.getMessage(), null); + return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); + } + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/group1/cuisines/exceptions/ResourceNotFoundException.java b/backend/src/main/java/com/group1/cuisines/exceptions/ResourceNotFoundException.java new file mode 100644 index 00000000..d1ab87bf --- /dev/null +++ b/backend/src/main/java/com/group1/cuisines/exceptions/ResourceNotFoundException.java @@ -0,0 +1,7 @@ +package com.group1.cuisines.exceptions; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/group1/cuisines/services/AuthenticationService.java b/backend/src/main/java/com/group1/cuisines/services/AuthenticationService.java index 06bb7823..1221f008 100644 --- a/backend/src/main/java/com/group1/cuisines/services/AuthenticationService.java +++ b/backend/src/main/java/com/group1/cuisines/services/AuthenticationService.java @@ -52,7 +52,7 @@ public ApiResponse signup( String token = jwtService.generateToken(user); return new ApiResponse<>( - 200, + 201, "User registered successfully.", AuthenticationTokenResponse.builder().token(token).build() ); diff --git a/backend/src/main/java/com/group1/cuisines/services/SearchService.java b/backend/src/main/java/com/group1/cuisines/services/SearchService.java index ee33a83e..abbe6422 100644 --- a/backend/src/main/java/com/group1/cuisines/services/SearchService.java +++ b/backend/src/main/java/com/group1/cuisines/services/SearchService.java @@ -1,6 +1,9 @@ package com.group1.cuisines.services; +import com.group1.cuisines.dto.DishDto; +import com.group1.cuisines.dto.DishResponseDto; import com.group1.cuisines.entities.Dish; +import com.group1.cuisines.exceptions.ResourceNotFoundException; import com.group1.cuisines.repositories.DishRepository; import com.group1.cuisines.repositories.UserRepository; import lombok.RequiredArgsConstructor; @@ -16,17 +19,23 @@ public class SearchService { private final DishRepository dishRepository; - public List searchDishes(String query, String cuisine, String foodType) { + public List searchDishes(String query, String cuisine, String foodType) { List dishes = dishRepository.findAll(); // Filter by dish name if (query != null && !query.isEmpty()) { dishes = dishRepository.findByNameContainingIgnoreCase(query); + if (dishes.isEmpty()) { + throw new ResourceNotFoundException("No dishes found with the given name query."); + } } // Filter by cuisine name if (cuisine != null && !cuisine.isEmpty()) { List dishesByCuisine = dishRepository.findByCuisinesName(cuisine); + if (dishesByCuisine.isEmpty()) { + throw new ResourceNotFoundException("No dishes found with the given cuisine."); + } dishes = dishes.stream() .filter(dishesByCuisine::contains) .collect(Collectors.toList()); @@ -37,9 +46,25 @@ public List searchDishes(String query, String cuisine, String foodType) { dishes = dishes.stream() .filter(d -> d.getFoodTypes() != null && d.getFoodTypes().contains(foodType)) .collect(Collectors.toList()); + + if (dishes.isEmpty()) { + throw new ResourceNotFoundException("No dishes found with the given food type."); + } } - return dishes; + // Map to DishResponseDto + return dishes.stream() + .map(d -> new DishResponseDto( + d.getId(), + d.getName(), + d.getImage(), + d.getDescription(), + d.getCountries(), + d.getIngredients(), + d.getFoodTypes(), + d.getCuisines().isEmpty() ? null : d.getCuisines().get(0).getName() + )) + .collect(Collectors.toList()); } From 98abe2a9737297cfa68f14be4e543563506bdbe3 Mon Sep 17 00:00:00 2001 From: EnesBaserr Date: Mon, 13 May 2024 23:25:18 +0300 Subject: [PATCH 2/2] Test cases updated. --- backend/pom.xml | 12 ++ .../controllers/AuthenticationController.java | 10 +- .../AuthenticationControllerTest.java | 151 ++++++------------ 3 files changed, 67 insertions(+), 106 deletions(-) diff --git a/backend/pom.xml b/backend/pom.xml index 470caae3..81791029 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -21,6 +21,18 @@ org.springframework.boot spring-boot-starter-security + + org.mockito + mockito-core + 5.2.0 + test + + + org.mockito + mockito-junit-jupiter + 5.2.0 + test + org.apache.jena apache-jena-libs diff --git a/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java b/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java index 9efcd63c..777b70ad 100644 --- a/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java +++ b/backend/src/main/java/com/group1/cuisines/controllers/AuthenticationController.java @@ -21,7 +21,7 @@ public class AuthenticationController { private final AuthenticationService authenticationService; // Authentication service @PostMapping("/signup") // Sign up endpoint - public ResponseEntity signup( + public ResponseEntity> signup( @RequestBody SignUpRequest request ) { ApiResponse response = authenticationService.signup(request); @@ -39,6 +39,12 @@ public ResponseEntity signup( public ResponseEntity> signin( @RequestBody SignInRequest request ) { - return ResponseEntity.ok(authenticationService.signin(request)); // Return response + ApiResponse response = authenticationService.signin(request); + + if (response.getStatus() == 401) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } else { + return ResponseEntity.ok(response); + } } } diff --git a/backend/src/test/java/com/group1/cuisines/AuthenticationControllerTest.java b/backend/src/test/java/com/group1/cuisines/AuthenticationControllerTest.java index d3d6218b..4aa77e4c 100644 --- a/backend/src/test/java/com/group1/cuisines/AuthenticationControllerTest.java +++ b/backend/src/test/java/com/group1/cuisines/AuthenticationControllerTest.java @@ -14,6 +14,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; public class AuthenticationControllerTest { @@ -31,123 +32,65 @@ public void setUp() { @Test public void shouldReturnSuccessOnValidSignin() { - SignInRequest signInRequest = new SignInRequest( - "testUser", - "testPassword" - ); - ApiResponse apiResponse = - new ApiResponse<>( - 200, - "Success", - new AuthenticationTokenResponse("token") - ); - when(authenticationService.signin(signInRequest)).thenReturn( - apiResponse - ); - ResponseEntity< - ApiResponse - > responseEntity = authenticationController.signin(signInRequest); - assertEquals( - 200, - responseEntity.getBody().getStatus(), - "Status code does not match expected value on successful signin" - ); - assertEquals( - apiResponse, - responseEntity.getBody(), - "Response body does not match expected value on successful signin" - ); + SignInRequest signInRequest = new SignInRequest("testUser", "testPassword"); + ApiResponse apiResponse = new ApiResponse<>(200, "Success", new AuthenticationTokenResponse("token")); + when(authenticationService.signin(signInRequest)).thenReturn(apiResponse); + + ResponseEntity> responseEntity = authenticationController.signin(signInRequest); + + assertEquals(HttpStatus.OK.value(), responseEntity.getStatusCodeValue(), "Status code does not match expected value on successful signin"); + assertEquals(apiResponse, responseEntity.getBody(), "Response body does not match expected value on successful signin"); } @Test public void shouldReturnFailureOnInvalidSignin() { - SignInRequest signInRequest = new SignInRequest( - "testUser", - "wrongPassword" - ); - ApiResponse apiResponse = - new ApiResponse<>(401, "Failure", null); - when(authenticationService.signin(signInRequest)).thenReturn( - apiResponse - ); - ResponseEntity< - ApiResponse - > responseEntity = authenticationController.signin(signInRequest); - assertEquals( - 401, - responseEntity.getBody().getStatus(), - "Status code does not match expected value on failed signin" - ); - assertEquals( - apiResponse, - responseEntity.getBody(), - "Response body does not match expected value on failed signin" - ); + SignInRequest signInRequest = new SignInRequest("testUser", "wrongPassword"); + ApiResponse apiResponse = new ApiResponse<>(401, "Invalid email/username or password.", null); + when(authenticationService.signin(signInRequest)).thenReturn(apiResponse); + + ResponseEntity> responseEntity = authenticationController.signin(signInRequest); + + assertEquals(HttpStatus.UNAUTHORIZED.value(), responseEntity.getStatusCodeValue(), "Status code does not match expected value on failed signin"); + assertEquals(apiResponse, responseEntity.getBody(), "Response body does not match expected value on failed signin"); } @Test public void shouldReturnSuccessOnValidSignup() { SignUpRequest signUpRequest = SignUpRequest.builder() - .email("newUser@gmail.com") - .username("newUser") - .country("USA") - .bio("Bio of the new user") - .password("newPassword") - .firstName("New") - .lastName("User") - .build(); - ApiResponse apiResponse = - new ApiResponse<>( - 200, - "Success", - new AuthenticationTokenResponse("token") - ); - when(authenticationService.signup(signUpRequest)).thenReturn( - apiResponse - ); - ResponseEntity< - ApiResponse - > responseEntity = authenticationController.signup(signUpRequest); - assertEquals( - 200, - responseEntity.getBody().getStatus(), - "Status code does not match expected value on successful signup" - ); - assertEquals( - apiResponse, - responseEntity.getBody(), - "Response body does not match expected value on successful signup" - ); + .email("newUser@gmail.com") + .username("newUser") + .country("USA") + .bio("Bio of the new user") + .password("newPassword") + .firstName("New") + .lastName("User") + .build(); + ApiResponse apiResponse = new ApiResponse<>(201, "User registered successfully.", new AuthenticationTokenResponse("token")); + when(authenticationService.signup(signUpRequest)).thenReturn(apiResponse); + + ResponseEntity> responseEntity = authenticationController.signup(signUpRequest); + + assertEquals(HttpStatus.CREATED.value(), responseEntity.getStatusCodeValue(), "Status code does not match expected value on successful signup"); + assertEquals(apiResponse, responseEntity.getBody(), "Response body does not match expected value on successful signup"); } @Test public void shouldReturnFailureOnInvalidSignup() { SignUpRequest signUpRequest = SignUpRequest.builder() - .email("newUser@gmail.com") - .username("newUser") - .country("USA") - .bio("Bio of the new user") - .password("newPassword") - .firstName("New") - .lastName("User") - .build(); - ApiResponse apiResponse = - new ApiResponse<>(409, "Failure", null); - when(authenticationService.signup(signUpRequest)).thenReturn( - apiResponse - ); - ResponseEntity< - ApiResponse - > responseEntity = authenticationController.signup(signUpRequest); - assertEquals( - 409, - responseEntity.getBody().getStatus(), - "Status code does not match expected value on failed signup" - ); - assertEquals( - apiResponse, - responseEntity.getBody(), - "Response body does not match expected value on failed signup" - ); + .email("newUser@gmail.com") + .username("newUser") + .country("USA") + .bio("Bio of the new user") + .password("newPassword") + .firstName("New") + .lastName("User") + .build(); + ApiResponse apiResponse = new ApiResponse<>(409, "Email or username already exists.", null); + when(authenticationService.signup(signUpRequest)).thenReturn(apiResponse); + + ResponseEntity> responseEntity = authenticationController.signup(signUpRequest); + + assertEquals(HttpStatus.CONFLICT.value(), responseEntity.getStatusCodeValue(), "Status code does not match expected value on failed signup"); + assertEquals(apiResponse, responseEntity.getBody(), "Response body does not match expected value on failed signup"); } }