mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:27:09 -05:00 
			
		
		
		
	feat(server,web): system config for admin (#959)
* feat: add admin config module for user configured config, uses it for ffmpeg * feat: add api endpoint to retrieve admin config settings and values * feat: add settings panel to admin page on web (wip) * feat: add api endpoint to update the admin config * chore: re-generate openapi spec after rebase * refactor: move from admin config to system config naming * chore: move away from UseGuards to new @Authenticated decorator * style: dark mode styling for lists and fix conflicting colors * wip: 2 column design, no edit button * refactor: system config * chore: generate open api * chore: rm broken test * chore: cleanup types * refactor: config module names Co-authored-by: Zack Pollard <zackpollard@ymail.com> Co-authored-by: Zack Pollard <zack.pollard@moonpig.com>
This commit is contained in:
		
							parent
							
								
									d3c35ec9c5
								
							
						
					
					
						commit
						b5d75e2016
					
				@ -59,6 +59,10 @@ doc/ServerStatsResponseDto.md
 | 
			
		||||
doc/ServerVersionReponseDto.md
 | 
			
		||||
doc/SignUpDto.md
 | 
			
		||||
doc/SmartInfoResponseDto.md
 | 
			
		||||
doc/SystemConfigApi.md
 | 
			
		||||
doc/SystemConfigKey.md
 | 
			
		||||
doc/SystemConfigResponseDto.md
 | 
			
		||||
doc/SystemConfigResponseItem.md
 | 
			
		||||
doc/ThumbnailFormat.md
 | 
			
		||||
doc/TimeGroupEnum.md
 | 
			
		||||
doc/UpdateAlbumDto.md
 | 
			
		||||
@ -79,6 +83,7 @@ lib/api/device_info_api.dart
 | 
			
		||||
lib/api/job_api.dart
 | 
			
		||||
lib/api/o_auth_api.dart
 | 
			
		||||
lib/api/server_info_api.dart
 | 
			
		||||
lib/api/system_config_api.dart
 | 
			
		||||
lib/api/user_api.dart
 | 
			
		||||
lib/api_client.dart
 | 
			
		||||
lib/api_exception.dart
 | 
			
		||||
@ -138,6 +143,9 @@ lib/model/server_stats_response_dto.dart
 | 
			
		||||
lib/model/server_version_reponse_dto.dart
 | 
			
		||||
lib/model/sign_up_dto.dart
 | 
			
		||||
lib/model/smart_info_response_dto.dart
 | 
			
		||||
lib/model/system_config_key.dart
 | 
			
		||||
lib/model/system_config_response_dto.dart
 | 
			
		||||
lib/model/system_config_response_item.dart
 | 
			
		||||
lib/model/thumbnail_format.dart
 | 
			
		||||
lib/model/time_group_enum.dart
 | 
			
		||||
lib/model/update_album_dto.dart
 | 
			
		||||
 | 
			
		||||
@ -109,6 +109,8 @@ Class | Method | HTTP request | Description
 | 
			
		||||
*ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | 
 | 
			
		||||
*ServerInfoApi* | [**getStats**](doc//ServerInfoApi.md#getstats) | **GET** /server-info/stats | 
 | 
			
		||||
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping | 
 | 
			
		||||
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config | 
 | 
			
		||||
*SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config | 
 | 
			
		||||
*UserApi* | [**createProfileImage**](doc//UserApi.md#createprofileimage) | **POST** /user/profile-image | 
 | 
			
		||||
*UserApi* | [**createUser**](doc//UserApi.md#createuser) | **POST** /user | 
 | 
			
		||||
*UserApi* | [**deleteUser**](doc//UserApi.md#deleteuser) | **DELETE** /user/{userId} | 
 | 
			
		||||
@ -173,6 +175,9 @@ Class | Method | HTTP request | Description
 | 
			
		||||
 - [ServerVersionReponseDto](doc//ServerVersionReponseDto.md)
 | 
			
		||||
 - [SignUpDto](doc//SignUpDto.md)
 | 
			
		||||
 - [SmartInfoResponseDto](doc//SmartInfoResponseDto.md)
 | 
			
		||||
 - [SystemConfigKey](doc//SystemConfigKey.md)
 | 
			
		||||
 - [SystemConfigResponseDto](doc//SystemConfigResponseDto.md)
 | 
			
		||||
 - [SystemConfigResponseItem](doc//SystemConfigResponseItem.md)
 | 
			
		||||
 - [ThumbnailFormat](doc//ThumbnailFormat.md)
 | 
			
		||||
 - [TimeGroupEnum](doc//TimeGroupEnum.md)
 | 
			
		||||
 - [UpdateAlbumDto](doc//UpdateAlbumDto.md)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								mobile/openapi/doc/AdminConfigResponseDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mobile/openapi/doc/AdminConfigResponseDto.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# openapi.model.AdminConfigResponseDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**config** | [**Object**](.md) |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								mobile/openapi/doc/ConfigApi.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								mobile/openapi/doc/ConfigApi.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
# openapi.api.ConfigApi
 | 
			
		||||
 | 
			
		||||
## Load the API package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
All URIs are relative to */api*
 | 
			
		||||
 | 
			
		||||
Method | HTTP request | Description
 | 
			
		||||
------------- | ------------- | -------------
 | 
			
		||||
[**getSystemConfig**](ConfigApi.md#getsystemconfig) | **GET** /config/system | 
 | 
			
		||||
[**updateSystemConfig**](ConfigApi.md#updatesystemconfig) | **PUT** /config/system | 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# **getSystemConfig**
 | 
			
		||||
> SystemConfigResponseDto getSystemConfig()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure HTTP Bearer authorization: bearer
 | 
			
		||||
// Case 1. Use String Token
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
 | 
			
		||||
// Case 2. Use Function which generate token.
 | 
			
		||||
// String yourTokenGeneratorFunction() { ... }
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = ConfigApi();
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getSystemConfig();
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling ConfigApi->getSystemConfig: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
This endpoint does not need any parameter.
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**SystemConfigResponseDto**](SystemConfigResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[bearer](../README.md#bearer)
 | 
			
		||||
 | 
			
		||||
### 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)
 | 
			
		||||
 | 
			
		||||
# **updateSystemConfig**
 | 
			
		||||
> SystemConfigResponseDto updateSystemConfig(body)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure HTTP Bearer authorization: bearer
 | 
			
		||||
// Case 1. Use String Token
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
 | 
			
		||||
// Case 2. Use Function which generate token.
 | 
			
		||||
// String yourTokenGeneratorFunction() { ... }
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = ConfigApi();
 | 
			
		||||
final body = Object(); // Object | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.updateSystemConfig(body);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling ConfigApi->updateSystemConfig: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **body** | **Object**|  | 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**SystemConfigResponseDto**](SystemConfigResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[bearer](../README.md#bearer)
 | 
			
		||||
 | 
			
		||||
### HTTP request headers
 | 
			
		||||
 | 
			
		||||
 - **Content-Type**: application/json
 | 
			
		||||
 - **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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								mobile/openapi/doc/SystemConfigApi.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								mobile/openapi/doc/SystemConfigApi.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
# openapi.api.SystemConfigApi
 | 
			
		||||
 | 
			
		||||
## Load the API package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
All URIs are relative to */api*
 | 
			
		||||
 | 
			
		||||
Method | HTTP request | Description
 | 
			
		||||
------------- | ------------- | -------------
 | 
			
		||||
[**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config | 
 | 
			
		||||
[**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config | 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# **getConfig**
 | 
			
		||||
> SystemConfigResponseDto getConfig()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure HTTP Bearer authorization: bearer
 | 
			
		||||
// Case 1. Use String Token
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
 | 
			
		||||
// Case 2. Use Function which generate token.
 | 
			
		||||
// String yourTokenGeneratorFunction() { ... }
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = SystemConfigApi();
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getConfig();
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling SystemConfigApi->getConfig: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
This endpoint does not need any parameter.
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**SystemConfigResponseDto**](SystemConfigResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[bearer](../README.md#bearer)
 | 
			
		||||
 | 
			
		||||
### 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)
 | 
			
		||||
 | 
			
		||||
# **updateConfig**
 | 
			
		||||
> SystemConfigResponseDto updateConfig(body)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure HTTP Bearer authorization: bearer
 | 
			
		||||
// Case 1. Use String Token
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
 | 
			
		||||
// Case 2. Use Function which generate token.
 | 
			
		||||
// String yourTokenGeneratorFunction() { ... }
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = SystemConfigApi();
 | 
			
		||||
final body = Object(); // Object | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.updateConfig(body);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling SystemConfigApi->updateConfig: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **body** | **Object**|  | 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**SystemConfigResponseDto**](SystemConfigResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[bearer](../README.md#bearer)
 | 
			
		||||
 | 
			
		||||
### HTTP request headers
 | 
			
		||||
 | 
			
		||||
 - **Content-Type**: application/json
 | 
			
		||||
 - **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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/SystemConfigEntity.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/SystemConfigEntity.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
# openapi.model.SystemConfigEntity
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**key** | **String** |  | 
 | 
			
		||||
**value** | [**Object**](.md) |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								mobile/openapi/doc/SystemConfigKey.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								mobile/openapi/doc/SystemConfigKey.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
# openapi.model.SystemConfigKey
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								mobile/openapi/doc/SystemConfigResponseDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mobile/openapi/doc/SystemConfigResponseDto.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# openapi.model.SystemConfigResponseDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**config** | [**List<SystemConfigResponseItem>**](SystemConfigResponseItem.md) |  | [default to const []]
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								mobile/openapi/doc/SystemConfigResponseItem.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								mobile/openapi/doc/SystemConfigResponseItem.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
# openapi.model.SystemConfigResponseItem
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**name** | **String** |  | 
 | 
			
		||||
**key** | [**SystemConfigKey**](SystemConfigKey.md) |  | 
 | 
			
		||||
**value** | **String** |  | 
 | 
			
		||||
**defaultValue** | **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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ part 'api/device_info_api.dart';
 | 
			
		||||
part 'api/job_api.dart';
 | 
			
		||||
part 'api/o_auth_api.dart';
 | 
			
		||||
part 'api/server_info_api.dart';
 | 
			
		||||
part 'api/system_config_api.dart';
 | 
			
		||||
part 'api/user_api.dart';
 | 
			
		||||
 | 
			
		||||
part 'model/add_assets_dto.dart';
 | 
			
		||||
@ -86,6 +87,9 @@ part 'model/server_stats_response_dto.dart';
 | 
			
		||||
part 'model/server_version_reponse_dto.dart';
 | 
			
		||||
part 'model/sign_up_dto.dart';
 | 
			
		||||
part 'model/smart_info_response_dto.dart';
 | 
			
		||||
part 'model/system_config_key.dart';
 | 
			
		||||
part 'model/system_config_response_dto.dart';
 | 
			
		||||
part 'model/system_config_response_item.dart';
 | 
			
		||||
part 'model/thumbnail_format.dart';
 | 
			
		||||
part 'model/time_group_enum.dart';
 | 
			
		||||
part 'model/update_album_dto.dart';
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										106
									
								
								mobile/openapi/lib/api/config_api.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								mobile/openapi/lib/api/config_api.dart
									
									
									
									
									
										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 ConfigApi {
 | 
			
		||||
  ConfigApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient;
 | 
			
		||||
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /config/system' operation and returns the [Response].
 | 
			
		||||
  Future<Response> getSystemConfigWithHttpInfo() async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/config/system';
 | 
			
		||||
 | 
			
		||||
    // 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<SystemConfigResponseDto?> getSystemConfig() async {
 | 
			
		||||
    final response = await getSystemConfigWithHttpInfo();
 | 
			
		||||
    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), 'SystemConfigResponseDto',) as SystemConfigResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'PUT /config/system' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [Object] body (required):
 | 
			
		||||
  Future<Response> updateSystemConfigWithHttpInfo(Object body,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/config/system';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody = body;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>['application/json'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'PUT',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
      formParams,
 | 
			
		||||
      contentTypes.isEmpty ? null : contentTypes.first,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [Object] body (required):
 | 
			
		||||
  Future<SystemConfigResponseDto?> updateSystemConfig(Object body,) async {
 | 
			
		||||
    final response = await updateSystemConfigWithHttpInfo(body,);
 | 
			
		||||
    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), 'SystemConfigResponseDto',) as SystemConfigResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								mobile/openapi/lib/api/system_config_api.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								mobile/openapi/lib/api/system_config_api.dart
									
									
									
									
									
										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 SystemConfigApi {
 | 
			
		||||
  SystemConfigApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient;
 | 
			
		||||
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /system-config' operation and returns the [Response].
 | 
			
		||||
  Future<Response> getConfigWithHttpInfo() async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/system-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<SystemConfigResponseDto?> getConfig() async {
 | 
			
		||||
    final response = await getConfigWithHttpInfo();
 | 
			
		||||
    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), 'SystemConfigResponseDto',) as SystemConfigResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'PUT /system-config' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [Object] body (required):
 | 
			
		||||
  Future<Response> updateConfigWithHttpInfo(Object body,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/system-config';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody = body;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>['application/json'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'PUT',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
      formParams,
 | 
			
		||||
      contentTypes.isEmpty ? null : contentTypes.first,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [Object] body (required):
 | 
			
		||||
  Future<SystemConfigResponseDto?> updateConfig(Object body,) async {
 | 
			
		||||
    final response = await updateConfigWithHttpInfo(body,);
 | 
			
		||||
    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), 'SystemConfigResponseDto',) as SystemConfigResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -292,6 +292,12 @@ class ApiClient {
 | 
			
		||||
          return SignUpDto.fromJson(value);
 | 
			
		||||
        case 'SmartInfoResponseDto':
 | 
			
		||||
          return SmartInfoResponseDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigKey':
 | 
			
		||||
          return SystemConfigKeyTypeTransformer().decode(value);
 | 
			
		||||
        case 'SystemConfigResponseDto':
 | 
			
		||||
          return SystemConfigResponseDto.fromJson(value);
 | 
			
		||||
        case 'SystemConfigResponseItem':
 | 
			
		||||
          return SystemConfigResponseItem.fromJson(value);
 | 
			
		||||
        case 'ThumbnailFormat':
 | 
			
		||||
          return ThumbnailFormatTypeTransformer().decode(value);
 | 
			
		||||
        case 'TimeGroupEnum':
 | 
			
		||||
 | 
			
		||||
@ -70,6 +70,9 @@ String parameterToString(dynamic value) {
 | 
			
		||||
  if (value is JobId) {
 | 
			
		||||
    return JobIdTypeTransformer().encode(value).toString();
 | 
			
		||||
  }
 | 
			
		||||
  if (value is SystemConfigKey) {
 | 
			
		||||
    return SystemConfigKeyTypeTransformer().encode(value).toString();
 | 
			
		||||
  }
 | 
			
		||||
  if (value is ThumbnailFormat) {
 | 
			
		||||
    return ThumbnailFormatTypeTransformer().encode(value).toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										111
									
								
								mobile/openapi/lib/model/admin_config_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								mobile/openapi/lib/model/admin_config_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AdminConfigResponseDto {
 | 
			
		||||
  /// Returns a new [AdminConfigResponseDto] instance.
 | 
			
		||||
  AdminConfigResponseDto({
 | 
			
		||||
    required this.config,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Object config;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is AdminConfigResponseDto &&
 | 
			
		||||
     other.config == config;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (config.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'AdminConfigResponseDto[config=$config]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'config'] = config;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [AdminConfigResponseDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static AdminConfigResponseDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "AdminConfigResponseDto[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "AdminConfigResponseDto[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return AdminConfigResponseDto(
 | 
			
		||||
        config: mapValueOfType<Object>(json, r'config')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<AdminConfigResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <AdminConfigResponseDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = AdminConfigResponseDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, AdminConfigResponseDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, AdminConfigResponseDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = AdminConfigResponseDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of AdminConfigResponseDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<AdminConfigResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<AdminConfigResponseDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = AdminConfigResponseDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'config',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										202
									
								
								mobile/openapi/lib/model/system_config_entity.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								mobile/openapi/lib/model/system_config_entity.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,202 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigEntity {
 | 
			
		||||
  /// Returns a new [SystemConfigEntity] instance.
 | 
			
		||||
  SystemConfigEntity({
 | 
			
		||||
    required this.key,
 | 
			
		||||
    required this.value,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  SystemConfigEntityKeyEnum key;
 | 
			
		||||
 | 
			
		||||
  Object value;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is SystemConfigEntity &&
 | 
			
		||||
     other.key == key &&
 | 
			
		||||
     other.value == value;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (key.hashCode) +
 | 
			
		||||
    (value.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'SystemConfigEntity[key=$key, value=$value]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'key'] = key;
 | 
			
		||||
      _json[r'value'] = value;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [SystemConfigEntity] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static SystemConfigEntity? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "SystemConfigEntity[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "SystemConfigEntity[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return SystemConfigEntity(
 | 
			
		||||
        key: SystemConfigEntityKeyEnum.fromJson(json[r'key'])!,
 | 
			
		||||
        value: mapValueOfType<Object>(json, r'value')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigEntity>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigEntity>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigEntity.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, SystemConfigEntity> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, SystemConfigEntity>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigEntity.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of SystemConfigEntity-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<SystemConfigEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<SystemConfigEntity>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigEntity.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'key',
 | 
			
		||||
    'value',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SystemConfigEntityKeyEnum {
 | 
			
		||||
  /// Instantiate a new enum with the provided [value].
 | 
			
		||||
  const SystemConfigEntityKeyEnum._(this.value);
 | 
			
		||||
 | 
			
		||||
  /// The underlying value of this enum member.
 | 
			
		||||
  final String value;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => value;
 | 
			
		||||
 | 
			
		||||
  String toJson() => value;
 | 
			
		||||
 | 
			
		||||
  static const crf = SystemConfigEntityKeyEnum._(r'ffmpeg_crf');
 | 
			
		||||
  static const preset = SystemConfigEntityKeyEnum._(r'ffmpeg_preset');
 | 
			
		||||
  static const targetVideoCodec = SystemConfigEntityKeyEnum._(r'ffmpeg_target_video_codec');
 | 
			
		||||
  static const targetAudioCodec = SystemConfigEntityKeyEnum._(r'ffmpeg_target_audio_codec');
 | 
			
		||||
  static const targetScaling = SystemConfigEntityKeyEnum._(r'ffmpeg_target_scaling');
 | 
			
		||||
 | 
			
		||||
  /// List of all possible values in this [enum][SystemConfigEntityKeyEnum].
 | 
			
		||||
  static const values = <SystemConfigEntityKeyEnum>[
 | 
			
		||||
    crf,
 | 
			
		||||
    preset,
 | 
			
		||||
    targetVideoCodec,
 | 
			
		||||
    targetAudioCodec,
 | 
			
		||||
    targetScaling,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static SystemConfigEntityKeyEnum? fromJson(dynamic value) => SystemConfigEntityKeyEnumTypeTransformer().decode(value);
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigEntityKeyEnum>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigEntityKeyEnum>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigEntityKeyEnum.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Transformation class that can [encode] an instance of [SystemConfigEntityKeyEnum] to String,
 | 
			
		||||
/// and [decode] dynamic data back to [SystemConfigEntityKeyEnum].
 | 
			
		||||
class SystemConfigEntityKeyEnumTypeTransformer {
 | 
			
		||||
  factory SystemConfigEntityKeyEnumTypeTransformer() => _instance ??= const SystemConfigEntityKeyEnumTypeTransformer._();
 | 
			
		||||
 | 
			
		||||
  const SystemConfigEntityKeyEnumTypeTransformer._();
 | 
			
		||||
 | 
			
		||||
  String encode(SystemConfigEntityKeyEnum data) => data.value;
 | 
			
		||||
 | 
			
		||||
  /// Decodes a [dynamic value][data] to a SystemConfigEntityKeyEnum.
 | 
			
		||||
  ///
 | 
			
		||||
  /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
 | 
			
		||||
  /// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
 | 
			
		||||
  /// cannot be decoded successfully, then an [UnimplementedError] is thrown.
 | 
			
		||||
  ///
 | 
			
		||||
  /// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
 | 
			
		||||
  /// and users are still using an old app with the old code.
 | 
			
		||||
  SystemConfigEntityKeyEnum? decode(dynamic data, {bool allowNull = true}) {
 | 
			
		||||
    if (data != null) {
 | 
			
		||||
      switch (data.toString()) {
 | 
			
		||||
        case r'ffmpeg_crf': return SystemConfigEntityKeyEnum.crf;
 | 
			
		||||
        case r'ffmpeg_preset': return SystemConfigEntityKeyEnum.preset;
 | 
			
		||||
        case r'ffmpeg_target_video_codec': return SystemConfigEntityKeyEnum.targetVideoCodec;
 | 
			
		||||
        case r'ffmpeg_target_audio_codec': return SystemConfigEntityKeyEnum.targetAudioCodec;
 | 
			
		||||
        case r'ffmpeg_target_scaling': return SystemConfigEntityKeyEnum.targetScaling;
 | 
			
		||||
        default:
 | 
			
		||||
          if (!allowNull) {
 | 
			
		||||
            throw ArgumentError('Unknown enum value to decode: $data');
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Singleton [SystemConfigEntityKeyEnumTypeTransformer] instance.
 | 
			
		||||
  static SystemConfigEntityKeyEnumTypeTransformer? _instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										94
									
								
								mobile/openapi/lib/model/system_config_key.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								mobile/openapi/lib/model/system_config_key.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigKey {
 | 
			
		||||
  /// Instantiate a new enum with the provided [value].
 | 
			
		||||
  const SystemConfigKey._(this.value);
 | 
			
		||||
 | 
			
		||||
  /// The underlying value of this enum member.
 | 
			
		||||
  final String value;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => value;
 | 
			
		||||
 | 
			
		||||
  String toJson() => value;
 | 
			
		||||
 | 
			
		||||
  static const crf = SystemConfigKey._(r'ffmpeg_crf');
 | 
			
		||||
  static const preset = SystemConfigKey._(r'ffmpeg_preset');
 | 
			
		||||
  static const targetVideoCodec = SystemConfigKey._(r'ffmpeg_target_video_codec');
 | 
			
		||||
  static const targetAudioCodec = SystemConfigKey._(r'ffmpeg_target_audio_codec');
 | 
			
		||||
  static const targetScaling = SystemConfigKey._(r'ffmpeg_target_scaling');
 | 
			
		||||
 | 
			
		||||
  /// List of all possible values in this [enum][SystemConfigKey].
 | 
			
		||||
  static const values = <SystemConfigKey>[
 | 
			
		||||
    crf,
 | 
			
		||||
    preset,
 | 
			
		||||
    targetVideoCodec,
 | 
			
		||||
    targetAudioCodec,
 | 
			
		||||
    targetScaling,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static SystemConfigKey? fromJson(dynamic value) => SystemConfigKeyTypeTransformer().decode(value);
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigKey>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigKey>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigKey.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Transformation class that can [encode] an instance of [SystemConfigKey] to String,
 | 
			
		||||
/// and [decode] dynamic data back to [SystemConfigKey].
 | 
			
		||||
class SystemConfigKeyTypeTransformer {
 | 
			
		||||
  factory SystemConfigKeyTypeTransformer() => _instance ??= const SystemConfigKeyTypeTransformer._();
 | 
			
		||||
 | 
			
		||||
  const SystemConfigKeyTypeTransformer._();
 | 
			
		||||
 | 
			
		||||
  String encode(SystemConfigKey data) => data.value;
 | 
			
		||||
 | 
			
		||||
  /// Decodes a [dynamic value][data] to a SystemConfigKey.
 | 
			
		||||
  ///
 | 
			
		||||
  /// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
 | 
			
		||||
  /// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
 | 
			
		||||
  /// cannot be decoded successfully, then an [UnimplementedError] is thrown.
 | 
			
		||||
  ///
 | 
			
		||||
  /// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
 | 
			
		||||
  /// and users are still using an old app with the old code.
 | 
			
		||||
  SystemConfigKey? decode(dynamic data, {bool allowNull = true}) {
 | 
			
		||||
    if (data != null) {
 | 
			
		||||
      switch (data.toString()) {
 | 
			
		||||
        case r'ffmpeg_crf': return SystemConfigKey.crf;
 | 
			
		||||
        case r'ffmpeg_preset': return SystemConfigKey.preset;
 | 
			
		||||
        case r'ffmpeg_target_video_codec': return SystemConfigKey.targetVideoCodec;
 | 
			
		||||
        case r'ffmpeg_target_audio_codec': return SystemConfigKey.targetAudioCodec;
 | 
			
		||||
        case r'ffmpeg_target_scaling': return SystemConfigKey.targetScaling;
 | 
			
		||||
        default:
 | 
			
		||||
          if (!allowNull) {
 | 
			
		||||
            throw ArgumentError('Unknown enum value to decode: $data');
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Singleton [SystemConfigKeyTypeTransformer] instance.
 | 
			
		||||
  static SystemConfigKeyTypeTransformer? _instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										111
									
								
								mobile/openapi/lib/model/system_config_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								mobile/openapi/lib/model/system_config_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigResponseDto {
 | 
			
		||||
  /// Returns a new [SystemConfigResponseDto] instance.
 | 
			
		||||
  SystemConfigResponseDto({
 | 
			
		||||
    this.config = const [],
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  List<SystemConfigResponseItem> config;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is SystemConfigResponseDto &&
 | 
			
		||||
     other.config == config;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (config.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'SystemConfigResponseDto[config=$config]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'config'] = config;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [SystemConfigResponseDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static SystemConfigResponseDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "SystemConfigResponseDto[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "SystemConfigResponseDto[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return SystemConfigResponseDto(
 | 
			
		||||
        config: SystemConfigResponseItem.listFromJson(json[r'config'])!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigResponseDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigResponseDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, SystemConfigResponseDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, SystemConfigResponseDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigResponseDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of SystemConfigResponseDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<SystemConfigResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<SystemConfigResponseDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigResponseDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'config',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										135
									
								
								mobile/openapi/lib/model/system_config_response_item.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								mobile/openapi/lib/model/system_config_response_item.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,135 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigResponseItem {
 | 
			
		||||
  /// Returns a new [SystemConfigResponseItem] instance.
 | 
			
		||||
  SystemConfigResponseItem({
 | 
			
		||||
    required this.name,
 | 
			
		||||
    required this.key,
 | 
			
		||||
    required this.value,
 | 
			
		||||
    required this.defaultValue,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  String name;
 | 
			
		||||
 | 
			
		||||
  SystemConfigKey key;
 | 
			
		||||
 | 
			
		||||
  String value;
 | 
			
		||||
 | 
			
		||||
  String defaultValue;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is SystemConfigResponseItem &&
 | 
			
		||||
     other.name == name &&
 | 
			
		||||
     other.key == key &&
 | 
			
		||||
     other.value == value &&
 | 
			
		||||
     other.defaultValue == defaultValue;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (name.hashCode) +
 | 
			
		||||
    (key.hashCode) +
 | 
			
		||||
    (value.hashCode) +
 | 
			
		||||
    (defaultValue.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'SystemConfigResponseItem[name=$name, key=$key, value=$value, defaultValue=$defaultValue]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'name'] = name;
 | 
			
		||||
      _json[r'key'] = key;
 | 
			
		||||
      _json[r'value'] = value;
 | 
			
		||||
      _json[r'defaultValue'] = defaultValue;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [SystemConfigResponseItem] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static SystemConfigResponseItem? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "SystemConfigResponseItem[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "SystemConfigResponseItem[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return SystemConfigResponseItem(
 | 
			
		||||
        name: mapValueOfType<String>(json, r'name')!,
 | 
			
		||||
        key: SystemConfigKey.fromJson(json[r'key'])!,
 | 
			
		||||
        value: mapValueOfType<String>(json, r'value')!,
 | 
			
		||||
        defaultValue: mapValueOfType<String>(json, r'defaultValue')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<SystemConfigResponseItem>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <SystemConfigResponseItem>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = SystemConfigResponseItem.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, SystemConfigResponseItem> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, SystemConfigResponseItem>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigResponseItem.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of SystemConfigResponseItem-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<SystemConfigResponseItem>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<SystemConfigResponseItem>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = SystemConfigResponseItem.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'name',
 | 
			
		||||
    'key',
 | 
			
		||||
    'value',
 | 
			
		||||
    'defaultValue',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								mobile/openapi/test/admin_config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								mobile/openapi/test/admin_config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AdminConfigApi
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = AdminConfigApi();
 | 
			
		||||
 | 
			
		||||
  group('tests for AdminConfigApi', () {
 | 
			
		||||
    //Future<AdminConfigResponseDto> getAdminConfig() async
 | 
			
		||||
    test('test getAdminConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								mobile/openapi/test/admin_config_response_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								mobile/openapi/test/admin_config_response_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AdminConfigResponseDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = AdminConfigResponseDto();
 | 
			
		||||
 | 
			
		||||
  group('test AdminConfigResponseDto', () {
 | 
			
		||||
    // Object config
 | 
			
		||||
    test('to test the property `config`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								mobile/openapi/test/config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								mobile/openapi/test/config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 ConfigApi
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = ConfigApi();
 | 
			
		||||
 | 
			
		||||
  group('tests for ConfigApi', () {
 | 
			
		||||
    //Future<SystemConfigResponseDto> getSystemConfig() async
 | 
			
		||||
    test('test getSystemConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //Future<SystemConfigResponseDto> putSystemConfig(Object body) async
 | 
			
		||||
    test('test putSystemConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								mobile/openapi/test/system_config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								mobile/openapi/test/system_config_api_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigApi
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = SystemConfigApi();
 | 
			
		||||
 | 
			
		||||
  group('tests for SystemConfigApi', () {
 | 
			
		||||
    //Future<SystemConfigResponseDto> getConfig() async
 | 
			
		||||
    test('test getConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //Future<SystemConfigResponseDto> updateConfig(Object body) async
 | 
			
		||||
    test('test updateConfig', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								mobile/openapi/test/system_config_entity_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/openapi/test/system_config_entity_test.dart
									
									
									
									
									
										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 SystemConfigEntity
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = SystemConfigEntity();
 | 
			
		||||
 | 
			
		||||
  group('test SystemConfigEntity', () {
 | 
			
		||||
    // String key
 | 
			
		||||
    test('to test the property `key`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Object value
 | 
			
		||||
    test('to test the property `value`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								mobile/openapi/test/system_config_key_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								mobile/openapi/test/system_config_key_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigKey
 | 
			
		||||
void main() {
 | 
			
		||||
 | 
			
		||||
  group('test SystemConfigKey', () {
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								mobile/openapi/test/system_config_response_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								mobile/openapi/test/system_config_response_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 SystemConfigResponseDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = SystemConfigResponseDto();
 | 
			
		||||
 | 
			
		||||
  group('test SystemConfigResponseDto', () {
 | 
			
		||||
    // Object config
 | 
			
		||||
    test('to test the property `config`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								mobile/openapi/test/system_config_response_item_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								mobile/openapi/test/system_config_response_item_test.dart
									
									
									
									
									
										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 SystemConfigResponseItem
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = SystemConfigResponseItem();
 | 
			
		||||
 | 
			
		||||
  group('test SystemConfigResponseItem', () {
 | 
			
		||||
    // String name
 | 
			
		||||
    test('to test the property `name`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String key
 | 
			
		||||
    test('to test the property `key`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Object value
 | 
			
		||||
    test('to test the property `value`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1 +1,6 @@
 | 
			
		||||
# Immich Server- NestJs
 | 
			
		||||
## How to run migration
 | 
			
		||||
 | 
			
		||||
1. Attached to the container shell
 | 
			
		||||
2. Run `npm run typeorm -- migration:generate ./libs/database/src/<migration-name> -d libs/database/src/config/database.config.ts`
 | 
			
		||||
3. Check if the migration file makes sense
 | 
			
		||||
4. Move the migration file to folder `server/libs/database/src/migrations` in your code editor.
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
import { SystemConfigKey, SystemConfigValue } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { IsEnum, IsNotEmpty, ValidateNested } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class UpdateSystemConfigDto {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @ValidateNested({ each: true })
 | 
			
		||||
  config!: SystemConfigItem[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SystemConfigItem {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsEnum(SystemConfigKey)
 | 
			
		||||
  @ApiProperty({
 | 
			
		||||
    enum: SystemConfigKey,
 | 
			
		||||
    enumName: 'SystemConfigKey',
 | 
			
		||||
  })
 | 
			
		||||
  key!: SystemConfigKey;
 | 
			
		||||
  value!: SystemConfigValue;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
import { SystemConfigKey, SystemConfigValue } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigResponseDto {
 | 
			
		||||
  config!: SystemConfigResponseItem[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SystemConfigResponseItem {
 | 
			
		||||
  @ApiProperty({ type: 'string' })
 | 
			
		||||
  name!: string;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({ enumName: 'SystemConfigKey', enum: SystemConfigKey })
 | 
			
		||||
  key!: SystemConfigKey;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({ type: 'string' })
 | 
			
		||||
  value!: SystemConfigValue;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({ type: 'string' })
 | 
			
		||||
  defaultValue!: SystemConfigValue;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
import { Body, Controller, Get, Put, ValidationPipe } from '@nestjs/common';
 | 
			
		||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
 | 
			
		||||
import { Authenticated } from '../../decorators/authenticated.decorator';
 | 
			
		||||
import { UpdateSystemConfigDto } from './dto/update-system-config';
 | 
			
		||||
import { SystemConfigResponseDto } from './response-dto/system-config-response.dto';
 | 
			
		||||
import { SystemConfigService } from './system-config.service';
 | 
			
		||||
 | 
			
		||||
@ApiTags('System Config')
 | 
			
		||||
@ApiBearerAuth()
 | 
			
		||||
@Authenticated({ admin: true })
 | 
			
		||||
@Controller('system-config')
 | 
			
		||||
export class SystemConfigController {
 | 
			
		||||
  constructor(private readonly systemConfigService: SystemConfigService) {}
 | 
			
		||||
 | 
			
		||||
  @Get()
 | 
			
		||||
  getConfig(): Promise<SystemConfigResponseDto> {
 | 
			
		||||
    return this.systemConfigService.getConfig();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Put()
 | 
			
		||||
  async updateConfig(@Body(ValidationPipe) dto: UpdateSystemConfigDto): Promise<SystemConfigResponseDto> {
 | 
			
		||||
    return this.systemConfigService.updateConfig(dto);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
import { SystemConfigEntity } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { TypeOrmModule } from '@nestjs/typeorm';
 | 
			
		||||
import { ImmichConfigModule } from 'libs/immich-config/src';
 | 
			
		||||
import { ImmichJwtModule } from '../../modules/immich-jwt/immich-jwt.module';
 | 
			
		||||
import { SystemConfigController } from './system-config.controller';
 | 
			
		||||
import { SystemConfigService } from './system-config.service';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [ImmichJwtModule, ImmichConfigModule, TypeOrmModule.forFeature([SystemConfigEntity])],
 | 
			
		||||
  controllers: [SystemConfigController],
 | 
			
		||||
  providers: [SystemConfigService],
 | 
			
		||||
})
 | 
			
		||||
export class SystemConfigModule {}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { ImmichConfigService } from 'libs/immich-config/src';
 | 
			
		||||
import { UpdateSystemConfigDto } from './dto/update-system-config';
 | 
			
		||||
import { SystemConfigResponseDto } from './response-dto/system-config-response.dto';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class SystemConfigService {
 | 
			
		||||
  constructor(private immichConfigService: ImmichConfigService) {}
 | 
			
		||||
 | 
			
		||||
  async getConfig(): Promise<SystemConfigResponseDto> {
 | 
			
		||||
    const config = await this.immichConfigService.getSystemConfig();
 | 
			
		||||
    return { config };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updateConfig(dto: UpdateSystemConfigDto): Promise<SystemConfigResponseDto> {
 | 
			
		||||
    await this.immichConfigService.updateSystemConfig(dto.config);
 | 
			
		||||
    const config = await this.immichConfigService.getSystemConfig();
 | 
			
		||||
    return { config };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -16,6 +16,7 @@ import { ScheduleModule } from '@nestjs/schedule';
 | 
			
		||||
import { ScheduleTasksModule } from './modules/schedule-tasks/schedule-tasks.module';
 | 
			
		||||
import { DatabaseModule } from '@app/database';
 | 
			
		||||
import { JobModule } from './api-v1/job/job.module';
 | 
			
		||||
import { SystemConfigModule } from './api-v1/system-config/system-config.module';
 | 
			
		||||
import { OAuthModule } from './api-v1/oauth/oauth.module';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
@ -60,6 +61,8 @@ import { OAuthModule } from './api-v1/oauth/oauth.module';
 | 
			
		||||
    ScheduleTasksModule,
 | 
			
		||||
 | 
			
		||||
    JobModule,
 | 
			
		||||
 | 
			
		||||
    SystemConfigModule,
 | 
			
		||||
  ],
 | 
			
		||||
  controllers: [AppController],
 | 
			
		||||
  providers: [],
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,9 @@ import { UserEntity } from '@app/database/entities/user.entity';
 | 
			
		||||
import { QueueNameEnum } from '@app/job/constants/queue-name.constant';
 | 
			
		||||
import { BullModule } from '@nestjs/bull';
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { ConfigModule, ConfigService } from '@nestjs/config';
 | 
			
		||||
import { ConfigModule } from '@nestjs/config';
 | 
			
		||||
import { TypeOrmModule } from '@nestjs/typeorm';
 | 
			
		||||
import { ImmichConfigModule } from 'libs/immich-config/src';
 | 
			
		||||
import { CommunicationModule } from '../../immich/src/api-v1/communication/communication.module';
 | 
			
		||||
import { MicroservicesService } from './microservices.service';
 | 
			
		||||
import { AssetUploadedProcessor } from './processors/asset-uploaded.processor';
 | 
			
		||||
@ -22,6 +23,7 @@ import { VideoTranscodeProcessor } from './processors/video-transcode.processor'
 | 
			
		||||
  imports: [
 | 
			
		||||
    ConfigModule.forRoot(immichAppConfig),
 | 
			
		||||
    DatabaseModule,
 | 
			
		||||
    ImmichConfigModule,
 | 
			
		||||
    TypeOrmModule.forFeature([UserEntity, ExifEntity, AssetEntity, SmartInfoEntity]),
 | 
			
		||||
    BullModule.forRootAsync({
 | 
			
		||||
      useFactory: async () => ({
 | 
			
		||||
@ -96,7 +98,6 @@ import { VideoTranscodeProcessor } from './processors/video-transcode.processor'
 | 
			
		||||
    VideoTranscodeProcessor,
 | 
			
		||||
    GenerateChecksumProcessor,
 | 
			
		||||
    MachineLearningProcessor,
 | 
			
		||||
    ConfigService,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [],
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import { InjectRepository } from '@nestjs/typeorm';
 | 
			
		||||
import { Job } from 'bull';
 | 
			
		||||
import ffmpeg from 'fluent-ffmpeg';
 | 
			
		||||
import { existsSync, mkdirSync } from 'fs';
 | 
			
		||||
import { ImmichConfigService } from 'libs/immich-config/src';
 | 
			
		||||
import { Repository } from 'typeorm';
 | 
			
		||||
 | 
			
		||||
@Processor(QueueNameEnum.VIDEO_CONVERSION)
 | 
			
		||||
@ -16,6 +17,7 @@ export class VideoTranscodeProcessor {
 | 
			
		||||
  constructor(
 | 
			
		||||
    @InjectRepository(AssetEntity)
 | 
			
		||||
    private assetRepository: Repository<AssetEntity>,
 | 
			
		||||
    private immichConfigService: ImmichConfigService,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  @Process({ name: mp4ConversionProcessorName, concurrency: 1 })
 | 
			
		||||
@ -40,9 +42,17 @@ export class VideoTranscodeProcessor {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async runFFMPEGPipeLine(asset: AssetEntity, savedEncodedPath: string): Promise<void> {
 | 
			
		||||
    const config = await this.immichConfigService.getSystemConfigMap();
 | 
			
		||||
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      ffmpeg(asset.originalPath)
 | 
			
		||||
        .outputOptions(['-crf 23', '-preset ultrafast', '-vcodec libx264', '-acodec mp3', '-vf scale=1280:-2'])
 | 
			
		||||
        .outputOptions([
 | 
			
		||||
          `-crf ${config.ffmpeg_crf}`,
 | 
			
		||||
          `-preset ${config.ffmpeg_preset}`,
 | 
			
		||||
          `-vcodec ${config.ffmpeg_target_video_codec}`,
 | 
			
		||||
          `-acodec ${config.ffmpeg_target_audio_codec}`,
 | 
			
		||||
          `-vf scale=${config.ffmpeg_target_scaling}`,
 | 
			
		||||
        ])
 | 
			
		||||
        .output(savedEncodedPath)
 | 
			
		||||
        .on('start', () => {
 | 
			
		||||
          Logger.log('Start Converting Video', 'mp4Conversion');
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										27
									
								
								server/libs/database/src/entities/system-config.entity.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								server/libs/database/src/entities/system-config.entity.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
 | 
			
		||||
 | 
			
		||||
@Entity('system_config')
 | 
			
		||||
export class SystemConfigEntity {
 | 
			
		||||
  @PrimaryColumn()
 | 
			
		||||
  key!: SystemConfigKey;
 | 
			
		||||
 | 
			
		||||
  @Column({ type: 'varchar', nullable: true })
 | 
			
		||||
  value!: SystemConfigValue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type SystemConfig = SystemConfigEntity[];
 | 
			
		||||
 | 
			
		||||
export enum SystemConfigKey {
 | 
			
		||||
  FFMPEG_CRF = 'ffmpeg_crf',
 | 
			
		||||
  FFMPEG_PRESET = 'ffmpeg_preset',
 | 
			
		||||
  FFMPEG_TARGET_VIDEO_CODEC = 'ffmpeg_target_video_codec',
 | 
			
		||||
  FFMPEG_TARGET_AUDIO_CODEC = 'ffmpeg_target_audio_codec',
 | 
			
		||||
  FFMPEG_TARGET_SCALING = 'ffmpeg_target_scaling',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type SystemConfigValue = string | null;
 | 
			
		||||
 | 
			
		||||
export interface SystemConfigItem {
 | 
			
		||||
  key: SystemConfigKey;
 | 
			
		||||
  value: SystemConfigValue;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
import { MigrationInterface, QueryRunner } from 'typeorm';
 | 
			
		||||
 | 
			
		||||
export class CreateSystemConfigTable1665540663419 implements MigrationInterface {
 | 
			
		||||
  name = 'CreateSystemConfigTable1665540663419';
 | 
			
		||||
 | 
			
		||||
  public async up(queryRunner: QueryRunner): Promise<void> {
 | 
			
		||||
    await queryRunner.query(
 | 
			
		||||
      `CREATE TABLE "system_config" ("key" character varying NOT NULL, "value" character varying, CONSTRAINT "PK_aab69295b445016f56731f4d535" PRIMARY KEY ("key"))`,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async down(queryRunner: QueryRunner): Promise<void> {
 | 
			
		||||
    await queryRunner.query(`DROP TABLE "system_config"`);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								server/libs/immich-config/src/immich-config.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								server/libs/immich-config/src/immich-config.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
import { SystemConfigEntity } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { TypeOrmModule } from '@nestjs/typeorm';
 | 
			
		||||
import { ImmichConfigService } from './immich-config.service';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [TypeOrmModule.forFeature([SystemConfigEntity])],
 | 
			
		||||
  providers: [ImmichConfigService],
 | 
			
		||||
  exports: [ImmichConfigService],
 | 
			
		||||
})
 | 
			
		||||
export class ImmichConfigModule {}
 | 
			
		||||
							
								
								
									
										97
									
								
								server/libs/immich-config/src/immich-config.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								server/libs/immich-config/src/immich-config.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
import { SystemConfigEntity, SystemConfigKey, SystemConfigValue } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { InjectRepository } from '@nestjs/typeorm';
 | 
			
		||||
import { In, Repository } from 'typeorm';
 | 
			
		||||
 | 
			
		||||
type SystemConfigMap = Record<SystemConfigKey, SystemConfigValue>;
 | 
			
		||||
 | 
			
		||||
const configDefaults: Record<SystemConfigKey, { name: string; value: SystemConfigValue }> = {
 | 
			
		||||
  [SystemConfigKey.FFMPEG_CRF]: {
 | 
			
		||||
    name: 'FFmpeg Constant Rate Factor (-crf)',
 | 
			
		||||
    value: '23',
 | 
			
		||||
  },
 | 
			
		||||
  [SystemConfigKey.FFMPEG_PRESET]: {
 | 
			
		||||
    name: 'FFmpeg preset (-preset)',
 | 
			
		||||
    value: 'ultrafast',
 | 
			
		||||
  },
 | 
			
		||||
  [SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC]: {
 | 
			
		||||
    name: 'FFmpeg target video codec (-vcodec)',
 | 
			
		||||
    value: 'libx264',
 | 
			
		||||
  },
 | 
			
		||||
  [SystemConfigKey.FFMPEG_TARGET_AUDIO_CODEC]: {
 | 
			
		||||
    name: 'FFmpeg target audio codec (-acodec)',
 | 
			
		||||
    value: 'mp3',
 | 
			
		||||
  },
 | 
			
		||||
  [SystemConfigKey.FFMPEG_TARGET_SCALING]: {
 | 
			
		||||
    name: 'FFmpeg target scaling (-vf scale=)',
 | 
			
		||||
    value: '1280:-2',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ImmichConfigService {
 | 
			
		||||
  constructor(
 | 
			
		||||
    @InjectRepository(SystemConfigEntity)
 | 
			
		||||
    private systemConfigRepository: Repository<SystemConfigEntity>,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  public async getSystemConfig() {
 | 
			
		||||
    const items = this._getDefaults();
 | 
			
		||||
 | 
			
		||||
    // override default values
 | 
			
		||||
    const overrides = await this.systemConfigRepository.find();
 | 
			
		||||
    for (const override of overrides) {
 | 
			
		||||
      const item = items.find((_item) => _item.key === override.key);
 | 
			
		||||
      if (item) {
 | 
			
		||||
        item.value = override.value;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return items;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async getSystemConfigMap(): Promise<SystemConfigMap> {
 | 
			
		||||
    const items = await this.getSystemConfig();
 | 
			
		||||
    const map: Partial<SystemConfigMap> = {};
 | 
			
		||||
 | 
			
		||||
    for (const { key, value } of items) {
 | 
			
		||||
      map[key] = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return map as SystemConfigMap;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async updateSystemConfig(items: SystemConfigEntity[]): Promise<void> {
 | 
			
		||||
    const deletes: SystemConfigEntity[] = [];
 | 
			
		||||
    const updates: SystemConfigEntity[] = [];
 | 
			
		||||
 | 
			
		||||
    for (const item of items) {
 | 
			
		||||
      if (item.value === null || item.value === this._getDefaultValue(item.key)) {
 | 
			
		||||
        deletes.push(item);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      updates.push(item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (updates.length > 0) {
 | 
			
		||||
      await this.systemConfigRepository.save(updates);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (deletes.length > 0) {
 | 
			
		||||
      await this.systemConfigRepository.delete({ key: In(deletes.map((item) => item.key)) });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private _getDefaults() {
 | 
			
		||||
    return Object.values(SystemConfigKey).map((key) => ({
 | 
			
		||||
      key,
 | 
			
		||||
      defaultValue: configDefaults[key].value,
 | 
			
		||||
      ...configDefaults[key],
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private _getDefaultValue(key: SystemConfigKey) {
 | 
			
		||||
    return this._getDefaults().find((item) => item.key === key)?.value || null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								server/libs/immich-config/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								server/libs/immich-config/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
export * from './immich-config.module';
 | 
			
		||||
export * from './immich-config.service';
 | 
			
		||||
							
								
								
									
										9
									
								
								server/libs/immich-config/tsconfig.lib.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								server/libs/immich-config/tsconfig.lib.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../../tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "outDir": "../../dist/libs/immich-config"
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["src/**/*"],
 | 
			
		||||
  "exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
 | 
			
		||||
}
 | 
			
		||||
@ -70,6 +70,15 @@
 | 
			
		||||
      "compilerOptions": {
 | 
			
		||||
        "tsConfigPath": "libs/job/tsconfig.lib.json"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "system-config": {
 | 
			
		||||
      "type": "library",
 | 
			
		||||
      "root": "libs/system-config",
 | 
			
		||||
      "entryFile": "index",
 | 
			
		||||
      "sourceRoot": "libs/system-config/src",
 | 
			
		||||
      "compilerOptions": {
 | 
			
		||||
        "tsConfigPath": "libs/system-config/tsconfig.lib.json"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
    "build": "nest build immich && nest build microservices && nest build cli",
 | 
			
		||||
    "format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
 | 
			
		||||
    "start": "nest start",
 | 
			
		||||
    "nest": "nest",
 | 
			
		||||
    "start:dev": "nest start --watch",
 | 
			
		||||
    "start:debug": "nest start --debug 0.0.0.0:9230 --watch",
 | 
			
		||||
    "start:prod": "node dist/main",
 | 
			
		||||
@ -139,7 +140,8 @@
 | 
			
		||||
      "@app/database/config/(.*)": "<rootDir>/libs/database/src/config/$1",
 | 
			
		||||
      "@app/database/config": "<rootDir>/libs/database/src/config",
 | 
			
		||||
      "@app/common": "<rootDir>/libs/common/src",
 | 
			
		||||
      "^@app/job(|/.*)$": "<rootDir>/libs/job/src/$1"
 | 
			
		||||
      "^@app/job(|/.*)$": "<rootDir>/libs/job/src/$1",
 | 
			
		||||
      "^@app/system-config(|/.*)$": "<rootDir>/libs/system-config/src/$1"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -16,29 +16,15 @@
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "baseUrl": "./",
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@app/common": [
 | 
			
		||||
        "libs/common/src"
 | 
			
		||||
      ],
 | 
			
		||||
      "@app/common/*": [
 | 
			
		||||
        "libs/common/src/*"
 | 
			
		||||
      ],
 | 
			
		||||
      "@app/database": [
 | 
			
		||||
        "libs/database/src"
 | 
			
		||||
      ],
 | 
			
		||||
      "@app/database/*": [
 | 
			
		||||
        "libs/database/src/*"
 | 
			
		||||
      ],
 | 
			
		||||
      "@app/job": [
 | 
			
		||||
        "libs/job/src"
 | 
			
		||||
      ],
 | 
			
		||||
      "@app/job/*": [
 | 
			
		||||
        "libs/job/src/*"
 | 
			
		||||
      ]
 | 
			
		||||
      "@app/common": ["libs/common/src"],
 | 
			
		||||
      "@app/common/*": ["libs/common/src/*"],
 | 
			
		||||
      "@app/database": ["libs/database/src"],
 | 
			
		||||
      "@app/database/*": ["libs/database/src/*"],
 | 
			
		||||
      "@app/job": ["libs/job/src"],
 | 
			
		||||
      "@app/job/*": ["libs/job/src/*"],
 | 
			
		||||
      "@app/system-config": ["libs/immich-config/src"],
 | 
			
		||||
      "@app/system-config/*": ["libs/immich-config/src/*"]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "exclude": [
 | 
			
		||||
    "dist",
 | 
			
		||||
    "node_modules",
 | 
			
		||||
    "upload"
 | 
			
		||||
  ]
 | 
			
		||||
  "exclude": ["dist", "node_modules", "upload"]
 | 
			
		||||
}
 | 
			
		||||
@ -8,6 +8,7 @@ import {
 | 
			
		||||
	JobApi,
 | 
			
		||||
	OAuthApi,
 | 
			
		||||
	ServerInfoApi,
 | 
			
		||||
	SystemConfigApi,
 | 
			
		||||
	UserApi
 | 
			
		||||
} from './open-api';
 | 
			
		||||
 | 
			
		||||
@ -20,6 +21,7 @@ class ImmichApi {
 | 
			
		||||
	public deviceInfoApi: DeviceInfoApi;
 | 
			
		||||
	public serverInfoApi: ServerInfoApi;
 | 
			
		||||
	public jobApi: JobApi;
 | 
			
		||||
	public systemConfigApi: SystemConfigApi;
 | 
			
		||||
 | 
			
		||||
	private config = new Configuration({ basePath: '/api' });
 | 
			
		||||
 | 
			
		||||
@ -32,6 +34,7 @@ class ImmichApi {
 | 
			
		||||
		this.deviceInfoApi = new DeviceInfoApi(this.config);
 | 
			
		||||
		this.serverInfoApi = new ServerInfoApi(this.config);
 | 
			
		||||
		this.jobApi = new JobApi(this.config);
 | 
			
		||||
		this.systemConfigApi = new SystemConfigApi(this.config);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public setAccessToken(accessToken: string) {
 | 
			
		||||
 | 
			
		||||
@ -1407,6 +1407,67 @@ export interface SmartInfoResponseDto {
 | 
			
		||||
 * @enum {string}
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export const SystemConfigKey = {
 | 
			
		||||
    Crf: 'ffmpeg_crf',
 | 
			
		||||
    Preset: 'ffmpeg_preset',
 | 
			
		||||
    TargetVideoCodec: 'ffmpeg_target_video_codec',
 | 
			
		||||
    TargetAudioCodec: 'ffmpeg_target_audio_codec',
 | 
			
		||||
    TargetScaling: 'ffmpeg_target_scaling'
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type SystemConfigKey = typeof SystemConfigKey[keyof typeof SystemConfigKey];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface SystemConfigResponseDto
 | 
			
		||||
 */
 | 
			
		||||
export interface SystemConfigResponseDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {Array<SystemConfigResponseItem>}
 | 
			
		||||
     * @memberof SystemConfigResponseDto
 | 
			
		||||
     */
 | 
			
		||||
    'config': Array<SystemConfigResponseItem>;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface SystemConfigResponseItem
 | 
			
		||||
 */
 | 
			
		||||
export interface SystemConfigResponseItem {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof SystemConfigResponseItem
 | 
			
		||||
     */
 | 
			
		||||
    'name': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {SystemConfigKey}
 | 
			
		||||
     * @memberof SystemConfigResponseItem
 | 
			
		||||
     */
 | 
			
		||||
    'key': SystemConfigKey;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof SystemConfigResponseItem
 | 
			
		||||
     */
 | 
			
		||||
    'value': string;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof SystemConfigResponseItem
 | 
			
		||||
     */
 | 
			
		||||
    'defaultValue': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @enum {string}
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export const ThumbnailFormat = {
 | 
			
		||||
    Jpeg: 'JPEG',
 | 
			
		||||
    Webp: 'WEBP'
 | 
			
		||||
@ -4946,6 +5007,173 @@ export class ServerInfoApi extends BaseAPI {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SystemConfigApi - axios parameter creator
 | 
			
		||||
 * @export
 | 
			
		||||
 */
 | 
			
		||||
export const SystemConfigApiAxiosParamCreator = function (configuration?: Configuration) {
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getConfig: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
			
		||||
            const localVarPath = `/system-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;
 | 
			
		||||
 | 
			
		||||
            // authentication bearer required
 | 
			
		||||
            // http bearer authentication required
 | 
			
		||||
            await setBearerAuthToObject(localVarHeaderParameter, configuration)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
			
		||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
			
		||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                url: toPathString(localVarUrlObj),
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {object} body 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        updateConfig: async (body: object, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
			
		||||
            // verify required parameter 'body' is not null or undefined
 | 
			
		||||
            assertParamExists('updateConfig', 'body', body)
 | 
			
		||||
            const localVarPath = `/system-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: 'PUT', ...baseOptions, ...options};
 | 
			
		||||
            const localVarHeaderParameter = {} as any;
 | 
			
		||||
            const localVarQueryParameter = {} as any;
 | 
			
		||||
 | 
			
		||||
            // authentication bearer required
 | 
			
		||||
            // http bearer authentication required
 | 
			
		||||
            await setBearerAuthToObject(localVarHeaderParameter, configuration)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
            localVarHeaderParameter['Content-Type'] = 'application/json';
 | 
			
		||||
 | 
			
		||||
            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
			
		||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
			
		||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
			
		||||
            localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration)
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                url: toPathString(localVarUrlObj),
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SystemConfigApi - functional programming interface
 | 
			
		||||
 * @export
 | 
			
		||||
 */
 | 
			
		||||
export const SystemConfigApiFp = function(configuration?: Configuration) {
 | 
			
		||||
    const localVarAxiosParamCreator = SystemConfigApiAxiosParamCreator(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        async getConfig(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SystemConfigResponseDto>> {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.getConfig(options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {object} body 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        async updateConfig(body: object, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SystemConfigResponseDto>> {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.updateConfig(body, options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SystemConfigApi - factory interface
 | 
			
		||||
 * @export
 | 
			
		||||
 */
 | 
			
		||||
export const SystemConfigApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
 | 
			
		||||
    const localVarFp = SystemConfigApiFp(configuration)
 | 
			
		||||
    return {
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        getConfig(options?: any): AxiosPromise<SystemConfigResponseDto> {
 | 
			
		||||
            return localVarFp.getConfig(options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {object} body 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        updateConfig(body: object, options?: any): AxiosPromise<SystemConfigResponseDto> {
 | 
			
		||||
            return localVarFp.updateConfig(body, options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SystemConfigApi - object-oriented interface
 | 
			
		||||
 * @export
 | 
			
		||||
 * @class SystemConfigApi
 | 
			
		||||
 * @extends {BaseAPI}
 | 
			
		||||
 */
 | 
			
		||||
export class SystemConfigApi extends BaseAPI {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
     * @throws {RequiredError}
 | 
			
		||||
     * @memberof SystemConfigApi
 | 
			
		||||
     */
 | 
			
		||||
    public getConfig(options?: AxiosRequestConfig) {
 | 
			
		||||
        return SystemConfigApiFp(this.configuration).getConfig(options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {object} body 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
     * @throws {RequiredError}
 | 
			
		||||
     * @memberof SystemConfigApi
 | 
			
		||||
     */
 | 
			
		||||
    public updateConfig(body: object, options?: AxiosRequestConfig) {
 | 
			
		||||
        return SystemConfigApiFp(this.configuration).updateConfig(body, options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * UserApi - axios parameter creator
 | 
			
		||||
 * @export
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ input:focus-visible {
 | 
			
		||||
 | 
			
		||||
@layer utilities {
 | 
			
		||||
	.immich-form-input {
 | 
			
		||||
		@apply bg-slate-100 p-2 rounded-md dark:text-immich-dark-bg focus:border-immich-primary text-sm;
 | 
			
		||||
		@apply bg-slate-100 p-2 rounded-md dark:text-immich-dark-bg focus:border-immich-primary text-sm dark:bg-gray-600 dark:text-immich-dark-fg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.immich-form-label {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,97 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
 | 
			
		||||
	import {
 | 
			
		||||
		notificationController,
 | 
			
		||||
		NotificationType
 | 
			
		||||
	} from '$lib/components/shared-components/notification/notification';
 | 
			
		||||
	import { api, SystemConfigResponseItem } from '@api';
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
 | 
			
		||||
	let isSaving = false;
 | 
			
		||||
	let items: Array<SystemConfigResponseItem & { originalValue: string }> = [];
 | 
			
		||||
 | 
			
		||||
	const refreshConfig = async () => {
 | 
			
		||||
		const { data: systemConfig } = await api.systemConfigApi.getConfig();
 | 
			
		||||
		items = systemConfig.config.map((item) => ({ ...item, originalValue: item.value }));
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	onMount(() => refreshConfig());
 | 
			
		||||
 | 
			
		||||
	const handleSave = async () => {
 | 
			
		||||
		try {
 | 
			
		||||
			isSaving = true;
 | 
			
		||||
			const updates = items
 | 
			
		||||
				.filter((item) => item.value !== item.originalValue)
 | 
			
		||||
				.map(({ key, value }) => ({ key, value: value || null }));
 | 
			
		||||
			if (updates.length > 0) {
 | 
			
		||||
				await api.systemConfigApi.updateConfig({ config: updates });
 | 
			
		||||
				refreshConfig();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			notificationController.show({
 | 
			
		||||
				message: `Saved settings`,
 | 
			
		||||
				type: NotificationType.Info
 | 
			
		||||
			});
 | 
			
		||||
		} catch (e) {
 | 
			
		||||
			console.error('Error [updateSystemConfig]', e);
 | 
			
		||||
			notificationController.show({
 | 
			
		||||
				message: `Unable to save changes.`,
 | 
			
		||||
				type: NotificationType.Error
 | 
			
		||||
			});
 | 
			
		||||
		} finally {
 | 
			
		||||
			isSaving = false;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section>
 | 
			
		||||
	<table class="text-left my-4 w-full">
 | 
			
		||||
		<thead
 | 
			
		||||
			class="border rounded-md mb-4 bg-gray-50 flex text-immich-primary h-12 dark:bg-immich-dark-gray dark:text-immich-dark-primary dark:border-immich-dark-gray"
 | 
			
		||||
		>
 | 
			
		||||
			<tr class="flex w-full place-items-center">
 | 
			
		||||
				<th class="text-center w-1/2 font-medium text-sm">Setting</th>
 | 
			
		||||
				<th class="text-center w-1/2 font-medium text-sm">Value</th>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</thead>
 | 
			
		||||
		<tbody class="rounded-md block border dark:border-immich-dark-gray">
 | 
			
		||||
			{#each items as item, i}
 | 
			
		||||
				<tr
 | 
			
		||||
					class={`text-center flex place-items-center w-full h-[80px] dark:text-immich-dark-fg ${
 | 
			
		||||
						i % 2 == 0 ? 'bg-slate-50 dark:bg-[#181818]' : 'bg-immich-bg dark:bg-immich-dark-bg'
 | 
			
		||||
					}`}
 | 
			
		||||
				>
 | 
			
		||||
					<td class="text-sm px-4 w-1/2 text-ellipsis">
 | 
			
		||||
						{item.name}
 | 
			
		||||
					</td>
 | 
			
		||||
					<td class="text-sm px-4 w-1/2 text-ellipsis">
 | 
			
		||||
						<input
 | 
			
		||||
							style="text-align: center"
 | 
			
		||||
							class="immich-form-input"
 | 
			
		||||
							id={item.key}
 | 
			
		||||
							disabled={isSaving}
 | 
			
		||||
							name={item.key}
 | 
			
		||||
							type="text"
 | 
			
		||||
							bind:value={item.value}
 | 
			
		||||
							placeholder={item.defaultValue + ''}
 | 
			
		||||
						/>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			{/each}
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
 | 
			
		||||
	<div class="flex justify-end">
 | 
			
		||||
		<button
 | 
			
		||||
			on:click={handleSave}
 | 
			
		||||
			class="px-6 py-3 text-sm bg-immich-primary dark:bg-immich-dark-primary font-medium rounded-2xl hover:bg-immich-primary/50 transition-all hover:cursor-pointer disabled:cursor-not-allowed shadow-sm text-immich-bg dark:text-immich-dark-gray"
 | 
			
		||||
			disabled={isSaving}
 | 
			
		||||
		>
 | 
			
		||||
			{#if isSaving}
 | 
			
		||||
				<LoadingSpinner />
 | 
			
		||||
			{:else}
 | 
			
		||||
				Save
 | 
			
		||||
			{/if}
 | 
			
		||||
		</button>
 | 
			
		||||
	</div>
 | 
			
		||||
</section>
 | 
			
		||||
@ -12,8 +12,6 @@ export const load: PageServerLoad = async ({ parent }) => {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const { data: allUsers } = await serverApi.userApi.getAllUsers(false);
 | 
			
		||||
	return {
 | 
			
		||||
		user: user,
 | 
			
		||||
		allUsers: allUsers
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return { user, allUsers };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
	import { AdminSideBarSelection } from '$lib/models/admin-sidebar-selection';
 | 
			
		||||
	import SideBarButton from '$lib/components/shared-components/side-bar/side-bar-button.svelte';
 | 
			
		||||
	import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
 | 
			
		||||
	import Sync from 'svelte-material-icons/Sync.svelte';
 | 
			
		||||
	import Cog from 'svelte-material-icons/Cog.svelte';
 | 
			
		||||
	import Server from 'svelte-material-icons/Server.svelte';
 | 
			
		||||
	import NavigationBar from '$lib/components/shared-components/navigation-bar.svelte';
 | 
			
		||||
@ -16,6 +17,7 @@
 | 
			
		||||
	import type { PageData } from './$types';
 | 
			
		||||
	import { api, ServerStatsResponseDto, UserResponseDto } from '@api';
 | 
			
		||||
	import JobsPanel from '$lib/components/admin-page/jobs/jobs-panel.svelte';
 | 
			
		||||
	import SettingsPanel from '$lib/components/admin-page/settings/settings-panel.svelte';
 | 
			
		||||
	import ServerStatsPanel from '$lib/components/admin-page/server-stats/server-stats-panel.svelte';
 | 
			
		||||
	import RestoreDialoge from '$lib/components/admin-page/restore-dialoge.svelte';
 | 
			
		||||
 | 
			
		||||
@ -190,11 +192,18 @@
 | 
			
		||||
		/>
 | 
			
		||||
		<SideBarButton
 | 
			
		||||
			title="Jobs"
 | 
			
		||||
			logo={Cog}
 | 
			
		||||
			logo={Sync}
 | 
			
		||||
			actionType={AdminSideBarSelection.JOBS}
 | 
			
		||||
			isSelected={selectedAction === AdminSideBarSelection.JOBS}
 | 
			
		||||
			on:selected={onButtonClicked}
 | 
			
		||||
		/>
 | 
			
		||||
		<SideBarButton
 | 
			
		||||
			title="Settings"
 | 
			
		||||
			logo={Cog}
 | 
			
		||||
			actionType={AdminSideBarSelection.SETTINGS}
 | 
			
		||||
			isSelected={selectedAction === AdminSideBarSelection.SETTINGS}
 | 
			
		||||
			on:selected={onButtonClicked}
 | 
			
		||||
		/>
 | 
			
		||||
		<SideBarButton
 | 
			
		||||
			title="Server Stats"
 | 
			
		||||
			logo={Server}
 | 
			
		||||
@ -228,6 +237,9 @@
 | 
			
		||||
				{#if selectedAction === AdminSideBarSelection.JOBS}
 | 
			
		||||
					<JobsPanel />
 | 
			
		||||
				{/if}
 | 
			
		||||
				{#if selectedAction === AdminSideBarSelection.SETTINGS}
 | 
			
		||||
					<SettingsPanel />
 | 
			
		||||
				{/if}
 | 
			
		||||
				{#if selectedAction === AdminSideBarSelection.STATS && serverStat}
 | 
			
		||||
					<ServerStatsPanel stats={serverStat} allUsers={data.allUsers} />
 | 
			
		||||
				{/if}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user