-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DDING-55] Feed 삭제 API 구현 #200
Changes from all commits
a26f1de
f845b05
f893e77
3846a83
34ef7ed
c982749
639d68a
eb38e0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,5 @@ public interface FacadeClubFeedService { | |
|
||
void update(UpdateFeedCommand command); | ||
|
||
void delete(Long feedId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ public void create(CreateFeedCommand command) { | |
|
||
if (feed.isImage()) { | ||
fileMetaDataService.updateStatusToCoupled(command.mediaId(), DomainType.FEED_IMAGE, createdId); | ||
return; | ||
} | ||
|
||
if (feed.isVideo()) { | ||
|
@@ -43,4 +44,12 @@ public void update(UpdateFeedCommand command) { | |
Feed updateFeed = command.toEntity(); | ||
originFeed.update(updateFeed); | ||
} | ||
|
||
@Override | ||
@Transactional | ||
public void delete(Long feedId) { | ||
Feed feed = feedService.getById(feedId); | ||
feedService.delete(feed); | ||
fileMetaDataService.updateStatusToDelete(feed.getFeedType().getDomainType(), feed.getId()); | ||
} | ||
Comment on lines
+50
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 권한 검증 로직 추가 필요 현재 구현에서는 피드 삭제 전에 사용자의 권한이나 소유권을 확인하는 로직이 없습니다. 보안을 위해 삭제 권한 검증을 추가하는 것이 좋겠습니다. 예시 구현: @Transactional
public void delete(Long feedId) {
Feed feed = feedService.getById(feedId);
+ Club club = clubService.getByUserId(SecurityUtil.getCurrentUserId());
+ if (!feed.getClub().equals(club)) {
+ throw new UnauthorizedException("피드 삭제 권한이 없습니다.");
+ }
feedService.delete(feed);
fileMetaDataService.updateStatusToDelete(feed.getFeedType().getDomainType(), feed.getId());
}
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,4 +12,6 @@ public interface FeedService { | |
Feed getById(Long feedId); | ||
|
||
Long create(Feed feed); | ||
|
||
void delete(Feed feed); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; | ||
import ddingdong.ddingdongBE.domain.filemetadata.entity.FileStatus; | ||
import ddingdong.ddingdongBE.domain.filemetadata.repository.FileMetaDataRepository; | ||
import ddingdong.ddingdongBE.domain.filemetadata.service.FileMetaDataServiceImpl; | ||
import ddingdong.ddingdongBE.domain.scorehistory.entity.Score; | ||
import ddingdong.ddingdongBE.domain.user.entity.User; | ||
import ddingdong.ddingdongBE.domain.user.repository.UserRepository; | ||
|
@@ -47,6 +48,8 @@ class FacadeClubFeedServiceImplTest extends TestContainerSupport { | |
private EntityManager entityManager; | ||
|
||
private final FixtureMonkey fixtureMonkey = FixtureMonkeyFactory.getNotNullBuilderIntrospectorMonkey(); | ||
@Autowired | ||
private FileMetaDataServiceImpl fileMetaDataServiceImpl; | ||
|
||
@DisplayName("요청된 Command를 사용하여 feed를 생성하며, FileMetaData를 Couple 상태로 변경한다.") | ||
@Test | ||
|
@@ -111,4 +114,72 @@ void update() { | |
assertThat(finded).isNotNull(); | ||
assertThat(finded.getActivityContent()).isEqualTo("변경된 활동내용"); | ||
} | ||
|
||
@DisplayName("주어진 feedId를 가진 Feed 엔터티를 삭제 및 fileMetaData 상태를 DELETED로 변경 - IMAGE") | ||
@Test | ||
void deleteImage() { | ||
// given | ||
UUID uuid = UuidCreator.getTimeOrderedEpoch(); | ||
|
||
|
||
Feed savedFeed = feedRepository.save( | ||
fixtureMonkey.giveMeBuilder(Feed.class) | ||
.set("feedType", FeedType.IMAGE) | ||
.set("activityContent", "활동내용") | ||
.set("club", null) | ||
.sample() | ||
); | ||
fileMetaDataRepository.save( | ||
fixtureMonkey.giveMeBuilder(FileMetaData.class) | ||
.set("id", uuid) | ||
.set("entityId", savedFeed.getId()) | ||
.set("domainType", DomainType.FEED_IMAGE) | ||
.set("fileStatus", FileStatus.COUPLED) | ||
.sample() | ||
); | ||
entityManager.flush(); | ||
// when | ||
facadeClubFeedService.delete(savedFeed.getId()); | ||
entityManager.flush(); | ||
// then | ||
Feed feed = feedRepository.findById(savedFeed.getId()).orElse(null); | ||
FileMetaData fileMetaData = fileMetaDataRepository.findById(uuid).orElse(null); | ||
assertThat(feed).isNull(); | ||
assertThat(fileMetaData).isNotNull(); | ||
assertThat(fileMetaData.getFileStatus()).isEqualTo(FileStatus.DELETED); | ||
} | ||
|
||
@DisplayName("주어진 feedId를 가진 Feed 엔터티를 삭제 및 fileMetaData 상태를 DELETED로 변경 - VIDEO") | ||
@Test | ||
void deleteVideo() { | ||
// given | ||
UUID uuid = UuidCreator.getTimeOrderedEpoch(); | ||
|
||
|
||
Feed savedFeed = feedRepository.save( | ||
fixtureMonkey.giveMeBuilder(Feed.class) | ||
.set("feedType", FeedType.VIDEO) | ||
.set("activityContent", "활동내용") | ||
.set("club", null) | ||
.sample() | ||
); | ||
fileMetaDataRepository.save( | ||
fixtureMonkey.giveMeBuilder(FileMetaData.class) | ||
.set("id", uuid) | ||
.set("entityId", savedFeed.getId()) | ||
.set("domainType", DomainType.FEED_VIDEO) | ||
.set("fileStatus", FileStatus.COUPLED) | ||
.sample() | ||
); | ||
entityManager.flush(); | ||
// when | ||
facadeClubFeedService.delete(savedFeed.getId()); | ||
entityManager.flush(); | ||
// then | ||
Feed feed = feedRepository.findById(savedFeed.getId()).orElse(null); | ||
FileMetaData fileMetaData = fileMetaDataRepository.findById(uuid).orElse(null); | ||
assertThat(feed).isNull(); | ||
assertThat(fileMetaData).isNotNull(); | ||
assertThat(fileMetaData.getFileStatus()).isEqualTo(FileStatus.DELETED); | ||
} | ||
Comment on lines
+152
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 비디오 Feed 삭제 테스트의 중복 코드를 제거해야 합니다.
다음과 같이 개선해 보시는 것은 어떨까요?: @ParameterizedTest
@EnumSource(FeedType.class)
void deleteFeed_ShouldDeleteFeedAndUpdateFileMetaData(FeedType feedType) {
// given
UUID uuid = UuidCreator.getTimeOrderedEpoch();
Feed savedFeed = createFeed(feedType);
createFileMetaData(uuid, savedFeed,
feedType == FeedType.IMAGE ? DomainType.FEED_IMAGE : DomainType.FEED_VIDEO);
entityManager.flush();
// when
facadeClubFeedService.delete(savedFeed.getId());
entityManager.flush();
// then
assertThat(feedRepository.findById(savedFeed.getId())).isEmpty();
FileMetaData fileMetaData = fileMetaDataRepository.findById(uuid).orElse(null);
assertThat(fileMetaData)
.isNotNull()
.extracting(FileMetaData::getFileStatus)
.isEqualTo(FileStatus.DELETED);
}
private Feed createFeed(FeedType feedType) {
return feedRepository.save(
fixtureMonkey.giveMeBuilder(Feed.class)
.set("feedType", feedType)
.set("activityContent", "활동내용")
.set("club", null)
.sample()
);
} |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
보안 검증이 누락된 것이 확인되었습니다.
ClubFeedApi 인터페이스에 정의된 보안 요구사항(@securityrequirement)에 맞게 구현되어야 하나, updateFeed와 deleteFeed 메서드 모두에서 인증 파라미터(PrincipalDetails)가 누락되어 있습니다. 다음과 같이 수정이 필요합니다:
🔗 Analysis chain
보안 검증이 필요합니다.
다른 엔드포인트들과 달리 deleteFeed 메서드에는 인증 검사(PrincipalDetails)가 누락되어 있습니다. 피드 삭제 권한이 있는 사용자만 접근할 수 있도록 보안 검증이 필요합니다.
다음과 같이 수정을 제안합니다:
🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts found
Script:
Length of output: 20533
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.