Skip to content

Commit 2899f43

Browse files
authored
Merge pull request #189 from TaskFlow-CLAP/CLAP-190
CLAP-190 푸시 알림 활성/비활성화 API 구현 및 알림 생성 logic 메소드별로 추가
2 parents 86debdd + 418f8be commit 2899f43

File tree

12 files changed

+235
-49
lines changed

12 files changed

+235
-49
lines changed

src/main/java/clap/server/adapter/inbound/web/notification/ManagementNotificationController.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package clap.server.adapter.inbound.web.notification;
22

33
import clap.server.adapter.inbound.security.SecurityUserDetails;
4+
import clap.server.application.port.inbound.notification.EnableAgitUsecase;
5+
import clap.server.application.port.inbound.notification.EnableEmailUsecase;
6+
import clap.server.application.port.inbound.notification.EnableKakaoUsecase;
47
import clap.server.application.port.inbound.notification.UpdateNotificationUsecase;
58
import clap.server.common.annotation.architecture.WebAdapter;
69
import io.swagger.v3.oas.annotations.Operation;
@@ -22,17 +25,39 @@
2225
public class ManagementNotificationController {
2326

2427
private final UpdateNotificationUsecase updateNotificationUsecase;
28+
private final EnableKakaoUsecase enableKakaoUsecase;
29+
private final EnableAgitUsecase enableAgitUsecase;
30+
private final EnableEmailUsecase enableEmailUsecase;
2531

2632
@Operation(summary = "알림 목록에서 한 개 눌렀을 때 읽음 처리")
2733
@Parameter(name = "notificationId", description = "알림 고유 ID", required = true, in = ParameterIn.PATH)
2834
@PatchMapping("/{notificationId}")
29-
public void updateNotificationIsRead(@PathVariable Long notificationId) {
30-
updateNotificationUsecase.updateNotification(notificationId);
35+
public void updateNotificationIsRead(@AuthenticationPrincipal SecurityUserDetails userInfo,
36+
@PathVariable Long notificationId) {
37+
updateNotificationUsecase.updateNotification(userInfo.getUserId(), notificationId);
3138
}
3239

3340
@Operation(summary = "알림 목록에서 전체 읽음 버튼을 눌렀을 때 전체 읽음 처리")
3441
@PatchMapping
3542
public void updateAllNotificationIsRead(@AuthenticationPrincipal SecurityUserDetails userInfo) {
3643
updateNotificationUsecase.updateAllNotification(userInfo.getUserId());
3744
}
45+
46+
@Operation(summary = "카카오 푸시 알림 활성화/비활성화 API", description = "알림 거부였을 시 -> 승인으로 변경, 알림 승인이였을 시 -> 거부로 변경")
47+
@PatchMapping("/kakao")
48+
public void enableKaKaoWork(@AuthenticationPrincipal SecurityUserDetails userInfo) {
49+
enableKakaoUsecase.enableKakao(userInfo.getUserId());
50+
}
51+
52+
@Operation(summary = "아지트 푸시 알림 활성화/비활성화 API", description = "알림 거부였을 시 -> 승인으로 변경, 알림 승인이였을 시 -> 거부로 변경")
53+
@PatchMapping("/agit")
54+
public void enableAgit(@AuthenticationPrincipal SecurityUserDetails userInfo) {
55+
enableAgitUsecase.enableAgit(userInfo.getUserId());
56+
}
57+
58+
@Operation(summary = "이메일 푸시 알림 활성화/비활성화 API", description = "알림 거부였을 시 -> 승인으로 변경, 알림 승인이였을 시 -> 거부로 변경")
59+
@PatchMapping("/email")
60+
public void enableEmail(@AuthenticationPrincipal SecurityUserDetails userInfo) {
61+
enableEmailUsecase.enableEmail(userInfo.getUserId());
62+
}
3863
}

src/main/java/clap/server/adapter/outbound/persistense/entity/member/MemberEntity.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,14 @@ public class MemberEntity extends BaseTimeEntity {
5252
@Column
5353
private String imageUrl;
5454

55-
@Column
56-
private Boolean notificationEnabled;
55+
@Column(name = "kakaowork_notification_enabled")
56+
private Boolean kakaoworkNotificationEnabled = Boolean.TRUE;;
57+
58+
@Column(name = "agit_notification_enabled")
59+
private Boolean agitNotificationEnabled = Boolean.TRUE;;
60+
61+
@Column(name = "email_notification_enabled")
62+
private Boolean emailNotificationEnabled = Boolean.TRUE;;
5763

5864
@ManyToOne(fetch = FetchType.LAZY)
5965
@JoinColumn(name = "admin_id")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package clap.server.application.port.inbound.notification;
2+
3+
public interface EnableAgitUsecase {
4+
5+
void enableAgit(Long userId);
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package clap.server.application.port.inbound.notification;
2+
3+
public interface EnableEmailUsecase {
4+
5+
void enableEmail(Long userId);
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package clap.server.application.port.inbound.notification;
2+
3+
public interface EnableKakaoUsecase {
4+
5+
void enableKakao(Long userId);
6+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package clap.server.application.port.inbound.notification;
22

33
public interface UpdateNotificationUsecase {
4-
void updateNotification(Long notificationId);
4+
void updateNotification(Long userId, Long notificationId);
55

66
void updateAllNotification(Long memberId);
77
}

src/main/java/clap/server/application/service/notification/ReadNotificationService.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package clap.server.application.service.notification;
22

3+
import clap.server.application.port.inbound.domain.MemberService;
34
import clap.server.application.port.inbound.notification.UpdateNotificationUsecase;
45
import clap.server.application.port.outbound.notification.CommandNotificationPort;
56
import clap.server.application.port.outbound.notification.LoadNotificationPort;
@@ -16,13 +17,16 @@
1617
@RequiredArgsConstructor
1718
public class ReadNotificationService implements UpdateNotificationUsecase {
1819

20+
private final MemberService memberService;
1921
private final LoadNotificationPort loadNotificationPort;
2022
private final CommandNotificationPort commandNotificationPort;
2123

2224

2325
@Transactional
2426
@Override
25-
public void updateNotification(Long notificationId) {
27+
public void updateNotification(Long userId, Long notificationId) {
28+
29+
memberService.findActiveMember(userId);
2630
Notification notification = loadNotificationPort.findById(notificationId)
2731
.orElseThrow(() -> new ApplicationException(NotificationErrorCode.NOTIFICATION_NOT_FOUND));
2832
notification.updateNotificationIsRead();
@@ -32,6 +36,7 @@ public void updateNotification(Long notificationId) {
3236
@Transactional
3337
@Override
3438
public void updateAllNotification(Long memberId) {
39+
memberService.findActiveMember(memberId);
3540
List<Notification> notificationList = loadNotificationPort.findNotificationsByMemberId(memberId);
3641
for (Notification notification : notificationList) {
3742
notification.updateNotificationIsRead();
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package clap.server.application.service.notification;
2+
3+
import clap.server.adapter.outbound.api.dto.SendAgitRequest;
4+
import clap.server.adapter.outbound.api.dto.SendKakaoWorkRequest;
5+
import clap.server.adapter.outbound.api.dto.SendWebhookRequest;
6+
import clap.server.adapter.outbound.persistense.entity.notification.constant.NotificationType;
7+
import clap.server.common.annotation.architecture.ApplicationService;
8+
import clap.server.domain.model.member.Member;
9+
import clap.server.domain.model.task.Task;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.context.ApplicationEventPublisher;
12+
13+
@ApplicationService
14+
@RequiredArgsConstructor
15+
public class SendWebhookService {
16+
17+
private final ApplicationEventPublisher applicationEventPublisher;
18+
19+
public void sendWebhookNotification(Member receiver, NotificationType notificationType,
20+
Task task, String message, String commenterName) {
21+
// 공통 데이터
22+
String email = receiver.getMemberInfo().getEmail();
23+
String taskTitle = task.getTitle();
24+
String requesterNickname = task.getRequester().getNickname();
25+
26+
// 이메일 전송
27+
if (receiver.getEmailNotificationEnabled()) {
28+
SendWebhookRequest sendWebhookRequest = new SendWebhookRequest(
29+
email, notificationType, taskTitle, requesterNickname, message, commenterName
30+
);
31+
applicationEventPublisher.publishEvent(sendWebhookRequest);
32+
}
33+
34+
// 카카오워크 전송
35+
if (receiver.getKakaoworkNotificationEnabled()) {
36+
SendKakaoWorkRequest sendKakaoWorkRequest = new SendKakaoWorkRequest(
37+
email, notificationType, taskTitle, requesterNickname, message, commenterName
38+
);
39+
applicationEventPublisher.publishEvent(sendKakaoWorkRequest);
40+
}
41+
42+
// 아지트 전송
43+
if (receiver.getAgitNotificationEnabled()) {
44+
SendAgitRequest sendAgitRequest = new SendAgitRequest(
45+
email, notificationType, taskTitle, requesterNickname, message, commenterName
46+
);
47+
applicationEventPublisher.publishEvent(sendAgitRequest);
48+
}
49+
}
50+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package clap.server.application.service.notification;
2+
3+
import clap.server.application.port.inbound.domain.MemberService;
4+
import clap.server.application.port.inbound.notification.EnableAgitUsecase;
5+
import clap.server.application.port.inbound.notification.EnableEmailUsecase;
6+
import clap.server.application.port.inbound.notification.EnableKakaoUsecase;
7+
import clap.server.application.port.outbound.member.CommandMemberPort;
8+
import clap.server.common.annotation.architecture.ApplicationService;
9+
import clap.server.domain.model.member.Member;
10+
import lombok.RequiredArgsConstructor;
11+
12+
@ApplicationService
13+
@RequiredArgsConstructor
14+
public class UpdateNotificationService implements EnableKakaoUsecase, EnableAgitUsecase, EnableEmailUsecase {
15+
16+
private final MemberService memberService;
17+
private final CommandMemberPort commandMemberPort;
18+
19+
@Override
20+
public void enableAgit(Long userId) {
21+
Member member = memberService.findActiveMember(userId);
22+
member.updateAgitEnabled();
23+
commandMemberPort.save(member);
24+
}
25+
26+
@Override
27+
public void enableEmail(Long userId) {
28+
Member member = memberService.findActiveMember(userId);
29+
member.updateEmailEnabled();
30+
commandMemberPort.save(member);
31+
}
32+
33+
@Override
34+
public void enableKakao(Long userId) {
35+
Member member = memberService.findActiveMember(userId);
36+
member.updateKaKaoEnabled();
37+
commandMemberPort.save(member);
38+
}
39+
}

src/main/java/clap/server/application/service/task/ApprovalTaskService.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package clap.server.application.service.task;
22

3+
import clap.server.adapter.inbound.web.dto.notification.SseRequest;
34
import clap.server.adapter.inbound.web.dto.task.ApprovalTaskRequest;
45
import clap.server.adapter.inbound.web.dto.task.ApprovalTaskResponse;
56
import clap.server.adapter.inbound.web.dto.task.FindApprovalFormResponse;
7+
import clap.server.adapter.outbound.persistense.entity.notification.constant.NotificationType;
68
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskHistoryType;
79
import clap.server.application.mapper.TaskMapper;
810
import clap.server.application.port.inbound.domain.CategoryService;
@@ -12,15 +14,23 @@
1214
import clap.server.application.port.inbound.task.ApprovalTaskUsecase;
1315
import clap.server.application.port.outbound.task.CommandTaskPort;
1416
import clap.server.application.port.outbound.taskhistory.CommandTaskHistoryPort;
17+
import clap.server.application.service.notification.SendWebhookService;
1518
import clap.server.common.annotation.architecture.ApplicationService;
1619
import clap.server.domain.model.member.Member;
20+
import clap.server.domain.model.notification.Notification;
1721
import clap.server.domain.model.task.Category;
1822
import clap.server.domain.model.task.Label;
1923
import clap.server.domain.model.task.Task;
2024
import clap.server.domain.model.task.TaskHistory;
2125
import lombok.RequiredArgsConstructor;
26+
import org.springframework.context.ApplicationEventPublisher;
2227
import org.springframework.transaction.annotation.Transactional;
2328

29+
import java.util.ArrayList;
30+
import java.util.List;
31+
32+
import static clap.server.domain.model.notification.Notification.createTaskNotification;
33+
2434
@ApplicationService
2535
@RequiredArgsConstructor
2636
@Transactional(readOnly = true)
@@ -32,6 +42,8 @@ public class ApprovalTaskService implements ApprovalTaskUsecase {
3242
private final LabelService labelService;
3343
private final CommandTaskPort commandTaskPort;
3444
private final CommandTaskHistoryPort commandTaskHistoryPort;
45+
private final ApplicationEventPublisher applicationEventPublisher;
46+
private final SendWebhookService sendWebhookService;
3547

3648
@Override
3749
@Transactional
@@ -45,15 +57,40 @@ public ApprovalTaskResponse approvalTaskByReviewer(Long reviewerId, Long taskId,
4557
task.approveTask(reviewer, processor, approvalTaskRequest.dueDate(), category, label);
4658
TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.PROCESSOR_ASSIGNED, task, null, processor,null);
4759
commandTaskHistoryPort.save(taskHistory);
60+
61+
List<Member> receivers = new ArrayList<>();
62+
receivers.add(task.getRequester());
63+
receivers.add(task.getProcessor());
64+
65+
publishNotification(receivers, task);
4866
return TaskMapper.toApprovalTaskResponse(commandTaskPort.save(task));
4967
}
5068

51-
5269
@Override
5370
public FindApprovalFormResponse findApprovalForm(Long managerId, Long taskId) {
5471
memberService.findActiveMember(managerId);
5572
Task task = taskService.findById(taskId);
5673
task.validateTaskRequested();
5774
return TaskMapper.toFindApprovalFormResponse(task);
5875
}
76+
77+
private void publishNotification(List<Member> receivers, Task task){
78+
for (Member receiver : receivers) {
79+
// 알림 저장
80+
Notification notification = createTaskNotification(task, receiver, NotificationType.PROCESSOR_ASSIGNED);
81+
applicationEventPublisher.publishEvent(notification);
82+
83+
// SSE 실시간 알림 전송
84+
SseRequest sseRequest = new SseRequest(
85+
notification.getTask().getTitle(),
86+
notification.getType(),
87+
receiver.getMemberId(),
88+
task.getProcessor().getNickname()
89+
);
90+
applicationEventPublisher.publishEvent(sseRequest);
91+
92+
sendWebhookService.sendWebhookNotification(receiver, NotificationType.PROCESSOR_ASSIGNED,
93+
task, task.getProcessor().getNickname(), null);
94+
}
95+
}
5996
}

0 commit comments

Comments
 (0)