Skip to content
Open
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
39 changes: 30 additions & 9 deletions src/main/kotlin/playlist/controller/PlaylistController.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.wafflestudio.seminar.spring2023.playlist.controller

import com.wafflestudio.seminar.spring2023.playlist.service.Playlist
import com.wafflestudio.seminar.spring2023.playlist.service.PlaylistException
import com.wafflestudio.seminar.spring2023.playlist.service.PlaylistGroup
import com.wafflestudio.seminar.spring2023.playlist.service.*
import com.wafflestudio.seminar.spring2023.user.service.AuthenticateException
import com.wafflestudio.seminar.spring2023.user.service.Authenticated
import com.wafflestudio.seminar.spring2023.user.service.User
import com.wafflestudio.seminar.spring2023.user.service.UserException
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.ExceptionHandler
Expand All @@ -14,40 +14,61 @@ import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class PlaylistController {
class PlaylistController(
private val playlistService: PlaylistService,
private val playlistLikeService: PlaylistLikeService,
) {

@GetMapping("/api/v1/playlist-groups")
fun getPlaylistGroup(): PlaylistGroupsResponse {
TODO()
return PlaylistGroupsResponse(playlistService.getGroups())
}

@GetMapping("/api/v1/playlists/{id}")
fun getPlaylist(
@PathVariable id: Long,
user: User?,
): PlaylistResponse {
TODO()
return PlaylistResponse(
playlist = playlistService.get(id),
isLiked = user?.let { playlistLikeService.exists(id, it.id) } ?: false
)
}

@PostMapping("/api/v1/playlists/{id}/likes")
fun likePlaylist(
@PathVariable id: Long,
@Authenticated user: User,
) {
TODO()
playlistLikeService.create(id, user.id)
}

@DeleteMapping("/api/v1/playlists/{id}/likes")
fun undoLikePlaylist(
@PathVariable id: Long,
@Authenticated user: User,
) {
TODO()
playlistLikeService.delete(id, user.id)
}

@ExceptionHandler
fun handleException(e: UserException): ResponseEntity<Unit> {
val status = when(e) {
is AuthenticateException -> 401
else -> 400
}

return ResponseEntity.status(status).build()
}

@ExceptionHandler
fun handleException(e: PlaylistException): ResponseEntity<Unit> {
TODO()
val status = when (e) {
is PlaylistNotFoundException -> 404
is PlaylistAlreadyLikedException, is PlaylistNeverLikedException -> 409
}

return ResponseEntity.status(status).build()
}
}

Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import jakarta.persistence.*

@Entity(name = "playlists")
class PlaylistEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
val title: String,
val subtitle: String,
val image: String,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id")
val group: PlaylistGroupEntity,
@OneToMany(mappedBy = "playlist")
val likeUsers: List<PlaylistLikesEntity>,
@OneToMany(mappedBy = "playlist")
val songs: List<PlaylistSongEntity>,
)
14 changes: 14 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistGroupEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import jakarta.persistence.*

@Entity(name = "playlist_groups")
class PlaylistGroupEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
val title: String,
val open: Boolean,
@OneToMany(mappedBy = "group")
val playlists: List<PlaylistEntity>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface PlaylistGroupRepository: JpaRepository<PlaylistGroupEntity, Long> {
@Query("select a from playlist_groups a inner join fetch a.playlists where a.open = :open")
fun findNotEmptyGroupsByOpen(open: Boolean): List<PlaylistGroupEntity>
}
18 changes: 18 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistLikesEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import com.wafflestudio.seminar.spring2023.playlist.service.Playlist
import com.wafflestudio.seminar.spring2023.user.repository.UserEntity
import jakarta.persistence.*

@Entity(name = "playlist_likes")
class PlaylistLikesEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "playlist_id")
val playlist: PlaylistEntity,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
val user: UserEntity,
)
12 changes: 12 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistLikesRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface PlaylistLikesRepository: JpaRepository<PlaylistLikesEntity, Long> {
@Query("select count(pl.id) > 0 from playlist_likes pl where pl.playlist.id=:playlistId and pl.user.id=:userId")
fun existsByPlaylistIdAndUserId(playlistId: Long, userId: Long): Boolean

@Query("select pl from playlist_likes pl where pl.playlist.id=:playlistId and pl.user.id=:userId")
fun findByPlaylistIdAndUserId(playlistId: Long, userId: Long): PlaylistLikesEntity?
}
14 changes: 14 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface PlaylistRepository : JpaRepository<PlaylistEntity, Long> {
@Query("""
select p from playlists p
left join fetch p.songs ps
join fetch ps.song s
where p.id = :id
""")
fun findByIdWithJoinFetch(id: Long): PlaylistEntity?
}
17 changes: 17 additions & 0 deletions src/main/kotlin/playlist/repository/PlaylistSongEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.wafflestudio.seminar.spring2023.playlist.repository

import com.wafflestudio.seminar.spring2023.song.repository.SongEntity
import jakarta.persistence.*

@Entity(name = "playlist_songs")
class PlaylistSongEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "playlist_id")
val playlist: PlaylistEntity,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "song_id")
val song: SongEntity,
)
14 changes: 13 additions & 1 deletion src/main/kotlin/playlist/service/Playlist.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.wafflestudio.seminar.spring2023.playlist.service

import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistEntity
import com.wafflestudio.seminar.spring2023.song.repository.SongEntity
import com.wafflestudio.seminar.spring2023.song.service.Song

data class Playlist(
Expand All @@ -8,4 +10,14 @@ data class Playlist(
val subtitle: String,
val image: String,
val songs: List<Song>,
)
) {
constructor(playlistEntity: PlaylistEntity, songEntities: List<SongEntity>): this(
id = playlistEntity.id,
title = playlistEntity.title,
subtitle = playlistEntity.title,
image = playlistEntity.image,
songs = songEntities.map {
Song(it)
}.sortedBy { it.id }
)
}
11 changes: 10 additions & 1 deletion src/main/kotlin/playlist/service/PlaylistBrief.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package com.wafflestudio.seminar.spring2023.playlist.service

import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistEntity

data class PlaylistBrief(
val id: Long,
val title: String,
val subtitle: String,
val image: String,
)
) {
constructor(entity: PlaylistEntity): this(
id = entity.id,
title = entity.title,
subtitle = entity.subtitle,
image = entity.image
)
}
12 changes: 11 additions & 1 deletion src/main/kotlin/playlist/service/PlaylistGroup.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package com.wafflestudio.seminar.spring2023.playlist.service

import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistGroupEntity

data class PlaylistGroup(
val id: Long,
val title: String,
val playlists: List<PlaylistBrief>,
)
) {
constructor(entity: PlaylistGroupEntity): this(
id = entity.id,
title = entity.title,
playlists = entity.playlists.map {
PlaylistBrief(it)
}
)
}
33 changes: 29 additions & 4 deletions src/main/kotlin/playlist/service/PlaylistLikeServiceImpl.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
package com.wafflestudio.seminar.spring2023.playlist.service

import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistLikesEntity
import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistLikesRepository
import com.wafflestudio.seminar.spring2023.playlist.repository.PlaylistRepository
import com.wafflestudio.seminar.spring2023.user.repository.UserRepository
import com.wafflestudio.seminar.spring2023.user.service.UserNotFoundException
import org.springframework.stereotype.Service

@Service
class PlaylistLikeServiceImpl : PlaylistLikeService {
class PlaylistLikeServiceImpl(
val playlistLikesRepository: PlaylistLikesRepository,
val playlistRepository: PlaylistRepository,
val userRepository: UserRepository,
) : PlaylistLikeService {

override fun exists(playlistId: Long, userId: Long): Boolean {
TODO()
return playlistLikesRepository.existsByPlaylistIdAndUserId(playlistId, userId)
}

override fun create(playlistId: Long, userId: Long) {
TODO()
if (exists(playlistId, userId)) throw PlaylistAlreadyLikedException()
val playlistEntity = playlistRepository.findById(playlistId).orElseThrow {
PlaylistNotFoundException()
}
val userEntity = userRepository.findById(userId).orElseThrow {
UserNotFoundException()
}
playlistLikesRepository.save(
PlaylistLikesEntity(
playlist = playlistEntity,
user = userEntity,
)
)
}

override fun delete(playlistId: Long, userId: Long) {
TODO()
val playlistLikesEntity = playlistLikesRepository.findByPlaylistIdAndUserId(playlistId, userId)
?: throw PlaylistNeverLikedException()
playlistLikesRepository.delete(
playlistLikesEntity
)
}
}
18 changes: 14 additions & 4 deletions src/main/kotlin/playlist/service/PlaylistServiceImpl.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package com.wafflestudio.seminar.spring2023.playlist.service

import com.wafflestudio.seminar.spring2023.playlist.repository.*
import com.wafflestudio.seminar.spring2023.song.repository.SongRepository
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Service

@Primary
@Service
class PlaylistServiceImpl : PlaylistService {
class PlaylistServiceImpl(
val playlistGroupRepository: PlaylistGroupRepository,
val playlistRepository: PlaylistRepository,
val songRepository: SongRepository,
) : PlaylistService {

override fun getGroups(): List<PlaylistGroup> {
TODO()
return playlistGroupRepository.findNotEmptyGroupsByOpen(true).map {
PlaylistGroup(it)
}
}

override fun get(id: Long): Playlist {
TODO()
val playlistEntity = playlistRepository.findByIdWithJoinFetch(id) ?: throw PlaylistNotFoundException()
val songEntities = songRepository.findByIdsWithJoinFetch(playlistEntity.songs.map { it.song.id })
return Playlist(playlistEntity, songEntities)
}
}
}
8 changes: 5 additions & 3 deletions src/main/kotlin/song/controller/SongController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@ import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
class SongController {
class SongController(
private val songService: SongService
) {

@GetMapping("/api/v1/songs")
fun searchSong(
@RequestParam keyword: String,
): SearchSongResponse {
TODO()
return SearchSongResponse(songService.search(keyword))
}

@GetMapping("/api/v1/albums")
fun searchAlbum(
@RequestParam keyword: String,
): SearchAlbumResponse {
TODO()
return SearchAlbumResponse(songService.searchAlbum(keyword))
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/main/kotlin/song/repository/AlbumRepository.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package com.wafflestudio.seminar.spring2023.song.repository

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface AlbumRepository : JpaRepository<AlbumEntity, Long>
interface AlbumRepository : JpaRepository<AlbumEntity, Long> {
@Query("""
select a from albums a
join fetch a.artist ar
where a.title like %:keyword% order by length(a.title) asc
""")
fun findAllByTitleKeywordWithJoinFetch(keyword: String): List<AlbumEntity>
}
Loading