앱 - 배역 상세 API, 지원 리스트 API
This commit is contained in:
parent
ddd552deb4
commit
affbb3eba3
|
@ -0,0 +1,34 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import org.springframework.data.domain.Pageable
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/audition/applicant")
|
||||||
|
class AuditionApplicantController(private val service: AuditionApplicantService) {
|
||||||
|
@GetMapping
|
||||||
|
fun getAuditionApplicantList(
|
||||||
|
@RequestParam auditionRoleId: Long,
|
||||||
|
@RequestParam sortType: AuditionApplicantSortType,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
|
||||||
|
pageable: Pageable
|
||||||
|
) = run {
|
||||||
|
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||||
|
|
||||||
|
ApiResponse.ok(
|
||||||
|
service.getAuditionApplicantList(
|
||||||
|
auditionRoleId = auditionRoleId,
|
||||||
|
sortType = sortType,
|
||||||
|
offset = pageable.offset,
|
||||||
|
limit = pageable.pageSize.toLong()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
|
import kr.co.vividnext.sodalive.audition.AuditionApplicant
|
||||||
|
import kr.co.vividnext.sodalive.audition.QAuditionApplicant.auditionApplicant
|
||||||
|
import kr.co.vividnext.sodalive.audition.QAuditionRole.auditionRole
|
||||||
|
import kr.co.vividnext.sodalive.audition.QAuditionVote.auditionVote
|
||||||
|
import kr.co.vividnext.sodalive.member.QMember.member
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
|
interface AuditionApplicantRepository : JpaRepository<AuditionApplicant, Long>, AuditionApplicantQueryRepository
|
||||||
|
|
||||||
|
interface AuditionApplicantQueryRepository {
|
||||||
|
fun isAlreadyApplicant(auditionRoleId: Long, memberId: Long): Boolean
|
||||||
|
fun getAuditionApplicantTotalCount(auditionRoleId: Long): Int
|
||||||
|
fun getAuditionApplicantList(
|
||||||
|
auditionRoleId: Long,
|
||||||
|
sortType: AuditionApplicantSortType,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long
|
||||||
|
): List<GetAuditionRoleApplicantItem>
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuditionApplicantQueryRepositoryImpl(
|
||||||
|
private val queryFactory: JPAQueryFactory,
|
||||||
|
|
||||||
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
|
private val cloudFrontHost: String
|
||||||
|
) : AuditionApplicantQueryRepository {
|
||||||
|
override fun isAlreadyApplicant(auditionRoleId: Long, memberId: Long): Boolean {
|
||||||
|
return queryFactory
|
||||||
|
.select(auditionApplicant.id)
|
||||||
|
.from(auditionApplicant)
|
||||||
|
.innerJoin(auditionApplicant.role, auditionRole)
|
||||||
|
.innerJoin(auditionApplicant.member, member)
|
||||||
|
.where(
|
||||||
|
auditionRole.id.eq(auditionRoleId),
|
||||||
|
member.id.eq(memberId),
|
||||||
|
auditionApplicant.isActive.isTrue
|
||||||
|
)
|
||||||
|
.fetch()
|
||||||
|
.size > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAuditionApplicantTotalCount(auditionRoleId: Long): Int {
|
||||||
|
return queryFactory
|
||||||
|
.select(auditionApplicant.id)
|
||||||
|
.from(auditionApplicant)
|
||||||
|
.innerJoin(auditionApplicant.role, auditionRole)
|
||||||
|
.where(
|
||||||
|
auditionRole.id.eq(auditionRoleId),
|
||||||
|
auditionRole.isActive.isTrue
|
||||||
|
)
|
||||||
|
.fetch()
|
||||||
|
.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAuditionApplicantList(
|
||||||
|
auditionRoleId: Long,
|
||||||
|
sortType: AuditionApplicantSortType,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long
|
||||||
|
): List<GetAuditionRoleApplicantItem> {
|
||||||
|
val orderBy = if (sortType == AuditionApplicantSortType.LIKES) {
|
||||||
|
auditionVote.id.count().desc()
|
||||||
|
} else {
|
||||||
|
auditionApplicant.id.desc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QGetAuditionRoleApplicantItem(
|
||||||
|
auditionApplicant.id,
|
||||||
|
member.nickname,
|
||||||
|
member.profileImage.prepend("/").prepend(cloudFrontHost),
|
||||||
|
auditionApplicant.voicePath.prepend("/").prepend(cloudFrontHost),
|
||||||
|
auditionVote.id.count()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(auditionApplicant)
|
||||||
|
.innerJoin(auditionApplicant.member, member)
|
||||||
|
.innerJoin(auditionApplicant.role, auditionRole)
|
||||||
|
.leftJoin(auditionVote).on(auditionApplicant.id.eq(auditionVote.applicant.id))
|
||||||
|
.where(
|
||||||
|
auditionRole.id.eq(auditionRoleId),
|
||||||
|
auditionRole.isActive.isTrue
|
||||||
|
)
|
||||||
|
.groupBy(auditionApplicant.id)
|
||||||
|
.orderBy(orderBy)
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class AuditionApplicantService(private val repository: AuditionApplicantRepository) {
|
||||||
|
fun getAuditionApplicantList(
|
||||||
|
auditionRoleId: Long,
|
||||||
|
sortType: AuditionApplicantSortType,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long
|
||||||
|
): GetAuditionApplicantListResponse {
|
||||||
|
val totalCount = repository.getAuditionApplicantTotalCount(auditionRoleId = auditionRoleId)
|
||||||
|
val items = repository.getAuditionApplicantList(
|
||||||
|
auditionRoleId = auditionRoleId,
|
||||||
|
sortType = sortType,
|
||||||
|
offset = offset,
|
||||||
|
limit = limit
|
||||||
|
)
|
||||||
|
|
||||||
|
return GetAuditionApplicantListResponse(
|
||||||
|
totalCount = totalCount,
|
||||||
|
items = items
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
enum class AuditionApplicantSortType {
|
||||||
|
NEWEST, LIKES
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.applicant
|
||||||
|
|
||||||
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
|
data class GetAuditionApplicantListResponse(
|
||||||
|
val totalCount: Int,
|
||||||
|
val items: List<GetAuditionRoleApplicantItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GetAuditionRoleApplicantItem @QueryProjection constructor(
|
||||||
|
val applicantId: Long,
|
||||||
|
val nickname: String,
|
||||||
|
val profileImageUrl: String,
|
||||||
|
val voiceUrl: String,
|
||||||
|
val voteCount: Long
|
||||||
|
)
|
|
@ -0,0 +1,29 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.role
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/audition/role")
|
||||||
|
class AuditionRoleController(private val service: AuditionRoleService) {
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
fun getAuditionRoleDetail(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
|
) = run {
|
||||||
|
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||||
|
|
||||||
|
ApiResponse.ok(
|
||||||
|
service.getAuditionRoleDetail(
|
||||||
|
auditionRoleId = id,
|
||||||
|
memberId = member.id!!
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ interface AuditionRoleRepository : JpaRepository<AuditionRole, Long>, AuditionRo
|
||||||
|
|
||||||
interface AuditionRoleQueryRepository {
|
interface AuditionRoleQueryRepository {
|
||||||
fun getAuditionRoleListByAuditionId(auditionId: Long): List<GetAuditionRoleListData>
|
fun getAuditionRoleListByAuditionId(auditionId: Long): List<GetAuditionRoleListData>
|
||||||
|
fun getAuditionRoleDetail(auditionRoleId: Long): GetAuditionRoleDetailData?
|
||||||
}
|
}
|
||||||
|
|
||||||
class AuditionRoleQueryRepositoryImpl(
|
class AuditionRoleQueryRepositoryImpl(
|
||||||
|
@ -40,4 +41,25 @@ class AuditionRoleQueryRepositoryImpl(
|
||||||
)
|
)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAuditionRoleDetail(auditionRoleId: Long): GetAuditionRoleDetailData? {
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QGetAuditionRoleDetailData(
|
||||||
|
auditionRole.id,
|
||||||
|
auditionRole.name,
|
||||||
|
auditionRole.imagePath.prepend("/").prepend(cloudfrontHost),
|
||||||
|
auditionRole.information,
|
||||||
|
audition.originalWorkUrl,
|
||||||
|
auditionRole.auditionScriptUrl
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(auditionRole)
|
||||||
|
.innerJoin(auditionRole.audition, audition)
|
||||||
|
.where(
|
||||||
|
auditionRole.id.eq(auditionRoleId),
|
||||||
|
auditionRole.isActive.isTrue
|
||||||
|
)
|
||||||
|
.fetchFirst()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.role
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.audition.applicant.AuditionApplicantRepository
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class AuditionRoleService(
|
||||||
|
private val repository: AuditionRoleRepository,
|
||||||
|
private val applicantRepository: AuditionApplicantRepository
|
||||||
|
) {
|
||||||
|
fun getAuditionRoleDetail(auditionRoleId: Long, memberId: Long): GetAuditionRoleDetailResponse {
|
||||||
|
val roleDetailData = repository.getAuditionRoleDetail(auditionRoleId = auditionRoleId)
|
||||||
|
?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.")
|
||||||
|
|
||||||
|
val isAlreadyApplicant = applicantRepository.isAlreadyApplicant(
|
||||||
|
auditionRoleId = auditionRoleId,
|
||||||
|
memberId = memberId
|
||||||
|
)
|
||||||
|
|
||||||
|
return roleDetailData.toDetailResponse(isAlreadyApplicant = isAlreadyApplicant)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package kr.co.vividnext.sodalive.audition.role
|
||||||
|
|
||||||
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
|
data class GetAuditionRoleDetailResponse(
|
||||||
|
val auditionRoleId: Long,
|
||||||
|
val name: String,
|
||||||
|
val imageUrl: String,
|
||||||
|
val information: String,
|
||||||
|
val originalWorkUrl: String,
|
||||||
|
val auditionScriptUrl: String,
|
||||||
|
val isAlreadyApplicant: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GetAuditionRoleDetailData @QueryProjection constructor(
|
||||||
|
val auditionRoleId: Long,
|
||||||
|
val name: String,
|
||||||
|
val imageUrl: String,
|
||||||
|
val information: String,
|
||||||
|
val originalWorkUrl: String,
|
||||||
|
val auditionScriptUrl: String
|
||||||
|
) {
|
||||||
|
fun toDetailResponse(isAlreadyApplicant: Boolean) = GetAuditionRoleDetailResponse(
|
||||||
|
auditionRoleId = auditionRoleId,
|
||||||
|
name = name,
|
||||||
|
imageUrl = imageUrl,
|
||||||
|
information = information,
|
||||||
|
originalWorkUrl = originalWorkUrl,
|
||||||
|
auditionScriptUrl = auditionScriptUrl,
|
||||||
|
isAlreadyApplicant = isAlreadyApplicant
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue