Skip to content

Commit 2176230

Browse files
authored
Merge pull request #238 from prgrms-aibe-devcourse/refector/v2-notification
refector: 알림 서비스/컨트롤러 V2 명명 규칙 적용 및 Converter 도입
2 parents e60aa26 + 17aec04 commit 2176230

7 files changed

Lines changed: 234 additions & 48 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package store.lastdance.controller.notification;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.Parameter;
5+
import lombok.extern.slf4j.Slf4j;
6+
import store.lastdance.dto.response.ApiResponse;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.http.ResponseEntity;
10+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
11+
import org.springframework.web.bind.annotation.*;
12+
import store.lastdance.dto.notification.NotificationSettingRequestDTO;
13+
import store.lastdance.dto.notification.NotificationSettingResponseDTO;
14+
import store.lastdance.exception.CustomException;
15+
import store.lastdance.exception.ErrorCode;
16+
import store.lastdance.security.oauth.CustomOAuth2User;
17+
import store.lastdance.service.notification.NotificationSettingV2Service;
18+
19+
@Slf4j
20+
@RestController
21+
@RequestMapping("/api/v2/notification-settings")
22+
@RequiredArgsConstructor
23+
@Tag(name = "알림 설정", description = "사용자 알림 설정 관리 API")
24+
public class NotificationSettingV2Controller {
25+
26+
private final NotificationSettingV2Service settingService;
27+
28+
@GetMapping("/me")
29+
@Operation(
30+
summary = "내 알림 설정 조회",
31+
description = "현재 로그인한 사용자의 알림 설정을 조회합니다."
32+
)
33+
public ResponseEntity<ApiResponse<NotificationSettingResponseDTO>> getMySettings(
34+
@Parameter(hidden = true) @AuthenticationPrincipal CustomOAuth2User user) {
35+
try{
36+
if (user == null) throw new CustomException(ErrorCode.TOKEN_NOT_FOUND);
37+
NotificationSettingResponseDTO setting = settingService.getUserSetting(user.getUserId());
38+
return ResponseEntity.ok(ApiResponse.success(setting));
39+
} catch (Exception e) {
40+
log.error("알림 설정 조회 실패 - 사용자: {}, 에러: {}", user.getUserId(), e.getMessage(), e);
41+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_FOUND_FAILED);
42+
}
43+
}
44+
45+
@PatchMapping("/me")
46+
@Operation(
47+
summary = "내 알림 설정 수정",
48+
description = "현재 로그인한 사용자의 알림 설정을 수정합니다."
49+
)
50+
public ResponseEntity<ApiResponse<String>> updateMySettings(
51+
@Parameter(hidden = true) @AuthenticationPrincipal CustomOAuth2User user,
52+
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "수정할 알림 설정")
53+
@RequestBody @jakarta.validation.Valid NotificationSettingRequestDTO request) {
54+
try {
55+
if (user == null) throw new CustomException(ErrorCode.TOKEN_NOT_FOUND);
56+
settingService.updateSetting(user.getUserId(), request);
57+
return ResponseEntity.ok(ApiResponse.success("알림 설정이 성공적으로 업데이트되었습니다."));
58+
} catch (Exception e) {
59+
log.error("알림 설정 수정 실패 - 사용자: {}, 에러: {}", user.getUserId(), e.getMessage(), e);
60+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_UPDATE_FAILED);
61+
}
62+
}
63+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package store.lastdance.converter.notification;
2+
3+
import org.springframework.stereotype.Component;
4+
import store.lastdance.domain.notification.NotificationSetting;
5+
import store.lastdance.dto.notification.NotificationSettingResponseDTO;
6+
7+
import java.util.UUID;
8+
9+
@Component
10+
public class NotificationSettingConverter {
11+
public NotificationSetting toEntity(UUID userId) {
12+
return NotificationSetting.builder()
13+
.userId(userId)
14+
.build();
15+
}
16+
17+
public NotificationSettingResponseDTO toDto(NotificationSetting notificationSetting) {
18+
return NotificationSettingResponseDTO.builder()
19+
.settingId(notificationSetting.getSettingId())
20+
.userId(notificationSetting.getUserId())
21+
.emailEnabled(notificationSetting.isEmailEnabled())
22+
.scheduleReminder(notificationSetting.isScheduleReminder())
23+
.paymentReminder(notificationSetting.isPaymentReminder())
24+
.checklistReminder(notificationSetting.isChecklistReminder())
25+
.sseEnabled(notificationSetting.isSseEnabled())
26+
.createdAt(notificationSetting.getCreatedAt())
27+
.build();
28+
}
29+
}

src/main/java/store/lastdance/domain/notification/NotificationSetting.java

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,21 @@ public class NotificationSetting {
2020
@Column(name = "user_id", unique = true, nullable = false)
2121
private UUID userId;
2222

23-
@Column(name = "email_enabled")
24-
private Boolean emailEnabled = true;
23+
@Getter
24+
@Column(name = "email_enabled", nullable = false)
25+
private boolean emailEnabled = false;
2526

26-
@Column(name = "schedule_reminder")
27-
private Boolean scheduleReminder = true;
27+
@Column(name = "schedule_reminder", nullable = false)
28+
private boolean scheduleReminder = false;
2829

29-
@Column(name = "payment_reminder")
30-
private Boolean paymentReminder = true;
30+
@Column(name = "payment_reminder", nullable = false)
31+
private boolean paymentReminder = false;
3132

32-
@Column(name = "checklist_reminder")
33-
private Boolean checklistReminder = true;
33+
@Column(name = "checklist_reminder", nullable = false)
34+
private boolean checklistReminder = false;
3435

35-
// SSE 연결 상태
36-
@Column(name = "sse_enabled")
37-
private Boolean sseEnabled = true;
38-
36+
@Column(name = "sse_enabled", nullable = false)
37+
private boolean sseEnabled = false;
3938

4039
@Column(name = "created_at")
4140
private LocalDateTime createdAt = LocalDateTime.now();
@@ -47,52 +46,34 @@ public class NotificationSetting {
4746
@Builder
4847
public NotificationSetting(@NonNull UUID userId) {
4948
this.userId = userId;
50-
this.emailEnabled = true;
51-
this.scheduleReminder = true;
52-
this.paymentReminder = true;
53-
this.checklistReminder = true;
5449
}
5550

56-
public void updateEmailEnabled(Boolean emailEnabled) {
51+
public void updateEmailEnabled(boolean emailEnabled) {
5752
this.emailEnabled = emailEnabled;
5853
}
5954

60-
public void updateScheduleReminder(Boolean scheduleReminder) {
55+
public void updateScheduleReminder(boolean scheduleReminder) {
6156
this.scheduleReminder = scheduleReminder;
6257
}
6358

64-
public void updatePaymentReminder(Boolean paymentReminder) {
59+
public void updatePaymentReminder(boolean paymentReminder) {
6560
this.paymentReminder = paymentReminder;
6661
}
6762

68-
public void updateChecklistReminder(Boolean checklistReminder) {
63+
public void updateChecklistReminder(boolean checklistReminder) {
6964
this.checklistReminder = checklistReminder;
7065
}
7166

72-
67+
public void updateSSEEnabled(boolean sseEnabled) { this.sseEnabled = sseEnabled; }
7368

74-
public void updateSSEEnabled(Boolean sseEnabled) {
75-
this.sseEnabled = sseEnabled;
76-
// SSE 비활성화시 연결 상태도 초기화
77-
// 이 곳에 오프라인 처리가 필요하다면, 이벤트를 발행하거나
78-
// ApplicationContext를 통해 OnlineStatusService를 직접 호출해야 합니다.
79-
// 현재 구조에서는 엔티티가 서비스에 직접 의존하지 않는 것이 좋으므로,
80-
// 이 로직은 서비스를 사용하는 상위 계층으로 이동하는 것을 권장합니다.
81-
}
82-
83-
// 유틸리티 메서드들
8469
public boolean isNotificationEnabled(NotificationType type) {
8570
return switch (type) {
86-
case SCHEDULE -> scheduleReminder != null && scheduleReminder;
87-
case PAYMENT -> paymentReminder != null && paymentReminder;
88-
case CHECKLIST -> checklistReminder != null && checklistReminder;
71+
case SCHEDULE -> scheduleReminder;
72+
case PAYMENT -> paymentReminder;
73+
case CHECKLIST -> checklistReminder;
8974
};
9075
}
9176

92-
public boolean isEmailEnabled() {
93-
return emailEnabled != null && emailEnabled;
94-
}
95-
9677
public boolean isEmailEnabledForType(NotificationType type) {
9778
return isEmailEnabled() && isNotificationEnabled(type);
9879
}

src/main/java/store/lastdance/exception/ErrorCode.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.Getter;
44
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
56
import org.springframework.http.HttpStatus;
67
import store.lastdance.dto.community.comment.CommentResponseDTO;
78

@@ -106,7 +107,14 @@ public enum ErrorCode {
106107
CALENDAR_INVALID_REPEAT_DATE_ORDER("반복 종료일은 일정 시작일보다 이후여야 합니다.", HttpStatus.BAD_REQUEST),
107108
CALENDAR_REPEAT_REQUIRED("반복 타입은 필수입니다.", HttpStatus.BAD_REQUEST),
108109
CALENDAR_DATE_REQUIRED("시작날짜와 종료날짜를 입력해주세요.", HttpStatus.BAD_REQUEST),
109-
INVALID_DATE_ORDER("시작날짜는 종료날짜보다 앞에 있어야 합니다.", HttpStatus.BAD_REQUEST);
110+
INVALID_DATE_ORDER("시작날짜는 종료날짜보다 앞에 있어야 합니다.", HttpStatus.BAD_REQUEST),
111+
112+
//알림 관련
113+
NOTIFICATION_SETTING_CREATE_FAILED("알림 설정 생성에 실패했습니다", HttpStatus.INTERNAL_SERVER_ERROR),
114+
NOTIFICATION_SETTING_FOUND_FAILED("알림 설정 조회에 실패했습니다", HttpStatus.INTERNAL_SERVER_ERROR),
115+
NOTIFICATION_SETTING_UPDATE_FAILED("알림 설정 수정에 실패했습니다", HttpStatus.INTERNAL_SERVER_ERROR),
116+
NOTIFICATION_SETTING_NOT_FOUND("알림 설정을 찾을 수 없습니다.", HttpStatus.NOT_FOUND),
117+
NOTIFICATION_SETTING_ALREADY_EXISTS("사용자의 알림 설정이 이미 존재합니다", HttpStatus.CONFLICT);
110118

111119
private final String message;
112120
private final HttpStatus httpStatus;

src/main/java/store/lastdance/service/notification/NotificationSettingServiceImpl.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ public NotificationSettingResponseDTO getUserSetting(UUID userId) {
4444
return NotificationSettingResponseDTO.builder()
4545
.settingId(setting.getSettingId())
4646
.userId(setting.getUserId())
47-
.emailEnabled(setting.getEmailEnabled() != null ? setting.getEmailEnabled() : true)
48-
.scheduleReminder(setting.getScheduleReminder() != null ? setting.getScheduleReminder() : true)
49-
.paymentReminder(setting.getPaymentReminder() != null ? setting.getPaymentReminder() : true)
50-
.checklistReminder(setting.getChecklistReminder() != null ? setting.getChecklistReminder() : true)
51-
.sseEnabled(setting.getSseEnabled() != null ? setting.getSseEnabled() : true)
47+
.emailEnabled(setting.isEmailEnabled())
48+
.scheduleReminder(setting.isScheduleReminder())
49+
.paymentReminder(setting.isPaymentReminder())
50+
.checklistReminder(setting.isChecklistReminder())
51+
.sseEnabled(setting.isSseEnabled())
5252
.createdAt(setting.getCreatedAt())
5353
.build();
5454
}
@@ -98,10 +98,10 @@ public void createDefaultSetting(UUID userId) {
9898
settingRepository.save(defaultSetting);
9999
log.info("사용자 기본 알림 설정 생성 완료: userId={}, emailEnabled={}, scheduleReminder={}, paymentReminder={}, checklistReminder={}",
100100
userId,
101-
defaultSetting.getEmailEnabled(),
102-
defaultSetting.getScheduleReminder(),
103-
defaultSetting.getPaymentReminder(),
104-
defaultSetting.getChecklistReminder());
101+
defaultSetting.isEmailEnabled(),
102+
defaultSetting.isScheduleReminder(),
103+
defaultSetting.isPaymentReminder(),
104+
defaultSetting.isChecklistReminder());
105105
} catch (Exception e) {
106106
log.error("사용자 기본 알림 설정 생성 실패: userId={}, error={}", userId, e.getMessage(), e);
107107
throw e;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package store.lastdance.service.notification;
2+
3+
import store.lastdance.domain.user.User;
4+
import store.lastdance.dto.notification.NotificationSettingRequestDTO;
5+
import store.lastdance.dto.notification.NotificationSettingResponseDTO;
6+
7+
import java.util.List;
8+
import java.util.UUID;
9+
10+
public interface NotificationSettingV2Service {
11+
NotificationSettingResponseDTO getUserSetting(UUID userId);
12+
NotificationSettingResponseDTO updateSetting(UUID userId, NotificationSettingRequestDTO request);
13+
14+
void createDefaultSetting(UUID userId);
15+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package store.lastdance.service.notification;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.dao.DataIntegrityViolationException;
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
8+
import store.lastdance.converter.notification.NotificationSettingConverter;
9+
import store.lastdance.domain.notification.NotificationSetting;
10+
import store.lastdance.dto.notification.NotificationSettingRequestDTO;
11+
import store.lastdance.dto.notification.NotificationSettingResponseDTO;
12+
import store.lastdance.exception.CustomException;
13+
import store.lastdance.exception.ErrorCode;
14+
import store.lastdance.repository.notification.NotificationSettingRepository;
15+
16+
import java.util.UUID;
17+
18+
@Service
19+
@RequiredArgsConstructor
20+
@Slf4j
21+
@Transactional
22+
public class NotificationSettingV2ServiceImpl implements NotificationSettingV2Service {
23+
24+
private final NotificationSettingRepository settingRepository;
25+
private final NotificationSettingConverter notificationSettingConverter;
26+
27+
@Override
28+
public NotificationSettingResponseDTO getUserSetting(UUID userId) {
29+
try{
30+
NotificationSetting setting = settingRepository.findByUserId(userId)
31+
.orElseGet(() -> settingRepository.save(
32+
notificationSettingConverter.toEntity(userId)));
33+
34+
return notificationSettingConverter.toDto(setting);
35+
} catch (CustomException ce) {
36+
throw ce;
37+
} catch (Exception e) {
38+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_UPDATE_FAILED);
39+
}
40+
}
41+
42+
@Override
43+
public NotificationSettingResponseDTO updateSetting(UUID userId, NotificationSettingRequestDTO request) {
44+
try{
45+
NotificationSetting setting = settingRepository.findByUserId(userId) .orElseThrow(() -> new CustomException(ErrorCode.NOTIFICATION_SETTING_NOT_FOUND));
46+
47+
boolean updated = false;
48+
if (request.getEmailEnabled() != null) {
49+
setting.updateEmailEnabled(request.getEmailEnabled());
50+
updated = true;
51+
}
52+
if (request.getScheduleReminder() != null) {
53+
setting.updateScheduleReminder(request.getScheduleReminder());
54+
updated = true;
55+
}
56+
if (request.getPaymentReminder() != null) {
57+
setting.updatePaymentReminder(request.getPaymentReminder());
58+
updated = true;
59+
}
60+
if (request.getChecklistReminder() != null) {
61+
setting.updateChecklistReminder(request.getChecklistReminder());
62+
updated = true;
63+
}
64+
if (request.getSseEnabled() != null) {
65+
setting.updateSSEEnabled(request.getSseEnabled());
66+
updated = true;
67+
}
68+
69+
if (updated) {
70+
settingRepository.save(setting);
71+
}
72+
return notificationSettingConverter.toDto(setting);
73+
} catch (CustomException ce) {
74+
throw ce;
75+
} catch (Exception e) {
76+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_UPDATE_FAILED);
77+
}
78+
}
79+
80+
@Override
81+
public void createDefaultSetting(UUID userId) {
82+
try {
83+
settingRepository.save(notificationSettingConverter.toEntity(userId));
84+
} catch (DataIntegrityViolationException e) {
85+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_ALREADY_EXISTS);
86+
} catch (Exception e) {
87+
throw new CustomException(ErrorCode.NOTIFICATION_SETTING_CREATE_FAILED);
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)