fix(reputation): validate the character exists before granting reputation

This commit is contained in:
Bastian Wagner
2026-08-21 09:30:04 +02:00
parent 79d4e04172
commit 321738496d
2 changed files with 62 additions and 2 deletions

View File

@@ -1,8 +1,9 @@
import { Injectable } from '@nestjs/common';
import { DataSource, EntityManager } from 'typeorm';
import { Character } from '../characters/entities/character.entity';
import { CharacterReputation } from './entities/character-reputation.entity';
import { ReputationFaction } from './entities/reputation-faction.entity';
import { reputationFactionNotFound } from './reputation.errors';
import { characterNotFound, reputationFactionNotFound } from './reputation.errors';
import { resolveReputationRank } from './reputation-rank';
export interface ReputationGrantResult {
@@ -37,9 +38,24 @@ export class ReputationService {
manager?: EntityManager,
): Promise<ReputationGrantResult> {
const run = async (txManager: EntityManager): Promise<ReputationGrantResult> => {
const characters = txManager.getRepository(Character);
const factions = txManager.getRepository(ReputationFaction);
const reputations = txManager.getRepository(CharacterReputation);
// When TurnInService (Task 6) passes its own `manager`, it will already
// hold a pessimistic write lock on this same character row from earlier
// in that transaction. Re-locking it here is a no-op re-lock in
// Postgres, not a deadlock risk -- CombatService.performAction relies on
// the same behavior for grantVictoryRewards. Do not remove this check
// to "avoid" the re-lock.
const character = await characters.findOne({
where: { id: characterId },
lock: { mode: 'pessimistic_write' },
});
if (!character) {
throw characterNotFound();
}
const faction = await factions.findOneBy({ key: factionKey });
if (!faction) {
throw reputationFactionNotFound();