mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 15:52:34 +09: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:
		
							
								
								
									
										112
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										112
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -2343,6 +2343,31 @@ export interface SearchResponseDto {
 | 
			
		||||
     */
 | 
			
		||||
    'assets': SearchAssetResponseDto;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface ServerConfigDto
 | 
			
		||||
 */
 | 
			
		||||
export interface ServerConfigDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'loginPageMessage': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'mapTileUrl': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'oauthButtonText': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
@@ -2367,6 +2392,12 @@ export interface ServerFeaturesDto {
 | 
			
		||||
     * @memberof ServerFeaturesDto
 | 
			
		||||
     */
 | 
			
		||||
    'facialRecognition': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
     * @memberof ServerFeaturesDto
 | 
			
		||||
     */
 | 
			
		||||
    'map': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
@@ -2810,6 +2841,12 @@ export interface SystemConfigDto {
 | 
			
		||||
     * @memberof SystemConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'machineLearning': SystemConfigMachineLearningDto;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {SystemConfigMapDto}
 | 
			
		||||
     * @memberof SystemConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'map': SystemConfigMapDto;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {SystemConfigOAuthDto}
 | 
			
		||||
@@ -3050,6 +3087,25 @@ export interface SystemConfigMachineLearningDto {
 | 
			
		||||
     */
 | 
			
		||||
    'url': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface SystemConfigMapDto
 | 
			
		||||
 */
 | 
			
		||||
export interface SystemConfigMapDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
     * @memberof SystemConfigMapDto
 | 
			
		||||
     */
 | 
			
		||||
    'enabled': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof SystemConfigMapDto
 | 
			
		||||
     */
 | 
			
		||||
    'tileUrl': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
@@ -10825,6 +10881,35 @@ export class SearchApi extends BaseAPI {
 | 
			
		||||
 */
 | 
			
		||||
export const ServerInfoApiAxiosParamCreator = function (configuration?: Configuration) {
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getServerConfig: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
			
		||||
            const localVarPath = `/server-info/config`;
 | 
			
		||||
            // use dummy base URL string because the URL constructor only accepts absolute URLs.
 | 
			
		||||
            const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
 | 
			
		||||
            let baseOptions;
 | 
			
		||||
            if (configuration) {
 | 
			
		||||
                baseOptions = configuration.baseOptions;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
 | 
			
		||||
            const localVarHeaderParameter = {} as any;
 | 
			
		||||
            const localVarQueryParameter = {} as any;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
			
		||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
			
		||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                url: toPathString(localVarUrlObj),
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11027,6 +11112,15 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur
 | 
			
		||||
export const ServerInfoApiFp = function(configuration?: Configuration) {
 | 
			
		||||
    const localVarAxiosParamCreator = ServerInfoApiAxiosParamCreator(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        async getServerConfig(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ServerConfigDto>> {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.getServerConfig(options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11091,6 +11185,14 @@ export const ServerInfoApiFp = function(configuration?: Configuration) {
 | 
			
		||||
export const ServerInfoApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
 | 
			
		||||
    const localVarFp = ServerInfoApiFp(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getServerConfig(options?: AxiosRequestConfig): AxiosPromise<ServerConfigDto> {
 | 
			
		||||
            return localVarFp.getServerConfig(options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11149,6 +11251,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas
 | 
			
		||||
 * @extends {BaseAPI}
 | 
			
		||||
 */
 | 
			
		||||
export class ServerInfoApi extends BaseAPI {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
     * @throws {RequiredError}
 | 
			
		||||
     * @memberof ServerInfoApi
 | 
			
		||||
     */
 | 
			
		||||
    public getServerConfig(options?: AxiosRequestConfig) {
 | 
			
		||||
        return ServerInfoApiFp(this.configuration).getServerConfig(options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							@@ -97,6 +97,7 @@ doc/SearchExploreResponseDto.md
 | 
			
		||||
doc/SearchFacetCountResponseDto.md
 | 
			
		||||
doc/SearchFacetResponseDto.md
 | 
			
		||||
doc/SearchResponseDto.md
 | 
			
		||||
doc/ServerConfigDto.md
 | 
			
		||||
doc/ServerFeaturesDto.md
 | 
			
		||||
doc/ServerInfoApi.md
 | 
			
		||||
doc/ServerInfoResponseDto.md
 | 
			
		||||
@@ -116,6 +117,7 @@ doc/SystemConfigDto.md
 | 
			
		||||
doc/SystemConfigFFmpegDto.md
 | 
			
		||||
doc/SystemConfigJobDto.md
 | 
			
		||||
doc/SystemConfigMachineLearningDto.md
 | 
			
		||||
doc/SystemConfigMapDto.md
 | 
			
		||||
doc/SystemConfigOAuthDto.md
 | 
			
		||||
doc/SystemConfigPasswordLoginDto.md
 | 
			
		||||
doc/SystemConfigStorageTemplateDto.md
 | 
			
		||||
@@ -249,6 +251,7 @@ lib/model/search_explore_response_dto.dart
 | 
			
		||||
lib/model/search_facet_count_response_dto.dart
 | 
			
		||||
lib/model/search_facet_response_dto.dart
 | 
			
		||||
lib/model/search_response_dto.dart
 | 
			
		||||
lib/model/server_config_dto.dart
 | 
			
		||||
lib/model/server_features_dto.dart
 | 
			
		||||
lib/model/server_info_response_dto.dart
 | 
			
		||||
lib/model/server_media_types_response_dto.dart
 | 
			
		||||
@@ -265,6 +268,7 @@ lib/model/system_config_dto.dart
 | 
			
		||||
lib/model/system_config_f_fmpeg_dto.dart
 | 
			
		||||
lib/model/system_config_job_dto.dart
 | 
			
		||||
lib/model/system_config_machine_learning_dto.dart
 | 
			
		||||
lib/model/system_config_map_dto.dart
 | 
			
		||||
lib/model/system_config_o_auth_dto.dart
 | 
			
		||||
lib/model/system_config_password_login_dto.dart
 | 
			
		||||
lib/model/system_config_storage_template_dto.dart
 | 
			
		||||
@@ -382,6 +386,7 @@ test/search_explore_response_dto_test.dart
 | 
			
		||||
test/search_facet_count_response_dto_test.dart
 | 
			
		||||
test/search_facet_response_dto_test.dart
 | 
			
		||||
test/search_response_dto_test.dart
 | 
			
		||||
test/server_config_dto_test.dart
 | 
			
		||||
test/server_features_dto_test.dart
 | 
			
		||||
test/server_info_api_test.dart
 | 
			
		||||
test/server_info_response_dto_test.dart
 | 
			
		||||
@@ -401,6 +406,7 @@ test/system_config_dto_test.dart
 | 
			
		||||
test/system_config_f_fmpeg_dto_test.dart
 | 
			
		||||
test/system_config_job_dto_test.dart
 | 
			
		||||
test/system_config_machine_learning_dto_test.dart
 | 
			
		||||
test/system_config_map_dto_test.dart
 | 
			
		||||
test/system_config_o_auth_dto_test.dart
 | 
			
		||||
test/system_config_password_login_dto_test.dart
 | 
			
		||||
test/system_config_storage_template_dto_test.dart
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							@@ -142,6 +142,7 @@ Class | Method | HTTP request | Description
 | 
			
		||||
*PersonApi* | [**updatePerson**](doc//PersonApi.md#updateperson) | **PUT** /person/{id} | 
 | 
			
		||||
*SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore | 
 | 
			
		||||
*SearchApi* | [**search**](doc//SearchApi.md#search) | **GET** /search | 
 | 
			
		||||
*ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | 
 | 
			
		||||
*ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | 
 | 
			
		||||
*ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info | 
 | 
			
		||||
*ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | 
 | 
			
		||||
@@ -266,6 +267,7 @@ Class | Method | HTTP request | Description
 | 
			
		||||
 - [SearchFacetCountResponseDto](doc//SearchFacetCountResponseDto.md)
 | 
			
		||||
 - [SearchFacetResponseDto](doc//SearchFacetResponseDto.md)
 | 
			
		||||
 - [SearchResponseDto](doc//SearchResponseDto.md)
 | 
			
		||||
 - [ServerConfigDto](doc//ServerConfigDto.md)
 | 
			
		||||
 - [ServerFeaturesDto](doc//ServerFeaturesDto.md)
 | 
			
		||||
 - [ServerInfoResponseDto](doc//ServerInfoResponseDto.md)
 | 
			
		||||
 - [ServerMediaTypesResponseDto](doc//ServerMediaTypesResponseDto.md)
 | 
			
		||||
@@ -282,6 +284,7 @@ Class | Method | HTTP request | Description
 | 
			
		||||
 - [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md)
 | 
			
		||||
 - [SystemConfigJobDto](doc//SystemConfigJobDto.md)
 | 
			
		||||
 - [SystemConfigMachineLearningDto](doc//SystemConfigMachineLearningDto.md)
 | 
			
		||||
 - [SystemConfigMapDto](doc//SystemConfigMapDto.md)
 | 
			
		||||
 - [SystemConfigOAuthDto](doc//SystemConfigOAuthDto.md)
 | 
			
		||||
 - [SystemConfigPasswordLoginDto](doc//SystemConfigPasswordLoginDto.md)
 | 
			
		||||
 - [SystemConfigStorageTemplateDto](doc//SystemConfigStorageTemplateDto.md)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								mobile/openapi/doc/ServerConfigDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								mobile/openapi/doc/ServerConfigDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
# openapi.model.ServerConfigDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**loginPageMessage** | **String** |  | 
 | 
			
		||||
**mapTileUrl** | **String** |  | 
 | 
			
		||||
**oauthButtonText** | **String** |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								mobile/openapi/doc/ServerFeaturesDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/doc/ServerFeaturesDto.md
									
									
									
										generated
									
									
									
								
							@@ -11,6 +11,7 @@ Name | Type | Description | Notes
 | 
			
		||||
**clipEncode** | **bool** |  | 
 | 
			
		||||
**configFile** | **bool** |  | 
 | 
			
		||||
**facialRecognition** | **bool** |  | 
 | 
			
		||||
**map** | **bool** |  | 
 | 
			
		||||
**oauth** | **bool** |  | 
 | 
			
		||||
**oauthAutoLaunch** | **bool** |  | 
 | 
			
		||||
**passwordLogin** | **bool** |  | 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								mobile/openapi/doc/ServerInfoApi.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										38
									
								
								mobile/openapi/doc/ServerInfoApi.md
									
									
									
										generated
									
									
									
								
							@@ -9,6 +9,7 @@ All URIs are relative to */api*
 | 
			
		||||
 | 
			
		||||
Method | HTTP request | Description
 | 
			
		||||
------------- | ------------- | -------------
 | 
			
		||||
[**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | 
 | 
			
		||||
[**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | 
 | 
			
		||||
[**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info | 
 | 
			
		||||
[**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version | 
 | 
			
		||||
@@ -17,6 +18,43 @@ Method | HTTP request | Description
 | 
			
		||||
[**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping | 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# **getServerConfig**
 | 
			
		||||
> ServerConfigDto getServerConfig()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
final api_instance = ServerInfoApi();
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getServerConfig();
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling ServerInfoApi->getServerConfig: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
This endpoint does not need any parameter.
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**ServerConfigDto**](ServerConfigDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
No authorization required
 | 
			
		||||
 | 
			
		||||
### HTTP request headers
 | 
			
		||||
 | 
			
		||||
 - **Content-Type**: Not defined
 | 
			
		||||
 - **Accept**: application/json
 | 
			
		||||
 | 
			
		||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
# **getServerFeatures**
 | 
			
		||||
> ServerFeaturesDto getServerFeatures()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								mobile/openapi/doc/SystemConfigDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/doc/SystemConfigDto.md
									
									
									
										generated
									
									
									
								
							@@ -11,6 +11,7 @@ Name | Type | Description | Notes
 | 
			
		||||
**ffmpeg** | [**SystemConfigFFmpegDto**](SystemConfigFFmpegDto.md) |  | 
 | 
			
		||||
**job** | [**SystemConfigJobDto**](SystemConfigJobDto.md) |  | 
 | 
			
		||||
**machineLearning** | [**SystemConfigMachineLearningDto**](SystemConfigMachineLearningDto.md) |  | 
 | 
			
		||||
**map** | [**SystemConfigMapDto**](SystemConfigMapDto.md) |  | 
 | 
			
		||||
**oauth** | [**SystemConfigOAuthDto**](SystemConfigOAuthDto.md) |  | 
 | 
			
		||||
**passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) |  | 
 | 
			
		||||
**storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) |  | 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/SystemConfigMapDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/SystemConfigMapDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
# openapi.model.SystemConfigMapDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**enabled** | **bool** |  | 
 | 
			
		||||
**tileUrl** | **String** |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							@@ -128,6 +128,7 @@ part 'model/search_explore_response_dto.dart';
 | 
			
		||||
part 'model/search_facet_count_response_dto.dart';
 | 
			
		||||
part 'model/search_facet_response_dto.dart';
 | 
			
		||||
part 'model/search_response_dto.dart';
 | 
			
		||||
part 'model/server_config_dto.dart';
 | 
			
		||||
part 'model/server_features_dto.dart';
 | 
			
		||||
part 'model/server_info_response_dto.dart';
 | 
			
		||||
part 'model/server_media_types_response_dto.dart';
 | 
			
		||||
@@ -144,6 +145,7 @@ part 'model/system_config_dto.dart';
 | 
			
		||||
part 'model/system_config_f_fmpeg_dto.dart';
 | 
			
		||||
part 'model/system_config_job_dto.dart';
 | 
			
		||||
part 'model/system_config_machine_learning_dto.dart';
 | 
			
		||||
part 'model/system_config_map_dto.dart';
 | 
			
		||||
part 'model/system_config_o_auth_dto.dart';
 | 
			
		||||
part 'model/system_config_password_login_dto.dart';
 | 
			
		||||
part 'model/system_config_storage_template_dto.dart';
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								mobile/openapi/lib/api/server_info_api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										41
									
								
								mobile/openapi/lib/api/server_info_api.dart
									
									
									
										generated
									
									
									
								
							@@ -16,6 +16,47 @@ class ServerInfoApi {
 | 
			
		||||
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /server-info/config' operation and returns the [Response].
 | 
			
		||||
  Future<Response> getServerConfigWithHttpInfo() async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/server-info/config';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>[];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'GET',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
      formParams,
 | 
			
		||||
      contentTypes.isEmpty ? null : contentTypes.first,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<ServerConfigDto?> getServerConfig() async {
 | 
			
		||||
    final response = await getServerConfigWithHttpInfo();
 | 
			
		||||
    if (response.statusCode >= HttpStatus.badRequest) {
 | 
			
		||||
      throw ApiException(response.statusCode, await _decodeBodyBytes(response));
 | 
			
		||||
    }
 | 
			
		||||
    // When a remote server returns no body with a status of 204, we shall not decode it.
 | 
			
		||||
    // At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
 | 
			
		||||
    // FormatException when trying to decode an empty string.
 | 
			
		||||
    if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
 | 
			
		||||
      return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerConfigDto',) as ServerConfigDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /server-info/features' operation and returns the [Response].
 | 
			
		||||
  Future<Response> getServerFeaturesWithHttpInfo() async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							@@ -349,6 +349,8 @@ class ApiClient {
 | 
			
		||||
          return SearchFacetResponseDto.fromJson(value);
 | 
			
		||||
        case 'SearchResponseDto':
 | 
			
		||||
          return SearchResponseDto.fromJson(value);
 | 
			
		||||
        case 'ServerConfigDto':
 | 
			
		||||
          return ServerConfigDto.fromJson(value);
 | 
			
		||||
        case 'ServerFeaturesDto':
 | 
			
		||||
          return ServerFeaturesDto.fromJson(value);
 | 
			
		||||
        case 'ServerInfoResponseDto':
 | 
			
		||||
@@ -381,6 +383,8 @@ class ApiClient {
 | 
			
		||||
          return SystemConfigJobDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigMachineLearningDto':
 | 
			
		||||
          return SystemConfigMachineLearningDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigMapDto':
 | 
			
		||||
          return SystemConfigMapDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigOAuthDto':
 | 
			
		||||
          return SystemConfigOAuthDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigPasswordLoginDto':
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								mobile/openapi/lib/model/server_config_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								mobile/openapi/lib/model/server_config_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
//
 | 
			
		||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
			
		||||
//
 | 
			
		||||
// @dart=2.12
 | 
			
		||||
 | 
			
		||||
// ignore_for_file: unused_element, unused_import
 | 
			
		||||
// ignore_for_file: always_put_required_named_parameters_first
 | 
			
		||||
// ignore_for_file: constant_identifier_names
 | 
			
		||||
// ignore_for_file: lines_longer_than_80_chars
 | 
			
		||||
 | 
			
		||||
part of openapi.api;
 | 
			
		||||
 | 
			
		||||
class ServerConfigDto {
 | 
			
		||||
  /// Returns a new [ServerConfigDto] instance.
 | 
			
		||||
  ServerConfigDto({
 | 
			
		||||
    required this.loginPageMessage,
 | 
			
		||||
    required this.mapTileUrl,
 | 
			
		||||
    required this.oauthButtonText,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  String loginPageMessage;
 | 
			
		||||
 | 
			
		||||
  String mapTileUrl;
 | 
			
		||||
 | 
			
		||||
  String oauthButtonText;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is ServerConfigDto &&
 | 
			
		||||
     other.loginPageMessage == loginPageMessage &&
 | 
			
		||||
     other.mapTileUrl == mapTileUrl &&
 | 
			
		||||
     other.oauthButtonText == oauthButtonText;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (loginPageMessage.hashCode) +
 | 
			
		||||
    (mapTileUrl.hashCode) +
 | 
			
		||||
    (oauthButtonText.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'ServerConfigDto[loginPageMessage=$loginPageMessage, mapTileUrl=$mapTileUrl, oauthButtonText=$oauthButtonText]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
      json[r'loginPageMessage'] = this.loginPageMessage;
 | 
			
		||||
      json[r'mapTileUrl'] = this.mapTileUrl;
 | 
			
		||||
      json[r'oauthButtonText'] = this.oauthButtonText;
 | 
			
		||||
    return json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [ServerConfigDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static ServerConfigDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      return ServerConfigDto(
 | 
			
		||||
        loginPageMessage: mapValueOfType<String>(json, r'loginPageMessage')!,
 | 
			
		||||
        mapTileUrl: mapValueOfType<String>(json, r'mapTileUrl')!,
 | 
			
		||||
        oauthButtonText: mapValueOfType<String>(json, r'oauthButtonText')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<ServerConfigDto> listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <ServerConfigDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = ServerConfigDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, ServerConfigDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, ServerConfigDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = ServerConfigDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of ServerConfigDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<ServerConfigDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<ServerConfigDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      // ignore: parameter_assignments
 | 
			
		||||
      json = json.cast<String, dynamic>();
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        map[entry.key] = ServerConfigDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'loginPageMessage',
 | 
			
		||||
    'mapTileUrl',
 | 
			
		||||
    'oauthButtonText',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								mobile/openapi/lib/model/server_features_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								mobile/openapi/lib/model/server_features_dto.dart
									
									
									
										generated
									
									
									
								
							@@ -16,6 +16,7 @@ class ServerFeaturesDto {
 | 
			
		||||
    required this.clipEncode,
 | 
			
		||||
    required this.configFile,
 | 
			
		||||
    required this.facialRecognition,
 | 
			
		||||
    required this.map,
 | 
			
		||||
    required this.oauth,
 | 
			
		||||
    required this.oauthAutoLaunch,
 | 
			
		||||
    required this.passwordLogin,
 | 
			
		||||
@@ -30,6 +31,8 @@ class ServerFeaturesDto {
 | 
			
		||||
 | 
			
		||||
  bool facialRecognition;
 | 
			
		||||
 | 
			
		||||
  bool map;
 | 
			
		||||
 | 
			
		||||
  bool oauth;
 | 
			
		||||
 | 
			
		||||
  bool oauthAutoLaunch;
 | 
			
		||||
@@ -47,6 +50,7 @@ class ServerFeaturesDto {
 | 
			
		||||
     other.clipEncode == clipEncode &&
 | 
			
		||||
     other.configFile == configFile &&
 | 
			
		||||
     other.facialRecognition == facialRecognition &&
 | 
			
		||||
     other.map == map &&
 | 
			
		||||
     other.oauth == oauth &&
 | 
			
		||||
     other.oauthAutoLaunch == oauthAutoLaunch &&
 | 
			
		||||
     other.passwordLogin == passwordLogin &&
 | 
			
		||||
@@ -60,6 +64,7 @@ class ServerFeaturesDto {
 | 
			
		||||
    (clipEncode.hashCode) +
 | 
			
		||||
    (configFile.hashCode) +
 | 
			
		||||
    (facialRecognition.hashCode) +
 | 
			
		||||
    (map.hashCode) +
 | 
			
		||||
    (oauth.hashCode) +
 | 
			
		||||
    (oauthAutoLaunch.hashCode) +
 | 
			
		||||
    (passwordLogin.hashCode) +
 | 
			
		||||
@@ -68,13 +73,14 @@ class ServerFeaturesDto {
 | 
			
		||||
    (tagImage.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'ServerFeaturesDto[clipEncode=$clipEncode, configFile=$configFile, facialRecognition=$facialRecognition, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, search=$search, sidecar=$sidecar, tagImage=$tagImage]';
 | 
			
		||||
  String toString() => 'ServerFeaturesDto[clipEncode=$clipEncode, configFile=$configFile, facialRecognition=$facialRecognition, map=$map, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, search=$search, sidecar=$sidecar, tagImage=$tagImage]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
      json[r'clipEncode'] = this.clipEncode;
 | 
			
		||||
      json[r'configFile'] = this.configFile;
 | 
			
		||||
      json[r'facialRecognition'] = this.facialRecognition;
 | 
			
		||||
      json[r'map'] = this.map;
 | 
			
		||||
      json[r'oauth'] = this.oauth;
 | 
			
		||||
      json[r'oauthAutoLaunch'] = this.oauthAutoLaunch;
 | 
			
		||||
      json[r'passwordLogin'] = this.passwordLogin;
 | 
			
		||||
@@ -95,6 +101,7 @@ class ServerFeaturesDto {
 | 
			
		||||
        clipEncode: mapValueOfType<bool>(json, r'clipEncode')!,
 | 
			
		||||
        configFile: mapValueOfType<bool>(json, r'configFile')!,
 | 
			
		||||
        facialRecognition: mapValueOfType<bool>(json, r'facialRecognition')!,
 | 
			
		||||
        map: mapValueOfType<bool>(json, r'map')!,
 | 
			
		||||
        oauth: mapValueOfType<bool>(json, r'oauth')!,
 | 
			
		||||
        oauthAutoLaunch: mapValueOfType<bool>(json, r'oauthAutoLaunch')!,
 | 
			
		||||
        passwordLogin: mapValueOfType<bool>(json, r'passwordLogin')!,
 | 
			
		||||
@@ -151,6 +158,7 @@ class ServerFeaturesDto {
 | 
			
		||||
    'clipEncode',
 | 
			
		||||
    'configFile',
 | 
			
		||||
    'facialRecognition',
 | 
			
		||||
    'map',
 | 
			
		||||
    'oauth',
 | 
			
		||||
    'oauthAutoLaunch',
 | 
			
		||||
    'passwordLogin',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								mobile/openapi/lib/model/system_config_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								mobile/openapi/lib/model/system_config_dto.dart
									
									
									
										generated
									
									
									
								
							@@ -16,6 +16,7 @@ class SystemConfigDto {
 | 
			
		||||
    required this.ffmpeg,
 | 
			
		||||
    required this.job,
 | 
			
		||||
    required this.machineLearning,
 | 
			
		||||
    required this.map,
 | 
			
		||||
    required this.oauth,
 | 
			
		||||
    required this.passwordLogin,
 | 
			
		||||
    required this.storageTemplate,
 | 
			
		||||
@@ -28,6 +29,8 @@ class SystemConfigDto {
 | 
			
		||||
 | 
			
		||||
  SystemConfigMachineLearningDto machineLearning;
 | 
			
		||||
 | 
			
		||||
  SystemConfigMapDto map;
 | 
			
		||||
 | 
			
		||||
  SystemConfigOAuthDto oauth;
 | 
			
		||||
 | 
			
		||||
  SystemConfigPasswordLoginDto passwordLogin;
 | 
			
		||||
@@ -41,6 +44,7 @@ class SystemConfigDto {
 | 
			
		||||
     other.ffmpeg == ffmpeg &&
 | 
			
		||||
     other.job == job &&
 | 
			
		||||
     other.machineLearning == machineLearning &&
 | 
			
		||||
     other.map == map &&
 | 
			
		||||
     other.oauth == oauth &&
 | 
			
		||||
     other.passwordLogin == passwordLogin &&
 | 
			
		||||
     other.storageTemplate == storageTemplate &&
 | 
			
		||||
@@ -52,19 +56,21 @@ class SystemConfigDto {
 | 
			
		||||
    (ffmpeg.hashCode) +
 | 
			
		||||
    (job.hashCode) +
 | 
			
		||||
    (machineLearning.hashCode) +
 | 
			
		||||
    (map.hashCode) +
 | 
			
		||||
    (oauth.hashCode) +
 | 
			
		||||
    (passwordLogin.hashCode) +
 | 
			
		||||
    (storageTemplate.hashCode) +
 | 
			
		||||
    (thumbnail.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, oauth=$oauth, passwordLogin=$passwordLogin, storageTemplate=$storageTemplate, thumbnail=$thumbnail]';
 | 
			
		||||
  String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, storageTemplate=$storageTemplate, thumbnail=$thumbnail]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
      json[r'ffmpeg'] = this.ffmpeg;
 | 
			
		||||
      json[r'job'] = this.job;
 | 
			
		||||
      json[r'machineLearning'] = this.machineLearning;
 | 
			
		||||
      json[r'map'] = this.map;
 | 
			
		||||
      json[r'oauth'] = this.oauth;
 | 
			
		||||
      json[r'passwordLogin'] = this.passwordLogin;
 | 
			
		||||
      json[r'storageTemplate'] = this.storageTemplate;
 | 
			
		||||
@@ -83,6 +89,7 @@ class SystemConfigDto {
 | 
			
		||||
        ffmpeg: SystemConfigFFmpegDto.fromJson(json[r'ffmpeg'])!,
 | 
			
		||||
        job: SystemConfigJobDto.fromJson(json[r'job'])!,
 | 
			
		||||
        machineLearning: SystemConfigMachineLearningDto.fromJson(json[r'machineLearning'])!,
 | 
			
		||||
        map: SystemConfigMapDto.fromJson(json[r'map'])!,
 | 
			
		||||
        oauth: SystemConfigOAuthDto.fromJson(json[r'oauth'])!,
 | 
			
		||||
        passwordLogin: SystemConfigPasswordLoginDto.fromJson(json[r'passwordLogin'])!,
 | 
			
		||||
        storageTemplate: SystemConfigStorageTemplateDto.fromJson(json[r'storageTemplate'])!,
 | 
			
		||||
@@ -137,6 +144,7 @@ class SystemConfigDto {
 | 
			
		||||
    'ffmpeg',
 | 
			
		||||
    'job',
 | 
			
		||||
    'machineLearning',
 | 
			
		||||
    'map',
 | 
			
		||||
    'oauth',
 | 
			
		||||
    'passwordLogin',
 | 
			
		||||
    'storageTemplate',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										106
									
								
								mobile/openapi/lib/model/system_config_map_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								mobile/openapi/lib/model/system_config_map_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
//
 | 
			
		||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
			
		||||
//
 | 
			
		||||
// @dart=2.12
 | 
			
		||||
 | 
			
		||||
// ignore_for_file: unused_element, unused_import
 | 
			
		||||
// ignore_for_file: always_put_required_named_parameters_first
 | 
			
		||||
// ignore_for_file: constant_identifier_names
 | 
			
		||||
// ignore_for_file: lines_longer_than_80_chars
 | 
			
		||||
 | 
			
		||||
part of openapi.api;
 | 
			
		||||
 | 
			
		||||
class SystemConfigMapDto {
 | 
			
		||||
  /// Returns a new [SystemConfigMapDto] instance.
 | 
			
		||||
  SystemConfigMapDto({
 | 
			
		||||
    required this.enabled,
 | 
			
		||||
    required this.tileUrl,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  bool enabled;
 | 
			
		||||
 | 
			
		||||
  String tileUrl;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is SystemConfigMapDto &&
 | 
			
		||||
     other.enabled == enabled &&
 | 
			
		||||
     other.tileUrl == tileUrl;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (enabled.hashCode) +
 | 
			
		||||
    (tileUrl.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'SystemConfigMapDto[enabled=$enabled, tileUrl=$tileUrl]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
      json[r'enabled'] = this.enabled;
 | 
			
		||||
      json[r'tileUrl'] = this.tileUrl;
 | 
			
		||||
    return json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [SystemConfigMapDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static SystemConfigMapDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      return SystemConfigMapDto(
 | 
			
		||||
        enabled: mapValueOfType<bool>(json, r'enabled')!,
 | 
			
		||||
        tileUrl: mapValueOfType<String>(json, r'tileUrl')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigMapDto> listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigMapDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigMapDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, SystemConfigMapDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, SystemConfigMapDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigMapDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of SystemConfigMapDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<SystemConfigMapDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<SystemConfigMapDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      // ignore: parameter_assignments
 | 
			
		||||
      json = json.cast<String, dynamic>();
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        map[entry.key] = SystemConfigMapDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'enabled',
 | 
			
		||||
    'tileUrl',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								mobile/openapi/test/server_config_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								mobile/openapi/test/server_config_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
//
 | 
			
		||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
			
		||||
//
 | 
			
		||||
// @dart=2.12
 | 
			
		||||
 | 
			
		||||
// ignore_for_file: unused_element, unused_import
 | 
			
		||||
// ignore_for_file: always_put_required_named_parameters_first
 | 
			
		||||
// ignore_for_file: constant_identifier_names
 | 
			
		||||
// ignore_for_file: lines_longer_than_80_chars
 | 
			
		||||
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
import 'package:test/test.dart';
 | 
			
		||||
 | 
			
		||||
// tests for ServerConfigDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = ServerConfigDto();
 | 
			
		||||
 | 
			
		||||
  group('test ServerConfigDto', () {
 | 
			
		||||
    // String loginPageMessage
 | 
			
		||||
    test('to test the property `loginPageMessage`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String mapTileUrl
 | 
			
		||||
    test('to test the property `mapTileUrl`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String oauthButtonText
 | 
			
		||||
    test('to test the property `oauthButtonText`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -31,6 +31,11 @@ void main() {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // bool map
 | 
			
		||||
    test('to test the property `map`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // bool oauth
 | 
			
		||||
    test('to test the property `oauth`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								mobile/openapi/test/server_info_api_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								mobile/openapi/test/server_info_api_test.dart
									
									
									
										generated
									
									
									
								
							@@ -17,6 +17,11 @@ void main() {
 | 
			
		||||
  // final instance = ServerInfoApi();
 | 
			
		||||
 | 
			
		||||
  group('tests for ServerInfoApi', () {
 | 
			
		||||
    //Future<ServerConfigDto> getServerConfig() async
 | 
			
		||||
    test('test getServerConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //Future<ServerFeaturesDto> getServerFeatures() async
 | 
			
		||||
    test('test getServerFeatures', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								mobile/openapi/test/system_config_dto_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								mobile/openapi/test/system_config_dto_test.dart
									
									
									
										generated
									
									
									
								
							@@ -31,6 +31,11 @@ void main() {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // SystemConfigMapDto map
 | 
			
		||||
    test('to test the property `map`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // SystemConfigOAuthDto oauth
 | 
			
		||||
    test('to test the property `oauth`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								mobile/openapi/test/system_config_map_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/openapi/test/system_config_map_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
//
 | 
			
		||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
			
		||||
//
 | 
			
		||||
// @dart=2.12
 | 
			
		||||
 | 
			
		||||
// ignore_for_file: unused_element, unused_import
 | 
			
		||||
// ignore_for_file: always_put_required_named_parameters_first
 | 
			
		||||
// ignore_for_file: constant_identifier_names
 | 
			
		||||
// ignore_for_file: lines_longer_than_80_chars
 | 
			
		||||
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
import 'package:test/test.dart';
 | 
			
		||||
 | 
			
		||||
// tests for SystemConfigMapDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = SystemConfigMapDto();
 | 
			
		||||
 | 
			
		||||
  group('test SystemConfigMapDto', () {
 | 
			
		||||
    // bool enabled
 | 
			
		||||
    test('to test the property `enabled`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String tileUrl
 | 
			
		||||
    test('to test the property `tileUrl`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -3342,6 +3342,27 @@
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "/server-info/config": {
 | 
			
		||||
      "get": {
 | 
			
		||||
        "operationId": "getServerConfig",
 | 
			
		||||
        "parameters": [],
 | 
			
		||||
        "responses": {
 | 
			
		||||
          "200": {
 | 
			
		||||
            "content": {
 | 
			
		||||
              "application/json": {
 | 
			
		||||
                "schema": {
 | 
			
		||||
                  "$ref": "#/components/schemas/ServerConfigDto"
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "description": ""
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "tags": [
 | 
			
		||||
          "Server Info"
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "/server-info/features": {
 | 
			
		||||
      "get": {
 | 
			
		||||
        "operationId": "getServerFeatures",
 | 
			
		||||
@@ -6618,6 +6639,25 @@
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "ServerConfigDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "loginPageMessage": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "mapTileUrl": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "oauthButtonText": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "required": [
 | 
			
		||||
          "oauthButtonText",
 | 
			
		||||
          "loginPageMessage",
 | 
			
		||||
          "mapTileUrl"
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "ServerFeaturesDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "clipEncode": {
 | 
			
		||||
@@ -6629,6 +6669,9 @@
 | 
			
		||||
          "facialRecognition": {
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "map": {
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "oauth": {
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
@@ -6649,15 +6692,16 @@
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "required": [
 | 
			
		||||
          "configFile",
 | 
			
		||||
          "clipEncode",
 | 
			
		||||
          "configFile",
 | 
			
		||||
          "facialRecognition",
 | 
			
		||||
          "sidecar",
 | 
			
		||||
          "search",
 | 
			
		||||
          "tagImage",
 | 
			
		||||
          "map",
 | 
			
		||||
          "oauth",
 | 
			
		||||
          "oauthAutoLaunch",
 | 
			
		||||
          "passwordLogin"
 | 
			
		||||
          "passwordLogin",
 | 
			
		||||
          "sidecar",
 | 
			
		||||
          "search",
 | 
			
		||||
          "tagImage"
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
@@ -6989,6 +7033,9 @@
 | 
			
		||||
          "machineLearning": {
 | 
			
		||||
            "$ref": "#/components/schemas/SystemConfigMachineLearningDto"
 | 
			
		||||
          },
 | 
			
		||||
          "map": {
 | 
			
		||||
            "$ref": "#/components/schemas/SystemConfigMapDto"
 | 
			
		||||
          },
 | 
			
		||||
          "oauth": {
 | 
			
		||||
            "$ref": "#/components/schemas/SystemConfigOAuthDto"
 | 
			
		||||
          },
 | 
			
		||||
@@ -7005,6 +7052,7 @@
 | 
			
		||||
        "required": [
 | 
			
		||||
          "ffmpeg",
 | 
			
		||||
          "machineLearning",
 | 
			
		||||
          "map",
 | 
			
		||||
          "oauth",
 | 
			
		||||
          "passwordLogin",
 | 
			
		||||
          "storageTemplate",
 | 
			
		||||
@@ -7162,6 +7210,21 @@
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "SystemConfigMapDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "enabled": {
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "tileUrl": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "required": [
 | 
			
		||||
          "enabled",
 | 
			
		||||
          "tileUrl"
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "SystemConfigOAuthDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "autoLaunch": {
 | 
			
		||||
 
 | 
			
		||||
@@ -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,12 +143,14 @@ 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,
 | 
			
		||||
        map: true,
 | 
			
		||||
        oauth: false,
 | 
			
		||||
        oauthAutoLaunch: false,
 | 
			
		||||
        passwordLogin: true,
 | 
			
		||||
@@ -160,6 +162,16 @@ describe(ServerInfoService.name, () => {
 | 
			
		||||
      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();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('getStats', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -83,6 +83,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => {
 | 
			
		||||
        clipEncode: true,
 | 
			
		||||
        configFile: false,
 | 
			
		||||
        facialRecognition: true,
 | 
			
		||||
        map: true,
 | 
			
		||||
        oauth: false,
 | 
			
		||||
        oauthAutoLaunch: false,
 | 
			
		||||
        passwordLogin: true,
 | 
			
		||||
@@ -93,6 +94,18 @@ describe(`${ServerInfoController.name} (e2e)`, () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('GET /server-info/config', () => {
 | 
			
		||||
    it('should respond with the server configuration', async () => {
 | 
			
		||||
      const { status, body } = await request(server).get('/server-info/config');
 | 
			
		||||
      expect(status).toBe(200);
 | 
			
		||||
      expect(body).toEqual({
 | 
			
		||||
        loginPageMessage: '',
 | 
			
		||||
        oauthButtonText: 'Login with OAuth',
 | 
			
		||||
        mapTileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('GET /server-info/stats', () => {
 | 
			
		||||
    it('should require authentication', async () => {
 | 
			
		||||
      const { status, body } = await request(server).get('/server-info/stats');
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										112
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										112
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -2343,6 +2343,31 @@ export interface SearchResponseDto {
 | 
			
		||||
     */
 | 
			
		||||
    'assets': SearchAssetResponseDto;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface ServerConfigDto
 | 
			
		||||
 */
 | 
			
		||||
export interface ServerConfigDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'loginPageMessage': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'mapTileUrl': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof ServerConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'oauthButtonText': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
@@ -2367,6 +2392,12 @@ export interface ServerFeaturesDto {
 | 
			
		||||
     * @memberof ServerFeaturesDto
 | 
			
		||||
     */
 | 
			
		||||
    'facialRecognition': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
     * @memberof ServerFeaturesDto
 | 
			
		||||
     */
 | 
			
		||||
    'map': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
@@ -2810,6 +2841,12 @@ export interface SystemConfigDto {
 | 
			
		||||
     * @memberof SystemConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'machineLearning': SystemConfigMachineLearningDto;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {SystemConfigMapDto}
 | 
			
		||||
     * @memberof SystemConfigDto
 | 
			
		||||
     */
 | 
			
		||||
    'map': SystemConfigMapDto;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {SystemConfigOAuthDto}
 | 
			
		||||
@@ -3050,6 +3087,25 @@ export interface SystemConfigMachineLearningDto {
 | 
			
		||||
     */
 | 
			
		||||
    'url': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface SystemConfigMapDto
 | 
			
		||||
 */
 | 
			
		||||
export interface SystemConfigMapDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
     * @memberof SystemConfigMapDto
 | 
			
		||||
     */
 | 
			
		||||
    'enabled': boolean;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof SystemConfigMapDto
 | 
			
		||||
     */
 | 
			
		||||
    'tileUrl': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
@@ -10825,6 +10881,35 @@ export class SearchApi extends BaseAPI {
 | 
			
		||||
 */
 | 
			
		||||
export const ServerInfoApiAxiosParamCreator = function (configuration?: Configuration) {
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getServerConfig: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
			
		||||
            const localVarPath = `/server-info/config`;
 | 
			
		||||
            // use dummy base URL string because the URL constructor only accepts absolute URLs.
 | 
			
		||||
            const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
 | 
			
		||||
            let baseOptions;
 | 
			
		||||
            if (configuration) {
 | 
			
		||||
                baseOptions = configuration.baseOptions;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
 | 
			
		||||
            const localVarHeaderParameter = {} as any;
 | 
			
		||||
            const localVarQueryParameter = {} as any;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
			
		||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
			
		||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                url: toPathString(localVarUrlObj),
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11027,6 +11112,15 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur
 | 
			
		||||
export const ServerInfoApiFp = function(configuration?: Configuration) {
 | 
			
		||||
    const localVarAxiosParamCreator = ServerInfoApiAxiosParamCreator(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        async getServerConfig(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ServerConfigDto>> {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.getServerConfig(options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11091,6 +11185,14 @@ export const ServerInfoApiFp = function(configuration?: Configuration) {
 | 
			
		||||
export const ServerInfoApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
 | 
			
		||||
    const localVarFp = ServerInfoApiFp(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getServerConfig(options?: AxiosRequestConfig): AxiosPromise<ServerConfigDto> {
 | 
			
		||||
            return localVarFp.getServerConfig(options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
@@ -11149,6 +11251,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas
 | 
			
		||||
 * @extends {BaseAPI}
 | 
			
		||||
 */
 | 
			
		||||
export class ServerInfoApi extends BaseAPI {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
     * @throws {RequiredError}
 | 
			
		||||
     * @memberof ServerInfoApi
 | 
			
		||||
     */
 | 
			
		||||
    public getServerConfig(options?: AxiosRequestConfig) {
 | 
			
		||||
        return ServerInfoApiFp(this.configuration).getServerConfig(options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    NotificationType,
 | 
			
		||||
  } from '$lib/components/shared-components/notification/notification';
 | 
			
		||||
  import { AppRoute } from '$lib/constants';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { handleError } from '$lib/utils/handle-error';
 | 
			
		||||
  import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
 | 
			
		||||
  import type { ComponentType } from 'svelte';
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,98 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import {
 | 
			
		||||
    notificationController,
 | 
			
		||||
    NotificationType,
 | 
			
		||||
  } from '$lib/components/shared-components/notification/notification';
 | 
			
		||||
  import { handleError } from '$lib/utils/handle-error';
 | 
			
		||||
  import { api, SystemConfigMapDto } from '@api';
 | 
			
		||||
  import { isEqual } from 'lodash-es';
 | 
			
		||||
  import { fade } from 'svelte/transition';
 | 
			
		||||
  import SettingButtonsRow from '../setting-buttons-row.svelte';
 | 
			
		||||
  import SettingSwitch from '../setting-switch.svelte';
 | 
			
		||||
  import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
 | 
			
		||||
 | 
			
		||||
  export let mapConfig: SystemConfigMapDto; // this is the config that is being edited
 | 
			
		||||
  export let disabled = false;
 | 
			
		||||
 | 
			
		||||
  let savedConfig: SystemConfigMapDto;
 | 
			
		||||
  let defaultConfig: SystemConfigMapDto;
 | 
			
		||||
 | 
			
		||||
  async function getConfigs() {
 | 
			
		||||
    [savedConfig, defaultConfig] = await Promise.all([
 | 
			
		||||
      api.systemConfigApi.getConfig().then((res) => res.data.map),
 | 
			
		||||
      api.systemConfigApi.getDefaults().then((res) => res.data.map),
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function saveSetting() {
 | 
			
		||||
    try {
 | 
			
		||||
      const { data: current } = await api.systemConfigApi.getConfig();
 | 
			
		||||
      const { data: updated } = await api.systemConfigApi.updateConfig({
 | 
			
		||||
        systemConfigDto: { ...current, map: mapConfig },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      mapConfig = { ...updated.map };
 | 
			
		||||
      savedConfig = { ...updated.map };
 | 
			
		||||
 | 
			
		||||
      notificationController.show({ message: 'Settings saved', type: NotificationType.Info });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      handleError(error, 'Unable to save settings');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function reset() {
 | 
			
		||||
    const { data: resetConfig } = await api.systemConfigApi.getConfig();
 | 
			
		||||
 | 
			
		||||
    mapConfig = { ...resetConfig.map };
 | 
			
		||||
    savedConfig = { ...resetConfig.map };
 | 
			
		||||
 | 
			
		||||
    notificationController.show({
 | 
			
		||||
      message: 'Reset settings to the recent saved settings',
 | 
			
		||||
      type: NotificationType.Info,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function resetToDefault() {
 | 
			
		||||
    const { data: configs } = await api.systemConfigApi.getDefaults();
 | 
			
		||||
 | 
			
		||||
    mapConfig = { ...configs.map };
 | 
			
		||||
    defaultConfig = { ...configs.map };
 | 
			
		||||
 | 
			
		||||
    notificationController.show({
 | 
			
		||||
      message: 'Reset map settings to default',
 | 
			
		||||
      type: NotificationType.Info,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div>
 | 
			
		||||
  {#await getConfigs() then}
 | 
			
		||||
    <div in:fade={{ duration: 500 }}>
 | 
			
		||||
      <form autocomplete="off" on:submit|preventDefault>
 | 
			
		||||
        <div class="ml-4 mt-4 flex flex-col gap-4">
 | 
			
		||||
          <SettingSwitch title="ENABLED" {disabled} subtitle="Enable map features" bind:checked={mapConfig.enabled} />
 | 
			
		||||
 | 
			
		||||
          <hr />
 | 
			
		||||
 | 
			
		||||
          <SettingInputField
 | 
			
		||||
            inputType={SettingInputFieldType.TEXT}
 | 
			
		||||
            label="Tile URL"
 | 
			
		||||
            desc="URL to a leaflet compatible tile server"
 | 
			
		||||
            bind:value={mapConfig.tileUrl}
 | 
			
		||||
            required={true}
 | 
			
		||||
            disabled={disabled || !mapConfig.enabled}
 | 
			
		||||
            isEdited={mapConfig.tileUrl !== savedConfig.tileUrl}
 | 
			
		||||
          />
 | 
			
		||||
 | 
			
		||||
          <SettingButtonsRow
 | 
			
		||||
            on:reset={reset}
 | 
			
		||||
            on:save={saveSetting}
 | 
			
		||||
            on:reset-to-default={resetToDefault}
 | 
			
		||||
            showResetToDefault={!isEqual(savedConfig, defaultConfig)}
 | 
			
		||||
            {disabled}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
  {/await}
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,18 +1,19 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { page } from '$app/stores';
 | 
			
		||||
  import { locale } from '$lib/stores/preferences.store';
 | 
			
		||||
  import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { getAssetFilename } from '$lib/utils/asset-utils';
 | 
			
		||||
  import { AlbumResponseDto, AssetResponseDto, ThumbnailFormat, api } from '@api';
 | 
			
		||||
  import type { LatLngTuple } from 'leaflet';
 | 
			
		||||
  import { DateTime } from 'luxon';
 | 
			
		||||
  import { createEventDispatcher } from 'svelte';
 | 
			
		||||
  import Calendar from 'svelte-material-icons/Calendar.svelte';
 | 
			
		||||
  import CameraIris from 'svelte-material-icons/CameraIris.svelte';
 | 
			
		||||
  import Close from 'svelte-material-icons/Close.svelte';
 | 
			
		||||
  import ImageOutline from 'svelte-material-icons/ImageOutline.svelte';
 | 
			
		||||
  import MapMarkerOutline from 'svelte-material-icons/MapMarkerOutline.svelte';
 | 
			
		||||
  import { createEventDispatcher } from 'svelte';
 | 
			
		||||
  import { AssetResponseDto, AlbumResponseDto, api, ThumbnailFormat } from '@api';
 | 
			
		||||
  import { asByteUnitString } from '../../utils/byte-units';
 | 
			
		||||
  import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
 | 
			
		||||
  import { getAssetFilename } from '$lib/utils/asset-utils';
 | 
			
		||||
  import UserAvatar from '../shared-components/user-avatar.svelte';
 | 
			
		||||
 | 
			
		||||
  export let asset: AssetResponseDto;
 | 
			
		||||
@@ -268,12 +269,12 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
{#if latlng}
 | 
			
		||||
{#if latlng && $featureFlags.loaded && $featureFlags.map}
 | 
			
		||||
  <div class="h-[360px]">
 | 
			
		||||
    {#await import('../shared-components/leaflet') then { Map, TileLayer, Marker }}
 | 
			
		||||
      <Map center={latlng} zoom={14}>
 | 
			
		||||
        <TileLayer
 | 
			
		||||
          urlTemplate={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'}
 | 
			
		||||
          urlTemplate={$serverConfig.mapTileUrl}
 | 
			
		||||
          options={{
 | 
			
		||||
            attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
 | 
			
		||||
          }}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
  import { goto } from '$app/navigation';
 | 
			
		||||
  import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
 | 
			
		||||
  import { AppRoute } from '$lib/constants';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { getServerErrorMessage, handleError } from '$lib/utils/handle-error';
 | 
			
		||||
  import { api, oauth } from '@api';
 | 
			
		||||
  import { createEventDispatcher, onMount } from 'svelte';
 | 
			
		||||
@@ -158,7 +158,7 @@
 | 
			
		||||
          <LoadingSpinner />
 | 
			
		||||
        </span>
 | 
			
		||||
      {:else}
 | 
			
		||||
        {$featureFlags.passwordLogin ? 'Login with OAuth' : 'Login'}
 | 
			
		||||
        {$serverConfig.oauthButtonText}
 | 
			
		||||
      {/if}
 | 
			
		||||
    </Button>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { onDestroy, onMount } from 'svelte';
 | 
			
		||||
  import { TileLayer, type TileLayerOptions } from 'leaflet';
 | 
			
		||||
  import { onDestroy, onMount } from 'svelte';
 | 
			
		||||
  import { getMapContext } from './map.svelte';
 | 
			
		||||
 | 
			
		||||
  export let urlTemplate: string;
 | 
			
		||||
@@ -15,6 +15,6 @@
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  onDestroy(() => {
 | 
			
		||||
    if (tileLayer) tileLayer.remove();
 | 
			
		||||
    tileLayer?.remove();
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
  import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
 | 
			
		||||
  import Cog from 'svelte-material-icons/Cog.svelte';
 | 
			
		||||
  import UserAvatar from '../user-avatar.svelte';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  export let user: UserResponseDto;
 | 
			
		||||
  export let showUploadButton = true;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
  import SideBarButton from './side-bar-button.svelte';
 | 
			
		||||
  import { locale } from '$lib/stores/preferences.store';
 | 
			
		||||
  import SideBarSection from './side-bar-section.svelte';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
 | 
			
		||||
  const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
 | 
			
		||||
    const { data: stats } = await api.assetApi.getAssetStats(dto);
 | 
			
		||||
@@ -62,9 +62,11 @@
 | 
			
		||||
      <SideBarButton title="Explore" logo={Magnify} isSelected={$page.route.id === '/(user)/explore'} />
 | 
			
		||||
    </a>
 | 
			
		||||
  {/if}
 | 
			
		||||
  {#if $featureFlags.map}
 | 
			
		||||
    <a data-sveltekit-preload-data="hover" href={AppRoute.MAP} draggable="false">
 | 
			
		||||
      <SideBarButton title="Map" logo={Map} isSelected={$page.route.id === '/(user)/map'} />
 | 
			
		||||
    </a>
 | 
			
		||||
  {/if}
 | 
			
		||||
  <a data-sveltekit-preload-data="hover" href={AppRoute.SHARING} draggable="false">
 | 
			
		||||
    <SideBarButton
 | 
			
		||||
      title="Sharing"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { goto } from '$app/navigation';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { oauth, UserResponseDto } from '@api';
 | 
			
		||||
  import { onMount } from 'svelte';
 | 
			
		||||
  import { fade } from 'svelte/transition';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { browser } from '$app/environment';
 | 
			
		||||
  import { page } from '$app/stores';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { APIKeyResponseDto, AuthDeviceResponseDto, oauth, UserResponseDto } from '@api';
 | 
			
		||||
  import SettingAccordion from '../admin-page/settings/setting-accordion.svelte';
 | 
			
		||||
  import ChangePasswordSettings from './change-password-settings.svelte';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,3 @@
 | 
			
		||||
import { env } from '$env/dynamic/public';
 | 
			
		||||
export const loginPageMessage: string | undefined = env.PUBLIC_LOGIN_PAGE_MESSAGE;
 | 
			
		||||
 | 
			
		||||
export enum AssetAction {
 | 
			
		||||
  ARCHIVE = 'archive',
 | 
			
		||||
  UNARCHIVE = 'unarchive',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
import { api, ServerFeaturesDto } from '@api';
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
export type FeatureFlags = ServerFeaturesDto & { loaded: boolean };
 | 
			
		||||
 | 
			
		||||
export const featureFlags = writable<FeatureFlags>({
 | 
			
		||||
  loaded: false,
 | 
			
		||||
  clipEncode: true,
 | 
			
		||||
  facialRecognition: true,
 | 
			
		||||
  sidecar: true,
 | 
			
		||||
  tagImage: true,
 | 
			
		||||
  search: true,
 | 
			
		||||
  oauth: false,
 | 
			
		||||
  oauthAutoLaunch: false,
 | 
			
		||||
  passwordLogin: true,
 | 
			
		||||
  configFile: false,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const loadFeatureFlags = async () => {
 | 
			
		||||
  const { data } = await api.serverInfoApi.getServerFeatures();
 | 
			
		||||
  featureFlags.update(() => ({ ...data, loaded: true }));
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										37
									
								
								web/src/lib/stores/server-config.store.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/src/lib/stores/server-config.store.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
import { api, ServerConfigDto, ServerFeaturesDto } from '@api';
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
export type FeatureFlags = ServerFeaturesDto & { loaded: boolean };
 | 
			
		||||
 | 
			
		||||
export const featureFlags = writable<FeatureFlags>({
 | 
			
		||||
  loaded: false,
 | 
			
		||||
  clipEncode: true,
 | 
			
		||||
  facialRecognition: true,
 | 
			
		||||
  sidecar: true,
 | 
			
		||||
  tagImage: true,
 | 
			
		||||
  map: true,
 | 
			
		||||
  search: true,
 | 
			
		||||
  oauth: false,
 | 
			
		||||
  oauthAutoLaunch: false,
 | 
			
		||||
  passwordLogin: true,
 | 
			
		||||
  configFile: false,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export type ServerConfig = ServerConfigDto & { loaded: boolean };
 | 
			
		||||
 | 
			
		||||
export const serverConfig = writable<ServerConfig>({
 | 
			
		||||
  loaded: false,
 | 
			
		||||
  oauthButtonText: '',
 | 
			
		||||
  mapTileUrl: '',
 | 
			
		||||
  loginPageMessage: '',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const loadConfig = async () => {
 | 
			
		||||
  const [{ data: flags }, { data: config }] = await Promise.all([
 | 
			
		||||
    api.serverInfoApi.getServerFeatures(),
 | 
			
		||||
    api.serverInfoApi.getServerConfig(),
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  featureFlags.update(() => ({ ...flags, loaded: true }));
 | 
			
		||||
  serverConfig.update(() => ({ ...config, loaded: true }));
 | 
			
		||||
};
 | 
			
		||||
@@ -1,16 +1,19 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { goto } from '$app/navigation';
 | 
			
		||||
  import AssetViewer from '$lib/components/asset-viewer/asset-viewer.svelte';
 | 
			
		||||
  import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
 | 
			
		||||
  import MapSettingsModal from '$lib/components/map-page/map-settings-modal.svelte';
 | 
			
		||||
  import Portal from '$lib/components/shared-components/portal/portal.svelte';
 | 
			
		||||
  import { AppRoute } from '$lib/constants';
 | 
			
		||||
  import { assetViewingStore } from '$lib/stores/asset-viewing.store';
 | 
			
		||||
  import { mapSettings } from '$lib/stores/preferences.store';
 | 
			
		||||
  import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { MapMarkerResponseDto, api } from '@api';
 | 
			
		||||
  import { isEqual, omit } from 'lodash-es';
 | 
			
		||||
  import { DateTime, Duration } from 'luxon';
 | 
			
		||||
  import { onDestroy, onMount } from 'svelte';
 | 
			
		||||
  import Cog from 'svelte-material-icons/Cog.svelte';
 | 
			
		||||
  import type { PageData } from './$types';
 | 
			
		||||
  import { DateTime, Duration } from 'luxon';
 | 
			
		||||
  import { assetViewingStore } from '$lib/stores/asset-viewing.store';
 | 
			
		||||
 | 
			
		||||
  export let data: PageData;
 | 
			
		||||
 | 
			
		||||
@@ -29,12 +32,12 @@
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  onDestroy(() => {
 | 
			
		||||
    if (abortController) {
 | 
			
		||||
      abortController.abort();
 | 
			
		||||
    }
 | 
			
		||||
    abortController?.abort();
 | 
			
		||||
    assetViewingStore.showAssetViewer(false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  $: $featureFlags.map || goto(AppRoute.PHOTOS);
 | 
			
		||||
 | 
			
		||||
  async function loadMapMarkers() {
 | 
			
		||||
    if (abortController) {
 | 
			
		||||
      abortController.abort();
 | 
			
		||||
@@ -98,7 +101,8 @@
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<UserPageLayout user={data.user} title={data.meta.title}>
 | 
			
		||||
{#if $featureFlags.loaded && $featureFlags.map}
 | 
			
		||||
  <UserPageLayout user={data.user} title={data.meta.title}>
 | 
			
		||||
    <div class="isolate h-full w-full">
 | 
			
		||||
      {#if leaflet}
 | 
			
		||||
        {@const { Map, TileLayer, AssetMarkerCluster, Control } = leaflet}
 | 
			
		||||
@@ -115,7 +119,7 @@
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <TileLayer
 | 
			
		||||
          urlTemplate={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'}
 | 
			
		||||
            urlTemplate={$serverConfig.mapTileUrl}
 | 
			
		||||
            options={{
 | 
			
		||||
              attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
 | 
			
		||||
            }}
 | 
			
		||||
@@ -136,9 +140,9 @@
 | 
			
		||||
        </Map>
 | 
			
		||||
      {/if}
 | 
			
		||||
    </div>
 | 
			
		||||
</UserPageLayout>
 | 
			
		||||
  </UserPageLayout>
 | 
			
		||||
 | 
			
		||||
<Portal target="body">
 | 
			
		||||
  <Portal target="body">
 | 
			
		||||
    {#if $showAssetViewer}
 | 
			
		||||
      <AssetViewer
 | 
			
		||||
        asset={$viewingAsset}
 | 
			
		||||
@@ -148,9 +152,9 @@
 | 
			
		||||
        on:close={() => assetViewingStore.showAssetViewer(false)}
 | 
			
		||||
      />
 | 
			
		||||
    {/if}
 | 
			
		||||
</Portal>
 | 
			
		||||
  </Portal>
 | 
			
		||||
 | 
			
		||||
{#if showSettingsModal}
 | 
			
		||||
  {#if showSettingsModal}
 | 
			
		||||
    <MapSettingsModal
 | 
			
		||||
      settings={{ ...$mapSettings }}
 | 
			
		||||
      on:close={() => (showSettingsModal = false)}
 | 
			
		||||
@@ -164,4 +168,5 @@
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  {/if}
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
  import AppleHeader from '$lib/components/shared-components/apple-header.svelte';
 | 
			
		||||
  import FaviconHeader from '$lib/components/shared-components/favicon-header.svelte';
 | 
			
		||||
  import { onMount } from 'svelte';
 | 
			
		||||
  import { loadFeatureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { loadConfig } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { handleError } from '$lib/utils/handle-error';
 | 
			
		||||
  import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
 | 
			
		||||
  import { api } from '@api';
 | 
			
		||||
@@ -37,9 +37,9 @@
 | 
			
		||||
 | 
			
		||||
  onMount(async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      await loadFeatureFlags();
 | 
			
		||||
      await loadConfig();
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      handleError(error, 'Unable to load feature flags');
 | 
			
		||||
      handleError(error, 'Unable to connect to server');
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
  import FFmpegSettings from '$lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte';
 | 
			
		||||
  import JobSettings from '$lib/components/admin-page/settings/job-settings/job-settings.svelte';
 | 
			
		||||
  import MachineLearningSettings from '$lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte';
 | 
			
		||||
  import MapSettings from '$lib/components/admin-page/settings/map-settings/map-settings.svelte';
 | 
			
		||||
  import OAuthSettings from '$lib/components/admin-page/settings/oauth/oauth-settings.svelte';
 | 
			
		||||
  import PasswordLoginSettings from '$lib/components/admin-page/settings/password-login/password-login-settings.svelte';
 | 
			
		||||
  import SettingAccordion from '$lib/components/admin-page/settings/setting-accordion.svelte';
 | 
			
		||||
@@ -11,7 +12,7 @@
 | 
			
		||||
  import Button from '$lib/components/elements/buttons/button.svelte';
 | 
			
		||||
  import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
 | 
			
		||||
  import { downloadManager } from '$lib/stores/download';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { downloadBlob } from '$lib/utils/asset-utils';
 | 
			
		||||
  import { SystemConfigDto, api, copyToClipboard } from '@api';
 | 
			
		||||
  import Alert from 'svelte-material-icons/Alert.svelte';
 | 
			
		||||
@@ -57,20 +58,6 @@
 | 
			
		||||
        <span class="pl-2">Export as JSON</span>
 | 
			
		||||
      </Button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <SettingAccordion title="Thumbnail Settings" subtitle="Manage the resolution of thumbnail sizes">
 | 
			
		||||
      <ThumbnailSettings disabled={$featureFlags.configFile} thumbnailConfig={configs.thumbnail} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion
 | 
			
		||||
      title="Video Transcoding Settings"
 | 
			
		||||
      subtitle="Manage the resolution and encoding information of the video files"
 | 
			
		||||
    >
 | 
			
		||||
      <FFmpegSettings disabled={$featureFlags.configFile} ffmpegConfig={configs.ffmpeg} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="Machine Learning Settings" subtitle="Manage model settings">
 | 
			
		||||
      <MachineLearningSettings disabled={$featureFlags.configFile} machineLearningConfig={configs.machineLearning} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion
 | 
			
		||||
      title="Job Settings"
 | 
			
		||||
@@ -80,14 +67,22 @@
 | 
			
		||||
      <JobSettings disabled={$featureFlags.configFile} jobConfig={configs.job} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="Password Authentication" subtitle="Manage login with password settings">
 | 
			
		||||
      <PasswordLoginSettings disabled={$featureFlags.configFile} passwordLoginConfig={configs.passwordLogin} />
 | 
			
		||||
    <SettingAccordion title="Machine Learning Settings" subtitle="Manage model settings">
 | 
			
		||||
      <MachineLearningSettings disabled={$featureFlags.configFile} machineLearningConfig={configs.machineLearning} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="Map Settings" subtitle="Manage map settings">
 | 
			
		||||
      <MapSettings disabled={$featureFlags.configFile} mapConfig={configs.map} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="OAuth Authentication" subtitle="Manage the login with OAuth settings">
 | 
			
		||||
      <OAuthSettings disabled={$featureFlags.configFile} oauthConfig={configs.oauth} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="Password Authentication" subtitle="Manage login with password settings">
 | 
			
		||||
      <PasswordLoginSettings disabled={$featureFlags.configFile} passwordLoginConfig={configs.passwordLogin} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion
 | 
			
		||||
      title="Storage Template"
 | 
			
		||||
      subtitle="Manage the folder structure and file name of the upload asset"
 | 
			
		||||
@@ -99,5 +94,16 @@
 | 
			
		||||
        user={data.user}
 | 
			
		||||
      />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion title="Thumbnail Settings" subtitle="Manage the resolution of thumbnail sizes">
 | 
			
		||||
      <ThumbnailSettings disabled={$featureFlags.configFile} thumbnailConfig={configs.thumbnail} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
 | 
			
		||||
    <SettingAccordion
 | 
			
		||||
      title="Video Transcoding Settings"
 | 
			
		||||
      subtitle="Manage the resolution and encoding information of the video files"
 | 
			
		||||
    >
 | 
			
		||||
      <FFmpegSettings disabled={$featureFlags.configFile} ffmpegConfig={configs.ffmpeg} />
 | 
			
		||||
    </SettingAccordion>
 | 
			
		||||
  {/await}
 | 
			
		||||
</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,18 +3,17 @@
 | 
			
		||||
  import LoginForm from '$lib/components/forms/login-form.svelte';
 | 
			
		||||
  import FullscreenContainer from '$lib/components/shared-components/fullscreen-container.svelte';
 | 
			
		||||
  import { AppRoute } from '$lib/constants';
 | 
			
		||||
  import { loginPageMessage } from '$lib/constants';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/feature-flags.store';
 | 
			
		||||
  import { featureFlags, serverConfig } from '$lib/stores/server-config.store';
 | 
			
		||||
  import type { PageData } from './$types';
 | 
			
		||||
 | 
			
		||||
  export let data: PageData;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if $featureFlags.loaded}
 | 
			
		||||
  <FullscreenContainer title={data.meta.title} showMessage={!!loginPageMessage}>
 | 
			
		||||
  <FullscreenContainer title={data.meta.title} showMessage={!!$serverConfig.loginPageMessage}>
 | 
			
		||||
    <p slot="message">
 | 
			
		||||
      <!-- eslint-disable-next-line svelte/no-at-html-tags -->
 | 
			
		||||
      {@html loginPageMessage}
 | 
			
		||||
      {@html $serverConfig.loginPageMessage}
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <LoginForm
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user