fix(server): remove the asset row when an upload fails after creating it (#30349)

This commit is contained in:
Santo Shakil 2026-08-03 18:59:05 +06:00 committed by GitHub
parent 0894865352
commit cee08a2320
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 14 additions and 2 deletions

View file

@ -317,6 +317,12 @@ describe(AssetMediaService.name, () => {
).rejects.toBeInstanceOf(BadRequestException); ).rejects.toBeInstanceOf(BadRequestException);
expect(mocks.asset.create).not.toHaveBeenCalled(); expect(mocks.asset.create).not.toHaveBeenCalled();
expect(mocks.asset.remove).not.toHaveBeenCalled();
expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.FileDelete,
data: { files: [file.originalPath, undefined] },
});
expect(mocks.event.emit).not.toHaveBeenCalled();
expect(mocks.user.updateUsage).not.toHaveBeenCalledWith(authStub.user1.user.id, file.size); expect(mocks.user.updateUsage).not.toHaveBeenCalledWith(authStub.user1.user.id, file.size);
expect(mocks.storage.utimes).not.toHaveBeenCalledWith( expect(mocks.storage.utimes).not.toHaveBeenCalledWith(
file.originalPath, file.originalPath,

View file

@ -1,7 +1,7 @@
import { BadRequestException, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { BadRequestException, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
import sanitize from 'sanitize-filename'; import sanitize from 'sanitize-filename';
import { StorageCore } from 'src/cores/storage.core'; import { StorageCore } from 'src/cores/storage.core';
import { AuthSharedLink } from 'src/database'; import { Asset, AuthSharedLink } from 'src/database';
import { import {
AssetBulkUploadCheckResponseDto, AssetBulkUploadCheckResponseDto,
AssetMediaResponseDto, AssetMediaResponseDto,
@ -128,6 +128,7 @@ export class AssetMediaService extends BaseService {
file: UploadFile, file: UploadFile,
sidecarFile?: UploadFile, sidecarFile?: UploadFile,
): Promise<AssetMediaResponseDto> { ): Promise<AssetMediaResponseDto> {
let asset: Asset | undefined;
try { try {
await this.requireAccess({ await this.requireAccess({
auth, auth,
@ -145,7 +146,7 @@ export class AssetMediaService extends BaseService {
); );
} }
const asset = await this.assetRepository.create({ asset = await this.assetRepository.create({
ownerId: auth.user.id, ownerId: auth.user.id,
libraryId: null, libraryId: null,
@ -215,6 +216,11 @@ export class AssetMediaService extends BaseService {
return { status: AssetMediaStatus.DUPLICATE, id: duplicateId }; return { status: AssetMediaStatus.DUPLICATE, id: duplicateId };
} }
// clean up the asset row if one was created
if (asset) {
await this.assetRepository.remove({ id: asset.id });
}
this.logger.error(`Error uploading file ${error}`, error?.stack); this.logger.error(`Error uploading file ${error}`, error?.stack);
throw error; throw error;
} }