GitBucket
4.23.0
Toggle navigation
Sign in
Files
Branches
1
Releases
Issues
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
yhornisse
/
bremer
Browse code
fix a bug and refactor
master
1 parent
4e7fae2
commit
397b3238a293f65cef563484608a0433041d69bf
yhornisse
authored
on 14 Aug 2023
Patch
Showing
3 changed files
src/main/kotlin/controller/api/PlaylistApiController.kt
src/main/kotlin/entity/Entity.kt
src/main/kotlin/service/PlaylistService.kt
Ignore Space
Show notes
View
src/main/kotlin/controller/api/PlaylistApiController.kt
/* * Copyright (c) 2023. yo-saito. All Rights Reserved. */ package net.piedpiper.bremer.controller.api import jakarta.validation.Valid import net.piedpiper.bremer.model.api.AllPlaylistResponse import net.piedpiper.bremer.model.api.PlaylistAudioRequest import net.piedpiper.bremer.model.api.PlaylistAudioResponse import net.piedpiper.bremer.model.api.PlaylistRequest import net.piedpiper.bremer.service.PlaylistService import org.apache.logging.log4j.LogManager import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* @RestController("bremer.controller.PlaylistApiController") @RequestMapping("bremer/api/playlist") class PlaylistApiController( @Qualifier("bremer.service.PlaylistService") private val playlistService: PlaylistService, ) { companion object{ private val log = LogManager.getLogger(PlaylistApiController::class.java) } @GetMapping fun getAllPlaylists(): ResponseEntity<AllPlaylistResponse> = ResponseEntity.ok(playlistService.getAllPlaylists()) @PostMapping fun createPlaylist( @Valid @RequestBody request: PlaylistRequest ): ResponseEntity<Void> { playlistService.createPlaylist(request) return ResponseEntity.ok(null) } @PutMapping("{slug}") fun updatePlaylist( @PathVariable("slug") slug: String, @Valid @RequestBody request: PlaylistRequest ): ResponseEntity<Void> { playlistService.updatePlaylist(slug, request) return ResponseEntity.ok(null) } @DeleteMapping("{slug}") fun deletePlaylist( @PathVariable("slug") slug: String ): ResponseEntity<Void> { playlistService.deletePlaylist(slug) return ResponseEntity.ok(null) } @GetMapping("{slug}") fun getAudioList(@PathVariable("slug") slug: String): ResponseEntity<PlaylistAudioResponse> = ResponseEntity.ok(playlistService.getPlaylist(slug)) @PutMapping("audio/{slug}") fun updateAudioList( @PathVariable("slug") slug: String, @Valid @RequestBody request: PlaylistAudioRequest ): ResponseEntity<Void> { playlistService.updatePlaylistAudioList(slug, request) return ResponseEntity.ok(null) } }
/* * Copyright (c) 2023. yo-saito. All Rights Reserved. */ package net.piedpiper.bremer.controller.api import jakarta.validation.Valid import net.piedpiper.bremer.model.api.AllPlaylistResponse import net.piedpiper.bremer.model.api.PlaylistAudioRequest import net.piedpiper.bremer.model.api.PlaylistAudioResponse import net.piedpiper.bremer.model.api.PlaylistRequest import net.piedpiper.bremer.service.PlaylistService import org.apache.logging.log4j.LogManager import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* @RestController("bremer.controller.PlaylistApiController") @RequestMapping("bremer/api/playlist") class PlaylistApiController( @Qualifier("bremer.service.PlaylistService") private val playlistService: PlaylistService, ) { companion object{ private val log = LogManager.getLogger(PlaylistApiController::class.java) } @GetMapping fun getAllPlaylists(): ResponseEntity<AllPlaylistResponse> = ResponseEntity.ok(playlistService.getAllPlaylists()) @PostMapping fun createPlaylist( @Valid @RequestBody request: PlaylistRequest ): ResponseEntity<Void> { playlistService.createPlaylist(request) return ResponseEntity.ok(null) } @PutMapping("{slug}") fun updatePlaylist( @PathVariable("slug") slug: String, @Valid @RequestBody request: PlaylistRequest ): ResponseEntity<Void> { playlistService.updatePlaylist(slug, request) return ResponseEntity.ok(null) } @DeleteMapping("{slug}") fun deletePlaylist( @PathVariable("slug") slug: String ): ResponseEntity<Void> { playlistService.deletePlaylist(slug) return ResponseEntity.ok(null) } @GetMapping("{slug}") fun getAudioList(@PathVariable("slug") slug: String): ResponseEntity<PlaylistAudioResponse> = ResponseEntity.ok(playlistService.getPlaylist(slug)) @PutMapping("audio/{slug}") fun updateAudioList( @PathVariable("slug") slug: String, @Valid @RequestBody request: PlaylistAudioRequest ): ResponseEntity<Void> { log.info("recieve: {}", request) playlistService.updatePlaylistAudioList(slug, request) return ResponseEntity.ok(null) } }
Ignore Space
Show notes
View
src/main/kotlin/entity/Entity.kt
/* * 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<AudioNameEntity>? = 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<PlaylistAudioEntity> = mutableListOf() ) @Table("playlist_audio") data class PlaylistAudioEntity( @property:Column("id", 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("slug") var slug: String = "", @property:Column("name") var name: String = "", )
/* * 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<AudioNameEntity>? = 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<PlaylistAudioEntity> = 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("slug") var slug: String = "", @property:Column("name") var name: String = "", )
Ignore Space
Show notes
View
src/main/kotlin/service/PlaylistService.kt
/* * Copyright (c) 2023. yo-saito. All Rights Reserved. */ package net.piedpiper.bremer.service import net.piedpiper.bremer.dao.AudioDao import net.piedpiper.bremer.dao.PlaylistAudioDao import net.piedpiper.bremer.dao.PlaylistDao import net.piedpiper.bremer.entity.AudioEntity import net.piedpiper.bremer.entity.PlaylistAudioEntity import net.piedpiper.bremer.entity.PlaylistEntity import net.piedpiper.bremer.exception.BadRequestException import net.piedpiper.bremer.exception.NotFoundException import net.piedpiper.bremer.model.api.AllPlaylistResponse import net.piedpiper.bremer.model.api.PlaylistAudioRequest import net.piedpiper.bremer.model.api.PlaylistAudioResponse import net.piedpiper.bremer.model.api.PlaylistRequest import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @Service("bremer.service.PlaylistService") class PlaylistService( @Qualifier("bremer.dao.PlaylistDao") private val playlistDao: PlaylistDao, @Qualifier("bremer.dao.PlaylistAudioDao") private val playlistAudioDao: PlaylistAudioDao, @Qualifier("bremer.dao.AudioDao") private val audioDao: AudioDao ) { @Transactional fun getAllPlaylists(): AllPlaylistResponse = AllPlaylistResponse(playlistDao.findAllOrderBySequence()) @Transactional fun getPlaylist(slug: String): PlaylistAudioResponse = playlistDao.findOneBySlug(slug) ?.let { PlaylistAudioResponse( playlistEntity = it, audioEntityList = it?.playlistAudio ?.mapNotNull { it.audioId } ?.let { ids -> findAllByOrderedIds(ids) } ) } ?: throw NotFoundException() private fun findAllByOrderedIds(ids: List<Long>): List<AudioEntity> { if (ids.isEmpty()) { return emptyList() } val id2idx = ids.mapIndexed { index, id -> id to index }.toMap() return audioDao.findAllByIdIn(ids) .sortedBy { id2idx[it.id] } } private fun findAllByOrderedSlugs(slugs: List<String>): List<AudioEntity> { if (slugs.isEmpty()) { return emptyList() } val slug2idx = slugs.mapIndexed { index, slug -> slug to index }.toMap() return audioDao.findAllBySlugIn(slugs) .sortedBy { slug2idx[it.slug] } } @Transactional fun createPlaylist(request: PlaylistRequest) { playlistDao.insertOne( PlaylistEntity( slug = UUID.randomUUID().toString(), name = request.name ) ) } @Transactional fun updatePlaylist(slug: String, request: PlaylistRequest) { val entity = playlistDao.findOneBySlugWithLock(slug) ?: throw NotFoundException() entity.name = request.name playlistDao.updateOne(entity) } @Transactional fun deletePlaylist(slug: String) { val playlist = playlistDao.findOneBySlugWithLock(slug); if (playlist?.playlistAudio?.isNotEmpty() == true) { playlistAudioDao.deleteAllByIds( playlist.playlistAudio.map { it.id }) } playlistDao.deleteBySlug(slug) } @Transactional fun updatePlaylistAudioList( slug: String, request: PlaylistAudioRequest ) { playlistDao.findOneBySlug(slug) ?.let { playlist -> val oldPlaylistAudioList = playlist.playlistAudio if (oldPlaylistAudioList.isNotEmpty()) { playlistAudioDao.deleteAllByIds(playlist.playlistAudio .map { it.id } .toList()) } val audioList = findAllByOrderedSlugs(request.audioSlugs) if (request.audioSlugs.size != audioList.size) { throw BadRequestException() } audioList.forEachIndexed { index, audio -> val a = if (index < oldPlaylistAudioList.count()) { oldPlaylistAudioList[index] } else { PlaylistAudioEntity() } a.playlistId = playlist.id a.sequence = index a.audioId = audio.id playlistAudioDao.insertOne(a) } } ?: throw NotFoundException() } }
/* * Copyright (c) 2023. yo-saito. All Rights Reserved. */ package net.piedpiper.bremer.service import net.piedpiper.bremer.dao.AudioDao import net.piedpiper.bremer.dao.PlaylistAudioDao import net.piedpiper.bremer.dao.PlaylistDao import net.piedpiper.bremer.entity.AudioEntity import net.piedpiper.bremer.entity.PlaylistAudioEntity import net.piedpiper.bremer.entity.PlaylistEntity import net.piedpiper.bremer.exception.BadRequestException import net.piedpiper.bremer.exception.NotFoundException import net.piedpiper.bremer.model.api.AllPlaylistResponse import net.piedpiper.bremer.model.api.PlaylistAudioRequest import net.piedpiper.bremer.model.api.PlaylistAudioResponse import net.piedpiper.bremer.model.api.PlaylistRequest import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @Service("bremer.service.PlaylistService") class PlaylistService( @Qualifier("bremer.dao.PlaylistDao") private val playlistDao: PlaylistDao, @Qualifier("bremer.dao.PlaylistAudioDao") private val playlistAudioDao: PlaylistAudioDao, @Qualifier("bremer.dao.AudioDao") private val audioDao: AudioDao ) { @Transactional fun getAllPlaylists(): AllPlaylistResponse = AllPlaylistResponse(playlistDao.findAllOrderBySequence()) @Transactional fun getPlaylist(slug: String): PlaylistAudioResponse = playlistDao.findOneBySlug(slug) ?.let { PlaylistAudioResponse( playlistEntity = it, audioEntityList = it?.playlistAudio ?.mapNotNull { it.audioId } ?.let { ids -> findAllByOrderedIds(ids) } ) } ?: throw NotFoundException() private fun findAllByOrderedIds(ids: List<Long>): List<AudioEntity> { if (ids.isEmpty()) { return emptyList() } val id2idx = ids.mapIndexed { index, id -> id to index }.toMap() return audioDao.findAllByIdIn(ids) .sortedBy { id2idx[it.id] } } private fun findAllByOrderedSlugs(slugs: List<String>): List<AudioEntity> { if (slugs.isEmpty()) { return emptyList() } val slug2idx = slugs.mapIndexed { index, slug -> slug to index }.toMap() return audioDao.findAllBySlugIn(slugs) .sortedBy { slug2idx[it.slug] } } @Transactional fun createPlaylist(request: PlaylistRequest) { playlistDao.insertOne( PlaylistEntity( slug = UUID.randomUUID().toString(), name = request.name ) ) } @Transactional fun updatePlaylist(slug: String, request: PlaylistRequest) { val entity = playlistDao.findOneBySlugWithLock(slug) ?: throw NotFoundException() entity.name = request.name playlistDao.updateOne(entity) } @Transactional fun deletePlaylist(slug: String) { val playlist = playlistDao.findOneBySlugWithLock(slug); if (playlist?.playlistAudio?.isNotEmpty() == true) { playlistAudioDao.deleteAllByIds( playlist.playlistAudio.map { it.id }) } playlistDao.deleteBySlug(slug) } @Transactional fun updatePlaylistAudioList( slug: String, request: PlaylistAudioRequest ) { playlistDao.findOneBySlug(slug) ?.let { playlist -> val audioList = findAllByOrderedSlugs(request.audioSlugs) if (request.audioSlugs.size != audioList.size) { throw BadRequestException() } val registeredAudioIds = playlist.playlistAudio.map { it.audioId }.toSet() val requestAudioIds = audioList.map { it.id }.toSet() val playlistSize = playlist.playlistAudio?.size ?: 0 // delete val deleteIds = playlist.playlistAudio .filter { !requestAudioIds.contains(it.audioId) } .map { it.id } .toList() if (deleteIds.isNotEmpty()) { playlistAudioDao.deleteAllByIds( playlist.playlistAudio .filter { !requestAudioIds.contains(it.audioId) } .map { it.id } .toList() ) } audioList.forEachIndexed { idx, audio -> if (registeredAudioIds.contains(audio.id)) { // ignore return@forEachIndexed } // add playlistAudioDao.insertOne( PlaylistAudioEntity( id = if (idx >= playlistSize) 0L else playlist?.playlistAudio!![idx].id, playlistId = playlist.id, sequence = idx, audioId = audio.id ) ) } } ?: throw NotFoundException() } }
Show line notes below