mirror of
https://github.com/immich-app/immich.git
synced 2024-11-21 18:16:55 +02:00
refactor(server): storage template options (#13553)
This commit is contained in:
parent
bb694aeeeb
commit
3d971f69dc
@ -30,35 +30,6 @@ export const excludePaths = ['/.well-known/immich', '/custom.css', '/favicon.ico
|
||||
|
||||
export const FACE_THUMBNAIL_SIZE = 250;
|
||||
|
||||
export const supportedYearTokens = ['y', 'yy'];
|
||||
export const supportedMonthTokens = ['M', 'MM', 'MMM', 'MMMM'];
|
||||
export const supportedWeekTokens = ['W', 'WW'];
|
||||
export const supportedDayTokens = ['d', 'dd'];
|
||||
export const supportedHourTokens = ['h', 'hh', 'H', 'HH'];
|
||||
export const supportedMinuteTokens = ['m', 'mm'];
|
||||
export const supportedSecondTokens = ['s', 'ss', 'SSS'];
|
||||
export const supportedPresetTokens = [
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{filename}}',
|
||||
'{{y}}/{{#if album}}{{album}}{{else}}Other/{{MM}}{{/if}}/{{filename}}',
|
||||
'{{y}}/{{MMM}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
||||
'{{album}}/{{filename}}',
|
||||
];
|
||||
|
||||
type ModelInfo = { dimSize: number };
|
||||
export const CLIP_MODEL_INFO: Record<string, ModelInfo> = {
|
||||
RN101__openai: { dimSize: 512 },
|
||||
|
@ -3,12 +3,16 @@ import { ApiTags } from '@nestjs/swagger';
|
||||
import { SystemConfigDto, SystemConfigTemplateStorageOptionDto } from 'src/dtos/system-config.dto';
|
||||
import { Permission } from 'src/enum';
|
||||
import { Authenticated } from 'src/middleware/auth.guard';
|
||||
import { StorageTemplateService } from 'src/services/storage-template.service';
|
||||
import { SystemConfigService } from 'src/services/system-config.service';
|
||||
|
||||
@ApiTags('System Config')
|
||||
@Controller('system-config')
|
||||
export class SystemConfigController {
|
||||
constructor(private service: SystemConfigService) {}
|
||||
constructor(
|
||||
private service: SystemConfigService,
|
||||
private storageTemplateService: StorageTemplateService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@Authenticated({ permission: Permission.SYSTEM_CONFIG_READ, admin: true })
|
||||
@ -31,6 +35,6 @@ export class SystemConfigController {
|
||||
@Get('storage-template-options')
|
||||
@Authenticated({ permission: Permission.SYSTEM_CONFIG_READ, admin: true })
|
||||
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
|
||||
return this.service.getStorageTemplateOptions();
|
||||
return this.storageTemplateService.getStorageTemplateOptions();
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,41 @@ describe(StorageTemplateService.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStorageTemplateOptions', () => {
|
||||
it('should send back the datetime variables', () => {
|
||||
expect(sut.getStorageTemplateOptions()).toEqual({
|
||||
dayOptions: ['d', 'dd'],
|
||||
hourOptions: ['h', 'hh', 'H', 'HH'],
|
||||
minuteOptions: ['m', 'mm'],
|
||||
monthOptions: ['M', 'MM', 'MMM', 'MMMM'],
|
||||
presetOptions: [
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{filename}}',
|
||||
'{{y}}/{{#if album}}{{album}}{{else}}Other/{{MM}}{{/if}}/{{filename}}',
|
||||
'{{y}}/{{MMM}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
||||
'{{album}}/{{filename}}',
|
||||
],
|
||||
secondOptions: ['s', 'ss', 'SSS'],
|
||||
weekOptions: ['W', 'WW'],
|
||||
yearOptions: ['y', 'yy'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleMigrationSingle', () => {
|
||||
it('should skip when storage template is disabled', async () => {
|
||||
systemMock.get.mockResolvedValue({ storageTemplate: { enabled: false } });
|
||||
|
@ -3,17 +3,9 @@ import handlebar from 'handlebars';
|
||||
import { DateTime } from 'luxon';
|
||||
import path from 'node:path';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import {
|
||||
supportedDayTokens,
|
||||
supportedHourTokens,
|
||||
supportedMinuteTokens,
|
||||
supportedMonthTokens,
|
||||
supportedSecondTokens,
|
||||
supportedWeekTokens,
|
||||
supportedYearTokens,
|
||||
} from 'src/constants';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { OnEvent } from 'src/decorators';
|
||||
import { SystemConfigTemplateStorageOptionDto } from 'src/dtos/system-config.dto';
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
import { AssetPathType, AssetType, StorageFolder } from 'src/enum';
|
||||
import { DatabaseLock } from 'src/interfaces/database.interface';
|
||||
@ -23,6 +15,38 @@ import { BaseService } from 'src/services/base.service';
|
||||
import { getLivePhotoMotionFilename } from 'src/utils/file';
|
||||
import { usePagination } from 'src/utils/pagination';
|
||||
|
||||
const storageTokens = {
|
||||
secondOptions: ['s', 'ss', 'SSS'],
|
||||
minuteOptions: ['m', 'mm'],
|
||||
dayOptions: ['d', 'dd'],
|
||||
weekOptions: ['W', 'WW'],
|
||||
hourOptions: ['h', 'hh', 'H', 'HH'],
|
||||
yearOptions: ['y', 'yy'],
|
||||
monthOptions: ['M', 'MM', 'MMM', 'MMMM'],
|
||||
};
|
||||
|
||||
const storagePresets = [
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{filename}}',
|
||||
'{{y}}/{{#if album}}{{album}}{{else}}Other/{{MM}}{{/if}}/{{filename}}',
|
||||
'{{y}}/{{MMM}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
||||
'{{album}}/{{filename}}',
|
||||
];
|
||||
|
||||
export interface MoveAssetMetadata {
|
||||
storageLabel: string | null;
|
||||
filename: string;
|
||||
@ -80,6 +104,10 @@ export class StorageTemplateService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
|
||||
return { ...storageTokens, presetOptions: storagePresets };
|
||||
}
|
||||
|
||||
async handleMigrationSingle({ id }: IEntityJob): Promise<JobStatus> {
|
||||
const config = await this.getConfig({ withCache: true });
|
||||
const storageTemplateEnabled = config.storageTemplate.enabled;
|
||||
@ -277,17 +305,7 @@ export class StorageTemplateService extends BaseService {
|
||||
const zone = asset.exifInfo?.timeZone || systemTimeZone;
|
||||
const dt = DateTime.fromJSDate(asset.fileCreatedAt, { zone });
|
||||
|
||||
const dateTokens = [
|
||||
...supportedYearTokens,
|
||||
...supportedMonthTokens,
|
||||
...supportedWeekTokens,
|
||||
...supportedDayTokens,
|
||||
...supportedHourTokens,
|
||||
...supportedMinuteTokens,
|
||||
...supportedSecondTokens,
|
||||
];
|
||||
|
||||
for (const token of dateTokens) {
|
||||
for (const token of Object.values(storageTokens).flat()) {
|
||||
substitutions[token] = dt.toFormat(token);
|
||||
}
|
||||
|
||||
|
@ -341,41 +341,6 @@ describe(SystemConfigService.name, () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe('getStorageTemplateOptions', () => {
|
||||
it('should send back the datetime variables', () => {
|
||||
expect(sut.getStorageTemplateOptions()).toEqual({
|
||||
dayOptions: ['d', 'dd'],
|
||||
hourOptions: ['h', 'hh', 'H', 'HH'],
|
||||
minuteOptions: ['m', 'mm'],
|
||||
monthOptions: ['M', 'MM', 'MMM', 'MMMM'],
|
||||
presetOptions: [
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{filename}}',
|
||||
'{{y}}/{{#if album}}{{album}}{{else}}Other/{{MM}}{{/if}}/{{filename}}',
|
||||
'{{y}}/{{MMM}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{filename}}',
|
||||
'{{y}}/{{MM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{MMMM}}/{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}-{{MMMM}}-{{dd}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{filename}}',
|
||||
'{{y}}/{{y}}-{{MM}}-{{dd}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{MM}}/{{assetId}}',
|
||||
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
||||
'{{album}}/{{filename}}',
|
||||
],
|
||||
secondOptions: ['s', 'ss', 'SSS'],
|
||||
weekOptions: ['W', 'WW'],
|
||||
yearOptions: ['y', 'yy'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateConfig', () => {
|
||||
it('should update the config and emit an event', async () => {
|
||||
systemMock.get.mockResolvedValue(partialConfig);
|
||||
|
@ -2,18 +2,8 @@ import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { instanceToPlain } from 'class-transformer';
|
||||
import _ from 'lodash';
|
||||
import { defaults } from 'src/config';
|
||||
import {
|
||||
supportedDayTokens,
|
||||
supportedHourTokens,
|
||||
supportedMinuteTokens,
|
||||
supportedMonthTokens,
|
||||
supportedPresetTokens,
|
||||
supportedSecondTokens,
|
||||
supportedWeekTokens,
|
||||
supportedYearTokens,
|
||||
} from 'src/constants';
|
||||
import { OnEvent } from 'src/decorators';
|
||||
import { SystemConfigDto, SystemConfigTemplateStorageOptionDto, mapConfig } from 'src/dtos/system-config.dto';
|
||||
import { SystemConfigDto, mapConfig } from 'src/dtos/system-config.dto';
|
||||
import { ArgOf } from 'src/interfaces/event.interface';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { clearConfigCache } from 'src/utils/config';
|
||||
@ -77,21 +67,6 @@ export class SystemConfigService extends BaseService {
|
||||
return mapConfig(newConfig);
|
||||
}
|
||||
|
||||
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
|
||||
const options = new SystemConfigTemplateStorageOptionDto();
|
||||
|
||||
options.dayOptions = supportedDayTokens;
|
||||
options.weekOptions = supportedWeekTokens;
|
||||
options.monthOptions = supportedMonthTokens;
|
||||
options.yearOptions = supportedYearTokens;
|
||||
options.hourOptions = supportedHourTokens;
|
||||
options.secondOptions = supportedSecondTokens;
|
||||
options.minuteOptions = supportedMinuteTokens;
|
||||
options.presetOptions = supportedPresetTokens;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
async getCustomCss(): Promise<string> {
|
||||
const { theme } = await this.getConfig({ withCache: false });
|
||||
return theme.customCss;
|
||||
|
Loading…
Reference in New Issue
Block a user