mirror of
https://github.com/KevinMidboe/immich.git
synced 2026-03-02 04:00:11 +00:00
feat(server): split generated content into a separate folder (#2047)
* feat: organize media folders * fix: tests
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
import { AssetEntity, AssetType, SystemConfig } from '@app/infra/db/entities';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import handlebar from 'handlebars';
|
||||
import * as luxon from 'luxon';
|
||||
import path from 'node:path';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { IStorageRepository, StorageCore, StorageFolder } from '../storage';
|
||||
import {
|
||||
IStorageRepository,
|
||||
ISystemConfigRepository,
|
||||
supportedDayTokens,
|
||||
supportedHourTokens,
|
||||
@@ -7,20 +13,14 @@ import {
|
||||
supportedMonthTokens,
|
||||
supportedSecondTokens,
|
||||
supportedYearTokens,
|
||||
} from '@app/domain';
|
||||
import { AssetEntity, AssetType, SystemConfig } from '@app/infra/db/entities';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import handlebar from 'handlebars';
|
||||
import * as luxon from 'luxon';
|
||||
import path from 'node:path';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { APP_UPLOAD_LOCATION } from '../domain.constant';
|
||||
} from '../system-config';
|
||||
import { SystemConfigCore } from '../system-config/system-config.core';
|
||||
|
||||
export class StorageTemplateCore {
|
||||
private logger = new Logger(StorageTemplateCore.name);
|
||||
private configCore: SystemConfigCore;
|
||||
private storageTemplate: HandlebarsTemplateDelegate<any>;
|
||||
private storageCore = new StorageCore();
|
||||
|
||||
constructor(
|
||||
configRepository: ISystemConfigRepository,
|
||||
@@ -38,7 +38,7 @@ export class StorageTemplateCore {
|
||||
const source = asset.originalPath;
|
||||
const ext = path.extname(source).split('.').pop() as string;
|
||||
const sanitized = sanitize(path.basename(filename, `.${ext}`));
|
||||
const rootPath = path.join(APP_UPLOAD_LOCATION, asset.ownerId);
|
||||
const rootPath = this.storageCore.getFolderLocation(StorageFolder.LIBRARY, asset.ownerId);
|
||||
const storagePath = this.render(this.storageTemplate, asset, sanitized, ext);
|
||||
const fullPath = path.normalize(path.join(rootPath, storagePath));
|
||||
let destination = `${fullPath}.${ext}`;
|
||||
|
||||
@@ -42,11 +42,11 @@ describe(StorageTemplateService.name, () => {
|
||||
assetMock.save.mockResolvedValue(assetEntityStub.image);
|
||||
|
||||
when(storageMock.checkFileExists)
|
||||
.calledWith('upload/user-id/2023/2023-02-23/asset-id.ext')
|
||||
.calledWith('upload/library/user-id/2023/2023-02-23/asset-id.ext')
|
||||
.mockResolvedValue(true);
|
||||
|
||||
when(storageMock.checkFileExists)
|
||||
.calledWith('upload/user-id/2023/2023-02-23/asset-id+1.ext')
|
||||
.calledWith('upload/library/user-id/2023/2023-02-23/asset-id+1.ext')
|
||||
.mockResolvedValue(false);
|
||||
|
||||
await sut.handleTemplateMigration();
|
||||
@@ -55,7 +55,7 @@ describe(StorageTemplateService.name, () => {
|
||||
expect(storageMock.checkFileExists).toHaveBeenCalledTimes(2);
|
||||
expect(assetMock.save).toHaveBeenCalledWith({
|
||||
id: assetEntityStub.image.id,
|
||||
originalPath: 'upload/user-id/2023/2023-02-23/asset-id+1.ext',
|
||||
originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id+1.ext',
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ describe(StorageTemplateService.name, () => {
|
||||
assetMock.getAll.mockResolvedValue([
|
||||
{
|
||||
...assetEntityStub.image,
|
||||
originalPath: 'upload/user-id/2023/2023-02-23/asset-id.ext',
|
||||
originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id.ext',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -79,7 +79,7 @@ describe(StorageTemplateService.name, () => {
|
||||
assetMock.getAll.mockResolvedValue([
|
||||
{
|
||||
...assetEntityStub.image,
|
||||
originalPath: 'upload/user-id/2023/2023-02-23/asset-id+1.ext',
|
||||
originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id+1.ext',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -100,11 +100,11 @@ describe(StorageTemplateService.name, () => {
|
||||
expect(assetMock.getAll).toHaveBeenCalled();
|
||||
expect(storageMock.moveFile).toHaveBeenCalledWith(
|
||||
'/original/path.ext',
|
||||
'upload/user-id/2023/2023-02-23/asset-id.ext',
|
||||
'upload/library/user-id/2023/2023-02-23/asset-id.ext',
|
||||
);
|
||||
expect(assetMock.save).toHaveBeenCalledWith({
|
||||
id: assetEntityStub.image.id,
|
||||
originalPath: 'upload/user-id/2023/2023-02-23/asset-id.ext',
|
||||
originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id.ext',
|
||||
});
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ describe(StorageTemplateService.name, () => {
|
||||
expect(assetMock.getAll).toHaveBeenCalled();
|
||||
expect(storageMock.moveFile).toHaveBeenCalledWith(
|
||||
'/original/path.ext',
|
||||
'upload/user-id/2023/2023-02-23/asset-id.ext',
|
||||
'upload/library/user-id/2023/2023-02-23/asset-id.ext',
|
||||
);
|
||||
expect(assetMock.save).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -131,11 +131,11 @@ describe(StorageTemplateService.name, () => {
|
||||
expect(assetMock.getAll).toHaveBeenCalled();
|
||||
expect(assetMock.save).toHaveBeenCalledWith({
|
||||
id: assetEntityStub.image.id,
|
||||
originalPath: 'upload/user-id/2023/2023-02-23/asset-id.ext',
|
||||
originalPath: 'upload/library/user-id/2023/2023-02-23/asset-id.ext',
|
||||
});
|
||||
expect(storageMock.moveFile.mock.calls).toEqual([
|
||||
['/original/path.ext', 'upload/user-id/2023/2023-02-23/asset-id.ext'],
|
||||
['upload/user-id/2023/2023-02-23/asset-id.ext', '/original/path.ext'],
|
||||
['/original/path.ext', 'upload/library/user-id/2023/2023-02-23/asset-id.ext'],
|
||||
['upload/library/user-id/2023/2023-02-23/asset-id.ext', '/original/path.ext'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AssetEntity, SystemConfig } from '@app/infra/db/entities';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { IAssetRepository } from '../asset/asset.repository';
|
||||
import { APP_UPLOAD_LOCATION } from '../domain.constant';
|
||||
import { APP_MEDIA_LOCATION } from '../domain.constant';
|
||||
import { IStorageRepository } from '../storage/storage.repository';
|
||||
import { INITIAL_SYSTEM_CONFIG, ISystemConfigRepository } from '../system-config';
|
||||
import { StorageTemplateCore } from './storage-template.core';
|
||||
@@ -41,7 +41,7 @@ export class StorageTemplateService {
|
||||
}
|
||||
|
||||
this.logger.debug('Cleaning up empty directories...');
|
||||
await this.storageRepository.removeEmptyDirs(APP_UPLOAD_LOCATION);
|
||||
await this.storageRepository.removeEmptyDirs(APP_MEDIA_LOCATION);
|
||||
} catch (error: any) {
|
||||
this.logger.error('Error running template migration', error);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user