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 @@ -65,6 +65,8 @@ public ReplyCreateResDTO createReply(Long feedbackId, Long userId, ReplyCreateRe
if (userId != null) {
user = userRepository.findByIdAndDeletedAtIsNull(userId)
.orElseThrow(() -> new BaseException(CommonErrorCode.NOT_FOUND));
// 회원이 원 피드백 영상의 프로젝트 멤버인지 검증
validateMemberAccess(userId, feedback.getVideo().getProject().getId());
} else {
// 게스트: 원 피드백의 영상에 접근할 자격이 있는지 검증 후 Guest 확보
guest = validateGuestAccess(req.guestId(), feedback.getVideo().getId());
Expand Down Expand Up @@ -130,6 +132,16 @@ private void validateWriter(Long userId, Long guestId) {
}
}

// 회원이 해당 프로젝트의 활성 멤버인지 검증
// 게스트의 validateGuestAccess와 대칭 — 회원은 프로젝트 멤버 자격으로 접근 인가
private void validateMemberAccess(Long userId, Long projectId) {
boolean isMember = projectMemberRepository
.existsByProjectIdAndUserIdAndLeftAtIsNull(projectId, userId);
if (!isMember) {
throw new BaseException(CommonErrorCode.FORBIDDEN);
}
}

// 게스트가 해당 영상에 접근할 자격이 있는지 검증하고, 검증된 Guest를 반환
// Guest → ShareLink → Video 체인으로 소유 여부 확인
private Guest validateGuestAccess(Long guestId, Long videoId) {
Expand Down Expand Up @@ -159,9 +171,11 @@ public ReplyListResDTO getReplyList(Long feedbackId, Long userId, Long guestId,
.filter(f -> f.getDeletedAt() == null)
.orElseThrow(() -> new BaseException(CommonErrorCode.NOT_FOUND));

// 2. 게스트가 조회하는 경우 원 피드백의 영상에 접근 자격이 있는지 검증
// 회원이 아니면 guestId 필수 — 익명(둘 다 null) 조회 차단
if (userId == null) {
// 2. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유
// 회원도 게스트도 아니면(둘 다 null) 익명 조회 차단
if (userId != null) {
validateMemberAccess(userId, feedback.getVideo().getProject().getId());
} else {
if (guestId == null) {
throw new BaseException(ShareLinkErrorCode.GUEST_ACCESS_DENIED);
}
Expand Down Expand Up @@ -204,8 +218,10 @@ public ReplyUpdateResDTO updateReply(Long replyId, Long userId, ReplyUpdateReqDT
// 2. 작성자 검증
validateWriter(userId, req.guestId());

// 3. 게스트면 이 답글의 영상에 접근 자격이 있는지 검증 (답글 → 피드백 → 영상)
if (userId == null) {
// 3. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유 (답글 → 피드백 → 영상)
if (userId != null) {
validateMemberAccess(userId, reply.getFeedback().getVideo().getProject().getId());
} else {
validateGuestAccess(req.guestId(), reply.getFeedback().getVideo().getId());
}

Expand Down Expand Up @@ -234,8 +250,10 @@ public void deleteReply(Long replyId, Long userId, Long guestId) {
// 2. 작성자 검증
validateWriter(userId, guestId);

// 3. 게스트면 이 답글의 영상에 접근 자격이 있는지 검증 (답글 → 피드백 → 영상)
if (userId == null) {
// 3. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유 (답글 → 피드백 → 영상)
if (userId != null) {
validateMemberAccess(userId, reply.getFeedback().getVideo().getProject().getId());
} else {
validateGuestAccess(guestId, reply.getFeedback().getVideo().getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public FeedbackCreateResDTO createFeedback(Long videoId, Long userId, FeedbackCr
if (userId != null) {
user = userRepository.findByIdAndDeletedAtIsNull(userId)
.orElseThrow(() -> new BaseException(CommonErrorCode.NOT_FOUND));
// 회원이 이 영상의 프로젝트 멤버인지 검증
validateMemberAccess(userId, video.getProject().getId());
} else {
// 게스트: 이 영상에 접근할 자격이 있는지 검증 후 Guest 확보
guest = validateGuestAccess(req.guestId(), videoId);
Expand Down Expand Up @@ -142,8 +144,10 @@ public FeedbackUpdateResDTO updateFeedback(Long feedbackId, Long userId, Feedbac
// 2. 작성자 검증
validateWriter(userId, req.guestId());

// 3. 게스트면 이 피드백의 영상에 접근 자격이 있는지 검증
if (userId == null) {
// 3. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유
if (userId != null) {
validateMemberAccess(userId, feedback.getVideo().getProject().getId());
} else {
validateGuestAccess(req.guestId(), feedback.getVideo().getId());
}

Expand All @@ -170,6 +174,16 @@ private void validateWriter(Long userId, Long guestId) {
}
}

// 회원이 해당 프로젝트의 활성 멤버인지 검증
// 게스트의 validateGuestAccess와 대칭 — 회원은 프로젝트 멤버 자격으로 접근 인가
private void validateMemberAccess(Long userId, Long projectId) {
boolean isMember = projectMemberRepository
.existsByProjectIdAndUserIdAndLeftAtIsNull(projectId, userId);
if (!isMember) {
throw new BaseException(CommonErrorCode.FORBIDDEN);
}
}

// 게스트가 해당 영상에 접근할 자격이 있는지 검증하고, 검증된 Guest를 반환
// Guest → ShareLink → Video 체인으로 소유 여부 확인
private Guest validateGuestAccess(Long guestId, Long videoId) {
Expand Down Expand Up @@ -202,8 +216,10 @@ public void deleteFeedback(Long feedbackId, Long userId, Long guestId) {
// 2. 작성자 검증
validateWriter(userId, guestId);

// 3. 게스트면 이 피드백의 영상에 접근 자격이 있는지 검증
if (userId == null) {
// 3. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유
if (userId != null) {
validateMemberAccess(userId, feedback.getVideo().getProject().getId());
} else {
validateGuestAccess(guestId, feedback.getVideo().getId());
}

Expand All @@ -230,9 +246,16 @@ select count(v) from Video v where v.id = :videoId
throw new BaseException(CommonErrorCode.NOT_FOUND);
}

// 2. 게스트가 조회하는 경우 이 영상에 접근 자격이 있는지 검증
// 회원이 아니면 guestId 필수 — 익명(둘 다 null) 조회 차단
if (userId == null) {
// 2. 접근 검증 — 회원은 프로젝트 멤버, 게스트는 공유링크 소유
// 회원도 게스트도 아니면(둘 다 null) 익명 조회 차단
if (userId != null) {
Long projectId = entityManagerProvider.getObject().createQuery("""
select v.project.id from Video v where v.id = :videoId
""", Long.class)
.setParameter("videoId", videoId)
.getSingleResult();
validateMemberAccess(userId, projectId);
} else {
if (guestId == null) {
throw new BaseException(ShareLinkErrorCode.GUEST_ACCESS_DENIED);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ void setUp() {

stubVideoLookup(video);
given(userRepository.findByIdAndDeletedAtIsNull(1L)).willReturn(Optional.of(user));
// 정상 회원은 프로젝트 멤버 — 멤버 검증 통과하도록 stub
given(projectMemberRepository.existsByProjectIdAndUserIdAndLeftAtIsNull(101L, 1L)).willReturn(true);
given(feedbackConverter.toFeedback(eq(video), eq(user), eq(null), any())).willReturn(feedback);
given(feedbackRepository.save(feedback)).willReturn(feedback);

Expand Down Expand Up @@ -130,6 +132,8 @@ void setUp() {
given(feedback.getDeletedAt()).willReturn(null);
given(feedback.getVideo()).willReturn(video);
given(userRepository.findByIdAndDeletedAtIsNull(1L)).willReturn(Optional.of(user));
// 정상 회원은 프로젝트 멤버 — 멤버 검증 통과하도록 stub
given(projectMemberRepository.existsByProjectIdAndUserIdAndLeftAtIsNull(101L, 1L)).willReturn(true);
given(feedbackDetailConverter.toFeedbackDetail(eq(feedback), eq(user), eq(null), any())).willReturn(reply);
given(feedbackDetailRepository.save(reply)).willReturn(reply);

Expand Down Expand Up @@ -184,4 +188,4 @@ private Users user(Long userId) {
given(user.getId()).willReturn(userId);
return user;
}
}
}
Loading