Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public enum ErrorCode {
INVALID_NOTE_DELETION(HttpStatus.BAD_REQUEST, "05003", "해당 노트를 삭제할 수 없습니다."),
INVALID_NOTE_UPDATE(HttpStatus.BAD_REQUEST, "05004", "해당 노트를 수정할 수 없습니다."),
TOO_MANY_DRAFT_NOTE(HttpStatus.BAD_REQUEST, "05005", "임시저장 노트의 개수가 초과되었습니다."),
NO_LYRICS_FOR_NOTE(HttpStatus.BAD_REQUEST, "05006", "해당 노트에 대한 가사가 필요합니다."),

// Song
SONG_NOT_FOUND(HttpStatus.NOT_FOUND, "06000", "해당 노래를 조회할 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1/notes")
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class NoteController {

private final NoteCommandService noteCommandService;
private final NoteQueryService noteQueryService;
private final ViewCommandService viewCommandService;

@PostMapping
@PostMapping("/notes")
public ResponseEntity<NoteCreateResponse> create(
@Authenticated AuthContext authContext,
@RequestBody @Valid NoteCreateRequest request
Expand All @@ -49,7 +49,7 @@ public ResponseEntity<NoteCreateResponse> create(
.body(new NoteCreateResponse(true));
}

@PatchMapping("/{noteId}")
@PatchMapping("/notes/{noteId}")
public ResponseEntity<NoteUpdateResponse> update(
@Authenticated AuthContext authContext,
@PathVariable(name = "noteId") Long noteId,
Expand All @@ -62,7 +62,7 @@ public ResponseEntity<NoteUpdateResponse> update(
.body(new NoteUpdateResponse(true));
}

@DeleteMapping("/{noteId}")
@DeleteMapping("/notes/{noteId}")
public ResponseEntity<NoteDeleteResponse> delete(
@Authenticated AuthContext authContext,
@PathVariable(name = "noteId") Long noteId
Expand All @@ -74,7 +74,7 @@ public ResponseEntity<NoteDeleteResponse> delete(
.body(new NoteDeleteResponse(true));
}

@GetMapping("/{noteId}")
@GetMapping("/notes/{noteId}")
public ResponseEntity<NoteDetailResponse> getNote(
@Authenticated AuthContext authContext,
@RequestHeader("Device-Id") String deviceId,
Expand All @@ -91,7 +91,7 @@ public ResponseEntity<NoteDetailResponse> getNote(
.body(noteQueryService.getNoteById(noteId, authContext.getId()));
}

@GetMapping
@GetMapping("/users/notes")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/user로 시작하는데도 NoteController에 적은 이유가 따로 있나요? 수정을 할 필요는 없을 것 같은데 궁금해요

public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfUser(
@Authenticated AuthContext authContext,
@RequestParam(name = "hasLyrics") boolean hasLyrics,
Expand All @@ -106,21 +106,22 @@ public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfUs
.body(response);
}

@GetMapping("/favorite-artists")
public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfFavoriteArtists(
@GetMapping("/notes")
public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotes(
@Authenticated AuthContext authContext,
@RequestParam(name = "hasLyrics") boolean hasLyrics,
@RequestParam(name = "isFavoriteArtistsOnly", defaultValue = "false") boolean isFavoriteArtistsOnly,
@RequestParam(name = "cursor", required = false) Long cursor,
@RequestParam(name = "size", defaultValue = "10") int size
) {
CursorBasePaginatedResponse<NoteGetResponse> response = noteQueryService.getNotesOfFavoriteArtists(hasLyrics, authContext.getId(), cursor, size);
CursorBasePaginatedResponse<NoteGetResponse> response = noteQueryService.getNotes(hasLyrics, isFavoriteArtistsOnly, authContext.getId(), cursor, size);

return ResponseEntity
.status(HttpStatus.OK)
.body(response);
}

@GetMapping("/artists")
@GetMapping("/notes/artists")
public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfArtist(
@Authenticated AuthContext authContext,
@RequestParam(name = "hasLyrics") boolean hasLyrics,
Expand All @@ -135,7 +136,7 @@ public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfAr
.body(response);
}

@GetMapping("/songs")
@GetMapping("/notes/songs")
public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfSong(
@Authenticated AuthContext authContext,
@RequestParam(name = "hasLyrics") boolean hasLyrics,
Expand All @@ -150,7 +151,7 @@ public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesOfSo
.body(response);
}

@GetMapping("/bookmarked")
@GetMapping("/notes/bookmarked")
public ResponseEntity<CursorBasePaginatedResponse<NoteGetResponse>> getNotesBookmarked(
@Authenticated AuthContext authContext,
@RequestParam(name = "hasLyrics") boolean hasLyrics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.projectlyrics.server.domain.note.entity.NoteBackground;
import com.projectlyrics.server.domain.note.entity.NoteStatus;
import com.projectlyrics.server.domain.note.entity.NoteType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

Expand All @@ -12,6 +13,8 @@ public record NoteCreateRequest(
NoteBackground background,
@NotNull
NoteStatus status,
@NotNull(message = "노트 유형이 입력되지 않았습니다.")
NoteType noteType,
Long songId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public record NoteDetailResponse(
Long id,
String content,
String status,
String noteType,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
LocalDateTime createdAt,
LyricsGetResponse lyrics,
Expand All @@ -31,6 +32,7 @@ public static NoteDetailResponse of(Note note, List<Comment> comments, Long user
note.getId(),
note.getContent(),
note.getNoteStatus().name(),
note.getNoteType().name(),
note.getCreatedAt(),
LyricsGetResponse.from(note.getLyrics()),
UserGetResponse.from(note.getPublisher()),
Expand All @@ -50,6 +52,7 @@ public static NoteDetailResponse of(Note note, List<Comment> comments, Long user
note.getId(),
note.getContent(),
note.getNoteStatus().name(),
note.getNoteType().name(),
createdAt,
LyricsGetResponse.from(note.getLyrics()),
UserGetResponse.from(note.getPublisher()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record NoteGetResponse(
Long id,
String content,
String status,
String noteType,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
LocalDateTime createdAt,
LyricsGetResponse lyrics,
Expand All @@ -28,6 +29,7 @@ public static NoteGetResponse of(Note note, Long userId) {
note.getId(),
note.getContent(),
note.getNoteStatus().name(),
note.getNoteType().name(),
note.getCreatedAt(),
LyricsGetResponse.from(note.getLyrics()),
UserGetResponse.from(note.getPublisher()),
Expand All @@ -44,6 +46,7 @@ public static NoteGetResponse of(Note note, Long userId, LocalDateTime createdAt
note.getId(),
note.getContent(),
note.getNoteStatus().name(),
note.getNoteType().name(),
createdAt,
LyricsGetResponse.from(note.getLyrics()),
UserGetResponse.from(note.getPublisher()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public class Note extends BaseEntity {
@Enumerated(EnumType.STRING)
private NoteStatus noteStatus;

@Enumerated(EnumType.STRING)
@Column(nullable = false, columnDefinition = "VARCHAR(50) DEFAULT 'FREE'")
private NoteType noteType;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name="lyrics_id")
private Lyrics lyrics;
Expand All @@ -58,12 +62,14 @@ private Note(
String content,
Lyrics lyrics,
NoteStatus noteStatus,
NoteType noteType,
User publisher,
Song song
) {
this.id = id;
this.content = content;
this.noteStatus = noteStatus;
this.noteType = noteType;
this.publisher = publisher;
this.song = song;
addLyrics(lyrics);
Expand All @@ -73,17 +79,19 @@ private Note(
String content,
Lyrics lyrics,
NoteStatus noteStatus,
NoteType noteType,
User publisher,
Song song
) {
this(null, content, lyrics, noteStatus, publisher, song);
this(null, content, lyrics, noteStatus, noteType, publisher, song);
}

public static Note create(NoteCreate noteCreate) {
return new Note(
noteCreate.content(),
Lyrics.of(noteCreate.lyrics(), noteCreate.background()),
noteCreate.status(),
noteCreate.noteType(),
noteCreate.publisher(),
noteCreate.song()
);
Expand All @@ -95,6 +103,7 @@ public static Note createWithId(Long id, NoteCreate noteCreate) {
noteCreate.content(),
Lyrics.of(noteCreate.lyrics(), noteCreate.background()),
noteCreate.status(),
noteCreate.noteType(),
noteCreate.publisher(),
noteCreate.song()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.projectlyrics.server.domain.note.entity;

import com.projectlyrics.server.domain.note.dto.request.NoteCreateRequest;
import com.projectlyrics.server.domain.note.exception.NoLyricsForNoteException;
import com.projectlyrics.server.domain.song.entity.Song;
import com.projectlyrics.server.domain.user.entity.User;

Expand All @@ -11,22 +12,32 @@ public record NoteCreate(
String lyrics,
NoteBackground background,
NoteStatus status,
NoteType noteType,
User publisher,
Song song
) {

public static NoteCreate from(NoteCreateRequest request, User publisher, Song song) {
checkNull(request.status());
checkNull(request.noteType());
checkNull(publisher);
checkNull(song);
validateLyricsForType(request.noteType(), request.lyrics());

return new NoteCreate(
request.content(),
request.lyrics(),
request.background(),
request.status(),
request.noteType(),
publisher,
song
);
}

private static void validateLyricsForType(NoteType noteType, String lyrics) {
if (noteType == NoteType.LYRICS_ANALYSIS && (lyrics == null || lyrics.isBlank())) {
throw new NoLyricsForNoteException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.projectlyrics.server.domain.note.entity;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.RequiredArgsConstructor;

import java.util.Arrays;

@RequiredArgsConstructor
public enum NoteType {

FREE("FREE"),
QUESTION("QUESTION"),
LYRICS_ANALYSIS("LYRICS_ANALYSIS"),
;

private final String type;

@JsonValue
public String getType() {
return type;
}

@JsonCreator
public static NoteType of(String type) {
return Arrays.stream(NoteType.values())
.filter(noteType -> noteType.type.equals(type))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Invalid NoteType: " + type));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.projectlyrics.server.domain.note.exception;

import com.projectlyrics.server.domain.common.message.ErrorCode;
import com.projectlyrics.server.global.exception.FeelinException;

public class NoLyricsForNoteException extends FeelinException {

public NoLyricsForNoteException() {
super(ErrorCode.NO_LYRICS_FOR_NOTE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public interface NoteQueryRepository {

Slice<Note> findAllByUserId(boolean hasLyrics, Long artistId, Long userId, Long cursorId, Pageable pageable);
Slice<Note> findAllByArtistIds(boolean hasLyrics, List<Long> artistsIds, Long userId, Long cursorId, Pageable pageable);
Slice<Note> findAll(boolean hasLyrics, List<Long> artistsIds, Long userId, Long cursorId, Pageable pageable);
Slice<Note> findAllByArtistId(boolean hasLyrics, Long artistId, Long userId, Long cursorId, Pageable pageable);
Slice<Note> findAllBookmarkedAndByArtistId(boolean hasLyrics, Long artistId, Long userId, Long cursorId, Pageable pageable);
Slice<Note> findAllBySongId(boolean hasLyrics, Long songId, Long userId, Long cursorId, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,33 @@ public Slice<Note> findAllByArtistIds(boolean hasLyrics, List<Long> artistsIds,
return new SliceImpl<>(content, pageable, QueryDslUtils.checkIfHasNext(pageable, content));
}

@Override
public Slice<Note> findAll(boolean hasLyrics, List<Long> artistsIds, Long userId, Long cursorId, Pageable pageable) {
List<Note> content = jpaQueryFactory
.selectFrom(note)
.leftJoin(note.lyrics).fetchJoin()
.join(note.publisher).fetchJoin()
.join(note.song).fetchJoin()
.join(song.artist).fetchJoin()
.leftJoin(note.comments).fetchJoin()
.where(
hasLyrics(hasLyrics),
artistsIds == null || artistsIds.isEmpty() ? null : note.song.artist.id.in(artistsIds),
note.deletedAt.isNull(),
QueryDslUtils.ltCursorId(cursorId, note.id),
note.publisher.notIn(
JPAExpressions.select(block.blocked)
.from(block)
.where(block.blocker.id.eq(userId).and(block.deletedAt.isNull()))
)
)
.orderBy(note.id.desc())
.limit(pageable.getPageSize() + 1)
.fetch();

return new SliceImpl<>(content, pageable, QueryDslUtils.checkIfHasNext(pageable, content));
}

@Override
public Slice<Note> findAllByArtistId(boolean hasLyrics, Long artistId, Long userId, Long cursorId, Pageable pageable) {
List<Note> content = jpaQueryFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,16 @@ public CursorBasePaginatedResponse<NoteGetResponse> getNotesByUserId(boolean has
return CursorBasePaginatedResponse.of(notes);
}

public CursorBasePaginatedResponse<NoteGetResponse> getNotesOfFavoriteArtists(boolean hasLyrics, Long userId, Long cursor, int size) {
List<Long> artistsIds = favoriteArtistQueryRepository.findAllByUserIdFetchArtist(userId)
.stream()
.map(favoriteArtist -> favoriteArtist.getArtist().getId())
.toList();

Slice<NoteGetResponse> notes = noteQueryRepository.findAllByArtistIds(hasLyrics, artistsIds, userId, cursor, PageRequest.ofSize(size))
public CursorBasePaginatedResponse<NoteGetResponse> getNotes(boolean hasLyrics, boolean isFavoriteArtistsOnly, Long userId, Long cursor, int size) {
List<Long> artistsIds = null;
if (isFavoriteArtistsOnly) {
artistsIds = favoriteArtistQueryRepository.findAllByUserIdFetchArtist(userId)
.stream()
.map(favoriteArtist -> favoriteArtist.getArtist().getId())
.toList();
}

Slice<NoteGetResponse> notes = noteQueryRepository.findAll(hasLyrics, artistsIds, userId, cursor, PageRequest.ofSize(size))
.map(note -> NoteGetResponse.of(note, userId));

return CursorBasePaginatedResponse.of(notes);
Expand Down
Loading
Loading