관리자

- 새로운 시리즈, 무료 추천 시리즈 등록/수정/순서변경 API 추가
This commit is contained in:
Klaus 2025-02-04 23:25:52 +09:00
parent 55badb6206
commit 05e714fff1
8 changed files with 226 additions and 0 deletions

View File

@ -0,0 +1,40 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
import kr.co.vividnext.sodalive.common.ApiResponse
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
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.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
@RestController
@PreAuthorize("hasRole('ADMIN')")
@RequestMapping("/admin/audio-content/series/recommend")
class AdminRecommendSeriesController(private val service: AdminRecommendSeriesService) {
@GetMapping
fun getRecommendSeriesList(@RequestParam isFree: Boolean) = ApiResponse.ok(
service.getRecommendSeriesList(isFree = isFree)
)
@PostMapping
fun createRecommendSeries(
@RequestPart("image") image: MultipartFile,
@RequestPart("request") requestString: String
) = ApiResponse.ok(service.createRecommendSeries(image, requestString))
@PutMapping
fun modifyRecommendSeries(
@RequestPart("image", required = false) image: MultipartFile? = null,
@RequestPart("request") requestString: String
) = ApiResponse.ok(service.updateRecommendSeries(image, requestString))
@PutMapping("/orders")
fun updateRecommendSeriesOrders(
@RequestBody request: UpdateRecommendSeriesOrdersRequest
) = ApiResponse.ok(service.updateRecommendSeriesOrders(request.ids))
}

View File

@ -0,0 +1,43 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.content.main.tab.QRecommendSeries.recommendSeries
import kr.co.vividnext.sodalive.content.main.tab.RecommendSeries
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.jpa.repository.JpaRepository
interface AdminRecommendSeriesRepository :
JpaRepository<RecommendSeries, Long>,
AdminRecommendSeriesQueryRepository
interface AdminRecommendSeriesQueryRepository {
fun getRecommendSeriesList(isFree: Boolean): List<GetAdminRecommendSeriesListResponse>
}
class AdminRecommendSeriesQueryRepositoryImpl(
private val queryFactory: JPAQueryFactory,
@Value("\${cloud.aws.cloud-front.host}")
private val imageHost: String
) : AdminRecommendSeriesQueryRepository {
override fun getRecommendSeriesList(isFree: Boolean): List<GetAdminRecommendSeriesListResponse> {
return queryFactory
.select(
QGetAdminRecommendSeriesListResponse(
recommendSeries.id,
series.id,
series.title,
recommendSeries.imagePath.prepend("/").prepend(imageHost)
)
)
.from(recommendSeries)
.innerJoin(recommendSeries.series, series)
.where(
recommendSeries.isActive.isTrue
.and(series.isActive.isTrue)
.and(recommendSeries.isFree.eq(isFree))
)
.fetch()
}
}

View File

@ -0,0 +1,87 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
import com.fasterxml.jackson.databind.ObjectMapper
import kr.co.vividnext.sodalive.admin.content.series.AdminContentSeriesRepository
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.content.main.tab.RecommendSeries
import kr.co.vividnext.sodalive.utils.generateFileName
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
@Service
class AdminRecommendSeriesService(
private val s3Uploader: S3Uploader,
private val repository: AdminRecommendSeriesRepository,
private val seriesRepository: AdminContentSeriesRepository,
private val objectMapper: ObjectMapper,
@Value("\${cloud.aws.s3.bucket}")
private val bucket: String
) {
fun getRecommendSeriesList(isFree: Boolean): List<GetAdminRecommendSeriesListResponse> {
return repository.getRecommendSeriesList(isFree = isFree)
}
@Transactional
fun createRecommendSeries(image: MultipartFile, requestString: String) {
val request = objectMapper.readValue(requestString, CreateRecommendSeriesRequest::class.java)
val series = seriesRepository.findByIdOrNull(request.seriesId)
?: throw SodaException("잘못된 요청입니다.")
val recommendSeries = RecommendSeries(isFree = request.isFree)
recommendSeries.series = series
repository.save(recommendSeries)
val fileName = generateFileName()
val imagePath = s3Uploader.upload(
inputStream = image.inputStream,
bucket = bucket,
filePath = "recommend_series/${recommendSeries.id}/$fileName"
)
recommendSeries.imagePath = imagePath
}
@Transactional
fun updateRecommendSeries(image: MultipartFile?, requestString: String) {
val request = objectMapper.readValue(requestString, UpdateRecommendSeriesRequest::class.java)
val recommendSeries = repository.findByIdOrNull(request.id)
?: throw SodaException("잘못된 요청입니다.")
if (image != null) {
val fileName = generateFileName()
val imagePath = s3Uploader.upload(
inputStream = image.inputStream,
bucket = bucket,
filePath = "recommend_series/${recommendSeries.id}/$fileName"
)
recommendSeries.imagePath = imagePath
}
if (request.isActive != null) {
recommendSeries.isActive = request.isActive
}
if (request.seriesId != null) {
val series = seriesRepository.findByIdOrNull(request.seriesId)
if (series != null) {
recommendSeries.series = series
}
}
}
@Transactional
fun updateRecommendSeriesOrders(ids: List<Long>) {
for (index in ids.indices) {
val recommendSeries = repository.findByIdOrNull(ids[index])
if (recommendSeries != null) {
recommendSeries.orders = index + 1
}
}
}
}

View File

@ -0,0 +1,6 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
data class CreateRecommendSeriesRequest(
val seriesId: Long,
val isFree: Boolean
)

View File

@ -0,0 +1,10 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
import com.querydsl.core.annotations.QueryProjection
data class GetAdminRecommendSeriesListResponse @QueryProjection constructor(
val id: Long,
val seriesId: Long,
val seriesTitle: String,
val imageUrl: String
)

View File

@ -0,0 +1,5 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
data class UpdateRecommendSeriesOrdersRequest(
val ids: List<Long>
)

View File

@ -0,0 +1,7 @@
package kr.co.vividnext.sodalive.admin.content.series.recommend
data class UpdateRecommendSeriesRequest(
val id: Long,
val seriesId: Long?,
val isActive: Boolean?
)

View File

@ -0,0 +1,28 @@
package kr.co.vividnext.sodalive.content.main.tab
import kr.co.vividnext.sodalive.common.BaseEntity
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.FetchType
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
@Entity
data class RecommendSeries(
@Column(nullable = false)
var imagePath: String = "",
@Column(nullable = false)
var orders: Int = 1,
@Column(nullable = false)
var isFree: Boolean = false,
@Column(nullable = false)
var isActive: Boolean = true
) : BaseEntity() {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "series_id", nullable = false)
var series: Series? = null
}