Skip to content

Commit 2961ccf

Browse files
authored
Merge pull request #20 from 9roomMoa/feat/#19
feat: 알림 읽음 처리 api
2 parents f6fe914 + c77dd89 commit 2961ccf

5 files changed

Lines changed: 95 additions & 7 deletions

File tree

src/main/java/com/groommoa/aether_back_notification/domain/notifications/controller/NotificationController.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.groommoa.aether_back_notification.domain.notifications.controller;
22

3-
import com.groommoa.aether_back_notification.domain.notifications.dto.CreateNotificationRequestDto;
4-
import com.groommoa.aether_back_notification.domain.notifications.dto.CreateNotificationResponseDto;
5-
import com.groommoa.aether_back_notification.domain.notifications.dto.NotificationPageResponseDto;
6-
import com.groommoa.aether_back_notification.domain.notifications.dto.NotificationResponseDto;
3+
import com.groommoa.aether_back_notification.domain.notifications.dto.*;
74
import com.groommoa.aether_back_notification.domain.notifications.entity.Notification;
85
import com.groommoa.aether_back_notification.domain.notifications.service.NotificationService;
96
import com.groommoa.aether_back_notification.infrastructure.sse.service.SseService;
@@ -16,12 +13,16 @@
1613
import jakarta.validation.constraints.Min;
1714
import lombok.RequiredArgsConstructor;
1815
import lombok.extern.slf4j.Slf4j;
16+
import org.bson.types.ObjectId;
1917
import org.springframework.http.MediaType;
2018
import org.springframework.http.ResponseEntity;
2119
import org.springframework.security.core.annotation.AuthenticationPrincipal;
2220
import org.springframework.web.bind.annotation.*;
2321
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
2422

23+
import java.util.List;
24+
import java.util.Map;
25+
2526
@Slf4j
2627
@RequestMapping("/notifications")
2728
@RequiredArgsConstructor
@@ -74,4 +75,19 @@ public SseEmitter subscribe(
7475

7576
return sseService.subscribe(userId, lastEventId);
7677
}
78+
79+
@PatchMapping("/read")
80+
public ResponseEntity<CommonResponse> markNotificationsAsRead(
81+
@AuthenticationPrincipal Claims claims,
82+
@Valid @RequestBody ReadNotificationsRequestDto request
83+
) {
84+
String userId = claims.getSubject();
85+
ReadNotificationResponseDto responseDto = notificationService.markNotificationsAsRead(userId, request);
86+
87+
CommonResponse response = new CommonResponse(
88+
HttpStatus.OK, "알림 읽음 요청이 처리되었습니다.", DtoUtils.toMap(responseDto)
89+
);
90+
91+
return ResponseEntity.ok(response);
92+
}
7793
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.groommoa.aether_back_notification.domain.notifications.dto;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
import java.util.List;
7+
8+
@RequiredArgsConstructor
9+
@Getter
10+
public class ReadNotificationResponseDto {
11+
12+
private final List<String> updatedIds;
13+
private final List<String> alreadyReadIds;
14+
private final List<String> notFoundIds;
15+
private final List<String> accessDeniedIds;
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.groommoa.aether_back_notification.domain.notifications.dto;
2+
3+
import jakarta.validation.constraints.NotEmpty;
4+
import jakarta.validation.constraints.Size;
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
import java.util.List;
9+
10+
@RequiredArgsConstructor
11+
@Getter
12+
public class ReadNotificationsRequestDto {
13+
14+
@NotEmpty(message="알림 ID 목록은 비어 있을 수 없습니다.")
15+
@Size(max=100, message="한번에 최대 100개의 알림한 처리할 수 있습니다.")
16+
private final List<String> notificationIds;
17+
}

src/main/java/com/groommoa/aether_back_notification/domain/notifications/entity/Notification.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
import com.groommoa.aether_back_notification.domain.notifications.common.NoticeType;
44
import lombok.Builder;
55
import lombok.Getter;
6+
import lombok.Setter;
67
import org.bson.types.ObjectId;
78
import org.springframework.data.annotation.CreatedDate;
89
import org.springframework.data.annotation.Id;
910
import org.springframework.data.annotation.LastModifiedDate;
1011
import org.springframework.data.mongodb.core.mapping.Document;
12+
import org.springframework.data.mongodb.core.mapping.Field;
1113

1214
import java.time.Instant;
1315

1416
@Document(collection = "notifications")
1517
@Builder
1618
@Getter
19+
@Setter
1720
public class Notification {
1821

1922
@Id
@@ -33,6 +36,7 @@ public class Notification {
3336
private RelatedContent relatedContent;
3437

3538
@Builder.Default
39+
@Field("isRead")
3640
private boolean isRead = false;
3741

3842
@CreatedDate

src/main/java/com/groommoa/aether_back_notification/domain/notifications/service/NotificationService.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.groommoa.aether_back_notification.domain.notifications.service;
22

3-
import com.groommoa.aether_back_notification.domain.notifications.dto.CreateNotificationRequestDto;
4-
import com.groommoa.aether_back_notification.domain.notifications.dto.NotificationPageResponseDto;
5-
import com.groommoa.aether_back_notification.domain.notifications.dto.NotificationResponseDto;
3+
import com.groommoa.aether_back_notification.domain.notifications.dto.*;
64
import com.groommoa.aether_back_notification.domain.notifications.entity.Notification;
75
import com.groommoa.aether_back_notification.domain.notifications.entity.RelatedContent;
86
import com.groommoa.aether_back_notification.domain.notifications.repository.NotificationRepository;
@@ -16,8 +14,11 @@
1614
import org.springframework.stereotype.Service;
1715
import org.springframework.transaction.annotation.Transactional;
1816

17+
import java.util.ArrayList;
1918
import java.util.List;
19+
import java.util.Optional;
2020

21+
@Slf4j
2122
@RequiredArgsConstructor
2223
@Service
2324
public class NotificationService {
@@ -76,4 +77,38 @@ public Notification createNotification(CreateNotificationRequestDto request) {
7677

7778
return notificationRepository.save(notification);
7879
}
80+
81+
@Transactional
82+
public ReadNotificationResponseDto markNotificationsAsRead(String userId, ReadNotificationsRequestDto request){
83+
List<String> updatedIds = new ArrayList<>();
84+
List<String> alreadyReadIds = new ArrayList<>();
85+
List<String> notFoundIds = new ArrayList<>();
86+
List<String> accessDeniedIds = new ArrayList<>();
87+
88+
List<String> notificationIds = request.getNotificationIds();
89+
for (String id : notificationIds) {
90+
Optional<Notification> optionalNotification = notificationRepository.findById(id);
91+
if (optionalNotification.isEmpty()){
92+
notFoundIds.add(id);
93+
continue;
94+
}
95+
Notification notification = optionalNotification.get();
96+
97+
// 읽음 요청한 유저 id와 대상 알림의 수신자(receiver) id가 서로 일치하는지 검사
98+
if (!notification.getReceiver().toHexString().equals(userId)) {
99+
accessDeniedIds.add(id);
100+
continue;
101+
}
102+
103+
if (!notification.isRead()){
104+
notification.setRead(true);
105+
notificationRepository.save(notification);
106+
107+
updatedIds.add(id);
108+
} else {
109+
alreadyReadIds.add(id);
110+
}
111+
}
112+
return new ReadNotificationResponseDto(updatedIds, alreadyReadIds, notFoundIds, accessDeniedIds);
113+
}
79114
}

0 commit comments

Comments
 (0)