mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:29:32 -05:00 
			
		
		
		
	* add migration * verify running migration populate new value * implemented service * generate api * FE works * FR Works * fix test * fix test fixture * fix test * fix test * consolidate api * fix test * added test * pr feedback * refactor * click ont humbnail to show feature selection as well
		
			
				
	
	
		
			1227 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			1227 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import {
 | 
						|
  AlbumResponseDto,
 | 
						|
  AssetResponseDto,
 | 
						|
  AudioStreamInfo,
 | 
						|
  AuthUserDto,
 | 
						|
  ExifResponseDto,
 | 
						|
  mapUser,
 | 
						|
  QueueName,
 | 
						|
  SearchResult,
 | 
						|
  SharedLinkResponseDto,
 | 
						|
  TagResponseDto,
 | 
						|
  VideoFormat,
 | 
						|
  VideoInfo,
 | 
						|
  VideoStreamInfo,
 | 
						|
} from '@app/domain';
 | 
						|
import {
 | 
						|
  AlbumEntity,
 | 
						|
  APIKeyEntity,
 | 
						|
  AssetEntity,
 | 
						|
  AssetFaceEntity,
 | 
						|
  AssetType,
 | 
						|
  ExifEntity,
 | 
						|
  PartnerEntity,
 | 
						|
  PersonEntity,
 | 
						|
  SharedLinkEntity,
 | 
						|
  SharedLinkType,
 | 
						|
  SystemConfig,
 | 
						|
  TagEntity,
 | 
						|
  TagType,
 | 
						|
  TranscodePreset,
 | 
						|
  UserEntity,
 | 
						|
  UserTokenEntity,
 | 
						|
} from '@app/infra/entities';
 | 
						|
 | 
						|
const today = new Date();
 | 
						|
const tomorrow = new Date();
 | 
						|
const yesterday = new Date();
 | 
						|
tomorrow.setDate(today.getDate() + 1);
 | 
						|
yesterday.setDate(yesterday.getDate() - 1);
 | 
						|
 | 
						|
const sharedLinkBytes = Buffer.from(
 | 
						|
  '2c2b646895f84753bff43fb696ad124f3b0faf2a0bd547406f26fa4a76b5c71990092baa536275654b2ab7a191fb21a6d6cd',
 | 
						|
  'hex',
 | 
						|
);
 | 
						|
 | 
						|
export const authStub = {
 | 
						|
  admin: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'admin_id',
 | 
						|
    email: 'admin@test.com',
 | 
						|
    isAdmin: true,
 | 
						|
    isPublicUser: false,
 | 
						|
    isAllowUpload: true,
 | 
						|
    externalPath: null,
 | 
						|
  }),
 | 
						|
  user1: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'user-id',
 | 
						|
    email: 'immich@test.com',
 | 
						|
    isAdmin: false,
 | 
						|
    isPublicUser: false,
 | 
						|
    isAllowUpload: true,
 | 
						|
    isAllowDownload: true,
 | 
						|
    isShowExif: true,
 | 
						|
    accessTokenId: 'token-id',
 | 
						|
    externalPath: null,
 | 
						|
  }),
 | 
						|
  user2: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'user-2',
 | 
						|
    email: 'user2@immich.app',
 | 
						|
    isAdmin: false,
 | 
						|
    isPublicUser: false,
 | 
						|
    isAllowUpload: true,
 | 
						|
    isAllowDownload: true,
 | 
						|
    isShowExif: true,
 | 
						|
    accessTokenId: 'token-id',
 | 
						|
    externalPath: null,
 | 
						|
  }),
 | 
						|
  external1: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'user-id',
 | 
						|
    email: 'immich@test.com',
 | 
						|
    isAdmin: false,
 | 
						|
    isPublicUser: false,
 | 
						|
    isAllowUpload: true,
 | 
						|
    isAllowDownload: true,
 | 
						|
    isShowExif: true,
 | 
						|
    accessTokenId: 'token-id',
 | 
						|
    externalPath: '/data/user1',
 | 
						|
  }),
 | 
						|
  adminSharedLink: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'admin_id',
 | 
						|
    email: 'admin@test.com',
 | 
						|
    isAdmin: true,
 | 
						|
    isAllowUpload: true,
 | 
						|
    isAllowDownload: true,
 | 
						|
    isPublicUser: true,
 | 
						|
    isShowExif: true,
 | 
						|
    sharedLinkId: '123',
 | 
						|
  }),
 | 
						|
  adminSharedLinkNoExif: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'admin_id',
 | 
						|
    email: 'admin@test.com',
 | 
						|
    isAdmin: true,
 | 
						|
    isAllowUpload: true,
 | 
						|
    isAllowDownload: true,
 | 
						|
    isPublicUser: true,
 | 
						|
    isShowExif: false,
 | 
						|
    sharedLinkId: '123',
 | 
						|
  }),
 | 
						|
  readonlySharedLink: Object.freeze<AuthUserDto>({
 | 
						|
    id: 'admin_id',
 | 
						|
    email: 'admin@test.com',
 | 
						|
    isAdmin: true,
 | 
						|
    isAllowUpload: false,
 | 
						|
    isAllowDownload: false,
 | 
						|
    isPublicUser: true,
 | 
						|
    isShowExif: true,
 | 
						|
    sharedLinkId: '123',
 | 
						|
    accessTokenId: 'token-id',
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const userEntityStub = {
 | 
						|
  admin: Object.freeze<UserEntity>({
 | 
						|
    ...authStub.admin,
 | 
						|
    password: 'admin_password',
 | 
						|
    firstName: 'admin_first_name',
 | 
						|
    lastName: 'admin_last_name',
 | 
						|
    storageLabel: 'admin',
 | 
						|
    externalPath: null,
 | 
						|
    oauthId: '',
 | 
						|
    shouldChangePassword: false,
 | 
						|
    profileImagePath: '',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    deletedAt: null,
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    tags: [],
 | 
						|
    assets: [],
 | 
						|
  }),
 | 
						|
  user1: Object.freeze<UserEntity>({
 | 
						|
    ...authStub.user1,
 | 
						|
    password: 'immich_password',
 | 
						|
    firstName: 'immich_first_name',
 | 
						|
    lastName: 'immich_last_name',
 | 
						|
    storageLabel: null,
 | 
						|
    externalPath: null,
 | 
						|
    oauthId: '',
 | 
						|
    shouldChangePassword: false,
 | 
						|
    profileImagePath: '',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    deletedAt: null,
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    tags: [],
 | 
						|
    assets: [],
 | 
						|
  }),
 | 
						|
  user2: Object.freeze<UserEntity>({
 | 
						|
    ...authStub.user2,
 | 
						|
    password: 'immich_password',
 | 
						|
    firstName: 'immich_first_name',
 | 
						|
    lastName: 'immich_last_name',
 | 
						|
    storageLabel: null,
 | 
						|
    externalPath: null,
 | 
						|
    oauthId: '',
 | 
						|
    shouldChangePassword: false,
 | 
						|
    profileImagePath: '',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    deletedAt: null,
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    tags: [],
 | 
						|
    assets: [],
 | 
						|
  }),
 | 
						|
  storageLabel: Object.freeze<UserEntity>({
 | 
						|
    ...authStub.user1,
 | 
						|
    password: 'immich_password',
 | 
						|
    firstName: 'immich_first_name',
 | 
						|
    lastName: 'immich_last_name',
 | 
						|
    storageLabel: 'label-1',
 | 
						|
    externalPath: null,
 | 
						|
    oauthId: '',
 | 
						|
    shouldChangePassword: false,
 | 
						|
    profileImagePath: '',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    deletedAt: null,
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    tags: [],
 | 
						|
    assets: [],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const fileStub = {
 | 
						|
  livePhotoStill: Object.freeze({
 | 
						|
    originalPath: 'fake_path/asset_1.jpeg',
 | 
						|
    mimeType: 'image/jpg',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    originalName: 'asset_1.jpeg',
 | 
						|
  }),
 | 
						|
  livePhotoMotion: Object.freeze({
 | 
						|
    originalPath: 'fake_path/asset_1.mp4',
 | 
						|
    mimeType: 'image/jpeg',
 | 
						|
    checksum: Buffer.from('live photo file hash', 'utf8'),
 | 
						|
    originalName: 'asset_1.mp4',
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const assetEntityStub = {
 | 
						|
  noResizePath: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    originalFileName: 'IMG_123',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: 'upload/library/IMG_123.jpg',
 | 
						|
    resizePath: null,
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: '/uploads/user-id/webp/path.ext',
 | 
						|
    thumbhash: Buffer.from('blablabla', 'base64'),
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: null,
 | 
						|
    isReadOnly: false,
 | 
						|
  }),
 | 
						|
  noWebpPath: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: 'upload/library/IMG_456.jpg',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: null,
 | 
						|
    thumbhash: Buffer.from('blablabla', 'base64'),
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    originalFileName: 'IMG_456',
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: null,
 | 
						|
    isReadOnly: false,
 | 
						|
    exifInfo: {
 | 
						|
      fileSizeInByte: 123_000,
 | 
						|
    } as ExifEntity,
 | 
						|
  }),
 | 
						|
  noThumbhash: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: '/original/path.ext',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: '/uploads/user-id/webp/path.ext',
 | 
						|
    thumbhash: null,
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    isReadOnly: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    originalFileName: 'asset-id.ext',
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: null,
 | 
						|
  }),
 | 
						|
  image: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: '/original/path.ext',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: '/uploads/user-id/webp/path.ext',
 | 
						|
    thumbhash: Buffer.from('blablabla', 'base64'),
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    isReadOnly: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    originalFileName: 'asset-id.ext',
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: null,
 | 
						|
    exifInfo: {
 | 
						|
      fileSizeInByte: 5_000,
 | 
						|
    } as ExifEntity,
 | 
						|
  }),
 | 
						|
  video: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    originalFileName: 'asset-id.ext',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: '/original/path.ext',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.VIDEO,
 | 
						|
    webpPath: null,
 | 
						|
    thumbhash: null,
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    isReadOnly: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: null,
 | 
						|
    exifInfo: {
 | 
						|
      fileSizeInByte: 100_000,
 | 
						|
    } as ExifEntity,
 | 
						|
  }),
 | 
						|
  livePhotoMotionAsset: Object.freeze({
 | 
						|
    id: 'live-photo-motion-asset',
 | 
						|
    originalPath: fileStub.livePhotoMotion.originalPath,
 | 
						|
    ownerId: authStub.user1.id,
 | 
						|
    type: AssetType.VIDEO,
 | 
						|
    isVisible: false,
 | 
						|
    fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
 | 
						|
    fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
 | 
						|
    exifInfo: {
 | 
						|
      fileSizeInByte: 100_000,
 | 
						|
    },
 | 
						|
  } as AssetEntity),
 | 
						|
 | 
						|
  livePhotoStillAsset: Object.freeze({
 | 
						|
    id: 'live-photo-still-asset',
 | 
						|
    originalPath: fileStub.livePhotoStill.originalPath,
 | 
						|
    ownerId: authStub.user1.id,
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    livePhotoVideoId: 'live-photo-motion-asset',
 | 
						|
    isVisible: true,
 | 
						|
    fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
 | 
						|
    fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
 | 
						|
    exifInfo: {
 | 
						|
      fileSizeInByte: 25_000,
 | 
						|
    },
 | 
						|
  } as AssetEntity),
 | 
						|
 | 
						|
  withLocation: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-with-favorite-id',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    originalPath: '/original/path.ext',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    sidecarPath: null,
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: null,
 | 
						|
    thumbhash: null,
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: false,
 | 
						|
    isArchived: false,
 | 
						|
    isReadOnly: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    originalFileName: 'asset-id.ext',
 | 
						|
    faces: [],
 | 
						|
    exifInfo: {
 | 
						|
      latitude: 100,
 | 
						|
      longitude: 100,
 | 
						|
      fileSizeInByte: 23_456,
 | 
						|
    } as ExifEntity,
 | 
						|
  }),
 | 
						|
  sidecar: Object.freeze<AssetEntity>({
 | 
						|
    id: 'asset-id',
 | 
						|
    deviceAssetId: 'device-asset-id',
 | 
						|
    fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    ownerId: 'user-id',
 | 
						|
    deviceId: 'device-id',
 | 
						|
    originalPath: '/original/path.ext',
 | 
						|
    resizePath: '/uploads/user-id/thumbs/path.ext',
 | 
						|
    thumbhash: null,
 | 
						|
    checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
    type: AssetType.IMAGE,
 | 
						|
    webpPath: null,
 | 
						|
    encodedVideoPath: null,
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    mimeType: null,
 | 
						|
    isFavorite: true,
 | 
						|
    isArchived: false,
 | 
						|
    isReadOnly: false,
 | 
						|
    duration: null,
 | 
						|
    isVisible: true,
 | 
						|
    livePhotoVideo: null,
 | 
						|
    livePhotoVideoId: null,
 | 
						|
    tags: [],
 | 
						|
    sharedLinks: [],
 | 
						|
    originalFileName: 'asset-id.ext',
 | 
						|
    faces: [],
 | 
						|
    sidecarPath: '/original/path.ext.xmp',
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const albumStub = {
 | 
						|
  empty: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-1',
 | 
						|
    albumName: 'Empty album',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
  sharedWithUser: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-2',
 | 
						|
    albumName: 'Empty album shared with user',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [userEntityStub.user1],
 | 
						|
  }),
 | 
						|
  sharedWithMultiple: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-3',
 | 
						|
    albumName: 'Empty album shared with users',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [userEntityStub.user1, userEntityStub.user2],
 | 
						|
  }),
 | 
						|
  sharedWithAdmin: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-3',
 | 
						|
    albumName: 'Empty album shared with admin',
 | 
						|
    ownerId: authStub.user1.id,
 | 
						|
    owner: userEntityStub.user1,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [userEntityStub.admin],
 | 
						|
  }),
 | 
						|
  oneAsset: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-4',
 | 
						|
    albumName: 'Album with one asset',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [assetEntityStub.image],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
  emptyWithInvalidThumbnail: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-5',
 | 
						|
    albumName: 'Empty album with invalid thumbnail',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: assetEntityStub.image,
 | 
						|
    albumThumbnailAssetId: assetEntityStub.image.id,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
  emptyWithValidThumbnail: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-5',
 | 
						|
    albumName: 'Empty album with invalid thumbnail',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [],
 | 
						|
    albumThumbnailAsset: null,
 | 
						|
    albumThumbnailAssetId: null,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
  oneAssetInvalidThumbnail: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-6',
 | 
						|
    albumName: 'Album with one asset and invalid thumbnail',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [assetEntityStub.image],
 | 
						|
    albumThumbnailAsset: assetEntityStub.livePhotoMotionAsset,
 | 
						|
    albumThumbnailAssetId: assetEntityStub.livePhotoMotionAsset.id,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
  oneAssetValidThumbnail: Object.freeze<AlbumEntity>({
 | 
						|
    id: 'album-6',
 | 
						|
    albumName: 'Album with one asset and invalid thumbnail',
 | 
						|
    ownerId: authStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    assets: [assetEntityStub.image],
 | 
						|
    albumThumbnailAsset: assetEntityStub.image,
 | 
						|
    albumThumbnailAssetId: assetEntityStub.image.id,
 | 
						|
    createdAt: new Date(),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    sharedLinks: [],
 | 
						|
    sharedUsers: [],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
const assetInfo: ExifResponseDto = {
 | 
						|
  make: 'camera-make',
 | 
						|
  model: 'camera-model',
 | 
						|
  exifImageWidth: 500,
 | 
						|
  exifImageHeight: 500,
 | 
						|
  fileSizeInByte: 100,
 | 
						|
  orientation: 'orientation',
 | 
						|
  dateTimeOriginal: today,
 | 
						|
  modifyDate: today,
 | 
						|
  timeZone: 'America/Los_Angeles',
 | 
						|
  lensModel: 'fancy',
 | 
						|
  fNumber: 100,
 | 
						|
  focalLength: 100,
 | 
						|
  iso: 100,
 | 
						|
  exposureTime: '1/16',
 | 
						|
  latitude: 100,
 | 
						|
  longitude: 100,
 | 
						|
  city: 'city',
 | 
						|
  state: 'state',
 | 
						|
  country: 'country',
 | 
						|
  description: 'description',
 | 
						|
};
 | 
						|
 | 
						|
const assetResponse: AssetResponseDto = {
 | 
						|
  id: 'id_1',
 | 
						|
  deviceAssetId: 'device_asset_id_1',
 | 
						|
  ownerId: 'user_id_1',
 | 
						|
  deviceId: 'device_id_1',
 | 
						|
  type: AssetType.VIDEO,
 | 
						|
  originalPath: 'fake_path/jpeg',
 | 
						|
  originalFileName: 'asset_1.jpeg',
 | 
						|
  resized: false,
 | 
						|
  thumbhash: null,
 | 
						|
  fileModifiedAt: today,
 | 
						|
  fileCreatedAt: today,
 | 
						|
  updatedAt: today,
 | 
						|
  isFavorite: false,
 | 
						|
  isArchived: false,
 | 
						|
  mimeType: 'image/jpeg',
 | 
						|
  smartInfo: {
 | 
						|
    tags: [],
 | 
						|
    objects: ['a', 'b', 'c'],
 | 
						|
  },
 | 
						|
  duration: '0:00:00.00000',
 | 
						|
  exifInfo: assetInfo,
 | 
						|
  livePhotoVideoId: null,
 | 
						|
  tags: [],
 | 
						|
  people: [],
 | 
						|
  checksum: 'ZmlsZSBoYXNo',
 | 
						|
};
 | 
						|
 | 
						|
const albumResponse: AlbumResponseDto = {
 | 
						|
  albumName: 'Test Album',
 | 
						|
  albumThumbnailAssetId: null,
 | 
						|
  createdAt: today,
 | 
						|
  updatedAt: today,
 | 
						|
  id: 'album-123',
 | 
						|
  ownerId: 'admin_id',
 | 
						|
  owner: mapUser(userEntityStub.admin),
 | 
						|
  sharedUsers: [],
 | 
						|
  shared: false,
 | 
						|
  assets: [],
 | 
						|
  assetCount: 1,
 | 
						|
};
 | 
						|
 | 
						|
export const userTokenEntityStub = {
 | 
						|
  userToken: Object.freeze<UserTokenEntity>({
 | 
						|
    id: 'token-id',
 | 
						|
    token: 'auth_token',
 | 
						|
    userId: userEntityStub.user1.id,
 | 
						|
    user: userEntityStub.user1,
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date(),
 | 
						|
    deviceType: '',
 | 
						|
    deviceOS: '',
 | 
						|
  }),
 | 
						|
  inactiveToken: Object.freeze<UserTokenEntity>({
 | 
						|
    id: 'not_active',
 | 
						|
    token: 'auth_token',
 | 
						|
    userId: userEntityStub.user1.id,
 | 
						|
    user: userEntityStub.user1,
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    deviceType: 'Mobile',
 | 
						|
    deviceOS: 'Android',
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const keyStub = {
 | 
						|
  admin: Object.freeze({
 | 
						|
    id: 'my-random-guid',
 | 
						|
    name: 'My Key',
 | 
						|
    key: 'my-api-key (hashed)',
 | 
						|
    userId: authStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
  } as APIKeyEntity),
 | 
						|
};
 | 
						|
 | 
						|
export const systemConfigStub = {
 | 
						|
  defaults: Object.freeze({
 | 
						|
    ffmpeg: {
 | 
						|
      crf: 23,
 | 
						|
      threads: 0,
 | 
						|
      preset: 'ultrafast',
 | 
						|
      targetAudioCodec: 'aac',
 | 
						|
      targetResolution: '720',
 | 
						|
      targetVideoCodec: 'h264',
 | 
						|
      maxBitrate: '0',
 | 
						|
      twoPass: false,
 | 
						|
      transcode: TranscodePreset.REQUIRED,
 | 
						|
    },
 | 
						|
    job: {
 | 
						|
      [QueueName.BACKGROUND_TASK]: { concurrency: 5 },
 | 
						|
      [QueueName.CLIP_ENCODING]: { concurrency: 2 },
 | 
						|
      [QueueName.METADATA_EXTRACTION]: { concurrency: 5 },
 | 
						|
      [QueueName.OBJECT_TAGGING]: { concurrency: 2 },
 | 
						|
      [QueueName.RECOGNIZE_FACES]: { concurrency: 2 },
 | 
						|
      [QueueName.SEARCH]: { concurrency: 5 },
 | 
						|
      [QueueName.SIDECAR]: { concurrency: 5 },
 | 
						|
      [QueueName.STORAGE_TEMPLATE_MIGRATION]: { concurrency: 5 },
 | 
						|
      [QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 },
 | 
						|
      [QueueName.VIDEO_CONVERSION]: { concurrency: 1 },
 | 
						|
    },
 | 
						|
    oauth: {
 | 
						|
      autoLaunch: false,
 | 
						|
      autoRegister: true,
 | 
						|
      buttonText: 'Login with OAuth',
 | 
						|
      clientId: '',
 | 
						|
      clientSecret: '',
 | 
						|
      enabled: false,
 | 
						|
      issuerUrl: '',
 | 
						|
      mobileOverrideEnabled: false,
 | 
						|
      mobileRedirectUri: '',
 | 
						|
      scope: 'openid email profile',
 | 
						|
    },
 | 
						|
    passwordLogin: {
 | 
						|
      enabled: true,
 | 
						|
    },
 | 
						|
    storageTemplate: {
 | 
						|
      template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
 | 
						|
    },
 | 
						|
  } as SystemConfig),
 | 
						|
  enabled: Object.freeze({
 | 
						|
    passwordLogin: {
 | 
						|
      enabled: true,
 | 
						|
    },
 | 
						|
    oauth: {
 | 
						|
      enabled: true,
 | 
						|
      autoRegister: true,
 | 
						|
      buttonText: 'OAuth',
 | 
						|
      autoLaunch: false,
 | 
						|
    },
 | 
						|
  } as SystemConfig),
 | 
						|
  disabled: Object.freeze({
 | 
						|
    passwordLogin: {
 | 
						|
      enabled: false,
 | 
						|
    },
 | 
						|
    oauth: {
 | 
						|
      enabled: false,
 | 
						|
      buttonText: 'OAuth',
 | 
						|
      issuerUrl: 'http://issuer,',
 | 
						|
      autoLaunch: false,
 | 
						|
    },
 | 
						|
  } as SystemConfig),
 | 
						|
  noAutoRegister: {
 | 
						|
    oauth: {
 | 
						|
      enabled: true,
 | 
						|
      autoRegister: false,
 | 
						|
      autoLaunch: false,
 | 
						|
    },
 | 
						|
    passwordLogin: { enabled: true },
 | 
						|
  } as SystemConfig,
 | 
						|
  override: {
 | 
						|
    oauth: {
 | 
						|
      enabled: true,
 | 
						|
      autoRegister: true,
 | 
						|
      autoLaunch: false,
 | 
						|
      buttonText: 'OAuth',
 | 
						|
      mobileOverrideEnabled: true,
 | 
						|
      mobileRedirectUri: 'http://mobile-redirect',
 | 
						|
    },
 | 
						|
    passwordLogin: { enabled: true },
 | 
						|
  } as SystemConfig,
 | 
						|
};
 | 
						|
 | 
						|
export const loginResponseStub = {
 | 
						|
  user1oauth: {
 | 
						|
    response: {
 | 
						|
      accessToken: 'cmFuZG9tLWJ5dGVz',
 | 
						|
      userId: 'user-id',
 | 
						|
      userEmail: 'immich@test.com',
 | 
						|
      firstName: 'immich_first_name',
 | 
						|
      lastName: 'immich_last_name',
 | 
						|
      profileImagePath: '',
 | 
						|
      isAdmin: false,
 | 
						|
      shouldChangePassword: false,
 | 
						|
    },
 | 
						|
    cookie: [
 | 
						|
      'immich_access_token=cmFuZG9tLWJ5dGVz; HttpOnly; Secure; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
      'immich_auth_type=oauth; HttpOnly; Secure; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
    ],
 | 
						|
  },
 | 
						|
  user1password: {
 | 
						|
    response: {
 | 
						|
      accessToken: 'cmFuZG9tLWJ5dGVz',
 | 
						|
      userId: 'user-id',
 | 
						|
      userEmail: 'immich@test.com',
 | 
						|
      firstName: 'immich_first_name',
 | 
						|
      lastName: 'immich_last_name',
 | 
						|
      profileImagePath: '',
 | 
						|
      isAdmin: false,
 | 
						|
      shouldChangePassword: false,
 | 
						|
    },
 | 
						|
    cookie: [
 | 
						|
      'immich_access_token=cmFuZG9tLWJ5dGVz; HttpOnly; Secure; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
      'immich_auth_type=password; HttpOnly; Secure; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
    ],
 | 
						|
  },
 | 
						|
  user1insecure: {
 | 
						|
    response: {
 | 
						|
      accessToken: 'cmFuZG9tLWJ5dGVz',
 | 
						|
      userId: 'user-id',
 | 
						|
      userEmail: 'immich@test.com',
 | 
						|
      firstName: 'immich_first_name',
 | 
						|
      lastName: 'immich_last_name',
 | 
						|
      profileImagePath: '',
 | 
						|
      isAdmin: false,
 | 
						|
      shouldChangePassword: false,
 | 
						|
    },
 | 
						|
    cookie: [
 | 
						|
      'immich_access_token=cmFuZG9tLWJ5dGVz; HttpOnly; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
      'immich_auth_type=password; HttpOnly; Path=/; Max-Age=34560000; SameSite=Lax;',
 | 
						|
    ],
 | 
						|
  },
 | 
						|
};
 | 
						|
 | 
						|
export const sharedLinkStub = {
 | 
						|
  individual: Object.freeze({
 | 
						|
    id: '123',
 | 
						|
    userId: authStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
    key: sharedLinkBytes,
 | 
						|
    type: SharedLinkType.INDIVIDUAL,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    allowUpload: true,
 | 
						|
    allowDownload: true,
 | 
						|
    showExif: true,
 | 
						|
    album: undefined,
 | 
						|
    description: null,
 | 
						|
    assets: [assetEntityStub.image],
 | 
						|
  } as SharedLinkEntity),
 | 
						|
  valid: Object.freeze({
 | 
						|
    id: '123',
 | 
						|
    userId: authStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
    key: sharedLinkBytes,
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    allowUpload: true,
 | 
						|
    allowDownload: true,
 | 
						|
    showExif: true,
 | 
						|
    album: undefined,
 | 
						|
    albumId: null,
 | 
						|
    description: null,
 | 
						|
    assets: [],
 | 
						|
  } as SharedLinkEntity),
 | 
						|
  expired: Object.freeze({
 | 
						|
    id: '123',
 | 
						|
    userId: authStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
    key: sharedLinkBytes,
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: yesterday,
 | 
						|
    allowUpload: true,
 | 
						|
    allowDownload: true,
 | 
						|
    showExif: true,
 | 
						|
    description: null,
 | 
						|
    albumId: null,
 | 
						|
    assets: [],
 | 
						|
  } as SharedLinkEntity),
 | 
						|
  readonlyNoExif: Object.freeze<SharedLinkEntity>({
 | 
						|
    id: '123',
 | 
						|
    userId: authStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
    key: sharedLinkBytes,
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    allowUpload: false,
 | 
						|
    allowDownload: false,
 | 
						|
    showExif: false,
 | 
						|
    description: null,
 | 
						|
    assets: [],
 | 
						|
    albumId: 'album-123',
 | 
						|
    album: {
 | 
						|
      id: 'album-123',
 | 
						|
      ownerId: authStub.admin.id,
 | 
						|
      owner: userEntityStub.admin,
 | 
						|
      albumName: 'Test Album',
 | 
						|
      createdAt: today,
 | 
						|
      updatedAt: today,
 | 
						|
      albumThumbnailAsset: null,
 | 
						|
      albumThumbnailAssetId: null,
 | 
						|
      sharedUsers: [],
 | 
						|
      sharedLinks: [],
 | 
						|
      assets: [
 | 
						|
        {
 | 
						|
          id: 'id_1',
 | 
						|
          owner: userEntityStub.user1,
 | 
						|
          ownerId: 'user_id_1',
 | 
						|
          deviceAssetId: 'device_asset_id_1',
 | 
						|
          deviceId: 'device_id_1',
 | 
						|
          type: AssetType.VIDEO,
 | 
						|
          originalPath: 'fake_path/jpeg',
 | 
						|
          resizePath: '',
 | 
						|
          checksum: Buffer.from('file hash', 'utf8'),
 | 
						|
          fileModifiedAt: today,
 | 
						|
          fileCreatedAt: today,
 | 
						|
          createdAt: today,
 | 
						|
          updatedAt: today,
 | 
						|
          isFavorite: false,
 | 
						|
          isArchived: false,
 | 
						|
          isReadOnly: false,
 | 
						|
          mimeType: 'image/jpeg',
 | 
						|
          smartInfo: {
 | 
						|
            assetId: 'id_1',
 | 
						|
            tags: [],
 | 
						|
            objects: ['a', 'b', 'c'],
 | 
						|
            asset: null as any,
 | 
						|
            clipEmbedding: [0.12, 0.13, 0.14],
 | 
						|
          },
 | 
						|
          webpPath: '',
 | 
						|
          thumbhash: null,
 | 
						|
          encodedVideoPath: '',
 | 
						|
          duration: null,
 | 
						|
          isVisible: true,
 | 
						|
          livePhotoVideo: null,
 | 
						|
          livePhotoVideoId: null,
 | 
						|
          originalFileName: 'asset_1.jpeg',
 | 
						|
          exifInfo: {
 | 
						|
            livePhotoCID: null,
 | 
						|
            assetId: 'id_1',
 | 
						|
            description: 'description',
 | 
						|
            exifImageWidth: 500,
 | 
						|
            exifImageHeight: 500,
 | 
						|
            fileSizeInByte: 100,
 | 
						|
            orientation: 'orientation',
 | 
						|
            dateTimeOriginal: today,
 | 
						|
            modifyDate: today,
 | 
						|
            timeZone: 'America/Los_Angeles',
 | 
						|
            latitude: 100,
 | 
						|
            longitude: 100,
 | 
						|
            city: 'city',
 | 
						|
            state: 'state',
 | 
						|
            country: 'country',
 | 
						|
            make: 'camera-make',
 | 
						|
            model: 'camera-model',
 | 
						|
            lensModel: 'fancy',
 | 
						|
            fNumber: 100,
 | 
						|
            focalLength: 100,
 | 
						|
            iso: 100,
 | 
						|
            exposureTime: '1/16',
 | 
						|
            fps: 100,
 | 
						|
            asset: null as any,
 | 
						|
            exifTextSearchableColumn: '',
 | 
						|
          },
 | 
						|
          tags: [],
 | 
						|
          sharedLinks: [],
 | 
						|
          faces: [],
 | 
						|
          sidecarPath: null,
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const sharedLinkResponseStub = {
 | 
						|
  valid: Object.freeze<SharedLinkResponseDto>({
 | 
						|
    allowDownload: true,
 | 
						|
    allowUpload: true,
 | 
						|
    assets: [],
 | 
						|
    createdAt: today,
 | 
						|
    description: null,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    id: '123',
 | 
						|
    key: sharedLinkBytes.toString('base64url'),
 | 
						|
    showExif: true,
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    userId: 'admin_id',
 | 
						|
  }),
 | 
						|
  expired: Object.freeze<SharedLinkResponseDto>({
 | 
						|
    album: undefined,
 | 
						|
    allowDownload: true,
 | 
						|
    allowUpload: true,
 | 
						|
    assets: [],
 | 
						|
    createdAt: today,
 | 
						|
    description: null,
 | 
						|
    expiresAt: yesterday,
 | 
						|
    id: '123',
 | 
						|
    key: sharedLinkBytes.toString('base64url'),
 | 
						|
    showExif: true,
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    userId: 'admin_id',
 | 
						|
  }),
 | 
						|
  readonly: Object.freeze<SharedLinkResponseDto>({
 | 
						|
    id: '123',
 | 
						|
    userId: 'admin_id',
 | 
						|
    key: sharedLinkBytes.toString('base64url'),
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    description: null,
 | 
						|
    allowUpload: false,
 | 
						|
    allowDownload: false,
 | 
						|
    showExif: true,
 | 
						|
    album: albumResponse,
 | 
						|
    assets: [assetResponse],
 | 
						|
  }),
 | 
						|
  readonlyNoExif: Object.freeze<SharedLinkResponseDto>({
 | 
						|
    id: '123',
 | 
						|
    userId: 'admin_id',
 | 
						|
    key: sharedLinkBytes.toString('base64url'),
 | 
						|
    type: SharedLinkType.ALBUM,
 | 
						|
    createdAt: today,
 | 
						|
    expiresAt: tomorrow,
 | 
						|
    description: null,
 | 
						|
    allowUpload: false,
 | 
						|
    allowDownload: false,
 | 
						|
    showExif: false,
 | 
						|
    album: albumResponse,
 | 
						|
    assets: [{ ...assetResponse, exifInfo: undefined }],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
// TODO - the constructor isn't used anywhere, so not test coverage
 | 
						|
new ExifResponseDto();
 | 
						|
 | 
						|
export const searchStub = {
 | 
						|
  emptyResults: Object.freeze<SearchResult<any>>({
 | 
						|
    total: 0,
 | 
						|
    count: 0,
 | 
						|
    page: 1,
 | 
						|
    items: [],
 | 
						|
    facets: [],
 | 
						|
    distances: [],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
const probeStubDefaultFormat: VideoFormat = {
 | 
						|
  formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
 | 
						|
  formatLongName: 'QuickTime / MOV',
 | 
						|
  duration: 0,
 | 
						|
};
 | 
						|
 | 
						|
const probeStubDefaultVideoStream: VideoStreamInfo[] = [
 | 
						|
  { height: 1080, width: 1920, codecName: 'h265', codecType: 'video', frameCount: 100, rotation: 0 },
 | 
						|
];
 | 
						|
 | 
						|
const probeStubDefaultAudioStream: AudioStreamInfo[] = [{ codecName: 'aac', codecType: 'audio' }];
 | 
						|
 | 
						|
const probeStubDefault: VideoInfo = {
 | 
						|
  format: probeStubDefaultFormat,
 | 
						|
  videoStreams: probeStubDefaultVideoStream,
 | 
						|
  audioStreams: probeStubDefaultAudioStream,
 | 
						|
};
 | 
						|
 | 
						|
export const probeStub = {
 | 
						|
  noVideoStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, videoStreams: [] }),
 | 
						|
  multipleVideoStreams: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    videoStreams: [
 | 
						|
      {
 | 
						|
        height: 1080,
 | 
						|
        width: 400,
 | 
						|
        codecName: 'h265',
 | 
						|
        codecType: 'video',
 | 
						|
        frameCount: 100,
 | 
						|
        rotation: 0,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        height: 1080,
 | 
						|
        width: 400,
 | 
						|
        codecName: 'h7000',
 | 
						|
        codecType: 'video',
 | 
						|
        frameCount: 99,
 | 
						|
        rotation: 0,
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  }),
 | 
						|
  noHeight: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    videoStreams: [
 | 
						|
      {
 | 
						|
        height: 0,
 | 
						|
        width: 400,
 | 
						|
        codecName: 'h265',
 | 
						|
        codecType: 'video',
 | 
						|
        frameCount: 100,
 | 
						|
        rotation: 0,
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  }),
 | 
						|
  videoStream2160p: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    videoStreams: [
 | 
						|
      {
 | 
						|
        height: 2160,
 | 
						|
        width: 3840,
 | 
						|
        codecName: 'h264',
 | 
						|
        codecType: 'video',
 | 
						|
        frameCount: 100,
 | 
						|
        rotation: 0,
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  }),
 | 
						|
  videoStreamVertical2160p: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    videoStreams: [
 | 
						|
      {
 | 
						|
        height: 2160,
 | 
						|
        width: 3840,
 | 
						|
        codecName: 'h264',
 | 
						|
        codecType: 'video',
 | 
						|
        frameCount: 100,
 | 
						|
        rotation: 90,
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  }),
 | 
						|
  audioStreamMp3: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    audioStreams: [{ codecType: 'audio', codecName: 'aac' }],
 | 
						|
  }),
 | 
						|
  matroskaContainer: Object.freeze<VideoInfo>({
 | 
						|
    ...probeStubDefault,
 | 
						|
    format: {
 | 
						|
      formatName: 'matroska,webm',
 | 
						|
      formatLongName: 'Matroska / WebM',
 | 
						|
      duration: 0,
 | 
						|
    },
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const personStub = {
 | 
						|
  noName: Object.freeze<PersonEntity>({
 | 
						|
    id: 'person-1',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    ownerId: userEntityStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    name: '',
 | 
						|
    thumbnailPath: '/path/to/thumbnail',
 | 
						|
    faces: [],
 | 
						|
  }),
 | 
						|
  withName: Object.freeze<PersonEntity>({
 | 
						|
    id: 'person-1',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    ownerId: userEntityStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    name: 'Person 1',
 | 
						|
    thumbnailPath: '/path/to/thumbnail',
 | 
						|
    faces: [],
 | 
						|
  }),
 | 
						|
  noThumbnail: Object.freeze<PersonEntity>({
 | 
						|
    id: 'person-1',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    ownerId: userEntityStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    name: '',
 | 
						|
    thumbnailPath: '',
 | 
						|
    faces: [],
 | 
						|
  }),
 | 
						|
  newThumbnail: Object.freeze<PersonEntity>({
 | 
						|
    id: 'person-1',
 | 
						|
    createdAt: new Date('2021-01-01'),
 | 
						|
    updatedAt: new Date('2021-01-01'),
 | 
						|
    ownerId: userEntityStub.admin.id,
 | 
						|
    owner: userEntityStub.admin,
 | 
						|
    name: '',
 | 
						|
    thumbnailPath: '/new/path/to/thumbnail',
 | 
						|
    faces: [],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const partnerStub = {
 | 
						|
  adminToUser1: Object.freeze<PartnerEntity>({
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    sharedById: userEntityStub.admin.id,
 | 
						|
    sharedBy: userEntityStub.admin,
 | 
						|
    sharedWith: userEntityStub.user1,
 | 
						|
    sharedWithId: userEntityStub.user1.id,
 | 
						|
  }),
 | 
						|
  user1ToAdmin1: Object.freeze<PartnerEntity>({
 | 
						|
    createdAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    updatedAt: new Date('2023-02-23T05:06:29.716Z'),
 | 
						|
    sharedBy: userEntityStub.user1,
 | 
						|
    sharedById: userEntityStub.user1.id,
 | 
						|
    sharedWithId: userEntityStub.admin.id,
 | 
						|
    sharedWith: userEntityStub.admin,
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const faceStub = {
 | 
						|
  face1: Object.freeze<AssetFaceEntity>({
 | 
						|
    assetId: assetEntityStub.image.id,
 | 
						|
    asset: assetEntityStub.image,
 | 
						|
    personId: personStub.withName.id,
 | 
						|
    person: personStub.withName,
 | 
						|
    embedding: [1, 2, 3, 4],
 | 
						|
    boundingBoxX1: 0,
 | 
						|
    boundingBoxY1: 0,
 | 
						|
    boundingBoxX2: 1,
 | 
						|
    boundingBoxY2: 1,
 | 
						|
    imageHeight: 1024,
 | 
						|
    imageWidth: 1024,
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const tagStub = {
 | 
						|
  tag1: Object.freeze<TagEntity>({
 | 
						|
    id: 'tag-1',
 | 
						|
    name: 'Tag1',
 | 
						|
    type: TagType.CUSTOM,
 | 
						|
    userId: userEntityStub.admin.id,
 | 
						|
    user: userEntityStub.admin,
 | 
						|
    renameTagId: null,
 | 
						|
    assets: [],
 | 
						|
  }),
 | 
						|
};
 | 
						|
 | 
						|
export const tagResponseStub = {
 | 
						|
  tag1: Object.freeze<TagResponseDto>({
 | 
						|
    id: 'tag-1',
 | 
						|
    name: 'Tag1',
 | 
						|
    type: 'CUSTOM',
 | 
						|
    userId: 'admin_id',
 | 
						|
  }),
 | 
						|
};
 |