mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	* refactor(server): delete assets endpoint * fix: formatting * chore: cleanup * chore: open api * chore(mobile): replace DeleteAssetDTO with BulkIdsDTOs * feat: trash an asset * chore(server): formatting * chore: open api * chore: wording * chore: open-api * feat(server): add withDeleted to getAssets queries * WIP: mobile-recycle-bin * feat(server): recycle-bin to system config * feat(web): use recycle-bin system config * chore(server): domain assetcore removed * chore(server): rename recycle-bin to trash * chore(web): rename recycle-bin to trash * chore(server): always send soft deleted assets for getAllByUserId * chore(web): formatting * feat(server): permanent delete assets older than trashed period * feat(web): trash empty placeholder image * feat(server): empty trash * feat(web): empty trash * WIP: mobile-recycle-bin * refactor(server): empty / restore trash to separate endpoint * test(server): handle failures * test(server): fix e2e server-info test * test(server): deletion test refactor * feat(mobile): use map settings from server-config to enable / disable map * feat(mobile): trash asset * fix(server): operations on assets in trash * feat(web): show trash statistics * fix(web): handle trash enabled * fix(mobile): restore updates from trash * fix(server): ignore trashed assets for person * fix(server): add / remove search index when trashed / restored * chore(web): format * fix(server): asset service test * fix(server): include trashed assts for duplicates from uploads * feat(mobile): no dialog for trash, always dialog for permanent delete * refactor(mobile): use isar where instead of dart filter * refactor(mobile): asset provide - handle deletes in single db txn * chore(mobile): review changes * feat(web): confirmation before empty trash * server: review changes * fix(server): handle library changes * fix: filter external assets from getting trashed / deleted * fix(server): empty-bin * feat: broadcast config update events through ws * change order of trash button on mobile * styling * fix(mobile): do not show trashed toast for local only assets --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
		
			
				
	
	
		
			303 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { AlbumResponseDto, AssetResponseDto, ExifResponseDto, mapUser, SharedLinkResponseDto } from '@app/domain';
 | |
| 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();
 | |
| const tomorrow = new Date();
 | |
| const yesterday = new Date();
 | |
| tomorrow.setDate(today.getDate() + 1);
 | |
| yesterday.setDate(yesterday.getDate() - 1);
 | |
| 
 | |
| const sharedLinkBytes = Buffer.from(
 | |
|   '2c2b646895f84753bff43fb696ad124f3b0faf2a0bd547406f26fa4a76b5c71990092baa536275654b2ab7a191fb21a6d6cd',
 | |
|   'hex',
 | |
| );
 | |
| 
 | |
| 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',
 | |
|   projectionType: null,
 | |
| };
 | |
| 
 | |
| 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,
 | |
|   isExternal: false,
 | |
|   isReadOnly: false,
 | |
|   isOffline: false,
 | |
|   fileCreatedAt: today,
 | |
|   localDateTime: today,
 | |
|   updatedAt: today,
 | |
|   isFavorite: false,
 | |
|   isArchived: false,
 | |
|   smartInfo: {
 | |
|     tags: [],
 | |
|     objects: ['a', 'b', 'c'],
 | |
|   },
 | |
|   duration: '0:00:00.00000',
 | |
|   exifInfo: assetInfo,
 | |
|   livePhotoVideoId: null,
 | |
|   tags: [],
 | |
|   people: [],
 | |
|   checksum: 'ZmlsZSBoYXNo',
 | |
|   isTrashed: false,
 | |
|   libraryId: 'library-id',
 | |
| };
 | |
| 
 | |
| const albumResponse: AlbumResponseDto = {
 | |
|   albumName: 'Test Album',
 | |
|   description: '',
 | |
|   albumThumbnailAssetId: null,
 | |
|   createdAt: today,
 | |
|   updatedAt: today,
 | |
|   id: 'album-123',
 | |
|   ownerId: 'admin_id',
 | |
|   owner: mapUser(userStub.admin),
 | |
|   sharedUsers: [],
 | |
|   shared: false,
 | |
|   hasSharedLink: false,
 | |
|   assets: [],
 | |
|   assetCount: 1,
 | |
| };
 | |
| 
 | |
| export const sharedLinkStub = {
 | |
|   individual: Object.freeze({
 | |
|     id: '123',
 | |
|     userId: authStub.admin.id,
 | |
|     user: userStub.admin,
 | |
|     key: sharedLinkBytes,
 | |
|     type: SharedLinkType.INDIVIDUAL,
 | |
|     createdAt: today,
 | |
|     expiresAt: tomorrow,
 | |
|     allowUpload: true,
 | |
|     allowDownload: true,
 | |
|     showExif: true,
 | |
|     album: undefined,
 | |
|     description: null,
 | |
|     assets: [assetStub.image],
 | |
|   } as SharedLinkEntity),
 | |
|   valid: Object.freeze({
 | |
|     id: '123',
 | |
|     userId: authStub.admin.id,
 | |
|     user: userStub.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: userStub.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: userStub.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: userStub.admin,
 | |
|       albumName: 'Test Album',
 | |
|       description: '',
 | |
|       createdAt: today,
 | |
|       updatedAt: today,
 | |
|       deletedAt: null,
 | |
|       albumThumbnailAsset: null,
 | |
|       albumThumbnailAssetId: null,
 | |
|       sharedUsers: [],
 | |
|       sharedLinks: [],
 | |
|       assets: [
 | |
|         {
 | |
|           id: 'id_1',
 | |
|           owner: undefined as unknown as UserEntity,
 | |
|           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,
 | |
|           localDateTime: today,
 | |
|           createdAt: today,
 | |
|           updatedAt: today,
 | |
|           isFavorite: false,
 | |
|           isArchived: false,
 | |
|           isExternal: false,
 | |
|           isReadOnly: false,
 | |
|           isOffline: false,
 | |
|           libraryId: 'library-id',
 | |
|           library: libraryStub.uploadLibrary1,
 | |
|           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: {
 | |
|             projectionType: null,
 | |
|             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: '',
 | |
|             profileDescription: 'sRGB',
 | |
|             bitsPerSample: 8,
 | |
|             colorspace: 'sRGB',
 | |
|           },
 | |
|           tags: [],
 | |
|           sharedLinks: [],
 | |
|           faces: [],
 | |
|           sidecarPath: null,
 | |
|           deletedAt: 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, startDate: assetResponse.fileCreatedAt, endDate: assetResponse.fileCreatedAt },
 | |
|     assets: [{ ...assetResponse, exifInfo: undefined }],
 | |
|   }),
 | |
| };
 |