Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
0f5d3cd
[REFACTOR] 전반적인 패키지 우선 분리
GiJungPark Nov 11, 2025
e0f021d
[REFACTOR] Feed Controller 패키지 이동
sansan20535 Nov 11, 2025
4fdf1b6
[REFACTOR] FeedCategory & PopularFeed Service 패키지 구조 변경 및 FCMService …
sansan20535 Nov 11, 2025
282691b
[REFACTOR] CategoryService 삭제
sansan20535 Nov 11, 2025
af3f50a
[REFACTOR] 소설 검색 및 소설 필터링 로직 파사드 패턴으로 분리
GiJungPark Nov 11, 2025
06cb1da
Merge pull request #412 from Team-WSS/refactor/#411
sansan20535 Nov 11, 2025
085a432
Merge pull request #413 from Team-WSS/refactor/#410
GiJungPark Nov 11, 2025
9eb2654
[FIX] QueryDSL Q클래스 경로 수정
GiJungPark Nov 11, 2025
cecde5a
[REFACTOR] CommentService 의존성 분리
sansan20535 Nov 16, 2025
1377df2
[REFACTOR] FeedServiceImpl 구현
sansan20535 Nov 16, 2025
c468a51
[REFACTOR] Novel 내에 존재하는 서재 로직을 분리
GiJungPark Nov 16, 2025
e9f29ea
Merge pull request #416 from Team-WSS/refactor/#410
GiJungPark Nov 16, 2025
988c38b
[REFACTOR] FeedServiceImpl로 FeedService 대체 및 FeedService의 @Transactio…
sansan20535 Nov 18, 2025
2662557
[CHORE] PopularNovel 도메인 객체 및 레포지토리를 Novel 컨텍스트로 이동
GiJungPark Nov 18, 2025
85ed3d6
[REFACTOR] 인기있는 소설을 Application 계층으로 이동
GiJungPark Nov 18, 2025
a5238d1
[REFACTOR] 키워드 및 매력 포인트 책임을 서재로 이동
GiJungPark Nov 18, 2025
1746311
[DOCS] FeedService & CommentService 중복 로직 수정 필요 주석 작성
sansan20535 Nov 18, 2025
919177c
[REFACTOR] Controller에서 NovelApplication을 참조하도록 변경
GiJungPark Nov 18, 2025
e5e4ff6
[FIX] PopularNovel 도메인 이동에 따른 패키지 import 명 수정
GiJungPark Nov 18, 2025
cae859e
[REFACTIR] PopularNovelsGetResponse DTO로 변경하는 책임을 Service에서 DTO로 이전
GiJungPark Nov 18, 2025
de59298
[REFACTOR] 서재 평가 생성의 책임을 서재, 키워드, 매력 포인트 각각 분리
GiJungPark Nov 18, 2025
3467f19
Merge pull request #415 from Team-WSS/refactor/#411
sansan20535 Nov 18, 2025
42e4e50
Merge pull request #417 from Team-WSS/refactor/#410
GiJungPark Nov 18, 2025
a914f0d
[REFACTOR] 사용하지 않는 GenreService 클래스 제거
GiJungPark Nov 25, 2025
0cdc1f1
[REFACTOR] 서재 평가 불러오기 로직 분리 및 Application으로 이전
GiJungPark Nov 25, 2025
b926114
Refactor: CommentController 생성 후 Comment 관련 Handler로직 이동
sansan20535 Nov 25, 2025
c0db346
[REFACTOR] 서재 평가 업데이트 로직 분리 및 Application으로 이전
GiJungPark Nov 25, 2025
1473785
Refactor: FeedService에 있는 Comment 비즈니스 로직을 CommentService로 이동
sansan20535 Nov 25, 2025
6933220
[REFACTOR] 서재 평가 삭제 로직 분리 및 Application으로 이전
GiJungPark Nov 25, 2025
881f3af
Refactor: FeedService에 있는 ReportedComment관련 비즈니스 로직 ReportedCommentSe…
sansan20535 Nov 25, 2025
8ba2785
Refactor: FeedService와 CommentService에서 Report 관련 로직 분리
sansan20535 Nov 25, 2025
f66f5b5
Refactor: ReportController생성 후 Report관련 로직 분리
sansan20535 Nov 25, 2025
bd9b10f
[REFACTOR] 서재 관심있어요 Application으로 로직 분리
GiJungPark Nov 25, 2025
7e8e270
[REFACTOR] 사용하지 않는 Service로직 제거
sansan20535 Nov 25, 2025
7b3b12c
Merge pull request #418 from Team-WSS/refactor/#411
GiJungPark Nov 25, 2025
f412619
Merge pull request #419 from Team-WSS/refactor/#410
GiJungPark Nov 25, 2025
3eb409d
[REFACTOR] 더 이상 사용하지 않는 NovelService 클래스를 삭제
GiJungPark Dec 2, 2025
e3803b0
[CHORE] UserNovelService가 UserController에서만 사용중임을 주석으로 표시
GiJungPark Dec 2, 2025
e402578
[REFCATOR] Platform 도메인을 Novel로 이전
GiJungPark Dec 2, 2025
f0a826b
[REFACTOR] UserNovelController를 LibraryController로 완전 대체
GiJungPark Dec 2, 2025
1098611
[REFACTOR] user domain 분리
EunjeongHeo Dec 2, 2025
5083743
[REFACTOR] user repository 분리
EunjeongHeo Dec 2, 2025
40d2267
[REFACTOR] user service 분리
EunjeongHeo Dec 2, 2025
7c4c44b
[REFACTOR] 댓글 작성 로직 Application으로 이동
sansan20535 Dec 2, 2025
7ca0346
[REFACTOR] 댓글 업데이트 로직 Application으로 이동
sansan20535 Dec 2, 2025
ed16261
[CHORE] NovelScheduler 클래스를 Application 패키지로 임시 옮김
GiJungPark Dec 2, 2025
f7bf44f
[REFACTOR] 인기있는 소설 로직을 NovelServiceImpl에서 분리
GiJungPark Dec 2, 2025
9fa60ab
[REFACTOR] 댓글 생성 로직에서 알림 전송 로직을 NotificationService에서 처리할 수 있도록 주석 추가
sansan20535 Dec 2, 2025
4629e70
[REFACTOR] 댓글 삭제 로직 Application으로 이동
sansan20535 Dec 2, 2025
445e2ca
[REFACTOR] 인기 있는 소설 탐색 Scheduler 내부 상세 구현을 Service로 책임 분산
GiJungPark Dec 2, 2025
7882b73
[REFACTOR] 댓글 조회 로직 Application으로 이동 및 CommentApplication에서 NovelRepo…
sansan20535 Dec 2, 2025
446fbcc
Merge pull request #422 from Team-WSS/refactor/#410
GiJungPark Dec 2, 2025
18cd5a5
Merge pull request #421 from Team-WSS/refactor/#411
GiJungPark Dec 2, 2025
9a16714
resolving merge conflicts
GiJungPark Dec 6, 2025
90aa55b
Merge pull request #423 from Team-WSS/refactor/#420
GiJungPark Dec 6, 2025
2151c6a
[REFACTOR] CommentService 대신 CommentFindApplication, CommentManagemen…
sansan20535 Dec 7, 2025
7391595
[REFACTOR] Report관련 로직 Application으로 이동
sansan20535 Dec 7, 2025
ea57a09
[REFACTOR] 키워드 서비스 로직(특정 단어가 속하는가)을 도메인 로직으로 수정
GiJungPark Dec 7, 2025
407101f
[REFACTOR] 매력 포인트, for문을 활용한 다건 save() 호출에서 saveAll로 리팩토링
GiJungPark Dec 7, 2025
8ce5b1d
[FIX] 충돌로 지워졌던 작품 평가 로직 복구
GiJungPark Dec 7, 2025
5129bca
refactor: user 서비스 레이어 분리
EunjeongHeo Dec 7, 2025
4998b3e
[CHORE] 서재 UserNovel로 작성된 메서드 명 Library로 수정
GiJungPark Dec 7, 2025
5ed435a
[REFACTOR] Feed 조회 관련 로직 FeedFindApplication으로 이동
sansan20535 Dec 7, 2025
92eeb8a
Merge pull request #424 from Team-WSS/refactor/#420
EunjeongHeo Dec 7, 2025
ea7f00b
[REFACTOR] Library에 있는 매력 포인트, 키워드 로직을 분리
GiJungPark Dec 7, 2025
53acc74
Merge pull request #425 from Team-WSS/refactor/#411
GiJungPark Dec 7, 2025
59d4d8c
Merge pull request #426 from Team-WSS/refactor/#410
GiJungPark Dec 7, 2025
7e6520b
[FEAT] AvatarProfile, AvatarProfileLine 엔티티 설계
GiJungPark Dec 9, 2025
89c52b4
[FEAT] 아바타 프로필 목록 조회 비즈니스 로직 작성
GiJungPark Dec 9, 2025
953d793
[FEAT] 신규 아바타 프로필 목록 조회 API 작성
GiJungPark Dec 9, 2025
4ef62e2
[REFACTOR] 유저 프로필 수정 시, AvatarId가 아닌 AvatarProfileId 변경하도록 변
GiJungPark Dec 11, 2025
fb95903
[REFACTOR] 유저 회원가입시, AvatarProfileId 1로 기본 설정되도록 수정
GiJungPark Dec 11, 2025
3f814ed
[REFACTOR] 본인 프로필 조회시, Avatar 이미지에서 AvatarProfile 이미지가 보이도록 수
GiJungPark Dec 11, 2025
8c31625
[REFACTOR] 타 유저 프로필 조회시, Avatar 이미지에서 AvatarProfile 이미지가 보이도록 수정
GiJungPark Dec 11, 2025
a121b86
[FIX] 프로필 업데이트시, AvatarProfileId가 아닌 AvatarId로 검증하는 로직 수정
GiJungPark Dec 11, 2025
7f8350b
[REFACTOR] 일반/관심글 피드 조회시, AvatarImage가 아닌 AvatarProfileImage로 avatarI…
GiJungPark Dec 11, 2025
e38363c
[REFACTOR] 작품 정보 조회시, AvatarImage를 AvatarProfileImage로 반환하도록 수정
GiJungPark Dec 11, 2025
8e514a9
[REFACTOR] 차단 유저 목록 조회, AvatarImage를 AvatarProfileImage로 반환하도록 수정
GiJungPark Dec 11, 2025
dd3bc6e
[REFACTOR] 인기있는 소설 조회시, AvatarImage를 AvatarProfileImage로 반환하도록 수정
GiJungPark Dec 11, 2025
e186584
[REFACTOR] 피드 댓글 전체 조회시, AvatarImage를 AvatarProfileImage로 반환하도록 수정
GiJungPark Dec 11, 2025
8e7719d
[REFACTOR] avatarProfileBackgroundImage를 avatarCharacterImage로 명칭 수
GiJungPark Dec 11, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.websoso.WSSServer.application;

import static org.websoso.WSSServer.domain.common.DiscordWebhookMessageType.WITHDRAW;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.websoso.WSSServer.domain.common.DiscordWebhookMessage;
import org.websoso.WSSServer.dto.user.WithdrawalRequest;
import org.websoso.WSSServer.feed.repository.CommentRepository;
import org.websoso.WSSServer.feed.repository.FeedRepository;
import org.websoso.WSSServer.oauth2.service.AppleService;
import org.websoso.WSSServer.oauth2.service.KakaoService;
import org.websoso.WSSServer.repository.RefreshTokenRepository;
import org.websoso.WSSServer.service.DiscordMessageClient;
import org.websoso.WSSServer.service.MessageFormatter;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.user.domain.WithdrawalReason;
import org.websoso.WSSServer.user.repository.UserRepository;
import org.websoso.WSSServer.user.repository.WithdrawalReasonRepository;

@Service
@RequiredArgsConstructor
@Transactional
public class AccountApplication {
private static final String KAKAO_PREFIX = "kakao";
private static final String APPLE_PREFIX = "apple";

private final WithdrawalReasonRepository withdrawalReasonRepository;
private final DiscordMessageClient discordMessageClient;
private final AppleService appleService;
private final FeedRepository feedRepository;
private final UserRepository userRepository;
private final CommentRepository commentRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final KakaoService kakaoService;

public void withdrawUser(User user, WithdrawalRequest withdrawalRequest) {
unlinkSocialAccount(user);

String messageContent = MessageFormatter.formatUserWithdrawMessage(user.getUserId(), user.getNickname(),
withdrawalRequest.reason());

cleanupUserData(user.getUserId());

discordMessageClient.sendDiscordWebhookMessage(
DiscordWebhookMessage.of(messageContent, WITHDRAW));

withdrawalReasonRepository.save(WithdrawalReason.create(withdrawalRequest.reason()));
}

private void unlinkSocialAccount(User user) {
if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.unlinkFromKakao(user);
} else if (user.getSocialId().startsWith(APPLE_PREFIX)) {
appleService.unlinkFromApple(user);
}
}

private void cleanupUserData(Long userId) {
refreshTokenRepository.deleteAll(refreshTokenRepository.findAllByUserId(userId));
feedRepository.updateUserToUnknown(userId);
commentRepository.updateUserToUnknown(userId);
userRepository.deleteById(userId);
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.websoso.WSSServer.service;
package org.websoso.WSSServer.application;

import static org.websoso.WSSServer.exception.error.CustomAuthError.INVALID_TOKEN;

Expand All @@ -9,19 +9,28 @@
import org.websoso.WSSServer.config.jwt.JWTUtil;
import org.websoso.WSSServer.config.jwt.JwtProvider;
import org.websoso.WSSServer.config.jwt.JwtValidationType;
import org.websoso.WSSServer.domain.RefreshToken;
import org.websoso.WSSServer.dto.auth.LogoutRequest;
import org.websoso.WSSServer.dto.auth.ReissueResponse;
import org.websoso.WSSServer.dto.user.LoginResponse;
import org.websoso.WSSServer.exception.exception.CustomAuthException;
import org.websoso.WSSServer.oauth2.service.KakaoService;
import org.websoso.WSSServer.repository.RefreshTokenRepository;
import org.websoso.WSSServer.user.domain.RefreshToken;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.user.repository.UserDeviceRepository;
import org.websoso.WSSServer.user.service.UserService;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService {

public class AuthApplication {
private final JwtProvider jwtProvider;
private final JWTUtil jwtUtil;
private final RefreshTokenRepository refreshTokenRepository;
private final UserDeviceRepository userDeviceRepository;
private final UserService userService;
private final KakaoService kakaoService;
private static final String KAKAO_PREFIX = "kakao";
private static final String APPLE_PREFIX = "apple";

public ReissueResponse reissue(String refreshToken) {
RefreshToken storedRefreshToken = refreshTokenRepository.findByRefreshToken(refreshToken)
Expand All @@ -41,4 +50,27 @@ public ReissueResponse reissue(String refreshToken) {

return ReissueResponse.of(newAccessToken, newRefreshToken);
}

// TODO: getUserOrException -> existUserOrException 변경
@Transactional(readOnly = true)
public LoginResponse login(Long userId) {
User user = userService.getUserOrException(userId);

CustomAuthenticationToken customAuthenticationToken = new CustomAuthenticationToken(user.getUserId(), null,
null);
String token = jwtProvider.generateAccessToken(customAuthenticationToken);

return LoginResponse.of(token);
}

public void logout(User user, LogoutRequest request) {
refreshTokenRepository.findByRefreshToken(request.refreshToken())
.ifPresent(refreshTokenRepository::delete);

userDeviceRepository.deleteByUserAndDeviceIdentifier(user, request.deviceIdentifier());

if (user.getSocialId().startsWith(KAKAO_PREFIX)) {
kakaoService.kakaoLogout(user);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.websoso.WSSServer.application;

import static org.websoso.WSSServer.exception.error.CustomAvatarError.AVATAR_NOT_FOUND;
import static org.websoso.WSSServer.exception.error.CustomUserError.USER_NOT_FOUND;

import java.util.AbstractMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.websoso.WSSServer.repository.AvatarProfileRepository;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.dto.comment.CommentGetResponse;
import org.websoso.WSSServer.dto.comment.CommentsGetResponse;
import org.websoso.WSSServer.dto.user.UserBasicInfo;
import org.websoso.WSSServer.exception.exception.CustomAvatarException;
import org.websoso.WSSServer.exception.exception.CustomUserException;
import org.websoso.WSSServer.feed.domain.Feed;
import org.websoso.WSSServer.feed.service.FeedServiceImpl;
import org.websoso.WSSServer.repository.BlockRepository;
import org.websoso.WSSServer.user.repository.UserRepository;

@Service
@RequiredArgsConstructor
public class CommentFindApplication {

private final FeedServiceImpl feedServiceImpl;

//ToDo : 의존성 제거 필요 부분
private final UserRepository userRepository;
private final BlockRepository blockRepository;
private final AvatarProfileRepository avatarProfileRepository;

@Transactional(readOnly = true)
public CommentsGetResponse getComments(User user, Long feedId) {
Feed feed = feedServiceImpl.getFeedOrException(feedId);
List<CommentGetResponse> responses = feed.getComments().stream()
.map(comment -> new AbstractMap.SimpleEntry<>(comment, userRepository.findById(comment.getUserId())
.orElseThrow(
() -> new CustomUserException(USER_NOT_FOUND, "user with the given id was not found"))))
.map(entry -> CommentGetResponse.of(getUserBasicInfo(entry.getValue()), entry.getKey(),
isUserCommentOwner(entry.getValue(), user), entry.getKey().getIsSpoiler(),
isBlocked(user, entry.getValue()), entry.getKey().getIsHidden())).toList();

return CommentsGetResponse.of(responses);
}

private Boolean isUserCommentOwner(User createdUser, User user) {
return createdUser.equals(user);
}

private Boolean isBlocked(User user, User createdFeedUser) {
return blockRepository.existsByBlockingIdAndBlockedId(user.getUserId(), createdFeedUser.getUserId());
}

private UserBasicInfo getUserBasicInfo(User user) {
return user.getUserBasicInfo(
avatarProfileRepository.findById(user.getAvatarProfileId()).orElseThrow(() ->
new CustomAvatarException(AVATAR_NOT_FOUND, "avatar with the given id was not found"))
.getAvatarProfileImage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.websoso.WSSServer.application;

import static java.lang.Boolean.TRUE;
import static org.websoso.WSSServer.domain.common.Action.DELETE;
import static org.websoso.WSSServer.domain.common.Action.UPDATE;
import static org.websoso.WSSServer.exception.error.CustomUserError.USER_NOT_FOUND;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.websoso.WSSServer.domain.Notification;
import org.websoso.WSSServer.domain.NotificationType;
import org.websoso.WSSServer.user.domain.User;
import org.websoso.WSSServer.user.domain.UserDevice;
import org.websoso.WSSServer.dto.comment.CommentCreateRequest;
import org.websoso.WSSServer.dto.comment.CommentUpdateRequest;
import org.websoso.WSSServer.exception.exception.CustomUserException;
import org.websoso.WSSServer.feed.domain.Comment;
import org.websoso.WSSServer.feed.domain.Feed;
import org.websoso.WSSServer.feed.service.CommentServiceImpl;
import org.websoso.WSSServer.feed.service.FeedServiceImpl;
import org.websoso.WSSServer.notification.FCMClient;
import org.websoso.WSSServer.notification.dto.FCMMessageRequest;
import org.websoso.WSSServer.novel.domain.Novel;
import org.websoso.WSSServer.novel.service.NovelServiceImpl;
import org.websoso.WSSServer.repository.BlockRepository;
import org.websoso.WSSServer.repository.NotificationRepository;
import org.websoso.WSSServer.repository.NotificationTypeRepository;
import org.websoso.WSSServer.user.repository.UserRepository;

@Service
@RequiredArgsConstructor
public class CommentManagementApplication {

private final CommentServiceImpl commentServiceImpl;
private final FeedServiceImpl feedServiceImpl;
private final NovelServiceImpl novelServiceImpl;
private final FCMClient fcmClient;

private static final int NOTIFICATION_TITLE_MAX_LENGTH = 12;
private static final int NOTIFICATION_TITLE_MIN_LENGTH = 0;

//ToDo : 의존성 제거 필요 부분
private final BlockRepository blockRepository;
private final NotificationRepository notificationRepository;
private final NotificationTypeRepository notificationTypeRepository;
private final UserRepository userRepository;

@Transactional
public void createComment(User user, Long feedId, CommentCreateRequest request) {
Feed feed = feedServiceImpl.getFeedOrException(feedId);
commentServiceImpl.createComment(user, feed, request);
sendCommentPushMessageToFeedOwner(user, feed);
sendCommentPushMessageToCommenters(user, feed);
}

private void sendCommentPushMessageToFeedOwner(User user, Feed feed) {
User feedOwner = feed.getUser();
if (user.equals(feedOwner) || blockRepository.existsByBlockingIdAndBlockedId(feedOwner.getUserId(),
user.getUserId())) {
return;
}

// ToDo : 해당 로직 NotificationSerivce에서 처리하도록 수정
NotificationType notificationTypeComment = notificationTypeRepository.findByNotificationTypeName("댓글");

String notificationTitle = createNotificationTitle(feed);
String notificationBody = String.format("%s님이 내 글에 댓글을 남겼어요.", user.getNickname());
Long feedId = feed.getFeedId();

Notification notification = Notification.create(notificationTitle, notificationBody, null,
feedOwner.getUserId(), feedId, notificationTypeComment);
notificationRepository.save(notification);

if (!TRUE.equals(feedOwner.getIsPushEnabled())) {
return;
}

List<UserDevice> feedOwnerDevices = feedOwner.getUserDevices();
if (feedOwnerDevices.isEmpty()) {
return;
}

FCMMessageRequest fcmMessageRequest = FCMMessageRequest.of(notificationTitle, notificationBody,
String.valueOf(feedId), "feedDetail", String.valueOf(notification.getNotificationId()));

List<String> targetFCMTokens = feedOwnerDevices.stream().map(UserDevice::getFcmToken).toList();

fcmClient.sendMulticastPushMessage(targetFCMTokens, fcmMessageRequest);
}

private void sendCommentPushMessageToCommenters(User user, Feed feed) {
User feedOwner = feed.getUser();

List<User> commenters = feed.getComments().stream().map(Comment::getUserId)
.filter(userId -> !userId.equals(user.getUserId()))
.filter(userId -> !userId.equals(feedOwner.getUserId()))
.filter(userId -> !blockRepository.existsByBlockingIdAndBlockedId(userId, user.getUserId())
&& !blockRepository.existsByBlockingIdAndBlockedId(userId, feed.getUser().getUserId()))
.distinct().map(userId -> userRepository.findById(userId).orElseThrow(
() -> new CustomUserException(USER_NOT_FOUND, "user with the given id was not found")))
.toList();

if (commenters.isEmpty()) {
return;
}

// ToDo : 해당 로직 NotificationSerivce에서 처리하도록 수정
NotificationType notificationTypeComment = notificationTypeRepository.findByNotificationTypeName("댓글");

String notificationTitle = createNotificationTitle(feed);
String notificationBody = "내가 댓글 단 글에 또 다른 댓글이 달렸어요.";
Long feedId = feed.getFeedId();

commenters.forEach(commenter -> {
Notification notification = Notification.create(notificationTitle, notificationBody, null,
commenter.getUserId(), feedId, notificationTypeComment);
notificationRepository.save(notification);

if (!TRUE.equals(commenter.getIsPushEnabled())) {
return;
}

List<UserDevice> commenterDevices = commenter.getUserDevices();
if (commenterDevices.isEmpty()) {
return;
}

List<String> targetFCMTokens = commenterDevices.stream().map(UserDevice::getFcmToken).distinct().toList();

FCMMessageRequest fcmMessageRequest = FCMMessageRequest.of(notificationTitle, notificationBody,
String.valueOf(feedId), "feedDetail", String.valueOf(notification.getNotificationId()));
fcmClient.sendMulticastPushMessage(targetFCMTokens, fcmMessageRequest);
});
}


private String createNotificationTitle(Feed feed) {
if (feed.getNovelId() == null) {
String feedContent = feed.getFeedContent();
feedContent = feedContent.length() <= NOTIFICATION_TITLE_MAX_LENGTH ? feedContent
: feedContent.substring(NOTIFICATION_TITLE_MIN_LENGTH, NOTIFICATION_TITLE_MAX_LENGTH);
return "'" + feedContent + "...'";
}
Novel novel = novelServiceImpl.getNovelOrException(feed.getNovelId());
return novel.getTitle();
}

@Transactional
public void updateComment(User user, Long feedId, Long commentId, CommentUpdateRequest request) {
Feed feed = feedServiceImpl.getFeedOrException(feedId);
Comment comment = commentServiceImpl.findComment(commentId);
comment.validateFeedAssociation(feed);
comment.validateUserAuthorization(user.getUserId(), UPDATE);
commentServiceImpl.updateComment(comment, request);
}

@Transactional
public void deleteComment(User user, Long feedId, Long commentId) {
Feed feed = feedServiceImpl.getFeedOrException(feedId);
Comment comment = commentServiceImpl.findComment(commentId);
comment.validateFeedAssociation(feed);
comment.validateUserAuthorization(user.getUserId(), DELETE);
commentServiceImpl.deleteComment(comment);
}
}
Loading
Loading