Skip to content

Commit

Permalink
Merge pull request #147 from Team-Capple/feat/#126/apnsSetting
Browse files Browse the repository at this point in the history
[FEAT] ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์›๊ฒฉ ์•Œ๋ฆผ ๋ฐœ์†ก ๋กœ์ง ์—ฐ๊ฒฐ
  • Loading branch information
jaewonLeeKOR authored Sep 13, 2024
2 parents 5ca7e39 + 6ed79f5 commit 42b1468
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 35 deletions.
106 changes: 75 additions & 31 deletions src/main/java/com/server/capple/config/apns/dto/ApnsClientRequest.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package com.server.capple.config.apns.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.server.capple.domain.board.entity.Board;
import com.server.capple.domain.boardComment.entity.BoardComment;
import com.server.capple.domain.notifiaction.entity.NotificationType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;

public class ApnsClientRequest {

@Getter
@NoArgsConstructor
@ToString
public static class SimplePushBody {
private Aps aps;

public SimplePushBody(String title, String subTitle, String body, Integer badge, String threadId, String targetContentId) {
this.aps = new Aps(new Aps.Alert(title, subTitle, body), badge, threadId, targetContentId);
private String boardId;
private String boardCommentId;
@Builder
public SimplePushBody(String title, String subTitle, String body, Integer badge, String sound, String threadId, String targetContentId, String boardId, String boardCommentId) {
this.aps = new Aps(new Aps.Alert(title, subTitle, body), badge, sound, threadId, targetContentId);
this.boardId = boardId;
this.boardCommentId = boardCommentId;
}

@ToString
Expand All @@ -23,11 +29,12 @@ public SimplePushBody(String title, String subTitle, String body, Integer badge,
public static class Aps {
private Alert alert;
private Integer badge;
@Schema(defaultValue = "default")
private String sound; // Library/Sounds ํด๋” ๋‚ด์˜ ํŒŒ์ผ ์ด๋ฆ„
@JsonProperty("thread-id")
private String threadId;
@JsonProperty("target-content-id")
private String targetContentId; // ํ”„๋ก ํŠธ ์ธก ์ž‘์—… ํ•„์š”ํ•จ

@ToString
@Getter
@AllArgsConstructor
Expand All @@ -41,53 +48,90 @@ public static class Alert {
}

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public static class FullAlertBody {
public static class BoardNotificationBody {
private Aps aps;
private String boardId;
@Builder
public BoardNotificationBody(NotificationType type, Board board) {
this.aps = Aps.builder()
.threadId("board-" + board.getId())
.alert(Aps.Alert.builder()
.title(type.getTitle())
.body(board.getContent())
.build())
.build();
this.boardId = board.getId().toString();
}

@ToString
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Aps {
private Alert alert;
@Builder.Default
private String sound = "default"; // Library/Sounds ํด๋” ๋‚ด์˜ ํŒŒ์ผ ์ด๋ฆ„
@JsonProperty("thread-id")
private String threadId;

@ToString
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Alert {
private String title;
private String body;
}
}
}

@Getter
@NoArgsConstructor
@ToString
public static class BoardCommentNotificationBody {
private Aps aps;
private String boardId;
private String boardCommentId;
@Builder
public BoardCommentNotificationBody(NotificationType type, Board board, BoardComment boardComment) {
this.aps = Aps.builder().threadId("board-" + board.getId())
.alert(Aps.Alert.builder()
.title(type.getTitle())
.subtitle(boardComment.getContent())
.body(board.getContent())
.build())
.build();
this.boardId = board.getId().toString();
this.boardCommentId = boardComment.getId().toString();
}

@ToString
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Aps {
private Alert alert; // alert ์ •๋ณด
private Integer badge; // ์•ฑ ์•„์ด์ฝ˜์— ํ‘œ์‹œํ•  ๋ฑƒ์ง€ ์ˆซ์ž
private Alert alert;
private Integer badge;
@Schema(defaultValue = "default")
private String sound; // Library/Sounds ํด๋” ๋‚ด์˜ ํŒŒ์ผ ์ด๋ฆ„
@Schema(defaultValue = "thread-id")
private String threadId; // ์•Œ๋ฆผ ๊ทธ๋ฃนํ™”๋ฅผ ์œ„ํ•œ thread id (UNNotificationContent ๊ฐ์ฒด์˜ threadIdentifier์™€ ์ผ์น˜ํ•ด์•ผ ํ•จ)
private String category; // ์•Œ๋ฆผ ๊ทธ๋ฃนํ™”๋ฅผ ์œ„ํ•œ category, (UNNotificationCategory ์‹๋ณ„์ž์™€ ์ผ์น˜ํ•ด์•ผ ํ•จ)
@Schema(defaultValue = "0")
@JsonProperty("content-available")
private Integer contentAvailable; // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์—ฌ๋ถ€, 1์ด๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ, 0์ด๋ฉด ํฌ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ (๋ฐฑ๊ทธ๋ผ์šด๋“œ์ผ ๊ฒฝ์šฐ alert, badge, sound๋Š” ๋„ฃ์œผ๋ฉด ์•ˆ๋จ)
@Schema(defaultValue = "0")
@JsonProperty("mutable-content")
private Integer mutableContent; // ์•Œ๋ฆผ ์„œ๋น„์Šค ํ™•์žฅ ํ”Œ๋ž˜๊ทธ
@Schema(defaultValue = "")
@JsonProperty("target-content-id")
private String targetContentId; // ์•Œ๋ฆผ์ด ํด๋ฆญ๋˜์—ˆ์„ ๋•Œ ๊ฐ€์ ธ์˜ฌ ์ฐฝ์˜ ์‹๋ณ„์ž, UNNotificationContent ๊ฐ์ฒด์— ์ฑ„์›Œ์ง
@JsonProperty("thread-id")
private String threadId;

@ToString
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public static class Alert {
@Schema(defaultValue = "title")
private String title;
@Schema(defaultValue = "subTitle")
private String subtitle;
@Schema(defaultValue = "body")
private String body;
@Schema(defaultValue = "")
@JsonProperty("launch-image")
private String launchImage; // ์‹คํ–‰์‹œ ๋ณด์—ฌ์ค„ ์ด๋ฏธ์ง€ ํŒŒ์ผ, ๊ธฐ๋ณธ ์‹คํ–‰ ์ด๋ฏธ์ง€ ๋Œ€์‹  ์ž…๋ ฅํ•œ ์ด๋ฏธ์ง€ ๋˜๋Š” ์Šคํ† ๋ฆฌ๋ณด๋“œ๊ฐ€ ์ผœ์ง
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public <T> Boolean sendApns(T request, List<String> deviceToken) {

deviceToken.parallelStream()
.forEach(token -> {
if (token.isBlank()) return;
tmpWebClient
.method(HttpMethod.POST)
.uri(token)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import com.server.capple.domain.board.repository.BoardHeartRedisRepository;
import com.server.capple.domain.board.repository.BoardHeartRepository;
import com.server.capple.domain.board.repository.BoardRepository;
import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService;
import com.server.capple.domain.member.entity.Member;
import com.server.capple.domain.notifiaction.service.NotificationService;
import com.server.capple.global.exception.RestApiException;
import com.server.capple.global.exception.errorCode.BoardErrorCode;
import lombok.RequiredArgsConstructor;
Expand All @@ -29,6 +31,8 @@ public class BoardServiceImpl implements BoardService {
private final BoardMapper boardMapper;
private final BoardHeartRepository boardHeartRepository;
private final BoardHeartMapper boardHeartMapper;
private final NotificationService notificationService;
private final BoardSubscribeMemberService boardSubscribeMemberService;

@Override
public BoardResponse.BoardCreate createBoard(Member member, BoardType boardType, String content) {
Expand All @@ -38,6 +42,7 @@ public BoardResponse.BoardCreate createBoard(Member member, BoardType boardType,
} else {
throw new RestApiException(BoardErrorCode.BOARD_BAD_REQUEST);
}
boardSubscribeMemberService.createBoardSubscribeMember(member, board);
return boardMapper.toBoardCreate(board);
}

Expand Down Expand Up @@ -98,6 +103,7 @@ public BoardResponse.BoardDelete deleteBoard(Member member, Long boardId) {
}

board.delete();
boardSubscribeMemberService.deleteBoardSubscribeMemberByBoardId(boardId);
return boardMapper.toBoardDelete(board);
}

Expand All @@ -122,12 +128,13 @@ public ToggleBoardHeart toggleBoardHeart(Member member, Long boardId) {
});
boolean isLiked = boardHeart.toggleHeart();
board.setHeartCount(boardHeart.isLiked());
if (isLiked) notificationService.sendBoardHeartNotification(member.getId(), board);
return new ToggleBoardHeart(boardId, isLiked);
}

@Override
public Board findBoard(Long boardId) {
return boardRepository.findById(boardId)
.orElseThrow(() -> new RestApiException(BoardErrorCode.BOARD_NOT_FOUND));
.orElseThrow(() -> new RestApiException(BoardErrorCode.BOARD_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
import com.server.capple.domain.boardComment.repository.BoardCommentHeartRedisRepository;
import com.server.capple.domain.boardComment.repository.BoardCommentHeartRepository;
import com.server.capple.domain.boardComment.repository.BoardCommentRepository;
import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService;
import com.server.capple.domain.member.entity.Member;
import com.server.capple.domain.member.service.MemberService;
import com.server.capple.domain.notifiaction.service.NotificationService;
import com.server.capple.global.exception.RestApiException;
import com.server.capple.global.exception.errorCode.CommentErrorCode;
import lombok.RequiredArgsConstructor;
Expand All @@ -35,6 +37,8 @@ public class BoardCommentServiceImpl implements BoardCommentService {
private final BoardCommentHeartRepository boardCommentHeartRepository;
private final BoardCommentMapper boardCommentMapper;
private final BoardCommentHeartMapper boardCommentHeartMapper;
private final NotificationService notificationService;
private final BoardSubscribeMemberService boardSubscribeMemberService;

@Override
@Transactional
Expand All @@ -44,6 +48,8 @@ public BoardCommentId createBoardComment(Member member, Long boardId, BoardComme

BoardComment boardComment = boardCommentRepository.save(
boardCommentMapper.toBoardComment(loginMember, board, request.getComment()));
notificationService.sendBoardCommentNotification(loginMember.getId(), board, boardComment); // ๊ฒŒ์‹œ๊ธ€ ๋Œ“๊ธ€ ์•Œ๋ฆผ
boardSubscribeMemberService.createBoardSubscribeMember(loginMember, board); // ์•Œ๋ฆผ ๋ฆฌ์ŠคํŠธ ์ถ”๊ฐ€

board.increaseCommentCount();
return new BoardCommentId(boardComment.getId());
Expand Down Expand Up @@ -85,6 +91,9 @@ public ToggleBoardCommentHeart toggleBoardCommentHeart(Member member, Long board
});
boolean isLiked = boardCommentHeart.toggleHeart();
boardComment.setHeartCount(boardCommentHeart.isLiked());
if(isLiked && !boardComment.getMember().getId().equals(member.getId())) {
notificationService.sendBoardCommentHeartNotification(member.getId(), boardComment.getBoard(), boardComment);
}
return new ToggleBoardCommentHeart(boardCommentId, isLiked);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.server.capple.domain.boardSubscribeMember.entity;

import com.server.capple.domain.board.entity.Board;
import com.server.capple.domain.member.entity.Member;
import jakarta.persistence.*;
import lombok.*;

@Getter
@Entity
@AllArgsConstructor
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BoardSubscribeMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@ManyToOne
@JoinColumn(name = "board_id", nullable = false)
private Board board;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.server.capple.domain.boardSubscribeMember.reposiotry;

import com.server.capple.domain.boardSubscribeMember.entity.BoardSubscribeMember;
import com.server.capple.domain.member.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface BoardSubscribeMemberRepository extends JpaRepository<BoardSubscribeMember, Long> {
Boolean existsByMemberIdAndBoardId(Long memberId, Long boardId);
List<BoardSubscribeMember> findBoardSubscribeMembersByBoardId(Long boardId);
void deleteBoardSubscribeMemberByBoardId(Long boardId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.server.capple.domain.boardSubscribeMember.service;

import com.server.capple.domain.board.entity.Board;
import com.server.capple.domain.member.entity.Member;

import java.util.List;

public interface BoardSubscribeMemberService {
void createBoardSubscribeMember(Member member, Board board);
List<Member> findBoardSubscribeMembers(Long boardId);
void deleteBoardSubscribeMemberByBoardId(Long boardId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.server.capple.domain.boardSubscribeMember.service;

import com.server.capple.domain.board.entity.Board;
import com.server.capple.domain.boardSubscribeMember.entity.BoardSubscribeMember;
import com.server.capple.domain.boardSubscribeMember.reposiotry.BoardSubscribeMemberRepository;
import com.server.capple.domain.member.entity.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class BoardSubscribeMemberServiceImpl implements BoardSubscribeMemberService {
private final BoardSubscribeMemberRepository boardSubscribeMemberRepository;
@Override
public void createBoardSubscribeMember(Member member, Board board) {
if(boardSubscribeMemberRepository.existsByMemberIdAndBoardId(member.getId(), board.getId())) {
return;
}
boardSubscribeMemberRepository.save(BoardSubscribeMember.builder().member(member).board(board).build());
}

@Override
public List<Member> findBoardSubscribeMembers(Long boardId) {
return boardSubscribeMemberRepository.findBoardSubscribeMembersByBoardId(boardId).stream().map(BoardSubscribeMember::getMember).toList();
}

@Override
public void deleteBoardSubscribeMemberByBoardId(Long boardId) {
boardSubscribeMemberRepository.deleteBoardSubscribeMemberByBoardId(boardId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.server.capple.domain.notifiaction.entity;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum NotificationType {
BOARD_HEART("๋ˆ„๊ตฐ๊ฐ€ ๋‚ด ๊ฒŒ์‹œ๊ธ€์„ ์ข‹์•„ํ–ˆ์–ด์š”", null),
BOARD_COMMENT("๋ˆ„๊ตฐ๊ฐ€ ๋‚ด ๊ฒŒ์‹œ๊ธ€์— ๋Œ“๊ธ€์„ ๋‹ฌ์•˜์–ด์š”", null),
BAORD_COMMENT_DUPLCATE("๋ˆ„๊ตฐ๊ฐ€ ๋‚˜์™€ ๊ฐ™์€ ๊ฒŒ์‹œ๊ธ€์— ๋Œ“๊ธ€์„ ๋‹ฌ์•˜์•„์š”", null),
BOARD_COMMENT_HEART("๋ˆ„๊ตฐ๊ฐ€ ๋‚ด ๋Œ“๊ธ€์„ ์ข‹์•„ํ–ˆ์–ด์š”", null),
TODAY_QUESTION_PUBLISHED("์˜ค๋Š˜์˜ ์งˆ๋ฌธ", "์˜ค๋Š˜์˜ ์งˆ๋ฌธ์ด ์ค€๋น„ ๋˜์—ˆ์–ด์š”.\n์ง€๊ธˆ ๋ฐ”๋กœ ๋‹ต๋ณ€ํ•ด๋ณด์„ธ์š”."),
TODAY_QUESTION_CLOSED("์˜ค๋Š˜์˜ ์งˆ๋ฌธ", "์˜ค๋Š˜์˜ ์งˆ๋ฌธ ๋‹ต๋ณ€ ์‹œ๊ฐ„์ด ๋งˆ๊ฐ๋˜์—ˆ์–ด์š”.\n๋‹ค๋ฅธ ๋Ÿฌ๋„ˆ๋“ค์€ ์–ด๋–ป๊ฒŒ ๋‹ต ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์„ธ์š”."),
;
private final String title;
private final String content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.server.capple.domain.notifiaction.service;

import com.server.capple.domain.board.entity.Board;
import com.server.capple.domain.boardComment.entity.BoardComment;

public interface NotificationService {
void sendBoardHeartNotification(Long actorId, Board board);
void sendBoardCommentNotification(Long actorId, Board board, BoardComment boardComment);
void sendBoardCommentHeartNotification(Long actorId, Board board, BoardComment boardComment);
}
Loading

0 comments on commit 42b1468

Please sign in to comment.