Skip to content

Commit

Permalink
Merge pull request #60 from YAPP-Github/feature/DRAW-192
Browse files Browse the repository at this point in the history
DRAW-192 강제 업데이트
  • Loading branch information
comforest authored Aug 13, 2024
2 parents 0946fd1 + a84b6ce commit ad9a78d
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {

implementation("org.springframework.boot:spring-boot-starter-web:${Versions.SPRING_BOOT}")
implementation("org.springframework.boot:spring-boot-starter-validation:${Versions.SPRING_BOOT}")
implementation("org.springframework.boot:spring-boot-starter-aop:${Versions.SPRING_BOOT}")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:${Versions.WEBMVC_UI}")
}

Expand Down
12 changes: 11 additions & 1 deletion app/api/src/main/kotlin/com/xorker/draw/HealthCheckController.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package com.xorker.draw

import com.xorker.draw.support.logging.logger
import com.xorker.draw.version.ApiMinVersion
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.slf4j.MDC
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@Tag(name = "개발용 API")
@RestController
class HealthCheckController {
val log = logger()

@Operation(hidden = true)
@GetMapping("/ping")
fun ping(): String {
return "pong"
}

@Operation(hidden = true)
@GetMapping("/test")
fun test(): String {
MDC.put("test", "test")
log.info("Call Test")
return "pong"
}

@Operation(summary = "강업 테스트")
@ApiMinVersion(androidVersion = "99.99.99", iosVersion = "99.99.99")
@GetMapping("/force-update")
fun forceUpdate() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.xorker.draw.version

@Target(allowedTargets = [AnnotationTarget.FUNCTION])
annotation class ApiMinVersion(
val androidVersion: String = "0.0.0",
val iosVersion: String = "0.0.0",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.xorker.draw.version

import com.xorker.draw.exception.NeedForceUpdateException
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.stereotype.Component
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes

@Aspect
@Component
class ForceUpdateAspect {

@Around("@annotation(ApiMinVersion)")
fun checkForceUpdate(joinPoint: ProceedingJoinPoint): Any {
try {
val attributes = RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes
val userAgent = attributes.request.getHeader("User-Agent")

val (appType, version) = userAgent.getVersionInfo()

val signature = joinPoint.signature as MethodSignature
val method = signature.method
val annotation = method.getAnnotation(ApiMinVersion::class.java)

if (appType.lowercase() == "android") {
if (Version.of(annotation.androidVersion) > version) {
throw NeedForceUpdateException
}
} else if (appType.lowercase() == "ios") {
if (Version.of(annotation.iosVersion) > version) {
throw NeedForceUpdateException
}
}
} catch (e: Exception) {
throw NeedForceUpdateException
}

return joinPoint.proceed()
}

private fun String.getVersionInfo(): Pair<String, Version> {
val lastIndexSpace = if (this.lastIndexOf(' ') == -1) 0 else this.lastIndexOf(' ')
val lastIndexSlash = this.lastIndexOf('/')

val appType = this.substring(lastIndexSpace, lastIndexSlash)
val version = this.substring(lastIndexSlash + 1)

return Pair(appType, Version.of(version))
}
}
24 changes: 24 additions & 0 deletions app/api/src/main/kotlin/com/xorker/draw/version/Version.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.xorker.draw.version

class Version(
val major: Int,
val minor: Int,
val patch: Int,
) : Comparable<Version> {
override fun compareTo(other: Version): Int {
if (major > other.major) return 1
if (major < other.major) return -1

if (minor > other.minor) return 1
if (minor < other.minor) return -1

return patch.compareTo(patch)
}

companion object {
fun of(version: String): Version {
val split = version.split(".")
return Version(split[0].toInt(), split[1].toInt(), split.getOrElse(2) { "0" }.toInt())
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.xorker.draw.exception

import com.xorker.draw.exception.ExceptionButtonAction.CloseDialog
import com.xorker.draw.exception.ExceptionButtonAction.ForceUpdate
import java.util.*
import org.springframework.context.MessageSource

Expand All @@ -11,6 +12,7 @@ enum class ExceptionButtonType(
OK("exception.button.ok", CloseDialog),
CANCEL("exception.button.cancel", CloseDialog),
CLOSE("exception.button.close", CloseDialog),
FORCE_UPDATE("exception.button.forceUpdate", ForceUpdate),
;

private val responseMap = HashMap<Locale, ExceptionButtonResponse>()
Expand All @@ -32,9 +34,12 @@ enum class ExceptionButtonType(
private val buttonOk = listOf(ExceptionButtonType.OK)
private val buttonOkCancel = listOf(ExceptionButtonType.OK, ExceptionButtonType.CANCEL)
private val buttonOkClose = listOf(ExceptionButtonType.OK, ExceptionButtonType.CLOSE)
private val buttonForceUpdate = listOf(ExceptionButtonType.FORCE_UPDATE)

fun XorkerException.getButtons(): List<ExceptionButtonType> {
return when (this) {
NeedForceUpdateException -> buttonForceUpdate

InvalidRequestValueException,
UnAuthorizedException,
NotFoundRoomException,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ data class ExceptionButtonResponse(
val action: ExceptionButtonAction,
)

sealed class ExceptionButtonAction(private val type: String, description: String) {
sealed class ExceptionButtonAction(val type: String, description: String) {
data object ForceUpdate : ExceptionButtonAction("FORCE_UPDATE", "강제 업데이트")
data object CloseDialog : ExceptionButtonAction("DIALOG_CLOSE", "에러 팝업 닫기") // TODO: 클라랑 명칭 맞추기
class OpenWebView(val url: String) : ExceptionButtonAction("OPEN_WEB_VIEW", "웹뷰 열기")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ exception.default.description='예상치 못한 예외가 발생했습니다.'
exception.button.ok='확인'
exception.button.cancel='취소'
exception.button.close='닫기'
exception.button.forceUpdate='스토어로 이동'
exception.forceUpdate.title='TODO 강제 업데이트 타이틀'
exception.forceUpdate.description='TODO 강제 업데이트 메시지'
exception.auth401.description='로그인을 다시 해주세요.'
exception.auth403.description='로그인을 다시 해주세요.'
exception.c003.description='존재하지 않는 참여 코드에요.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ exception.button.ok='확인'
exception.button.cancel='취소'
exception.button.close='닫기'
exception.auth401.description='로그인을 다시 해주세요.'
exception.auth401.description='로그인을 다시 해주세요.'
exception.auth403.description='로그인을 다시 해주세요.'
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ sealed class XorkerException(val code: String, message: String, cause: Throwable
//region Client
sealed class ClientException(code: String, message: String, cause: Throwable? = null) : XorkerException(code, message, cause)

data object NeedForceUpdateException : ClientException("forceUpdate", "인증 실패") { private fun readResolve(): Any = NeedForceUpdateException }
data object UnAuthenticationException : ClientException("auth401", "인증 실패") { private fun readResolve(): Any = UnAuthenticationException }
data object UnAuthorizedException : ClientException("auth403", "인가 실패") { private fun readResolve(): Any = UnAuthorizedException }

Expand Down

0 comments on commit ad9a78d

Please sign in to comment.