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
@@ -1,12 +1,15 @@
package ku_rum.backend.domain.notice.application;

import ku_rum.backend.domain.bookmark.domain.repository.BookmarkRepository;
import ku_rum.backend.domain.notice.domain.Notice;
import ku_rum.backend.domain.notice.domain.NoticeDetail;
import ku_rum.backend.domain.notice.domain.PublishStatus;
import ku_rum.backend.domain.notice.domain.repository.NoticeDetailRepository;
import ku_rum.backend.domain.notice.domain.repository.NoticeRepository;
import ku_rum.backend.domain.notice.dto.response.NoticeDetailResponse;
import ku_rum.backend.domain.notice.dto.response.NoticeResponse;
import ku_rum.backend.domain.user.application.UserService;
import ku_rum.backend.domain.user.domain.User;
import ku_rum.backend.global.exception.global.GlobalException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
Expand All @@ -29,18 +32,22 @@ public class NoticeService {

private final NoticeRepository noticeRepository;
private final NoticeDetailRepository noticeDetailRepository;
private final BookmarkRepository bookmarkRepository;
private final UserService userService;

public Page<NoticeResponse> findByCategory(Long categoryId, Pageable pageable) {
return noticeRepository.findByCategoryIdAndPublishStatus(categoryId, PublishStatus.SUCCESS_CRAWLING, pageable)
.map(NoticeResponse::from);
}

public NoticeDetailResponse findByNoticeId(Long noticeId) {
User user = userService.getUser();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "NoticeService.java" -o -name "NoticeController.java" -o -name "UserService.java" | head -20

Repository: KU-rum/backend

Length of output: 285


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/domain/notice/application/NoticeService.java | head -80

Repository: KU-rum/backend

Length of output: 4328


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/domain/user/application/UserService.java | grep -A 30 "getUser()"

Repository: KU-rum/backend

Length of output: 4481


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/domain/notice/presentation/NoticeController.java

Repository: KU-rum/backend

Length of output: 2574


🏁 Script executed:

find . -type f -name "*SecurityConfig*" -o -name "*Security*.java" | grep -E "(config|security)" | head -20

Repository: KU-rum/backend

Length of output: 122


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/global/config/SecurityConfig.java

Repository: KU-rum/backend

Length of output: 7919


🏁 Script executed:

find . -type f -name "AuthorizationList.java" -o -name "*AuthorizationList*"

Repository: KU-rum/backend

Length of output: 125


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/global/config/AuthorizationList.java

Repository: KU-rum/backend

Length of output: 2545


🏁 Script executed:

find . -type f -name "UserUtil.java"

Repository: KU-rum/backend

Length of output: 115


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/global/utill/UserUtil.java

Repository: KU-rum/backend

Length of output: 1601


🏁 Script executed:

cat -n ./src/main/java/ku_rum/backend/global/security/CustomUserDetails.java | head -40

Repository: KU-rum/backend

Length of output: 1784


공지사항 상세 조회 엔드포인트에서 인증되지 않은 사용자 접근 시 예외 발생

/api/v1/notices/{noticeId} 엔드포인트는 AuthorizationList/api/v1/notices/**로 등록되어 있어 인증 없이 접근 가능합니다. 그러나 NoticeService.findByNoticeId() 메서드(44줄)에서 userService.getUser()를 무조건 호출하는데, 이는 인증되지 않은 사용자의 SecurityContext에서 CustomUserDetails를 찾지 못해 ClassCastException 또는 NullPointerException을 발생시킵니다.

해결 방법:

  • 인증된 사용자인지 확인 후 북마크 여부만 처리하거나
  • 엔드포인트 자체에 인증 요구 사항 추가

Notice notice = findNoticeByNoticeId(noticeId);
NoticeDetail noticeDetail = noticeDetailRepository.findByNotice(notice)
.orElseThrow(() -> new GlobalException(NO_SUCH_NOTICE_DETAIL));
String encodedHtml = noticeDetail.getHtmlContent();
return new NoticeDetailResponse(noticeDetail.getNotice().getId(), encodedHtml, notice.getLink(), noticeDetail.getNotice().getTitle(), noticeDetail.getNotice().getPubDate());
boolean isBookmark = bookmarkRepository.existsByUserAndNotice(user, notice);
return new NoticeDetailResponse(noticeDetail.getNotice().getId(), encodedHtml, notice.getLink(), noticeDetail.getNotice().getTitle(), noticeDetail.getNotice().getPubDate(), isBookmark);
//byte[] decodedBytes = Base64.getDecoder().decode(encodedHtml);
//String htmlContent = new String(decodedBytes, StandardCharsets.UTF_8);
//return new NoticeDetailResponse(noticeDetail.getNotice().getId(), htmlContent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public record NoticeDetailResponse(
String content,
String link,
String title,
LocalDateTime pubdate
LocalDateTime pubdate,
boolean isBookmark
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ void getNoticeDetailById() throws Exception {
String htmlContent = "<div>공지 상세 내용</div>";
String link = "url";
String title = "공지사항 제목";
NoticeDetailResponse noticeDetailResponse = new NoticeDetailResponse(noticeId, htmlContent, link, title, LocalDateTime.now());
boolean isBookmark = true;
NoticeDetailResponse noticeDetailResponse = new NoticeDetailResponse(noticeId, htmlContent, link, title, LocalDateTime.now(), isBookmark);
Comment on lines +121 to +122
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

테스트에 isBookmark 필드 검증을 추가하세요.

isBookmark 필드를 생성자에 추가했지만, 응답 검증(assertion)이 누락되었습니다. Line 136 이후에 isBookmark 필드에 대한 검증을 추가해야 합니다.

🔎 제안하는 수정 사항

Line 136 다음에 아래 assertion을 추가하세요:

                 .andExpect(jsonPath("$.data.pubdate").exists())
+                .andExpect(jsonPath("$.data.isBookmark").value(true))

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/test/java/ku_rum/backend/domain/notice/presentation/NoticeControllerTest.java
around lines 121 to 122 and referencing the assertions area after line 136, the
test constructs NoticeDetailResponse with isBookmark=true but never asserts that
field; add an assertion verifying the response's isBookmark value (e.g.,
assertTrue or assertEquals(true, ...)) immediately after the existing assertions
at line 136 to validate the bookmark flag.

given(noticeService.findByNoticeId(eq(noticeId)))
.willReturn(noticeDetailResponse);

Expand Down
Loading