From 1cac5e451ae92b83b41cefc44f5aa89cfb8b2766 Mon Sep 17 00:00:00 2001 From: Menci Date: Tue, 7 Oct 2025 03:32:52 +0800 Subject: [PATCH] refactor: user registrar (#182) --- .../icu/samnyan/aqua/net/UserRegistrar.kt | 41 ++--------------- .../icu/samnyan/aqua/net/db/AquaNetUser.kt | 46 ++++++++++++++++++- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt b/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt index bf9aed47..0570496e 100644 --- a/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt +++ b/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt @@ -34,7 +34,6 @@ class UserRegistrar( val cardService: CardService, val validator: AquaUserServices, val emailProps: EmailProperties, - val sessionRepo: SessionTokenRepo, final val paths: PathProps ) { val portraitPath = paths.aquaNetPortrait.path() @@ -68,29 +67,7 @@ class UserRegistrar( val country = geoIP.getCountry(ip) // Create user - val u = async { AquaNetUser( - username = validator.checkUsername(username), - email = validator.checkEmail(email), - pwHash = validator.checkPwHash(password), - regTime = millis(), lastLogin = millis(), country = country, - ) } - - // 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 - async { - userRepo.save(u) - cardRepo.save(card) - } + val u = async { validator.create(username, email, password, country) } // Send confirmation email emailService.sendConfirmation(u) @@ -205,11 +182,6 @@ class UserRegistrar( // Remove the token from the list resetPasswordRepo.delete(reset) - // Clear all sessions - sessionRepo.deleteAll( - sessionRepo.findByAquaNetUserAuId(reset.aquaNetUser.auId) - ) - return SUCCESS } @@ -245,21 +217,14 @@ class UserRegistrar( @API("/setting") @Doc("Validate and set a user setting field.", "Success message") suspend fun setting(@RP token: Str, @RP key: Str, @RP value: Str) = jwt.auth(token) { u -> - // Check if the key is a settable field - val field = SETTING_FIELDS.find { it.name == key } ?: (400 - "Invalid setting") - async { - // Set the validated field - field.setter.call(u, field.checker.call(validator, value)) + validator.update(u, key, value) // Save the user userRepo.save(u) // Clear all tokens if changing password - if (key == "pwHash") - sessionRepo.deleteAll( - sessionRepo.findByAquaNetUserAuId(u.auId) - ) + if (key == "pwHash") validator.clearAllSessions(u) } SUCCESS diff --git a/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt b/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt index 8651f41a..49727b0c 100644 --- a/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt +++ b/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt @@ -2,6 +2,8 @@ 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 @@ -9,11 +11,13 @@ 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 @@ -124,7 +128,9 @@ class AquaUserServices( val allNetProps: AllNetProps, val jwt: JWT, val em: EntityManager, - val pop: GameMusicPopularity + val pop: GameMusicPopularity, + val cardService: CardService, + val sessionRepo: SessionTokenRepo, ) { companion object { val SETTING_FIELDS = AquaUserServices::class.functions @@ -136,6 +142,42 @@ class AquaUserServices( } } + fun create(username: Str, email: Str, password: Str, country: Str): AquaNetUser { + // Create user + val u = AquaNetUser( + username = checkUsername(username), + email = validateEmail(email), + pwHash = checkPwHash(password), + regTime = millis(), lastLogin = millis(), country = country, + ) + + // 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") @@ -173,7 +215,7 @@ class AquaUserServices( 400 - "User with username `$this` already exists" } - fun checkEmail(email: Str) = email.apply { + fun validateEmail(email: Str) = email.apply { // Check if email is valid if (!isValidEmail()) 400 - "Invalid email"