Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
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
@@ -0,0 +1,14 @@
package com.example.spot.notification.application;

import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationListDTO;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.StudyNotificationListDTO;
import org.springframework.data.domain.Pageable;

public interface GetNotificationUseCase {

// 생성된 알림 전체 조회
NotificationListDTO getAllNotifications(Long memberId, Pageable pageable);

// 신청한 스터디 알림 전체 조회
StudyNotificationListDTO getAllAppliedStudyNotification(Long memberId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.spot.notification.application;

import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationProcessDTO;

public interface HandleAppliedStudyParticipationUseCase {

// 신청한 스터디 참가
NotificationProcessDTO joinAppliedStudy(Long studyId, Long memberId, boolean isAccept);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.spot.notification.application;

import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationProcessDTO;

public interface ReadNotificationUseCase {

// 알림 읽음 처리
NotificationProcessDTO readNotification(Long memberId, Long notificationId);
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
package com.example.spot.notification.application.notification;
package com.example.spot.notification.application.impl;

import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.GeneralException;
import com.example.spot.notification.application.GetNotificationUseCase;
import com.example.spot.notification.domain.Notification;
import com.example.spot.notification.domain.NotificationRepository;
import com.example.spot.notification.domain.enums.NotifyType;
import com.example.spot.notification.presentation.dto.notification.NotificationResponseDTO.NotificationListDTO;
import com.example.spot.notification.presentation.dto.notification.NotificationResponseDTO.NotificationListDTO.NotificationDTO;
import com.example.spot.notification.presentation.dto.notification.NotificationResponseDTO.StudyNotificationListDTO;
import com.example.spot.notification.presentation.dto.notification.NotificationResponseDTO.StudyNotificationListDTO.StudyNotificationDTO;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationListDTO;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationListDTO.NotificationDTO;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.StudyNotificationListDTO;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.StudyNotificationListDTO.StudyNotificationDTO;
import java.util.ArrayList;
import java.util.List;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.example.spot.notification.domain.NotificationRepository;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class NotificationQueryServiceImpl implements NotificationQueryService {
public class GetNotificationUseCaseImpl implements GetNotificationUseCase {

private final NotificationRepository notificationRepository;

/**
* 회원이 참가 신청한 스터디에 대한 알림을 조회합니다.
*
* @param memberId 사용자 ID
* @param pageable 페이징 정보
* @return 참가 신청한 스터디에 대한 알림 목록
Expand All @@ -36,39 +36,42 @@ public class NotificationQueryServiceImpl implements NotificationQueryService {
public StudyNotificationListDTO getAllAppliedStudyNotification(Long memberId, Pageable pageable) {
// 특정 회원이 참가 신청한 스터디에 대한 알림 조회
List<Notification> notifications = notificationRepository.findByMemberIdAndTypeAndIsChecked(
memberId, pageable, NotifyType.STUDY_APPLY, false);
memberId, pageable, NotifyType.STUDY_APPLY, false);

// 알림이 존재하지 않는 경우
if (notifications.isEmpty())
if (notifications.isEmpty()) {
throw new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND);
}

// DTO를 담을 리스트 생성
List<StudyNotificationDTO> notificationDTOs = new ArrayList<>();

// 알림을 DTO로 변환하여 리스트에 추가
notifications.forEach(notification -> {
StudyNotificationDTO notificationDTO = StudyNotificationDTO.builder()
.notificationId(notification.getId())
.studyId(notification.getStudy().getId())
.createdAt(notification.getCreatedAt())
.type(notification.getType())
.studyTitle(notification.getStudy().getTitle())
.studyProfileImage(notification.getStudy().getProfileImage())
.isChecked(notification.getIsChecked())
.build();
.notificationId(notification.getId())
.studyId(notification.getStudy().getId())
.createdAt(notification.getCreatedAt())
.type(notification.getType())
.studyTitle(notification.getStudy().getTitle())
.studyProfileImage(notification.getStudy().getProfileImage())
.isChecked(notification.getIsChecked())
.build();
notificationDTOs.add(notificationDTO);
});

// DTO 리스트를 반환
return StudyNotificationListDTO.builder()
.notifications(notificationDTOs)
.totalNotificationCount((long) notificationDTOs.size())
.uncheckedNotificationCount((long) (int) notificationDTOs.stream().filter(notificationDTO -> !notificationDTO.getIsChecked()).count())
.build();
.notifications(notificationDTOs)
.totalNotificationCount((long) notificationDTOs.size())
.uncheckedNotificationCount((long) (int) notificationDTOs.stream()
.filter(notificationDTO -> !notificationDTO.getIsChecked()).count())
.build();
}

/**
* 회원에게 생성된 알림을 전체 조회합니다.
*
* @param memberId 사용자 ID
* @param pageable 페이징 정보
* @return 알림 목록
Expand All @@ -79,11 +82,12 @@ public NotificationListDTO getAllNotifications(Long memberId, Pageable pageable)

// 특정 회원에게 생성된 알림을 조회
List<Notification> notifications = notificationRepository.findByMemberIdAndTypeNot(
memberId, pageable, NotifyType.STUDY_APPLY);
memberId, pageable, NotifyType.STUDY_APPLY);

// 알림이 존재하지 않는 경우
if (notifications.isEmpty())
if (notifications.isEmpty()) {
throw new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND);
}

// DTO를 담을 리스트 생성
List<NotificationDTO> notificationDTOs = new ArrayList<>();
Expand All @@ -106,12 +110,12 @@ public NotificationListDTO getAllNotifications(Long memberId, Pageable pageable)

// DTO 리스트를 반환
return NotificationListDTO.builder()
.notifications(notificationDTOs)
.totalNotificationCount((long) notificationDTOs.size())
.uncheckedNotificationCount((long) (int) notificationDTOs.stream().filter(notificationDTO -> !notificationDTO.getIsChecked()).count())
.build();
.notifications(notificationDTOs)
.totalNotificationCount((long) notificationDTOs.size())
.uncheckedNotificationCount((long) (int) notificationDTOs.stream()
.filter(notificationDTO -> !notificationDTO.getIsChecked()).count())
.build();
}



}
Original file line number Diff line number Diff line change
@@ -1,67 +1,31 @@
package com.example.spot.notification.application.notification;
package com.example.spot.notification.application.impl;

import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.GeneralException;
import com.example.spot.notification.application.HandleAppliedStudyParticipationUseCase;
import com.example.spot.notification.domain.Notification;
import com.example.spot.notification.domain.NotificationRepository;
import com.example.spot.notification.domain.enums.NotifyType;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationProcessDTO;
import com.example.spot.study.domain.association.StudyMember;
import com.example.spot.study.domain.enums.StudyApplicationStatus;
import com.example.spot.notification.domain.enums.NotifyType;
import com.example.spot.study.domain.repository.StudyMemberRepository;
import com.example.spot.notification.presentation.dto.notification.NotificationResponseDTO.NotificationProcessDTO;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import com.example.spot.notification.domain.NotificationRepository;

import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class NotificationCommandServiceImpl implements NotificationCommandService {
@RequiredArgsConstructor
public class HandleAppliedStudyParticipationUseCaseImpl implements HandleAppliedStudyParticipationUseCase {

private final StudyMemberRepository studyMemberRepository;
private final NotificationRepository notificationRepository;

/**
* 알림을 읽음 처리 합니다. 이미 읽은 알림인 경우 예외를 발생시킵니다.
* @param memberId 사용자 ID
* @param notificationId 알림 ID
* @return 알림 읽음 처리 결과 및 처리 일시
* @throws GeneralException 알림이 존재하지 않거나 이미 읽음 처리된 경우
* @throws GeneralException 알림이 사용자에게 속하지 않는 경우
* @throws GeneralException 알림이 이미 읽음 처리된 경우
* @see NotificationProcessDTO
*/
@Override
public NotificationProcessDTO readNotification(Long memberId, Long notificationId) {

// 알림 조회
Notification notification = notificationRepository.findById(notificationId).orElseThrow(
() -> new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND));

// 알림이 사용자에게 속하지 않는 경우
if (!Objects.equals(notification.getMember().getId(), memberId))
throw new GeneralException(ErrorStatus._NOTIFICATION_IS_NOT_BELONG_TO_MEMBER);

// 이미 읽음 처리된 경우
if (notification.getIsChecked())
throw new GeneralException(ErrorStatus._NOTIFICATION_ALREADY_READ);

// 알림 읽음 처리
notification.markAsRead();

// 알림 읽음 처리 결과 반환
return NotificationProcessDTO.builder()
.isAccept(notification.getIsChecked())
.processedAt(notification.getUpdatedAt())
.build();
}
private final StudyMemberRepository studyMemberRepository;

/**
* 스터디 신청 알림에 대한 처리를 수행합니다. isAccept가 true인 경우 스터디 신청을 수락하고, false인 경우 거절합니다.
* @param studyId 스터디 ID
*
* @param studyId 스터디 ID
* @param memberId 사용자 ID
* @param isAccept 스터디 신청 수락 여부
* @return 스터디 신청 처리 결과 및 처리 일시
Expand All @@ -74,22 +38,24 @@ public NotificationProcessDTO joinAppliedStudy(Long studyId, Long memberId, bool

// 스터디 신청 알림 조회 -
Notification notification = notificationRepository.findByMemberIdAndStudyIdAndTypeAndIsChecked(
memberId, studyId, NotifyType.STUDY_APPLY, false).orElseThrow(() -> new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND));
memberId, studyId, NotifyType.STUDY_APPLY, false)
.orElseThrow(() -> new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND));

// 이미 읽음 처리된 경우
if (notification.getIsChecked())
if (notification.getIsChecked()) {
throw new GeneralException(ErrorStatus._NOTIFICATION_ALREADY_READ);
}

// 스터디 신청자 조회
StudyMember studyMember = studyMemberRepository.findByMemberIdAndStudyIdAndStatus(
memberId, studyId, StudyApplicationStatus.AWAITING_SELF_APPROVAL).orElseThrow(
() -> new GeneralException(ErrorStatus._STUDY_APPLICANT_NOT_FOUND));
memberId, studyId, StudyApplicationStatus.AWAITING_SELF_APPROVAL).orElseThrow(
() -> new GeneralException(ErrorStatus._STUDY_APPLICANT_NOT_FOUND));

// 스터디 신청 처리
if (isAccept) {
// 스터디 신청 수락
studyMember.setStatus(StudyApplicationStatus.APPROVED);
}else {
} else {
// 스터디 신청 거절
studyMember.setStatus(StudyApplicationStatus.REJECTED);
}
Expand All @@ -98,9 +64,8 @@ public NotificationProcessDTO joinAppliedStudy(Long studyId, Long memberId, bool

// 스터디 신청 처리 결과 반환
return NotificationProcessDTO.builder()
.isAccept(isAccept)
.processedAt(notification.getUpdatedAt())
.build();
.isAccept(isAccept)
.processedAt(notification.getUpdatedAt())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.spot.notification.application.impl;

import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.GeneralException;
import com.example.spot.notification.application.ReadNotificationUseCase;
import com.example.spot.notification.domain.Notification;
import com.example.spot.notification.domain.NotificationRepository;
import com.example.spot.notification.presentation.dto.response.NotificationResponseDTO.NotificationProcessDTO;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
public class ReadNotificationUseCaseImpl implements ReadNotificationUseCase {

private final NotificationRepository notificationRepository;

/**
* 알림을 읽음 처리 합니다. 이미 읽은 알림인 경우 예외를 발생시킵니다.
*
* @param memberId 사용자 ID
* @param notificationId 알림 ID
* @return 알림 읽음 처리 결과 및 처리 일시
* @throws GeneralException 알림이 존재하지 않거나 이미 읽음 처리된 경우
* @throws GeneralException 알림이 사용자에게 속하지 않는 경우
* @throws GeneralException 알림이 이미 읽음 처리된 경우
* @see NotificationProcessDTO
*/
@Override
public NotificationProcessDTO readNotification(Long memberId, Long notificationId) {

// 알림 조회
Notification notification = notificationRepository.findById(notificationId).orElseThrow(
() -> new GeneralException(ErrorStatus._NOTIFICATION_NOT_FOUND));

// 알림이 사용자에게 속하지 않는 경우
if (!Objects.equals(notification.getMember().getId(), memberId)) {
throw new GeneralException(ErrorStatus._NOTIFICATION_IS_NOT_BELONG_TO_MEMBER);
}

// 이미 읽음 처리된 경우
if (notification.getIsChecked()) {
throw new GeneralException(ErrorStatus._NOTIFICATION_ALREADY_READ);
}

// 알림 읽음 처리
notification.markAsRead();

// 알림 읽음 처리 결과 반환
return NotificationProcessDTO.builder()
.isAccept(notification.getIsChecked())
.processedAt(notification.getUpdatedAt())
.build();
}
}

This file was deleted.

This file was deleted.

Loading