mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat(server,web): server config (#4006)
* feat: server config * chore: open api * fix: redirect /map to /photos when disabled
This commit is contained in:
parent
3edade6761
commit
f1db257628
48 changed files with 1103 additions and 162 deletions
|
|
@ -79,16 +79,21 @@ export class ServerMediaTypesResponseDto {
|
|||
sidecar!: string[];
|
||||
}
|
||||
|
||||
export class ServerFeaturesDto implements FeatureFlags {
|
||||
configFile!: boolean;
|
||||
clipEncode!: boolean;
|
||||
facialRecognition!: boolean;
|
||||
sidecar!: boolean;
|
||||
search!: boolean;
|
||||
tagImage!: boolean;
|
||||
export class ServerConfigDto {
|
||||
oauthButtonText!: string;
|
||||
loginPageMessage!: string;
|
||||
mapTileUrl!: string;
|
||||
}
|
||||
|
||||
// TODO: use these instead of `POST oauth/config`
|
||||
export class ServerFeaturesDto implements FeatureFlags {
|
||||
clipEncode!: boolean;
|
||||
configFile!: boolean;
|
||||
facialRecognition!: boolean;
|
||||
map!: boolean;
|
||||
oauth!: boolean;
|
||||
oauthAutoLaunch!: boolean;
|
||||
passwordLogin!: boolean;
|
||||
sidecar!: boolean;
|
||||
search!: boolean;
|
||||
tagImage!: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,22 +143,34 @@ describe(ServerInfoService.name, () => {
|
|||
it('should respond the server version', () => {
|
||||
expect(sut.getVersion()).toEqual(serverVersion);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFeatures', () => {
|
||||
it('should respond the server features', async () => {
|
||||
await expect(sut.getFeatures()).resolves.toEqual({
|
||||
clipEncode: true,
|
||||
facialRecognition: true,
|
||||
oauth: false,
|
||||
oauthAutoLaunch: false,
|
||||
passwordLogin: true,
|
||||
search: true,
|
||||
sidecar: true,
|
||||
tagImage: true,
|
||||
configFile: false,
|
||||
});
|
||||
expect(configMock.load).toHaveBeenCalled();
|
||||
describe('getFeatures', () => {
|
||||
it('should respond the server features', async () => {
|
||||
await expect(sut.getFeatures()).resolves.toEqual({
|
||||
clipEncode: true,
|
||||
facialRecognition: true,
|
||||
map: true,
|
||||
oauth: false,
|
||||
oauthAutoLaunch: false,
|
||||
passwordLogin: true,
|
||||
search: true,
|
||||
sidecar: true,
|
||||
tagImage: true,
|
||||
configFile: false,
|
||||
});
|
||||
expect(configMock.load).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConfig', () => {
|
||||
it('should respond the server configuration', async () => {
|
||||
await expect(sut.getConfig()).resolves.toEqual({
|
||||
loginPageMessage: '',
|
||||
oauthButtonText: 'Login with OAuth',
|
||||
mapTileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
});
|
||||
expect(configMock.load).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { IStorageRepository, StorageCore, StorageFolder } from '../storage';
|
|||
import { ISystemConfigRepository, SystemConfigCore } from '../system-config';
|
||||
import { IUserRepository, UserStatsQueryResponse } from '../user';
|
||||
import {
|
||||
ServerConfigDto,
|
||||
ServerFeaturesDto,
|
||||
ServerInfoResponseDto,
|
||||
ServerMediaTypesResponseDto,
|
||||
|
|
@ -55,6 +56,19 @@ export class ServerInfoService {
|
|||
return this.configCore.getFeatures();
|
||||
}
|
||||
|
||||
async getConfig(): Promise<ServerConfigDto> {
|
||||
const config = await this.configCore.getConfig();
|
||||
|
||||
// TODO move to system config
|
||||
const loginPageMessage = process.env.PUBLIC_LOGIN_PAGE_MESSAGE || '';
|
||||
|
||||
return {
|
||||
loginPageMessage,
|
||||
mapTileUrl: config.map.tileUrl,
|
||||
oauthButtonText: config.oauth.buttonText,
|
||||
};
|
||||
}
|
||||
|
||||
async getStats(): Promise<ServerStatsResponseDto> {
|
||||
const userStats: UserStatsQueryResponse[] = await this.userRepository.getUserStats();
|
||||
const serverStats = new ServerStatsResponseDto();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { IsBoolean, IsString } from 'class-validator';
|
||||
|
||||
export class SystemConfigMapDto {
|
||||
@IsBoolean()
|
||||
enabled!: boolean;
|
||||
|
||||
@IsString()
|
||||
tileUrl!: string;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { IsObject, ValidateNested } from 'class-validator';
|
|||
import { SystemConfigFFmpegDto } from './system-config-ffmpeg.dto';
|
||||
import { SystemConfigJobDto } from './system-config-job.dto';
|
||||
import { SystemConfigMachineLearningDto } from './system-config-machine-learning.dto';
|
||||
import { SystemConfigMapDto } from './system-config-map.dto';
|
||||
import { SystemConfigOAuthDto } from './system-config-oauth.dto';
|
||||
import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto';
|
||||
import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto';
|
||||
|
|
@ -20,6 +21,11 @@ export class SystemConfigDto implements SystemConfig {
|
|||
@IsObject()
|
||||
machineLearning!: SystemConfigMachineLearningDto;
|
||||
|
||||
@Type(() => SystemConfigMapDto)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
map!: SystemConfigMapDto;
|
||||
|
||||
@Type(() => SystemConfigOAuthDto)
|
||||
@ValidateNested()
|
||||
@IsObject()
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||
[QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 },
|
||||
[QueueName.VIDEO_CONVERSION]: { concurrency: 1 },
|
||||
},
|
||||
|
||||
machineLearning: {
|
||||
enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false',
|
||||
url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003',
|
||||
|
|
@ -75,6 +74,10 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||
maxDistance: 0.6,
|
||||
},
|
||||
},
|
||||
map: {
|
||||
enabled: true,
|
||||
tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
},
|
||||
oauth: {
|
||||
enabled: false,
|
||||
issuerUrl: '',
|
||||
|
|
@ -108,6 +111,7 @@ export enum FeatureFlag {
|
|||
CLIP_ENCODE = 'clipEncode',
|
||||
FACIAL_RECOGNITION = 'facialRecognition',
|
||||
TAG_IMAGE = 'tagImage',
|
||||
MAP = 'map',
|
||||
SIDECAR = 'sidecar',
|
||||
SEARCH = 'search',
|
||||
OAUTH = 'oauth',
|
||||
|
|
@ -169,6 +173,7 @@ export class SystemConfigCore {
|
|||
[FeatureFlag.CLIP_ENCODE]: mlEnabled && config.machineLearning.clip.enabled,
|
||||
[FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled,
|
||||
[FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.classification.enabled,
|
||||
[FeatureFlag.MAP]: config.map.enabled,
|
||||
[FeatureFlag.SIDECAR]: true,
|
||||
[FeatureFlag.SEARCH]: process.env.TYPESENSE_ENABLED !== 'false',
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ const updatedConfig = Object.freeze<SystemConfig>({
|
|||
maxDistance: 0.6,
|
||||
},
|
||||
},
|
||||
map: {
|
||||
enabled: true,
|
||||
tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
},
|
||||
oauth: {
|
||||
autoLaunch: true,
|
||||
autoRegister: true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
ServerConfigDto,
|
||||
ServerFeaturesDto,
|
||||
ServerInfoResponseDto,
|
||||
ServerInfoService,
|
||||
|
|
@ -42,6 +43,12 @@ export class ServerInfoController {
|
|||
return this.service.getFeatures();
|
||||
}
|
||||
|
||||
@PublicRoute()
|
||||
@Get('config')
|
||||
getServerConfig(): Promise<ServerConfigDto> {
|
||||
return this.service.getConfig();
|
||||
}
|
||||
|
||||
@AdminRoute()
|
||||
@Get('stats')
|
||||
getStats(): Promise<ServerStatsResponseDto> {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ export enum SystemConfigKey {
|
|||
MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_SCORE = 'machineLearning.facialRecognition.minScore',
|
||||
MACHINE_LEARNING_FACIAL_RECOGNITION_MAX_DISTANCE = 'machineLearning.facialRecognition.maxDistance',
|
||||
|
||||
MAP_ENABLED = 'map.enabled',
|
||||
MAP_TILE_URL = 'map.tileUrl',
|
||||
|
||||
OAUTH_ENABLED = 'oauth.enabled',
|
||||
OAUTH_ISSUER_URL = 'oauth.issuerUrl',
|
||||
OAUTH_CLIENT_ID = 'oauth.clientId',
|
||||
|
|
@ -164,6 +167,10 @@ export interface SystemConfig {
|
|||
maxDistance: number;
|
||||
};
|
||||
};
|
||||
map: {
|
||||
enabled: boolean;
|
||||
tileUrl: string;
|
||||
};
|
||||
oauth: {
|
||||
enabled: boolean;
|
||||
issuerUrl: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue