fix: [chu3] import functional, improve error response for importing

This commit is contained in:
Raymond
2026-05-15 23:47:09 -04:00
parent 4895456bb0
commit 2e55247de0
2 changed files with 46 additions and 42 deletions
@@ -107,52 +107,57 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@API("import") @API("import")
fun importUserData(@RP token: Str, @RB json: Str) = us.jwt.auth(token) { u -> fun importUserData(@RP token: Str, @RB json: Str) = us.jwt.auth(token) { u ->
val export = json.parseJackson(exportClass.java) try {
if (!export.gameId.equals(game, true)) 400 - "Invalid game ID" val export = json.parseJackson(exportClass.java)
if (!export.gameId.equals(game, true)) 400 - "Invalid game ID"
val lists = listRepos.toList().associate { (f, r) -> r to f.get(export) as List<IUserEntity<UserModel>> }.vNotNull() val lists = listRepos.toList().associate { (f, r) -> r to f.get(export) as List<IUserEntity<UserModel>> }.vNotNull()
val singles = singleRepos.toList().associate { (f, r) -> r to f.get(export) as IUserEntity<UserModel> }.vNotNull() val singles = singleRepos.toList().associate { (f, r) -> r to f.get(export) as IUserEntity<UserModel> }.vNotNull()
var repoFieldMap = exportRepos.toList().associate { (f, r) -> r to f } var repoFieldMap = exportRepos.toList().associate { (f, r) -> r to f }
// Validate new user data // Validate new user data
// Check that all ids are 0 (this should be true since all ids are @JsonIgnore) // Check that all ids are 0 (this should be true since all ids are @JsonIgnore)
if (export.userData.id != 0L) 400 - "User ID must be 0" if (export.userData.id != 0L) 400 - "User ID must be 0"
lists.values.flatten().forEach { if (it.id != 0L) 400 - "ID must be 0" } lists.values.flatten().forEach { if (it.id != 0L) 400 - "ID must be 0" }
singles.values.forEach { if (it.id != 0L) 400 - "ID must be 0" } singles.values.forEach { if (it.id != 0L) 400 - "ID must be 0" }
// Set user card // Set user card
export.userData.card = u.ghostCard export.userData.card = u.ghostCard
// Check existing data // Check existing data
userDataRepo.findByCard(u.ghostCard)?.also { gu -> userDataRepo.findByCard(u.ghostCard)?.also { gu ->
// Store a backup of the old data // Store a backup of the old data
val fl = "${game}-backup-${u.auId}-${LocalDateTime.now().urlSafeStr()}.json" val fl = "${game}-backup-${u.auId}-${LocalDateTime.now().urlSafeStr()}.json"
(Path(netProps.importBackupPath) / fl).writeText(export(u).toJson()) (Path(netProps.importBackupPath) / fl).writeText(export(u).toJson())
// Delete the old data (After migration v1000.7, all user-linked entities have ON DELETE CASCADE) // Delete the old data (After migration v1000.7, all user-linked entities have ON DELETE CASCADE)
log.info("$game Import: Deleting old data for user ${u.auId}") log.info("$game Import: Deleting old data for user ${u.auId}")
userDataRepo.delete(gu) userDataRepo.delete(gu)
userDataRepo.flush() userDataRepo.flush()
}
trans.execute {
// Insert new data
val nu = userDataRepo.save(export.userData)
// Set user fields
lists.values.flatten().forEach { it.user = nu }
singles.values.forEach { it.user = nu }
// Save new data
singles.forEach { (repo, single) -> (repo as IUserRepo<UserModel, Any>).save(single) }
lists.forEach { (repo, list) -> (repo as IUserRepo<UserModel, Any>).saveAll(list) }
// Handle custom importers
customImporters.forEach { (field, importer) ->
importer(export, nu)
} }
trans.execute {
// Insert new data
val nu = userDataRepo.save(export.userData)
// Set user fields
lists.values.flatten().forEach { it.user = nu }
singles.values.forEach { it.user = nu }
// Save new data
singles.forEach { (repo, single) -> (repo as IUserRepo<UserModel, Any>).save(single) }
lists.forEach { (repo, list) -> (repo as IUserRepo<UserModel, Any>).saveAll(list) }
// Handle custom importers
customImporters.forEach { (field, importer) ->
importer(export, nu)
}
}
cardService.updateCardTimestamp(u.ghostCard, gameName, resetCreatedAt = true)
SUCCESS
} catch(e: Exception) {
log.error(e.message, e)
500 - "Failed to import user data. More information can be found in the server logs (or contact an administrator for help if you do not have access)."
} }
cardService.updateCardTimestamp(u.ghostCard, gameName, resetCreatedAt = true)
SUCCESS
} }
/** /**
@@ -23,10 +23,9 @@ class FlexibleDateTimeDeserializer : JsonDeserializer<LocalDateTime?>() {
public override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): LocalDateTime { public override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): LocalDateTime {
return LocalDateTime.parse(p.getText(), FORMATTER) return LocalDateTime.parse(p.getText(), FORMATTER)
} }
companion object { companion object {
// Card Maker needs the date ending with ".0" and chunithm sends the dates without it so we need a flexible parser // Chusan imports previous would fail because the pattern was too strict. Now the incorrect pattern should at least get accepted correctly
private val FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.S]") private val FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd[' ']['T']HH:mm:ss[.S][.SS][.SSS]")
} }
} }