diff --git a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java index afde6d58e3..d13381ec40 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java +++ b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java @@ -26,7 +26,7 @@ public class OwnerService { public OwnerResponse getOwner(Long ownerId) { Owner foundOwner = ownerRepository.getById(ownerId); List attachments = ownerAttachmentRepository.findAllByOwnerId(ownerId); - List shops = shopRepository.findAllByOwner(foundOwner); + List shops = shopRepository.findAllByOwnerId(ownerId); return OwnerResponse.of(foundOwner, attachments, shops); } } diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopApi.java b/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopApi.java new file mode 100644 index 0000000000..3cbb1af4f4 --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopApi.java @@ -0,0 +1,36 @@ +package in.koreatech.koin.domain.ownershop.controller; + +import static in.koreatech.koin.domain.user.model.UserType.OWNER; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; + +import in.koreatech.koin.domain.ownershop.dto.OwnerShopsResponse; +import in.koreatech.koin.global.auth.Auth; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "(Normal) Owner Shop: 상점 (점주 전용)", description = "사장님이 상점 정보를 관리한다.") +public interface OwnerShopApi { + + @ApiResponses( + value = { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))), + } + ) + @Operation(summary = "자신의 모든 상점 조회") + @SecurityRequirement(name = "Jwt Authentication") + @GetMapping("/owner/shops") + ResponseEntity getOwnerShops( + @Auth(permit = {OWNER}) Long userId + ); + +} diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopContoller.java b/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopContoller.java new file mode 100644 index 0000000000..355bbf526c --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/ownershop/controller/OwnerShopContoller.java @@ -0,0 +1,26 @@ +package in.koreatech.koin.domain.ownershop.controller; + +import static in.koreatech.koin.domain.user.model.UserType.OWNER; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import in.koreatech.koin.domain.ownershop.dto.OwnerShopsResponse; +import in.koreatech.koin.domain.ownershop.service.OwnerShopService; +import in.koreatech.koin.global.auth.Auth; +import lombok.RequiredArgsConstructor; + +@Controller +@RequiredArgsConstructor +public class OwnerShopContoller implements OwnerShopApi { + + private final OwnerShopService ownerShopService; + + @Override + public ResponseEntity getOwnerShops( + @Auth(permit = {OWNER}) Long ownerId + ) { + OwnerShopsResponse ownerShopsResponses = ownerShopService.getOwnerShops(ownerId); + return ResponseEntity.ok().body(ownerShopsResponses); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsResponse.java b/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsResponse.java new file mode 100644 index 0000000000..2bebbe7f75 --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsResponse.java @@ -0,0 +1,30 @@ +package in.koreatech.koin.domain.ownershop.dto; + +import java.util.List; + +import in.koreatech.koin.domain.shop.model.Shop; + +public record OwnerShopsResponse( + Long count, + List shops +) { + + public static OwnerShopsResponse from(List shops) { + return new OwnerShopsResponse( + (long)shops.size(), + shops.stream() + .map(InnerShopResponse::from) + .toList() + ); + } + + private record InnerShopResponse( + Long id, + String name + ) { + + public static InnerShopResponse from(Shop shop) { + return new InnerShopResponse(shop.getId(), shop.getName()); + } + } +} diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java new file mode 100644 index 0000000000..04357689e5 --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java @@ -0,0 +1,24 @@ +package in.koreatech.koin.domain.ownershop.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import in.koreatech.koin.domain.ownershop.dto.OwnerShopsResponse; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.repository.ShopRepository; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class OwnerShopService { + + private final ShopRepository shopRepository; + + public OwnerShopsResponse getOwnerShops(Long ownerId) { + List shops = shopRepository.findAllByOwnerId(ownerId); + return OwnerShopsResponse.from(shops); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/shop/repository/ShopRepository.java b/src/main/java/in/koreatech/koin/domain/shop/repository/ShopRepository.java index 80fa564397..448af0466d 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/repository/ShopRepository.java +++ b/src/main/java/in/koreatech/koin/domain/shop/repository/ShopRepository.java @@ -4,12 +4,11 @@ import org.springframework.data.repository.Repository; -import in.koreatech.koin.domain.owner.domain.Owner; import in.koreatech.koin.domain.shop.model.Shop; public interface ShopRepository extends Repository { Shop save(Shop shop); - List findAllByOwner(Owner owner); + List findAllByOwnerId(Long ownerId); } diff --git a/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java new file mode 100644 index 0000000000..a6306dd420 --- /dev/null +++ b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java @@ -0,0 +1,130 @@ +package in.koreatech.koin.acceptance; + +import static in.koreatech.koin.domain.user.model.UserType.OWNER; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; + +import in.koreatech.koin.AcceptanceTest; +import in.koreatech.koin.domain.owner.domain.Owner; +import in.koreatech.koin.domain.owner.repository.OwnerRepository; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.repository.ShopRepository; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.koin.domain.user.model.UserGender; +import in.koreatech.koin.global.auth.JwtProvider; +import io.restassured.RestAssured; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; + +class OwnerShopApiTest extends AcceptanceTest { + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private ShopRepository shopRepository; + + @Autowired + private JwtProvider jwtProvider; + + private Owner owner; + private Shop shop; + private String token; + + @BeforeEach + void setUp() { + Owner ownerRequest = Owner.builder() + .companyRegistrationNumber("123-45-67890") + .companyRegistrationCertificateImageUrl("https://test.com/test.jpg") + .grantShop(true) + .grantEvent(true) + .user( + User.builder() + .password("1234") + .nickname("주노") + .name("최준호") + .phoneNumber("010-1234-5678") + .userType(OWNER) + .gender(UserGender.MAN) + .email("test@koreatech.ac.kr") + .isAuthed(true) + .isDeleted(false) + .build() + ) + .build(); + owner = ownerRepository.save(ownerRequest); + token = jwtProvider.createToken(owner.getUser()); + + Shop shopRequest = Shop.builder() + .owner(owner) + .name("테스트 상점") + .internalName("테스트") + .chosung("테스트") + .phone("010-1234-5678") + .address("대전광역시 유성구 대학로 291") + .description("테스트 상점입니다.") + .delivery(true) + .deliveryPrice(3000L) + .payCard(true) + .payBank(true) + .isDeleted(false) + .isEvent(false) + .remarks("비고") + .hit(0L) + .build(); + shop = shopRepository.save(shopRequest); + } + + @Test + @DisplayName("사장님의 가게 목록을 조회한다.") + void getOwnerShops() { + // given + final int SHOP_COUNT = 2; + + Shop shopRequest = Shop.builder() + .owner(owner) + .name("테스트 상점2") + .internalName("테스트") + .chosung("테스트") + .phone("010-1234-5678") + .address("대전광역시 유성구 대학로 291") + .description("테스트 상점2입니다.") + .delivery(true) + .deliveryPrice(4000L) + .payCard(true) + .payBank(true) + .isDeleted(false) + .isEvent(false) + .remarks("비고2") + .hit(10L) + .build(); + Shop shop2 = shopRepository.save(shopRequest); + + // when then + ExtractableResponse response = RestAssured + .given() + .header("Authorization", "Bearer " + token) + .when() + .get("/owner/shops") + .then() + .log().all() + .statusCode(HttpStatus.OK.value()) + .extract(); + + assertSoftly( + softly -> { + softly.assertThat(response.body().jsonPath().getLong("count")).isEqualTo(SHOP_COUNT); + softly.assertThat(response.body().jsonPath().getList("shops").size()).isEqualTo(SHOP_COUNT); + softly.assertThat(response.body().jsonPath().getLong("shops[0].id")).isEqualTo(shop.getId()); + softly.assertThat(response.body().jsonPath().getString("shops[0].name")).isEqualTo(shop.getName()); + softly.assertThat(response.body().jsonPath().getLong("shops[1].id")).isEqualTo(shop2.getId()); + softly.assertThat(response.body().jsonPath().getString("shops[1].name")).isEqualTo(shop2.getName()); + } + ); + } +}