fix(AdminService, AdminController): enhance error handling and character deletion logic
All checks were successful
Deploy to production / deploy (push) Successful in 1m44s

- Updated error handling in AdminController to include 'targetnotdead' status for improved response accuracy.
- Modified character deletion logic in AdminService to ensure correct target character is identified, especially when dealing with living characters, enhancing data integrity during cleanup operations.
- Adjusted attributes fetched for characters to include 'health', facilitating better decision-making in deletion processes.
This commit is contained in:
Torsten Schulz (local)
2026-04-20 16:27:08 +02:00
parent 7417736daf
commit 27d42c0a3a
2 changed files with 60 additions and 24 deletions

View File

@@ -518,7 +518,7 @@ class AdminController {
console.log(error);
const status = error.message === 'noaccess'
? 403
: (['invalidCharacter', 'notfound'].includes(error.message) ? 400 : 500);
: (['invalidCharacter', 'notfound', 'targetnotdead'].includes(error.message) ? 400 : 500);
res.status(status).json({ error: error.message });
}
}

View File

@@ -1186,14 +1186,50 @@ class AdminService {
}
const character = await FalukantCharacter.findByPk(parsedCharacterId, {
attributes: ['id', 'userId']
attributes: ['id', 'userId', 'health']
});
if (!character) {
throw new Error('notfound');
}
let targetCharacterId = parsedCharacterId;
let targetCharacter = character;
// Schutz gegen versehentliches Löschen des lebenden Erben:
// Wenn ein lebender Charakter gewählt wurde, versuchen wir den eindeutig
// verstorbenen Eltern-Charakter als Cleanup-Ziel zu ermitteln.
if (Number(character.health) > 0) {
const deadParents = await sequelize.query(
`
SELECT DISTINCT c.id
FROM falukant_data.child_relation cr
JOIN falukant_data.character c
ON c.id = cr.mother_character_id
OR c.id = cr.father_character_id
WHERE cr.child_character_id = :childCharacterId
AND c.health <= 0
ORDER BY c.id ASC
`,
{
replacements: { childCharacterId: parsedCharacterId },
type: QueryTypes.SELECT
}
);
if (deadParents.length !== 1) {
throw new Error('targetnotdead');
}
targetCharacterId = Number(deadParents[0].id);
targetCharacter = await FalukantCharacter.findByPk(targetCharacterId, {
attributes: ['id', 'userId', 'health']
});
if (!targetCharacter) {
throw new Error('notfound');
}
}
const summary = {
characterId: parsedCharacterId,
requestedCharacterId: parsedCharacterId,
characterId: targetCharacterId,
knowledgeDeleted: 0,
debtorsPrismDeleted: 0,
politicalOfficeArchived: 0,
@@ -1223,15 +1259,15 @@ class AdminService {
};
summary.knowledgeDeleted = await Knowledge.destroy({
where: { characterId: parsedCharacterId },
where: { characterId: targetCharacterId },
transaction: t
});
summary.debtorsPrismDeleted = await DebtorsPrism.destroy({
where: { characterId: parsedCharacterId },
where: { characterId: targetCharacterId },
transaction: t
});
summary.electionCandidateDeleted = await Candidate.destroy({
where: { characterId: parsedCharacterId },
where: { characterId: targetCharacterId },
transaction: t
});
@@ -1257,14 +1293,14 @@ class AdminService {
RETURNING id
`,
{
replacements: { characterId: parsedCharacterId },
replacements: { characterId: targetCharacterId },
type: QueryTypes.SELECT,
transaction: t
}
);
summary.politicalOfficeArchived = archivedRows.length;
summary.politicalOfficeDeleted = await PoliticalOffice.destroy({
where: { characterId: parsedCharacterId },
where: { characterId: targetCharacterId },
transaction: t
});
@@ -1274,7 +1310,7 @@ class AdminService {
DELETE FROM falukant_data.occupied_political_office
WHERE character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.political_benefit_last_tick',
@@ -1282,7 +1318,7 @@ class AdminService {
DELETE FROM falukant_data.political_benefit_last_tick
WHERE character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.falukant_character_trait',
@@ -1290,7 +1326,7 @@ class AdminService {
DELETE FROM falukant_data.falukant_character_trait
WHERE character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.church_application',
@@ -1299,7 +1335,7 @@ class AdminService {
WHERE character_id = :characterId
OR supervisor_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.church_office',
@@ -1308,7 +1344,7 @@ class AdminService {
WHERE character_id = :characterId
OR supervisor_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.political_appointment',
@@ -1317,7 +1353,7 @@ class AdminService {
WHERE appointer_character_id = :characterId
OR target_character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.marriage_proposals',
@@ -1326,7 +1362,7 @@ class AdminService {
WHERE requester_character_id = :characterId
OR proposed_character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.child_relation',
@@ -1336,7 +1372,7 @@ class AdminService {
OR mother_character_id = :characterId
OR child_character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.relationship_state',
@@ -1348,7 +1384,7 @@ class AdminService {
OR character2_id = :characterId
)
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.relationship',
@@ -1357,7 +1393,7 @@ class AdminService {
WHERE character1_id = :characterId
OR character2_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_data.region_tax_history',
@@ -1365,7 +1401,7 @@ class AdminService {
DELETE FROM falukant_data.region_tax_history
WHERE setter_character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_log.health_activity',
@@ -1373,7 +1409,7 @@ class AdminService {
DELETE FROM falukant_log.health_activity
WHERE character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
await deleteIfTableExists(
'falukant_log.political_office_history',
@@ -1381,18 +1417,18 @@ class AdminService {
DELETE FROM falukant_log.political_office_history
WHERE character_id = :characterId
`,
{ characterId: parsedCharacterId }
{ characterId: targetCharacterId }
);
const deletedCharacters = await FalukantCharacter.destroy({
where: { id: parsedCharacterId },
where: { id: targetCharacterId },
transaction: t
});
summary.characterDeleted = deletedCharacters > 0;
});
if (character.userId) {
const falukantUser = await FalukantUser.findByPk(character.userId, {
if (targetCharacter.userId) {
const falukantUser = await FalukantUser.findByPk(targetCharacter.userId, {
include: [{ model: User, as: 'user', attributes: ['hashedId'] }]
});
const hashedId = falukantUser?.user?.hashedId;