관리자 - FAQ API
This commit is contained in:
parent
87a5ceee9c
commit
a983595bad
|
@ -0,0 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
data class CreateFaqRequest(
|
||||
val question: String,
|
||||
val answer: String,
|
||||
val category: String
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.ManyToOne
|
||||
|
||||
@Entity
|
||||
data class Faq(
|
||||
@Column(nullable = false)
|
||||
var question: String,
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
var answer: String,
|
||||
var isActive: Boolean = true,
|
||||
val orders: Int = 1
|
||||
) : BaseEntity() {
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "category_id", nullable = false)
|
||||
var category: FaqCategory? = null
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
|
||||
@Entity
|
||||
data class FaqCategory(
|
||||
@Column(nullable = false)
|
||||
val category: String,
|
||||
val isActive: Boolean = true,
|
||||
val orders: Int = 1
|
||||
) : BaseEntity()
|
|
@ -0,0 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface FaqCategoryRepository : JpaRepository<FaqCategory, Long>
|
|
@ -0,0 +1,41 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
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.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/faq")
|
||||
class FaqController(private val service: FaqService) {
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
fun createFaq(@RequestBody request: CreateFaqRequest) = ApiResponse.ok(
|
||||
service.save(request),
|
||||
"등록되었습니다."
|
||||
)
|
||||
|
||||
@PutMapping
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
fun modifyFaq(@RequestBody request: ModifyFaqRequest) = ApiResponse.ok(
|
||||
service.modify(request),
|
||||
"수정되었습니다."
|
||||
)
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
fun deleteCoin(@PathVariable id: Long) = ApiResponse.ok(service.delete(id), "삭제되었습니다.")
|
||||
|
||||
@GetMapping
|
||||
fun getFaqList(@RequestParam("category") category: String) = ApiResponse.ok(service.getFaqList(category))
|
||||
|
||||
@GetMapping("/category")
|
||||
fun getFaqCategoryList() = ApiResponse.ok(service.getCategoryList())
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import com.querydsl.core.types.dsl.Expressions
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.faq.QFaq.faq
|
||||
import kr.co.vividnext.sodalive.faq.QFaqCategory.faqCategory
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface FaqRepository : JpaRepository<Faq, Long>
|
||||
|
||||
@Repository
|
||||
class FaqQueryRepository(private val queryFactory: JPAQueryFactory) {
|
||||
fun getCategory(category: String): FaqCategory? {
|
||||
return queryFactory
|
||||
.selectFrom(faqCategory)
|
||||
.where(
|
||||
faqCategory.isActive.isTrue
|
||||
.and(faqCategory.category.eq(category))
|
||||
)
|
||||
.fetchFirst()
|
||||
}
|
||||
|
||||
fun getCategoryList(): List<String> {
|
||||
return queryFactory
|
||||
.select(faqCategory.category)
|
||||
.from(faqCategory)
|
||||
.where(faqCategory.isActive.isTrue)
|
||||
.orderBy(faqCategory.orders.desc())
|
||||
.fetch()
|
||||
}
|
||||
|
||||
fun getFaqList(category: String): List<GetFaqResponseItem> {
|
||||
return queryFactory
|
||||
.select(
|
||||
QGetFaqResponseItem(
|
||||
faq.id,
|
||||
Expressions.asString(category),
|
||||
faq.question,
|
||||
faq.answer
|
||||
)
|
||||
)
|
||||
.from(faq)
|
||||
.innerJoin(faq.category, faqCategory)
|
||||
.where(
|
||||
faq.isActive.isTrue
|
||||
.and(faqCategory.isActive.isTrue)
|
||||
.and(faqCategory.category.eq(category))
|
||||
)
|
||||
.orderBy(faq.orders.desc())
|
||||
.fetch()
|
||||
}
|
||||
|
||||
fun getFaq(id: Long): Faq? {
|
||||
return queryFactory
|
||||
.selectFrom(faq)
|
||||
.where(
|
||||
faq.isActive.isTrue
|
||||
.and(faq.id.eq(id))
|
||||
)
|
||||
.fetchFirst()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@Service
|
||||
class FaqService(
|
||||
private val repository: FaqRepository,
|
||||
private val queryRepository: FaqQueryRepository
|
||||
) {
|
||||
@Transactional
|
||||
fun save(request: CreateFaqRequest): Long {
|
||||
if (request.question.isBlank()) throw SodaException("질문을 입력하세요.")
|
||||
if (request.answer.isBlank()) throw SodaException("답변을 입력하세요.")
|
||||
if (request.category.isBlank()) throw SodaException("카테고리를 선택하세요.")
|
||||
|
||||
val category = queryRepository.getCategory(request.category)
|
||||
?: throw SodaException("잘못된 카테고리 입니다.")
|
||||
|
||||
val faq = Faq(request.question, request.answer)
|
||||
faq.category = category
|
||||
|
||||
return repository.save(faq).id!!
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun modify(request: ModifyFaqRequest) {
|
||||
val faq = queryRepository.getFaq(request.id)
|
||||
?: throw SodaException("잘못된 요청입니다.")
|
||||
|
||||
if (request.question != null) {
|
||||
if (request.question.isBlank()) throw SodaException("질문을 입력하세요.")
|
||||
faq.question = request.question
|
||||
}
|
||||
|
||||
if (request.answer != null) {
|
||||
if (request.answer.isBlank()) throw SodaException("답변을 입력하세요.")
|
||||
faq.answer = request.answer
|
||||
}
|
||||
|
||||
if (request.category != null) {
|
||||
if (request.category.isBlank()) throw SodaException("카테고리를 선택하세요.")
|
||||
val category = queryRepository.getCategory(request.category) ?: throw SodaException("잘못된 카테고리 입니다.")
|
||||
faq.category = category
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun delete(id: Long) {
|
||||
if (id <= 0) throw SodaException("잘못된 요청입니다.")
|
||||
val faq = repository.findByIdOrNull(id)
|
||||
?: throw SodaException("잘못된 요청입니다.")
|
||||
|
||||
faq.isActive = false
|
||||
}
|
||||
|
||||
fun getFaqList(category: String) = queryRepository.getFaqList(category)
|
||||
|
||||
fun getCategoryList() = queryRepository.getCategoryList()
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection
|
||||
|
||||
data class GetFaqResponseItem @QueryProjection constructor(
|
||||
val id: Long,
|
||||
val category: String,
|
||||
val question: String,
|
||||
val answer: String
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
package kr.co.vividnext.sodalive.faq
|
||||
|
||||
data class ModifyFaqRequest(
|
||||
val id: Long,
|
||||
val question: String? = null,
|
||||
val answer: String? = null,
|
||||
val category: String? = null
|
||||
)
|
Loading…
Reference in New Issue