mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(server) user-defined storage structure (#1098)
[Breaking] newly uploaded file will conform to the default structure of `{uploadLocation}/{userId}/year/year-month-day/filename.ext`
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import { SystemConfig, SystemConfigEntity, SystemConfigKey } from '@app/database/entities/system-config.entity';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import * as _ from 'lodash';
|
||||
import { Subject } from 'rxjs';
|
||||
import { DeepPartial, In, Repository } from 'typeorm';
|
||||
|
||||
export type SystemConfigValidator = (config: SystemConfig) => void | Promise<void>;
|
||||
|
||||
const defaults: SystemConfig = Object.freeze({
|
||||
ffmpeg: {
|
||||
crf: '23',
|
||||
@@ -21,10 +24,19 @@ const defaults: SystemConfig = Object.freeze({
|
||||
buttonText: 'Login with OAuth',
|
||||
autoRegister: true,
|
||||
},
|
||||
|
||||
storageTemplate: {
|
||||
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
|
||||
},
|
||||
});
|
||||
|
||||
@Injectable()
|
||||
export class ImmichConfigService {
|
||||
private logger = new Logger(ImmichConfigService.name);
|
||||
private validators: SystemConfigValidator[] = [];
|
||||
|
||||
public config$ = new Subject<SystemConfig>();
|
||||
|
||||
constructor(
|
||||
@InjectRepository(SystemConfigEntity)
|
||||
private systemConfigRepository: Repository<SystemConfigEntity>,
|
||||
@@ -34,6 +46,10 @@ export class ImmichConfigService {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
public addValidator(validator: SystemConfigValidator) {
|
||||
this.validators.push(validator);
|
||||
}
|
||||
|
||||
public async getConfig() {
|
||||
const overrides = await this.systemConfigRepository.find();
|
||||
const config: DeepPartial<SystemConfig> = {};
|
||||
@@ -45,7 +61,16 @@ export class ImmichConfigService {
|
||||
return _.defaultsDeep(config, defaults) as SystemConfig;
|
||||
}
|
||||
|
||||
public async updateConfig(config: DeepPartial<SystemConfig> | null): Promise<void> {
|
||||
public async updateConfig(config: SystemConfig): Promise<SystemConfig> {
|
||||
try {
|
||||
for (const validator of this.validators) {
|
||||
await validator(config);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.warn(`Unable to save system config due to a validation error: ${e}`);
|
||||
throw new BadRequestException(e instanceof Error ? e.message : e);
|
||||
}
|
||||
|
||||
const updates: SystemConfigEntity[] = [];
|
||||
const deletes: SystemConfigEntity[] = [];
|
||||
|
||||
@@ -70,5 +95,11 @@ export class ImmichConfigService {
|
||||
if (deletes.length > 0) {
|
||||
await this.systemConfigRepository.delete({ key: In(deletes.map((item) => item.key)) });
|
||||
}
|
||||
|
||||
const newConfig = await this.getConfig();
|
||||
|
||||
this.config$.next(newConfig);
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user