Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAW-192 강제 업데이트 #60

Merged
merged 2 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,5 +2,8 @@ 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='로그인을 다시 해주세요.'
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
Loading