Files
immich/server/src/services/system-config.service.ts
2025-07-15 13:41:19 -04:00

80 lines
3.0 KiB
TypeScript

import { BadRequestException, Injectable } from '@nestjs/common';
import { instanceToPlain } from 'class-transformer';
import _ from 'lodash';
import { defaults } from 'src/config';
import { OnEvent } from 'src/decorators';
import { mapConfig, SystemConfigDto } from 'src/dtos/system-config.dto';
import { BootstrapEventPriority } from 'src/enum';
import { ArgOf } from 'src/repositories/event.repository';
import { BaseService } from 'src/services/base.service';
import { clearConfigCache } from 'src/utils/config';
import { toPlainObject } from 'src/utils/object';
@Injectable()
export class SystemConfigService extends BaseService {
@OnEvent({ name: 'AppBootstrap', priority: BootstrapEventPriority.SystemConfig })
async onBootstrap() {
const config = await this.getConfig({ withCache: false });
await this.eventRepository.emit('ConfigInit', { newConfig: config });
}
async getSystemConfig(): Promise<SystemConfigDto> {
const config = await this.getConfig({ withCache: false });
return mapConfig(config);
}
getDefaults(): SystemConfigDto {
return mapConfig(defaults);
}
@OnEvent({ name: 'ConfigInit', priority: -100 })
onConfigInit({ newConfig: { logging } }: ArgOf<'ConfigInit'>) {
const { logLevel: envLevel } = this.configRepository.getEnv();
const configLevel = logging.enabled ? logging.level : false;
const level = envLevel ?? configLevel;
this.logger.setLogLevel(level);
this.logger.log(`LogLevel=${level} ${envLevel ? '(set via IMMICH_LOG_LEVEL)' : '(set via system config)'}`);
}
@OnEvent({ name: 'ConfigUpdate', server: true })
onConfigUpdate({ newConfig }: ArgOf<'ConfigUpdate'>) {
this.onConfigInit({ newConfig });
clearConfigCache();
}
@OnEvent({ name: 'ConfigValidate' })
onConfigValidate({ newConfig, oldConfig }: ArgOf<'ConfigValidate'>) {
const { logLevel } = this.configRepository.getEnv();
if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && logLevel) {
throw new Error('Logging cannot be changed while the environment variable IMMICH_LOG_LEVEL is set.');
}
}
async updateSystemConfig(dto: SystemConfigDto): Promise<SystemConfigDto> {
const { configFile } = this.configRepository.getEnv();
if (configFile) {
throw new BadRequestException('Cannot update configuration while IMMICH_CONFIG_FILE is in use');
}
const oldConfig = await this.getConfig({ withCache: false });
try {
await this.eventRepository.emit('ConfigValidate', { newConfig: toPlainObject(dto), oldConfig });
} catch (error) {
this.logger.warn(`Unable to save system config due to a validation error: ${error}`);
throw new BadRequestException(error instanceof Error ? error.message : error);
}
const newConfig = await this.updateConfig(dto);
await this.eventRepository.emit('ConfigUpdate', { newConfig, oldConfig });
return mapConfig(newConfig);
}
async getCustomCss(): Promise<string> {
const { theme } = await this.getConfig({ withCache: false });
return theme.customCss;
}
}