[O] More cascade

This commit is contained in:
Azalea
2026-08-02 00:05:29 +00:00
parent 36eea3c23f
commit fc2ebe2f19
10 changed files with 74 additions and 43 deletions

View File

@@ -4,17 +4,14 @@ import ext.*
import icu.samnyan.aqua.net.components.*
import icu.samnyan.aqua.net.db.AquaNetUser
import icu.samnyan.aqua.net.db.AquaNetUserRepo
import icu.samnyan.aqua.net.db.AquaGameOptionsRepo
import icu.samnyan.aqua.net.db.AquaUserServices
import icu.samnyan.aqua.net.db.EmailConfirmationRepo
import icu.samnyan.aqua.net.db.ResetPasswordRepo
import icu.samnyan.aqua.net.db.SessionTokenRepo
import icu.samnyan.aqua.net.utils.AquaNetProps
import icu.samnyan.aqua.net.utils.PathProps
import icu.samnyan.aqua.net.utils.SUCCESS
import icu.samnyan.aqua.sega.allnet.UserKeychip
import icu.samnyan.aqua.sega.allnet.UserKeychipRepo
import icu.samnyan.aqua.sega.allnet.KeychipSessionRepo
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
import icu.samnyan.aqua.sega.diva.DivaRepos
import icu.samnyan.aqua.sega.diva.model.db.userdata.PlayerProfile
@@ -376,12 +373,6 @@ data class AccountFileCleanup(
class AccountDeletionService(
val userRepo: AquaNetUserRepo,
val cardRepo: CardRepository,
val gameOptionsRepo: AquaGameOptionsRepo,
val sessionRepo: SessionTokenRepo,
val confirmationRepo: EmailConfirmationRepo,
val resetPasswordRepo: ResetPasswordRepo,
val userKeychipRepo: UserKeychipRepo,
val keychipSessionRepo: KeychipSessionRepo,
val mai2: Mai2Repos,
val chu3: Chu3Repos,
val ongeki: OngekiUserRepos,
@@ -405,28 +396,10 @@ class AccountDeletionService(
wacca.user.findByCard(ghostCard)?.let { wacca.user.delete(it) }
chu3.userLoginBonus.deleteAll(chu3.userLoginBonus.findByUser(ghostCard.extId.toInt()))
sessionRepo.deleteAll(sessionRepo.findByAquaNetUserAuId(auId))
confirmationRepo.deleteAll(confirmationRepo.findByAquaNetUserAuId(auId))
resetPasswordRepo.deleteAll(resetPasswordRepo.findByAquaNetUserAuId(auId))
userKeychipRepo.deleteAll(userKeychipRepo.findAllByUserAuId(auId))
keychipSessionRepo.deleteAll(keychipSessionRepo.findAllByUserAuId(auId))
val linkedCards = (cardRepo.findAllByAquaUserAuId(auId) + ghostCard).distinctBy { it.id }
linkedCards.forEach { it.aquaUser = null }
cardRepo.saveAll(linkedCards)
cardRepo.flush()
user.cards.clear()
user.keychips.clear()
user.keychipSessions.clear()
val gameOptions = user.gameOptions
user.gameOptions = null
userRepo.delete(user)
userRepo.flush()
cardRepo.delete(ghostCard)
cardRepo.flush()
gameOptions?.let { gameOptionsRepo.delete(it) }
log.info("Deleted account and game data for user $auId")
return AccountFileCleanup(user.profilePicture, ghostCard.extId, divaScreenshots)

View File

@@ -1,7 +1,9 @@
package icu.samnyan.aqua.net.db
import jakarta.persistence.*
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaRepository
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.time.Instant
@@ -20,9 +22,10 @@ class EmailConfirmation(
@Column(nullable = false)
var createdAt: Instant = Instant.now(),
// Linking to the AquaNetUser
@ManyToOne
@JoinColumn(name = "auId", referencedColumnName = "auId")
// Linking to the AquaNetUser
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "auId", referencedColumnName = "auId")
var aquaNetUser: AquaNetUser = AquaNetUser()
) : Serializable
@@ -30,4 +33,4 @@ class EmailConfirmation(
interface EmailConfirmationRepo : JpaRepository<EmailConfirmation, Long> {
fun findByToken(token: String): EmailConfirmation?
fun findByAquaNetUserAuId(auId: Long): List<EmailConfirmation>
}
}

View File

@@ -2,6 +2,8 @@ package icu.samnyan.aqua.net.db
import jakarta.persistence.*
import org.springframework.data.jpa.repository.JpaRepository
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.time.Instant
@@ -22,6 +24,7 @@ class ResetPassword(
// Linking to the AquaNetUser
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "auId", referencedColumnName = "auId")
var aquaNetUser: AquaNetUser = AquaNetUser()
) : Serializable
@@ -30,4 +33,4 @@ class ResetPassword(
interface ResetPasswordRepo : JpaRepository<ResetPassword, Long> {
fun findByToken(token: String): ResetPassword?
fun findByAquaNetUserAuId(auId: Long): List<ResetPassword>
}
}

View File

@@ -2,6 +2,8 @@ package icu.samnyan.aqua.net.db
import jakarta.persistence.*
import org.springframework.data.jpa.repository.JpaRepository
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.time.Instant
@@ -22,6 +24,7 @@ class SessionToken(
// Linking to the AquaNetUser
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "auId", referencedColumnName = "auId")
var aquaNetUser: AquaNetUser = AquaNetUser()
) : Serializable

View File

@@ -79,13 +79,13 @@ class AquaNetUser(
// Each user can have multiple keychips (if the user owns cabinets)
@JsonIgnore
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL])
var keychips: MutableList<UserKeychip> = mutableListOf(),
@OneToMany(mappedBy = "user", cascade = [CascadeType.PERSIST, CascadeType.MERGE])
var keychips: MutableList<UserKeychip> = mutableListOf(),
// Each user's keychip can have multiple sessions
@JsonIgnore
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL])
var keychipSessions: MutableList<KeychipSession> = mutableListOf(),
@OneToMany(mappedBy = "user", cascade = [CascadeType.PERSIST, CascadeType.MERGE])
var keychipSessions: MutableList<KeychipSession> = mutableListOf(),
@Column(nullable = false)
var canModifyKeychips: Boolean = false,

View File

@@ -5,7 +5,9 @@ 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.data.jpa.repository.JpaRepository
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
@@ -18,9 +20,10 @@ import java.security.SecureRandom
@Table(name = "allnet_keychip_sessions", indexes = [
Index(name = "idx_last_use", columnList = "lastUse")
])
class KeychipSession(
@ManyToOne
@JoinColumn(name = "au_id")
class KeychipSession(
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "au_id")
var user: AquaNetUser? = null,
@Column(length = 4)
@@ -47,7 +50,6 @@ fun genUrlSafeToken(length: Int): String {
@Repository("KeychipSessionRepo")
interface KeychipSessionRepo : JpaRepository<KeychipSession, String> {
fun findByToken(token: String): KeychipSession?
fun findAllByUserAuId(auId: Long): List<KeychipSession>
@Transactional
fun deleteAllByLastUseBefore(expire: Long)

View File

@@ -4,6 +4,8 @@ import icu.samnyan.aqua.net.db.AquaNetUser
import jakarta.persistence.*
import jakarta.transaction.Transactional
import org.springframework.data.jpa.repository.JpaRepository
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import org.springframework.stereotype.Repository
@Entity
@@ -13,6 +15,7 @@ class UserKeychip(
val id: Long = 0,
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "au_id", nullable = false)
var user: AquaNetUser,

View File

@@ -11,5 +11,4 @@ import org.springframework.stereotype.Repository
interface CardRepository : JpaRepository<Card, Long> {
fun findByExtId(extId: Long): Card?
fun findByLuid(luid: String): Card?
fun findAllByAquaUserAuId(auId: Long): List<Card>
}

View File

@@ -3,6 +3,8 @@ package icu.samnyan.aqua.sega.general.model
import com.fasterxml.jackson.annotation.JsonIgnore
import icu.samnyan.aqua.net.db.AquaNetUser
import jakarta.persistence.*
import org.hibernate.annotations.OnDelete
import org.hibernate.annotations.OnDeleteAction
import java.time.LocalDateTime
enum class CardStatus {
@@ -59,6 +61,7 @@ class Card(
// Defines the AquaNet user that this card is bound to
@ManyToOne
@OnDelete(action = OnDeleteAction.SET_NULL)
@JoinColumn(name = "net_user_id")
@JsonIgnore
var aquaUser: AquaNetUser? = null,

View File

@@ -0,0 +1,42 @@
-- Account-owned rows disappear with the account. Physical cards are only unlinked.
ALTER TABLE aqua_net_session
DROP FOREIGN KEY IF EXISTS FK_SESSION;
ALTER TABLE aqua_net_session
ADD CONSTRAINT FK_SESSION
FOREIGN KEY (au_id) REFERENCES aqua_net_user (au_id)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE aqua_net_email_confirmation
DROP FOREIGN KEY IF EXISTS FK_EMAIL_CONFIRMATION_ON_AQUA_USER;
ALTER TABLE aqua_net_email_confirmation
ADD CONSTRAINT FK_EMAIL_CONFIRMATION_ON_AQUA_USER
FOREIGN KEY (au_id) REFERENCES aqua_net_user (au_id)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE aqua_net_email_reset_password
DROP FOREIGN KEY IF EXISTS FK_EMAIL_RESET_PASSWORD_ON_AQUA_USER;
ALTER TABLE aqua_net_email_reset_password
ADD CONSTRAINT FK_EMAIL_RESET_PASSWORD_ON_AQUA_USER
FOREIGN KEY (au_id) REFERENCES aqua_net_user (au_id)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE allnet_keychip_sessions
DROP FOREIGN KEY IF EXISTS FK_ALLNET_KEYCHIP_SESSIONS_ON_AU;
ALTER TABLE allnet_keychip_sessions
ADD CONSTRAINT FK_ALLNET_KEYCHIP_SESSIONS_ON_AU
FOREIGN KEY (au_id) REFERENCES aqua_net_user (au_id)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE user_keychip
DROP FOREIGN KEY IF EXISTS fk_user_keychip_on_au;
ALTER TABLE user_keychip
ADD CONSTRAINT fk_user_keychip_on_au
FOREIGN KEY (au_id) REFERENCES aqua_net_user (au_id)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE sega_card
DROP FOREIGN KEY IF EXISTS FK_SEGA_CARD_ON_NET_USER;
ALTER TABLE sega_card
ADD CONSTRAINT FK_SEGA_CARD_ON_NET_USER
FOREIGN KEY (net_user_id) REFERENCES aqua_net_user (au_id)
ON DELETE SET NULL ON UPDATE CASCADE;