2024-10-02 10:54:35 -04:00
|
|
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
2023-12-14 11:55:40 -05:00
|
|
|
import { instanceToPlain } from 'class-transformer';
|
|
|
|
|
import _ from 'lodash';
|
2024-09-30 10:35:11 -04:00
|
|
|
import { defaults } from 'src/config';
|
2023-01-21 11:11:55 -05:00
|
|
|
import {
|
|
|
|
|
supportedDayTokens,
|
|
|
|
|
supportedHourTokens,
|
|
|
|
|
supportedMinuteTokens,
|
|
|
|
|
supportedMonthTokens,
|
|
|
|
|
supportedPresetTokens,
|
|
|
|
|
supportedSecondTokens,
|
2023-09-28 19:47:31 +02:00
|
|
|
supportedWeekTokens,
|
2023-01-21 11:11:55 -05:00
|
|
|
supportedYearTokens,
|
2024-03-20 22:15:09 -05:00
|
|
|
} from 'src/constants';
|
2024-09-30 10:35:11 -04:00
|
|
|
import { OnEvent } from 'src/decorators';
|
2024-03-22 16:36:20 -04:00
|
|
|
import { SystemConfigDto, SystemConfigTemplateStorageOptionDto, mapConfig } from 'src/dtos/system-config.dto';
|
2024-10-02 10:54:35 -04:00
|
|
|
import { ArgOf } from 'src/interfaces/event.interface';
|
2024-09-30 17:31:21 -04:00
|
|
|
import { BaseService } from 'src/services/base.service';
|
2024-10-01 16:03:55 -04:00
|
|
|
import { clearConfigCache } from 'src/utils/config';
|
2024-08-29 20:10:09 +02:00
|
|
|
import { toPlainObject } from 'src/utils/object';
|
2023-01-21 11:11:55 -05:00
|
|
|
|
|
|
|
|
@Injectable()
|
2024-09-30 17:31:21 -04:00
|
|
|
export class SystemConfigService extends BaseService {
|
2024-09-30 10:35:11 -04:00
|
|
|
@OnEvent({ name: 'app.bootstrap', priority: -100 })
|
2024-08-15 16:12:41 -04:00
|
|
|
async onBootstrap() {
|
2024-09-30 17:31:21 -04:00
|
|
|
const config = await this.getConfig({ withCache: false });
|
2024-09-30 10:35:11 -04:00
|
|
|
await this.eventRepository.emit('config.update', { newConfig: config });
|
2023-01-21 11:11:55 -05:00
|
|
|
}
|
|
|
|
|
|
2024-09-30 17:31:21 -04:00
|
|
|
async getSystemConfig(): Promise<SystemConfigDto> {
|
|
|
|
|
const config = await this.getConfig({ withCache: false });
|
2023-01-21 11:11:55 -05:00
|
|
|
return mapConfig(config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getDefaults(): SystemConfigDto {
|
2024-05-14 14:43:49 -04:00
|
|
|
return mapConfig(defaults);
|
2023-01-21 11:11:55 -05:00
|
|
|
}
|
|
|
|
|
|
2024-09-30 10:35:11 -04:00
|
|
|
@OnEvent({ name: 'config.update', server: true })
|
|
|
|
|
onConfigUpdate({ newConfig: { logging } }: ArgOf<'config.update'>) {
|
2024-10-02 08:37:26 -04:00
|
|
|
const { logLevel: envLevel } = this.configRepository.getEnv();
|
2024-09-30 10:35:11 -04:00
|
|
|
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)'}`);
|
|
|
|
|
// TODO only do this if the event is a socket.io event
|
2024-09-30 17:31:21 -04:00
|
|
|
clearConfigCache();
|
2024-09-30 10:35:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@OnEvent({ name: 'config.validate' })
|
2024-08-27 18:06:50 -04:00
|
|
|
onConfigValidate({ newConfig, oldConfig }: ArgOf<'config.validate'>) {
|
2024-10-02 08:37:26 -04:00
|
|
|
const { logLevel } = this.configRepository.getEnv();
|
|
|
|
|
if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && logLevel) {
|
2024-05-17 11:44:22 -04:00
|
|
|
throw new Error('Logging cannot be changed while the environment variable IMMICH_LOG_LEVEL is set.');
|
2024-03-17 20:16:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-30 17:31:21 -04:00
|
|
|
async updateSystemConfig(dto: SystemConfigDto): Promise<SystemConfigDto> {
|
2024-10-01 16:03:55 -04:00
|
|
|
const { configFile } = this.configRepository.getEnv();
|
|
|
|
|
if (configFile) {
|
2024-05-14 15:31:36 -04:00
|
|
|
throw new BadRequestException('Cannot update configuration while IMMICH_CONFIG_FILE is in use');
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-30 17:31:21 -04:00
|
|
|
const oldConfig = await this.getConfig({ withCache: false });
|
2024-03-17 20:16:02 +01:00
|
|
|
|
|
|
|
|
try {
|
2024-08-29 20:10:09 +02:00
|
|
|
await this.eventRepository.emit('config.validate', { newConfig: toPlainObject(dto), oldConfig });
|
2024-03-17 20:16:02 +01:00
|
|
|
} 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);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-30 17:31:21 -04:00
|
|
|
const newConfig = await this.updateConfig(dto);
|
2023-12-13 12:23:51 -05:00
|
|
|
|
2024-08-27 18:06:50 -04:00
|
|
|
await this.eventRepository.emit('config.update', { newConfig, oldConfig });
|
2023-12-13 12:23:51 -05:00
|
|
|
|
2023-12-08 11:15:46 -05:00
|
|
|
return mapConfig(newConfig);
|
2023-01-21 11:11:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
|
|
|
|
|
const options = new SystemConfigTemplateStorageOptionDto();
|
|
|
|
|
|
|
|
|
|
options.dayOptions = supportedDayTokens;
|
2023-09-28 19:47:31 +02:00
|
|
|
options.weekOptions = supportedWeekTokens;
|
2023-01-21 11:11:55 -05:00
|
|
|
options.monthOptions = supportedMonthTokens;
|
|
|
|
|
options.yearOptions = supportedYearTokens;
|
|
|
|
|
options.hourOptions = supportedHourTokens;
|
|
|
|
|
options.secondOptions = supportedSecondTokens;
|
|
|
|
|
options.minuteOptions = supportedMinuteTokens;
|
|
|
|
|
options.presetOptions = supportedPresetTokens;
|
|
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
}
|
2023-11-09 17:10:56 +01:00
|
|
|
|
2023-11-17 23:13:36 -05:00
|
|
|
async getCustomCss(): Promise<string> {
|
2024-09-30 17:31:21 -04:00
|
|
|
const { theme } = await this.getConfig({ withCache: false });
|
2023-11-17 23:13:36 -05:00
|
|
|
return theme.customCss;
|
|
|
|
|
}
|
2023-01-21 11:11:55 -05:00
|
|
|
}
|