diff --git a/src/main/kotlin/config/BremerConfig.kt b/src/main/kotlin/config/BremerConfig.kt index 5aab926..c420f26 100644 --- a/src/main/kotlin/config/BremerConfig.kt +++ b/src/main/kotlin/config/BremerConfig.kt @@ -4,7 +4,7 @@ package net.piedpiper.bremer.config -import net.piedpiper.bremer.service.app.LoginAppService +import net.piedpiper.bremer.service.LoginService import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger import org.springframework.beans.factory.annotation.Qualifier @@ -30,8 +30,8 @@ @Configuration @EnableWebSecurity class WebSecurityConfig( - @Qualifier("bremer.service.LoginAppService") - private val loginAppService: LoginAppService + @Qualifier("bremer.service.LoginService") + private val loginService: LoginService ) { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { @@ -57,7 +57,7 @@ .logoutSuccessUrl("/bremer/login.html?logout") } .csrf { it.disable() } - .userDetailsService(loginAppService) + .userDetailsService(loginService) return http.build() } } diff --git a/src/main/kotlin/controller/api/AudioApiController.kt b/src/main/kotlin/controller/api/AudioApiController.kt index c3ada9e..fa3b81e 100644 --- a/src/main/kotlin/controller/api/AudioApiController.kt +++ b/src/main/kotlin/controller/api/AudioApiController.kt @@ -5,7 +5,7 @@ package net.piedpiper.bremer.controller.api import net.piedpiper.bremer.model.api.AudioListResponse -import net.piedpiper.bremer.service.app.AudioAppService +import net.piedpiper.bremer.service.AudioService import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -13,21 +13,22 @@ import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -@RestController +@RestController("bremer.controller.AudioApiController") @RequestMapping("bremer/api/audio") class AudioApiController( - @Qualifier("bremer.service.AudioAppService") - private val audioAppService: AudioAppService + @Qualifier("bremer.service.AudioService") + private val audioService: AudioService ) { @GetMapping fun getAudioList( @RequestParam("audio", required = false) audioName: String?, @RequestParam("artist", required = false) artistName: String?, - @RequestParam("album", required = false) albumName: String? + @RequestParam("album", required = false) albumName: String?, + @RequestParam("tag", required = false) tagName: String? ): ResponseEntity = - ResponseEntity.ok(audioAppService.getByKeywords(audioName, artistName, albumName)) + ResponseEntity.ok(audioService.getByKeywords(audioName, artistName, albumName, tagName)) @GetMapping("history") fun getLeastRecentlyPlayedList(): ResponseEntity = - ResponseEntity.ok(audioAppService.getLeastRecentlyAccessedAudio()) + ResponseEntity.ok(audioService.getLeastRecentlyAccessedAudio()) } \ No newline at end of file diff --git a/src/main/kotlin/controller/api/PlaylistApiController.kt b/src/main/kotlin/controller/api/PlaylistApiController.kt index 5e4b8ad..e100bad 100644 --- a/src/main/kotlin/controller/api/PlaylistApiController.kt +++ b/src/main/kotlin/controller/api/PlaylistApiController.kt @@ -5,11 +5,10 @@ package net.piedpiper.bremer.controller.api import jakarta.validation.Valid -import net.piedpiper.bremer.entity.AudioEntity -import net.piedpiper.bremer.model.PlaylistAudioResponse -import net.piedpiper.bremer.model.PlaylistListResponse -import net.piedpiper.bremer.model.PlaylistRequest -import net.piedpiper.bremer.service.app.PlaylistAppService +import net.piedpiper.bremer.model.api.PlaylistAudioResponse +import net.piedpiper.bremer.model.api.PlaylistListResponse +import net.piedpiper.bremer.model.api.PlaylistRequest +import net.piedpiper.bremer.service.PlaylistService import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -18,34 +17,32 @@ import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import java.util.UUID -@RestController +@RestController("bremer.controller.PlaylistApiController") @RequestMapping("bremer/api/playlist") class PlaylistApiController( - @Qualifier("bremer.service.PlaylistAppService") - private val playlistAppService: PlaylistAppService, + @Qualifier("bremer.service.PlaylistService") + private val playlistService: PlaylistService, ) { @GetMapping fun getAll(): ResponseEntity = - ResponseEntity.ok(playlistAppService.getAllPlaylists()) + ResponseEntity.ok(playlistService.getAllPlaylists()) @GetMapping("{slug}") fun get(@PathVariable("slug") slug: String): ResponseEntity = - ResponseEntity.ok(playlistAppService.getPlaylist(slug)) + ResponseEntity.ok(playlistService.getPlaylist(slug)) @PostMapping fun create( @Valid @RequestBody request: PlaylistRequest ): ResponseEntity = - ResponseEntity.ok(playlistAppService.createPlaylist(request)) + ResponseEntity.ok(playlistService.createPlaylist(request)) @PutMapping("{slug}") fun update( @PathVariable("slug") slug: String, @Valid @RequestBody request: PlaylistRequest ): ResponseEntity = - ResponseEntity.ok(playlistAppService.updatePlaylist(slug, request)) + ResponseEntity.ok(playlistService.updatePlaylist(slug, request)) } diff --git a/src/main/kotlin/controller/view/AudioViewController.kt b/src/main/kotlin/controller/view/AudioViewController.kt index 13a9a62..c1768de 100644 --- a/src/main/kotlin/controller/view/AudioViewController.kt +++ b/src/main/kotlin/controller/view/AudioViewController.kt @@ -5,7 +5,7 @@ package net.piedpiper.bremer.controller.view import jakarta.servlet.http.HttpServletResponse -import net.piedpiper.bremer.service.app.AudioAppService +import net.piedpiper.bremer.service.AudioService import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.MediaType import org.springframework.stereotype.Controller @@ -17,8 +17,8 @@ @Controller("bremer.controller.AudioController") @RequestMapping("bremer/audio") class AudioViewController( - @Qualifier("bremer.service.AudioAppService") - private val audioAppService: AudioAppService + @Qualifier("bremer.service.AudioService") + private val audioService: AudioService ) { @GetMapping("{slug}") @@ -26,7 +26,7 @@ @PathVariable("slug") slug: String, response: HttpServletResponse ) { - val file = audioAppService.getAudioFile(slug) + val file = audioService.getAudioFile(slug) response.outputStream.use { response.setContentLengthLong(file.length()) response.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE diff --git a/src/main/kotlin/dao/AudioDao.kt b/src/main/kotlin/dao/AudioDao.kt index a306032..cebd621 100644 --- a/src/main/kotlin/dao/AudioDao.kt +++ b/src/main/kotlin/dao/AudioDao.kt @@ -4,10 +4,7 @@ package net.piedpiper.bremer.dao -import net.piedpiper.bremer.entity.AlbumEntity -import net.piedpiper.bremer.entity.ArtistEntity -import net.piedpiper.bremer.entity.AudioEntity -import net.piedpiper.bremer.entity.AudioNameEntity +import net.piedpiper.bremer.entity.* import net.piedpiper.bremer.utils.SelectSQLBuilder import net.piedpiper.bremer.utils.WHERE_IN import org.apache.ibatis.annotations.* @@ -30,6 +27,10 @@ fun findAllByAlbumIdIn(@Param("albumIds") albumIds: List): List @ResultMap("net.piedpiper.bremer.AudioEntity") + @SelectProvider(type = Sql::class, method = "findAllByTagIdIn") + fun findAllByTagIdIn(@Param("tagIds") tagIds: List): List + + @ResultMap("net.piedpiper.bremer.AudioEntity") @SelectProvider(type = Sql::class, method = "findAllByIdIn") fun findAllByIdIn(@Param("ids") ids: List): List @@ -72,6 +73,7 @@ .leftOuterJoin(AudioNameEntity::class, "audio.id = audio_name.audio_id") .toSql() .WHERE_IN("audio.album_id", "albumIds", albumIds.size) + .ORDER_BY("audio.album_id, audio.sequence") .toString() @JvmStatic @@ -82,6 +84,7 @@ .leftOuterJoin(AudioNameEntity::class, "audio.id = audio_name.audio_id") .toSql() .WHERE_IN("audio.id", "ids", ids.size) + .ORDER_BY("audio.album_id, audio.sequence") .toString() @JvmStatic @@ -92,6 +95,19 @@ .leftOuterJoin(AudioNameEntity::class, "audio.id = audio_name.audio_id") .toSql() .WHERE_IN("audio.slug", "slugs", slugs.size) + .ORDER_BY("audio.album_id, audio.sequence") + .toString() + + @JvmStatic + fun findAllByTagIdIn(@Param("tagIds") tagIds: List): String = + SelectSQLBuilder(AudioEntity::class) + .leftOuterJoin(AlbumEntity::class, "audio.album_id = album.id") + .leftOuterJoin(ArtistEntity::class, "album.artist_id = artist.id", AlbumEntity::class) + .leftOuterJoin(AudioNameEntity::class, "audio.id = audio_name.audio_id") + .leftOuterJoin(AudioTagEntity::class, "audio.id = audio_tag.audio_id") + .toSql() + .WHERE_IN("audio_tag.tag_id", "tagIds", tagIds.size) + .ORDER_BY("audio.album_id, audio.sequence") .toString() @JvmStatic diff --git a/src/main/kotlin/dao/PlaylistDao.kt b/src/main/kotlin/dao/PlaylistDao.kt index 5c024d1..3511149 100644 --- a/src/main/kotlin/dao/PlaylistDao.kt +++ b/src/main/kotlin/dao/PlaylistDao.kt @@ -24,13 +24,16 @@ fun findOneBySlug(@Param("slug") slug: String): PlaylistEntity? @ResultMap("net.piedpiper.bremer.PlaylistEntity") - @Select("SELECT * FROM playlist") - fun findAll(): List + @Select("SELECT * FROM playlist ORDER BY sequence ASC") + fun findAllOrderBySequence(): List @InsertProvider(type = Sql::class, method = "insertOne") @Options(useGeneratedKeys = true, keyProperty = "id") fun insertOne(@Param("entity") entity: PlaylistEntity): Boolean + @Delete("DELETE FROM playlist WHERE slug = #{slug}") + fun deleteBySlug(@Param("slug") slug: String): Boolean + @UpdateProvider(type = Sql::class, method = "updateOne") fun updateOne(@Param("entity") entity: PlaylistEntity) diff --git a/src/main/kotlin/dao/TagDao.kt b/src/main/kotlin/dao/TagDao.kt new file mode 100644 index 0000000..5ef8151 --- /dev/null +++ b/src/main/kotlin/dao/TagDao.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023. yo-saito. All Rights Reserved. + */ + +package net.piedpiper.bremer.dao + +import net.piedpiper.bremer.entity.TagEntity +import org.apache.ibatis.annotations.Mapper +import org.apache.ibatis.annotations.Param +import org.apache.ibatis.annotations.ResultMap +import org.apache.ibatis.annotations.Select +import org.springframework.stereotype.Repository + +@Repository("bremer.dao.TagDao") +@Mapper +interface TagDao { + + @ResultMap("net.piedpiper.bremer.TagEntity") + @Select("SELECT * FROM tag") + fun findAll(): List + + @ResultMap("net.piedpiper.bremer.TagEntity") + @Select("SELECT * FROM tag WHERE name LIKE CONCAT('%', #{nameLike}, '%') LIMIT #{limit}") + fun findAllByNameLikeLimit( + @Param("nameLike") nameLike: String, + @Param("limit") limit: Int + ): List +} \ No newline at end of file diff --git a/src/main/kotlin/entity/Audio.kt b/src/main/kotlin/entity/Audio.kt deleted file mode 100644 index f8f9f72..0000000 --- a/src/main/kotlin/entity/Audio.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023. yo-saito. All Rights Reserved. - */ - -package net.piedpiper.bremer.entity - -import net.piedpiper.bremer.utils.sql.Column -import net.piedpiper.bremer.utils.sql.Table -import java.time.LocalDateTime - -@Table("audio") -data class AudioEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("slug") - var slug: String = "", - @property:Column("name") - var name: String = "", - @property:Column("album_id") - var albumId: Long = 0L, - @property:Column("sequence") - var sequence: Int = 0, - @property:Column("path") - var path: String = "", - // join - var album: AlbumEntity? = null, - var aliasNames: List? = null -) - -@Table("audio_name") -data class AudioNameEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("audio_id") - var audioId: Long = 0L, - @property:Column("name") - var name: String = "" -) - -@Table("album") -data class AlbumEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("artist_id") - var artistId: Long = 0L, - @property:Column("name") - var name: String = "", - // join - var artist: ArtistEntity? = null -) - -@Table("artist") -data class ArtistEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("name") - var name: String = "", -) - -@Table("audio_play_history") -data class AudioPlayHistoryEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("audio_id") - var audioId: Long = 0L, - @property:Column("last_played_at") - var lastPlayedAt: LocalDateTime = LocalDateTime.MIN -) diff --git a/src/main/kotlin/entity/Entity.kt b/src/main/kotlin/entity/Entity.kt new file mode 100644 index 0000000..d456668 --- /dev/null +++ b/src/main/kotlin/entity/Entity.kt @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023. yo-saito. All Rights Reserved. + */ + +package net.piedpiper.bremer.entity + +import net.piedpiper.bremer.utils.sql.Column +import net.piedpiper.bremer.utils.sql.Table +import java.time.LocalDateTime + +@Table("audio") +data class AudioEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("slug") + var slug: String = "", + @property:Column("name") + var name: String = "", + @property:Column("album_id") + var albumId: Long = 0L, + @property:Column("sequence") + var sequence: Int = 0, + @property:Column("path") + var path: String = "", + // join + var album: AlbumEntity? = null, + var aliasNames: List? = null +) + +@Table("audio_name") +data class AudioNameEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("audio_id") + var audioId: Long = 0L, + @property:Column("name") + var name: String = "" +) + +@Table("album") +data class AlbumEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("artist_id") + var artistId: Long = 0L, + @property:Column("name") + var name: String = "", + // join + var artist: ArtistEntity? = null +) + +@Table("artist") +data class ArtistEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("name") + var name: String = "", +) + +@Table("audio_tag") +data class AudioTagEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("audio_id") + var audioId: Long = 0L, + @property:Column("tag_id") + var tagId: Long = 0L +) + +@Table("user") +data class UserEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("account_id") + var accountId: String = "", + @property:Column("secret") + var secret: String = "", +) + +@Table("audio_play_history") +data class AudioPlayHistoryEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("audio_id") + var audioId: Long = 0L, + @property:Column("last_played_at") + var lastPlayedAt: LocalDateTime = LocalDateTime.MIN +) + +@Table("playlist") +data class PlaylistEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("slug") + var slug: String = "", + @property:Column("name") + var name: String = "", + @property:Column("sequence") + var sequence: Int = 0, + // join + var playlistAudio: List = mutableListOf() +) + +@Table("playlist_audio") +data class PlaylistAudioEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("playlist_id") + var playlistId: Long = 0L, + @property:Column("sequence") + var sequence: Int = 0, + @property:Column("audio_id") + var audioId: Long = 0L +) + +@Table("tag") +data class TagEntity( + @property:Column("id", insertable = false, updatable = false) + var id: Long = 0L, + @property:Column("name") + var name: String = "", +) diff --git a/src/main/kotlin/entity/Playlist.kt b/src/main/kotlin/entity/Playlist.kt deleted file mode 100644 index e9680a2..0000000 --- a/src/main/kotlin/entity/Playlist.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023. yo-saito. All Rights Reserved. - */ - -package net.piedpiper.bremer.entity - -import net.piedpiper.bremer.utils.sql.Column -import net.piedpiper.bremer.utils.sql.Table - - -@Table("playlist") -data class PlaylistEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("slug") - var slug: String = "", - @property:Column("name") - var name: String = "", - // join - var playlistAudio: List = mutableListOf() -) - -@Table("playlist_audio") -data class PlaylistAudioEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("playlist_id") - var playlistId: Long = 0L, - @property:Column("sequence") - var sequence: Int = 0, - @property:Column("audio_id") - var audioId: Long = 0L -) diff --git a/src/main/kotlin/entity/User.kt b/src/main/kotlin/entity/User.kt deleted file mode 100644 index 90f2d5c..0000000 --- a/src/main/kotlin/entity/User.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2023. yo-saito. All Rights Reserved. - */ - -package net.piedpiper.bremer.entity - -import net.piedpiper.bremer.utils.sql.Column -import net.piedpiper.bremer.utils.sql.Table - -@Table("user") -data class UserEntity( - @property:Column("id", insertable = false, updatable = false) - var id: Long = 0L, - @property:Column("account_id") - var accountId: String = "", - @property:Column("secret") - var secret: String = "", -) \ No newline at end of file diff --git a/src/main/kotlin/model/api/Api.kt b/src/main/kotlin/model/api/Api.kt new file mode 100644 index 0000000..d054266 --- /dev/null +++ b/src/main/kotlin/model/api/Api.kt @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023. yo-saito. All Rights Reserved. + */ + +package net.piedpiper.bremer.model.api + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import jakarta.validation.constraints.NotBlank +import net.piedpiper.bremer.entity.AudioEntity +import net.piedpiper.bremer.entity.PlaylistEntity + +data class AudioListResponse( + private val entities: List +) { + val audio: List