diff --git a/src/main/java/org/swmaestro/repl/gifthub/auth/service/DeviceTokenService.java b/src/main/java/org/swmaestro/repl/gifthub/auth/service/DeviceTokenService.java index 8155e3bb..67129e93 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/auth/service/DeviceTokenService.java +++ b/src/main/java/org/swmaestro/repl/gifthub/auth/service/DeviceTokenService.java @@ -96,6 +96,17 @@ public DeviceToken read(Long deviceTokenId) { .orElseThrow(() -> new BusinessException("존재하지 않는 토큰입니다.", StatusEnum.INTERNAL_SERVER_ERROR)); } + /* + * DeviceToken 삭제 메서드 + */ + public void delete(Member member, String token) { + DeviceToken deviceToken = read(token); + if (!deviceToken.getMember().equals(member)) { + throw new BusinessException("토큰을 삭제할 권한이 없습니다.", StatusEnum.FORBIDDEN); + } + deviceTokenRepository.delete(deviceToken); + } + /* * DeviceToken 삭제 메서드 (token) */ diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationController.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationController.java index 28fdd9e2..39b94f74 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationController.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationController.java @@ -3,6 +3,7 @@ import java.util.List; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -10,7 +11,9 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.swmaestro.repl.gifthub.notifications.dto.DeviceTokenSaveRequestDto; +import org.swmaestro.repl.gifthub.auth.entity.Member; +import org.swmaestro.repl.gifthub.auth.service.MemberService; +import org.swmaestro.repl.gifthub.notifications.dto.DeviceTokenRequestDto; import org.swmaestro.repl.gifthub.notifications.dto.NoticeNotificationDto; import org.swmaestro.repl.gifthub.notifications.dto.NotificationReadResponseDto; import org.swmaestro.repl.gifthub.notifications.service.FCMNotificationService; @@ -33,6 +36,7 @@ public class NotificationController { private final NotificationService notificationService; private final FCMNotificationService fcmNotificationService; + private final MemberService memberService; private final JwtProvider jwtProvider; @GetMapping @@ -62,9 +66,29 @@ public ResponseEntity listNotification(HttpServletRequest request) { public ResponseEntity registerDeviceToken( HttpServletRequest request, @RequestHeader("Authorization") String accessToken, - @RequestBody DeviceTokenSaveRequestDto deviceTokenSaveRequestDto) { + @RequestBody DeviceTokenRequestDto deviceTokenRequestDto) { String username = jwtProvider.getUsername(accessToken.substring(7)); - notificationService.saveDeviceToken(username, deviceTokenSaveRequestDto.getToken()); + notificationService.saveDeviceToken(username, deviceTokenRequestDto.getToken()); + return ResponseEntity.ok( + SuccessMessage.builder() + .path(request.getRequestURI()) + .build()); + } + + @DeleteMapping("/device") + @Operation(summary = "디바이스 토큰 삭제 메서드", description = "알림 서비스를 위한 디바이스 토큰을 삭제하기 위한 메서드입니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "디바이스 토큰 등록 성공"), + @ApiResponse(responseCode = "400(400)", description = "존재하지 토큰 등록 시도"), + @ApiResponse(responseCode = "400(404)", description = "존재하지 않는 회원"), + }) + public ResponseEntity deleteDeviceToken( + HttpServletRequest request, + @RequestHeader("Authorization") String accessToken, + @RequestBody DeviceTokenRequestDto deviceTokenRequestDto) { + String username = jwtProvider.getUsername(accessToken.substring(7)); + Member member = memberService.read(username); + notificationService.deleteDeviceToken(member, deviceTokenRequestDto.getToken()); return ResponseEntity.ok( SuccessMessage.builder() .path(request.getRequestURI()) diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenSaveRequestDto.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenRequestDto.java similarity index 83% rename from src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenSaveRequestDto.java rename to src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenRequestDto.java index ba3529de..b991b9b5 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenSaveRequestDto.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/dto/DeviceTokenRequestDto.java @@ -11,11 +11,11 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) -public class DeviceTokenSaveRequestDto { +public class DeviceTokenRequestDto { private String token; @Builder - public DeviceTokenSaveRequestDto(String token) { + public DeviceTokenRequestDto(String token) { this.token = token; } } diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/service/NotificationService.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/service/NotificationService.java index 5a8461e7..7a82f46c 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/service/NotificationService.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/service/NotificationService.java @@ -69,6 +69,15 @@ public boolean saveDeviceToken(String username, String deviceToken) { } + public boolean deleteDeviceToken(Member member, String deviceToken) { + try { + deviceTokenService.delete(member, deviceToken); + return true; + } catch (Exception e) { + throw new BusinessException("디바이스 토큰 삭제에 실패하였습니다.", StatusEnum.BAD_REQUEST); + } + } + /** * Notification 저장 메서드 */ diff --git a/src/test/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationControllerTest.java b/src/test/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationControllerTest.java index a5bbba47..19076f2c 100644 --- a/src/test/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationControllerTest.java +++ b/src/test/java/org/swmaestro/repl/gifthub/notifications/controller/NotificationControllerTest.java @@ -16,7 +16,9 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; -import org.swmaestro.repl.gifthub.notifications.dto.DeviceTokenSaveRequestDto; +import org.swmaestro.repl.gifthub.auth.entity.Member; +import org.swmaestro.repl.gifthub.auth.service.MemberService; +import org.swmaestro.repl.gifthub.notifications.dto.DeviceTokenRequestDto; import org.swmaestro.repl.gifthub.notifications.dto.NotificationReadResponseDto; import org.swmaestro.repl.gifthub.notifications.service.NotificationService; import org.swmaestro.repl.gifthub.util.JwtProvider; @@ -38,6 +40,9 @@ public class NotificationControllerTest { @MockBean private NotificationService notificationService; + @MockBean + private MemberService memberService; + /** * 알림 목록 조회 테스트 */ @@ -78,17 +83,17 @@ void saveDeviceToken() throws Exception { // given String accessToken = "my.access.token"; String username = "이진우"; - DeviceTokenSaveRequestDto deviceTokenSaveRequestDto = DeviceTokenSaveRequestDto.builder().token("my.device.token").build(); + DeviceTokenRequestDto deviceTokenRequestDto = DeviceTokenRequestDto.builder().token("my.device.token").build(); // when when(jwtProvider.resolveToken(any())).thenReturn(accessToken); when(jwtProvider.getUsername(anyString())).thenReturn(username); - when(notificationService.saveDeviceToken(username, deviceTokenSaveRequestDto.getToken())).thenReturn(true); + when(notificationService.saveDeviceToken(username, deviceTokenRequestDto.getToken())).thenReturn(true); // then mockMvc.perform(post("/notifications/device").header("Authorization", "Bearer " + accessToken) .contentType("application/json") - .content(objectMapper.writeValueAsString(deviceTokenSaveRequestDto))) + .content(objectMapper.writeValueAsString(deviceTokenRequestDto))) .andExpect(status().isOk()) .andReturn(); } @@ -118,4 +123,23 @@ void readNotificationTest() throws Exception { .andExpect(status().isOk()) .andReturn(); } + + @Test + @WithMockUser(username = "이진우", roles = "USER") + void deleteDeviceToken() throws Exception { + String accessToken = "my.access.token"; + String username = "이진우"; + DeviceTokenRequestDto deviceTokenRequestDto = DeviceTokenRequestDto.builder().token("my.device.token").build(); + Member member = Member.builder().username(username).build(); + + when(jwtProvider.resolveToken(any())).thenReturn(accessToken); + when(jwtProvider.getUsername(anyString())).thenReturn(username); + when(memberService.read(username)).thenReturn(member); + when(notificationService.deleteDeviceToken(member, deviceTokenRequestDto.getToken())).thenReturn(true); + + mockMvc.perform(delete("/notifications/device").header("Authorization", "Bearer " + accessToken) + .contentType("application/json") + .content(objectMapper.writeValueAsString(deviceTokenRequestDto))) + .andExpect(status().isOk()); + } }