Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,24 @@ public BaseResponse<SliceResponse<DailyCoordinateListResponse>> getDailyCoordina
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}

@GetMapping("/daily/today")
@GetMapping("/daily/today/preview")
@Operation(
operationId = "Coordinate_getTodayDailyCoordinateClothes",
summary = "오늘의 코디 옷 정보 조회",
description = "오늘의 코디에 포함된 옷 정보를 조회하는 API입니다.")
public BaseResponse<List<DailyCoordinateClothResponse>> getTodayDailyCoordinateClothes() {
List<DailyCoordinateClothResponse> response =
coordinateService.getTodayDailyCoordinateClothes();
operationId = "Coordinate_getTodayCoordinatePreview",
summary = "오늘의 코디 Preview 조회",
description = "오늘의 코디의 Preview를 조회하는 API입니다.")
public BaseResponse<DailyCoordinatePreviewResponse> getTodayCoordinatePreview() {
DailyCoordinatePreviewResponse response = coordinateService.getTodayCoordinatePreview();
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}

@GetMapping("/daily/today/details")
@Operation(
operationId = "Coordinate_getTodayCoordinateDetails",
summary = "오늘의 코디 Details 조회",
description = "오늘의 코디의 Details를 조회하는 API입니다.")
public BaseResponse<List<CoordinateDetailsListResponse>> getTodayCoordinateDetails() {
List<CoordinateDetailsListResponse> response =
coordinateService.getTodayCoordinateDetails();
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.clokey.domain.coordinate.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
import org.clokey.coordinate.entity.Coordinate;

public record DailyCoordinatePreviewResponse(
@Schema(description = "오늘의 코디의 ID", example = "1") Long coordinateId,
@Schema(description = "오늘의 코디의 imageUrl", example = "https://example.jpg") String imageUrl,
@Schema(description = "오늘의 코디의 날짜", example = "2026-02-04") LocalDate date) {
public static DailyCoordinatePreviewResponse from(Coordinate coordinate) {
return new DailyCoordinatePreviewResponse(
coordinate.getId(),
coordinate.getImageUrl(),
coordinate.getUpdatedAt().toLocalDate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ public enum CoordinateErrorCode implements BaseErrorCode {
COORDINATE_NOT_IN_LOOK_BOOK(400, "COORDINATE_4005", "룩북에 속해있지 않은 (오늘의) 코디입니다."),
COORDINATE_LIKE_LIMIT(400, "COORDINATE_4006", "최대 5개의 코디에 좋아요를 누를 수 있습니다."),

NOT_COORDINATE_OWNER(400, "COORDINATE_4031", "나의 코디가 아닙니다. 권한이 없습니다."),
NOT_COORDINATE_OWNER(403, "COORDINATE_4031", "나의 코디가 아닙니다. 권한이 없습니다."),

COORDINATE_NOT_FOUND(400, "COORDINATE_4041", "존재하지 않는 코디입니다.");
COORDINATE_NOT_FOUND(404, "COORDINATE_4041", "존재하지 않는 코디입니다."),
DAILY_COORDINATE_NOT_FOUND(404, "COORDINATE_4042", "오늘의 코디가 존재하지 않습니다.");

private final int status;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ public interface CoordinateService {
SliceResponse<DailyCoordinateListResponse> getDailyCoordinates(
Long lastCoordinateId, int size, SortDirection direction);

List<DailyCoordinateClothResponse> getTodayDailyCoordinateClothes();
DailyCoordinatePreviewResponse getTodayCoordinatePreview();

List<CoordinateDetailsListResponse> getTodayCoordinateDetails();

CoordinatePreviewResponse getCoordinatePreview(Long coordinateId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,25 +322,19 @@ public SliceResponse<DailyCoordinateListResponse> getDailyCoordinates(
}

@Override
public List<DailyCoordinateClothResponse> getTodayDailyCoordinateClothes() {
public DailyCoordinatePreviewResponse getTodayCoordinatePreview() {
final Member currentMember = memberUtil.getCurrentMember();
Optional<Coordinate> coordinate =
coordinateRepository.findDailyCoordinateByDateAndMemberId(
LocalDate.now(), currentMember.getId());
final Coordinate coordinate = getTodayDailyCoordinate(currentMember);

if (coordinate.isEmpty()) {
return List.of();
}

List<CoordinateDetailsListResponse> details =
coordinateRepository.findAllCoordinateDetailsByCoordinateId(
coordinate.get().getId());
return DailyCoordinatePreviewResponse.from(coordinate);
}

if (details.isEmpty()) {
return List.of();
}
@Override
public List<CoordinateDetailsListResponse> getTodayCoordinateDetails() {
final Member currentMember = memberUtil.getCurrentMember();
final Coordinate coordinate = getTodayDailyCoordinate(currentMember);

return details.stream().map(DailyCoordinateClothResponse::from).toList();
return coordinateRepository.findAllCoordinateDetailsByCoordinateId(coordinate.getId());
}

@Override
Expand Down Expand Up @@ -487,4 +481,13 @@ private Coordinate getCoordinateById(Long coordinateId) {
.orElseThrow(
() -> new BaseCustomException(CoordinateErrorCode.COORDINATE_NOT_FOUND));
}

private Coordinate getTodayDailyCoordinate(Member member) {
return coordinateRepository
.findDailyCoordinateByDateAndMemberId(LocalDate.now(), member.getId())
.orElseThrow(
() ->
new BaseCustomException(
CoordinateErrorCode.DAILY_COORDINATE_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.clokey.domain.coordinate.dto.request.CoordinateAutoCreateRequest;
Expand Down Expand Up @@ -1663,47 +1664,106 @@ class 최애_코디_조회_요청_시 {
}

@Nested
class 오늘의_코디_조회_요청_시 {
class 오늘의_코디_Preview_조회_요청_시 {

@Test
void 유효한_요청이면_오늘의_코디_정보를_반환한다() throws Exception {
void 유효한_요청이면_오늘의_코디_Preview를_반환한다() throws Exception {
// given
List<DailyCoordinateClothResponse> response =
LocalDate today = LocalDate.now();
DailyCoordinatePreviewResponse response =
new DailyCoordinatePreviewResponse(1L, "testImageUrl", LocalDate.now());
given(coordinateService.getTodayCoordinatePreview()).willReturn(response);

// when & then
ResultActions perform =
mockMvc.perform(
get("/coordinate/daily/today/preview")
.contentType(MediaType.APPLICATION_JSON));

perform.andExpect(status().isOk())
.andExpect(jsonPath("$.isSuccess").value(true))
.andExpect(jsonPath("$.code").value("COMMON200"))
.andExpect(jsonPath("$.message").value("성공입니다."))
.andExpect(jsonPath("$.result.coordinateId").value(1))
.andExpect(jsonPath("$.result.imageUrl").value("testImageUrl"))
.andExpect(jsonPath("$.result.date").value(today.toString()));
}
}

@Nested
class 오늘의_코디_Details_조회_요청_시 {

@Test
void 유효한_요청이면_오늘의_코디_Details를_반환한다() throws Exception {
// given
List<CoordinateDetailsListResponse> response =
List.of(
new DailyCoordinateClothResponse(
"https://image.example/cloth1.jpg",
"brand1",
"name1",
"category1",
"parent1"),
new DailyCoordinateClothResponse(
"https://image.example/cloth2.jpg",
"brand2",
"name2",
"category2",
"parent2"));

given(coordinateService.getTodayDailyCoordinateClothes()).willReturn(response);

ResultActions perform = mockMvc.perform(get("/coordinate/daily/today"));
new CoordinateDetailsListResponse(
1L,
50.2,
60.1,
1.5,
240.1,
1,
14L,
"testImageUrl1",
"testBrand1",
"testName1",
"testCategoryName1",
"testParentCategoryName1"),
new CoordinateDetailsListResponse(
2L,
50.2,
60.1,
1.5,
240.1,
2,
15L,
"testImageUrl2",
"testBrand2",
"testName2",
"testCategoryName2",
"testParentCategoryName2"));

given(coordinateService.getTodayCoordinateDetails()).willReturn(response);

// when & then
ResultActions perform =
mockMvc.perform(
get("/coordinate/daily/today/details")
.contentType(MediaType.APPLICATION_JSON));

perform.andExpect(status().isOk())
.andExpect(jsonPath("$.isSuccess").value(true))
.andExpect(jsonPath("$.code").value("COMMON200"))
.andExpect(jsonPath("$.message").value("성공입니다."))
.andExpect(jsonPath("$.result[0].coordinateClothId").value(1))
.andExpect(jsonPath("$.result[0].locationX").value(50.2))
.andExpect(jsonPath("$.result[0].locationY").value(60.1))
.andExpect(jsonPath("$.result[0].ratio").value(1.5))
.andExpect(jsonPath("$.result[0].degree").value(240.1))
.andExpect(jsonPath("$.result[0].order").value(1))
.andExpect(jsonPath("$.result[0].clothId").value(14))
.andExpect(jsonPath("$.result[0].imageUrl").value("testImageUrl1"))
.andExpect(jsonPath("$.result[0].brand").value("testBrand1"))
.andExpect(jsonPath("$.result[0].name").value("testName1"))
.andExpect(jsonPath("$.result[0].category").value("testCategoryName1"))
.andExpect(
jsonPath("$.result[0].imageUrl")
.value("https://image.example/cloth1.jpg"))
.andExpect(jsonPath("$.result[0].brand").value("brand1"))
.andExpect(jsonPath("$.result[0].name").value("name1"))
.andExpect(jsonPath("$.result[0].category").value("category1"))
.andExpect(jsonPath("$.result[0].parentCategory").value("parent1"))
jsonPath("$.result[0].parentCategory").value("testParentCategoryName1"))
.andExpect(jsonPath("$.result[1].coordinateClothId").value(2))
.andExpect(jsonPath("$.result[1].locationX").value(50.2))
.andExpect(jsonPath("$.result[1].locationY").value(60.1))
.andExpect(jsonPath("$.result[1].ratio").value(1.5))
.andExpect(jsonPath("$.result[1].degree").value(240.1))
.andExpect(jsonPath("$.result[1].order").value(2))
.andExpect(jsonPath("$.result[1].clothId").value(15))
.andExpect(jsonPath("$.result[1].imageUrl").value("testImageUrl2"))
.andExpect(jsonPath("$.result[1].brand").value("testBrand2"))
.andExpect(jsonPath("$.result[1].name").value("testName2"))
.andExpect(jsonPath("$.result[1].category").value("testCategoryName2"))
.andExpect(
jsonPath("$.result[1].imageUrl")
.value("https://image.example/cloth2.jpg"))
.andExpect(jsonPath("$.result[1].brand").value("brand2"))
.andExpect(jsonPath("$.result[1].name").value("name2"))
.andExpect(jsonPath("$.result[1].category").value("category2"))
.andExpect(jsonPath("$.result[1].parentCategory").value("parent2"));
jsonPath("$.result[1].parentCategory")
.value("testParentCategoryName2"));
}
}
}
Loading