feat(server,web): libraries (#3124)

* feat: libraries

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Jonathan Jogenfors
2023-09-20 13:16:33 +02:00
committed by GitHub
parent 816db700e1
commit acdc66413c
143 changed files with 10941 additions and 386 deletions

View File

@@ -1,6 +1,7 @@
import { AssetEntity, AssetType, ExifEntity } from '@app/infra/entities';
import { authStub } from './auth.stub';
import { fileStub } from './file.stub';
import { libraryStub } from './library.stub';
import { userStub } from './user.stub';
export const assetStub = {
@@ -33,6 +34,10 @@ export const assetStub = {
faces: [],
sidecarPath: null,
isReadOnly: false,
isOffline: false,
isExternal: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
}),
noWebpPath: Object.freeze<AssetEntity>({
id: 'asset-id',
@@ -63,6 +68,10 @@ export const assetStub = {
faces: [],
sidecarPath: null,
isReadOnly: false,
isOffline: false,
isExternal: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
exifInfo: {
fileSizeInByte: 123_000,
} as ExifEntity,
@@ -87,8 +96,12 @@ export const assetStub = {
isFavorite: true,
isArchived: false,
isReadOnly: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
duration: null,
isVisible: true,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
tags: [],
@@ -119,8 +132,86 @@ export const assetStub = {
isReadOnly: false,
duration: null,
isVisible: true,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
tags: [],
sharedLinks: [],
originalFileName: 'asset-id.jpg',
faces: [],
sidecarPath: null,
exifInfo: {
fileSizeInByte: 5_000,
} as ExifEntity,
}),
external: 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: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/data/user1/photo.jpg',
resizePath: '/uploads/user-id/thumbs/path.jpg',
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'),
isFavorite: true,
isArchived: false,
isReadOnly: false,
isExternal: true,
duration: null,
isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
tags: [],
sharedLinks: [],
originalFileName: 'asset-id.jpg',
faces: [],
sidecarPath: null,
exifInfo: {
fileSizeInByte: 5_000,
} as ExifEntity,
}),
offline: 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: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.jpg',
resizePath: '/uploads/user-id/thumbs/path.jpg',
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'),
isFavorite: true,
isArchived: false,
isReadOnly: false,
isExternal: false,
duration: null,
isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null,
isOffline: true,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
tags: [],
sharedLinks: [],
originalFileName: 'asset-id.jpg',
@@ -149,7 +240,11 @@ export const assetStub = {
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
isArchived: false,
isExternal: false,
isReadOnly: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
duration: null,
isVisible: true,
livePhotoVideo: null,
@@ -184,6 +279,10 @@ export const assetStub = {
isFavorite: true,
isArchived: false,
isReadOnly: false,
isExternal: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
duration: null,
isVisible: true,
livePhotoVideo: null,
@@ -204,6 +303,8 @@ export const assetStub = {
isVisible: false,
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
exifInfo: {
fileSizeInByte: 100_000,
},
@@ -218,6 +319,8 @@ export const assetStub = {
isVisible: true,
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
exifInfo: {
fileSizeInByte: 25_000,
},
@@ -244,6 +347,10 @@ export const assetStub = {
isFavorite: false,
isArchived: false,
isReadOnly: false,
isExternal: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
duration: null,
isVisible: true,
livePhotoVideo: null,
@@ -278,6 +385,10 @@ export const assetStub = {
isFavorite: true,
isArchived: false,
isReadOnly: false,
isExternal: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
duration: null,
isVisible: true,
livePhotoVideo: null,

View File

@@ -24,11 +24,11 @@ export const errorStub = {
statusCode: 401,
message: 'Invalid share key',
},
badRequest: {
badRequest: (message: any = null) => ({
error: 'Bad Request',
statusCode: 400,
message: expect.any(Array),
},
message: message ?? expect.anything(),
}),
noPermission: {
error: 'Bad Request',
statusCode: 400,
@@ -44,4 +44,9 @@ export const errorStub = {
statusCode: 400,
message: 'The server already has an admin',
},
noDeleteUploadLibrary: {
error: 'Bad Request',
statusCode: 400,
message: 'Cannot delete the last upload library',
},
};

View File

@@ -7,6 +7,7 @@ export * from './device.stub';
export * from './error.stub';
export * from './face.stub';
export * from './file.stub';
export * from './library.stub';
export * from './media.stub';
export * from './partner.stub';
export * from './person.stub';

33
server/test/fixtures/library.stub.ts vendored Normal file
View File

@@ -0,0 +1,33 @@
import { LibraryEntity, LibraryType } from '@app/infra/entities';
import { userStub } from './user.stub';
export const libraryStub = {
uploadLibrary1: Object.freeze<LibraryEntity>({
id: 'library-id',
name: 'test_library',
assets: [],
owner: userStub.user1,
ownerId: 'user-id',
type: LibraryType.UPLOAD,
importPaths: [],
createdAt: new Date('2022-01-01'),
updatedAt: new Date('2022-01-01'),
refreshedAt: null,
isVisible: true,
exclusionPatterns: [],
}),
externalLibrary1: Object.freeze<LibraryEntity>({
id: 'library-id',
name: 'test_library',
assets: [],
owner: userStub.externalPath1,
ownerId: 'user-id',
type: LibraryType.EXTERNAL,
importPaths: [],
createdAt: new Date('2023-01-01'),
updatedAt: new Date('2023-01-01'),
refreshedAt: null,
isVisible: true,
exclusionPatterns: [],
}),
};

View File

@@ -2,6 +2,7 @@ import { AlbumResponseDto, AssetResponseDto, ExifResponseDto, mapUser, SharedLin
import { AssetType, SharedLinkEntity, SharedLinkType, UserEntity } from '@app/infra/entities';
import { assetStub } from './asset.stub';
import { authStub } from './auth.stub';
import { libraryStub } from './library.stub';
import { userStub } from './user.stub';
const today = new Date();
@@ -50,6 +51,9 @@ const assetResponse: AssetResponseDto = {
resized: false,
thumbhash: null,
fileModifiedAt: today,
isExternal: false,
isReadOnly: false,
isOffline: false,
fileCreatedAt: today,
updatedAt: today,
isFavorite: false,
@@ -64,6 +68,7 @@ const assetResponse: AssetResponseDto = {
tags: [],
people: [],
checksum: 'ZmlsZSBoYXNo',
libraryId: 'library-id',
};
const albumResponse: AlbumResponseDto = {
@@ -173,7 +178,11 @@ export const sharedLinkStub = {
updatedAt: today,
isFavorite: false,
isArchived: false,
isExternal: false,
isReadOnly: false,
isOffline: false,
libraryId: 'library-id',
library: libraryStub.uploadLibrary1,
smartInfo: {
assetId: 'id_1',
tags: [],

View File

@@ -70,4 +70,38 @@ export const userStub = {
assets: [],
memoriesEnabled: true,
}),
externalPath1: Object.freeze<UserEntity>({
...authStub.user1,
password: 'immich_password',
firstName: 'immich_first_name',
lastName: 'immich_last_name',
storageLabel: 'label-1',
externalPath: '/data/user1',
oauthId: '',
shouldChangePassword: false,
profileImagePath: '',
createdAt: new Date('2021-01-01'),
deletedAt: null,
updatedAt: new Date('2021-01-01'),
tags: [],
assets: [],
memoriesEnabled: true,
}),
externalPath2: Object.freeze<UserEntity>({
...authStub.user1,
password: 'immich_password',
firstName: 'immich_first_name',
lastName: 'immich_last_name',
storageLabel: 'label-1',
externalPath: '/data/user2',
oauthId: '',
shouldChangePassword: false,
profileImagePath: '',
createdAt: new Date('2021-01-01'),
deletedAt: null,
updatedAt: new Date('2021-01-01'),
tags: [],
assets: [],
memoriesEnabled: true,
}),
};