From 0985f737536b47415fd9728e1152b83e8d3bb92b Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:08:12 -0400 Subject: [PATCH] [M] Move common models to shared --- planet/build.gradle.kts | 2 +- .../main/kotlin/icu/samnyan/aqua/net/Fedy.kt | 6 +- .../kotlin/icu/samnyan/aqua/net/Safety.kt | 82 +--- .../aqua/net/db/AquaEmailConfirmation.kt | 43 +- .../aqua/net/db/AquaEmailResetPassword.kt | 25 +- .../samnyan/aqua/net/db/AquaGameOptions.kt | 83 +--- .../icu/samnyan/aqua/net/db/AquaNetSession.kt | 23 - .../icu/samnyan/aqua/net/db/AquaNetUser.kt | 416 +++++++----------- .../icu/samnyan/aqua/net/games/Models.kt | 175 ++------ .../icu/samnyan/aqua/sega/allnet/Keychip.kt | 30 +- .../aqua/sega/allnet/KeychipSession.kt | 151 +++---- .../samnyan/aqua/sega/diva/util/DivaUtils.kt | 33 -- .../aqua/sega/general/model/CardTimestamp.kt | 32 -- .../sega/general/model/CardTimestampRepo.kt | 10 + .../aqua/sega/general/service/CardService.kt | 15 +- shared/build.gradle.kts | 23 + .../kotlin/icu/samnyan/aqua/net/Safety.kt | 18 + .../aqua/net/db/AquaEmailConfirmation.kt | 23 + .../aqua/net/db/AquaEmailResetPassword.kt | 23 + .../samnyan/aqua/net/db/AquaGameOptions.kt | 75 ++++ .../icu/samnyan/aqua/net/db/AquaNetSession.kt | 24 + .../icu/samnyan/aqua/net/db/AquaNetUser.kt | 94 ++++ .../icu/samnyan/aqua/net/games/Models.kt | 123 ++++++ .../icu/samnyan/aqua/sega/allnet/Keychip.kt | 20 + .../aqua/sega/allnet/KeychipSession.kt | 34 ++ .../aqua/sega/chusan/model/Chu3GameData.kt | 0 .../sega/chusan/model/request/Chu3UserAll.kt | 0 .../chusan/model/request/MatchingWaitState.kt | 0 .../chusan/model/request/UpsertUserGacha.kt | 0 .../sega/chusan/model/request/UserEmoney.kt | 0 .../model/userdata/Chu3MatchingMember.kt | 0 .../chusan/model/userdata/Chu3NetBattleLog.kt | 0 .../chusan/model/userdata/Chu3UserActivity.kt | 0 .../model/userdata/Chu3UserChallenge.kt | 0 .../chusan/model/userdata/Chu3UserData.kt | 2 +- .../chusan/model/userdata/Chu3UserEntity.kt | 2 +- .../chusan/model/userdata/Chu3UserItem.kt | 0 .../model/userdata/Chu3UserLinkedVerse.kt | 0 .../chusan/model/userdata/Chu3UserMisc.kt | 0 .../chusan/model/userdata/UserCMission.kt | 0 .../model/userdata/UserCMissionProgress.kt | 0 .../model/userdata/UserCardPrintState.kt | 0 .../chusan/model/userdata/UserCharacter.kt | 0 .../sega/chusan/model/userdata/UserCharge.kt | 0 .../sega/chusan/model/userdata/UserCourse.kt | 0 .../sega/chusan/model/userdata/UserDuel.kt | 0 .../sega/chusan/model/userdata/UserGacha.kt | 0 .../chusan/model/userdata/UserGameOption.kt | 0 .../chusan/model/userdata/UserGeneralData.kt | 0 .../chusan/model/userdata/UserLoginBonus.kt | 0 .../sega/chusan/model/userdata/UserMap.kt | 0 .../chusan/model/userdata/UserMusicDetail.kt | 0 .../sega/chusan/model/userdata/UserPlaylog.kt | 0 .../sega/chusan/model/userdata/UserRegions.kt | 0 .../aqua/sega/diva/model/DivaRequestModels.kt | 0 .../aqua/sega/diva/model/DivaResponse.kt | 0 .../aqua/sega/diva/model/Internalizable.kt | 0 .../aqua/sega/diva/model/common/Const.kt | 0 .../sega/diva/model/common/ContestProgress.kt | 0 .../aqua/sega/diva/model/common/LevelInfo.kt | 0 .../aqua/sega/diva/model/common/SortMode.kt | 0 .../model/common/collection/ClearTally.kt | 0 .../common/collection/FestaCollection.kt | 0 .../common/collection/PsRankingCollection.kt | 0 .../sega/diva/model/db/gamedata/Contest.kt | 40 +- .../sega/diva/model/db/gamedata/Difficulty.kt | 0 .../diva/model/db/gamedata/DivaCustomize.kt | 0 .../sega/diva/model/db/gamedata/DivaModule.kt | 0 .../aqua/sega/diva/model/db/gamedata/Festa.kt | 0 .../aqua/sega/diva/model/db/gamedata/Pv.kt | 0 .../sega/diva/model/db/gamedata/PvEntry.kt | 0 .../diva/model/db/userdata/GameSession.kt | 0 .../sega/diva/model/db/userdata/PlayLog.kt | 0 .../diva/model/db/userdata/PlayerContest.kt | 0 .../diva/model/db/userdata/PlayerCustomize.kt | 0 .../diva/model/db/userdata/PlayerInventory.kt | 0 .../diva/model/db/userdata/PlayerModule.kt | 0 .../diva/model/db/userdata/PlayerProfile.kt | 0 .../model/db/userdata/PlayerPvCustomize.kt | 0 .../diva/model/db/userdata/PlayerPvRecord.kt | 0 .../model/db/userdata/PlayerScreenShot.kt | 0 .../samnyan/aqua/sega/diva/util/DivaUtils.kt | 35 ++ .../aqua/sega/general/IntegerListConverter.kt | 0 .../samnyan/aqua/sega/general/model/Card.kt | 0 .../aqua/sega/general/model/CardTimestamp.kt | 22 + .../aqua/sega/general/model/PropertyEntry.kt | 0 .../sega/general/model/UserRecentRating.kt | 0 .../sega/maimai2/model/GameDataEntities.kt | 0 .../aqua/sega/maimai2/model/UserRating.kt | 0 .../aqua/sega/maimai2/model/UserRivalMusic.kt | 0 .../model/request/Mai2UpsertUserAll.kt | 0 .../maimai2/model/request/Mai2UserPhoto.kt | 0 .../maimai2/model/userdata/Mai2UserDetail.kt | 0 .../maimai2/model/userdata/UserEntities.kt | 0 .../aqua/sega/ongeki/model/OngekiEnums.kt | 0 .../sega/ongeki/model/OngekiGameEntities.kt | 0 .../aqua/sega/ongeki/model/OngekiUpsertCM.kt | 0 .../sega/ongeki/model/OngekiUpsertUserAll.kt | 0 .../sega/ongeki/model/OngekiUserEntities.kt | 2 +- .../icu/samnyan/aqua/sega/util/Serializers.kt | 0 .../icu/samnyan/aqua/sega/wacca/Constants.kt | 0 .../aqua/sega/wacca/model/ApiModels.kt | 0 .../aqua/sega/wacca/model/db/WaccaUser.kt | 0 .../sega/wacca/model/db/WaccaUserModels.kt | 0 104 files changed, 844 insertions(+), 842 deletions(-) delete mode 100644 planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt create mode 100644 planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestampRepo.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/Chu3GameData.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/Chu3UserAll.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/MatchingWaitState.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UpsertUserGacha.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UserEmoney.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3MatchingMember.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3NetBattleLog.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserActivity.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserChallenge.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt (99%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt (86%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserItem.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserLinkedVerse.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserMisc.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMission.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMissionProgress.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCardPrintState.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharacter.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharge.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCourse.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserDuel.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGacha.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGameOption.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGeneralData.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserLoginBonus.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMap.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMusicDetail.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserPlaylog.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaRequestModels.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaResponse.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/Internalizable.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/Const.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/ContestProgress.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/LevelInfo.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/SortMode.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/ClearTally.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/FestaCollection.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/PsRankingCollection.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt (66%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Difficulty.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaCustomize.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaModule.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Festa.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Pv.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/PvEntry.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/GameSession.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayLog.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerContest.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerCustomize.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerInventory.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerModule.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerProfile.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvCustomize.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvRecord.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerScreenShot.kt (100%) create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/general/IntegerListConverter.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/general/model/Card.kt (100%) create mode 100644 shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/general/model/PropertyEntry.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/general/model/UserRecentRating.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRating.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRivalMusic.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UserPhoto.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiEnums.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiGameEntities.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertCM.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertUserAll.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt (99%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/util/Serializers.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/wacca/Constants.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/ApiModels.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt (100%) rename {planet => shared}/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt (100%) diff --git a/planet/build.gradle.kts b/planet/build.gradle.kts index c1746763..0065726f 100644 --- a/planet/build.gradle.kts +++ b/planet/build.gradle.kts @@ -118,7 +118,7 @@ hibernate { } kapt { - includeCompileClasspath = false + includeCompileClasspath = true keepJavacAnnotationProcessors = true } diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/Fedy.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/Fedy.kt index c2f6359a..aaa537fa 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/Fedy.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/Fedy.kt @@ -179,14 +179,14 @@ class Fedy( val card = cardRepo.findByExtId(req.extId) ?: (404 - "Card with extId ${req.extId} not found") val cardTimestamp = cardService.getCardTimestamp(card, req.game) - if (cardTimestamp.updatedAt.toEpochMilli() == req.updatedAtMs) return@handleFedy DataPullRes(error = null, result = null) // No changes - val isRebased = req.createdAtMs > 0 && cardTimestamp.createdAt.toEpochMilli() > req.createdAtMs + if (cardTimestamp.updatedAt == req.updatedAtMs) return@handleFedy DataPullRes(error = null, result = null) // No changes + val isRebased = req.createdAtMs > 0 && cardTimestamp.createdAt > req.createdAtMs val exportOptions = if (!isRebased) { req.exportOptions } else { req.exportOptions.copy(playlogAfter = null) } { DataPullRes(result = DataPullResult(data = when (req.game) { "mai2" -> mai2Import.export(card, exportOptions) else -> 406 - "Unsupported game" - }, createdAtMs = cardTimestamp.createdAt.toEpochMilli(), updatedAtMs = cardTimestamp.updatedAt.toEpochMilli(), isRebased = isRebased)) + }, createdAtMs = cardTimestamp.createdAt, updatedAtMs = cardTimestamp.updatedAt, isRebased = isRebased)) } caught { DataPullRes(error = it) } } diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt index 04588caf..db5f59f4 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt @@ -1,82 +1,22 @@ package icu.samnyan.aqua.net -import ext.HTTP -import ext.mut -import ext.toJson -import icu.samnyan.aqua.net.games.BaseEntity -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.http.* -import jakarta.persistence.Entity -import kotlinx.serialization.Serializable -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Configuration import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository import org.springframework.stereotype.Service -import java.text.Normalizer -@Configuration -@ConfigurationProperties(prefix = "aqua-net.openai") -class OpenAIConfig { - var apiKey: String = "" +@Repository +interface SafetyRepo : JpaRepository { + fun findBySafetyId(safetyId: String): Safety? } -@Entity -class AquaNetSafety : BaseEntity() { - var content: String = "" - var safe: Boolean = false -} - -interface AquaNetSafetyRepo : JpaRepository { - fun findByContent(content: String): AquaNetSafety? -} - -@Serializable -data class OpenAIResp( - val id: String, - val model: String, - val results: List -) - -@Serializable -data class OpenAIMod( - val flagged: Boolean, - val categories: Map, - val categoryScores: Map, -) - @Service -class AquaNetSafetyService( - val safety: AquaNetSafetyRepo, - val openAIConfig: OpenAIConfig -) { - /** - * It is very inefficient to have query inside a loop, so we batch the query. - */ - suspend fun isSafeBatch(rawContents: List): List { - val contents = rawContents.map { Normalizer.normalize(it, Normalizer.Form.NFKC) } - val origMap = safety.findAll().associateBy { it.content }.mut - val map = safety.findAll().associateBy { it.content.lowercase().trim() }.mut +class AquaNetSafetyService(val safetyRepo: SafetyRepo) { + fun isSafe(safetyId: String): Boolean { + val safety = safetyRepo.findBySafetyId(safetyId) + return safety == null || safety.status == 0 + } - // Process unseen content with OpenAI - val news = contents.filter { it.lowercase().trim() !in map && it !in contents }.map { inp -> - HTTP.post("https://api.openai.com/v1/moderations") { - header("Authorization", "Bearer ${openAIConfig.apiKey}") - header("Content-Type", "application/json") - setBody(mapOf("input" to inp).toJson()) - }.let { - if (!it.status.isSuccess()) throw Exception("OpenAI request failed for $inp") - val body = it.body>() - AquaNetSafety().apply { - content = inp - safe = !body.results.first().flagged - } - } - } - if (news.isNotEmpty()) safety.saveAll(news) - news.associateByTo(origMap) { it.content } - news.associateByTo(map) { it.content.lowercase().trim() } - - return contents.map { map[it.lowercase().trim()]?.safe ?: origMap[it]?.safe ?: true } + fun isSafeBatch(safetyIds: List): List { + return safetyIds.map { isSafe(it) } } } diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt index 9a324647..f9e23a92 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt @@ -1,33 +1,10 @@ -package icu.samnyan.aqua.net.db - -import jakarta.persistence.* -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.stereotype.Repository -import java.io.Serializable -import java.time.Instant - -@Entity -@Table(name = "aqua_net_email_confirmation") -class EmailConfirmation( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long = 0, - - @Column(nullable = false) - var token: String = "", - - // Token creation time - @Column(nullable = false) - var createdAt: Instant = Instant.now(), - - // Linking to the AquaNetUser - @ManyToOne - @JoinColumn(name = "auId", referencedColumnName = "auId") - var aquaNetUser: AquaNetUser = AquaNetUser() -) : Serializable - -@Repository -interface EmailConfirmationRepo : JpaRepository { - fun findByToken(token: String): EmailConfirmation? - fun findByAquaNetUserAuId(auId: Long): List -} \ No newline at end of file +package icu.samnyan.aqua.net.db + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface EmailConfirmationRepo : JpaRepository { + fun findByToken(token: String): EmailConfirmation? + fun findByAquaNetUserAuId(auId: Long): List +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt index 98a0281c..4487fb0c 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt @@ -1,33 +1,10 @@ package icu.samnyan.aqua.net.db -import jakarta.persistence.* import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository -import java.io.Serializable -import java.time.Instant - -@Entity -@Table(name = "aqua_net_email_reset_password") -class ResetPassword( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long = 0, - - @Column(nullable = false) - var token: String = "", - - // Token creation time - @Column(nullable = false) - var createdAt: Instant = Instant.now(), - - // Linking to the AquaNetUser - @ManyToOne - @JoinColumn(name = "auId", referencedColumnName = "auId") - var aquaNetUser: AquaNetUser = AquaNetUser() -) : Serializable @Repository interface ResetPasswordRepo : JpaRepository { fun findByToken(token: String): ResetPassword? fun findByAquaNetUserAuId(auId: Long): List -} \ No newline at end of file +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt index baba4fc0..93e7ca0b 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt @@ -1,76 +1,7 @@ -package icu.samnyan.aqua.net.db - -import com.fasterxml.jackson.annotation.JsonIgnore -import ext.SettingField -import jakarta.persistence.* -import org.springframework.data.jpa.repository.JpaRepository - -@Entity -class AquaGameOptions( - @Id @JsonIgnore - @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long = 0, - - @SettingField("mai2") @Column(name = "mai2_unlock_music") - var mai2UnlockMusic: Boolean = false, - @SettingField("mai2") @Column(name = "mai2_unlock_chara") - var mai2UnlockChara: Boolean = false, - @SettingField("mai2") @Column(name = "mai2_unlock_chara_max_level") - var mai2UnlockCharaMaxLevel: Boolean = false, - @SettingField("mai2") @Column(name = "mai2_unlock_partners") - var mai2UnlockPartners: Boolean = false, - @SettingField("mai2") @Column(name = "mai2_unlock_collectables") - var mai2UnlockCollectables: Boolean = false, - @SettingField("mai2") @Column(name = "mai2_unlock_tickets") - var mai2UnlockTickets: Boolean = false, - - @SettingField("wacca") - var waccaUnlockMusic: Boolean = false, - @SettingField("wacca") - var waccaUnlockPlates: Boolean = false, - @SettingField("wacca") - var waccaUnlockCollectables: Boolean = false, - @SettingField("wacca") - var waccaUnlockTickets: Boolean = false, - @SettingField("wacca") - var waccaInfiniteWp: Boolean = false, - @SettingField("wacca") - var waccaAlwaysVip: Boolean = false, - - @SettingField("chu3") - var chusanTeamName: String = "", - - @SettingField("chu3") - var chusanInfinitePenguins: Boolean = false, - - @SettingField("chu3-matching") - var chusanMatchingServer: String = "", - - @SettingField("chu3-matching") - var chusanMatchingReflector: String = "", - - @SettingField("chu3-linked-verse") - var chusanLvUnlockAll: Boolean = false, - @SettingField("chu3-linked-verse") - var chusanLvDifficulty: Int = 1, - - @SettingField("chu3-matching-chat") - var chusanSymbolChat1: Int? = null, - @SettingField("chu3-matching-chat") - var chusanSymbolChat2: Int? = null, - @SettingField("chu3-matching-chat") - var chusanSymbolChat3: Int? = null, - @SettingField("chu3-matching-chat") - var chusanSymbolChat4: Int? = null, - - @SettingField("mai2") - var enableMusicRank: Boolean = true, - - @SettingField("ongeki") - var ongekiInfiniteKaika: Boolean = false, - - @SettingField("profile") - var countryOverride: String = "", -) - -interface AquaGameOptionsRepo : JpaRepository +package icu.samnyan.aqua.net.db + +import org.springframework.data.jpa.repository.JpaRepository + +// Entity AquaGameOptions is now in :shared + +interface AquaGameOptionsRepo : JpaRepository diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt index f3f24d52..f1d38dd2 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt @@ -1,30 +1,7 @@ package icu.samnyan.aqua.net.db -import jakarta.persistence.* import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository -import java.io.Serializable -import java.time.Instant -import java.util.* - -fun getTokenExpiry() = Instant.now().plusSeconds(7 * 86400) - -@Entity -@Table(name = "aqua_net_session") -class SessionToken( - @Id - @Column(nullable = false) - var token: String = UUID.randomUUID().toString(), - - // Token creation time - @Column(nullable = false) - var expiry: Instant = getTokenExpiry(), - - // Linking to the AquaNetUser - @ManyToOne - @JoinColumn(name = "auId", referencedColumnName = "auId") - var aquaNetUser: AquaNetUser = AquaNetUser() -) : Serializable @Repository interface SessionTokenRepo : JpaRepository { diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt index 34b2221b..e25640d3 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt @@ -1,251 +1,165 @@ -package icu.samnyan.aqua.net.db - -import com.fasterxml.jackson.annotation.JsonIgnore -import ext.* -import icu.samnyan.aqua.net.UserRegistrar.Companion.cardExtIdEnd -import icu.samnyan.aqua.net.UserRegistrar.Companion.cardExtIdStart -import icu.samnyan.aqua.net.components.JWT -import icu.samnyan.aqua.sega.allnet.AllNetProps -import icu.samnyan.aqua.sega.allnet.KeyChipRepo -import icu.samnyan.aqua.sega.allnet.KeychipSession -import icu.samnyan.aqua.sega.general.GameMusicPopularity -import icu.samnyan.aqua.sega.general.dao.CardRepository -import icu.samnyan.aqua.sega.general.model.Card -import icu.samnyan.aqua.sega.general.service.CardService -import jakarta.persistence.* -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.stereotype.Service -import java.io.Serializable -import java.time.LocalDateTime -import kotlin.jvm.optionals.getOrNull -import kotlin.reflect.KFunction -import kotlin.reflect.KMutableProperty -import kotlin.reflect.full.functions - -@Entity -class AquaNetUser( - @JsonIgnore - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var auId: Long = 0, - - @Column(nullable = false, unique = true, length = 32) - var username: String = "", - - // Login credentials - @Column(nullable = false, unique = true) - var email: String = "", - - @JsonIgnore - @Column(nullable = false) - var pwHash: String = "", - - @Column(nullable = true, length = 32) - var displayName: String = "", - - // Country code at most 3 characters - @Column(length = 3) - var country: String = "", - - // Region code at most 2 characters - @Column(length = 2) - var region: String = "", - - // Last login time - var lastLogin: Long = 0L, - - // Registration time - var regTime: Long = 0L, - - // Profile fields - var profileLocation: String? = "", - var profileBio: String? = "", - var profilePicture: String? = "", - var optOutOfLeaderboard: Boolean = false, - - // Email confirmation - var emailConfirmed: Boolean = false, - - @OneToOne(cascade = [CascadeType.ALL]) - @JoinColumn(name = "ghostCard", unique = true, nullable = false) - var ghostCard: Card = Card(), - - // One user can have multiple cards - @OneToMany(mappedBy = "aquaUser", cascade = [CascadeType.ALL]) - var cards: MutableList = mutableListOf(), - - // Each user can have one keychip (if the user owns a cabinet) - @JsonIgnore - @Column(nullable = true, length = 32, unique = true) - var keychip: Str? = null, - - // Each user's keychip can have multiple sessions - @JsonIgnore - @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL]) - var keychipSessions: MutableList = mutableListOf(), - - @OneToOne(cascade = [CascadeType.ALL]) - @JoinColumn(name = "gameOptions", unique = true, nullable = true) - var gameOptions: AquaGameOptions? = null, -) : Serializable { - val computedName get() = displayName.ifEmpty { username } - - val publicFields get() = mapOf( - "username" to username, - "displayName" to displayName, - "country" to country, - "regTime" to regTime, - "profileLocation" to profileLocation, - "profileBio" to profileBio, - "profilePicture" to profilePicture, - ) -} - -interface AquaNetUserRepo : JpaRepository { - fun findByAuId(auId: Long): AquaNetUser? - fun findByEmailIgnoreCase(email: String): AquaNetUser? - fun findByUsernameIgnoreCase(username: String): AquaNetUser? - fun findByKeychip(keychip: String): AquaNetUser? - fun findByGhostCardExtId(extId: Long): AquaNetUser? -} - -data class SettingField( - val name: Str, - val checker: KFunction<*>, - val setter: KMutableProperty.Setter<*>, -) - -/** - * This class is a validator for user fields. It will return the parsed value if the field is valid, or - * throw an ApiException if the field is invalid. - */ -@Service -class AquaUserServices( - val userRepo: AquaNetUserRepo, - val cardRepo: CardRepository, - val hasher: PasswordEncoder, - val keyChipRepo: KeyChipRepo, - val allNetProps: AllNetProps, - val jwt: JWT, - val em: EntityManager, - val pop: GameMusicPopularity, - val cardService: CardService, - val sessionRepo: SessionTokenRepo, -) { - companion object { - val SETTING_FIELDS = AquaUserServices::class.functions - .filter { it.name.startsWith("check") } - .map { - val name = it.name.removePrefix("check").replaceFirstChar { c -> c.lowercase() } - val prop = AquaNetUser::class.members.find { m -> m.name == name } as KMutableProperty<*> - SettingField(name, it, prop.setter) - } - } - - fun create(username: Str, email: Str, password: Str, country: Str, emailConfirmed: Boolean = false): AquaNetUser { - // Create user - val u = AquaNetUser( - username = checkUsername(username), - email = validateEmail(email), - pwHash = checkPwHash(password), - regTime = millis(), lastLogin = millis(), country = country, - emailConfirmed = emailConfirmed - ) - - // Create a ghost card - val card = Card().apply { - extId = cardService.randExtID(cardExtIdStart, cardExtIdEnd) - luid = extId.toString() - registerTime = LocalDateTime.now() - accessTime = registerTime - aquaUser = u - isGhost = true - } - u.ghostCard = card - - // Save the user - userRepo.save(u) - cardRepo.save(card) - - return u - } - - fun update(user: AquaNetUser, key: Str, value: Str) { - // Check if the key is a settable field - val field = SETTING_FIELDS.find { it.name == key } ?: (400 - "Invalid setting") - // Set the validated field - field.setter.call(user, field.checker.call(this, value)) - } - - fun clearAllSessions(user: AquaNetUser) = sessionRepo.deleteAll(sessionRepo.findByAquaNetUserAuId(user.auId)) - - suspend fun byName(username: Str, callback: suspend (AquaNetUser) -> T) = - async { userRepo.findByUsernameIgnoreCase(username) }?.let { callback(it) } ?: (404 - "User not found") - - suspend fun cardByName(username: Str) = - if (username.startsWith("user")) username.substring(4).toLongOrNull() - ?.let { cardRepo.findById(it)() } ?: (404 - "Card not found") - else byName(username) { it.ghostCard } - - suspend fun cardByName(username: Str, callback: suspend (Card) -> T) = callback(cardByName(username)) - - fun validKeychip(keychipId: Str): Bool { - if (!allNetProps.checkKeychip) return true - if (keychipId.isBlank()) return false - if (userRepo.findByKeychip(keychipId) != null || keyChipRepo.existsByKeychipId(keychipId)) return true - return false - } - - fun checkUsername(username: Str) = username.apply { - // Check if username is valid - if (length < 2) 400 - "Username must be at least 2 letters" - if (length > 32) 400 - "Username too long (max 32 letters)" - if (contains(" ")) 400 - "Username cannot contain spaces" - - // card{id} is a reserved format - if (startsWith("user") && substring(4).toLongOrNull() != null) - 400 - "Username cannot be 'user' + a number. This format is reserved for user IDs." - - // Check if username is within A-Za-z0-9_-~. - find { !it.isLetterOrDigit() && it != '_' && it != '-' && it != '~' && it != '.' }?.let { - 400 - "Username cannot contain `$it`. Please only use letters (A-Z), numbers (0-9), and `_-~.` characters. You can set a display name later." - } - - // Check if user with the same username exists - if (userRepo.findByUsernameIgnoreCase(this) != null) - 400 - "User with username `$this` already exists" - } - - fun validateEmail(email: Str) = email.apply { - // Check if email is valid - if (!isValidEmail()) 400 - "Invalid email" - - // Check if user with the same email exists - if (userRepo.findByEmailIgnoreCase(email) != null) - 400 - "User with email `$email` already exists" - } - - fun checkPwHash(password: Str) = password.run { - // Validate password - if (length < 8) 400 - "Password must be at least 8 characters" - - hasher.encode(this) - } - - fun checkDisplayName(displayName: Str) = displayName.apply { - // Check if display name is valid - if (length > 32) 400 - "Display name too long (max 32 letters)" - } - - fun checkProfileLocation(profileLocation: Str) = profileLocation.apply { - // Check if profile location is valid - if (length > 64) 400 - "Profile location too long (max 64 letters)" - } - - fun checkProfileBio(profileBio: Str) = profileBio.apply { - // Check if profile bio is valid - if (length > 255) 400 - "Profile bio too long (max 255 letters)" - } - - fun checkOptOutOfLeaderboard(optOutOfLeaderboard: Str) = optOutOfLeaderboard.toBoolean() -} +package icu.samnyan.aqua.net.db + +import ext.* +import icu.samnyan.aqua.net.UserRegistrar.Companion.cardExtIdEnd +import icu.samnyan.aqua.net.UserRegistrar.Companion.cardExtIdStart +import icu.samnyan.aqua.net.components.JWT +import icu.samnyan.aqua.sega.allnet.AllNetProps +import icu.samnyan.aqua.sega.allnet.KeyChipRepo +import icu.samnyan.aqua.sega.allnet.KeychipSession +import icu.samnyan.aqua.sega.general.GameMusicPopularity +import icu.samnyan.aqua.sega.general.dao.CardRepository +import icu.samnyan.aqua.sega.general.model.Card +import icu.samnyan.aqua.sega.general.service.CardService +import jakarta.persistence.* +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service +import java.time.LocalDateTime +import kotlin.reflect.KFunction +import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.functions + +// Entity AquaNetUser and SettingField are now in :shared + +interface AquaNetUserRepo : JpaRepository { + fun findByAuId(auId: Long): AquaNetUser? + fun findByEmailIgnoreCase(email: String): AquaNetUser? + fun findByUsernameIgnoreCase(username: String): AquaNetUser? + fun findByKeychip(keychip: String): AquaNetUser? + fun findByGhostCardExtId(extId: Long): AquaNetUser? +} + +/** + * User services (formerly inside AquaNetUser.kt in the monolithic setup). + */ +@Service +class AquaUserServices( + val userRepo: AquaNetUserRepo, + val cardRepo: CardRepository, + val hasher: PasswordEncoder, + val keyChipRepo: KeyChipRepo, + val allNetProps: AllNetProps, + val jwt: JWT, + val em: EntityManager, + val pop: GameMusicPopularity, + val cardService: CardService, + val sessionRepo: SessionTokenRepo, +) { + companion object { + val SETTING_FIELDS = AquaUserServices::class.functions + .filter { it.name.startsWith("check") } + .map { + val name = it.name.removePrefix("check").replaceFirstChar { c -> c.lowercase() } + val prop = AquaNetUser::class.members.find { m -> m.name == name } as KMutableProperty<*> + SettingField(name, it, prop.setter) + } + } + + fun create(username: Str, email: Str, password: Str, country: Str, emailConfirmed: Boolean = false): AquaNetUser { + // Create user + val u = AquaNetUser( + username = checkUsername(username), + email = validateEmail(email), + pwHash = checkPwHash(password), + regTime = millis(), lastLogin = millis(), country = country, + emailConfirmed = emailConfirmed + ) + + // Create a ghost card + val card = Card().apply { + extId = cardService.randExtID(cardExtIdStart, cardExtIdEnd) + luid = extId.toString() + registerTime = LocalDateTime.now() + accessTime = registerTime + aquaUser = u + isGhost = true + } + u.ghostCard = card + + // Save the user + userRepo.save(u) + cardRepo.save(card) + + return u + } + + fun update(user: AquaNetUser, key: Str, value: Str) { + // Check if the key is a settable field + val field = SETTING_FIELDS.find { it.name == key } ?: (400 - "Invalid setting") + // Set the validated field + field.setter.call(user, field.checker.call(this, value)) + } + + fun clearAllSessions(user: AquaNetUser) = sessionRepo.deleteAll(sessionRepo.findByAquaNetUserAuId(user.auId)) + + suspend fun byName(username: Str, callback: suspend (AquaNetUser) -> T) = + async { userRepo.findByUsernameIgnoreCase(username) }?.let { callback(it) } ?: (404 - "User not found") + + suspend fun cardByName(username: Str) = + if (username.startsWith("user")) username.substring(4).toLongOrNull() + ?.let { cardRepo.findById(it)() } ?: (404 - "Card not found") + else byName(username) { it.ghostCard } + + suspend fun cardByName(username: Str, callback: suspend (Card) -> T) = callback(cardByName(username)) + + fun validKeychip(keychipId: Str): Bool { + if (!allNetProps.checkKeychip) return true + if (keychipId.isBlank()) return false + if (userRepo.findByKeychip(keychipId) != null || keyChipRepo.existsByKeychipId(keychipId)) return true + return false + } + + fun checkUsername(username: Str) = username.apply { + // Check if username is valid + if (length < 2) 400 - "Username must be at least 2 letters" + if (length > 32) 400 - "Username too long (max 32 letters)" + if (contains(" ")) 400 - "Username cannot contain spaces" + + // card{id} is a reserved format + if (startsWith("user") && substring(4).toLongOrNull() != null) + 400 - "Username cannot be 'user' + a number. This format is reserved for user IDs." + + // Check if username is within A-Za-z0-9_-~. + find { !it.isLetterOrDigit() && it != '_' && it != '-' && it != '~' && it != '.' }?.let { + 400 - "Username cannot contain `$it`. Please only use letters (A-Z), numbers (0-9), and `_-~.` characters. You can set a display name later." + } + + // Check if user with the same username exists + if (userRepo.findByUsernameIgnoreCase(this) != null) + 400 - "User with username `$this` already exists" + } + + fun validateEmail(email: Str) = email.apply { + // Check if email is valid + if (!isValidEmail()) 400 - "Invalid email" + + // Check if user with the same email exists + if (userRepo.findByEmailIgnoreCase(email) != null) + 400 - "User with email `$email` already exists" + } + + fun checkPwHash(password: Str) = password.run { + // Validate password + if (length < 8) 400 - "Password must be at least 8 characters" + + hasher.encode(this) + } + + fun checkDisplayName(displayName: Str) = displayName.apply { + // Check if display name is valid + if (length > 32) 400 - "Display name too long (max 32 letters)" + } + + fun checkProfileLocation(profileLocation: Str) = profileLocation.apply { + // Check if profile location is valid + if (length > 64) 400 - "Profile location too long (max 64 letters)" + } + + fun checkProfileBio(profileBio: Str) = profileBio.apply { + // Check if profile bio is valid + if (length > 255) 400 - "Profile bio too long (max 255 letters)" + } + + fun checkOptOutOfLeaderboard(optOutOfLeaderboard: Str) = optOutOfLeaderboard.toBoolean() +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt b/planet/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt index 5fefbb11..fb733773 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt @@ -1,146 +1,29 @@ -package icu.samnyan.aqua.net.games - -import com.fasterxml.jackson.annotation.JsonIgnore -import ext.JACKSON -import ext.JavaSerializable -import icu.samnyan.aqua.sega.general.model.Card -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.MappedSuperclass -import kotlinx.serialization.Serializable -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.data.repository.NoRepositoryBean -import java.util.* - -data class TrendOut(val date: String, val rating: Int, val plays: Int) - -data class RankCount(val name: String, val count: Int) - -data class GenericGameSummary( - val name: String, - - val aquaUser: Map?, - - val serverRank: Long, - val accuracy: Double, - val rating: Int, - val ratingHighest: Int, - val ranks: List, - val detailedRanks: Map>, - val maxCombo: Int, - val fullCombo: Int, - val allPerfect: Int, - val totalScore: Long, - - val plays: Int, - val totalPlayTime: Long, - val joined: String, - val lastSeen: String, - val lastVersion: String, - val lastPlayedHost: String? = null, - - val ratingComposition: Map, - - val recent: List, - - val rival: Boolean?, - val favorites: List? -) - -data class GenericRankingPlayer( - var rank: Int, - val name: String, - val username: String?, - val accuracy: Double, - val rating: Int, - val allPerfect: Int, - val fullCombo: Int, - val lastSeen: String -) - -@Serializable -data class GenericMusicMeta( - val name: String?, - val ver: String, - val notes: List -) - -@Serializable -data class GenericNoteMeta( - val lv: Double?, -) - -@Serializable -data class GenericItemMeta( - val name: String? = null, - val disable: Boolean? = null, - val ver: String? = null -) - -// Here are some interfaces to generalize across multiple games -interface IUserData { - val id: Long - var userName: String - val playerRating: Int - val highestRating: Int - val firstPlayDate: Any - val lastPlayDate: Any - val lastRomVersion: String - val totalScore: Long - var card: Card? - val lastClientId: String? -} - -interface IGenericGamePlaylog { - val user: IUserData - val musicId: Int - val level: Int - val userPlayDate: Any - val achievement: Int - val maxCombo: Int - val isFullCombo: Boolean - val beforeRating: Int - val afterRating: Int - val isAllPerfect: Boolean -} - -interface IGenericUserMusic { - val musicId: Int -} - -@MappedSuperclass -open class BaseEntity( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonIgnore - open var id: Long = 0 -) : JavaSerializable { - override fun toString() = JACKSON.writeValueAsString(this) -} - -@NoRepositoryBean -interface GenericUserDataRepo : JpaRepository { - fun findByCard(card: Card): T? - fun findByCard_ExtId(extId: Long): T? - - @Query("select e from #{#entityName} e where e.card.rankingBanned = false") - fun findAllNonBanned(): List -} - -@NoRepositoryBean -interface GenericPlaylogRepo : JpaRepository { - fun findByUserCardExtId(extId: Long): List - fun findByUserCardExtId(extId: Long, page: Pageable): Page -} - -@NoRepositoryBean -interface GenericUserMusicRepo : JpaRepository { - fun findByUserCardExtId(extId: Long): List - fun findByUser_Card_ExtIdAndMusicIdIn(userId: Long, musicId: List): List -} - -data class ImportResult(val errors: List, val warnings: List, val json: String) +package icu.samnyan.aqua.net.games + +import icu.samnyan.aqua.sega.general.model.Card +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.NoRepositoryBean + +@NoRepositoryBean +interface GenericUserDataRepo : JpaRepository { + fun findByCard(card: Card): T? + fun findByCard_ExtId(extId: Long): T? + + @Query("select e from #{'#'}{#entityName} e where e.card.rankingBanned = false") + fun findAllNonBanned(): List +} + +@NoRepositoryBean +interface GenericPlaylogRepo : JpaRepository { + fun findByUserCardExtId(extId: Long): List + fun findByUserCardExtId(extId: Long, page: Pageable): Page +} + +@NoRepositoryBean +interface GenericUserMusicRepo : JpaRepository { + fun findByUserCardExtId(extId: Long): List + fun findByUser_Card_ExtIdAndMusicIdIn(userId: Long, musicId: List): List +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt index f88ff798..02b6ccf9 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt @@ -1,32 +1,10 @@ package icu.samnyan.aqua.sega.allnet -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.Table import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository -import java.io.Serializable -/** - * This is the old method of securing requests - a keychip whitelist, - * it's kept here only for backwards compatibility. - */ -@Entity -@Table(name = "allnet_keychips") -class Keychip( - @Id - val id: Long = 0, - - @Column(unique = true, nullable = false) - val keychipId: String = "", -) : Serializable { - companion object { - const val serialVersionUID = 1L - } +@Repository +interface KeyChipRepo : JpaRepository { + fun findByKeychipId(keychipId: String): Keychip? + fun existsByKeychipId(keychipId: String): Boolean } - -@Repository("KeyChipRepository") -interface KeyChipRepo : JpaRepository { - fun existsByKeychipId(keychipId: String?): Boolean -} \ No newline at end of file diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt index 143e55d8..d4d54066 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt @@ -1,91 +1,60 @@ -package icu.samnyan.aqua.sega.allnet - -import ext.async -import icu.samnyan.aqua.net.db.AquaNetUser -import jakarta.persistence.* -import jakarta.transaction.Transactional -import org.slf4j.LoggerFactory -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.scheduling.annotation.Scheduled -import org.springframework.stereotype.Repository -import org.springframework.stereotype.Service -import java.security.SecureRandom - -/** - * This is a one-to-many mapping of keychip to session token. - */ -@Entity -@Table(name = "allnet_keychip_sessions", indexes = [ - Index(name = "idx_last_use", columnList = "lastUse") -]) -class KeychipSession( - @ManyToOne - @JoinColumn(name = "au_id") - var user: AquaNetUser? = null, - - @Column(length = 4) - val gameId: String, - - @Id - @Column(length = 32) - val token: String = genUrlSafeToken(32), - - @Column(nullable = false) - var lastUse: Long = System.currentTimeMillis() -) - - -val urlSafeChars = ('a'..'z') + ('A'..'Z') + ('0'..'9') + listOf('-', '_', '.', '~') - -fun genUrlSafeToken(length: Int): String { - val random = SecureRandom() - return (1..length) - .map { urlSafeChars[random.nextInt(urlSafeChars.size)] } - .joinToString("") -} - -@Repository("KeychipSessionRepo") -interface KeychipSessionRepo : JpaRepository { - fun findByToken(token: String): KeychipSession? - - @Transactional - fun deleteAllByLastUseBefore(expire: Long) -} - -@Service -class KeychipSessionService( - val repo: KeychipSessionRepo, - val props: AllNetProps -) { - val logger = LoggerFactory.getLogger(KeychipSessionService::class.java) - - /** - * Delete sessions that are older than the expire time. - */ - @Scheduled(fixedDelayString = "\${allnet.server.keychip-ses-clean-interval}") - suspend fun cleanup() = async { - logger.info("!!! Keychip session cleanup !!!") - val expire = System.currentTimeMillis() - props.keychipSesExpire - repo.deleteAllByLastUseBefore(expire) - } - - /** - * Create a new session. - */ - fun new(user: AquaNetUser?, gameId: String): KeychipSession { - val session = KeychipSession(user = user, gameId = gameId) - return repo.save(session) - } - - /** - * Find a session. If found, renew the last use time. - */ - fun find(token: String) = repo.findByToken(token)?.apply { - lastUse = System.currentTimeMillis() - try { - repo.save(this) - } catch (_: Exception) { - logger.error("Failed to update last use time for session $token") - } - } -} +package icu.samnyan.aqua.sega.allnet + +import ext.async +import icu.samnyan.aqua.net.db.AquaNetUser +import jakarta.transaction.Transactional +import org.slf4j.LoggerFactory +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Repository +import org.springframework.stereotype.Service + +/** + * Repository and Service for KeychipSession (Entity is located in :shared module). + */ + +@Repository("KeychipSessionRepo") +interface KeychipSessionRepo : JpaRepository { + fun findByToken(token: String): KeychipSession? + + @Transactional + fun deleteAllByLastUseBefore(expire: Long) +} + +@Service +class KeychipSessionService( + val repo: KeychipSessionRepo, + val props: AllNetProps +) { + val logger = LoggerFactory.getLogger(KeychipSessionService::class.java) + + /** + * Delete sessions that are older than the expire time. + */ + @Scheduled(fixedDelayString = "\${allnet.server.keychip-ses-clean-interval}") + suspend fun cleanup() = async { + logger.info("!!! Keychip session cleanup !!!") + val expire = System.currentTimeMillis() - props.keychipSesExpire + repo.deleteAllByLastUseBefore(expire) + } + + /** + * Create a new session. + */ + fun new(user: AquaNetUser?, gameId: String): KeychipSession { + val session = KeychipSession(user = user, gameId = gameId) + return repo.save(session) + } + + /** + * Find a session. If found, renew the last use time. + */ + fun find(token: String) = repo.findByToken(token)?.apply { + lastUse = System.currentTimeMillis() + try { + repo.save(this) + } catch (_: Exception) { + logger.error("Failed to update last use time for session $token") + } + } +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt index e2413dbb..0bf707e1 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt @@ -1,40 +1,12 @@ package icu.samnyan.aqua.sega.diva.util -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.ser.std.StdSerializer import icu.samnyan.aqua.sega.diva.PlayerPvRecordRepository import icu.samnyan.aqua.sega.diva.model.common.Edition import icu.samnyan.aqua.sega.diva.model.common.LevelInfo import icu.samnyan.aqua.sega.diva.model.db.userdata.PlayerProfile import org.springframework.stereotype.Component -import java.net.URLEncoder -import java.nio.charset.StandardCharsets -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter import kotlin.math.roundToInt -object DivaStringUtils { - @JvmStatic - fun getDummyString(content: String, length: Int) = "$content,".repeat(length).removeSuffix(",") -} - -object DivaTime { - val now get() = getString(LocalDateTime.now()) - - @JvmStatic - fun getString(time: LocalDateTime) = URIEncoder.encode(format(time)) - - @JvmStatic - fun format(time: LocalDateTime) = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time) -} - -class DivaDateTimeSerializer(t: Class? = null) : StdSerializer(t) { - override fun serialize(value: LocalDateTime, gen: JsonGenerator, provider: SerializerProvider) { - gen.writeString(DivaTime.getString(value)) - } -} - @Component class DivaCalculator(private val playerPvRecordRepository: PlayerPvRecordRepository) { fun getLevelInfo(profile: PlayerProfile): LevelInfo { @@ -50,8 +22,3 @@ class DivaCalculator(private val playerPvRecordRepository: PlayerPvRecordReposit return LevelInfo(level + 1, exp) } } - -object URIEncoder { - @JvmStatic - fun encode(str: String) = URLEncoder.encode(str, StandardCharsets.UTF_8).replace("\\+".toRegex(), "%20") -} \ No newline at end of file diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt deleted file mode 100644 index 9a64e3e8..00000000 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt +++ /dev/null @@ -1,32 +0,0 @@ -package icu.samnyan.aqua.sega.general.model - -import ext.Str -import jakarta.persistence.* -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.stereotype.Repository -import java.time.Instant - -@Entity(name = "SegaCardTimestamp") -@Table(name = "sega_card_timestamp") -class CardTimestamp( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long = 0, - - @Column(nullable = false) - var createdAt: Instant = Instant.now(), - - @Column(nullable = false) - var updatedAt: Instant = Instant.now(), - - var game: Str, - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "card_id") - var card: Card? = null, -) - -@Repository -interface CardTimestampRepo : JpaRepository { - fun findByCardIdAndGame(cardId: Long, game: Str): CardTimestamp? -} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestampRepo.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestampRepo.kt new file mode 100644 index 00000000..d309bb51 --- /dev/null +++ b/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestampRepo.kt @@ -0,0 +1,10 @@ +package icu.samnyan.aqua.sega.general.model + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository +import java.util.* + +@Repository +interface CardTimestampRepo : JpaRepository { + fun findByCardIdAndGameId(cardId: Long, gameId: String): Optional +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/service/CardService.kt b/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/service/CardService.kt index d5761fe9..d46f3c99 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/service/CardService.kt +++ b/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/service/CardService.kt @@ -104,12 +104,19 @@ class CardService(val cardRepo: CardRepository, val cardTimestampRepo: CardTimes return eid } - fun getCardTimestamp(card: Card, game: Str, now: Instant = Instant.now()) = - cardTimestampRepo.findByCardIdAndGame(card.id, game) ?: CardTimestamp(game = game, card = card, createdAt = now, updatedAt = now); + fun getCardTimestamp(card: Card, game: Str, now: Instant = Instant.now()): CardTimestamp = + cardTimestampRepo.findByCardIdAndGameId(card.id, game).orElseGet { + CardTimestamp().apply { + this.gameId = game + this.cardId = card.id + this.createdAt = now.toEpochMilli() + this.updatedAt = now.toEpochMilli() + } + } fun updateCardTimestamp(card: Card, game: Str, now: Instant = Instant.now(), resetCreatedAt: Bool = false) { - cardTimestampRepo.save(getCardTimestamp(card, game, now).apply { updatedAt = now } - .apply { if (resetCreatedAt) createdAt = now }); + cardTimestampRepo.save(getCardTimestamp(card, game, now).apply { updatedAt = now.toEpochMilli() } + .apply { if (resetCreatedAt) createdAt = now.toEpochMilli() }); fedy.onDataUpdated(card.extId, game, resetCreatedAt) } } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index d3f80072..a54b9294 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -2,6 +2,8 @@ plugins { kotlin("jvm") kotlin("plugin.jpa") kotlin("plugin.serialization") + kotlin("kapt") + id("org.hibernate.orm") version "6.4.4.Final" } dependencies { @@ -11,9 +13,30 @@ dependencies { api("com.fasterxml.jackson.core:jackson-databind:2.17.0") api("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.0") + // QueryDSL + implementation("io.github.openfeign.querydsl:querydsl-jpa:6.10.1") + kapt("io.github.openfeign.querydsl:querydsl-apt:6.10.1:jpa") + // Core libraries api("org.slf4j:slf4j-api:2.0.12") api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") api("org.jetbrains.kotlin:kotlin-reflect:2.1.10") + + // Hibernate enhancement requires the core library in shared as well + implementation("org.hibernate.orm:hibernate-core:6.4.4.Final") +} + +hibernate { + enhancement { + enableLazyInitialization = true + enableAssociationManagement = false + enableExtendedEnhancement = false + } +} + +sourceSets { + main { + java.srcDir("${layout.buildDirectory.get()}/generated/source/kapt/main") + } } diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt new file mode 100644 index 00000000..baf19f6a --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/Safety.kt @@ -0,0 +1,18 @@ +package icu.samnyan.aqua.net + +import jakarta.persistence.* +import java.io.Serializable + +@Entity +@Table(name = "aqua_net_safety") +class Safety( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long = 0, + + @Column(nullable = false, unique = true, length = 64) + var safetyId: String = "", + + @Column(nullable = false) + var status: Int = 0 +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt new file mode 100644 index 00000000..aac7242f --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailConfirmation.kt @@ -0,0 +1,23 @@ +package icu.samnyan.aqua.net.db + +import jakarta.persistence.* +import java.io.Serializable +import java.time.Instant + +@Entity +@Table(name = "aqua_net_email_confirmation") +class EmailConfirmation( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long = 0, + + @ManyToOne + @JoinColumn(name = "auId") + var aquaNetUser: AquaNetUser = AquaNetUser(), + + @Column(nullable = false, unique = true) + var token: String = "", + + @Column(nullable = false) + var createdAt: Instant = Instant.now() +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt new file mode 100644 index 00000000..24797993 --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaEmailResetPassword.kt @@ -0,0 +1,23 @@ +package icu.samnyan.aqua.net.db + +import jakarta.persistence.* +import java.io.Serializable +import java.time.Instant + +@Entity +@Table(name = "aqua_net_email_reset_password") +class ResetPassword( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long = 0, + + @ManyToOne + @JoinColumn(name = "auId") + var aquaNetUser: AquaNetUser = AquaNetUser(), + + @Column(nullable = false, unique = true) + var token: String = "", + + @Column(nullable = false) + var createdAt: Instant = Instant.now() +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt new file mode 100644 index 00000000..78288d69 --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaGameOptions.kt @@ -0,0 +1,75 @@ +package icu.samnyan.aqua.net.db + +import com.fasterxml.jackson.annotation.JsonIgnore +import ext.SettingField +import jakarta.persistence.* +import java.io.Serializable + +@Entity +@Table(name = "aqua_net_game_options") +class AquaGameOptions( + @Id @JsonIgnore + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long = 0, + + @SettingField("mai2") @Column(name = "mai2_unlock_music") + var mai2UnlockMusic: Boolean = false, + @SettingField("mai2") @Column(name = "mai2_unlock_chara") + var mai2UnlockChara: Boolean = false, + @SettingField("mai2") @Column(name = "mai2_unlock_chara_max_level") + var mai2UnlockCharaMaxLevel: Boolean = false, + @SettingField("mai2") @Column(name = "mai2_unlock_partners") + var mai2UnlockPartners: Boolean = false, + @SettingField("mai2") @Column(name = "mai2_unlock_collectables") + var mai2UnlockCollectables: Boolean = false, + @SettingField("mai2") @Column(name = "mai2_unlock_tickets") + var mai2UnlockTickets: Boolean = false, + + @SettingField("wacca") + var waccaUnlockMusic: Boolean = false, + @SettingField("wacca") + var waccaUnlockPlates: Boolean = false, + @SettingField("wacca") + var waccaUnlockCollectables: Boolean = false, + @SettingField("wacca") + var waccaUnlockTickets: Boolean = false, + @SettingField("wacca") + var waccaInfiniteWp: Boolean = false, + @SettingField("wacca") + var waccaAlwaysVip: Boolean = false, + + @SettingField("chu3") + var chusanTeamName: String = "", + + @SettingField("chu3") + var chusanInfinitePenguins: Boolean = false, + + @SettingField("chu3-matching") + var chusanMatchingServer: String = "", + + @SettingField("chu3-matching") + var chusanMatchingReflector: String = "", + + @SettingField("chu3-linked-verse") + var chusanLvUnlockAll: Boolean = false, + @SettingField("chu3-linked-verse") + var chusanLvDifficulty: Int = 1, + + @SettingField("chu3-matching-chat") + var chusanSymbolChat1: Int? = null, + @SettingField("chu3-matching-chat") + var chusanSymbolChat2: Int? = null, + @SettingField("chu3-matching-chat") + var chusanSymbolChat3: Int? = null, + @SettingField("chu3-matching-chat") + var chusanSymbolChat4: Int? = null, + + @SettingField("mai2") + var enableMusicRank: Boolean = true, + + @SettingField("ongeki") + var ongekiInfiniteKaika: Boolean = false, + + @SettingField("profile") + var countryOverride: String = "", +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt new file mode 100644 index 00000000..d8452b59 --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetSession.kt @@ -0,0 +1,24 @@ +package icu.samnyan.aqua.net.db + +import jakarta.persistence.* +import java.io.Serializable +import java.time.Instant +import java.util.* + +fun getTokenExpiry() = Instant.now().plusSeconds(7 * 86400) + +@Entity +@Table(name = "aqua_net_session") +class SessionToken( + @Id + @Column(nullable = false) + var token: String = UUID.randomUUID().toString(), + + // Token creation time + @Column(nullable = false) + var expiry: Instant = getTokenExpiry(), + + @ManyToOne + @JoinColumn(name = "auId", referencedColumnName = "auId") + var aquaNetUser: AquaNetUser = AquaNetUser() +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt new file mode 100644 index 00000000..ed6d773e --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/db/AquaNetUser.kt @@ -0,0 +1,94 @@ +package icu.samnyan.aqua.net.db + +import com.fasterxml.jackson.annotation.JsonIgnore +import ext.* +import icu.samnyan.aqua.sega.allnet.KeychipSession +import icu.samnyan.aqua.sega.general.model.Card +import jakarta.persistence.* +import java.io.Serializable +import kotlin.reflect.KFunction +import kotlin.reflect.KMutableProperty + +@Entity +class AquaNetUser( + @JsonIgnore + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + var auId: Long = 0, + + @Column(nullable = false, unique = true, length = 32) + var username: String = "", + + // Login credentials + @Column(nullable = false, unique = true) + var email: String = "", + + @JsonIgnore + @Column(nullable = false) + var pwHash: String = "", + + @Column(nullable = true, length = 32) + var displayName: String = "", + + // Country code at most 3 characters + @Column(length = 3) + var country: String = "", + + // Region code at most 2 characters + @Column(length = 2) + var region: String = "", + + // Last login time + var lastLogin: Long = 0L, + + // Registration time + var regTime: Long = 0L, + + // Profile fields + var profileLocation: String? = "", + var profileBio: String? = "", + var profilePicture: String? = "", + var optOutOfLeaderboard: Boolean = false, + + // Email confirmation + var emailConfirmed: Boolean = false, + + @OneToOne(cascade = [CascadeType.ALL]) + @JoinColumn(name = "ghostCard", unique = true, nullable = false) + var ghostCard: Card = Card(), + + // One user can have multiple cards + @OneToMany(mappedBy = "aquaUser", cascade = [CascadeType.ALL]) + var cards: MutableList = mutableListOf(), + + // Each user can have one keychip (if the user owns a cabinet) + @JsonIgnore + @Column(nullable = true, length = 32, unique = true) + var keychip: Str? = null, + + // Each user's keychip can have multiple sessions + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL]) + var keychipSessions: MutableList = mutableListOf(), + + @OneToOne(cascade = [CascadeType.ALL]) + @JoinColumn(name = "gameOptions", unique = true, nullable = true) + var gameOptions: AquaGameOptions? = null, +) : Serializable { + val computedName get() = displayName.ifEmpty { username } + + val publicFields get() = mapOf( + "username" to username, + "displayName" to displayName, + "country" to country, + "regTime" to regTime, + "profileLocation" to profileLocation, + "profileBio" to profileBio, + "profilePicture" to profilePicture, + ) +} + +data class SettingField( + val name: Str, + val checker: KFunction<*>, + val setter: KMutableProperty.Setter<*>, +) diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt b/shared/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt new file mode 100644 index 00000000..9222b36a --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/net/games/Models.kt @@ -0,0 +1,123 @@ +package icu.samnyan.aqua.net.games + +import com.fasterxml.jackson.annotation.JsonIgnore +import ext.JACKSON +import ext.JavaSerializable +import icu.samnyan.aqua.sega.general.model.Card +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.MappedSuperclass +import kotlinx.serialization.Serializable + +data class TrendOut(val date: String, val rating: Int, val plays: Int) + +data class RankCount(val name: String, val count: Int) + +data class GenericGameSummary( + val name: String, + val aquaUser: Map?, + val serverRank: Long, + val accuracy: Double, + val rating: Int, + val ratingHighest: Int, + val ranks: List, + val detailedRanks: Map>, + val maxCombo: Int, + val fullCombo: Int, + val allPerfect: Int, + val totalScore: Long, + val plays: Int, + val totalPlayTime: Long, + val joined: String, + val lastSeen: String, + val lastVersion: String, + val lastPlayedHost: String? = null, + val ratingComposition: Map, + val recent: List, + val rival: Boolean?, + val favorites: List? +) + +data class GenericRankingPlayer( + var rank: Int, + val name: String, + val username: String?, + val accuracy: Double, + val rating: Int, + val allPerfect: Int, + val fullCombo: Int, + val lastSeen: String +) + +@Serializable +data class GenericMusicMeta( + val name: String?, + val ver: String, + val notes: List +) + +@Serializable +data class GenericNoteMeta( + val lv: Double?, +) + +@Serializable +data class GenericItemMeta( + val name: String? = null, + val disable: Boolean? = null, + val ver: String? = null +) + +// Here are some interfaces to generalize across multiple games +interface IUserData { + val id: Long + var userName: String + val playerRating: Int + val highestRating: Int + val firstPlayDate: Any + val lastPlayDate: Any + val lastRomVersion: String + val totalScore: Long + var card: Card? + val lastClientId: String? +} + +interface IGenericGamePlaylog { + val user: IUserData + val musicId: Int + val level: Int + val userPlayDate: Any + val achievement: Int + val maxCombo: Int + val isFullCombo: Boolean + val beforeRating: Int + val afterRating: Int + val isAllPerfect: Boolean +} + +interface IGenericUserMusic { + val musicId: Int +} + +interface IUserEntity { + var id: Long + var user: UserModel +} + +interface IExportClass { + var gameId: String + var userData: UserModel +} + +@MappedSuperclass +open class BaseEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @JsonIgnore + open var id: Long = 0 +) : JavaSerializable { + override fun toString() = JACKSON.writeValueAsString(this) +} + +data class ImportResult(val errors: List, val warnings: List, val json: String) diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt new file mode 100644 index 00000000..a3ae6fd8 --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/Keychip.kt @@ -0,0 +1,20 @@ +package icu.samnyan.aqua.sega.allnet + +import icu.samnyan.aqua.net.db.AquaNetUser +import jakarta.persistence.* +import java.io.Serializable + +@Entity +@Table(name = "allnet_keychips") +class Keychip( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long = 0, + + @Column(nullable = false, unique = true, length = 32) + var keychipId: String = "", + + @ManyToOne + @JoinColumn(name = "auId") + var user: AquaNetUser? = null +) : Serializable diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt new file mode 100644 index 00000000..6f45532f --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/allnet/KeychipSession.kt @@ -0,0 +1,34 @@ +package icu.samnyan.aqua.sega.allnet + +import icu.samnyan.aqua.net.db.AquaNetUser +import jakarta.persistence.* +import java.security.SecureRandom + +@Entity +@Table(name = "allnet_keychip_sessions", indexes = [ + Index(name = "idx_last_use", columnList = "lastUse") +]) +class KeychipSession( + @ManyToOne + @JoinColumn(name = "au_id") + var user: AquaNetUser? = null, + + @Column(length = 4) + val gameId: String, + + @Id + @Column(length = 32) + val token: String = genUrlSafeToken(32), + + @Column(nullable = false) + var lastUse: Long = System.currentTimeMillis() +) + +val urlSafeChars = ('a'..'z') + ('A'..'Z') + ('0'..'9') + listOf('-', '_', '.', '~') + +fun genUrlSafeToken(length: Int): String { + val random = SecureRandom() + return (1..length) + .map { urlSafeChars[random.nextInt(urlSafeChars.size)] } + .joinToString("") +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/Chu3GameData.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/Chu3GameData.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/Chu3GameData.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/Chu3GameData.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/Chu3UserAll.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/Chu3UserAll.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/Chu3UserAll.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/Chu3UserAll.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/MatchingWaitState.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/MatchingWaitState.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/MatchingWaitState.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/MatchingWaitState.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UpsertUserGacha.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UpsertUserGacha.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UpsertUserGacha.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UpsertUserGacha.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UserEmoney.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UserEmoney.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UserEmoney.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/request/UserEmoney.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3MatchingMember.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3MatchingMember.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3MatchingMember.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3MatchingMember.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3NetBattleLog.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3NetBattleLog.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3NetBattleLog.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3NetBattleLog.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserActivity.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserActivity.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserActivity.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserActivity.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserChallenge.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserChallenge.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserChallenge.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserChallenge.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt similarity index 99% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt index 31f15a11..dc5fe40b 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserData.kt @@ -14,7 +14,7 @@ import icu.samnyan.aqua.sega.chusan.model.request.UserEmoney import icu.samnyan.aqua.sega.general.model.Card import icu.samnyan.aqua.sega.util.AccessCodeSerializer import jakarta.persistence.* -import kotlinx.io.IOException +import java.io.IOException import java.time.LocalDateTime import java.time.format.DateTimeFormatter diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt similarity index 86% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt index a45722f1..27c3f49c 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserEntity.kt @@ -8,7 +8,7 @@ import jakarta.persistence.ManyToOne import jakarta.persistence.MappedSuperclass @MappedSuperclass -class Chu3UserEntity : BaseEntity(), IUserEntity { +open class Chu3UserEntity : BaseEntity(), IUserEntity { @JsonIgnore @ManyToOne @JoinColumn(name = "user_id") diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserItem.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserItem.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserItem.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserItem.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserLinkedVerse.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserLinkedVerse.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserLinkedVerse.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserLinkedVerse.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserMisc.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserMisc.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserMisc.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/Chu3UserMisc.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMission.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMission.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMission.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMission.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMissionProgress.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMissionProgress.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMissionProgress.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCMissionProgress.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCardPrintState.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCardPrintState.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCardPrintState.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCardPrintState.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharacter.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharacter.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharacter.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharacter.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharge.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharge.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharge.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCharge.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCourse.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCourse.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCourse.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserCourse.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserDuel.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserDuel.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserDuel.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserDuel.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGacha.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGacha.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGacha.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGacha.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGameOption.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGameOption.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGameOption.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGameOption.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGeneralData.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGeneralData.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGeneralData.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserGeneralData.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserLoginBonus.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserLoginBonus.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserLoginBonus.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserLoginBonus.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMap.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMap.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMap.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMap.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMusicDetail.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMusicDetail.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMusicDetail.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserMusicDetail.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserPlaylog.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserPlaylog.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserPlaylog.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserPlaylog.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaRequestModels.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaRequestModels.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaRequestModels.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaRequestModels.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaResponse.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaResponse.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaResponse.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/DivaResponse.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/Internalizable.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/Internalizable.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/Internalizable.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/Internalizable.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/Const.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/Const.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/Const.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/Const.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/ContestProgress.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/ContestProgress.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/ContestProgress.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/ContestProgress.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/LevelInfo.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/LevelInfo.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/LevelInfo.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/LevelInfo.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/SortMode.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/SortMode.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/SortMode.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/SortMode.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/ClearTally.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/ClearTally.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/ClearTally.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/ClearTally.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/FestaCollection.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/FestaCollection.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/FestaCollection.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/FestaCollection.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/PsRankingCollection.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/PsRankingCollection.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/PsRankingCollection.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/common/collection/PsRankingCollection.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt similarity index 66% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt index c258b86a..e0b978f0 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Contest.kt @@ -6,7 +6,6 @@ import icu.samnyan.aqua.sega.diva.model.common.ContestNormaType import icu.samnyan.aqua.sega.diva.util.DivaTime import icu.samnyan.aqua.sega.diva.util.URIEncoder import jakarta.persistence.* -import org.apache.commons.lang3.StringUtils import java.io.Serializable import java.time.LocalDateTime @@ -25,7 +24,7 @@ class Contest : Serializable { @Enumerated(EnumType.STRING) var league: ContestLeague = ContestLeague.BEGINNER var stars = 0 - var minComplexity = 0 // Only use when Pv difficulty list is not set. + var minComplexity = 0 var maxComplexity = 0 var stages = 0 var stageLimit: String = "" @@ -36,45 +35,36 @@ class Contest : Serializable { var sliverBorders = 0 var goldBorders = 0 - // Pv List format: "pv_id_start:pv_id_end,pv_id_start:pv_id_end,pv_id_start:pv_id_end" more than 20 group will be ignore, put in -1 for empty end var pvList: String = "" - - // Pv difficulty list format: "pv_difficulty:min_complexity:max_complexity" var pvDiffList: String = "" - // ContestReward format: - // Reward Type: (-1 None, 0 VP, 1 Skin, 2 Callsign, 3 Customize) - // Format: "rewardType:reward:string1:string2" string1 and 2 should be urlencoded and must exist. use *** aka %2A%2A%2A as placeholder var bronzeContestReward: String = "" var sliverContestReward: String = "" var goldContestReward: String = "" - - // ContestReward format: "rewardType:reward:string1:string2" var contestEntryReward: String = "" constructor() val string: String get() { - val list = mutableListOf( - this.id, // Contest ID - DivaTime.format(this.startTime), // Start time - DivaTime.format(this.endTime), // End time - URIEncoder.encode(this.name), // Contest name - URIEncoder.encode(this.description), // Contest description - this.league.value, // Contest league - this.stars, // Contest starts - this.stages, // Contest stage, 1~9 - this.stageLimit, // list_lump_num ( 0 will be all stage same. > 1 will became stage max defined chart ) + val list = mutableListOf( + this.id, + DivaTime.format(this.startTime), + DivaTime.format(this.endTime), + URIEncoder.encode(this.name), + URIEncoder.encode(this.description), + this.league.value, + this.stars, + this.stages, + this.stageLimit, this.normaType.value, this.bronzeBorders, this.sliverBorders, this.goldBorders ) for (i in 1..20) { - // format is "pv_range_start,pv_range_end,min_complexity,max_complexity,difficulty,unknown" if (pvList.isBlank() || !pvList.contains(":")) { - list += listOf(-1, -1) + list.addAll(listOf(-1, -1)) if (i == 1) { list.add(this.minComplexity) list.add(this.maxComplexity) @@ -82,16 +72,16 @@ class Contest : Serializable { list.add(-2) list.add(-2) } - list += listOf(-1, -2, "7fffffffffffffffffffffffffffffff") + list.addAll(listOf(-1, -2, "7fffffffffffffffffffffffffffffff")) } else { val groups = pvList.split(',').dropLastWhile { it.isEmpty() }.toTypedArray() if (groups.size < i) { - list += listOf(-1, -1, -2, -2, -1, -2, "7fffffffffffffffffffffffffffffff") + list.addAll(listOf(-1, -1, -2, -2, -1, -2, "7fffffffffffffffffffffffffffffff")) } else { val ids = groups[i - 1].split(':').dropLastWhile { it.isEmpty() }.toTypedArray() list.add(ids[0]) list.add(ids[1]) - if (StringUtils.isBlank(pvDiffList) || !pvDiffList.contains(":")) { + if (pvDiffList.isBlank() || !pvDiffList.contains(":")) { list.add(this.minComplexity) list.add(this.maxComplexity) list.add(-1) diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Difficulty.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Difficulty.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Difficulty.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Difficulty.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaCustomize.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaCustomize.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaCustomize.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaCustomize.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaModule.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaModule.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaModule.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/DivaModule.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Festa.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Festa.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Festa.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Festa.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Pv.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Pv.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Pv.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/Pv.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/PvEntry.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/PvEntry.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/PvEntry.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/gamedata/PvEntry.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/GameSession.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/GameSession.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/GameSession.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/GameSession.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayLog.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayLog.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayLog.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayLog.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerContest.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerContest.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerContest.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerContest.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerCustomize.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerCustomize.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerCustomize.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerCustomize.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerInventory.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerInventory.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerInventory.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerInventory.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerModule.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerModule.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerModule.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerModule.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerProfile.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerProfile.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerProfile.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerProfile.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvCustomize.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvCustomize.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvCustomize.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvCustomize.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvRecord.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvRecord.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvRecord.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerPvRecord.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerScreenShot.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerScreenShot.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerScreenShot.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/model/db/userdata/PlayerScreenShot.kt diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt new file mode 100644 index 00000000..6bdea64d --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/diva/util/DivaUtils.kt @@ -0,0 +1,35 @@ +package icu.samnyan.aqua.sega.diva.util + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +object DivaStringUtils { + @JvmStatic + fun getDummyString(content: String, length: Int) = ",".repeat(length).removeSuffix(",") +} + +object DivaTime { + val now get() = getString(LocalDateTime.now()) + + @JvmStatic + fun getString(time: LocalDateTime) = URIEncoder.encode(format(time)) + + @JvmStatic + fun format(time: LocalDateTime) = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time) +} + +class DivaDateTimeSerializer(t: Class? = null) : StdSerializer(t) { + override fun serialize(value: LocalDateTime, gen: JsonGenerator, provider: SerializerProvider) { + gen.writeString(DivaTime.getString(value)) + } +} + +object URIEncoder { + @JvmStatic + fun encode(str: String) = URLEncoder.encode(str, StandardCharsets.UTF_8).replace("\\+".toRegex(), "%20") +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/IntegerListConverter.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/IntegerListConverter.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/general/IntegerListConverter.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/general/IntegerListConverter.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/Card.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/Card.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/Card.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/Card.kt diff --git a/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt new file mode 100644 index 00000000..1a16e183 --- /dev/null +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/CardTimestamp.kt @@ -0,0 +1,22 @@ +package icu.samnyan.aqua.sega.general.model + +import icu.samnyan.aqua.net.games.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Table + +@Entity +@Table(name = "sega_card_timestamp") +class CardTimestamp : BaseEntity() { + @Column(name = "card_id") + var cardId: Long = 0 + + @Column(name = "game_id") + var gameId: String = "" + + @Column(name = "created_at") + var createdAt: Long = 0 + + @Column(name = "updated_at") + var updatedAt: Long = 0 +} diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/PropertyEntry.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/PropertyEntry.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/PropertyEntry.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/PropertyEntry.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/UserRecentRating.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/UserRecentRating.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/general/model/UserRecentRating.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/general/model/UserRecentRating.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRating.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRating.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRating.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRating.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRivalMusic.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRivalMusic.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRivalMusic.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/UserRivalMusic.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UserPhoto.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UserPhoto.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UserPhoto.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UserPhoto.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiEnums.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiEnums.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiEnums.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiEnums.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiGameEntities.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiGameEntities.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiGameEntities.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiGameEntities.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertCM.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertCM.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertCM.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertCM.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertUserAll.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertUserAll.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertUserAll.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUpsertUserAll.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt similarity index 99% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt index 47aa146d..354e2b0b 100644 --- a/planet/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt +++ b/shared/src/main/kotlin/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt @@ -11,7 +11,7 @@ import java.time.LocalDate import java.time.LocalDateTime @MappedSuperclass -class OngekiUserEntity : BaseEntity(), IUserEntity { +open class OngekiUserEntity : BaseEntity(), IUserEntity { @JsonIgnore @ManyToOne @JoinColumn(name = "user_id") diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/util/Serializers.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/util/Serializers.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/util/Serializers.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/util/Serializers.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/Constants.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/Constants.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/Constants.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/Constants.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/ApiModels.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/ApiModels.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/ApiModels.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/ApiModels.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt diff --git a/planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt b/shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt similarity index 100% rename from planet/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt rename to shared/src/main/kotlin/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt