Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#499 알림메시지 변경하기 #511

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e5494fd
refactor: 프로필 이미지도 정팩메로 통일
This2sho Sep 12, 2023
aec11af
refactor: imageFileUploader 메소드 분리
This2sho Sep 14, 2023
1666e78
feat: 회원 정보 수정 기능 구현
This2sho Sep 14, 2023
5b8153e
test: api 문서화 테스트 코드 작성
This2sho Sep 14, 2023
817324a
test: 최신 RequestBuilder로 변경
This2sho Sep 17, 2023
39f4fb8
Merge remote-tracking branch 'origin/dev' into feat/#53_회원_정보_수정
This2sho Oct 1, 2023
7c4abb8
refactor: ImageInfo 생성과 실제 이미지 저장 로직 분리
This2sho Oct 2, 2023
3f6af80
refactor: 중복 체크 AuthService 에서 MemberService로 이동
This2sho Oct 6, 2023
325f5bb
Merge remote-tracking branch 'origin/dev' into feat/#53_회원_정보_수정
BackFoxx Oct 7, 2023
b33321e
fix: conflict 해결, 변경된 API 인해 깨지는 테스트 해결
BackFoxx Oct 7, 2023
a00f599
fix: application.properties 프로필 수정
BackFoxx Oct 7, 2023
98f7c69
test: 프로필 이미지 테스트용 픽스쳐 추가
This2sho Oct 10, 2023
0c0a7cd
refactor: api 수정에 따른 회원 정보 수정 기능 변경
This2sho Oct 10, 2023
8070bfa
docs: 회원 정보 수정 docs 테스트 구현
This2sho Oct 10, 2023
16722da
Merge remote-tracking branch 'origin/dev' into feat/#53_회원_정보_수정
This2sho Oct 10, 2023
7383f54
Merge remote-tracking branch 'origin/feat/#53_회원_정보_수정' into feat/#53…
This2sho Oct 11, 2023
a84aa0c
refactor: Domain 객체에서 url 반환하도록 변경
This2sho Oct 11, 2023
6500efc
refactor: MyPage에서 profileImage 반환할 수 있게 변경 및 response 필드명(id) 통일
This2sho Oct 11, 2023
b686e12
feat: 회원 프로필 이미지 반환하도록 변경 및 docs 수정
This2sho Oct 11, 2023
7e54a52
fix: dto 필드명 바꾸면서 바뀐 것들 다시 수정
This2sho Oct 11, 2023
bb527ed
refactor: 마이페이지 조회 v1, v2 대응하도록 수정
This2sho Oct 16, 2023
2fa9348
refactor: 마이페이지 DTO 변경으로 인한 v2도 대응하도록 변경
This2sho Oct 16, 2023
f633889
test: 이미지 파일 생성시 Post용, Profile용 분리
This2sho Oct 16, 2023
619267d
test: Docs 테스트에 대응하는 버전 적용
This2sho Oct 16, 2023
74636f6
refactor: 잘못 적용된 예외 수정
This2sho Oct 16, 2023
7eb8fc9
build: 사용하지 않는 의존성 제거
This2sho Oct 16, 2023
b46242e
refactor: 알림 발송시 사용하는 제목과 본문 정보를 묶어 하나의 엔티티로 분리
BackFoxx Oct 18, 2023
e202771
feat: 알림 메시지로 발송할 제목과 본문 내용을 수정하는 기능 구현
BackFoxx Oct 18, 2023
81674b4
refactor: NotificationMessage의 이름을 NotificationMessageId로 바꾸고, 알림 메시지…
BackFoxx Oct 18, 2023
f4b6b77
refactor: 알림 메시지가 변경된 후에 보내는 알림에만 변경된 알림 메시지가 적용되도록 개선
BackFoxx Oct 18, 2023
092ca6d
Merge branch 'dev' into feat/#499_알림메시지_변경하기
BackFoxx Oct 18, 2023
2153e97
Merge branch 'dev' into feat/#499_알림메시지_변경하기
BackFoxx Oct 18, 2023
5f681c0
feat: 알림 메시지를 수정하는 API 구현
BackFoxx Oct 18, 2023
b4a51cf
refactor: NotificationMessageId의 이름과 패키지 위치 수정
BackFoxx Oct 18, 2023
214c444
fix: 테스트 깨짐 방지를 위해 기본 알림 메시지를 저장
BackFoxx Oct 18, 2023
ca76e03
feat: 네임드 파라미터를 사용해 title과 body 값을 동적으로 치환할 수 있는 기능 구현
BackFoxx Oct 19, 2023
74dede0
refactor: 컨트롤러의 파라미터로 DTO를 받도록 변경
BackFoxx Oct 19, 2023
79e5a3c
Merge branch 'dev' into feat/#499_알림메시지_변경하기
BackFoxx Oct 19, 2023
4e741a9
docs: notification 도메인 API 문서화
BackFoxx Oct 19, 2023
f9d932a
docs: notification 도메인 flyway 적용
BackFoxx Oct 19, 2023
9748a1f
Merge remote-tracking branch 'origin/dev' into feat/#499_알림메시지_변경하기
BackFoxx Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions backend/src/docs/asciidoc/common/notification-api.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[[notification-api]]
== 알림

== 나에게 온 알림 조회
operation::notification[snippets='http-request,response-fields,http-response']

== 알림 메시지 수정(어드민용)
operation::notification-updating-message[snippets='request-fields,http-request,http-response']

BackFoxx marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ public enum ExceptionInformation {
LOGGING_TYPE_NOT_EXISTS(9001, "존재하지 않는 로그 타입입니다."),
ABUSING_TYPE_NOT_FOUND(9100, "존재하지 않는 리포팅 카테고리 분류입니다."),
REPORT_TYPE_NOT_FOUND(9101, "존재하지 않는 리포팅 타입 분류입니다."),
NOTIFICATION_REQUEST_FAILED(9200, "알림 발송 요청에 실패했습니다.");
NOTIFICATION_REQUEST_FAILED(9200, "알림 발송 요청에 실패했습니다."),
NOTIFICATION_MESSAGE_NOT_FOUND(9201, "알림 발송에 필요한 메시지를 찾지 못했습니다."),
NOTIFICATION_MESSAGE_INVALID_CONTENT(9203, "알림 메시지로 사용할 수 없는 메시지입니다.");

private int code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public interface MemberRepository extends JpaRepository<Member, Long>, MemberCus
boolean existsByEmail(String email);

boolean existsByNickname(String nickname);

Optional<Member> findByNickname(String nickname);
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package edonymyeon.backend.notification.application;

import static edonymyeon.backend.notification.domain.NotificationMessage.COMMENT_NOTIFICATION_TITLE;
import static edonymyeon.backend.notification.domain.NotificationMessage.THUMBS_NOTIFICATION_TITLE;
import static edonymyeon.backend.notification.domain.NotificationMessage.THUMBS_PER_10_NOTIFICATION_TITLE;
import static edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId.COMMENT_NOTIFICATION_TITLE;
import static edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId.THUMBS_NOTIFICATION_TITLE;
import static edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId.THUMBS_PER_10_NOTIFICATION_TITLE;

import edonymyeon.backend.comment.domain.Comment;
import edonymyeon.backend.consumption.application.ConsumptionService;
import edonymyeon.backend.global.exception.BusinessLogicException;
import edonymyeon.backend.global.exception.EdonymyeonException;
import edonymyeon.backend.global.exception.ExceptionInformation;
import edonymyeon.backend.member.application.dto.ActiveMemberId;
import edonymyeon.backend.member.application.dto.MemberId;
import edonymyeon.backend.member.domain.Member;
Expand All @@ -15,8 +17,10 @@
import edonymyeon.backend.notification.application.dto.NotificationResponse;
import edonymyeon.backend.notification.application.dto.Receiver;
import edonymyeon.backend.notification.domain.Notification;
import edonymyeon.backend.notification.domain.NotificationMessage;
import edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId;
import edonymyeon.backend.notification.domain.ScreenType;
import edonymyeon.backend.notification.domain.notification_content.application.NotificationMessageRepository;
import edonymyeon.backend.notification.domain.notification_content.domain.NotificationContent;
import edonymyeon.backend.notification.repository.NotificationRepository;
import edonymyeon.backend.post.application.GeneralFindingCondition;
import edonymyeon.backend.post.application.PostSlice;
Expand All @@ -25,7 +29,9 @@
import edonymyeon.backend.setting.domain.SettingType;
import edonymyeon.backend.thumbs.application.ThumbsService;
import jakarta.persistence.EntityManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -55,6 +61,8 @@ public class NotificationService {

private final ConsumptionService consumptionService;

private final NotificationMessageRepository notificationMessageRepository;

/**
* 특정 회원이 받은 알림 내역을 조회합니다.
* @param memberId 알림 내역을 조회할 회원의 식별자
Expand All @@ -80,14 +88,31 @@ public void sendThumbsNotificationToWriter(final Post post) {
return;
}

final Long reactionCount = thumbsService.countReactions(post.getId());
final Map<String, String> notificationContentParameters = new HashMap<>();
notificationContentParameters.put("count", reactionCount.toString());
notificationContentParameters.put("title", post.getTitle());

if (settingService.isSettingActive(new ActiveMemberId(post.getWriterId()), SettingType.NOTIFICATION_PER_10_THUMBS)
&& isDivisibleBy10(thumbsService.countReactions(post.getId()))) {
sendNotification(post.getMember(), ScreenType.POST, post.getId(), THUMBS_PER_10_NOTIFICATION_TITLE);
&& isDivisibleBy10(reactionCount)) {
sendNotification(
post.getMember(),
ScreenType.POST,
post.getId(),
THUMBS_PER_10_NOTIFICATION_TITLE,
notificationContentParameters
);
return;
}

if (settingService.isSettingActive(new ActiveMemberId(post.getWriterId()), SettingType.NOTIFICATION_PER_THUMBS)) {
sendNotification(post.getMember(), ScreenType.POST, post.getId(), THUMBS_NOTIFICATION_TITLE);
sendNotification(
post.getMember(),
ScreenType.POST,
post.getId(),
THUMBS_NOTIFICATION_TITLE,
notificationContentParameters
);
}
}

Expand All @@ -109,7 +134,17 @@ public void sendCommentNotificationToPostWriter(Comment comment) {
if (settingService.isSettingActive(new ActiveMemberId(comment.getPost().getWriterId()), SettingType.NOTIFICATION_PER_COMMENT)) {
comment = entityManager.merge(comment);

sendNotification(comment.getPostWriter(), ScreenType.POST, comment.findPostId(), COMMENT_NOTIFICATION_TITLE);
final Map<String, String> notificationContentParameters = new HashMap<>();
notificationContentParameters.put("title", comment.getPost().getTitle());
notificationContentParameters.put("comment", comment.getContent());

sendNotification(
comment.getPostWriter(),
ScreenType.POST,
comment.findPostId(),
COMMENT_NOTIFICATION_TITLE,
notificationContentParameters
);
}
}

Expand All @@ -130,24 +165,46 @@ public void remindConfirmingConsumptions() {
private void remindConfirmingConsumptions(final Member member) {
if (settingService.isSettingActive(new ActiveMemberId(member.getId()),
SettingType.NOTIFICATION_CONSUMPTION_CONFIRMATION_REMINDING)) {
sendNotification(member, ScreenType.MYPOST, null, NotificationMessage.UNCONFIRMED_POST_REMINDER_TITLE);
sendNotification(
member,
ScreenType.MYPOST,
null,
NotificationContentId.UNCONFIRMED_POST_REMINDER_TITLE,
Map.of()
);
}
}

/**
* 사용자에게 알림을 전송합니다.
* @param notifyingTarget 알림을 전송할 대상
* @param notifyingType 알림을 클릭했을 때 리다이렉트할 페이지의 종류
* @param redirectId 알림을 클릭했을 때 리다이렉트할 페이지의 id
* @param notificationMessage 알림에서 표시할 제목
*
* @param notifyingTarget 알림을 전송할 대상
* @param notifyingType 알림을 클릭했을 때 리다이렉트할 페이지의 종류
* @param redirectId 알림을 클릭했을 때 리다이렉트할 페이지의 id
* @param notificationContentId 알림에서 표시할 제목
* @param notificationContentParameters 알림 메시지에 표시할 DSL 파라미터
*/
private void sendNotification(final Member notifyingTarget, final ScreenType notifyingType, final Long redirectId,
final NotificationMessage notificationMessage) {
private void sendNotification(
final Member notifyingTarget,
final ScreenType notifyingType,
final Long redirectId,
final NotificationContentId notificationContentId,
final Map<String, String> notificationContentParameters) {
if (notifyingTarget.isDeleted()) {
return;
}

final Long notificationId = saveNotification(notifyingTarget, notifyingType, redirectId, notificationMessage);
final NotificationContent notificationContent
= notificationMessageRepository.findById(notificationContentId)
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved
.orElseThrow(() -> new EdonymyeonException(ExceptionInformation.NOTIFICATION_MESSAGE_NOT_FOUND));

final Long notificationId = saveNotification(
notifyingTarget,
notifyingType,
redirectId,
notificationContent.getTitle(notificationContentParameters),
notificationContent.getBody(notificationContentParameters)
);

final Optional<String> deviceToken = notifyingTarget.getActiveDeviceToken();
if (deviceToken.isEmpty()) {
Expand All @@ -159,7 +216,7 @@ private void sendNotification(final Member notifyingTarget, final ScreenType not
try {
notificationSender.sendNotification(
receiver,
notificationMessage.getMessage()
notificationContent.getTitle(notificationContentParameters)
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved
);
} catch (BusinessLogicException e) {
log.error("알림 전송에 실패했습니다.", e);
Expand All @@ -168,17 +225,25 @@ private void sendNotification(final Member notifyingTarget, final ScreenType not

/**
* 알림 전송 전/후 해당 내용을 저장합니다.
* @param notifyingTarget 알림을 전송받은 대상
* @param notifyingType 알림을 클릭했을 때 리다이렉트한 페이지의 종류
* @param redirectId 알림을 클릭했을 때 리다이렉트한 페이지의 id
* @param notificationMessage 알림에서 표시한 제목
*
* @param notifyingTarget 알림을 전송받은 대상
* @param notifyingType 알림을 클릭했을 때 리다이렉트한 페이지의 종류
* @param redirectId 알림을 클릭했을 때 리다이렉트한 페이지의 id
* @param title 알림 메시지에 사용할 제목
* @param body 알림 메시지에 사용할 본문
* @return 알림 식별자
*/
private Long saveNotification(final Member notifyingTarget, final ScreenType notifyingType, final Long redirectId,
final NotificationMessage notificationMessage) {
private Long saveNotification(final Member notifyingTarget,
final ScreenType notifyingType,
final Long redirectId,
final String title,
final String body
) {

final Notification notification = new Notification(
notifyingTarget,
notificationMessage.getMessage(),
title,
body,
notifyingType,
redirectId
);
Expand All @@ -205,4 +270,15 @@ public void markNotificationAsRead(final Long notificationId) {
public void deleteNotificationByPost(final Long postId) {
notificationRepository.deleteAllByPostId(postId);
}

/**
* 알림 메시지로 보낼 제목과 본문 내용을 변경합니다.
* @param content 변경할 Notification 정보
*/
@Transactional
public void updateContent(final NotificationContent content) {
final NotificationContent notificationContent = notificationMessageRepository.findById(content.getId())
.orElseThrow(() -> new EdonymyeonException(ExceptionInformation.NOTIFICATION_MESSAGE_NOT_FOUND));
notificationContent.update(content);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
@Entity
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getter를 직접 만들어 준 이유가 있나요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조만간 롬복 파기작업을 할거에요 .. 사용하지 않는 게터가 도메인 객체에 너무 많은 건 좋지 못한 것 같소

public class Notification extends TemporalRecord {

Expand All @@ -30,6 +28,8 @@ public class Notification extends TemporalRecord {

private String title;

private String body;
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved

@Enumerated(EnumType.STRING)
private ScreenType screenType;

Expand All @@ -38,9 +38,16 @@ public class Notification extends TemporalRecord {
@Column(name = "is_read")
private boolean read;

public Notification(final Member member, final String title, final ScreenType screenType, final Long postId) {
public Notification(
final Member member,
final String title,
final String body,
final ScreenType screenType,
final Long postId
) {
this.member = member;
this.title = title;
this.body = body;
this.screenType = screenType;
this.postId = postId;
this.read = false;
Expand All @@ -49,4 +56,32 @@ public Notification(final Member member, final String title, final ScreenType sc
public void markAsRead() {
this.read = true;
}

public Long getId() {
return id;
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved
}

public String getTitle() {
return this.title;
}

public String getBody() {
return this.body;
}

public ScreenType getScreenType() {
return screenType;
}

public boolean isRead() {
return read;
}

public Long getPostId() {
return postId;
}

public Member getMember() {
return member;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package edonymyeon.backend.notification.domain.notification_content.application;

import edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId;
import edonymyeon.backend.notification.domain.notification_content.domain.NotificationContent;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NotificationMessageRepository extends JpaRepository<NotificationContent, NotificationContentId> {
BackFoxx marked this conversation as resolved.
Show resolved Hide resolved

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package edonymyeon.backend.notification.domain.notification_content.application.dto;

import edonymyeon.backend.notification.domain.notification_content.domain.NotificationContentId;

public record NotificationContentRequest(NotificationContentId id, String title, String body) {
}
Loading
Loading