Skip to content

Commit

Permalink
Merge branch 'dev' into feat/#77
Browse files Browse the repository at this point in the history
# Conflicts:
#	backend/src/test/java/com/votogether/domain/member/repository/MemberCategoryRepositoryTest.java
  • Loading branch information
woo-chang committed Jul 20, 2023
2 parents 8b66134 + 411d0a0 commit 67dd311
Show file tree
Hide file tree
Showing 58 changed files with 1,842 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import com.votogether.domain.member.entity.Member;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -28,16 +30,38 @@ public class CategoryController {
@ApiResponse(responseCode = "200", description = "조회 성공")
@GetMapping("/guest")
public ResponseEntity<List<CategoryResponse>> getAllCategories() {
List<CategoryResponse> categories = categoryService.getAllCategories();
final List<CategoryResponse> categories = categoryService.getAllCategories();
return ResponseEntity.status(HttpStatus.OK).body(categories);
}

@Operation(summary = "선호 카테고리 추가하기", description = "선호하는 카테고리를 선호 카테고리 목록에 추가한다.")
@ApiResponse(responseCode = "201", description = "추가 성공")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "추가 성공"),
@ApiResponse(responseCode = "400", description = "해당 카테고리가 추가가 되어 있어 중복 추가 실패"),
@ApiResponse(responseCode = "404", description = "해당 카테고리가 존재하지 않아 추가 실패"),
})
@PostMapping("/{categoryId}/like")
public ResponseEntity<Void> addFavoriteCategory(final Member member, @PathVariable final Long categoryId) {
categoryService.addFavoriteCategory(member, categoryId);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@Operation(summary = "선호 카테고리 삭제하기", description = "선호하는 카테고리를 선호 카테고리 목록에서 삭제한다.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "삭제 성공"),
@ApiResponse(responseCode = "400", description = "선호하는 카테고리가 아니여서 삭제 실패"),
@ApiResponse(responseCode = "404", description = "해당 카테고리가 존재하지 않아 삭제 실패")
})
@DeleteMapping("/{categoryId}/like")
public ResponseEntity<Void> removeFavoriteCategory(final Member member, @PathVariable final Long categoryId) {
categoryService.removeFavoriteCategory(member, categoryId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

@GetMapping
public ResponseEntity<Void> getAllCategories(final Member member) {
categoryService.getAllCategories(member);
return ResponseEntity.status(HttpStatus.OK).build();
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.votogether.domain.category.dto.response;

import com.votogether.domain.category.entity.Category;
import java.util.List;

public record CategoryResponse(
Long id,
String name,
boolean isFavorite
) {

public CategoryResponse(final Category category) {
this(category.getId(), category.getName(), false);
public CategoryResponse(final Category category, final boolean isFavorite) {
this(category.getId(), category.getName(), isFavorite);
}

public CategoryResponse(final Category category, final List<Category> favoriteCategories) {
this(category.getId(), category.getName(), favoriteCategories.contains(category));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.member.entity.MemberCategory;
import com.votogether.domain.member.repository.MemberCategoryRepository;
import java.util.Comparator;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -20,27 +21,53 @@ public class CategoryService {

@Transactional(readOnly = true)
public List<CategoryResponse> getAllCategories() {
List<Category> categories = categoryRepository.findAll();
final List<Category> categories = categoryRepository.findAll();

return categories.stream()
.map(CategoryResponse::new)
.sorted(Comparator.comparing(Category::getName))
.map(category -> new CategoryResponse(category, false))
.toList();
}

@Transactional
public void addFavoriteCategory(final Member member, final Long categoryId) {
Category category = categoryRepository.findById(categoryId)
final Category category = categoryRepository.findById(categoryId)
.orElseThrow(() -> new IllegalArgumentException("해당 카테고리가 존재하지 않습니다."));

memberCategoryRepository.findByMemberAndCategory(member, category)
.ifPresent(ignore -> new IllegalStateException("이미 선호 카테고리에 등록되어 있습니다."));

MemberCategory memberCategory = MemberCategory.builder()
final MemberCategory memberCategory = MemberCategory.builder()
.member(member)
.category(category)
.build();

memberCategoryRepository.save(memberCategory);
}

@Transactional
public void removeFavoriteCategory(final Member member, final Long categoryId) {
final Category category = categoryRepository.findById(categoryId)
.orElseThrow(() -> new IllegalArgumentException("해당 카테고리가 존재하지 않습니다."));
final MemberCategory memberCategory = memberCategoryRepository.findByMemberAndCategory(member, category)
.orElseThrow(() -> new IllegalArgumentException("해당 카테고리는 선호 카테고리가 아닙니다."));

memberCategoryRepository.delete(memberCategory);
}

@Transactional(readOnly = true)
public List<CategoryResponse> getAllCategories(final Member member) {
final List<Category> categories = categoryRepository.findAll();
final List<MemberCategory> memberCategories = memberCategoryRepository.findByMember(member);

final List<Category> favoriteCategories = memberCategories.stream()
.map(MemberCategory::getCategory)
.toList();

return categories.stream()
.sorted(Comparator.comparing(Category::getName))
.map(category -> new CategoryResponse(category, favoriteCategories))
.toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import com.votogether.domain.category.entity.Category;
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.member.entity.MemberCategory;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberCategoryRepository extends JpaRepository<MemberCategory, Long> {

Optional<MemberCategory> findByMemberAndCategory(final Member member, final Category category);

List<MemberCategory> findByMember(final Member member);

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,21 @@ public void vote(
final Long postId,
final Long postOptionId
) {
Post post = postRepository.findById(postId)
final Post post = postRepository.findById(postId)
.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 존재하지 않습니다."));

validateAlreadyVoted(member, post);

PostOption postOption = postOptionRepository.findById(postOptionId)
final PostOption postOption = postOptionRepository.findById(postOptionId)
.orElseThrow(() -> new IllegalArgumentException("해당 선택지가 존재하지 않습니다."));

Vote vote = post.makeVote(member, postOption);
final Vote vote = post.makeVote(member, postOption);
member.plusPoint(1);
voteRepository.save(vote);
}

private void validateAlreadyVoted(Member member, Post post) {

private void validateAlreadyVoted(final Member member, final Post post) {
final PostOptions postOptions = post.getPostOptions();
final List<Vote> alreadyVoted =
voteRepository.findByMemberAndPostOptionIn(member, postOptions.getPostOptions());
Expand All @@ -55,20 +56,20 @@ public void changeVote(
final Long originPostOptionId,
final Long newPostOptionId
) {
Post post = postRepository.findById(postId)
final Post post = postRepository.findById(postId)
.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 존재하지 않습니다."));

PostOption originPostOption = postOptionRepository.findById(originPostOptionId)
final PostOption originPostOption = postOptionRepository.findById(originPostOptionId)
.orElseThrow(() -> new IllegalArgumentException("헤당 선택지가 존재하지 않습니다."));

Vote originVote = voteRepository.findByMemberAndPostOption(member, originPostOption)
final Vote originVote = voteRepository.findByMemberAndPostOption(member, originPostOption)
.orElseThrow(() -> new IllegalArgumentException("선택지에 해당되는 투표가 존재하지 않습니다."));

PostOption newPostOption = postOptionRepository.findById(newPostOptionId)
final PostOption newPostOption = postOptionRepository.findById(newPostOptionId)
.orElseThrow(() -> new IllegalArgumentException("헤당 선택지가 존재하지 않습니다."));

voteRepository.delete(originVote);
Vote vote = post.makeVote(member, newPostOption);
final Vote vote = post.makeVote(member, newPostOption);
voteRepository.save(vote);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.votogether.domain.category.contorller;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;

import com.votogether.domain.category.dto.response.CategoryResponse;
import com.votogether.domain.category.entity.Category;
import com.votogether.domain.category.service.CategoryService;
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;

@WebMvcTest(CategoryController.class)
class CategoryControllerTest {

@MockBean
CategoryService categoryService;

@BeforeEach
void setUp() {
RestAssuredMockMvc.standaloneSetup(new CategoryController(categoryService));
}

@Test
@DisplayName("전체 카테고리 목록을 조회한다.")
void getAllCategories() {
// given
Category category = Category.builder()
.name("개발")
.build();
given(categoryService.getAllCategories()).willReturn(List.of(new CategoryResponse(category, false)));

// when
RestAssuredMockMvc.
given().log().all()
.when().get("/categories/guest")
.then().log().all()
.status(HttpStatus.OK)
.body("[0].id", nullValue())
.body("[0].name", equalTo("개발"))
.body("[0].isFavorite", equalTo(false));
}

@Test
@DisplayName("선호하는 카테고리를 선호 카테고리 목록에 추가한다.")
void addFavoriteCategory() {
// given
doNothing().when(categoryService).addFavoriteCategory(any(), any());

// when & then
RestAssuredMockMvc.
given().log().all()
.when().post("/categories/{categoryId}/like", 1)
.then().log().all()
.status(HttpStatus.CREATED);
}

@Test
@DisplayName("선호 카테고리를 삭제한다.")
void removeFavoriteCategory() {
// given
doNothing().when(categoryService).removeFavoriteCategory(any(), any());

// when & then
RestAssuredMockMvc.
given().log().all()
.when().delete("/categories/{categoryId}/like", 1)
.then().log().all()
.status(HttpStatus.NO_CONTENT);
}

}
Loading

0 comments on commit 67dd311

Please sign in to comment.