mirror of
https://github.com/immich-app/immich
synced 2026-08-22 13:13:05 +00:00
Merge branch 'main' into feat/album-asset-workflow-trigger
This commit is contained in:
commit
61620e6c27
41 changed files with 307 additions and 67 deletions
|
|
@ -9,6 +9,7 @@ import semver from 'semver';
|
|||
import {
|
||||
EXTENSION_NAMES,
|
||||
POSTGRES_VERSION_RANGE,
|
||||
serverVersion,
|
||||
VECTOR_EXTENSIONS,
|
||||
VECTOR_INDEX_TABLES,
|
||||
VECTOR_VERSION_RANGE,
|
||||
|
|
@ -382,6 +383,17 @@ export class DatabaseRepository {
|
|||
|
||||
if (error) {
|
||||
this.logger.error(`Migrations failed: ${error}`);
|
||||
|
||||
const missing =
|
||||
error instanceof Error ? error.message.match(/previously executed migration (.+) is missing/u) : null;
|
||||
if (missing) {
|
||||
throw new Error(
|
||||
`Migration "${missing[1]}" was already applied to this database but is not in this version of Immich (${serverVersion}). ` +
|
||||
`This usually means the database was migrated by a newer version. Downgrades are not supported.`,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -317,6 +317,12 @@ describe(AssetMediaService.name, () => {
|
|||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
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.storage.utimes).not.toHaveBeenCalledWith(
|
||||
file.originalPath,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { BadRequestException, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { AuthSharedLink } from 'src/database';
|
||||
import { Asset, AuthSharedLink } from 'src/database';
|
||||
import {
|
||||
AssetBulkUploadCheckResponseDto,
|
||||
AssetMediaResponseDto,
|
||||
|
|
@ -128,6 +128,7 @@ export class AssetMediaService extends BaseService {
|
|||
file: UploadFile,
|
||||
sidecarFile?: UploadFile,
|
||||
): Promise<AssetMediaResponseDto> {
|
||||
let asset: Asset | undefined;
|
||||
try {
|
||||
await this.requireAccess({
|
||||
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,
|
||||
libraryId: null,
|
||||
|
||||
|
|
@ -215,6 +216,11 @@ export class AssetMediaService extends BaseService {
|
|||
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);
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ describe(PartnerService.name, () => {
|
|||
const auth = AuthFactory.create({ id: user1.id });
|
||||
|
||||
mocks.partner.get.mockResolvedValue(void 0);
|
||||
mocks.user.get.mockResolvedValue(user2);
|
||||
mocks.partner.create.mockResolvedValue(getForPartner(partner));
|
||||
|
||||
await expect(sut.create(auth, { sharedWithId: user2.id })).resolves.toBeDefined();
|
||||
|
|
@ -76,6 +77,19 @@ describe(PartnerService.name, () => {
|
|||
|
||||
expect(mocks.partner.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw an error when sharedWithId does not resolve to an existing (non-deleted) user', async () => {
|
||||
const user1 = UserFactory.create();
|
||||
const user2 = UserFactory.create();
|
||||
const auth = AuthFactory.create({ id: user1.id });
|
||||
|
||||
mocks.partner.get.mockResolvedValue(void 0);
|
||||
mocks.user.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.create(auth, { sharedWithId: user2.id })).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.partner.create).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove', () => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ export class PartnerService extends BaseService {
|
|||
throw new BadRequestException(`Partner already exists`);
|
||||
}
|
||||
|
||||
const user = await this.userRepository.get(sharedWithId, {});
|
||||
if (!user) {
|
||||
this.logger.debug('Partner creation failed: user not found');
|
||||
throw new BadRequestException('Invalid user');
|
||||
}
|
||||
|
||||
const partner = await this.partnerRepository.create(partnerId);
|
||||
return this.mapPartner(partner, PartnerDirection.SharedBy);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue