feat(ai-character): 관리자 기능 기반을 추가한다

This commit is contained in:
2026-07-22 01:43:08 +09:00
parent 5b700892c3
commit 3f4d7b237f
39 changed files with 5657 additions and 114 deletions
@@ -1,9 +1,12 @@
package kr.co.vividnext.sodalive.common
import org.springframework.http.HttpStatus
class SodaException(
message: String? = null,
val errorProperty: String? = null,
val messageKey: String? = null
val messageKey: String? = null,
val httpStatus: HttpStatus? = null
) : RuntimeException(message)
class AdsChargeException(
@@ -6,6 +6,7 @@ import kr.co.vividnext.sodalive.i18n.SodaMessageSource
import org.slf4j.LoggerFactory
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.InternalAuthenticationServiceException
@@ -13,7 +14,9 @@ import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.multipart.MaxUploadSizeExceededException
import org.springframework.web.multipart.MultipartException
import org.springframework.web.server.ResponseStatusException
import javax.servlet.http.HttpServletRequest
@RestControllerAdvice
class SodaExceptionHandler(
@@ -38,12 +41,25 @@ class SodaExceptionHandler(
)
}
@ExceptionHandler(MaxUploadSizeExceededException::class)
fun handleMaxUploadSizeExceededException(e: MaxUploadSizeExceededException) = run {
val logMessage = messageSource.getMessage("common.error.max_upload_size", logLang)
@ExceptionHandler(MaxUploadSizeExceededException::class, MultipartException::class)
fun handleMultipartException(e: MultipartException, request: HttpServletRequest) = run {
val isAiCharacterAdminPath = isAiCharacterAdminPath(request.requestURI)
val messageKey = if (e is MaxUploadSizeExceededException) {
"common.error.max_upload_size"
} else if (isAiCharacterAdminPath) {
"common.error.invalid_request"
} else {
"common.error.unknown"
}
val logMessage = messageSource.getMessage(messageKey, logLang)
logger.error("API error: {}", logMessage, e)
val message = messageSource.getMessage("common.error.max_upload_size", langContext.lang)
ApiResponse.error(message = message)
val message = messageSource.getMessage(messageKey, langContext.lang)
val body = ApiResponse.error(message = message)
if (isAiCharacterAdminPath) {
ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body)
} else {
body
}
}
@ExceptionHandler(AccessDeniedException::class)
@@ -99,4 +115,12 @@ class SodaExceptionHandler(
val message = messageSource.getMessage("common.error.unknown", langContext.lang)
ApiResponse.error(message)
}
private fun isAiCharacterAdminPath(requestUri: String): Boolean {
return requestUri == AI_CHARACTER_ADMIN_PATH_PREFIX || requestUri.startsWith("$AI_CHARACTER_ADMIN_PATH_PREFIX/")
}
companion object {
private const val AI_CHARACTER_ADMIN_PATH_PREFIX = "/admin/ai-characters"
}
}