From e4330fee928dc829a433aac75c5a90c87ee8584f Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Thu, 21 Mar 2024 04:09:48 -0400 Subject: [PATCH] [F] Fix artemis conversion --- src/main/java/ext/Ext.kt | 50 +++++++++++-------- .../chuni/v2/external/Chu3DataExport.java | 31 ------------ .../sega/chuni/v2/external/Chu3DataExport.kt | 22 ++++++++ .../aqua/net/games/ImportController.kt | 13 +++-- .../samnyan/aqua/net/games/chu3/Chu3Import.kt | 6 +-- .../samnyan/aqua/net/games/mai2/Mai2Import.kt | 3 +- 6 files changed, 63 insertions(+), 62 deletions(-) delete mode 100644 src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.java create mode 100644 src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.kt diff --git a/src/main/java/ext/Ext.kt b/src/main/java/ext/Ext.kt index c2767798..bd768ce0 100644 --- a/src/main/java/ext/Ext.kt +++ b/src/main/java/ext/Ext.kt @@ -1,5 +1,6 @@ package ext +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.DeserializationFeature @@ -85,37 +86,42 @@ fun Str.isValidEmail(): Bool = emailRegex.matches(this) // JSON val ACCEPTABLE_FALSE = setOf("0", "false", "no", "off", "False", "None", "null") val ACCEPTABLE_TRUE = setOf("1", "true", "yes", "on", "True") -@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST") +val JSON_FUZZY_BOOLEAN = SimpleModule().addDeserializer(Boolean::class.java, object : JsonDeserializer() { + override fun deserialize(parser: JsonParser, context: DeserializationContext) = when(parser.text) { + in ACCEPTABLE_FALSE -> false + in ACCEPTABLE_TRUE -> true + else -> 400 - "Invalid boolean value ${parser.text}" + } +}) +val JSON_DATETIME = SimpleModule().addDeserializer(LocalDateTime::class.java, object : JsonDeserializer() { + override fun deserialize(parser: JsonParser, context: DeserializationContext) = + parser.text.asDateTime() ?: (400 - "Invalid date time value ${parser.text}") +}) val JACKSON = ObjectMapper().apply { + setSerializationInclusion(JsonInclude.Include.NON_NULL) + setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL) findAndRegisterModules() - registerModule(SimpleModule().addDeserializer(Boolean::class.java, object : JsonDeserializer() { - override fun deserialize(parser: JsonParser, context: DeserializationContext) = when(parser.text) { - in ACCEPTABLE_FALSE -> false - in ACCEPTABLE_TRUE -> true - else -> 400 - "Invalid boolean value ${parser.text}" - } - }).addDeserializer(List::class.java, object : JsonDeserializer>() { - override fun deserialize(parser: JsonParser, context: DeserializationContext) = - try { - val text = parser.text.trim('[', ']') - if (text.isEmpty()) emptyList() - else text.split(',').map { it.trim().toInt() } as List - } catch (e: Exception) { - 400 - "Invalid list value ${parser.text}: $e" } - }).addDeserializer(LocalDateTime::class.java, object : JsonDeserializer() { - override fun deserialize(parser: JsonParser, context: DeserializationContext) = - parser.text.asDateTime() ?: (400 - "Invalid date time value ${parser.text}") - })) + registerModule(JSON_FUZZY_BOOLEAN) + registerModule(JSON_DATETIME) configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } -inline fun Str.parseJson() = JACKSON.readValue(this, T::class.java) +inline fun ObjectMapper.readValue(str: Str) = readValue(str, T::class.java) +// TODO: https://stackoverflow.com/q/78197784/7346633 +inline fun Str.parseJackson() = if (contains("null")) { + val map = JACKSON.readValue>(this) + JACKSON.convertValue(map.recursiveNotNull(), T::class.java) +} +else JACKSON.readValue(this, T::class.java) fun T.toJson() = JACKSON.writeValueAsString(this) @OptIn(ExperimentalSerializationApi::class) val JSON = Json { ignoreUnknownKeys = true isLenient = true namingStrategy = JsonNamingStrategy.SnakeCase + explicitNulls = false + coerceInputValues = true } +inline fun Json.parse(str: Str) = decodeFromString(str) // Global Tools val HTTP = HttpClient(CIO) { install(ContentNegotiation) { @@ -160,6 +166,10 @@ fun Map.vNotNull(): Map = filterValues { it != null }.m fun MutableList.popAll(list: List) = list.also { removeAll(it) } fun MutableList.popAll(vararg items: T) = popAll(items.toList()) inline fun Iterable.mapApply(block: T.() -> Unit) = map { it.apply(block) } +@Suppress("UNCHECKED_CAST") +fun Map.recursiveNotNull(): Map = mapNotNull { (k, v) -> + k to if (v is Map<*, *>) (v as Map).recursiveNotNull() else v +}.toMap() as Map // Optionals operator fun Optional.invoke(): T? = orElse(null) diff --git a/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.java b/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.java deleted file mode 100644 index 87fc6af9..00000000 --- a/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.java +++ /dev/null @@ -1,31 +0,0 @@ -package icu.samnyan.aqua.api.model.resp.sega.chuni.v2.external; - -import icu.samnyan.aqua.sega.chusan.model.userdata.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -/** - * This class is use for exporting chusan profile - * @author samnyan (publicamusement@protonmail.com) - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class Chu3DataExport { - public String gameId = "SDHD"; - public UserData userData; - public UserGameOption userGameOption; - public List userActivityList; - public List userCharacterList; - public List userChargeList; - public List userCourseList; - public List userDuelList; - public List userItemList; - public List userMapList; - public List userMusicDetailList; - public List userPlaylogList; - public List userLoginBonusList; -} diff --git a/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.kt b/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.kt new file mode 100644 index 00000000..ed0397ce --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/api/model/resp/sega/chuni/v2/external/Chu3DataExport.kt @@ -0,0 +1,22 @@ +package icu.samnyan.aqua.api.model.resp.sega.chuni.v2.external + +import icu.samnyan.aqua.sega.chusan.model.userdata.* + +data class Chu3DataExport( + var gameId: String = "SDHD", + var userData: UserData, + var userGameOption: UserGameOption, + var userActivityList: List, + var userCharacterList: List, + var userChargeList: List, + var userCourseList: List, + var userDuelList: List, + var userItemList: List, + var userMapList: List, + var userMusicDetailList: List, + var userPlaylogList: List, + var userLoginBonusList: List, +) { + constructor() : this("SDHD", UserData(), UserGameOption(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList()) +} + diff --git a/src/main/java/icu/samnyan/aqua/net/games/ImportController.kt b/src/main/java/icu/samnyan/aqua/net/games/ImportController.kt index f8a49775..818ca0f8 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/ImportController.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/ImportController.kt @@ -4,12 +4,11 @@ import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.module.SimpleModule -import ext.API -import ext.JACKSON -import ext.minus -import ext.splitLines +import ext.* import java.lang.reflect.Field import kotlin.reflect.KClass +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.KProperty1 // Import class with renaming data class ImportClass( @@ -19,7 +18,7 @@ data class ImportClass( ) abstract class ImportController( - val exportFields: Map, + val exportFields: Map>, val renameTable: Map> ) { abstract fun createEmpty(): T @@ -35,14 +34,14 @@ abstract class ImportController( */ @Suppress("UNCHECKED_CAST") @API("convert-artemis") - fun importArtemisSql(sql: String): ImportResult { + fun importArtemisSql(@RB sql: String): ImportResult { val data = createEmpty() val errors = ArrayList() val warnings = ArrayList() fun err(msg: String) { errors.add(msg) } fun warn(msg: String) { warnings.add(msg) } - val lists = exportFields.filter { it.value.type == List::class.java } + val lists = exportFields.filter { it.value returns List::class } .mapValues { it.value.get(data) as ArrayList } val statements = sql.splitLines().mapNotNull { diff --git a/src/main/java/icu/samnyan/aqua/net/games/chu3/Chu3Import.kt b/src/main/java/icu/samnyan/aqua/net/games/chu3/Chu3Import.kt index ba130a51..1f507c1b 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/chu3/Chu3Import.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/chu3/Chu3Import.kt @@ -1,6 +1,7 @@ package icu.samnyan.aqua.net.games.chu3 import ext.API +import ext.vars import icu.samnyan.aqua.api.model.resp.sega.chuni.v2.external.Chu3DataExport import icu.samnyan.aqua.net.games.ImportClass import icu.samnyan.aqua.net.games.ImportController @@ -10,7 +11,7 @@ import org.springframework.web.bind.annotation.RestController @RestController @API("api/v2/game/chu3") class Chu3Import : ImportController( - exportFields = Chu3DataExport::class.java.declaredFields.associateBy { + exportFields = Chu3DataExport::class.vars().associateBy { var name = it.name if (name == "userMapList") name = "userMapAreaList" name.replace("List", "").lowercase() @@ -33,6 +34,5 @@ class Chu3Import : ImportController( // "chuni_profile_recent_rating" to ImportClass(UserRecentRating::class), ) ) { - override fun createEmpty() = Chu3DataExport("SDEZ", UserData(), UserGameOption(), ArrayList(), ArrayList(), - ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList(), ArrayList()) + override fun createEmpty() = Chu3DataExport() } \ No newline at end of file diff --git a/src/main/java/icu/samnyan/aqua/net/games/mai2/Mai2Import.kt b/src/main/java/icu/samnyan/aqua/net/games/mai2/Mai2Import.kt index 3f9c235f..ec575411 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/mai2/Mai2Import.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/mai2/Mai2Import.kt @@ -1,6 +1,7 @@ package icu.samnyan.aqua.net.games.mai2 import ext.API +import ext.vars import icu.samnyan.aqua.api.model.resp.sega.maimai2.external.Maimai2DataExport import icu.samnyan.aqua.net.games.ImportClass import icu.samnyan.aqua.net.games.ImportController @@ -10,7 +11,7 @@ import org.springframework.web.bind.annotation.RestController @RestController @API("api/v2/game/mai2") class Mai2Import : ImportController( - exportFields = Maimai2DataExport::class.java.declaredFields.associateBy { + exportFields = Maimai2DataExport::class.vars().associateBy { it.name.replace("List", "").lowercase() }, renameTable = mapOf(