1+ package com .back .domain .notification .controller ;
2+
3+ import com .back .domain .notification .dto .NotificationCreateRequest ;
4+ import com .back .domain .notification .dto .NotificationResponse ;
5+ import com .back .domain .notification .dto .NotificationListResponse ;
6+ import com .back .domain .notification .entity .Notification ;
7+ import com .back .domain .notification .service .NotificationService ;
8+ import com .back .domain .studyroom .entity .Room ;
9+ import com .back .domain .studyroom .repository .RoomRepository ;
10+ import com .back .domain .user .entity .User ;
11+ import com .back .domain .user .repository .UserRepository ;
12+ import com .back .global .common .dto .RsData ;
13+ import com .back .global .exception .CustomException ;
14+ import com .back .global .exception .ErrorCode ;
15+ import com .back .global .security .user .CustomUserDetails ;
16+ import io .swagger .v3 .oas .annotations .Operation ;
17+ import io .swagger .v3 .oas .annotations .Parameter ;
18+ import io .swagger .v3 .oas .annotations .tags .Tag ;
19+ import lombok .RequiredArgsConstructor ;
20+ import lombok .extern .slf4j .Slf4j ;
21+ import org .springframework .data .domain .Page ;
22+ import org .springframework .data .domain .PageRequest ;
23+ import org .springframework .data .domain .Pageable ;
24+ import org .springframework .http .ResponseEntity ;
25+ import org .springframework .security .core .annotation .AuthenticationPrincipal ;
26+ import org .springframework .web .bind .annotation .*;
27+
28+ @ Slf4j
29+ @ RestController
30+ @ RequiredArgsConstructor
31+ @ RequestMapping ("/api/notifications" )
32+ @ Tag (name = "알림" , description = "알림 관련 API" )
33+ public class NotificationController {
34+
35+ private final NotificationService notificationService ;
36+ private final UserRepository userRepository ;
37+ private final RoomRepository roomRepository ;
38+
39+ @ Operation (summary = "알림 전송" , description = "USER/ROOM/COMMUNITY/SYSTEM 타입별 알림 생성 및 전송" )
40+ @ PostMapping
41+ public ResponseEntity <RsData <NotificationResponse >> createNotification (
42+ @ Parameter (hidden = true ) @ AuthenticationPrincipal CustomUserDetails userDetails ,
43+ @ RequestBody NotificationCreateRequest request ) {
44+
45+ log .info ("알림 전송 요청 - 타입: {}, 제목: {}" , request .targetType (), request .title ());
46+
47+ Notification notification = switch (request .targetType ()) {
48+ case "USER" -> {
49+ User targetUser = userRepository .findById (request .targetId ())
50+ .orElseThrow (() -> new CustomException (ErrorCode .USER_NOT_FOUND ));
51+ yield notificationService .createPersonalNotification (
52+ targetUser ,
53+ request .title (),
54+ request .message (),
55+ request .redirectUrl ()
56+ );
57+ }
58+ case "ROOM" -> {
59+ Room room = roomRepository .findById (request .targetId ())
60+ .orElseThrow (() -> new CustomException (ErrorCode .ROOM_NOT_FOUND ));
61+ yield notificationService .createRoomNotification (
62+ room ,
63+ request .title (),
64+ request .message (),
65+ request .redirectUrl ()
66+ );
67+ }
68+ case "COMMUNITY" -> {
69+ User targetUser = userRepository .findById (request .targetId ())
70+ .orElseThrow (() -> new CustomException (ErrorCode .USER_NOT_FOUND ));
71+ yield notificationService .createCommunityNotification (
72+ targetUser ,
73+ request .title (),
74+ request .message (),
75+ request .redirectUrl ()
76+ );
77+ }
78+ case "SYSTEM" -> {
79+ yield notificationService .createSystemNotification (
80+ request .title (),
81+ request .message (),
82+ request .redirectUrl ()
83+ );
84+ }
85+ default -> throw new IllegalArgumentException ("유효하지 않은 알림 타입입니다: " + request .targetType ());
86+ };
87+
88+ NotificationResponse response = NotificationResponse .from (notification );
89+
90+ return ResponseEntity .ok (RsData .success ("알림 전송 성공" , response ));
91+ }
92+
93+ @ Operation (summary = "알림 목록 조회" , description = "사용자의 알림 목록 조회 (페이징)" )
94+ @ GetMapping
95+ public ResponseEntity <RsData <NotificationListResponse >> getNotifications (
96+ @ Parameter (hidden = true ) @ AuthenticationPrincipal CustomUserDetails userDetails ,
97+ @ Parameter (description = "페이지 번호 (0부터 시작)" ) @ RequestParam (defaultValue = "0" ) int page ,
98+ @ Parameter (description = "페이지 크기" ) @ RequestParam (defaultValue = "20" ) int size ,
99+ @ Parameter (description = "읽지 않은 알림만 조회" ) @ RequestParam (defaultValue = "false" ) boolean unreadOnly ) {
100+
101+ log .info ("알림 목록 조회 - 유저 ID: {}, 읽지 않은 것만: {}" , userDetails .getUserId (), unreadOnly );
102+
103+ Pageable pageable = PageRequest .of (page , size );
104+ Page <Notification > notifications ;
105+
106+ if (unreadOnly ) {
107+ notifications = notificationService .getUnreadNotifications (userDetails .getUserId (), pageable );
108+ } else {
109+ notifications = notificationService .getUserNotifications (userDetails .getUserId (), pageable );
110+ }
111+
112+ long unreadCount = notificationService .getUnreadCount (userDetails .getUserId ());
113+
114+ NotificationListResponse response = NotificationListResponse .from (
115+ notifications ,
116+ userDetails .getUserId (),
117+ unreadCount ,
118+ notificationService
119+ );
120+
121+ return ResponseEntity .ok (RsData .success ("알림 목록 조회 성공" , response ));
122+ }
123+
124+ @ Operation (summary = "알림 읽음 처리" , description = "특정 알림을 읽음 상태로 변경" )
125+ @ PutMapping ("/{notificationId}/read" )
126+ public ResponseEntity <RsData <NotificationResponse >> markAsRead (
127+ @ Parameter (hidden = true ) @ AuthenticationPrincipal CustomUserDetails userDetails ,
128+ @ Parameter (description = "알림 ID" ) @ PathVariable Long notificationId ) {
129+
130+ log .info ("알림 읽음 처리 - 알림 ID: {}, 유저 ID: {}" , notificationId , userDetails .getUserId ());
131+
132+ User user = userRepository .findById (userDetails .getUserId ())
133+ .orElseThrow (() -> new CustomException (ErrorCode .USER_NOT_FOUND ));
134+
135+ notificationService .markAsRead (notificationId , user );
136+
137+ Notification notification = notificationService .getNotification (notificationId );
138+ NotificationResponse response = NotificationResponse .from (notification );
139+
140+ return ResponseEntity .ok (RsData .success ("알림 읽음 처리 성공" , response ));
141+ }
142+
143+ @ Operation (summary = "모든 알림 읽음 처리" , description = "사용자의 읽지 않은 모든 알림을 읽음 상태로 변경" )
144+ @ PutMapping ("/read-all" )
145+ public ResponseEntity <RsData <Void >> markAllAsRead (
146+ @ Parameter (hidden = true ) @ AuthenticationPrincipal CustomUserDetails userDetails ) {
147+
148+ log .info ("전체 알림 읽음 처리 - 유저 ID: {}" , userDetails .getUserId ());
149+
150+ User user = userRepository .findById (userDetails .getUserId ())
151+ .orElseThrow (() -> new CustomException (ErrorCode .USER_NOT_FOUND ));
152+
153+ notificationService .markMultipleAsRead (userDetails .getUserId (), user );
154+
155+ return ResponseEntity .ok (RsData .success ("전체 알림 읽음 처리 성공" ));
156+ }
157+ }
0 commit comments