diff --git a/backend/src/main/java/com/zzang/chongdae/offering/controller/OfferingController.java b/backend/src/main/java/com/zzang/chongdae/offering/controller/OfferingController.java index 545a2825c..7deff0b72 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/controller/OfferingController.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/controller/OfferingController.java @@ -3,6 +3,7 @@ import com.zzang.chongdae.member.repository.entity.MemberEntity; import com.zzang.chongdae.offering.service.OfferingService; import com.zzang.chongdae.offering.service.dto.OfferingAllResponse; +import com.zzang.chongdae.offering.service.dto.OfferingAllResponseItem; import com.zzang.chongdae.offering.service.dto.OfferingDetailResponse; import com.zzang.chongdae.offering.service.dto.OfferingFilterAllResponse; import com.zzang.chongdae.offering.service.dto.OfferingMeetingResponse; @@ -34,14 +35,6 @@ public class OfferingController { private final OfferingService offeringService; - @GetMapping("/offerings/{offering-id}") - public ResponseEntity getOfferingDetail( - @PathVariable(value = "offering-id") Long offeringId, - MemberEntity member) { - OfferingDetailResponse response = offeringService.getOfferingDetail(offeringId, member); - return ResponseEntity.ok(response); - } - @GetMapping("/offerings") public ResponseEntity getAllOffering( @RequestParam(value = "filter", defaultValue = "RECENT") String filterName, @@ -59,6 +52,21 @@ public ResponseEntity getAllOfferingFilter() { return ResponseEntity.ok(response); } + @GetMapping("/offerings/{offering-id}") + public ResponseEntity getOffering( + @PathVariable(value = "offering-id") Long offeringId) { + OfferingAllResponseItem response = offeringService.getOffering(offeringId); + return ResponseEntity.ok(response); + } + + @GetMapping("/offerings/{offering-id}/detail") + public ResponseEntity getOfferingDetail( + @PathVariable(value = "offering-id") Long offeringId, + MemberEntity member) { + OfferingDetailResponse response = offeringService.getOfferingDetail(offeringId, member); + return ResponseEntity.ok(response); + } + @GetMapping("/offerings/{offering-id}/meetings") public ResponseEntity getOfferingMeeting( @PathVariable(value = "offering-id") Long offeringId, diff --git a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java index 12a0282cd..ae6dcde31 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/service/OfferingService.java @@ -2,8 +2,8 @@ import com.zzang.chongdae.global.exception.MarketException; import com.zzang.chongdae.member.repository.entity.MemberEntity; -import com.zzang.chongdae.offering.domain.OfferingJoinedCount; import com.zzang.chongdae.offering.domain.OfferingFilter; +import com.zzang.chongdae.offering.domain.OfferingJoinedCount; import com.zzang.chongdae.offering.domain.OfferingMeeting; import com.zzang.chongdae.offering.domain.OfferingPrice; import com.zzang.chongdae.offering.exception.OfferingErrorCode; @@ -53,6 +53,13 @@ public OfferingDetailResponse getOfferingDetail(Long offeringId, MemberEntity me offering, offeringPrice, offeringJoinedCount, isProposer, isParticipated); } + public OfferingAllResponseItem getOffering(Long offeringId) { + OfferingEntity offering = offeringRepository.findById(offeringId) + .orElseThrow(() -> new MarketException(OfferingErrorCode.NOT_FOUND)); + OfferingPrice offeringPrice = offering.toOfferingPrice(); + return new OfferingAllResponseItem(offering, offeringPrice); + } + public OfferingAllResponse getAllOffering(String filterName, String searchKeyword, Long lastId, Integer pageSize) { Pageable pageable = PageRequest.ofSize(pageSize); OfferingFilter filter = OfferingFilter.findByName(filterName); diff --git a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java index fdddcab69..d1f7b32a0 100644 --- a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java +++ b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java @@ -96,18 +96,86 @@ void should_responseOfferingDetail_when_givenOfferingId() { .filter(document("get-offering-detail-success", resource(successSnippets))) .cookies(cookieProvider.createCookies()) .pathParam("offering-id", 1) - .when().get("/offerings/{offering-id}") + .when().get("/offerings/{offering-id}/detail") .then().log().all() .statusCode(200); } - @DisplayName("유효하지 않은 공모를 조회할 경우 예외가 발생한다.") + @DisplayName("유효하지 않은 공모를 상세 조회할 경우 예외가 발생한다.") @Test void should_throwException_when_invalidOffering() { given(spec).log().all() .filter(document("get-offering-detail-fail-invalid-offering", resource(failSnippets))) .cookies(cookieProvider.createCookies()) .pathParam("offering-id", 100) + .when().get("/offerings/{offering-id}/detail") + .then().log().all() + .statusCode(400); + } + } + + @DisplayName("공모 단건 조회") + @Nested + class GetOffering { + + List pathParameterDescriptors = List.of( + parameterWithName("offering-id").description("공모 id (필수)") + ); + List successResponseDescriptors = List.of( + fieldWithPath("id").description("공모 id"), + fieldWithPath("title").description("제목"), + fieldWithPath("meetingAddressDong").description("모집 동 주소"), + fieldWithPath("currentCount").description("현재원"), + fieldWithPath("totalCount").description("총원"), + fieldWithPath("thumbnailUrl").description("사진 링크"), + fieldWithPath("dividedPrice").description("n빵 가격"), + fieldWithPath("originPrice").description("원 가격"), + fieldWithPath("discountRate").description("할인율"), + fieldWithPath("status").description("공모 상태" + + getEnumValuesAsString(OfferingStatus.class)), + fieldWithPath("isOpen").description("공모 참여 가능 여부") + ); + ResourceSnippetParameters successSnippets = builder() + .summary("공모 단건 조회") + .description("공모 단건을 조회합니다.") + .pathParameters(pathParameterDescriptors) + .responseFields(successResponseDescriptors) + .responseSchema(schema("OfferingSuccessResponse")) + .build(); + ResourceSnippetParameters failSnippets = builder() + .summary("공모 단건 조회") + .description("공모 id를 통해 공모의 단건 정보를 조회합니다.") + .pathParameters(pathParameterDescriptors) + .responseFields(failResponseDescriptors) + .responseSchema(schema("OfferingFailResponse")) + .build(); + + @BeforeEach + void setUp() { + MemberEntity proposer = memberFixture.createMember(); + OfferingEntity offering = offeringFixture.createOffering(proposer); + offeringMemberFixture.createProposer(proposer, offering); + } + + @DisplayName("공모 단건을 조회할 수 있다") + @Test + void should_responseOffering_when_givenOfferingId() { + given(spec).log().all() + .filter(document("get-offering-success", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) + .pathParam("offering-id", 1) + .when().get("/offerings/{offering-id}") + .then().log().all() + .statusCode(200); + } + + @DisplayName("유효하지 않은 공모를 단건 조회할 경우 예외가 발생한다.") + @Test + void should_throwException_when_invalidOffering() { + given(spec).log().all() + .filter(document("get-offering-fail-invalid-offering", resource(failSnippets))) + .cookies(cookieProvider.createCookies()) + .pathParam("offering-id", 100) .when().get("/offerings/{offering-id}") .then().log().all() .statusCode(400); diff --git a/backend/src/test/java/com/zzang/chongdae/offering/service/OfferingServiceTest.java b/backend/src/test/java/com/zzang/chongdae/offering/service/OfferingServiceTest.java index 316004917..56046217e 100644 --- a/backend/src/test/java/com/zzang/chongdae/offering/service/OfferingServiceTest.java +++ b/backend/src/test/java/com/zzang/chongdae/offering/service/OfferingServiceTest.java @@ -1,10 +1,15 @@ package com.zzang.chongdae.offering.service; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.zzang.chongdae.global.exception.MarketException; import com.zzang.chongdae.global.service.ServiceTest; import com.zzang.chongdae.member.repository.entity.MemberEntity; +import com.zzang.chongdae.offering.repository.entity.OfferingEntity; +import com.zzang.chongdae.offering.service.dto.OfferingAllResponseItem; import com.zzang.chongdae.offering.service.dto.OfferingSaveRequest; import java.time.LocalDateTime; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -14,10 +19,38 @@ public class OfferingServiceTest extends ServiceTest { @Autowired OfferingService offeringService; + @DisplayName("공모 id를 통해 공모를 단건 조회할 수 있다.") + @Test + void should_getOffering_when_givenOfferingId() { + // given + MemberEntity member = memberFixture.createMember("ever"); + OfferingEntity offering = offeringFixture.createOffering(member); + OfferingAllResponseItem expected = new OfferingAllResponseItem(offering, offering.toOfferingPrice()); + + // when + OfferingAllResponseItem actual = offeringService.getOffering(offering.getId()); + + // then + assertEquals(expected, actual); + } + + @DisplayName("유효하지 않은 공모 id를 통해 공모를 단건 조회할 경우 예외가 발생한다.") + @Test + void should_throwException_when_givenInvalidOfferingId() { + // given + MemberEntity member = memberFixture.createMember("ever"); + OfferingEntity offering = offeringFixture.createOffering(member); + + // when & then + long invalidOfferingId = offering.getId() + 9999; + + assertThatThrownBy(() -> offeringService.getOffering(invalidOfferingId)) + .isInstanceOf(MarketException.class); + } + @DisplayName("공목 등록 시 원 가격 정보가 없더라도 공모 작성에 성공할 수 있다.") @Test void should_createOffering_when_givenOfferingWithoutOriginPriceCreateRequest() { - // given MemberEntity member = memberFixture.createMember("pizza"); OfferingSaveRequest request = new OfferingSaveRequest( @@ -39,6 +72,6 @@ void should_createOffering_when_givenOfferingWithoutOriginPriceCreateRequest() { Long actual = offeringService.saveOffering(request, member); // then - Assertions.assertEquals(expected, actual); + assertEquals(expected, actual); } }