AI Implementation feature(903): Admin Area Challenges: List, Import/Export and Add/Edit Modal 1.03 (#44)
This commit was merged in pull request #44.
This commit is contained in:
@@ -446,24 +446,29 @@ export class AdminChallengesService {
|
||||
}
|
||||
|
||||
const result: ImportResult = { imported: 0, skipped: [], warnings: [] };
|
||||
let orphanedStoredFilenames: string[] = [];
|
||||
try {
|
||||
await this.dataSource.transaction(async (manager) => {
|
||||
const challengeRepo = manager.getRepository(ChallengeEntity);
|
||||
const fileRepo = manager.getRepository(ChallengeFileEntity);
|
||||
|
||||
// Full-replace: capture every existing challenge and its disk-bound
|
||||
// files so we can unlink them after the wipe, then delete every row.
|
||||
// ChallengeFileEntity and SolveEntity both cascade on challenge delete.
|
||||
const existingChallenges = await challengeRepo.find();
|
||||
const existingIds = existingChallenges.map((c) => c.id);
|
||||
if (existingIds.length > 0) {
|
||||
const existingFiles = await fileRepo.find({ where: { challengeId: In(existingIds) } });
|
||||
orphanedStoredFilenames = existingFiles.map((f) => f.storedFilename);
|
||||
await manager.delete(ChallengeEntity, { id: In(existingIds) });
|
||||
}
|
||||
|
||||
for (const ch of doc.challenges) {
|
||||
const cat = catMap.get(ch.categorySystemKey.toLowerCase());
|
||||
if (!cat) {
|
||||
result.skipped.push({ name: ch.name, reason: `Unknown category: ${ch.categorySystemKey}` });
|
||||
continue;
|
||||
}
|
||||
// Upsert by case-insensitive name.
|
||||
const existing = await challengeRepo
|
||||
.createQueryBuilder('c')
|
||||
.where('LOWER(c.name) = :n', { n: ch.name.toLowerCase() })
|
||||
.getOne();
|
||||
if (existing) {
|
||||
await manager.delete(ChallengeEntity, { id: existing.id });
|
||||
}
|
||||
const row = challengeRepo.create({
|
||||
id: uuid(),
|
||||
name: ch.name,
|
||||
@@ -501,6 +506,11 @@ export class AdminChallengesService {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Best-effort unlink of files owned by wiped challenges (post-commit).
|
||||
for (const storedFilename of orphanedStoredFilenames) {
|
||||
this.fileService.removeFinal(storedFilename);
|
||||
}
|
||||
|
||||
// Commit each staged file by renaming to its final filename (the
|
||||
// ChallengeFile rows already reference those names).
|
||||
for (const list of stagedByName.values()) {
|
||||
|
||||
Reference in New Issue
Block a user