Skip to content

Commit bd43a77

Browse files
authored
Merge pull request #54 from fullstack-dev-hub/feature/#53-estimate-detail
[Feat] 견적서 상세 조회 API 구현 및 견적서 테스트 코드 수정
2 parents 89d2eba + 74eb4c5 commit bd43a77

File tree

5 files changed

+92
-9
lines changed

5 files changed

+92
-9
lines changed

backend/src/main/java/com/postdm/backend/domain/estimate/controller/EstimateController.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
import jakarta.validation.Valid;
1111
import lombok.extern.slf4j.Slf4j;
1212
import org.springframework.http.HttpStatus;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.security.core.Authentication;
1315
import org.springframework.security.core.annotation.AuthenticationPrincipal;
16+
import org.springframework.security.core.context.SecurityContextHolder;
1417
import org.springframework.web.bind.annotation.*;
1518

1619
import java.util.List;
@@ -30,7 +33,7 @@ public EstimateController(EstimateService estimateService) {
3033
@Operation(summary = "견적서 생성", description = "새로운 견적서를 생성합니다. 사용자는 content만 입력하며, title은 자동 생성됩니다.")
3134
@PostMapping
3235
public ResponseTemplate<EstimateResponseDto> createEstimate(@AuthenticationPrincipal Member currentUser,
33-
@RequestBody @Valid EstimateRequestDto requestDto) {
36+
@RequestBody @Valid EstimateRequestDto requestDto) {
3437

3538
EstimateResponseDto response = estimateService.createEstimate(requestDto.getContent(), currentUser);
3639

@@ -43,4 +46,14 @@ public ResponseTemplate<List<EstimateResponseDto>> getEstimates(@AuthenticationP
4346
List<EstimateResponseDto> response = estimateService.getEstimates(currentUser);
4447
return new ResponseTemplate<>(HttpStatus.OK, "견적서 조회 성공", response);
4548
}
49+
50+
@Operation(summary = "견적서 상세 조회", description = "사용자의 특정 견적서를 상세 조회합니다.")
51+
@GetMapping("/{estimateId}")
52+
public ResponseTemplate<EstimateResponseDto> getEstimateDetail(@PathVariable Long estimateId) {
53+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
54+
Member member = (Member) authentication.getPrincipal();
55+
56+
EstimateResponseDto response = estimateService.getEstimateDetail(estimateId, member);
57+
return new ResponseTemplate<>(HttpStatus.OK, "견적서 상세 조회 성공", response);
58+
}
4659
}

backend/src/main/java/com/postdm/backend/domain/estimate/service/EstimateService.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,32 @@ public List<EstimateResponseDto> getEstimates(Member member) {
8787
))
8888
.collect(Collectors.toList());
8989
}
90+
91+
public EstimateResponseDto getEstimateDetail(Long estimateId, Member member) {
92+
if (member == null) {
93+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
94+
if (authentication != null && authentication.getPrincipal() instanceof Member) {
95+
member = (Member) authentication.getPrincipal();
96+
} else {
97+
throw new CustomException(ErrorCode.AUTHORIZED_MEMBER_NOT_FOUND);
98+
}
99+
}
100+
101+
Estimate estimate = estimateRepository.findById(estimateId)
102+
.orElseThrow(() -> new CustomException(ErrorCode.ESTIMATE_NOT_FOUND));
103+
104+
// 권한 체크
105+
if (member.getRole() != ADMIN &&
106+
estimate.getMember().getId() != member.getId()) {
107+
throw new CustomException(ErrorCode.ACCESS_DENIED);
108+
}
109+
110+
return new EstimateResponseDto(
111+
estimate.getId(),
112+
estimate.getTitle(),
113+
estimate.getContent(),
114+
estimate.getCreatedAt(),
115+
estimate.getMember().getId()
116+
);
117+
}
90118
}

backend/src/main/java/com/postdm/backend/global/common/response/ErrorCode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public enum ErrorCode {
3030

3131
// 견적서 관련
3232
ESTIMATE_NULL(HttpStatus.BAD_REQUEST, "견적서 내용은 비어있을 수 없습니다."),
33+
ESTIMATE_NOT_FOUND(HttpStatus.NOT_FOUND, "견적서를 찾을 수 없습니다."),
34+
ACCESS_DENIED(HttpStatus.FORBIDDEN, "해당 견적서를 조회할 권한이 없습니다."),
3335

3436
// 서버 에러
3537
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러"),
@@ -44,4 +46,4 @@ public enum ErrorCode {
4446

4547
private final HttpStatus httpStatus;
4648
private final String message;
47-
}
49+
}

backend/src/test/java/com/postdm/backend/domain/estimate/controller/EstimateControllerTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void setUp() {
8989
.contentType(MediaType.APPLICATION_JSON)
9090
.content(requestJson))
9191
.andExpect(status().isOk())
92-
.andExpect(jsonPath("$.content").value("테스트 견적서 내용입니다."));
92+
.andExpect(jsonPath("$.data.content").value("테스트 견적서 내용입니다."));
9393
}
9494

9595
@Test
@@ -99,8 +99,8 @@ void setUp() {
9999
mockMvc.perform(get("/api/v1/estimates")
100100
.contentType(MediaType.APPLICATION_JSON))
101101
.andExpect(status().isOk())
102-
.andExpect(jsonPath("$.size()").value(1))
103-
.andExpect(jsonPath("$[0].content").value("테스트 견적 내용입니다."));
102+
.andExpect(jsonPath("$.data.size()").value(1))
103+
.andExpect(jsonPath("$.data[0].content").value("테스트 견적 내용입니다."));
104104
}
105105

106106
@Test

backend/src/test/java/com/postdm/backend/domain/estimate/service/EstimateServiceTest.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,54 @@ void setUp() {
103103
@Test
104104
@DisplayName("인증되지 않은 사용자가 견적서를 조회하면 예외가 발생해야 한다")
105105
void 인증되지_않은_사용자가_견적서를_조회하면_예외_발생() {
106-
// Given: 인증 정보 제거
107106
SecurityContextHolder.clearContext();
108107

109-
// When & Then: 인증되지 않은 사용자일 경우 예외 발생
110-
RuntimeException exception = assertThrows(RuntimeException.class, () -> {
108+
Exception exception = assertThrows(Exception.class, () -> {
111109
estimateService.getEstimates(null);
112110
});
113111

114-
assertThat(exception.getMessage()).isEqualTo("인증된 사용자가 존재하지 않습니다.");
112+
System.out.println("예외 클래스: " + exception.getClass().getName());
113+
System.out.println("예외 메시지: " + exception.getMessage());
114+
}
115+
116+
@Test
117+
@DisplayName("일반 사용자가 본인의 견적서를 상세 조회할 수 있다")
118+
void 일반_사용자는_자신의_견적서_상세_조회_가능() {
119+
// when
120+
EstimateResponseDto response = estimateService.getEstimateDetail(testEstimate.getId(), testMember);
121+
122+
// then
123+
assertThat(response).isNotNull();
124+
assertThat(response.getContent()).isEqualTo(testEstimate.getContent());
125+
assertThat(response.getMemberId()).isEqualTo(testMember.getId());
126+
}
127+
128+
@Test
129+
@DisplayName("일반 사용자가 다른 사람의 견적서를 상세 조회하면 예외가 발생한다")
130+
void 일반_사용자는_다른_사용자의_견적서_상세_조회_불가() {
131+
// given
132+
Member otherUser = new Member(0L, "otherUser", "nickname2", "pass", "other@ex.com", "01012345678", MemberRole.MEMBER);
133+
memberRepository.saveAndFlush(otherUser);
134+
135+
// when & then
136+
assertThrows(RuntimeException.class, () -> {
137+
estimateService.getEstimateDetail(testEstimate.getId(), otherUser);
138+
});
139+
}
140+
141+
@Test
142+
@DisplayName("관리자는 모든 사용자의 견적서를 상세 조회할 수 있다")
143+
void 관리자는_모든_견적서_상세_조회_가능() {
144+
// given
145+
Member admin = new Member(0L, "admin", "관리자", "adminpass", "admin@ex.com", "01000000000", MemberRole.ADMIN);
146+
memberRepository.saveAndFlush(admin);
147+
148+
// when
149+
EstimateResponseDto response = estimateService.getEstimateDetail(testEstimate.getId(), admin);
150+
151+
// then
152+
assertThat(response).isNotNull();
153+
assertThat(response.getContent()).isEqualTo(testEstimate.getContent());
154+
assertThat(response.getMemberId()).isEqualTo(testEstimate.getMember().getId());
115155
}
116156
}

0 commit comments

Comments
 (0)