refactor: remove album entity, update types (#17450)

This commit is contained in:
Daniel Dietzler 2025-04-18 23:10:34 +02:00 committed by GitHub
parent 854ea13d6a
commit 52ae06c119
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 473 additions and 396 deletions

View file

@ -1,11 +1,10 @@
import { AlbumEntity } from 'src/entities/album.entity';
import { AlbumUserRole, AssetOrder } from 'src/enum';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { userStub } from 'test/fixtures/user.stub';
export const albumStub = {
empty: Object.freeze<AlbumEntity>({
empty: Object.freeze({
id: 'album-1',
albumName: 'Empty album',
description: '',
@ -21,8 +20,9 @@ export const albumStub = {
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
sharedWithUser: Object.freeze<AlbumEntity>({
sharedWithUser: Object.freeze({
id: 'album-2',
albumName: 'Empty album shared with user',
description: '',
@ -43,8 +43,9 @@ export const albumStub = {
],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
sharedWithMultiple: Object.freeze<AlbumEntity>({
sharedWithMultiple: Object.freeze({
id: 'album-3',
albumName: 'Empty album shared with users',
description: '',
@ -69,8 +70,9 @@ export const albumStub = {
],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
sharedWithAdmin: Object.freeze<AlbumEntity>({
sharedWithAdmin: Object.freeze({
id: 'album-3',
albumName: 'Empty album shared with admin',
description: '',
@ -91,8 +93,9 @@ export const albumStub = {
],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
oneAsset: Object.freeze<AlbumEntity>({
oneAsset: Object.freeze({
id: 'album-4',
albumName: 'Album with one asset',
description: '',
@ -108,8 +111,9 @@ export const albumStub = {
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
twoAssets: Object.freeze<AlbumEntity>({
twoAssets: Object.freeze({
id: 'album-4a',
albumName: 'Album with two assets',
description: '',
@ -125,8 +129,9 @@ export const albumStub = {
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
emptyWithValidThumbnail: Object.freeze<AlbumEntity>({
emptyWithValidThumbnail: Object.freeze({
id: 'album-5',
albumName: 'Empty album with valid thumbnail',
description: '',
@ -142,5 +147,6 @@ export const albumStub = {
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
updateId: '42',
}),
};

View file

@ -1,5 +1,5 @@
import { AssetFile, Exif } from 'src/database';
import { AssetEntity } from 'src/entities/asset.entity';
import { AssetFace, AssetFile, Exif } from 'src/database';
import { MapAsset } from 'src/dtos/asset-response.dto';
import { AssetFileType, AssetStatus, AssetType } from 'src/enum';
import { StorageAsset } from 'src/types';
import { authStub } from 'test/fixtures/auth.stub';
@ -26,13 +26,15 @@ const fullsizeFile: AssetFile = {
const files: AssetFile[] = [fullsizeFile, previewFile, thumbnailFile];
export const stackStub = (stackId: string, assets: AssetEntity[]) => {
export const stackStub = (stackId: string, assets: (MapAsset & { exifInfo: Exif })[]) => {
return {
id: stackId,
assets,
ownerId: assets[0].ownerId,
primaryAsset: assets[0],
primaryAssetId: assets[0].id,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
};
};
@ -85,9 +87,12 @@ export const assetStub = {
isExternal: false,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
}),
noWebpPath: Object.freeze<AssetEntity>({
noWebpPath: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -122,9 +127,12 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
}),
noThumbhash: Object.freeze<AssetEntity>({
noThumbhash: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -156,6 +164,9 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
}),
primaryImage: Object.freeze({
@ -195,12 +206,13 @@ export const assetStub = {
} as Exif,
stackId: 'stack-1',
stack: stackStub('stack-1', [
{ id: 'primary-asset-id' } as AssetEntity,
{ id: 'stack-child-asset-1' } as AssetEntity,
{ id: 'stack-child-asset-2' } as AssetEntity,
{ id: 'primary-asset-id' } as MapAsset & { exifInfo: Exif },
{ id: 'stack-child-asset-1' } as MapAsset & { exifInfo: Exif },
{ id: 'stack-child-asset-2' } as MapAsset & { exifInfo: Exif },
]),
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
}),
@ -229,6 +241,9 @@ export const assetStub = {
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
updateId: 'foo',
libraryId: null,
stackId: null,
sharedLinks: [],
originalFileName: 'asset-id.jpg',
faces: [],
@ -241,10 +256,10 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
libraryId: null,
stack: null,
}),
trashed: Object.freeze<AssetEntity>({
trashed: Object.freeze({
id: 'asset-id',
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
@ -281,9 +296,12 @@ export const assetStub = {
duplicateId: null,
isOffline: false,
status: AssetStatus.TRASHED,
libraryId: null,
stackId: null,
updateId: '42',
}),
trashedOffline: Object.freeze<AssetEntity>({
trashedOffline: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -321,8 +339,10 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: true,
stackId: null,
updateId: '42',
}),
archived: Object.freeze<AssetEntity>({
archived: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -359,9 +379,12 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
}),
external: Object.freeze<AssetEntity>({
external: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -397,9 +420,12 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
stackId: null,
stack: null,
}),
image1: Object.freeze<AssetEntity>({
image1: Object.freeze({
id: 'asset-id-1',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -434,9 +460,13 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
stackId: null,
libraryId: null,
stack: null,
}),
imageFrom2015: Object.freeze<AssetEntity>({
imageFrom2015: Object.freeze({
id: 'asset-id-1',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -510,7 +540,9 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
}),
livePhotoMotionAsset: Object.freeze({
@ -527,7 +559,7 @@ export const assetStub = {
timeZone: `America/New_York`,
},
libraryId: null,
} as AssetEntity & { libraryId: string | null; files: AssetFile[]; exifInfo: Exif }),
} as MapAsset & { faces: AssetFace[]; files: AssetFile[]; exifInfo: Exif }),
livePhotoStillAsset: Object.freeze({
id: 'live-photo-still-asset',
@ -544,7 +576,8 @@ export const assetStub = {
timeZone: `America/New_York`,
},
files,
} as AssetEntity & { libraryId: string | null }),
faces: [] as AssetFace[],
} as MapAsset & { faces: AssetFace[] }),
livePhotoWithOriginalFileName: Object.freeze({
id: 'live-photo-still-asset',
@ -562,7 +595,8 @@ export const assetStub = {
timeZone: `America/New_York`,
},
libraryId: null,
} as AssetEntity & { libraryId: string | null }),
faces: [] as AssetFace[],
} as MapAsset & { faces: AssetFace[] }),
withLocation: Object.freeze({
id: 'asset-with-favorite-id',
@ -590,6 +624,9 @@ export const assetStub = {
isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null,
updateId: 'foo',
libraryId: null,
stackId: null,
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
@ -604,7 +641,7 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
libraryId: null,
tags: [],
}),
sidecar: Object.freeze({
@ -639,10 +676,12 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
updateId: 'foo',
libraryId: null,
stackId: null,
}),
sidecarWithoutExt: Object.freeze<AssetEntity>({
sidecarWithoutExt: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -676,7 +715,7 @@ export const assetStub = {
isOffline: false,
}),
hasEncodedVideo: Object.freeze<AssetEntity>({
hasEncodedVideo: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
originalFileName: 'asset-id.ext',
@ -711,9 +750,13 @@ export const assetStub = {
deletedAt: null,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
stack: null,
}),
hasFileExtension: Object.freeze<AssetEntity>({
hasFileExtension: Object.freeze({
id: 'asset-id',
status: AssetStatus.ACTIVE,
deviceAssetId: 'device-asset-id',
@ -788,6 +831,9 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
}),
imageHif: Object.freeze({
@ -827,5 +873,8 @@ export const assetStub = {
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
}),
};

View file

@ -1,6 +1,5 @@
import { Session } from 'src/database';
import { AuthDto } from 'src/dtos/auth.dto';
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
const authUser = {
admin: {
@ -42,14 +41,16 @@ export const authStub = {
id: 'token-id',
} as Session,
}),
adminSharedLink: Object.freeze<AuthDto>({
adminSharedLink: Object.freeze({
user: authUser.admin,
sharedLink: {
id: '123',
showExif: true,
allowDownload: true,
allowUpload: true,
key: Buffer.from('shared-link-key'),
} as SharedLinkEntity,
expiresAt: null,
password: null,
userId: '42',
},
}),
};

View file

@ -1,10 +1,9 @@
import { UserAdmin } from 'src/database';
import { AlbumResponseDto } from 'src/dtos/album.dto';
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
import { AssetResponseDto, MapAsset } from 'src/dtos/asset-response.dto';
import { ExifResponseDto } from 'src/dtos/exif.dto';
import { SharedLinkResponseDto } from 'src/dtos/shared-link.dto';
import { mapUser } from 'src/dtos/user.dto';
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { AssetOrder, AssetStatus, AssetType, SharedLinkType } from 'src/enum';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
@ -113,12 +112,12 @@ export const sharedLinkStub = {
allowUpload: true,
allowDownload: true,
showExif: true,
album: undefined,
albumId: null,
album: null,
description: null,
assets: [assetStub.image],
password: 'password',
albumId: null,
} as SharedLinkEntity),
}),
valid: Object.freeze({
id: '123',
userId: authStub.admin.user.id,
@ -130,12 +129,12 @@ export const sharedLinkStub = {
allowUpload: true,
allowDownload: true,
showExif: true,
album: undefined,
albumId: null,
description: null,
password: null,
assets: [],
} as SharedLinkEntity),
assets: [] as MapAsset[],
album: null,
}),
expired: Object.freeze({
id: '123',
userId: authStub.admin.user.id,
@ -150,9 +149,10 @@ export const sharedLinkStub = {
description: null,
password: null,
albumId: null,
assets: [],
} as SharedLinkEntity),
readonlyNoExif: Object.freeze<SharedLinkEntity>({
assets: [] as MapAsset[],
album: null,
}),
readonlyNoExif: Object.freeze({
id: '123',
userId: authStub.admin.user.id,
key: sharedLinkBytes,
@ -168,6 +168,7 @@ export const sharedLinkStub = {
albumId: 'album-123',
album: {
id: 'album-123',
updateId: '42',
ownerId: authStub.admin.user.id,
owner: userStub.admin,
albumName: 'Test Album',
@ -239,17 +240,22 @@ export const sharedLinkStub = {
colorspace: 'sRGB',
autoStackId: null,
rating: 3,
updatedAt: today,
updateId: '42',
},
sharedLinks: [],
faces: [],
sidecarPath: null,
deletedAt: null,
duplicateId: null,
updateId: '42',
libraryId: null,
stackId: null,
},
],
},
}),
passwordRequired: Object.freeze<SharedLinkEntity>({
passwordRequired: Object.freeze({
id: '123',
userId: authStub.admin.user.id,
key: sharedLinkBytes,
@ -263,6 +269,7 @@ export const sharedLinkStub = {
password: 'password',
assets: [],
albumId: null,
album: null,
}),
};

View file

@ -39,9 +39,12 @@ describe(MemoryService.name, () => {
it('should create a memory from an asset', async () => {
const { sut, repos, getRepository } = createSut();
const now = DateTime.fromObject({ year: 2025, month: 2, day: 25 }, { zone: 'utc' });
const now = DateTime.fromObject({ year: 2025, month: 2, day: 25 }, { zone: 'utc' }) as DateTime<true>;
const user = mediumFactory.userInsert();
const asset = mediumFactory.assetInsert({ ownerId: user.id, localDateTime: now.minus({ years: 1 }).toISO() });
const asset = mediumFactory.assetInsert({
ownerId: user.id,
localDateTime: now.minus({ years: 1 }).toISO(),
});
const jobStatus = mediumFactory.assetJobStatusInsert({ assetId: asset.id });
const userRepo = getRepository('user');
@ -86,7 +89,7 @@ describe(MemoryService.name, () => {
it('should not generate a memory twice for the same day', async () => {
const { sut, repos, getRepository } = createSut();
const now = DateTime.fromObject({ year: 2025, month: 2, day: 20 }, { zone: 'utc' });
const now = DateTime.fromObject({ year: 2025, month: 2, day: 20 }, { zone: 'utc' }) as DateTime<true>;
const assetRepo = getRepository('asset');
const memoryRepo = getRepository('memory');

View file

@ -118,7 +118,7 @@ describe(MetadataService.name, () => {
process.env.TZ = serverTimeZone ?? undefined;
const { filePath } = await createTestFile(exifData);
mocks.assetJob.getForMetadataExtraction.mockResolvedValue({ id: 'asset-1', originalPath: filePath } as never);
mocks.assetJob.getForMetadataExtraction.mockResolvedValue({ id: 'asset-1', originalPath: filePath } as any);
await sut.handleMetadataExtraction({ id: 'asset-1' });

View file

@ -11,7 +11,7 @@ export const newAssetRepositoryMock = (): Mocked<RepositoryInterface<AssetReposi
upsertJobStatus: vitest.fn(),
getByDayOfYear: vitest.fn(),
getByIds: vitest.fn().mockResolvedValue([]),
getByIdsWithAllRelations: vitest.fn().mockResolvedValue([]),
getByIdsWithAllRelationsButStacks: vitest.fn().mockResolvedValue([]),
getByDeviceIds: vitest.fn(),
getByUserId: vitest.fn(),
getById: vitest.fn(),

View file

@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto';
import {
Activity,
ApiKey,
Asset,
AuthApiKey,
AuthSharedLink,
AuthUser,
@ -14,6 +13,7 @@ import {
User,
UserAdmin,
} from 'src/database';
import { MapAsset } from 'src/dtos/asset-response.dto';
import { AuthDto } from 'src/dtos/auth.dto';
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
import { OnThisDayData } from 'src/types';
@ -184,7 +184,7 @@ const userAdminFactory = (user: Partial<UserAdmin> = {}) => {
};
};
const assetFactory = (asset: Partial<Asset> = {}) => ({
const assetFactory = (asset: Partial<MapAsset> = {}) => ({
id: newUuid(),
createdAt: newDate(),
updatedAt: newDate(),