From faf1945933ab6f2a22ab0bb2c47783accd26e84d Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:02:24 -0400 Subject: [PATCH] [M] Move packages --- src/main/java/ext/Ext.kt | 4 + .../aqua/net/games/{ => chu3}/Chusan.kt | 93 +++++------ .../aqua/net/games/{ => mai2}/Maimai2.kt | 144 +++++++++--------- .../aqua/net/games/{ => ongeki}/Ongeki.kt | 84 +++++----- .../handler/impl/GetUserItemHandler.kt | 2 +- 5 files changed, 166 insertions(+), 161 deletions(-) rename src/main/java/icu/samnyan/aqua/net/games/{ => chu3}/Chusan.kt (95%) rename src/main/java/icu/samnyan/aqua/net/games/{ => mai2}/Maimai2.kt (89%) rename src/main/java/icu/samnyan/aqua/net/games/{ => ongeki}/Ongeki.kt (87%) diff --git a/src/main/java/ext/Ext.kt b/src/main/java/ext/Ext.kt index 1125e118..544ff484 100644 --- a/src/main/java/ext/Ext.kt +++ b/src/main/java/ext/Ext.kt @@ -22,9 +22,12 @@ import java.nio.file.Path import java.time.LocalDate import java.time.LocalDateTime import java.time.format.DateTimeFormatter +import kotlin.reflect.KCallable import kotlin.reflect.KClass import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.jvmErasure typealias RP = RequestParam typealias RB = RequestBody @@ -50,6 +53,7 @@ fun KClass.vars() = memberProperties.mapNotNull { it as? KMutablePr fun KClass.varsMap() = vars().associateBy { it.name } fun KClass.getters() = java.methods.filter { it.name.startsWith("get") } fun KClass.gettersMap() = getters().associateBy { it.name.removePrefix("get").decapitalize() } +infix fun KCallable<*>.returns(type: KClass<*>) = returnType.jvmErasure.isSubclassOf(type) @Suppress("UNCHECKED_CAST") fun KMutableProperty1.setCast(obj: C, value: String) = set(obj, when (returnType.classifier) { String::class -> value diff --git a/src/main/java/icu/samnyan/aqua/net/games/Chusan.kt b/src/main/java/icu/samnyan/aqua/net/games/chu3/Chusan.kt similarity index 95% rename from src/main/java/icu/samnyan/aqua/net/games/Chusan.kt rename to src/main/java/icu/samnyan/aqua/net/games/chu3/Chusan.kt index 91f63c15..03bfb22b 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/Chusan.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/chu3/Chusan.kt @@ -1,47 +1,48 @@ -package icu.samnyan.aqua.net.games - -import ext.API -import ext.RP -import ext.Str -import ext.minus -import icu.samnyan.aqua.net.db.AquaUserServices -import icu.samnyan.aqua.net.utils.* -import icu.samnyan.aqua.sega.chusan.model.* -import icu.samnyan.aqua.sega.chusan.model.userdata.UserData -import org.springframework.web.bind.annotation.RestController - -@RestController -@API("api/v2/game/chu3") -class Chusan( - override val us: AquaUserServices, - override val playlogRepo: Chu3UserPlaylogRepo, - override val userDataRepo: Chu3UserDataRepo, - val userGeneralDataRepository: Chu3UserGeneralDataRepo, -): GameApiController("chu3", UserData::class) { - override suspend fun trend(@RP username: Str): List = us.cardByName(username) { card -> - findTrend(playlogRepo.findByUserCardExtId(card.extId) - .map { TrendLog(it.playDate.toString(), it.playerRating) }) - } - - - // Only show > AAA rank - override val shownRanks = chu3Scores.filter { it.first >= 95 * 10000 } - override val settableFields: Map Unit> by lazy { mapOf( - "userName" to { u, v -> u.setUserName(v) - if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } - }, - ) } - - override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card -> - // Summary values: total plays, player rating, server-wide ranking - // number of each rank, max combo, number of full combo, number of all perfect - val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId) - .associate { it.propertyKey to it.propertyValue } - - val ratingComposition = mapOf( - "recent" to (extra["recent_rating_list"] ?: ""), - ) - - genericUserSummary(card, ratingComposition) - } +package icu.samnyan.aqua.net.games.chu3 + +import ext.API +import ext.RP +import ext.Str +import ext.minus +import icu.samnyan.aqua.net.db.AquaUserServices +import icu.samnyan.aqua.net.games.* +import icu.samnyan.aqua.net.utils.* +import icu.samnyan.aqua.sega.chusan.model.* +import icu.samnyan.aqua.sega.chusan.model.userdata.UserData +import org.springframework.web.bind.annotation.RestController + +@RestController +@API("api/v2/game/chu3") +class Chusan( + override val us: AquaUserServices, + override val playlogRepo: Chu3UserPlaylogRepo, + override val userDataRepo: Chu3UserDataRepo, + val userGeneralDataRepository: Chu3UserGeneralDataRepo, +): GameApiController("chu3", UserData::class) { + override suspend fun trend(@RP username: Str): List = us.cardByName(username) { card -> + findTrend(playlogRepo.findByUserCardExtId(card.extId) + .map { TrendLog(it.playDate.toString(), it.playerRating) }) + } + + + // Only show > AAA rank + override val shownRanks = chu3Scores.filter { it.first >= 95 * 10000 } + override val settableFields: Map Unit> by lazy { mapOf( + "userName" to { u, v -> u.setUserName(v) + if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } + }, + ) } + + override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card -> + // Summary values: total plays, player rating, server-wide ranking + // number of each rank, max combo, number of full combo, number of all perfect + val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId) + .associate { it.propertyKey to it.propertyValue } + + val ratingComposition = mapOf( + "recent" to (extra["recent_rating_list"] ?: ""), + ) + + genericUserSummary(card, ratingComposition) + } } \ No newline at end of file diff --git a/src/main/java/icu/samnyan/aqua/net/games/Maimai2.kt b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt similarity index 89% rename from src/main/java/icu/samnyan/aqua/net/games/Maimai2.kt rename to src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt index 31308ca8..d42e53bc 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/Maimai2.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt @@ -1,75 +1,71 @@ -package icu.samnyan.aqua.net.games - -import ext.API -import ext.RP -import ext.Str -import ext.minus -import icu.samnyan.aqua.api.model.resp.sega.maimai2.external.Maimai2DataExport -import icu.samnyan.aqua.net.db.AquaUserServices -import icu.samnyan.aqua.net.utils.* -import icu.samnyan.aqua.sega.maimai2.model.* -import icu.samnyan.aqua.sega.maimai2.model.userdata.UserDetail -import org.springframework.web.bind.annotation.RestController -import java.lang.reflect.Field -import java.util.* -import kotlin.reflect.full.declaredMembers -import kotlin.reflect.full.isSubclassOf -import kotlin.reflect.jvm.jvmErasure - -@RestController -@API("api/v2/game/mai2") -class Maimai2( - override val us: AquaUserServices, - override val playlogRepo: Mai2UserPlaylogRepo, - override val userDataRepo: Mai2UserDataRepo, - val userGeneralDataRepository: Mai2UserGeneralDataRepo, - val repos: Mai2Repos -): GameApiController("mai2", UserDetail::class) { - override suspend fun trend(@RP username: Str): List = us.cardByName(username) { card -> - findTrend(playlogRepo.findByUserCardExtId(card.extId) - .map { TrendLog(it.playDate, it.afterRating) }) - } - - // Only show > S rank - override val shownRanks = mai2Scores.filter { it.first >= 97 * 10000 } - override val settableFields: Map Unit> by lazy { mapOf( - "userName" to { u, v -> u.userName = v - if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } - }, - ) } - - override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card -> - val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId) - .associate { it.propertyKey to it.propertyValue } - - val ratingComposition = mapOf( - "best35" to (extra["recent_rating"] ?: ""), - "best15" to (extra["recent_rating_new"] ?: "") - ) - - genericUserSummary(card, ratingComposition) - } - - // Use reflection to get all properties in Mai2Repos with matching names in Maimai2DataExport - var exportFields: Map> = listOf(*Maimai2DataExport::class.java.declaredFields) - .filter { it.name !in arrayOf("gameId", "userData") } - .associateWith { Mai2Repos::class.declaredMembers - .filter { f -> f.returnType.jvmErasure.isSubclassOf(UserLinked::class) } - .firstOrNull { f -> f.name == it.name || f.name == it.name.replace("List", "") } - ?.call(repos) as UserLinked<*>? ?: error("No matching field found for ${it.name}") - } - - @API("export") - fun exportAllUserData(@RP token: Str) = us.jwt.auth(token) { u -> - try { - Maimai2DataExport().apply { - gameId = "SDEZ" - userData = repos.userData.findByCard(u.ghostCard) ?: (404 - "User not found") - exportFields.forEach { (f, u) -> - f.set(this, if (f.type == List::class.java) u.findByUser(userData) - else u.findSingleByUser(userData).orElse(null)) - } - } - } catch (e: Exception) { 500 - "Error during data export. Reason: ${e.message}" } - } +package icu.samnyan.aqua.net.games.mai2 + +import ext.* +import icu.samnyan.aqua.api.model.resp.sega.maimai2.external.Maimai2DataExport +import icu.samnyan.aqua.net.db.AquaUserServices +import icu.samnyan.aqua.net.games.* +import icu.samnyan.aqua.net.utils.* +import icu.samnyan.aqua.sega.maimai2.model.* +import icu.samnyan.aqua.sega.maimai2.model.userdata.UserDetail +import org.springframework.web.bind.annotation.RestController +import java.lang.reflect.Field +import java.util.* +import kotlin.reflect.full.declaredMembers + +@RestController +@API("api/v2/game/mai2") +class Maimai2( + override val us: AquaUserServices, + override val playlogRepo: Mai2UserPlaylogRepo, + override val userDataRepo: Mai2UserDataRepo, + val userGeneralDataRepository: Mai2UserGeneralDataRepo, + val repos: Mai2Repos +): GameApiController("mai2", UserDetail::class) { + override suspend fun trend(@RP username: Str): List = us.cardByName(username) { card -> + findTrend(playlogRepo.findByUserCardExtId(card.extId) + .map { TrendLog(it.playDate, it.afterRating) }) + } + + // Only show > S rank + override val shownRanks = mai2Scores.filter { it.first >= 97 * 10000 } + override val settableFields: Map Unit> by lazy { mapOf( + "userName" to { u, v -> u.userName = v + if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } + }, + ) } + + override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card -> + val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId) + .associate { it.propertyKey to it.propertyValue } + + val ratingComposition = mapOf( + "best35" to (extra["recent_rating"] ?: ""), + "best15" to (extra["recent_rating_new"] ?: "") + ) + + genericUserSummary(card, ratingComposition) + } + + // Use reflection to get all properties in Mai2Repos with matching names in Maimai2DataExport + var exportFields: Map> = listOf(*Maimai2DataExport::class.java.declaredFields) + .filter { it.name !in arrayOf("gameId", "userData") } + .associateWith { Mai2Repos::class.declaredMembers + .filter { f -> f returns UserLinked::class } + .firstOrNull { f -> f.name == it.name || f.name == it.name.replace("List", "") } + ?.call(repos) as UserLinked<*>? ?: error("No matching field found for ${it.name}") + } + + @API("export") + fun exportAllUserData(@RP token: Str) = us.jwt.auth(token) { u -> + try { + Maimai2DataExport().apply { + gameId = "SDEZ" + userData = repos.userData.findByCard(u.ghostCard) ?: (404 - "User not found") + exportFields.forEach { (f, u) -> + f.set(this, if (f.type == List::class.java) u.findByUser(userData) + else u.findSingleByUser(userData).orElse(null)) + } + } + } catch (e: Exception) { 500 - "Error during data export. Reason: ${e.message}" } + } } \ No newline at end of file diff --git a/src/main/java/icu/samnyan/aqua/net/games/Ongeki.kt b/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt similarity index 87% rename from src/main/java/icu/samnyan/aqua/net/games/Ongeki.kt rename to src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt index a24ea129..2d77fbb1 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/Ongeki.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt @@ -1,41 +1,45 @@ -package icu.samnyan.aqua.net.games - -import ext.API -import ext.minus -import icu.samnyan.aqua.net.db.AquaUserServices -import icu.samnyan.aqua.net.utils.* -import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserDataRepository -import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserGeneralDataRepository -import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserPlaylogRepository -import icu.samnyan.aqua.sega.ongeki.model.userdata.UserData -import org.springframework.web.bind.annotation.RestController - -@RestController -@API("api/v2/game/ongeki") -class Ongeki( - override val us: AquaUserServices, - override val playlogRepo: UserPlaylogRepository, - override val userDataRepo: UserDataRepository, - val userGeneralDataRepository: UserGeneralDataRepository -): GameApiController("ongeki", UserData::class) { - override suspend fun trend(username: String) = us.cardByName(username) { card -> - findTrend(playlogRepo.findByUser_Card_ExtId(card.extId) - .map { TrendLog(it.playDate, it.playerRating) }) - } - - override val shownRanks = ongekiScores.filter { it.first >= 950000 } - override val settableFields: Map Unit> by lazy { mapOf( - "userName" to { u, v -> u.setUserName(v) - if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } - }, - ) } - - override suspend fun userSummary(username: String) = us.cardByName(username) { card -> -// val extra = userGeneralDataRepository.findByUser_Card_ExtId(u.ghostCard.extId) -// .associate { it.propertyKey to it.propertyValue } - - // TODO: Rating composition - - genericUserSummary(card, mapOf()) - } +package icu.samnyan.aqua.net.games.ongeki + +import ext.API +import ext.minus +import icu.samnyan.aqua.net.db.AquaUserServices +import icu.samnyan.aqua.net.games.GameApiController +import icu.samnyan.aqua.net.games.TrendLog +import icu.samnyan.aqua.net.games.USERNAME_CHARS +import icu.samnyan.aqua.net.games.findTrend +import icu.samnyan.aqua.net.utils.* +import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserDataRepository +import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserGeneralDataRepository +import icu.samnyan.aqua.sega.ongeki.dao.userdata.UserPlaylogRepository +import icu.samnyan.aqua.sega.ongeki.model.userdata.UserData +import org.springframework.web.bind.annotation.RestController + +@RestController +@API("api/v2/game/ongeki") +class Ongeki( + override val us: AquaUserServices, + override val playlogRepo: UserPlaylogRepository, + override val userDataRepo: UserDataRepository, + val userGeneralDataRepository: UserGeneralDataRepository +): GameApiController("ongeki", UserData::class) { + override suspend fun trend(username: String) = us.cardByName(username) { card -> + findTrend(playlogRepo.findByUser_Card_ExtId(card.extId) + .map { TrendLog(it.playDate, it.playerRating) }) + } + + override val shownRanks = ongekiScores.filter { it.first >= 950000 } + override val settableFields: Map Unit> by lazy { mapOf( + "userName" to { u, v -> u.setUserName(v) + if (!v.all { it in USERNAME_CHARS }) { 400 - "Invalid character in username" } + }, + ) } + + override suspend fun userSummary(username: String) = us.cardByName(username) { card -> +// val extra = userGeneralDataRepository.findByUser_Card_ExtId(u.ghostCard.extId) +// .associate { it.propertyKey to it.propertyValue } + + // TODO: Rating composition + + genericUserSummary(card, mapOf()) + } } \ No newline at end of file diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetUserItemHandler.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetUserItemHandler.kt index d1ebec3a..8fc957a8 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetUserItemHandler.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetUserItemHandler.kt @@ -1,6 +1,6 @@ package icu.samnyan.aqua.sega.maimai2.handler.impl -import icu.samnyan.aqua.net.games.Maimai2 +import icu.samnyan.aqua.net.games.mai2.Maimai2 import icu.samnyan.aqua.sega.general.dao.CardRepository import icu.samnyan.aqua.sega.maimai2.handler.BaseHandler import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos