From 180a74b66c004d0fc8579b1119df44f8df3ab9cc Mon Sep 17 00:00:00 2001 From: kjunh972 Date: Mon, 27 Oct 2025 00:42:00 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20[Record]=20=EA=B8=B0=EB=A1=9D=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../record/controller/RecordController.java | 8 ++++ .../domain/record/service/RecordService.java | 12 ++++++ .../controller/RecordControllerTest.java | 42 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/runtracker/src/main/java/com/runtracker/domain/record/controller/RecordController.java b/runtracker/src/main/java/com/runtracker/domain/record/controller/RecordController.java index 5ebd00f..f9ac4ac 100644 --- a/runtracker/src/main/java/com/runtracker/domain/record/controller/RecordController.java +++ b/runtracker/src/main/java/com/runtracker/domain/record/controller/RecordController.java @@ -44,4 +44,12 @@ public ApiResponse getRunningRecord( RunningRecordDTO record = recordService.getRunningRecordById(userDetails.getMemberId(), recordId); return ApiResponse.ok(record); } + + @DeleteMapping("/{recordId}") + public ApiResponse deleteRecord( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @PathVariable Long recordId) { + recordService.deleteRecord(userDetails.getMemberId(), recordId); + return ApiResponse.ok(); + } } \ No newline at end of file diff --git a/runtracker/src/main/java/com/runtracker/domain/record/service/RecordService.java b/runtracker/src/main/java/com/runtracker/domain/record/service/RecordService.java index b607c70..16f751f 100644 --- a/runtracker/src/main/java/com/runtracker/domain/record/service/RecordService.java +++ b/runtracker/src/main/java/com/runtracker/domain/record/service/RecordService.java @@ -211,4 +211,16 @@ public static LocalDate getMonthStart(LocalDate date) { public static LocalDate getMonthEnd(LocalDate date) { return date.with(TemporalAdjusters.lastDayOfMonth()); } + + @Transactional + public void deleteRecord(Long memberId, Long recordId) { + RunningRecord record = recordRepository.findById(recordId) + .orElseThrow(() -> new RecordNotFoundException("Running record not found with id: " + recordId)); + + if (!record.getMemberId().equals(memberId)) { + throw new RecordNotFoundException("Running record not found with id: " + recordId); + } + + recordRepository.delete(record); + } } diff --git a/runtracker/src/test/java/com/runtracker/domain/record/controller/RecordControllerTest.java b/runtracker/src/test/java/com/runtracker/domain/record/controller/RecordControllerTest.java index fb667e5..0468de4 100644 --- a/runtracker/src/test/java/com/runtracker/domain/record/controller/RecordControllerTest.java +++ b/runtracker/src/test/java/com/runtracker/domain/record/controller/RecordControllerTest.java @@ -18,8 +18,10 @@ import static com.epages.restdocs.apispec.ResourceDocumentation.resource; import static org.mockito.ArgumentMatchers.*; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -322,4 +324,44 @@ void getAllRunningRecordsTest() throws Exception { ) )); } + + @Test + void deleteRecordTest() throws Exception { + // given + doNothing().when(recordService).deleteRecord(anyLong(), anyLong()); + given(jwtUtil.getMemberIdFromToken(anyString())).willReturn(1L); + given(jwtUtil.getSocialIdFromToken(anyString())).willReturn("kakao_123"); + + UserDetailsImpl mockUserDetails = UserDetailsImpl.builder() + .memberId(1L) + .socialId("kakao_123") + .roles(List.of(MemberRole.USER)) + .build(); + given(userDetailsService.loadUserByUsername("1")).willReturn(mockUserDetails); + + // when + this.mockMvc.perform(delete("/api/records/{recordId}", 1L) + .header(AUTH_HEADER, TEST_ACCESS_TOKEN)) + .andExpect(status().isOk()) + .andDo(document("record-delete", + resource( + ResourceSnippetParameters.builder() + .tag("records") + .summary("러닝 기록 삭제") + .description("본인의 러닝 기록을 삭제합니다.") + .requestHeaders( + headerWithName("Authorization").description("엑세스 토큰") + ) + .pathParameters( + parameterWithName("recordId").description("삭제할 러닝 기록 ID") + ) + .responseFields( + fieldWithPath("status.statusCode").type(JsonFieldType.STRING).description("상태 코드"), + fieldWithPath("status.message").type(JsonFieldType.STRING).description("상태 메시지"), + fieldWithPath("status.description").type(JsonFieldType.STRING).description("상태 설명").optional() + ) + .build() + ) + )); + } } \ No newline at end of file