diff --git a/src/main/java/com/gamzabat/algohub/feature/notice/domain/NoticeRead.java b/src/main/java/com/gamzabat/algohub/feature/notice/domain/NoticeRead.java new file mode 100644 index 00000000..70ee20f5 --- /dev/null +++ b/src/main/java/com/gamzabat/algohub/feature/notice/domain/NoticeRead.java @@ -0,0 +1,35 @@ +package com.gamzabat.algohub.feature.notice.domain; + +import com.gamzabat.algohub.feature.user.domain.User; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +public class NoticeRead { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "notice_id") + private Notice notice; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @Builder + public NoticeRead(Notice notice, User user) { + this.notice = notice; + this.user = user; + } +} diff --git a/src/main/java/com/gamzabat/algohub/feature/notice/dto/GetNoticeResponse.java b/src/main/java/com/gamzabat/algohub/feature/notice/dto/GetNoticeResponse.java index 6eff899b..e6e0cbd3 100644 --- a/src/main/java/com/gamzabat/algohub/feature/notice/dto/GetNoticeResponse.java +++ b/src/main/java/com/gamzabat/algohub/feature/notice/dto/GetNoticeResponse.java @@ -11,9 +11,10 @@ public record GetNoticeResponse(String author, String content, String title, String category, - String createAt) { + String createAt, + boolean isRead) { - public static GetNoticeResponse toDTO(Notice notice) { + public static GetNoticeResponse toDTO(Notice notice, boolean isRead) { return GetNoticeResponse.builder() .author(notice.getAuthor().getNickname()) .noticeId(notice.getId()) @@ -21,7 +22,7 @@ public static GetNoticeResponse toDTO(Notice notice) { .content(notice.getContent()) .category(notice.getCategory()) .createAt(DateFormatUtil.formatDate(notice.getCreatedAt().toLocalDate())) + .isRead(isRead) .build(); - } } diff --git a/src/main/java/com/gamzabat/algohub/feature/notice/repository/NoticeReadRepository.java b/src/main/java/com/gamzabat/algohub/feature/notice/repository/NoticeReadRepository.java new file mode 100644 index 00000000..7161a670 --- /dev/null +++ b/src/main/java/com/gamzabat/algohub/feature/notice/repository/NoticeReadRepository.java @@ -0,0 +1,11 @@ +package com.gamzabat.algohub.feature.notice.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.gamzabat.algohub.feature.notice.domain.Notice; +import com.gamzabat.algohub.feature.notice.domain.NoticeRead; +import com.gamzabat.algohub.feature.user.domain.User; + +public interface NoticeReadRepository extends JpaRepository { + boolean existsByNoticeAndUser(Notice notice, User user); +} diff --git a/src/main/java/com/gamzabat/algohub/feature/notice/service/NoticeService.java b/src/main/java/com/gamzabat/algohub/feature/notice/service/NoticeService.java index 784e15d3..db7abd25 100644 --- a/src/main/java/com/gamzabat/algohub/feature/notice/service/NoticeService.java +++ b/src/main/java/com/gamzabat/algohub/feature/notice/service/NoticeService.java @@ -18,11 +18,13 @@ import com.gamzabat.algohub.feature.group.studygroup.repository.GroupMemberRepository; import com.gamzabat.algohub.feature.group.studygroup.repository.StudyGroupRepository; import com.gamzabat.algohub.feature.notice.domain.Notice; +import com.gamzabat.algohub.feature.notice.domain.NoticeRead; import com.gamzabat.algohub.feature.notice.dto.CreateNoticeRequest; import com.gamzabat.algohub.feature.notice.dto.GetNoticeResponse; import com.gamzabat.algohub.feature.notice.dto.UpdateNoticeRequest; import com.gamzabat.algohub.feature.notice.exception.NoticeValidationException; import com.gamzabat.algohub.feature.notice.repository.NoticeCommentRepository; +import com.gamzabat.algohub.feature.notice.repository.NoticeReadRepository; import com.gamzabat.algohub.feature.notice.repository.NoticeRepository; import com.gamzabat.algohub.feature.user.domain.User; @@ -38,6 +40,7 @@ public class NoticeService { private final NoticeCommentRepository noticeCommentRepository; private final StudyGroupRepository studyGroupRepository; private final GroupMemberRepository groupMemberRepository; + private final NoticeReadRepository noticeReadRepository; @Transactional public void createNotice(@AuthedUser User user, CreateNoticeRequest request) { @@ -68,6 +71,8 @@ public GetNoticeResponse getNotice(@AuthedUser User user, Long noticeId) { if (!groupMemberRepository.existsByUserAndStudyGroup(user, notice.getStudyGroup())) throw new StudyGroupValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 스터디 그룹 입니다."); + markNoticeAsRead(user, notice); + log.info("success to get notice"); return GetNoticeResponse.builder() .author(notice.getAuthor().getNickname()) @@ -76,6 +81,7 @@ public GetNoticeResponse getNotice(@AuthedUser User user, Long noticeId) { .content(notice.getContent()) .category(notice.getCategory()) .createAt(DateFormatUtil.formatDate(notice.getCreatedAt().toLocalDate())) + .isRead(true) .build(); } @@ -87,7 +93,9 @@ public List getNoticeList(@AuthedUser User user, Long studyGr throw new GroupMemberValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 스터디 그룹입니다"); List list = noticeRepository.findAllByStudyGroup(studyGroup); - List result = list.stream().map(GetNoticeResponse::toDTO).toList(); + List result = list.stream().map( + notice -> GetNoticeResponse.toDTO(notice, noticeReadRepository.existsByNoticeAndUser(notice, user)) + ).toList(); log.info("success to get notice list"); return result; } @@ -123,4 +131,12 @@ private void validateStudyGroupExists(Notice notice) { .orElseThrow(() -> new StudyGroupValidationException(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 스터디 그룹입니다")); } + private void markNoticeAsRead(User user, Notice notice) { + if (!noticeReadRepository.existsByNoticeAndUser(notice, user)) { + noticeReadRepository.save( + NoticeRead.builder().notice(notice).user(user).build() + ); + } + log.info("success to read notice. userId: {}, noticeId: {}", user.getId(), notice.getId()); + } } diff --git a/src/test/java/com/gamzabat/algohub/service/NoticeServiceTest.java b/src/test/java/com/gamzabat/algohub/service/NoticeServiceTest.java index a79eb091..44833bca 100644 --- a/src/test/java/com/gamzabat/algohub/service/NoticeServiceTest.java +++ b/src/test/java/com/gamzabat/algohub/service/NoticeServiceTest.java @@ -31,11 +31,13 @@ import com.gamzabat.algohub.feature.group.studygroup.repository.GroupMemberRepository; import com.gamzabat.algohub.feature.group.studygroup.repository.StudyGroupRepository; import com.gamzabat.algohub.feature.notice.domain.Notice; +import com.gamzabat.algohub.feature.notice.domain.NoticeRead; import com.gamzabat.algohub.feature.notice.dto.CreateNoticeRequest; import com.gamzabat.algohub.feature.notice.dto.GetNoticeResponse; import com.gamzabat.algohub.feature.notice.dto.UpdateNoticeRequest; import com.gamzabat.algohub.feature.notice.exception.NoticeValidationException; import com.gamzabat.algohub.feature.notice.repository.NoticeCommentRepository; +import com.gamzabat.algohub.feature.notice.repository.NoticeReadRepository; import com.gamzabat.algohub.feature.notice.repository.NoticeRepository; import com.gamzabat.algohub.feature.notice.service.NoticeService; import com.gamzabat.algohub.feature.user.domain.User; @@ -52,6 +54,8 @@ public class NoticeServiceTest { GroupMemberRepository groupMemberRepository; @Mock private NoticeCommentRepository noticeCommentRepository; + @Mock + private NoticeReadRepository noticeReadRepository; @Captor private ArgumentCaptor noticeCaptor; @@ -183,6 +187,7 @@ void getNoticeSuccess_1() { assertThat(response.category()).isEqualTo("category"); assertThat(response.createAt()).isEqualTo(DateFormatUtil.formatDate(LocalDateTime.now().toLocalDate())); assertThat(response.noticeId()).isEqualTo(1000L); + verify(noticeReadRepository, times(1)).save(any(NoticeRead.class)); } @Test @@ -247,6 +252,7 @@ void getNoticeListSuccess_1() { assertThat(result.get(i).content()).isEqualTo("content" + i); assertThat(result.get(i).title()).isEqualTo("title" + i); assertThat(result.get(i).category()).isEqualTo("category" + i); + assertThat(result.get(i).isRead()).isFalse(); } }