-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 플레이리스트 구현 #262
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
Merged
Merged
feat: 플레이리스트 구현 #262
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
13d6f67
feat: 플레이리스트 엔티티 초기 구현 및 생성 로직 추가
metDaisy 6a445ce
feat: 사용자 요약 DTO 및 매퍼 추가
metDaisy bdae7b4
fix: 사용자 조회 시 N+1 문제 해결
metDaisy 460ea3f
feat: 플레이리스트 관련 예외 클래스 추가
metDaisy 6dbc0e0
feat: 플레이리스트 서비스 로직 구현
metDaisy c748766
feat: 플레이리스트 DTO 및 매퍼 정의
metDaisy 7710d58
feat: 플레이리스트 리포지토리 초기 구현
metDaisy f43b8e3
refactor: Playlist 엔티티 필드 업데이트 로직 개선
metDaisy b9bd252
feat: 플레이리스트 API 컨트롤러 초기 구현
metDaisy 6d3c4ee
feat: 구독 엔티티 및 관련 예외 클래스 추가
metDaisy 8bbcce1
feat: 구독 기능 API 및 서비스 구현
metDaisy 7cf541c
feat: 구독 취소 기능 추가
metDaisy a6203bf
feat: 플레이리스트 커서 기반 페이지네이션 구현
metDaisy 9e77f6c
feat: 플레이리스트 커서 기반 조회 구현
metDaisy 89d0843
refactor: CursorResponse 정렬 방향 값 처리 로직 개선
metDaisy f0c66fa
feat: 플레이리스트 항목 엔티티 및 DTO 정의
metDaisy 252331a
feat: 플레이리스트 응답에 콘텐츠 목록 포함
metDaisy 30ee167
chore: .gitignore에 IDE 설정 파일 추가
metDaisy 4a365c2
refactor: 플레이리스트 조회 쿼리 및 엔티티 정의 개선
metDaisy 24aca46
feat: 플레이리스트 콘텐츠 추가 및 삭제 기능 구현
metDaisy 3987dac
feat: 플레이리스트 관련 Repository 및 Exception 추가
metDaisy 5f7b273
feat: 플레이리스트 관련 API 인터페이스 구현
metDaisy fa50132
feat: 플레이리스트 구독 API 추가
metDaisy 430aca5
test: 플레이리스트 관련 테스트 코드 추가
metDaisy c3e4a17
test: 플레이리스트 컨트롤러 테스트 코드 추가
metDaisy b65b4b0
fix: 플레이리스트 아이템의 position 컬럼 삭제
metDaisy 2e1c63b
fix: PlaylistRepository에서 불필요한 메서드 제거
metDaisy a71837e
feat: 사용자 엔티티 그래프 로딩 추가
metDaisy 0ecdf06
fix: MapStruct unmapped target policy 변경
metDaisy c3e9807
fix: 플레이리스트 관련 예외 처리 및 유효성 검사 개선
metDaisy 62c287e
feat: 플레이리스트 구독 중복 예외 처리 및 메시지 수정
metDaisy a97f3fc
test: 플레이리스트 컨트롤러 테스트 코드 추가
metDaisy 5eb3de6
refactor: 플레이리스트 커서 조회 로직 개선
metDaisy 7af0d75
test: 구독 관련 테스트 코드 추가
metDaisy 54eefb9
feat: 플레이리스트 조회 시 구독 여부 반환
metDaisy c86eed6
fix: 구독 취소 시 구독자 수 감소 로직 추가
metDaisy cee790b
refactor: 플레이리스트 소유자 인증 로직 변경
metDaisy 2dd3f6e
feat: 커서 기반 플레이리스트 연속 조회 테스트 추가
metDaisy 0264f1e
test: 알림 생성 시간 테스트 로직 개선
metDaisy 8359a55
feat: QueryDSL 의존성 및 JaCoCo 설정 업데이트
metDaisy 8966857
test: 플레이리스트 조회 테스트 추가
metDaisy 3af4dae
fix: 플레이리스트 컨텐츠 추가 시 중복 검사 및 예외 처리
metDaisy 7cc90c0
test: 플레이리스트 컨트롤러 테스트 코드 수정
metDaisy 62b461a
플레이리스트 기능 개선 및 쿼리 최적화
metDaisy 7618f18
refactor: 플레이리스트 콘텐츠 삭제 로직 개선
metDaisy 9fbcde5
refactor: 플레이리스트 관련 이벤트 패키지 구조 변경
metDaisy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/main/java/com/codeit/team5/mopl/global/mapper/GlobalMapperConfig.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.codeit.team5.mopl.global.mapper; | ||
|
|
||
| import org.mapstruct.InjectionStrategy; | ||
| import org.mapstruct.MapperConfig; | ||
| import org.mapstruct.MappingConstants; | ||
| import org.mapstruct.NullValuePropertyMappingStrategy; | ||
| import org.mapstruct.ReportingPolicy; | ||
|
|
||
| @MapperConfig(componentModel = MappingConstants.ComponentModel.SPRING, | ||
| unmappedTargetPolicy = ReportingPolicy.WARN, | ||
| nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, | ||
| injectionStrategy = InjectionStrategy.CONSTRUCTOR) | ||
|
metDaisy marked this conversation as resolved.
|
||
| public interface GlobalMapperConfig { | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
src/main/java/com/codeit/team5/mopl/playlist/constant/PlaylistSortBy.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.codeit.team5.mopl.playlist.constant; | ||
|
|
||
| import com.codeit.team5.mopl.playlist.exception.PlaylistIncorrectSortByException; | ||
| import com.codeit.team5.mopl.playlist.exception.PlaylistSortByMismatchException; | ||
| import java.time.Instant; | ||
| import java.util.function.Function; | ||
| import lombok.Getter; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @Getter | ||
| @RequiredArgsConstructor | ||
| public enum PlaylistSortBy { | ||
| UPDATED_AT("updatedAt", Instant::parse), | ||
| SUBSCRIBE_COUNT("subscribeCount", Integer::parseInt), | ||
| ; | ||
| private final String sortByType; | ||
| private final Function<String, ?> parser; | ||
|
|
||
| public static PlaylistSortBy from(String text) { | ||
| for (PlaylistSortBy value : PlaylistSortBy.values()) { | ||
| if (value.getSortByType().equalsIgnoreCase(text)) { | ||
| return value; | ||
| } | ||
| } | ||
| throw new PlaylistIncorrectSortByException(text); | ||
| } | ||
|
|
||
| public Object parse(String cursor) { | ||
| try { | ||
| return parser.apply(cursor); | ||
| } catch (Exception ex) { | ||
| throw new PlaylistSortByMismatchException(sortByType, cursor); | ||
| } | ||
|
|
||
| } | ||
|
metDaisy marked this conversation as resolved.
|
||
| } | ||
94 changes: 94 additions & 0 deletions
94
src/main/java/com/codeit/team5/mopl/playlist/controller/PlaylistController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| package com.codeit.team5.mopl.playlist.controller; | ||
|
|
||
| import java.util.UUID; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.ModelAttribute; | ||
| import org.springframework.web.bind.annotation.PatchMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
| import com.codeit.team5.mopl.auth.security.details.MoplPrincipal; | ||
| import com.codeit.team5.mopl.global.dto.CursorResponse; | ||
| import com.codeit.team5.mopl.playlist.controller.api.PlaylistControllerApi; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistCreateRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistCursorRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistUpdateRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.response.PlaylistResponse; | ||
| import com.codeit.team5.mopl.playlist.mapper.PlaylistMapper; | ||
| import com.codeit.team5.mopl.playlist.service.PlaylistService; | ||
| import jakarta.validation.Valid; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/playlists") | ||
| @RequiredArgsConstructor | ||
| public class PlaylistController implements PlaylistControllerApi { | ||
|
|
||
| private final PlaylistService service; | ||
| private final PlaylistMapper mapper; | ||
|
|
||
| @Override | ||
| @GetMapping("/{id}") | ||
| public ResponseEntity<PlaylistResponse> find(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @PathVariable UUID id) { | ||
| UUID userId = principal.getId(); | ||
| return ResponseEntity.status(HttpStatus.OK).body(service.find(id, userId)); | ||
| } | ||
|
|
||
| @Override | ||
| @GetMapping | ||
| public ResponseEntity<CursorResponse<PlaylistResponse>> findCursor( | ||
| @AuthenticationPrincipal MoplPrincipal principal, | ||
| @ModelAttribute @Valid PlaylistCursorRequest request) { | ||
| UUID userId = principal.getId(); | ||
| return ResponseEntity.status(HttpStatus.OK) | ||
| .body(service.findByCursor(mapper.toCommand(request), userId)); | ||
| } | ||
|
metDaisy marked this conversation as resolved.
|
||
|
|
||
| @Override | ||
| @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| public ResponseEntity<PlaylistResponse> create(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @RequestBody @Valid PlaylistCreateRequest request) { | ||
| return ResponseEntity.status(HttpStatus.CREATED) | ||
| .body(service.create(principal.getId(), request)); | ||
| } | ||
|
|
||
| @Override | ||
| @PatchMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| public ResponseEntity<PlaylistResponse> update(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @PathVariable UUID id, @RequestBody PlaylistUpdateRequest request) { | ||
| return ResponseEntity.status(HttpStatus.OK) | ||
| .body(service.update(id, principal.getId(), request)); | ||
| } | ||
|
metDaisy marked this conversation as resolved.
|
||
|
|
||
| @Override | ||
| @DeleteMapping("/{id}") | ||
| public ResponseEntity<Void> delete(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @PathVariable UUID id) { | ||
| service.delete(id, principal.getId()); | ||
| return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); | ||
| } | ||
|
|
||
| @Override | ||
| @PostMapping("/{playlistId}/contents/{contentId}") | ||
| public ResponseEntity<Void> addContent(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @PathVariable UUID playlistId, @PathVariable UUID contentId) { | ||
| service.addContent(principal.getId(), playlistId, contentId); | ||
| return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); | ||
| } | ||
|
|
||
| @Override | ||
| @DeleteMapping("/{playlistId}/contents/{contentId}") | ||
| public ResponseEntity<Void> removeContent(@AuthenticationPrincipal MoplPrincipal principal, | ||
| @PathVariable UUID playlistId, @PathVariable UUID contentId) { | ||
| service.removeContent(principal.getId(), playlistId, contentId); | ||
| return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); | ||
| } | ||
| } | ||
49 changes: 49 additions & 0 deletions
49
src/main/java/com/codeit/team5/mopl/playlist/controller/api/PlaylistControllerApi.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.codeit.team5.mopl.playlist.controller.api; | ||
|
|
||
| import java.util.UUID; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.ModelAttribute; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import com.codeit.team5.mopl.auth.security.details.MoplPrincipal; | ||
| import com.codeit.team5.mopl.global.dto.CursorResponse; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistCreateRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistCursorRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.request.PlaylistUpdateRequest; | ||
| import com.codeit.team5.mopl.playlist.dto.response.PlaylistResponse; | ||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.Parameter; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
|
|
||
| @Tag(name = "플레이리스트 관리") | ||
| public interface PlaylistControllerApi { | ||
|
|
||
| @Operation(summary = "플레이리스트 단건 조회") | ||
| ResponseEntity<PlaylistResponse> find(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @PathVariable UUID id); | ||
|
|
||
| @Operation(summary = "플레이리스트 목록 조회 (커서 페이지네이션)") | ||
| ResponseEntity<CursorResponse<PlaylistResponse>> findCursor( | ||
| @Parameter(hidden = true) MoplPrincipal principal, | ||
| @ModelAttribute PlaylistCursorRequest request); | ||
|
|
||
| @Operation(summary = "플레이리스트 생성", description = "생성한 플레이리스트는 API 요청자 본인의 플레이리스트로 생성됩니다.") | ||
| ResponseEntity<PlaylistResponse> create(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @RequestBody PlaylistCreateRequest request); | ||
|
|
||
| @Operation(summary = "플레이리스트 수정", description = "플레이리스트 소유자만 수정할 수 있습니다.") | ||
| ResponseEntity<PlaylistResponse> update(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @PathVariable UUID id, @RequestBody PlaylistUpdateRequest request); | ||
|
|
||
| @Operation(summary = "플레이리스트 삭제", description = "플레이리스트 소유자만 삭제할 수 있습니다.") | ||
| ResponseEntity<Void> delete(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @PathVariable UUID playlistId); | ||
|
metDaisy marked this conversation as resolved.
|
||
|
|
||
| @Operation(summary = "플레이리스트에 콘텐츠 추가", description = "플레이리스트 소유자만 콘텐츠를 추가할 수 있습니다.") | ||
| ResponseEntity<Void> addContent(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @PathVariable UUID playlistId, @PathVariable UUID contentId); | ||
|
|
||
| @Operation(summary = "플레이리스트에서 콘텐츠 삭제", description = "플레이리스트 소유자만 콘텐츠를 삭제할 수 있습니다.") | ||
| ResponseEntity<Void> removeContent(@Parameter(hidden = true) MoplPrincipal principal, | ||
| @PathVariable UUID playlistId, @PathVariable UUID contentId); | ||
| } | ||
8 changes: 8 additions & 0 deletions
8
src/main/java/com/codeit/team5/mopl/playlist/dto/PlaylistContentsDto.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.codeit.team5.mopl.playlist.dto; | ||
|
|
||
| import com.codeit.team5.mopl.content.entity.Content; | ||
| import com.codeit.team5.mopl.playlist.entity.Playlist; | ||
| import java.util.List; | ||
|
|
||
| public record PlaylistContentsDto(Playlist playlist, List<Content> contents, boolean subscribedByMe) { | ||
| } |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/codeit/team5/mopl/playlist/dto/PlaylistCursorCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.codeit.team5.mopl.playlist.dto; | ||
|
|
||
| import com.codeit.team5.mopl.playlist.constant.PlaylistSortBy; | ||
| import org.springframework.data.domain.Sort; | ||
| import java.util.UUID; | ||
| import lombok.Builder; | ||
|
|
||
| @Builder | ||
| public record PlaylistCursorCommand(String keywordLike, UUID ownerIdEqual, UUID subscriberIdEqual, | ||
| Object cursor, UUID idAfter, Integer limit, Sort.Direction sortDirection, | ||
| PlaylistSortBy sortBy) { | ||
|
metDaisy marked this conversation as resolved.
|
||
| } | ||
9 changes: 9 additions & 0 deletions
9
src/main/java/com/codeit/team5/mopl/playlist/dto/request/PlaylistCreateRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.codeit.team5.mopl.playlist.dto.request; | ||
|
|
||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Size; | ||
|
|
||
| public record PlaylistCreateRequest(@NotBlank @Size(max = 255) String title, | ||
| @NotBlank String description) { | ||
|
|
||
| } |
18 changes: 18 additions & 0 deletions
18
src/main/java/com/codeit/team5/mopl/playlist/dto/request/PlaylistCursorRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.codeit.team5.mopl.playlist.dto.request; | ||
|
|
||
| import java.util.UUID; | ||
| import org.springframework.data.domain.Sort; | ||
| import jakarta.validation.constraints.Max; | ||
| import jakarta.validation.constraints.NotNull; | ||
| import jakarta.validation.constraints.Positive; | ||
|
|
||
| public record PlaylistCursorRequest(String keywordLike, | ||
| UUID ownerIdEqual, | ||
| UUID subscriberIdEqual, | ||
| String cursor, | ||
| UUID idAfter, | ||
| @NotNull @Positive @Max(50) Integer limit, | ||
| @NotNull Sort.Direction sortDirection, | ||
| @NotNull String sortBy) { | ||
|
|
||
| } |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/codeit/team5/mopl/playlist/dto/request/PlaylistUpdateRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.codeit.team5.mopl.playlist.dto.request; | ||
|
|
||
| public record PlaylistUpdateRequest(String title, String description) { | ||
|
|
||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.