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 e286be15..cb8a4f92 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; @@ -121,4 +122,24 @@ public ResponseEntity denyExpirationNotification( .path(request.getRequestURI()) .build()); } + + @DeleteMapping("/{notificationId}") + @Operation(summary = "Notification 삭제 메서드", description = "클라이언트에서 요청한 알림을 삭제하기 위한 메서드입니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "알림 삭제 성공"), + @ApiResponse(responseCode = "400(404)", description = "존재하지 않는 알림"), + @ApiResponse(responseCode = "400(404)", description = "존재하지 않는 회원"), + @ApiResponse(responseCode = "400(403)", description = "알림 삭제 권한 없음") + }) + public ResponseEntity deleteNotification( + HttpServletRequest request, + @RequestHeader("Authorization") String accessToken, + @PathVariable Long notificationId) { + String username = jwtProvider.getUsername(accessToken.substring(7)); + notificationService.delete(notificationId, username); + return ResponseEntity.ok( + SuccessMessage.builder() + .path(request.getRequestURI()) + .build()); + } } diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/entity/Notification.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/entity/Notification.java index a7514b36..a4fa959d 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/entity/Notification.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/entity/Notification.java @@ -69,4 +69,8 @@ public Notification(Long id, User receiver, Voucher voucher, NotificationType ty public void setCheckedAt(LocalDateTime checkedAt) { this.checkedAt = checkedAt; } + + public void setDeletedAt(LocalDateTime deletedAt) { + this.deletedAt = deletedAt; + } } diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/repository/NotificationRepository.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/repository/NotificationRepository.java index 20eced4a..6e5c2698 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/repository/NotificationRepository.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/repository/NotificationRepository.java @@ -6,5 +6,5 @@ import org.swmaestro.repl.gifthub.notifications.entity.Notification; public interface NotificationRepository extends JpaRepository { - List findAllByReceiverUsername(String username); + List findAllByReceiverUsernameAndDeletedAtIsNull(String username); } 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 331f119e..21beb573 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 @@ -27,7 +27,7 @@ public List list(String username) { if (userService.read(username) == null) { throw new BusinessException("존재하지 않는 회원입니다.", StatusEnum.NOT_FOUND); } - List notifications = notificationRepository.findAllByReceiverUsername(username); + List notifications = notificationRepository.findAllByReceiverUsernameAndDeletedAtIsNull(username); List notificationReadResponseDtos = new ArrayList<>(); @@ -56,29 +56,6 @@ public NotificationReadResponseDto mapToDto(Notification notification) { return notificationReadResponseDto; } - // /** - // * 디바이스 토큰을 저장하는 메서드 - // */ - // public boolean saveDeviceToken(String username, String deviceToken) { - // try { - // deviceTokenService.save(username, deviceToken); - // - // return true; - // } catch (Exception e) { - // throw new BusinessException("디바이스 토큰 저장에 실패하였습니다.", StatusEnum.BAD_REQUEST); - // } - // - // } - // - // public boolean deleteDeviceToken(User user, String deviceToken) { - // try { - // deviceTokenService.delete(user, deviceToken); - // return true; - // } catch (Exception e) { - // throw new BusinessException("디바이스 토큰 삭제에 실패하였습니다.", StatusEnum.BAD_REQUEST); - // } - // } - /** * Notification 저장 메서드 */ @@ -109,4 +86,20 @@ public NotificationReadResponseDto read(Long id, String username) { notificationRepository.save(notification); return notificationReadResponseDto; } + + /** + * Notification 삭제 메서드 + */ + public void delete(Long id, String username) { + if (userService.read(username) == null) { + throw new BusinessException("존재하지 않는 회원입니다.", StatusEnum.NOT_FOUND); + } + Notification notification = notificationRepository.findById(id).orElseThrow(() -> new BusinessException("존재하지 않는 알림입니다.", StatusEnum.NOT_FOUND)); + + if (!notification.getReceiver().getUsername().equals(username)) { + throw new BusinessException("알림을 삭제할 권한이 없습니다.", StatusEnum.FORBIDDEN); + } + notification.setDeletedAt(LocalDateTime.now()); + notificationRepository.save(notification); + } } diff --git a/src/main/java/org/swmaestro/repl/gifthub/notifications/service/ScheduledTasks.java b/src/main/java/org/swmaestro/repl/gifthub/notifications/service/ScheduledTasks.java index ef4274c7..c884166a 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/notifications/service/ScheduledTasks.java +++ b/src/main/java/org/swmaestro/repl/gifthub/notifications/service/ScheduledTasks.java @@ -39,11 +39,18 @@ public void sendExpirationNotification() { long daysDifference = ChronoUnit.DAYS.between(today, voucher.getExpiresAt()); if (daysDifference <= 3) { + String message; + if (daysDifference == 0) { + message = voucher.getBrand().getName() + "에서 사용할 수 있는 기프티콘이 오늘 만료됩니다."; + } else { + message = voucher.getBrand().getName() + "에서 사용할 수 있는 기프티콘 기한이 " + daysDifference + "일 남았습니다."; + } + FCMNotificationRequestDto requestDto = FCMNotificationRequestDto.builder() .targetUser(voucher.getUser()) .targetVoucher(voucher) .title(NotificationType.EXPIRATION.getDescription()) - .body(voucher.getBrand().getName() + "에서 사용할 수 있는 기프티콘 기한이 " + daysDifference + "일 남았습니다.") + .body(message) .build(); fcmNotificationService.sendNotificationByToken(requestDto); diff --git a/src/main/java/org/swmaestro/repl/gifthub/vouchers/dto/VoucherReadResponseDto.java b/src/main/java/org/swmaestro/repl/gifthub/vouchers/dto/VoucherReadResponseDto.java index 58b12bc2..b2f061db 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/vouchers/dto/VoucherReadResponseDto.java +++ b/src/main/java/org/swmaestro/repl/gifthub/vouchers/dto/VoucherReadResponseDto.java @@ -1,20 +1,18 @@ package org.swmaestro.repl.gifthub.vouchers.dto; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; @Getter -@Builder @ToString @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) public class VoucherReadResponseDto { private Long id; @@ -24,4 +22,19 @@ public class VoucherReadResponseDto { private Integer price; private Integer balance; private String imageUrl; + @JsonProperty("is_accessible") + private boolean accessible; + + @Builder + public VoucherReadResponseDto(Long id, Long productId, String barcode, String expiresAt, Integer price, + Integer balance, String imageUrl, boolean accessible) { + this.id = id; + this.productId = productId; + this.barcode = barcode; + this.expiresAt = expiresAt; + this.price = price; + this.balance = balance; + this.imageUrl = imageUrl; + this.accessible = accessible; + } } diff --git a/src/main/java/org/swmaestro/repl/gifthub/vouchers/entity/Voucher.java b/src/main/java/org/swmaestro/repl/gifthub/vouchers/entity/Voucher.java index 639cf358..e8b66623 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/vouchers/entity/Voucher.java +++ b/src/main/java/org/swmaestro/repl/gifthub/vouchers/entity/Voucher.java @@ -36,7 +36,7 @@ public class Voucher extends BaseTimeEntity { @JoinColumn(name = "product_id", nullable = false) private Product product; - @Column(length = 12, nullable = false) + @Column(length = 12) private String barcode; @Column diff --git a/src/main/java/org/swmaestro/repl/gifthub/vouchers/service/VoucherService.java b/src/main/java/org/swmaestro/repl/gifthub/vouchers/service/VoucherService.java index 5b435d79..616b0054 100644 --- a/src/main/java/org/swmaestro/repl/gifthub/vouchers/service/VoucherService.java +++ b/src/main/java/org/swmaestro/repl/gifthub/vouchers/service/VoucherService.java @@ -108,9 +108,9 @@ public VoucherReadResponseDto read(Long id, String username) { if (!vouchers.contains(voucher.get())) { throw new BusinessException("상품권을 조회할 권한이 없습니다.", StatusEnum.FORBIDDEN); } - if (voucher.get().isDeleted()) { - throw new BusinessException("삭제된 상품권 입니다.", StatusEnum.BAD_REQUEST); - } + // if (voucher.get().isDeleted()) { + // throw new BusinessException("삭제된 상품권 입니다.", StatusEnum.BAD_REQUEST); + // } VoucherReadResponseDto voucherReadResponseDto = mapToDto(voucher.get()); return voucherReadResponseDto; @@ -246,6 +246,7 @@ public boolean delete(String username, Long voucherId) { try { voucher.get().setDeletedAt(LocalDateTime.now()); + voucher.get().setBarcode(null); voucherRepository.save(voucher.get()); return true; } catch (Exception e) { @@ -265,6 +266,7 @@ public VoucherReadResponseDto mapToDto(Voucher voucher) { .balance(voucher.getBalance()) .expiresAt(voucher.getExpiresAt().toString()) .imageUrl(voucher.getImageUrl()) + .accessible(voucher.getDeletedAt() == null) .build(); return voucherReadResponseDto; } @@ -275,6 +277,9 @@ public VoucherReadResponseDto mapToDto(Voucher voucher) { public boolean isDuplicateVoucher(String username, String barcode) { List vouchers = voucherRepository.findAllByUserUsername(username); for (Voucher voucher : vouchers) { + if (voucher.getBarcode() == null) { + continue; + } if (voucher.getBarcode().equals(barcode)) { return true; }