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
@@ -0,0 +1,38 @@
package com.somemore.center.controller;

import com.somemore.center.dto.request.PreferItemCreateRequestDto;
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
import com.somemore.global.common.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/preferItem")
@Tag(name = "PreferItem Command API", description = "선호 물품 등록, 삭제 기능을 제공합니다")
public class PreferItemCommandApiController {

private final CreatePreferItemUseCase createPreferItemUseCase;

@Secured("ROLE_CENTER")
@Operation(summary = "기관 선호물품 등록 API")
@PostMapping()
public ApiResponse<PreferItemCreateResponseDto> registerPreferItem(@Valid @RequestBody PreferItemCreateRequestDto requestDto,
@AuthenticationPrincipal String userId) {

PreferItemCreateResponseDto responseDto = createPreferItemUseCase.createPreferItem(UUID.fromString(userId), requestDto);

return ApiResponse.ok(200, responseDto, "관심 기관 등록 성공");
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package com.somemore.center.dto.request;


import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.center.domain.PreferItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

import java.util.UUID;


@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record PreferItemCreateRequestDto(

UUID centerId,
@Schema(description = "선호물품 이름", example = "어린이 도서")
@NotNull(message = "물품 이름은 필수값입니다.")
String itemName

) {
public PreferItem createPreferItem() {
public PreferItem toEntity(UUID centerId) {
return PreferItem.create(centerId, itemName);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.somemore.center.dto.response;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.center.domain.PreferItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.util.UUID;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Builder
public record PreferItemCreateResponseDto(
@Schema(description = "선호물품의 ID", example = "111")
Long id,
@Schema(description = "기관의 ID", example = "123e4567-e89b-12d3-a456-426614174000")
UUID centerId,
@Schema(description = "선호물품 이름", example = "어린이 도서")
String itemName
) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스웨거 적용 하면 좋을 것 같아요

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 여태 등록의 경우에는 id만 반환해줬는데 선호물품아이디, 기관아이디, 아이템이름을 보내주는 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피그마를 보고 넣어줬습니다 물품 추가, 삭제시 바로바로 웹페이지에 적용이 되는데
정합성을 유지하려면 필드를 넣어줘야할 것 같았습니다!
프론트가 구현 방식에 따라 다시 바뀔수도 있습니다

public static PreferItemCreateResponseDto from(PreferItem preferItem) {
return PreferItemCreateResponseDto.builder()
.id(preferItem.getId())
.centerId(preferItem.getCenterId())
.itemName(preferItem.getItemName())
.build();
}
}

Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.somemore.center.service.command;

import com.somemore.center.domain.PreferItem;
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
import com.somemore.center.repository.PreferItemRepository;
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
import com.somemore.center.usecase.query.CenterQueryUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@RequiredArgsConstructor
@Transactional
@Service
Expand All @@ -17,11 +21,15 @@ public class CreatePreferItemService implements CreatePreferItemUseCase {
private final PreferItemRepository preferItemRepository;

@Override
public void createPreferItem(PreferItemCreateRequestDto requestDto) {
public PreferItemCreateResponseDto createPreferItem(UUID userId, PreferItemCreateRequestDto requestDto) {

centerQueryUseCase.validateCenterExists(userId);

PreferItem preferItem = requestDto.toEntity(userId);

centerQueryUseCase.validateCenterExists(requestDto.centerId());
preferItemRepository.save(preferItem);

preferItemRepository.save(requestDto.createPreferItem());
return PreferItemCreateResponseDto.from(preferItem);
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.somemore.center.usecase.command;

import com.somemore.center.dto.request.PreferItemCreateRequestDto;
import com.somemore.center.dto.response.PreferItemCreateResponseDto;

import java.util.UUID;

public interface CreatePreferItemUseCase {

void createPreferItem(PreferItemCreateRequestDto requestDto);
PreferItemCreateResponseDto createPreferItem(UUID userId, PreferItemCreateRequestDto requestDto);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.somemore.center.controller;

import com.somemore.ControllerTestSupport;
import com.somemore.WithMockCustomUser;
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
import com.somemore.global.exception.BadRequestException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;

import java.util.UUID;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class PreferItemCommandApiControllerTest extends ControllerTestSupport {

@MockBean
private CreatePreferItemUseCase createPreferItemUseCase;


@DisplayName("기관은 선호물품을 등록할 수 있다. (controller)")
@Test
@WithMockCustomUser(role = "CENTER")
void registerPreferItem() throws Exception {
// given
UUID userId = UUID.fromString("123e4567-e89b-12d3-a456-426614174000"); // 고정된 UUID 사용
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto("어린이 도서");
PreferItemCreateResponseDto responseDto = new PreferItemCreateResponseDto(
1L,
userId,
"어린이 도서"
);

given(createPreferItemUseCase.createPreferItem(userId, requestDto))
.willReturn(responseDto);

// when & then
mockMvc.perform(post("/api/preferItem")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestDto))
.principal(() -> userId.toString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.message").value("관심 기관 등록 성공"))
.andExpect(jsonPath("$.data.id").value(responseDto.id()))
.andExpect(jsonPath("$.data.center_id").value(responseDto.centerId().toString()))
.andExpect(jsonPath("$.data.item_name").value(responseDto.itemName()));

// verify
verify(createPreferItemUseCase).createPreferItem(userId, requestDto);
}

@DisplayName("존재하지 않는 기관 ID로 선호물품을 등록할 수 없다. (controller)")
@Test
@WithMockCustomUser(role = "CENTER")
void registerPreferItem_Fail_WhenCenterNotExists() throws Exception {
// given
UUID userId = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto("어린이 도서");

given(createPreferItemUseCase.createPreferItem(userId, requestDto))
.willThrow(new BadRequestException("존재하지 않는 기관입니다."));

// when & then
mockMvc.perform(post("/api/preferItem")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestDto))
.principal(() -> userId.toString()))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.status").value(400))
.andExpect(jsonPath("$.detail").value("존재하지 않는 기관입니다."));

// verify
verify(createPreferItemUseCase).createPreferItem(userId, requestDto);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
import com.somemore.center.repository.CenterRepository;
import com.somemore.center.repository.PreferItemRepository;
import com.somemore.global.exception.BadRequestException;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@Transactional
class CreatePreferItemServiceTest extends IntegrationTestSupport {
Expand All @@ -29,26 +33,16 @@ class CreatePreferItemServiceTest extends IntegrationTestSupport {
@Test
void createPreferItem() {
//given
Center center = Center.create(
"기본 기관 이름",
"010-1234-5678",
"http://example.com/image.jpg",
"기관 소개 내용",
"http://example.com",
"account123",
"password123"
);
Center center = createCenter();
centerRepository.save(center);
String itemName = "어린이 도서";


PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto(
center.getId(),
itemName
);

//when
createPreferItemService.createPreferItem(requestDto);
createPreferItemService.createPreferItem(center.getId(), requestDto);

//then
PreferItem savedItem = preferItemRepository.findAll().stream()
Expand All @@ -61,4 +55,37 @@ void createPreferItem() {
assertThat(savedItem.getItemName()).isEqualTo(itemName);
}

@DisplayName("존재하지 않는 기관 아이디로 선호물품을 등록하려고 하면 예외를 발생시킨다.")
@Test
void createPreferItemThrowsExceptionWhenCenterDoesNotExist() {
// given
UUID invalidCenterId = UUID.randomUUID();
String itemName = "어린이 도서";

PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto(
itemName
);

// when & then
assertThatThrownBy(() -> createPreferItemService.createPreferItem(invalidCenterId, requestDto))
.isInstanceOf(BadRequestException.class)
.hasMessageContaining("존재하지 않는 기관입니다.");
}

private Center createCenter() {
Center center = Center.create(
"기본 기관 이름",
"010-1234-5678",
"http://example.com/image.jpg",
"기관 소개 내용",
"http://example.com",
"account123",
"password123"
);

centerRepository.save(center);

return center;
}

}