Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -40,7 +40,7 @@ public class EnrollController {
@Operation(summary = "직관 신청 API", description = "직관 신청을 요청하는 API 입니다.")
public CreateEnrollInfo requestEnroll(@Valid @RequestBody CreateEnrollRequest createEnrollRequest,
@PathVariable Long boardId,
@JwtValidation Long userId) {
@JwtValidation Long userId) throws IOException {
return enrollService.requestEnroll(createEnrollRequest, boardId, userId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import java.io.IOException;

public interface EnrollService {
CreateEnrollInfo requestEnroll(CreateEnrollRequest request, Long boardId, Long userId);
CreateEnrollInfo requestEnroll(CreateEnrollRequest request, Long boardId, Long userId) throws IOException;

CancelEnrollInfo cancelEnroll(Long enrollId, Long userId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
import com.back.catchmate.domain.board.repository.BoardRepository;
import com.back.catchmate.domain.enroll.converter.EnrollConverter;
import com.back.catchmate.domain.enroll.dto.EnrollRequest.CreateEnrollRequest;
import com.back.catchmate.domain.enroll.dto.EnrollResponse;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.CancelEnrollInfo;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.CreateEnrollInfo;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.NewEnrollCountInfo;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.PagedEnrollReceiveInfo;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.PagedEnrollRequestInfo;
import com.back.catchmate.domain.enroll.dto.EnrollResponse.UpdateEnrollInfo;
import com.back.catchmate.domain.enroll.entity.AcceptStatus;
import com.back.catchmate.domain.enroll.entity.Enroll;
import com.back.catchmate.domain.enroll.repository.EnrollRepository;
import com.back.catchmate.domain.notification.message.NotificationMessages;
import com.back.catchmate.domain.notification.service.FCMService;
import com.back.catchmate.domain.notification.service.NotificationService;
import com.back.catchmate.domain.user.entity.User;
import com.back.catchmate.domain.user.repository.UserRepository;
import com.back.catchmate.global.error.ErrorCode;
Expand All @@ -35,11 +37,12 @@ public class EnrollServiceImpl implements EnrollService {
private final UserRepository userRepository;
private final BoardRepository boardRepository;
private final FCMService fcmService;
private final NotificationService notificationService;
private final EnrollConverter enrollConverter;

@Override
@Transactional
public CreateEnrollInfo requestEnroll(CreateEnrollRequest request, Long boardId, Long userId) {
public CreateEnrollInfo requestEnroll(CreateEnrollRequest request, Long boardId, Long userId) throws IOException {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(ErrorCode.USER_NOT_FOUND));

Expand All @@ -57,6 +60,18 @@ public CreateEnrollInfo requestEnroll(CreateEnrollRequest request, Long boardId,

Enroll enroll = enrollConverter.toEntity(request, user, board);
enrollRepository.save(enroll);

String title = NotificationMessages.ENROLLMENT_NOTIFICATION_TITLE;
String body = String.format(NotificationMessages.ENROLLMENT_NOTIFICATION_BODY, user.getNickName());

// 게시글 작성자의 아이디를 통해 FCM 토큰 확인
User boardWriter = userRepository.findById(board.getUser().getId())
.orElseThrow(() -> new BaseException(ErrorCode.USER_NOT_FOUND));

fcmService.sendMessage(boardWriter.getFcmToken(), title, body, boardId);

// 데이터베이스에 저장
notificationService.createNotification(title, body, enroll.getUser().getProfileImageUrl(), boardId, boardWriter.getId());
return enrollConverter.toCreateEnrollInfo(enroll);
}

Expand Down Expand Up @@ -119,7 +134,7 @@ public PagedEnrollReceiveInfo getReceiveEnrollListByBoardId(Long userId, Long bo

@Override
@Transactional(readOnly = true)
public EnrollResponse.NewEnrollCountInfo getNewEnrollListCount(Long userId) {
public NewEnrollCountInfo getNewEnrollListCount(Long userId) {
int enrollListCount = enrollRepository.countNewEnrollListByUserId(userId);
return enrollConverter.toNewEnrollCountResponse(enrollListCount);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.back.catchmate.domain.notification.controller;

import com.back.catchmate.domain.notification.dto.NotificationResponse.NotificationInfo;
import com.back.catchmate.domain.notification.dto.NotificationResponse.PagedNotificationInfo;
import com.back.catchmate.domain.notification.service.NotificationService;
import com.back.catchmate.global.jwt.JwtValidation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "알림 관련 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/notification")
public class NotificationController {
private final NotificationService notificationService;

@GetMapping("/receive")
@Operation(summary = "내가 받은 알림 목록 조회 API", description = "내가 받은 알림 목록을 조회하는 API 입니다.")
public PagedNotificationInfo getNotificationList(@JwtValidation Long userId,
@Parameter(hidden = true) Pageable pageable) {
return notificationService.getNotificationList(userId, pageable);
}

@GetMapping("/receive/{notificationId}")
@Operation(summary = "내가 받은 알림 단일 조회 API", description = "내가 받은 알림을 단일 조회하는 API 입니다.")
public NotificationInfo getNotification(@JwtValidation Long userId,
@PathVariable Long notificationId) {
return notificationService.getNotification(userId, notificationId);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
package com.back.catchmate.domain.notification.converter;

import com.back.catchmate.domain.notification.dto.NotificationResponse.CreateNotificationInfo;
import com.back.catchmate.domain.board.converter.BoardConverter;
import com.back.catchmate.domain.board.dto.BoardResponse.BoardInfo;
import com.back.catchmate.domain.board.entity.Board;
import com.back.catchmate.domain.notification.dto.NotificationResponse.NotificationInfo;
import com.back.catchmate.domain.notification.dto.NotificationResponse.PagedNotificationInfo;
import com.back.catchmate.domain.notification.entity.Notification;
import com.back.catchmate.domain.user.entity.User;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class NotificationConverter {
public CreateNotificationInfo toCreateNotificationInfo(Notification notification) {
return CreateNotificationInfo.builder()
private final BoardConverter boardConverter;

public Notification toEntity(User user, Board board, String senderProfileImageUrl, String title, String body) {
return Notification.builder()
.user(user)
.board(board)
.title(title)
.body(body)
.senderProfileImageUrl(senderProfileImageUrl)
.isRead(false)
.build();
}

public PagedNotificationInfo toPagedNotificationInfo(Page<Notification> notificationList) {
List<NotificationInfo> enrollRequestInfoList = notificationList.stream()
.map(notification -> toNotificationInfo(notification, notification.getBoard()))
.collect(Collectors.toList());

return PagedNotificationInfo.builder()
.notificationInfoList(enrollRequestInfoList)
.totalPages(notificationList.getTotalPages())
.totalElements(notificationList.getTotalElements())
.build();
}

public NotificationInfo toNotificationInfo(Notification notification, Board board) {
BoardInfo boardInfo = boardConverter.toBoardInfo(board);

return NotificationInfo.builder()
.notificationId(notification.getId())
.createdAt(LocalDateTime.now())
.title(notification.getTitle())
.body(notification.getBody())
.senderProfileImageUrl(notification.getSenderProfileImageUrl())
.isRead(notification.isRead())
.boardInfo(boardInfo)
.createdAt(notification.getCreatedAt())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

public abstract class NotificationResponse {

Expand All @@ -17,6 +18,7 @@ public abstract class NotificationResponse {
public static class NotificationInfo {
private Long notificationId;
private BoardInfo boardInfo;
private String senderProfileImageUrl;
private String title;
private String body;
private LocalDateTime createdAt;
Expand All @@ -31,4 +33,16 @@ public static class CreateNotificationInfo {
private Long notificationId;
private LocalDateTime createdAt;
}

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class PagedNotificationInfo {
private List<NotificationInfo> notificationInfoList;
private Integer totalPages;
private Long totalElements;
private Boolean isFirst;
private Boolean isLast;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public class Notification extends BaseTimeEntity {
@JoinColumn(name = "board_id", nullable = false)
private Board board;

@Column(nullable = false)
private String senderProfileImageUrl;

@Column(nullable = false)
private String title;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ public class NotificationMessages {
public static final String ENROLLMENT_REJECT_TITLE = "직관 신청 수락 안내 문자";
public static final String ENROLLMENT_ACCEPT_BODY = "귀하의 직관 신청이 승인되었습니다. 참여를 환영합니다!";
public static final String ENROLLMENT_REJECT_BODY = "귀하의 직관 신청이 거절되었습니다. 다음 기회에 참여를 부탁드립니다.";

public static final String ENROLLMENT_NOTIFICATION_TITLE = "직관 신청 안내 문자";
public static final String ENROLLMENT_NOTIFICATION_BODY = "%s님의 직관 신청이 도착했어요";
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.back.catchmate.domain.notification.repository;

import com.back.catchmate.domain.notification.entity.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface NotificationRepository extends JpaRepository<Notification, Long> {
Page<Notification> findByUserId(Long userId, Pageable pageable);

Optional<Notification> findByIdAndUserId(Long notificationId, Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.back.catchmate.domain.notification.service;

import com.back.catchmate.domain.notification.dto.NotificationResponse.NotificationInfo;
import com.back.catchmate.domain.notification.dto.NotificationResponse.PagedNotificationInfo;
import org.springframework.data.domain.Pageable;

public interface NotificationService {
void createNotification(String title, String body, String senderProfileImageUrl, Long boardId, Long userId);

PagedNotificationInfo getNotificationList(Long userId, Pageable pageable);

NotificationInfo getNotification(Long userId, Long notificationId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.back.catchmate.domain.notification.service;

import com.back.catchmate.domain.board.entity.Board;
import com.back.catchmate.domain.board.repository.BoardRepository;
import com.back.catchmate.domain.notification.converter.NotificationConverter;
import com.back.catchmate.domain.notification.dto.NotificationResponse.NotificationInfo;
import com.back.catchmate.domain.notification.dto.NotificationResponse.PagedNotificationInfo;
import com.back.catchmate.domain.notification.entity.Notification;
import com.back.catchmate.domain.notification.repository.NotificationRepository;
import com.back.catchmate.domain.user.entity.User;
import com.back.catchmate.domain.user.repository.UserRepository;
import com.back.catchmate.global.error.ErrorCode;
import com.back.catchmate.global.error.exception.BaseException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class NotificationServiceImpl implements NotificationService {
private final UserRepository userRepository;
private final BoardRepository boardRepository;
private final NotificationRepository notificationRepository;
private final NotificationConverter notificationConverter;

@Override
@Transactional
public void createNotification(String title, String body, String senderProfileImageUrl, Long boardId, Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(ErrorCode.USER_NOT_FOUND));

Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new BaseException(ErrorCode.BOARD_NOT_FOUND));

Notification notification = notificationConverter.toEntity(user, board, senderProfileImageUrl, title, body);
notificationRepository.save(notification);
}

@Override
@Transactional(readOnly = true)
public PagedNotificationInfo getNotificationList(Long userId, Pageable pageable) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(ErrorCode.USER_NOT_FOUND));

Page<Notification> notificationList = notificationRepository.findByUserId(user.getId(), pageable);
return notificationConverter.toPagedNotificationInfo(notificationList);
}

@Override
@Transactional
public NotificationInfo getNotification(Long userId, Long notificationId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(ErrorCode.USER_NOT_FOUND));

Notification notification = notificationRepository.findByIdAndUserId(notificationId, user.getId())
.orElseThrow(() -> new BaseException(ErrorCode.NOTIFICATION_NOT_FOUND));

// 읽지 않은 알림일 경우, 읽음으로 표시
if (notification.isNotRead()) {
notification.markAsRead();
}

return notificationConverter.toNotificationInfo(notification, notification.getBoard());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class UserServiceImpl implements UserService{
private final ClubRepository clubRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final UserConverter userConverter;
private final ClubConverter clubConverter;

@Override
@Transactional
Expand Down
Loading