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
22 changes: 11 additions & 11 deletions src/main/java/ddingdong/ddingdongBE/domain/feed/api/FeedApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ddingdong.ddingdongBE.domain.feed.controller.dto.response.ClubFeedPageResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.FeedResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.NewestFeedPerClubPageResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.FeedPageResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -21,28 +21,28 @@ public interface FeedApi {

@Operation(summary = "특정 동아리 피드 페이지 조회 API")
@ApiResponse(responseCode = "200", description = "특정 동아리 피드 페이지 조회 성공",
content = @Content(schema = @Schema(implementation = ClubFeedPageResponse.class)))
content = @Content(schema = @Schema(implementation = ClubFeedPageResponse.class)))
@ResponseStatus(HttpStatus.OK)
@GetMapping("/clubs/{clubId}/feeds")
ClubFeedPageResponse getFeedPageByClub(
@PathVariable("clubId") Long clubId,
@RequestParam(value = "size", defaultValue = "9") int size,
@RequestParam(value = "currentCursorId", defaultValue = "-1") Long currentCursorId
);
@PathVariable("clubId") Long clubId,
@RequestParam(value = "size", defaultValue = "9") int size,
@RequestParam(value = "currentCursorId", defaultValue = "-1") Long currentCursorId
);

@Operation(summary = "모든 동아리 최신 피드 페이지 조회 API")
@ApiResponse(responseCode = "200", description = "모든 동아리 최신 피드 페이지 조회 성공",
content = @Content(schema = @Schema(implementation = NewestFeedPerClubPageResponse.class)))
content = @Content(schema = @Schema(implementation = FeedPageResponse.class)))
@ResponseStatus(HttpStatus.OK)
@GetMapping("/feeds")
NewestFeedPerClubPageResponse getNewestFeedPerClub(
@RequestParam(value = "size", defaultValue = "9") int size,
@RequestParam(value = "currentCursorId", defaultValue = "-1") Long currentCursorId
FeedPageResponse getAllFeedPage(
@RequestParam(value = "size", defaultValue = "9") int size,
@RequestParam(value = "currentCursorId", defaultValue = "-1") Long currentCursorId
);

@Operation(summary = "동아리 피드 상세 조회 API")
@ApiResponse(responseCode = "200", description = "동아리 피드 상세 조회 API",
content = @Content(schema = @Schema(implementation = FeedResponse.class)))
content = @Content(schema = @Schema(implementation = FeedResponse.class)))
@ResponseStatus(HttpStatus.OK)
@GetMapping("/feeds/{feedId}")
FeedResponse getByFeedId(@PathVariable("feedId") Long feedId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import ddingdong.ddingdongBE.domain.feed.api.FeedApi;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.ClubFeedPageResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.FeedResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.NewestFeedPerClubPageResponse;
import ddingdong.ddingdongBE.domain.feed.controller.dto.response.FeedPageResponse;
import ddingdong.ddingdongBE.domain.feed.service.FacadeFeedService;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.ClubFeedPageQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.NewestFeedPerClubPageQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedPageQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -19,21 +19,21 @@ public class FeedController implements FeedApi {

@Override
public ClubFeedPageResponse getFeedPageByClub(
Long clubId,
int size,
Long currentCursorId
Long clubId,
int size,
Long currentCursorId
) {
ClubFeedPageQuery clubFeedPageQuery = facadeFeedService.getFeedPageByClub(clubId, size, currentCursorId);
return ClubFeedPageResponse.from(clubFeedPageQuery);
}

@Override
public NewestFeedPerClubPageResponse getNewestFeedPerClub(
int size,
Long currentCursorId
public FeedPageResponse getAllFeedPage(
int size,
Long currentCursorId
) {
NewestFeedPerClubPageQuery newestFeedPerClubPageQuery = facadeFeedService.getNewestFeedPerClubPage(size, currentCursorId);
return NewestFeedPerClubPageResponse.from(newestFeedPerClubPageQuery);
FeedPageQuery feedPageQuery = facadeFeedService.getAllFeedPage(size, currentCursorId);
return FeedPageResponse.from(feedPageQuery);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
package ddingdong.ddingdongBE.domain.feed.controller.dto.response;

import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedListQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.NewestFeedPerClubPageQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedPageQuery;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Builder;

public record NewestFeedPerClubPageResponse(
@ArraySchema(schema = @Schema(name = "동아리 최신 피드 정보", implementation = NewestFeedListResponse.class))
List<NewestFeedListResponse> newestFeeds,
public record FeedPageResponse(
@ArraySchema(schema = @Schema(name = "동아리 최신 피드 정보", implementation = FeedListResponse.class))
List<FeedListResponse> newestFeeds,
@Schema(name = "피드 페이지 정보", implementation = PagingResponse.class)
PagingResponse pagingInfo
) {

public static NewestFeedPerClubPageResponse from(
NewestFeedPerClubPageQuery newestFeedPerClubPageQuery) {
List<NewestFeedListResponse> newestFeeds = newestFeedPerClubPageQuery.feedListQueries()
public static FeedPageResponse from(
FeedPageQuery feedPageQuery) {
List<FeedListResponse> newestFeeds = feedPageQuery.feedListQueries()
.stream()
.map(NewestFeedListResponse::from)
.map(FeedListResponse::from)
.toList();
return new NewestFeedPerClubPageResponse(newestFeeds,
PagingResponse.from(newestFeedPerClubPageQuery.pagingQuery()));
return new FeedPageResponse(newestFeeds,
PagingResponse.from(feedPageQuery.pagingQuery()));
}

@Builder
public record NewestFeedListResponse(
public record FeedListResponse(
@Schema(description = "피드 ID", example = "1")
Long id,
@Schema(description = "피드 썸네일 CDN URL", example = "https://%s.s3.%s.amazonaws.com/%s/%s/%s")
Expand All @@ -38,8 +38,8 @@ public record NewestFeedListResponse(
String feedType
) {

public static NewestFeedListResponse from(FeedListQuery query) {
return NewestFeedListResponse.builder()
public static FeedListResponse from(FeedListQuery query) {
return FeedListResponse.builder()
.id(query.id())
.thumbnailOriginUrl(query.thumbnailOriginUrl())
.thumbnailCdnUrl(query.thumbnailCdnUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,32 @@ or exists (
limit :size
""", nativeQuery = true)
Slice<Feed> findPageByClubIdOrderById(
@Param("clubId") Long clubId,
@Param("size") int size,
@Param("currentCursorId") Long currentCursorId
@Param("clubId") Long clubId,
@Param("size") int size,
@Param("currentCursorId") Long currentCursorId
);

@Query(value = """
select * from feed f
where f.id in
(select max(id)
from feed
where deleted_at is null
and (
f.feed_type != 'VIDEO'
or exists (
select 1
from (
select id
from file_meta_data
where entity_id = f.id
and domain_type = 'FEED_VIDEO'
) filtered_fm
join vod_processing_job vpj
on filtered_fm.id = vpj.file_meta_data_id
where vpj.convert_job_status = 'COMPLETE'
)
)
GROUP BY club_id)
and (:currentCursorId = -1 or id < :currentCursorId)
ORDER BY id DESC
limit :size
""",
nativeQuery = true)
Slice<Feed> findNewestPerClubPage(
@Param("size") int size,
@Param("currentCursorId") Long currentCursorId
where f.deleted_at is null
and (
f.feed_type != 'VIDEO'
or exists (
select 1
from file_meta_data fm
join vod_processing_job vpj on fm.id = vpj.file_meta_data_id
where fm.entity_id = f.id
and fm.domain_type = 'FEED_VIDEO'
and vpj.convert_job_status = 'COMPLETE'
)
)
and (:currentCursorId = -1 or f.id < :currentCursorId)
ORDER BY f.id DESC
limit :size
""", nativeQuery = true)
Slice<Feed> getAllFeedPage(
@Param("size") int size,
@Param("currentCursorId") Long currentCursorId
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedFileInfoQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedListQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.NewestFeedPerClubPageQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedPageQuery;
import ddingdong.ddingdongBE.domain.feed.service.dto.query.PagingQuery;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -36,18 +36,18 @@ public ClubFeedPageQuery getFeedPageByClub(Long clubId, int size, Long currentCu
return ClubFeedPageQuery.of(feedListQueries, pagingQuery);
}

public NewestFeedPerClubPageQuery getNewestFeedPerClubPage(int size, Long currentCursorId) {
Slice<Feed> feedPage = feedService.getNewestFeedPerClubPage(size, currentCursorId);
public FeedPageQuery getAllFeedPage(int size, Long currentCursorId) {
Slice<Feed> feedPage = feedService.getAllFeedPage(size, currentCursorId);
if (feedPage == null) {
return NewestFeedPerClubPageQuery.createEmpty();
return FeedPageQuery.createEmpty();
}
List<Feed> completeFeeds = feedPage.getContent();

List<FeedListQuery> feedListQueries = completeFeeds.stream().map(feedFileService::extractFeedThumbnailInfo)
.toList();
PagingQuery pagingQuery = PagingQuery.of(currentCursorId, completeFeeds, feedPage.hasNext());

return NewestFeedPerClubPageQuery.of(feedListQueries, pagingQuery);
return FeedPageQuery.of(feedListQueries, pagingQuery);
}

public FeedQuery getById(Long feedId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public interface FeedService {

Slice<Feed> getFeedPageByClubId(Long clubId, int size, Long currentCursorId);

Slice<Feed> getNewestFeedPerClubPage(int size, Long currentCursorId);
Slice<Feed> getAllFeedPage(int size, Long currentCursorId);

Feed getById(Long feedId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public Slice<Feed> getFeedPageByClubId(Long clubId, int size, Long currentCursor
}

@Override
public Slice<Feed> getNewestFeedPerClubPage(int size, Long currentCursorId) {
Slice<Feed> feedPages = feedRepository.findNewestPerClubPage(size + 1, currentCursorId);
public Slice<Feed> getAllFeedPage(int size, Long currentCursorId) {
Slice<Feed> feedPages = feedRepository.getAllFeedPage(size + 1, currentCursorId);
return buildSlice(feedPages, size);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ddingdong.ddingdongBE.domain.feed.service.dto.query;

import java.util.Collections;
import java.util.List;

public record FeedPageQuery(
List<FeedListQuery> feedListQueries,
PagingQuery pagingQuery
) {

public static FeedPageQuery of(List<FeedListQuery> feedListQueries, PagingQuery pagingQuery) {
return new FeedPageQuery(feedListQueries, pagingQuery);
}

public static FeedPageQuery createEmpty() {
return new FeedPageQuery(Collections.emptyList(), PagingQuery.createEmpty());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,21 @@ public static Club createClub(final User user) {
.score(Score.from(BigDecimal.valueOf(85.5)))
.build();
}

public static Club createClub() {
return Club.builder()
.clubMembers(new ArrayList<>())
.name("컴퓨터공학과 동아리")
.category("학술")
.tag("프로그래밍, 개발, IT")
.leader("김동아")
.phoneNumber(PhoneNumber.from("010-1234-5678"))
.location(Location.from("S3014")) // S + 4자리 숫자
.regularMeeting("매주 수요일 18:00")
.introduction("컴퓨터공학과 학생들이 함께 공부하고 프로젝트를 진행하는 동아리입니다.")
.activity("알고리즘 스터디, 웹 개발 프로젝트, 해커톤 참가")
.ideal("함께 성장하는 개발자 커뮤니티")
.score(Score.from(BigDecimal.valueOf(85.5)))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ddingdong.ddingdongBE.common.fixture;

import ddingdong.ddingdongBE.domain.club.entity.Club;
import ddingdong.ddingdongBE.domain.feed.entity.Feed;
import ddingdong.ddingdongBE.domain.feed.entity.FeedType;

public class FeedFixture {

public static Feed createImageFeed(Club club, String content) {
return Feed.builder()
.club(club)
.feedType(FeedType.IMAGE)
.activityContent(content)
.build();
}

public static Feed createVideoFeed(Club club, String content) {
return Feed.builder()
.club(club)
.feedType(FeedType.VIDEO)
.activityContent(content)
.build();
}

public static Feed createFeed(Club club, FeedType feedType, String content) {
return Feed.builder()
.club(club)
.feedType(feedType)
.activityContent(content)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ddingdong.ddingdongBE.common.fixture;

import com.github.f4b6a3.uuid.UuidCreator;
import ddingdong.ddingdongBE.domain.filemetadata.entity.DomainType;
import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData;
import ddingdong.ddingdongBE.domain.filemetadata.entity.FileStatus;
import ddingdong.ddingdongBE.domain.vodprocessing.entity.ConvertJobStatus;
import ddingdong.ddingdongBE.domain.vodprocessing.entity.VodProcessingJob;

public class VodProcessingJobFixture {

public static FileMetaData createFileMetaData(Long feedId) {
return FileMetaData.builder()
.id(UuidCreator.getTimeOrderedEpoch())
.fileKey("test-key-" + feedId)
.fileName("test-" + feedId + ".mp4")
.domainType(DomainType.FEED_VIDEO)
.entityId(feedId)
.fileStatus(FileStatus.COUPLED)
.build();
}

public static VodProcessingJob createCompleteVodProcessingJob(FileMetaData fileMetaData) {
return VodProcessingJob.builder()
.fileMetaData(fileMetaData)
.convertJobId(UuidCreator.getTimeOrderedEpoch().toString())
.userId("testUser")
.convertJobStatus(ConvertJobStatus.COMPLETE)
.build();
}

public static VodProcessingJob createPendingVodProcessingJob(FileMetaData fileMetaData) {
return VodProcessingJob.builder()
.fileMetaData(fileMetaData)
.convertJobId(UuidCreator.getTimeOrderedEpoch().toString())
.userId("testUser")
.convertJobStatus(ConvertJobStatus.PENDING)
.build();
}
}
Loading