Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
880db68
[FEAT] Feed 도메인에 isPublic 추가
Kim-TaeUk Apr 18, 2025
7152dfe
[FEAT] FeedCreateRequest에 isPublic 필드 추가
Kim-TaeUk Apr 18, 2025
9e6fe3e
[FEAT] FeedCreateRequest에 isPublic 필드에 @NotNull 추가
Kim-TaeUk Apr 18, 2025
555133b
[STYLE] 가독성을 위한 개행 - FeedCreateRequest
Kim-TaeUk Apr 18, 2025
9bcdae3
[FEAT] Feed 생성자 및 정적 팩터리 메서드에 isPublic 파라미터 추가
Kim-TaeUk Apr 18, 2025
38d1f5a
[REFACTOR] Feed 생성 시 FeedCreateRequest로 파라미터 캡슐화
Kim-TaeUk Apr 18, 2025
7e64d02
[STYLE] 가독성을 위한 개행 - FeedUpdateRequest
Kim-TaeUk Apr 18, 2025
b64051e
[FEAT] FeedUpdateRequest에 isPublic 필드 추가
Kim-TaeUk Apr 18, 2025
1b6bc72
[FEAT] FeedUpdateRequest에 isPublic 필드에 @NotNull 추가
Kim-TaeUk Apr 18, 2025
3801324
[FEAT] Feed.updateFeed에 isPublic 파라미터 추가
Kim-TaeUk Apr 18, 2025
5497c7e
[REFACTOR] Feed 수정 시 FeedUpdateRequest로 파라미터 캡슐화
Kim-TaeUk Apr 18, 2025
062fdc2
[REMOVE] 사용하지 않는 import 삭제
Kim-TaeUk Apr 18, 2025
e2effbf
[FEAT] 응답(PopularFeedGetResponse)에 isPublic 추가
Kim-TaeUk Apr 18, 2025
31e9d5b
[FEAT] 인증 여부에 따라 null-safe하게 userId 처리
Kim-TaeUk Apr 18, 2025
b9e0687
[FEAT] 공개 범위에 따른 피드 필터링하는 isVisibleToUser() 추가
Kim-TaeUk Apr 18, 2025
68a10cf
[FIX] 공개 범위에 따른 피드 필터링위해 메서드 시그니처 변경 - userId 포함
Kim-TaeUk Apr 18, 2025
fde912a
[FIX] 체이닝에 공개 범위에 따른 피드 필터링 로직 추가
Kim-TaeUk Apr 18, 2025
0726d96
[FEAT] 응답(InterestFeedGetResponse)에 isPublic 추가
Kim-TaeUk Apr 18, 2025
e229dd5
[FEAT] Feed 도메인에 isVisibleTo() 추가
Kim-TaeUk Apr 18, 2025
a625c9a
[REFACTOR] 공개 범위에 따른 피드 필터링 여부 판단을 도메인 메서드로 변경
Kim-TaeUk Apr 18, 2025
32bfa37
[REMOVE] 서비스 레이어에서 사용하던 isVisibleToUser() 제거
Kim-TaeUk Apr 18, 2025
2dcfa72
[FIX] 공개 범위에 따른 피드 필터링 로직 추가
Kim-TaeUk Apr 18, 2025
a56d427
[REFACTOR] 삼항연산자가 아닌 Optional로 처리하도록 변경
Kim-TaeUk Apr 19, 2025
db0944b
[RENAME] 메서드에서 이름이 드러나므로 변수명 변경
Kim-TaeUk Apr 19, 2025
7ecff9e
[FIX] 공개 범위에 따른 피드 필터링 로직 추가
Kim-TaeUk Apr 21, 2025
c613b08
[REFACTOR] 삼항연산자가 아닌 Optional로 처리하도록 변경
Kim-TaeUk Apr 21, 2025
91b6dd1
[FEAT] 응답(UserFeedGetResponse)에 isPublic 추가
Kim-TaeUk Apr 21, 2025
c1d96c7
[FIX] 공개 범위에 따른 피드 필터링 로직 추가
Kim-TaeUk Apr 21, 2025
3024154
[FEAT] FeedInfo에 isPublic 추가
Kim-TaeUk Apr 21, 2025
57e7350
[STYLE] 컨벤션에 맞게 개행 추가
Kim-TaeUk Apr 21, 2025
93d6209
[STYLE] 불필요한 개행 제거
Kim-TaeUk Apr 21, 2025
633ec92
[REFACTOR] 선택된 카테고리가 없는 경우 기본값을 반환하는 getChosenCategoryOrDefault 메서드 추출
Kim-TaeUk Apr 21, 2025
357bf02
[REFACTOR] 삼항연산자가 아닌 Optional로 처리하도록 변경
Kim-TaeUk Apr 21, 2025
c3554f7
[STYLE] 컨벤션에 맞게 개행 추가
Kim-TaeUk Apr 21, 2025
a36dd2e
[REFACTOR] isMine() 내부에서 getWriterId() 사용하도록 변경
Kim-TaeUk Apr 21, 2025
024d2cd
[REFACTOR] isVisibleTo() 내부에서 isMine() 사용하도록 변경
Kim-TaeUk Apr 21, 2025
b5f7b31
[FIX] 공개 범위에 따른 피드 필터링 로직 추가
Kim-TaeUk Apr 21, 2025
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
33 changes: 22 additions & 11 deletions src/main/java/org/websoso/WSSServer/domain/Feed.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicInsert;
import org.websoso.WSSServer.dto.feed.FeedCreateRequest;
import org.websoso.WSSServer.dto.feed.FeedUpdateRequest;

@Getter
@DynamicInsert
Expand All @@ -44,6 +46,9 @@ public class Feed {
@Column(nullable = false)
private Boolean isSpoiler;

@Column(columnDefinition = "Boolean default true", nullable = false)
private Boolean isPublic;

@Column(nullable = false)
private LocalDateTime createdDate;

Expand All @@ -69,21 +74,23 @@ public class Feed {
@OneToOne(mappedBy = "feed", cascade = ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private PopularFeed popularFeed;

private Feed(String feedContent, Long novelId, Boolean isSpoiler, User user) {
this.feedContent = feedContent;
this.novelId = novelId;
this.isSpoiler = isSpoiler;
private Feed(FeedCreateRequest request, User user) {
this.feedContent = request.feedContent();
this.novelId = request.novelId();
this.isSpoiler = request.isSpoiler();
this.isPublic = request.isPublic();
this.user = user;
}

public static Feed create(String feedContent, Long novelId, Boolean isSpoiler, User user) {
return new Feed(feedContent, novelId, isSpoiler, user);
public static Feed create(FeedCreateRequest request, User user) {
return new Feed(request, user);
}

public void updateFeed(String feedContent, Boolean isSpoiler, Long novelId) {
this.feedContent = feedContent;
this.isSpoiler = isSpoiler;
this.novelId = novelId;
public void updateFeed(FeedUpdateRequest request) {
this.feedContent = request.feedContent();
this.isSpoiler = request.isSpoiler();
this.isPublic = request.isPublic();
this.novelId = request.novelId();
this.modifiedDate = LocalDateTime.now();
}

Expand All @@ -100,6 +107,10 @@ public Long getWriterId() {
}

public boolean isMine(Long userId) {
return this.user.getUserId().equals(userId);
return this.getWriterId().equals(userId);
}

public boolean isVisibleTo(Long userId) {
return this.isPublic || this.isMine(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ public record FeedCreateRequest(
@NotNull(message = "카테고리는 null일 수 없습니다.")
@NotEmpty(message = "카테고리는 1개 이상 선택해야 합니다.")
List<String> relevantCategories,

@NotBlank(message = "피드 내용은 비어 있거나, 공백일 수 없습니다.")
@Size(max = 2000, message = "피드 내용은 2000자를 초과할 수 없습니다.")
String feedContent,

Long novelId,

@NotNull(message = "스포일러 여부는 null일 수 없습니다.")
Boolean isSpoiler
Boolean isSpoiler,

@NotNull(message = "공개 여부는 null일 수 없습니다.")
Boolean isPublic
) {
}
7 changes: 4 additions & 3 deletions src/main/java/org/websoso/WSSServer/dto/feed/FeedInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public record FeedInfo(
List<String> relevantCategories,
Boolean isSpoiler,
Boolean isModified,
Boolean isMyFeed

Boolean isMyFeed,
Boolean isPublic
) {
public static FeedInfo of(Feed feed, UserBasicInfo userBasicInfo, Novel novel, Boolean isLiked,
List<String> relevantCategories, Boolean isMyFeed) {
Expand Down Expand Up @@ -60,7 +60,8 @@ public static FeedInfo of(Feed feed, UserBasicInfo userBasicInfo, Novel novel, B
relevantCategories,
feed.getIsSpoiler(),
!feed.getCreatedDate().equals(feed.getModifiedDate()),
isMyFeed
isMyFeed,
feed.getIsPublic()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ public record FeedUpdateRequest(
@NotNull(message = "카테고리는 null일 수 없습니다.")
@NotEmpty(message = "카테고리는 1개 이상 선택해야 합니다.")
List<String> relevantCategories,

@NotBlank(message = "피드 내용은 비어 있거나, 공백일 수 없습니다.")
@Size(max = 2000, message = "피드 내용은 2000자를 초과할 수 없습니다.")
String feedContent,

Long novelId,

@NotNull(message = "스포일러 여부는 null일 수 없습니다.")
Boolean isSpoiler
Boolean isSpoiler,

@NotNull(message = "공개 여부는 null일 수 없습니다.")
Boolean isPublic
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record InterestFeedGetResponse(
String novelImage,
Float novelRating,
Long novelRatingCount,
Boolean isPublic,
String nickname,
String avatarImage,
String feedContent
Expand All @@ -27,6 +28,7 @@ public static InterestFeedGetResponse of(Novel novel, User user, Feed feed, Avat
novel.getNovelImage(),
novelRating,
novelRatingCount,
feed.getIsPublic(),
user.getNickname(),
avatar.getAvatarImage(),
feed.getFeedContent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public record UserFeedGetResponse(
String title,
Float novelRating,
Long novelRatingCount,
List<String> relevantCategories
List<String> relevantCategories,
Boolean isPublic
) {

public static UserFeedGetResponse of(Feed feed, Novel novel, Long visitorId) {
Expand All @@ -50,7 +51,8 @@ public static UserFeedGetResponse of(Feed feed, Novel novel, Long visitorId) {
null : novel.getTitle(),
novelRating,
novelRatingCount,
relevantCategories
relevantCategories,
feed.getIsPublic()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public record PopularFeedGetResponse(
String feedContent,
Integer likeCount,
Integer commentCount,
Boolean isSpoiler
Boolean isSpoiler,
Boolean isPublic
) {

public static PopularFeedGetResponse of(PopularFeed popularFeed) {
Expand All @@ -16,7 +17,8 @@ public static PopularFeedGetResponse of(PopularFeed popularFeed) {
popularFeed.getFeed().getFeedContent(),
popularFeed.getFeed().getLikes().size(),
popularFeed.getFeed().getComments().size(),
popularFeed.getFeed().getIsSpoiler()
popularFeed.getFeed().getIsSpoiler(),
popularFeed.getFeed().getIsPublic()
);
}
}
58 changes: 37 additions & 21 deletions src/main/java/org/websoso/WSSServer/service/FeedService.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public class FeedService {
public void createFeed(User user, FeedCreateRequest request) {
Optional.ofNullable(request.novelId())
.ifPresent(novelService::getNovelOrException);
Feed feed = Feed.create(request.feedContent(), request.novelId(), request.isSpoiler(), user);
Feed feed = Feed.create(request, user);
feedRepository.save(feed);
feedCategoryService.createFeedCategory(feed, request.relevantCategories());
}
Expand All @@ -94,7 +94,7 @@ public void updateFeed(Long feedId, FeedUpdateRequest request) {
if (request.novelId() != null && feed.isNovelChanged(request.novelId())) {
novelService.getNovelOrException(request.novelId());
}
feed.updateFeed(request.feedContent(), request.isSpoiler(), request.novelId());
feed.updateFeed(request);
feedCategoryService.updateFeedCategory(feed, request.relevantCategories());
}

Expand Down Expand Up @@ -193,14 +193,25 @@ public FeedGetResponse getFeedById(User user, Long feedId) {

@Transactional(readOnly = true)
public FeedsGetResponse getFeeds(User user, String category, Long lastFeedId, int size) {
Slice<Feed> feeds = findFeedsByCategoryLabel(category == null ? DEFAULT_CATEGORY : category,
lastFeedId, user == null ? null : user.getUserId(), PageRequest.of(DEFAULT_PAGE_NUMBER, size));
Long userIdOrNull = Optional.ofNullable(user)
.map(User::getUserId)
.orElse(null);

List<FeedInfo> feedGetResponses = feeds.getContent().stream()
.map(feed -> createFeedInfo(feed, user)).toList();
Slice<Feed> feeds = findFeedsByCategoryLabel(getChosenCategoryOrDefault(category),
lastFeedId, userIdOrNull, PageRequest.of(DEFAULT_PAGE_NUMBER, size));

return FeedsGetResponse.of(category == null ? DEFAULT_CATEGORY : category, feeds.hasNext(),
feedGetResponses);
List<FeedInfo> feedGetResponses = feeds.getContent()
.stream()
.filter(feed -> feed.isVisibleTo(userIdOrNull))
.map(feed -> createFeedInfo(feed, user))
.toList();

return FeedsGetResponse.of(getChosenCategoryOrDefault(category), feeds.hasNext(), feedGetResponses);
}

private static String getChosenCategoryOrDefault(String category) {
return Optional.ofNullable(category)
.orElse(DEFAULT_CATEGORY);
}

public void createComment(User user, Long feedId, CommentCreateRequest request) {
Expand Down Expand Up @@ -322,6 +333,7 @@ public InterestFeedsGetResponse getInterestFeeds(User user) {
.collect(Collectors.toMap(Avatar::getAvatarId, avatar -> avatar));

List<InterestFeedGetResponse> interestFeedGetResponses = interestFeeds.stream()
.filter(feed -> feed.isVisibleTo(user.getUserId()))
.map(feed -> {
Novel novel = novelMap.get(feed.getNovelId());
Avatar avatar = avatarMap.get(feed.getUser().getAvatarId());
Expand All @@ -332,14 +344,15 @@ public InterestFeedsGetResponse getInterestFeeds(User user) {
}

public NovelGetResponseFeedTab getFeedsByNovel(User user, Long novelId, Long lastFeedId, int size) {
Long userIdOrNull = user == null
? null
: user.getUserId();

Long userIdOrNull = Optional.ofNullable(user)
.map(User::getUserId)
.orElse(null);
Slice<Feed> feeds = feedRepository.findFeedsByNovelId(novelId, lastFeedId, userIdOrNull,
PageRequest.of(DEFAULT_PAGE_NUMBER, size));

List<FeedInfo> feedGetResponses = feeds.getContent().stream()
List<FeedInfo> feedGetResponses = feeds.getContent()
.stream()
.filter(feed -> feed.isVisibleTo(userIdOrNull))
.map(feed -> createFeedInfo(feed, user))
.toList();

Expand All @@ -349,28 +362,31 @@ public NovelGetResponseFeedTab getFeedsByNovel(User user, Long novelId, Long las
@Transactional(readOnly = true)
public UserFeedsGetResponse getUserFeeds(User visitor, Long ownerId, Long lastFeedId, int size) {
User owner = userService.getUserOrException(ownerId);
Long visitorId = visitor == null
? null
: visitor.getUserId();
Long visitorId = Optional.ofNullable(visitor)
.map(User::getUserId)
.orElse(null);

if (owner.getIsProfilePublic() || isOwner(visitor, ownerId)) {
List<Feed> feedsByNoOffsetPagination =
feedRepository.findFeedsByNoOffsetPagination(owner, lastFeedId, size);
List<Feed> feeds = feedRepository.findFeedsByNoOffsetPagination(owner, lastFeedId, size);

List<Feed> visibleFeeds = feeds.stream()
.filter(feed -> feed.isVisibleTo(visitorId))
.toList();

List<Long> novelIds = feedsByNoOffsetPagination.stream()
List<Long> novelIds = visibleFeeds.stream()
.map(Feed::getNovelId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Long, Novel> novelMap = novelRepository.findAllById(novelIds)
.stream()
.collect(Collectors.toMap(Novel::getNovelId, novel -> novel));

List<UserFeedGetResponse> userFeedGetResponseList = feedsByNoOffsetPagination.stream()
List<UserFeedGetResponse> userFeedGetResponseList = visibleFeeds.stream()
.map(feed -> UserFeedGetResponse.of(feed, novelMap.get(feed.getNovelId()), visitorId))
.toList();

// TODO Slice의 hasNext()로 판단하도록 수정
Boolean isLoadable = feedsByNoOffsetPagination.size() == size;
Boolean isLoadable = feeds.size() == size;

return UserFeedsGetResponse.of(isLoadable, userFeedGetResponseList);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.websoso.WSSServer.domain.Feed;
Expand Down Expand Up @@ -105,10 +104,17 @@ private String generateNotificationBodyFragment(Feed feed) {

@Transactional(readOnly = true)
public PopularFeedsGetResponse getPopularFeeds(User user) {
Long currentUserId = Optional.ofNullable(user)
.map(User::getUserId)
.orElse(null);

List<PopularFeed> popularFeeds = Optional.ofNullable(user)
.map(u -> findPopularFeedsWithUser(u.getUserId()))
.orElseGet(this::findPopularFeedsWithoutUser);
List<PopularFeedGetResponse> popularFeedGetResponses = mapToPopularFeedGetResponseList(popularFeeds);

List<PopularFeedGetResponse> popularFeedGetResponses =
mapToPopularFeedGetResponseList(popularFeeds, currentUserId);

return new PopularFeedsGetResponse(popularFeedGetResponses);
}

Expand All @@ -120,8 +126,10 @@ private List<PopularFeed> findPopularFeedsWithoutUser() {
return popularFeedRepository.findTop9ByOrderByPopularFeedIdDesc();
}

private static List<PopularFeedGetResponse> mapToPopularFeedGetResponseList(List<PopularFeed> popularFeeds) {
private static List<PopularFeedGetResponse> mapToPopularFeedGetResponseList(List<PopularFeed> popularFeeds,
Long currentUserId) {
return popularFeeds.stream()
.filter(pf -> pf.getFeed().isVisibleTo(currentUserId))
.map(PopularFeedGetResponse::of)
.toList();
}
Expand Down
Loading