Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/bounswe/bounswe2024group1
Browse files Browse the repository at this point in the history
…into frontend/feature/120-feed-page-ui
  • Loading branch information
NazireAta committed May 14, 2024
2 parents ca8e9af + 9b04e67 commit 67f66be
Show file tree
Hide file tree
Showing 37 changed files with 813 additions and 186 deletions.
15 changes: 4 additions & 11 deletions .github/workflows/backend_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,23 @@ name: backend-test
on:
push:
paths:
- 'backend/**'
- "backend/**"
- compose.yml
- dev.yml
- '.github/workflows/backend_test.yml'

- ".github/workflows/backend_test.yml"
pull_request:
branches:
- main
- staging
- develop


jobs:
test:
runs-on: ubuntu-latest
env:
working-directory:
backend
working-directory: backend
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Test with Maven
run: docker compose -f dev.yml run --rm backend mvn test



14 changes: 11 additions & 3 deletions .github/workflows/frontend_test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
name: Front-End CI

on: [push, pull_request]
on:
push:
paths:
- "frontend/**"
- ".github/workflows/frontend_test.yml"
pull_request:
branches:
- main
- staging

jobs:
build:
Expand All @@ -15,8 +23,8 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
cache: 'yarn'
node-version: "20"
cache: "yarn"

- name: Enable Corepack
run: corepack enable
Expand Down
12 changes: 12 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http)
.hasRole("ADMIN") // Require ADMIN role for "/api/v1/resources"
.requestMatchers(HttpMethod.POST,"/**")
.authenticated()
.requestMatchers("/feed?type=following").authenticated()
.requestMatchers(HttpMethod.DELETE,"/**").authenticated()) // Require authentication for all other requests
.sessionManagement(
manager ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -23,13 +24,27 @@ public class AuthenticationController {
public ResponseEntity<ApiResponse<AuthenticationTokenResponse>> signup(
@RequestBody SignUpRequest request
) {
return ResponseEntity.ok(authenticationService.signup(request)); // Return response
ApiResponse<AuthenticationTokenResponse> 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
public ResponseEntity<ApiResponse<AuthenticationTokenResponse>> signin(
@RequestBody SignInRequest request
) {
return ResponseEntity.ok(authenticationService.signin(request)); // Return response
ApiResponse<AuthenticationTokenResponse> response = authenticationService.signin(request);

if (response.getStatus() == 401) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
} else {
return ResponseEntity.ok(response);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.group1.cuisines.controllers;

import com.group1.cuisines.dao.response.ApiResponse;
import com.group1.cuisines.dao.response.ErrorResponse;
import com.group1.cuisines.dao.response.SuccessResponse;
import com.group1.cuisines.dto.CuisineDetailsDto;
import com.group1.cuisines.entities.Cuisine;
import com.group1.cuisines.repositories.CuisineRepository;
import com.group1.cuisines.services.CuisineService;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand All @@ -21,14 +26,12 @@ public class CuisineController {
private final CuisineRepository cuisineRepository;

@GetMapping("/{cuisineId}")
public ResponseEntity<?> getCuisineDetails(
@PathVariable String cuisineId,
@RequestParam(defaultValue = "false") boolean includeDishes) {

Cuisine cuisine = cuisineService.getCuisineById(cuisineId, includeDishes);
if (cuisine == null) {
return ResponseEntity.notFound().build();
public ResponseEntity<?> getCuisineById(@PathVariable String cuisineId, @RequestParam(required = false) Boolean includeDishes) {
try {
CuisineDetailsDto cuisineDetails = cuisineService.getCuisineById(cuisineId, Boolean.TRUE.equals(includeDishes));
return ResponseEntity.ok(new SuccessResponse<>(200,cuisineDetails, "Cuisine details fetched successfully"));
} catch (EntityNotFoundException e) {
return ResponseEntity.ok(new ErrorResponse(204,"Cuisine not found"));
}
return ResponseEntity.ok(cuisine);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.group1.cuisines.controllers;

import com.group1.cuisines.dao.response.SuccessResponse;
import com.group1.cuisines.dto.RecipeDetailsDto;
import com.group1.cuisines.services.RecipeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;

@RestController
@RequestMapping("/api/v1")
public class FeedController {

@Autowired
private RecipeService recipeService;

@GetMapping("/feed")
public ResponseEntity<?> getFeed(@RequestParam String type, Authentication authentication) {
if (!"explore".equals(type) && !"following".equals(type)) {
return ResponseEntity.badRequest().body("Invalid type parameter.");
}

if ("following".equals(type)) {
if (authentication == null || !authentication.isAuthenticated()) {
// Return an empty set and a message for unauthenticated users
return ResponseEntity.ok(new SuccessResponse<>(400,Collections.emptyList(), "No content available. Please log in and follow other users !."));
}
// Fetch following users' recipes for authenticated users
String username = authentication.getName();
List<RecipeDetailsDto> recipes = recipeService.getRecipesByType(type, username);
return ResponseEntity.ok(new SuccessResponse<>(200,recipes, "Recipes fetched successfully from followed users."));
}

// For 'explore', accessible to everyone
List<RecipeDetailsDto> recipes = recipeService.getRecipesByType(type, null);
return ResponseEntity.ok(new SuccessResponse<>(200,recipes, "Recipes fetched successfully."));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.group1.cuisines.controllers;
import com.group1.cuisines.dto.CommentsDto;
import com.group1.cuisines.dto.NewRecipeDto;
import com.group1.cuisines.dto.RatingDto;
import com.group1.cuisines.dto.RecipeDetailDto;
import com.group1.cuisines.dao.response.SuccessResponse;
import com.group1.cuisines.dto.*;
import com.group1.cuisines.entities.Comment;
import com.group1.cuisines.entities.User;
import com.group1.cuisines.services.RecipeService;
Expand All @@ -23,6 +21,28 @@ public class RecipeController {
@Autowired
private RecipeService recipeService;


@GetMapping("/recipes/{recipeId}")
public ResponseEntity<?> getRecipeById(@PathVariable Integer recipeId) {
RecipeDetailsDto recipeDetails = recipeService.getRecipeById(recipeId);
if (recipeDetails != null) {
return ResponseEntity.ok(new SuccessResponse<>(200,recipeDetails, "Recipe fetched successfully"));
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Recipe not found");
}
}


@GetMapping("/recipes")
public ResponseEntity<List<RecipeDto>> getRecipes(@RequestParam(required = false) String sort,
@RequestParam(required = false) String dishId,
@RequestParam(required = false) String cuisineId) {
List<RecipeDto> recipes = recipeService.findRecipes(sort, dishId, cuisineId);
return ResponseEntity.ok(recipes);
}



@PostMapping("/recipes")
public ResponseEntity<?> createRecipe(@RequestBody NewRecipeDto newRecipe) throws Exception{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package com.group1.cuisines.controllers;

import com.group1.cuisines.dao.response.ApiResponse;
import com.group1.cuisines.dao.response.ErrorResponse;
import com.group1.cuisines.dao.response.SuccessResponse;
import com.group1.cuisines.dto.DishResponseDto;
import com.group1.cuisines.dto.UserDto;
import com.group1.cuisines.entities.Dish;
import com.group1.cuisines.entities.User;
import com.group1.cuisines.services.SearchService;
import com.group1.cuisines.services.UserService;
import com.group1.cuisines.services.WikidataService;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -28,15 +33,24 @@ public ResponseEntity<?> searchUsers(@RequestParam(required = false) String q) {
List<User> users = userService.searchUsers(q);
if (users.isEmpty()) {
// Return a custom message with a "No Content" status when no users are found
return ResponseEntity.status(HttpStatus.NO_CONTENT).body("No users found");
return ResponseEntity.ok(new ErrorResponse(204,"No users found"));
}
return ResponseEntity.ok(users); // Return the list of users when found
return ResponseEntity.ok(new SuccessResponse<>(200, users.stream().map(user -> new UserDto(
user.getId(),
user.getUsername(),
user.getFirstName(),
user.getLastName(),
user.getFollowerCount(),
user.getFollowingCount(),
user.getRecipeCount()
)).collect(Collectors.toList()), "Users fetched successfully"));

}

@GetMapping("/dishes")
public ApiResponse<List<Dish>> searchDishes(@RequestParam(required = false) String q,
@RequestParam(required = false) String cuisine,
@RequestParam(required = false) String foodType) {
public ApiResponse<List<DishResponseDto>> searchDishes(@RequestParam(required = false) String q,
@RequestParam(required = false) String cuisine,
@RequestParam(required = false) String foodType) {
return new ApiResponse<>(
200,
"Search completed",
Expand Down
Loading

0 comments on commit 67f66be

Please sign in to comment.