feat: implement activity logging for user actions and create activities table
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 44s

This commit is contained in:
Kaimbacher 2026-06-24 15:03:17 +02:00
commit 7e2f320b4f
12 changed files with 420 additions and 160 deletions

View file

@ -40,6 +40,8 @@ import type { Multipart } from '@adonisjs/bodyparser';
import * as fs from 'fs';
import { parseBytesSize, getConfigFor, getTmpPath, formatBytes, errorMessage } from '#app/utils/utility-functions';
import validation from '#services/validation_service';
import ActivityLogger from '#services/activity_logger';
import logger from '@adonisjs/core/services/logger';
interface Dictionary {
[index: string]: string;
@ -469,9 +471,7 @@ export default class DatasetController {
console.error('Error cleaning up temporary file:', cleanupError);
}
});
request.multipart.abort(
validation.make('files', `Upload limit of ${formatBytes(aggregatedLimit)} exceeded.`, 'limit')
);
request.multipart.abort(validation.make('files', `Upload limit of ${formatBytes(aggregatedLimit)} exceeded.`, 'limit'));
}
});
@ -513,10 +513,21 @@ export default class DatasetController {
trx = await db.transaction();
const user = (await User.find(auth.user?.id)) as User;
await this.createDatasetAndAssociations(user, request, trx);
// await this.createDatasetAndAssociations(user, request, trx);
const { dataset, mainTitle } = await this.createDatasetAndAssociations(user, request, trx);
await trx.commit();
console.log('Dataset and related models created successfully');
// NACH dem Commit: Dataset ist garantiert persistiert, keine Waisen-Gefahr.
// Fire-and-forget, damit ein Log-Fehler den bereits erfolgreichen Upload nicht kippt.
void ActivityLogger.log({
type: 'dataset.uploaded',
description: `New publication uploaded: ${mainTitle ?? 'Untitled'}`,
userId: user.id,
subjectType: 'Dataset',
subjectId: dataset.id,
}).catch((err) => logger.error({ err }, 'failed to record dataset.uploaded activity'));
} catch (error) {
// Clean up temporary files if validation or later steps fail
uploadedTmpFiles.forEach((tmpPath) => {
@ -564,6 +575,15 @@ export default class DatasetController {
await this.savePersons(dataset, request.input('contributors', []), 'contributor', trx);
//save main and additional titles
// const titles = request.input('titles', []);
// for (const titleData of titles) {
// const title = new Title();
// title.value = titleData.value;
// title.language = titleData.language;
// title.type = titleData.type;
// await dataset.useTransaction(trx).related('titles').save(title);
// }
let mainTitle: string | null = null;
const titles = request.input('titles', []);
for (const titleData of titles) {
const title = new Title();
@ -571,6 +591,11 @@ export default class DatasetController {
title.language = titleData.language;
title.type = titleData.type;
await dataset.useTransaction(trx).related('titles').save(title);
if (titleData.type === 'Main') {
// <-- an eure Typ-Konvention anpassen
mainTitle = titleData.value;
}
}
// save descriptions
@ -664,6 +689,8 @@ export default class DatasetController {
await dataset.useTransaction(trx).related('files').save(newFile);
await newFile.createHashValues(trx);
}
return { dataset, mainTitle }; // <-- statt void
}
private generateRandomString(length: number): string {
@ -1095,7 +1122,7 @@ export default class DatasetController {
}
});
const error = new errors.E_VALIDATION_ERROR({
'files': `Aggregated upload limit of ${formatBytes(aggregatedLimit)} exceeded. The total size of files being uploaded would exceed the limit.`,
files: `Aggregated upload limit of ${formatBytes(aggregatedLimit)} exceeded. The total size of files being uploaded would exceed the limit.`,
});
request.multipart.abort(error);
}