Skip to content

Commit

Permalink
FIX: (#145) 판매점 도메인 표현 계층을 재정의한다
Browse files Browse the repository at this point in the history
  • Loading branch information
anxi01 committed Feb 20, 2025
1 parent cfc612f commit 497423e
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 392 deletions.
124 changes: 19 additions & 105 deletions src/main/java/com/zerozero/store/presentation/CreateStoreController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,126 +2,40 @@

import com.zerozero.configuration.argumentresolver.LoginUser;
import com.zerozero.configuration.interceptor.Authorization;
import com.zerozero.configuration.property.CreateStoreQueueProperty;
import com.zerozero.configuration.swagger.ApiErrorCode;
import com.zerozero.core.application.BaseRequest;
import com.zerozero.core.application.BaseResponse;
import com.zerozero.core.domain.entity.User;
import com.zerozero.core.exception.error.GlobalErrorCode;
import com.zerozero.queue.store.CreateStoreMessageProducer;
import com.zerozero.queue.store.CreateStoreMessageProducer.CreateStoreMessageProducerRequest;
import com.zerozero.store.application.CreateStoreUseCase;
import com.zerozero.store.application.CreateStoreUseCase.CreateStoreErrorCode;
import com.zerozero.core.support.error.GlobalErrorType;
import com.zerozero.core.support.response.ApiResponse;
import com.zerozero.store.domain.service.CreateStoreUseCase;
import com.zerozero.store.exception.StoreErrorType;
import com.zerozero.store.presentation.request.CreateStoreRequest;
import com.zerozero.user.domain.model.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
@Tag(name = "Store", description = "판매점")
public class CreateStoreController {

private final CreateStoreUseCase createStoreUseCase;

private final CreateStoreQueueProperty createStoreQueueProperty;

@Operation(
summary = "판매점 등록 API",
description = "사용자가 검색한 판매점 ID를 통해 제로음료 판매점을 등록합니다.",
operationId = "/store"
)
@ApiErrorCode({GlobalErrorCode.class, CreateStoreErrorCode.class})
@Authorization
@PostMapping("/store")
public ResponseEntity<CreateStoreResponse> createStore(@Valid @RequestBody CreateStoreRequest request,
@Parameter(hidden = true) @LoginUser User user) {
CreateStoreUseCase.CreateStoreResponse createStoreResponse = createStoreUseCase.execute(
CreateStoreUseCase.CreateStoreRequest.builder()
.placeName(request.getPlaceName())
.longitude(request.getLongitude())
.latitude(request.getLatitude())
.images(request.getImages())
.user(user)
.build());
if (createStoreResponse == null || !createStoreResponse.isSuccess()) {
Optional.ofNullable(createStoreResponse)
.map(BaseResponse::getErrorCode)
.ifPresentOrElse(errorCode -> {
throw errorCode.toException();
}, () -> {
throw GlobalErrorCode.INTERNAL_ERROR.toException();
});
private final CreateStoreUseCase createStoreUseCase;

@Operation(
summary = "판매점 등록 API",
description = "사용자가 검색한 판매점 ID를 통해 제로음료 판매점을 등록합니다.",
operationId = "/store")
@ApiErrorCode({GlobalErrorType.class, StoreErrorType.class})
@Authorization
@PostMapping("/store")
public ApiResponse<UUID> createStore(@Valid @RequestBody CreateStoreRequest createStoreRequest, @Parameter(hidden = true) @LoginUser User user) {
return ApiResponse.success(createStoreUseCase.execute(createStoreRequest, user));
}

CreateStoreMessageProducer createStoreMessageProducer = new CreateStoreMessageProducer(createStoreQueueProperty,
CreateStoreMessageProducerRequest.builder()
.storeId(createStoreResponse.getStoreId())
.build());
createStoreMessageProducer.publishMessage();

return ResponseEntity.ok(
CreateStoreResponse.builder()
.storeId(createStoreResponse.getStoreId())
.build());
}

@ToString
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(description = "판매점 등록 응답")
public static class CreateStoreResponse extends BaseResponse<GlobalErrorCode> {

@Schema(description = "판매점 ID", example = "11ef3e05-f45b-7e6c-a084-7b554bfaa162")
private UUID storeId;
}

@ToString
@Getter
@Setter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(description = "판매점 등록 요청")
public static class CreateStoreRequest implements BaseRequest {

@NotNull(message = "판매점 이름은 필수 값입니다.")
@Schema(description = "판매점 이름", example = "꿉당")
private String placeName;

@NotNull(message = "판매점 x좌표(경도)는 필수 값입니다.")
@Schema(description = "판매점 x좌표(경도)", example = "127.01275515884753")
private String longitude;

@NotNull(message = "판매점 y좌표(위도)는 필수 값입니다.")
@Schema(description = "판매점 y좌표(위도)", example = "37.49206032952165")
private String latitude;

@NotNull(message = "판매점 사진은 필수 값입니다.")
@Schema(description = "판매점 업로드 이미지 URL 리스트",
example = "[\"https://s3.ap-northeast-2.amazonaws.com/zerozero-upload/images/store/0cbf3b99-b0ba-4148-a891-d04cb71ae236-test.png\", \"https://s3.ap-northeast-2.amazonaws.com/zerozero-upload/images/store/another-image.png\"]")
private List<String> images;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,18 @@
import com.zerozero.configuration.argumentresolver.LoginUser;
import com.zerozero.configuration.interceptor.Authorization;
import com.zerozero.configuration.swagger.ApiErrorCode;
import com.zerozero.core.application.BaseRequest;
import com.zerozero.core.application.BaseResponse;
import com.zerozero.core.domain.entity.Review.Filter;
import com.zerozero.core.domain.entity.User;
import com.zerozero.core.domain.vo.Store;
import com.zerozero.core.domain.vo.ZeroDrink.Type;
import com.zerozero.core.exception.error.GlobalErrorCode;
import com.zerozero.review.application.ReadStoreReviewUseCase;
import com.zerozero.review.application.ReadStoreReviewUseCase.ReadStoreReviewRequest;
import com.zerozero.review.application.ReadStoreReviewUseCase.ReadStoreReviewResponse;
import com.zerozero.store.application.ReadStoreInfoUseCase;
import com.zerozero.store.application.ReadStoreInfoUseCase.ReadStoreInfoErrorCode;
import com.zerozero.core.support.error.GlobalErrorType;
import com.zerozero.core.support.response.ApiResponse;
import com.zerozero.store.application.StoreService;
import com.zerozero.store.exception.StoreErrorType;
import com.zerozero.store.presentation.request.ReadStoreRequest;
import com.zerozero.store.presentation.response.ReadStoreResponse;
import com.zerozero.user.domain.model.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -45,123 +23,19 @@
@Tag(name = "Store", description = "판매점")
public class ReadStoreInfoController {

private final ReadStoreInfoUseCase readStoreInfoUseCase;

private final ReadStoreReviewUseCase readStoreReviewUseCase;

@Operation(
summary = "판매점 조회 API",
description = "판매점 ID를 통해 판매점과 리뷰를 조회합니다.",
operationId = "/store"
)
@ApiErrorCode({GlobalErrorCode.class, ReadStoreInfoErrorCode.class})
@Authorization
@GetMapping("/store")
public ResponseEntity<ReadStoreInfoResponse> readStoreInfo(@ParameterObject ReadStoreInfoRequest request, @Parameter(hidden = true) @LoginUser User user) {
ReadStoreInfoUseCase.ReadStoreInfoResponse readStoreInfoResponse = readStoreInfoUseCase.execute(
ReadStoreInfoUseCase.ReadStoreInfoRequest.builder()
.storeId(request.getStoreId())
.build());
if (readStoreInfoResponse == null || !readStoreInfoResponse.isSuccess()) {
Optional.ofNullable(readStoreInfoResponse)
.map(BaseResponse::getErrorCode)
.ifPresentOrElse(errorCode -> {
throw errorCode.toException();
}, () -> {
throw GlobalErrorCode.INTERNAL_ERROR.toException();
});
}
ReadStoreReviewResponse readStoreReviewResponse = readStoreReviewUseCase.execute(
ReadStoreReviewRequest.builder()
.storeId(request.getStoreId())
.filter(request.getFilter())
.user(user)
.build());
if (readStoreReviewResponse == null || !readStoreReviewResponse.isSuccess()) {
Optional.ofNullable(readStoreReviewResponse)
.map(BaseResponse::getErrorCode)
.ifPresentOrElse(errorCode -> {
throw errorCode.toException();
}, () -> {
throw GlobalErrorCode.INTERNAL_ERROR.toException();
});
}
return ResponseEntity.ok(toResponse(readStoreInfoResponse, readStoreReviewResponse));
}

private ReadStoreInfoResponse toResponse(ReadStoreInfoUseCase.ReadStoreInfoResponse readStoreInfoResponse, ReadStoreReviewResponse readStoreReviewResponse) {
return ReadStoreInfoResponse.builder()
.store(readStoreInfoResponse.getStore())
.reviews(Optional.ofNullable(readStoreReviewResponse.getReviews())
.map(reviews -> Arrays.stream(reviews)
.map(ReadStoreInfoResponse.Review::of)
.toArray(ReadStoreInfoResponse.Review[]::new))
.orElse(new ReadStoreInfoResponse.Review[0]))
.zeroDrinks(getTop3ZeroDrinks(readStoreReviewResponse.getReviews()))
.build();
}

private List<Type> getTop3ZeroDrinks(ReadStoreReviewResponse.Review[] reviews) {
if (reviews == null) {
return Collections.emptyList();
}
List<Type> allZeroDrinks = Arrays.stream(reviews)
.flatMap(review -> review.getReview().getZeroDrinks().stream())
.collect(Collectors.toList());

return allZeroDrinks.stream()
.collect(Collectors.groupingBy(type -> type, Collectors.counting()))
.entrySet().stream()
.sorted(Map.Entry.<Type, Long>comparingByValue().reversed()
.thenComparing(Map.Entry.comparingByKey()))
.limit(3)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}

@ToString
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(description = "판매점 조회 응답")
public static class ReadStoreInfoResponse extends BaseResponse<GlobalErrorCode> {

@Schema(description = "판매점 조회 정보")
private Store store;

@Schema(description = "리뷰 목록")
private Review[] reviews;

@Schema(description = "제로 음료수 순위")
private List<Type> zeroDrinks;

record Review(com.zerozero.core.domain.vo.Review review, com.zerozero.core.domain.vo.User user, Integer likeCount, Boolean isLiked) {

public static Review of(ReadStoreReviewResponse.Review review) {
if (review == null) {
return null;
}
return new Review(review.getReview(), review.getUser(), review.getLikeCount(), review.getIsLiked());
}
private final StoreService storeService;

@Operation(
summary = "판매점 조회 API",
description = "판매점 ID를 통해 판매점과 리뷰를 조회합니다.",
operationId = "/store"
)
@ApiErrorCode({GlobalErrorType.class, StoreErrorType.class})
@Authorization
@GetMapping("/store")
public ApiResponse<ReadStoreResponse> readStoreInfo(@ParameterObject ReadStoreRequest readStoreRequest, @Parameter(hidden = true) @LoginUser User user) {
ReadStoreResponse readStoreResponse = storeService.readStore(readStoreRequest, user);
return ApiResponse.success(readStoreResponse);
}
}

@ToString
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(description = "판매점 조회 요청")
public static class ReadStoreInfoRequest implements BaseRequest {

@Schema(description = "판매점 ID", example = "11ef3e05-f45b-7e6c-a084-7b554bfaa162")
private UUID storeId;

@Schema(description = "리뷰 정렬 조건 : RECENT(최신순), RECOMMEND(추천순)", example = "RECENT")
@Builder.Default
private Filter filter = Filter.RECENT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.zerozero.store.presentation;

import com.zerozero.configuration.argumentresolver.LoginUser;
import com.zerozero.configuration.interceptor.Authorization;
import com.zerozero.configuration.swagger.ApiErrorCode;
import com.zerozero.core.support.error.GlobalErrorType;
import com.zerozero.core.support.response.ApiResponse;
import com.zerozero.store.domain.response.StoreResponse;
import com.zerozero.store.domain.service.ReadUserStoresUseCase;
import com.zerozero.user.domain.model.User;
import com.zerozero.user.exception.UserErrorType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
@Tag(name = "User", description = "사용자")
public class ReadUserStoresController {

private final ReadUserStoresUseCase readUserStoresUseCase;

@Operation(
summary = "사용자가 등록한 판매점 목록 조회 API",
description = "사용자가 등록한 판매점 목록을 조회합니다.",
operationId = "/user/stores"
)
@ApiErrorCode({GlobalErrorType.class, UserErrorType.class})
@Authorization
@GetMapping("/user/stores")
public ApiResponse<List<StoreResponse>> readUserStores(@Parameter(hidden = true) @LoginUser User user) {
List<StoreResponse> storeResponses = readUserStoresUseCase.execute(user);
return ApiResponse.success(storeResponses);
}

}
Loading

0 comments on commit 497423e

Please sign in to comment.