mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	Add asset repository and refactor asset service (#540)
* build endpoint to get asset count by month * Added asset repository * Added create asset * get asset by device ID * Added test for existing methods * Refactor additional endpoint * Refactor database api to get curated locations and curated objects * Refactor get search properties * Fixed cookies parsing for websocket * Added API to get asset count by time group * Remove unused code
This commit is contained in:
		| @@ -8,6 +8,8 @@ doc/AdminSignupResponseDto.md | ||||
| doc/AlbumApi.md | ||||
| doc/AlbumResponseDto.md | ||||
| doc/AssetApi.md | ||||
| doc/AssetCountByTimeGroupDto.md | ||||
| doc/AssetCountByTimeGroupResponseDto.md | ||||
| doc/AssetFileUploadResponseDto.md | ||||
| doc/AssetResponseDto.md | ||||
| doc/AssetTypeEnum.md | ||||
| @@ -27,6 +29,7 @@ doc/DeviceInfoApi.md | ||||
| doc/DeviceInfoResponseDto.md | ||||
| doc/DeviceTypeEnum.md | ||||
| doc/ExifResponseDto.md | ||||
| doc/GetAssetCountByTimeGroupDto.md | ||||
| doc/LoginCredentialDto.md | ||||
| doc/LoginResponseDto.md | ||||
| doc/LogoutResponseDto.md | ||||
| @@ -39,6 +42,7 @@ doc/ServerVersionReponseDto.md | ||||
| doc/SignUpDto.md | ||||
| doc/SmartInfoResponseDto.md | ||||
| doc/ThumbnailFormat.md | ||||
| doc/TimeGroupEnum.md | ||||
| doc/UpdateAlbumDto.md | ||||
| doc/UpdateDeviceInfoDto.md | ||||
| doc/UpdateUserDto.md | ||||
| @@ -66,6 +70,8 @@ lib/model/add_assets_dto.dart | ||||
| lib/model/add_users_dto.dart | ||||
| lib/model/admin_signup_response_dto.dart | ||||
| lib/model/album_response_dto.dart | ||||
| lib/model/asset_count_by_time_group_dto.dart | ||||
| lib/model/asset_count_by_time_group_response_dto.dart | ||||
| lib/model/asset_file_upload_response_dto.dart | ||||
| lib/model/asset_response_dto.dart | ||||
| lib/model/asset_type_enum.dart | ||||
| @@ -83,6 +89,7 @@ lib/model/delete_asset_status.dart | ||||
| lib/model/device_info_response_dto.dart | ||||
| lib/model/device_type_enum.dart | ||||
| lib/model/exif_response_dto.dart | ||||
| lib/model/get_asset_count_by_time_group_dto.dart | ||||
| lib/model/login_credential_dto.dart | ||||
| lib/model/login_response_dto.dart | ||||
| lib/model/logout_response_dto.dart | ||||
| @@ -94,6 +101,7 @@ lib/model/server_version_reponse_dto.dart | ||||
| lib/model/sign_up_dto.dart | ||||
| lib/model/smart_info_response_dto.dart | ||||
| lib/model/thumbnail_format.dart | ||||
| lib/model/time_group_enum.dart | ||||
| lib/model/update_album_dto.dart | ||||
| lib/model/update_device_info_dto.dart | ||||
| lib/model/update_user_dto.dart | ||||
|   | ||||
| @@ -79,10 +79,11 @@ Class | Method | HTTP request | Description | ||||
| *AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **GET** /asset/download |  | ||||
| *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |  | ||||
| *AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{assetId} |  | ||||
| *AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/searchTerm |  | ||||
| *AssetApi* | [**getAssetCountByTimeGroup**](doc//AssetApi.md#getassetcountbytimegroup) | **GET** /asset/count-by-date |  | ||||
| *AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |  | ||||
| *AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{assetId} |  | ||||
| *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/allLocation |  | ||||
| *AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/allObjects |  | ||||
| *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |  | ||||
| *AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |  | ||||
| *AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |  | ||||
| *AssetApi* | [**searchAsset**](doc//AssetApi.md#searchasset) | **POST** /asset/search |  | ||||
| *AssetApi* | [**serveFile**](doc//AssetApi.md#servefile) | **GET** /asset/file |  | ||||
| @@ -112,6 +113,8 @@ Class | Method | HTTP request | Description | ||||
|  - [AddUsersDto](doc//AddUsersDto.md) | ||||
|  - [AdminSignupResponseDto](doc//AdminSignupResponseDto.md) | ||||
|  - [AlbumResponseDto](doc//AlbumResponseDto.md) | ||||
|  - [AssetCountByTimeGroupDto](doc//AssetCountByTimeGroupDto.md) | ||||
|  - [AssetCountByTimeGroupResponseDto](doc//AssetCountByTimeGroupResponseDto.md) | ||||
|  - [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md) | ||||
|  - [AssetResponseDto](doc//AssetResponseDto.md) | ||||
|  - [AssetTypeEnum](doc//AssetTypeEnum.md) | ||||
| @@ -129,6 +132,7 @@ Class | Method | HTTP request | Description | ||||
|  - [DeviceInfoResponseDto](doc//DeviceInfoResponseDto.md) | ||||
|  - [DeviceTypeEnum](doc//DeviceTypeEnum.md) | ||||
|  - [ExifResponseDto](doc//ExifResponseDto.md) | ||||
|  - [GetAssetCountByTimeGroupDto](doc//GetAssetCountByTimeGroupDto.md) | ||||
|  - [LoginCredentialDto](doc//LoginCredentialDto.md) | ||||
|  - [LoginResponseDto](doc//LoginResponseDto.md) | ||||
|  - [LogoutResponseDto](doc//LogoutResponseDto.md) | ||||
| @@ -140,6 +144,7 @@ Class | Method | HTTP request | Description | ||||
|  - [SignUpDto](doc//SignUpDto.md) | ||||
|  - [SmartInfoResponseDto](doc//SmartInfoResponseDto.md) | ||||
|  - [ThumbnailFormat](doc//ThumbnailFormat.md) | ||||
|  - [TimeGroupEnum](doc//TimeGroupEnum.md) | ||||
|  - [UpdateAlbumDto](doc//UpdateAlbumDto.md) | ||||
|  - [UpdateDeviceInfoDto](doc//UpdateDeviceInfoDto.md) | ||||
|  - [UpdateUserDto](doc//UpdateUserDto.md) | ||||
|   | ||||
| @@ -14,10 +14,11 @@ Method | HTTP request | Description | ||||
| [**downloadFile**](AssetApi.md#downloadfile) | **GET** /asset/download |  | ||||
| [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset |  | ||||
| [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{assetId} |  | ||||
| [**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/searchTerm |  | ||||
| [**getAssetCountByTimeGroup**](AssetApi.md#getassetcountbytimegroup) | **GET** /asset/count-by-date |  | ||||
| [**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |  | ||||
| [**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{assetId} |  | ||||
| [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/allLocation |  | ||||
| [**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/allObjects |  | ||||
| [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |  | ||||
| [**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |  | ||||
| [**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |  | ||||
| [**searchAsset**](AssetApi.md#searchasset) | **POST** /asset/search |  | ||||
| [**serveFile**](AssetApi.md#servefile) | **GET** /asset/file |  | ||||
| @@ -267,6 +268,53 @@ Name | Type | Description  | Notes | ||||
|  | ||||
| [[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) | ||||
|  | ||||
| # **getAssetCountByTimeGroup** | ||||
| > AssetCountByTimeGroupResponseDto getAssetCountByTimeGroup(getAssetCountByTimeGroupDto) | ||||
|  | ||||
|  | ||||
|  | ||||
| ### 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 = AssetApi(); | ||||
| final getAssetCountByTimeGroupDto = GetAssetCountByTimeGroupDto(); // GetAssetCountByTimeGroupDto |  | ||||
|  | ||||
| try { | ||||
|     final result = api_instance.getAssetCountByTimeGroup(getAssetCountByTimeGroupDto); | ||||
|     print(result); | ||||
| } catch (e) { | ||||
|     print('Exception when calling AssetApi->getAssetCountByTimeGroup: $e\n'); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Parameters | ||||
|  | ||||
| Name | Type | Description  | Notes | ||||
| ------------- | ------------- | ------------- | ------------- | ||||
|  **getAssetCountByTimeGroupDto** | [**GetAssetCountByTimeGroupDto**](GetAssetCountByTimeGroupDto.md)|  |  | ||||
|  | ||||
| ### Return type | ||||
|  | ||||
| [**AssetCountByTimeGroupResponseDto**](AssetCountByTimeGroupResponseDto.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) | ||||
|  | ||||
| # **getAssetSearchTerms** | ||||
| > List<String> getAssetSearchTerms() | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/AssetCountByTimeGroupDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/AssetCountByTimeGroupDto.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # openapi.model.AssetCountByTimeGroupDto | ||||
|  | ||||
| ## Load the model package | ||||
| ```dart | ||||
| import 'package:openapi/api.dart'; | ||||
| ``` | ||||
|  | ||||
| ## Properties | ||||
| Name | Type | Description | Notes | ||||
| ------------ | ------------- | ------------- | ------------- | ||||
| **timeGroup** | **String** |  |  | ||||
| **count** | **int** |  |  | ||||
|  | ||||
| [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) | ||||
|  | ||||
|  | ||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/AssetCountByTimeGroupResponseDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/AssetCountByTimeGroupResponseDto.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # openapi.model.AssetCountByTimeGroupResponseDto | ||||
|  | ||||
| ## Load the model package | ||||
| ```dart | ||||
| import 'package:openapi/api.dart'; | ||||
| ``` | ||||
|  | ||||
| ## Properties | ||||
| Name | Type | Description | Notes | ||||
| ------------ | ------------- | ------------- | ------------- | ||||
| **totalAssets** | **int** |  |  | ||||
| **groups** | [**List<AssetCountByTimeGroupDto>**](AssetCountByTimeGroupDto.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) | ||||
|  | ||||
|  | ||||
							
								
								
									
										15
									
								
								mobile/openapi/doc/GetAssetCountByTimeGroupDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mobile/openapi/doc/GetAssetCountByTimeGroupDto.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # openapi.model.GetAssetCountByTimeGroupDto | ||||
|  | ||||
| ## Load the model package | ||||
| ```dart | ||||
| import 'package:openapi/api.dart'; | ||||
| ``` | ||||
|  | ||||
| ## Properties | ||||
| Name | Type | Description | Notes | ||||
| ------------ | ------------- | ------------- | ------------- | ||||
| **timeGroup** | [**TimeGroupEnum**](TimeGroupEnum.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/TimeGroupEnum.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								mobile/openapi/doc/TimeGroupEnum.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # openapi.model.TimeGroupEnum | ||||
|  | ||||
| ## 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) | ||||
|  | ||||
|  | ||||
| @@ -38,6 +38,8 @@ part 'model/add_assets_dto.dart'; | ||||
| part 'model/add_users_dto.dart'; | ||||
| part 'model/admin_signup_response_dto.dart'; | ||||
| part 'model/album_response_dto.dart'; | ||||
| part 'model/asset_count_by_time_group_dto.dart'; | ||||
| part 'model/asset_count_by_time_group_response_dto.dart'; | ||||
| part 'model/asset_file_upload_response_dto.dart'; | ||||
| part 'model/asset_response_dto.dart'; | ||||
| part 'model/asset_type_enum.dart'; | ||||
| @@ -55,6 +57,7 @@ part 'model/delete_asset_status.dart'; | ||||
| part 'model/device_info_response_dto.dart'; | ||||
| part 'model/device_type_enum.dart'; | ||||
| part 'model/exif_response_dto.dart'; | ||||
| part 'model/get_asset_count_by_time_group_dto.dart'; | ||||
| part 'model/login_credential_dto.dart'; | ||||
| part 'model/login_response_dto.dart'; | ||||
| part 'model/logout_response_dto.dart'; | ||||
| @@ -66,6 +69,7 @@ part 'model/server_version_reponse_dto.dart'; | ||||
| part 'model/sign_up_dto.dart'; | ||||
| part 'model/smart_info_response_dto.dart'; | ||||
| part 'model/thumbnail_format.dart'; | ||||
| part 'model/time_group_enum.dart'; | ||||
| part 'model/update_album_dto.dart'; | ||||
| part 'model/update_device_info_dto.dart'; | ||||
| part 'model/update_user_dto.dart'; | ||||
|   | ||||
| @@ -298,10 +298,57 @@ class AssetApi { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   /// Performs an HTTP 'GET /asset/searchTerm' operation and returns the [Response]. | ||||
|   /// Performs an HTTP 'GET /asset/count-by-date' operation and returns the [Response]. | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [GetAssetCountByTimeGroupDto] getAssetCountByTimeGroupDto (required): | ||||
|   Future<Response> getAssetCountByTimeGroupWithHttpInfo(GetAssetCountByTimeGroupDto getAssetCountByTimeGroupDto,) async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/asset/count-by-date'; | ||||
|  | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody = getAssetCountByTimeGroupDto; | ||||
|  | ||||
|     final queryParams = <QueryParam>[]; | ||||
|     final headerParams = <String, String>{}; | ||||
|     final formParams = <String, String>{}; | ||||
|  | ||||
|     const contentTypes = <String>['application/json']; | ||||
|  | ||||
|  | ||||
|     return apiClient.invokeAPI( | ||||
|       path, | ||||
|       'GET', | ||||
|       queryParams, | ||||
|       postBody, | ||||
|       headerParams, | ||||
|       formParams, | ||||
|       contentTypes.isEmpty ? null : contentTypes.first, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [GetAssetCountByTimeGroupDto] getAssetCountByTimeGroupDto (required): | ||||
|   Future<AssetCountByTimeGroupResponseDto?> getAssetCountByTimeGroup(GetAssetCountByTimeGroupDto getAssetCountByTimeGroupDto,) async { | ||||
|     final response = await getAssetCountByTimeGroupWithHttpInfo(getAssetCountByTimeGroupDto,); | ||||
|     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), 'AssetCountByTimeGroupResponseDto',) as AssetCountByTimeGroupResponseDto; | ||||
|      | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   /// Performs an HTTP 'GET /asset/search-terms' operation and returns the [Response]. | ||||
|   Future<Response> getAssetSearchTermsWithHttpInfo() async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/asset/searchTerm'; | ||||
|     final path = r'/asset/search-terms'; | ||||
|  | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody; | ||||
| @@ -398,10 +445,10 @@ class AssetApi { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   /// Performs an HTTP 'GET /asset/allLocation' operation and returns the [Response]. | ||||
|   /// Performs an HTTP 'GET /asset/curated-locations' operation and returns the [Response]. | ||||
|   Future<Response> getCuratedLocationsWithHttpInfo() async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/asset/allLocation'; | ||||
|     final path = r'/asset/curated-locations'; | ||||
|  | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody; | ||||
| @@ -442,10 +489,10 @@ class AssetApi { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   /// Performs an HTTP 'GET /asset/allObjects' operation and returns the [Response]. | ||||
|   /// Performs an HTTP 'GET /asset/curated-objects' operation and returns the [Response]. | ||||
|   Future<Response> getCuratedObjectsWithHttpInfo() async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/asset/allObjects'; | ||||
|     final path = r'/asset/curated-objects'; | ||||
|  | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody; | ||||
|   | ||||
| @@ -200,6 +200,10 @@ class ApiClient { | ||||
|           return AdminSignupResponseDto.fromJson(value); | ||||
|         case 'AlbumResponseDto': | ||||
|           return AlbumResponseDto.fromJson(value); | ||||
|         case 'AssetCountByTimeGroupDto': | ||||
|           return AssetCountByTimeGroupDto.fromJson(value); | ||||
|         case 'AssetCountByTimeGroupResponseDto': | ||||
|           return AssetCountByTimeGroupResponseDto.fromJson(value); | ||||
|         case 'AssetFileUploadResponseDto': | ||||
|           return AssetFileUploadResponseDto.fromJson(value); | ||||
|         case 'AssetResponseDto': | ||||
| @@ -234,6 +238,8 @@ class ApiClient { | ||||
|           return DeviceTypeEnumTypeTransformer().decode(value); | ||||
|         case 'ExifResponseDto': | ||||
|           return ExifResponseDto.fromJson(value); | ||||
|         case 'GetAssetCountByTimeGroupDto': | ||||
|           return GetAssetCountByTimeGroupDto.fromJson(value); | ||||
|         case 'LoginCredentialDto': | ||||
|           return LoginCredentialDto.fromJson(value); | ||||
|         case 'LoginResponseDto': | ||||
| @@ -256,6 +262,8 @@ class ApiClient { | ||||
|           return SmartInfoResponseDto.fromJson(value); | ||||
|         case 'ThumbnailFormat': | ||||
|           return ThumbnailFormatTypeTransformer().decode(value); | ||||
|         case 'TimeGroupEnum': | ||||
|           return TimeGroupEnumTypeTransformer().decode(value); | ||||
|         case 'UpdateAlbumDto': | ||||
|           return UpdateAlbumDto.fromJson(value); | ||||
|         case 'UpdateDeviceInfoDto': | ||||
|   | ||||
| @@ -67,6 +67,9 @@ String parameterToString(dynamic value) { | ||||
|   if (value is ThumbnailFormat) { | ||||
|     return ThumbnailFormatTypeTransformer().encode(value).toString(); | ||||
|   } | ||||
|   if (value is TimeGroupEnum) { | ||||
|     return TimeGroupEnumTypeTransformer().encode(value).toString(); | ||||
|   } | ||||
|   return value.toString(); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										119
									
								
								mobile/openapi/lib/model/asset_count_by_time_group_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								mobile/openapi/lib/model/asset_count_by_time_group_dto.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| // | ||||
| // 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 AssetCountByTimeGroupDto { | ||||
|   /// Returns a new [AssetCountByTimeGroupDto] instance. | ||||
|   AssetCountByTimeGroupDto({ | ||||
|     required this.timeGroup, | ||||
|     required this.count, | ||||
|   }); | ||||
|  | ||||
|   String timeGroup; | ||||
|  | ||||
|   int count; | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) => identical(this, other) || other is AssetCountByTimeGroupDto && | ||||
|      other.timeGroup == timeGroup && | ||||
|      other.count == count; | ||||
|  | ||||
|   @override | ||||
|   int get hashCode => | ||||
|     // ignore: unnecessary_parenthesis | ||||
|     (timeGroup.hashCode) + | ||||
|     (count.hashCode); | ||||
|  | ||||
|   @override | ||||
|   String toString() => 'AssetCountByTimeGroupDto[timeGroup=$timeGroup, count=$count]'; | ||||
|  | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final _json = <String, dynamic>{}; | ||||
|       _json[r'timeGroup'] = timeGroup; | ||||
|       _json[r'count'] = count; | ||||
|     return _json; | ||||
|   } | ||||
|  | ||||
|   /// Returns a new [AssetCountByTimeGroupDto] instance and imports its values from | ||||
|   /// [value] if it's a [Map], null otherwise. | ||||
|   // ignore: prefer_constructors_over_static_methods | ||||
|   static AssetCountByTimeGroupDto? 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 "AssetCountByTimeGroupDto[$key]" is missing from JSON.'); | ||||
|           assert(json[key] != null, 'Required key "AssetCountByTimeGroupDto[$key]" has a null value in JSON.'); | ||||
|         }); | ||||
|         return true; | ||||
|       }()); | ||||
|  | ||||
|       return AssetCountByTimeGroupDto( | ||||
|         timeGroup: mapValueOfType<String>(json, r'timeGroup')!, | ||||
|         count: mapValueOfType<int>(json, r'count')!, | ||||
|       ); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   static List<AssetCountByTimeGroupDto>? listFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final result = <AssetCountByTimeGroupDto>[]; | ||||
|     if (json is List && json.isNotEmpty) { | ||||
|       for (final row in json) { | ||||
|         final value = AssetCountByTimeGroupDto.fromJson(row); | ||||
|         if (value != null) { | ||||
|           result.add(value); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return result.toList(growable: growable); | ||||
|   } | ||||
|  | ||||
|   static Map<String, AssetCountByTimeGroupDto> mapFromJson(dynamic json) { | ||||
|     final map = <String, AssetCountByTimeGroupDto>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = AssetCountByTimeGroupDto.fromJson(entry.value); | ||||
|         if (value != null) { | ||||
|           map[entry.key] = value; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   // maps a json object with a list of AssetCountByTimeGroupDto-objects as value to a dart map | ||||
|   static Map<String, List<AssetCountByTimeGroupDto>> mapListFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final map = <String, List<AssetCountByTimeGroupDto>>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = AssetCountByTimeGroupDto.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>{ | ||||
|     'timeGroup', | ||||
|     'count', | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,119 @@ | ||||
| // | ||||
| // 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 AssetCountByTimeGroupResponseDto { | ||||
|   /// Returns a new [AssetCountByTimeGroupResponseDto] instance. | ||||
|   AssetCountByTimeGroupResponseDto({ | ||||
|     required this.totalAssets, | ||||
|     this.groups = const [], | ||||
|   }); | ||||
|  | ||||
|   int totalAssets; | ||||
|  | ||||
|   List<AssetCountByTimeGroupDto> groups; | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) => identical(this, other) || other is AssetCountByTimeGroupResponseDto && | ||||
|      other.totalAssets == totalAssets && | ||||
|      other.groups == groups; | ||||
|  | ||||
|   @override | ||||
|   int get hashCode => | ||||
|     // ignore: unnecessary_parenthesis | ||||
|     (totalAssets.hashCode) + | ||||
|     (groups.hashCode); | ||||
|  | ||||
|   @override | ||||
|   String toString() => 'AssetCountByTimeGroupResponseDto[totalAssets=$totalAssets, groups=$groups]'; | ||||
|  | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final _json = <String, dynamic>{}; | ||||
|       _json[r'totalAssets'] = totalAssets; | ||||
|       _json[r'groups'] = groups; | ||||
|     return _json; | ||||
|   } | ||||
|  | ||||
|   /// Returns a new [AssetCountByTimeGroupResponseDto] instance and imports its values from | ||||
|   /// [value] if it's a [Map], null otherwise. | ||||
|   // ignore: prefer_constructors_over_static_methods | ||||
|   static AssetCountByTimeGroupResponseDto? 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 "AssetCountByTimeGroupResponseDto[$key]" is missing from JSON.'); | ||||
|           assert(json[key] != null, 'Required key "AssetCountByTimeGroupResponseDto[$key]" has a null value in JSON.'); | ||||
|         }); | ||||
|         return true; | ||||
|       }()); | ||||
|  | ||||
|       return AssetCountByTimeGroupResponseDto( | ||||
|         totalAssets: mapValueOfType<int>(json, r'totalAssets')!, | ||||
|         groups: AssetCountByTimeGroupDto.listFromJson(json[r'groups'])!, | ||||
|       ); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   static List<AssetCountByTimeGroupResponseDto>? listFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final result = <AssetCountByTimeGroupResponseDto>[]; | ||||
|     if (json is List && json.isNotEmpty) { | ||||
|       for (final row in json) { | ||||
|         final value = AssetCountByTimeGroupResponseDto.fromJson(row); | ||||
|         if (value != null) { | ||||
|           result.add(value); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return result.toList(growable: growable); | ||||
|   } | ||||
|  | ||||
|   static Map<String, AssetCountByTimeGroupResponseDto> mapFromJson(dynamic json) { | ||||
|     final map = <String, AssetCountByTimeGroupResponseDto>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = AssetCountByTimeGroupResponseDto.fromJson(entry.value); | ||||
|         if (value != null) { | ||||
|           map[entry.key] = value; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   // maps a json object with a list of AssetCountByTimeGroupResponseDto-objects as value to a dart map | ||||
|   static Map<String, List<AssetCountByTimeGroupResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final map = <String, List<AssetCountByTimeGroupResponseDto>>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = AssetCountByTimeGroupResponseDto.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>{ | ||||
|     'totalAssets', | ||||
|     'groups', | ||||
|   }; | ||||
| } | ||||
|  | ||||
							
								
								
									
										111
									
								
								mobile/openapi/lib/model/get_asset_count_by_time_group_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								mobile/openapi/lib/model/get_asset_count_by_time_group_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 GetAssetCountByTimeGroupDto { | ||||
|   /// Returns a new [GetAssetCountByTimeGroupDto] instance. | ||||
|   GetAssetCountByTimeGroupDto({ | ||||
|     required this.timeGroup, | ||||
|   }); | ||||
|  | ||||
|   TimeGroupEnum timeGroup; | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) => identical(this, other) || other is GetAssetCountByTimeGroupDto && | ||||
|      other.timeGroup == timeGroup; | ||||
|  | ||||
|   @override | ||||
|   int get hashCode => | ||||
|     // ignore: unnecessary_parenthesis | ||||
|     (timeGroup.hashCode); | ||||
|  | ||||
|   @override | ||||
|   String toString() => 'GetAssetCountByTimeGroupDto[timeGroup=$timeGroup]'; | ||||
|  | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final _json = <String, dynamic>{}; | ||||
|       _json[r'timeGroup'] = timeGroup; | ||||
|     return _json; | ||||
|   } | ||||
|  | ||||
|   /// Returns a new [GetAssetCountByTimeGroupDto] instance and imports its values from | ||||
|   /// [value] if it's a [Map], null otherwise. | ||||
|   // ignore: prefer_constructors_over_static_methods | ||||
|   static GetAssetCountByTimeGroupDto? 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 "GetAssetCountByTimeGroupDto[$key]" is missing from JSON.'); | ||||
|           assert(json[key] != null, 'Required key "GetAssetCountByTimeGroupDto[$key]" has a null value in JSON.'); | ||||
|         }); | ||||
|         return true; | ||||
|       }()); | ||||
|  | ||||
|       return GetAssetCountByTimeGroupDto( | ||||
|         timeGroup: TimeGroupEnum.fromJson(json[r'timeGroup'])!, | ||||
|       ); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   static List<GetAssetCountByTimeGroupDto>? listFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final result = <GetAssetCountByTimeGroupDto>[]; | ||||
|     if (json is List && json.isNotEmpty) { | ||||
|       for (final row in json) { | ||||
|         final value = GetAssetCountByTimeGroupDto.fromJson(row); | ||||
|         if (value != null) { | ||||
|           result.add(value); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return result.toList(growable: growable); | ||||
|   } | ||||
|  | ||||
|   static Map<String, GetAssetCountByTimeGroupDto> mapFromJson(dynamic json) { | ||||
|     final map = <String, GetAssetCountByTimeGroupDto>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = GetAssetCountByTimeGroupDto.fromJson(entry.value); | ||||
|         if (value != null) { | ||||
|           map[entry.key] = value; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   // maps a json object with a list of GetAssetCountByTimeGroupDto-objects as value to a dart map | ||||
|   static Map<String, List<GetAssetCountByTimeGroupDto>> mapListFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final map = <String, List<GetAssetCountByTimeGroupDto>>{}; | ||||
|     if (json is Map && json.isNotEmpty) { | ||||
|       json = json.cast<String, dynamic>(); // ignore: parameter_assignments | ||||
|       for (final entry in json.entries) { | ||||
|         final value = GetAssetCountByTimeGroupDto.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>{ | ||||
|     'timeGroup', | ||||
|   }; | ||||
| } | ||||
|  | ||||
							
								
								
									
										85
									
								
								mobile/openapi/lib/model/time_group_enum.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								mobile/openapi/lib/model/time_group_enum.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| // | ||||
| // 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 TimeGroupEnum { | ||||
|   /// Instantiate a new enum with the provided [value]. | ||||
|   const TimeGroupEnum._(this.value); | ||||
|  | ||||
|   /// The underlying value of this enum member. | ||||
|   final String value; | ||||
|  | ||||
|   @override | ||||
|   String toString() => value; | ||||
|  | ||||
|   String toJson() => value; | ||||
|  | ||||
|   static const day = TimeGroupEnum._(r'day'); | ||||
|   static const month = TimeGroupEnum._(r'month'); | ||||
|  | ||||
|   /// List of all possible values in this [enum][TimeGroupEnum]. | ||||
|   static const values = <TimeGroupEnum>[ | ||||
|     day, | ||||
|     month, | ||||
|   ]; | ||||
|  | ||||
|   static TimeGroupEnum? fromJson(dynamic value) => TimeGroupEnumTypeTransformer().decode(value); | ||||
|  | ||||
|   static List<TimeGroupEnum>? listFromJson(dynamic json, {bool growable = false,}) { | ||||
|     final result = <TimeGroupEnum>[]; | ||||
|     if (json is List && json.isNotEmpty) { | ||||
|       for (final row in json) { | ||||
|         final value = TimeGroupEnum.fromJson(row); | ||||
|         if (value != null) { | ||||
|           result.add(value); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return result.toList(growable: growable); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// Transformation class that can [encode] an instance of [TimeGroupEnum] to String, | ||||
| /// and [decode] dynamic data back to [TimeGroupEnum]. | ||||
| class TimeGroupEnumTypeTransformer { | ||||
|   factory TimeGroupEnumTypeTransformer() => _instance ??= const TimeGroupEnumTypeTransformer._(); | ||||
|  | ||||
|   const TimeGroupEnumTypeTransformer._(); | ||||
|  | ||||
|   String encode(TimeGroupEnum data) => data.value; | ||||
|  | ||||
|   /// Decodes a [dynamic value][data] to a TimeGroupEnum. | ||||
|   /// | ||||
|   /// 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. | ||||
|   TimeGroupEnum? decode(dynamic data, {bool allowNull = true}) { | ||||
|     if (data != null) { | ||||
|       switch (data.toString()) { | ||||
|         case r'day': return TimeGroupEnum.day; | ||||
|         case r'month': return TimeGroupEnum.month; | ||||
|         default: | ||||
|           if (!allowNull) { | ||||
|             throw ArgumentError('Unknown enum value to decode: $data'); | ||||
|           } | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   /// Singleton [TimeGroupEnumTypeTransformer] instance. | ||||
|   static TimeGroupEnumTypeTransformer? _instance; | ||||
| } | ||||
|  | ||||
							
								
								
									
										32
									
								
								mobile/openapi/test/asset_count_by_time_group_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/openapi/test/asset_count_by_time_group_dto_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 AssetCountByTimeGroupDto | ||||
| void main() { | ||||
|   // final instance = AssetCountByTimeGroupDto(); | ||||
|  | ||||
|   group('test AssetCountByTimeGroupDto', () { | ||||
|     // String timeGroup | ||||
|     test('to test the property `timeGroup`', () async { | ||||
|       // TODO | ||||
|     }); | ||||
|  | ||||
|     // int count | ||||
|     test('to test the property `count`', () async { | ||||
|       // TODO | ||||
|     }); | ||||
|  | ||||
|  | ||||
|   }); | ||||
|  | ||||
| } | ||||
| @@ -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 AssetCountByTimeGroupResponseDto | ||||
| void main() { | ||||
|   // final instance = AssetCountByTimeGroupResponseDto(); | ||||
|  | ||||
|   group('test AssetCountByTimeGroupResponseDto', () { | ||||
|     // int totalAssets | ||||
|     test('to test the property `totalAssets`', () async { | ||||
|       // TODO | ||||
|     }); | ||||
|  | ||||
|     // List<AssetCountByTimeGroupDto> groups (default value: const []) | ||||
|     test('to test the property `groups`', () async { | ||||
|       // TODO | ||||
|     }); | ||||
|  | ||||
|  | ||||
|   }); | ||||
|  | ||||
| } | ||||
| @@ -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 GetAssetCountByTimeGroupDto | ||||
| void main() { | ||||
|   // final instance = GetAssetCountByTimeGroupDto(); | ||||
|  | ||||
|   group('test GetAssetCountByTimeGroupDto', () { | ||||
|     // String timeGroup (default value: 'month') | ||||
|     test('to test the property `timeGroup`', () async { | ||||
|       // TODO | ||||
|     }); | ||||
|  | ||||
|  | ||||
|   }); | ||||
|  | ||||
| } | ||||
							
								
								
									
										21
									
								
								mobile/openapi/test/time_group_enum_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								mobile/openapi/test/time_group_enum_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 TimeGroupEnum | ||||
| void main() { | ||||
|  | ||||
|   group('test TimeGroupEnum', () { | ||||
|  | ||||
|   }); | ||||
|  | ||||
| } | ||||
							
								
								
									
										187
									
								
								server/apps/immich/src/api-v1/asset/asset-repository.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								server/apps/immich/src/api-v1/asset/asset-repository.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| import { SearchPropertiesDto } from './dto/search-properties.dto'; | ||||
| import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto'; | ||||
| import { AssetEntity, AssetType } from '@app/database/entities/asset.entity'; | ||||
| import { BadRequestException, Injectable } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| import { Repository } from 'typeorm/repository/Repository'; | ||||
| import { CreateAssetDto } from './dto/create-asset.dto'; | ||||
| import { CuratedObjectsResponseDto } from './response-dto/curated-objects-response.dto'; | ||||
| import { AssetCountByTimeGroupDto } from './response-dto/asset-count-by-time-group-response.dto'; | ||||
| import { TimeGroupEnum } from './dto/get-asset-count-by-time-group.dto'; | ||||
|  | ||||
| export interface IAssetRepository { | ||||
|   create(createAssetDto: CreateAssetDto, ownerId: string, originalPath: string, mimeType: string): Promise<AssetEntity>; | ||||
|   getAllByUserId(userId: string): Promise<AssetEntity[]>; | ||||
|   getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>; | ||||
|   getById(assetId: string): Promise<AssetEntity>; | ||||
|   getLocationsByUserId(userId: string): Promise<CuratedLocationsResponseDto[]>; | ||||
|   getDetectedObjectsByUserId(userId: string): Promise<CuratedObjectsResponseDto[]>; | ||||
|   getSearchPropertiesByUserId(userId: string): Promise<SearchPropertiesDto[]>; | ||||
|   getAssetCountByTimeGroup(userId: string, timeGroup: TimeGroupEnum): Promise<AssetCountByTimeGroupDto[]>; | ||||
| } | ||||
|  | ||||
| export const ASSET_REPOSITORY = 'ASSET_REPOSITORY'; | ||||
|  | ||||
| @Injectable() | ||||
| export class AssetRepository implements IAssetRepository { | ||||
|   constructor( | ||||
|     @InjectRepository(AssetEntity) | ||||
|     private assetRepository: Repository<AssetEntity>, | ||||
|   ) {} | ||||
|   async getAssetCountByTimeGroup(userId: string, timeGroup: TimeGroupEnum) { | ||||
|     let result: AssetCountByTimeGroupDto[] = []; | ||||
|  | ||||
|     if (timeGroup === TimeGroupEnum.Month) { | ||||
|       result = await this.assetRepository | ||||
|         .createQueryBuilder('asset') | ||||
|         .select(`COUNT(asset.id)::int`, 'count') | ||||
|         .addSelect(`to_char(date_trunc('month', "createdAt"::timestamptz), 'YYYY_MM')`, 'timeGroup') | ||||
|         .where('"userId" = :userId', { userId: userId }) | ||||
|         .groupBy(`date_trunc('month', "createdAt"::timestamptz)`) | ||||
|         .orderBy(`date_trunc('month', "createdAt"::timestamptz)`, 'DESC') | ||||
|         .getRawMany(); | ||||
|     } else if (timeGroup === TimeGroupEnum.Day) { | ||||
|       result = await this.assetRepository | ||||
|         .createQueryBuilder('asset') | ||||
|         .select(`COUNT(asset.id)::int`, 'count') | ||||
|         .addSelect(`to_char(date_trunc('day', "createdAt"::timestamptz), 'YYYY_MM_DD')`, 'timeGroup') | ||||
|         .where('"userId" = :userId', { userId: userId }) | ||||
|         .groupBy(`date_trunc('day', "createdAt"::timestamptz)`) | ||||
|         .orderBy(`date_trunc('day', "createdAt"::timestamptz)`, 'DESC') | ||||
|         .getRawMany(); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   async getSearchPropertiesByUserId(userId: string): Promise<SearchPropertiesDto[]> { | ||||
|     return await this.assetRepository | ||||
|       .createQueryBuilder('asset') | ||||
|       .where('asset.userId = :userId', { userId: userId }) | ||||
|       .leftJoin('asset.exifInfo', 'ei') | ||||
|       .leftJoin('asset.smartInfo', 'si') | ||||
|       .select('si.tags', 'tags') | ||||
|       .addSelect('si.objects', 'objects') | ||||
|       .addSelect('asset.type', 'assetType') | ||||
|       .addSelect('ei.orientation', 'orientation') | ||||
|       .addSelect('ei."lensModel"', 'lensModel') | ||||
|       .addSelect('ei.make', 'make') | ||||
|       .addSelect('ei.model', 'model') | ||||
|       .addSelect('ei.city', 'city') | ||||
|       .addSelect('ei.state', 'state') | ||||
|       .addSelect('ei.country', 'country') | ||||
|       .distinctOn(['si.tags']) | ||||
|       .getRawMany(); | ||||
|   } | ||||
|  | ||||
|   async getDetectedObjectsByUserId(userId: string): Promise<CuratedObjectsResponseDto[]> { | ||||
|     return await this.assetRepository.query( | ||||
|       ` | ||||
|         SELECT DISTINCT ON (unnest(si.objects)) a.id, unnest(si.objects) as "object", a."resizePath", a."deviceAssetId", a."deviceId" | ||||
|         FROM assets a | ||||
|         LEFT JOIN smart_info si ON a.id = si."assetId" | ||||
|         WHERE a."userId" = $1 | ||||
|         AND si.objects IS NOT NULL | ||||
|       `, | ||||
|       [userId], | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   async getLocationsByUserId(userId: string): Promise<CuratedLocationsResponseDto[]> { | ||||
|     return await this.assetRepository.query( | ||||
|       ` | ||||
|         SELECT DISTINCT ON (e.city) a.id, e.city, a."resizePath", a."deviceAssetId", a."deviceId" | ||||
|         FROM assets a | ||||
|         LEFT JOIN exif e ON a.id = e."assetId" | ||||
|         WHERE a."userId" = $1 | ||||
|         AND e.city IS NOT NULL | ||||
|         AND a.type = 'IMAGE'; | ||||
|       `, | ||||
|       [userId], | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get a single asset information by its ID | ||||
|    * - include exif info | ||||
|    * @param assetId | ||||
|    */ | ||||
|   async getById(assetId: string): Promise<AssetEntity> { | ||||
|     return await this.assetRepository.findOneOrFail({ | ||||
|       where: { | ||||
|         id: assetId, | ||||
|       }, | ||||
|       relations: ['exifInfo'], | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get all assets belong to the user on the database | ||||
|    * @param userId | ||||
|    */ | ||||
|   async getAllByUserId(userId: string): Promise<AssetEntity[]> { | ||||
|     const query = this.assetRepository | ||||
|       .createQueryBuilder('asset') | ||||
|       .where('asset.userId = :userId', { userId: userId }) | ||||
|       .andWhere('asset.resizePath is not NULL') | ||||
|       .leftJoinAndSelect('asset.exifInfo', 'exifInfo') | ||||
|       .orderBy('asset.createdAt', 'DESC'); | ||||
|  | ||||
|     return await query.getMany(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create new asset information in database | ||||
|    * @param createAssetDto | ||||
|    * @param ownerId | ||||
|    * @param originalPath | ||||
|    * @param mimeType | ||||
|    * @returns Promise<AssetEntity> | ||||
|    */ | ||||
|   async create( | ||||
|     createAssetDto: CreateAssetDto, | ||||
|     ownerId: string, | ||||
|     originalPath: string, | ||||
|     mimeType: string, | ||||
|   ): Promise<AssetEntity> { | ||||
|     const asset = new AssetEntity(); | ||||
|     asset.deviceAssetId = createAssetDto.deviceAssetId; | ||||
|     asset.userId = ownerId; | ||||
|     asset.deviceId = createAssetDto.deviceId; | ||||
|     asset.type = createAssetDto.assetType || AssetType.OTHER; | ||||
|     asset.originalPath = originalPath; | ||||
|     asset.createdAt = createAssetDto.createdAt; | ||||
|     asset.modifiedAt = createAssetDto.modifiedAt; | ||||
|     asset.isFavorite = createAssetDto.isFavorite; | ||||
|     asset.mimeType = mimeType; | ||||
|     asset.duration = createAssetDto.duration || null; | ||||
|  | ||||
|     const createdAsset = await this.assetRepository.save(asset); | ||||
|  | ||||
|     if (!createdAsset) { | ||||
|       throw new BadRequestException('Asset not created'); | ||||
|     } | ||||
|     return createdAsset; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get assets by device's Id on the database | ||||
|    * @param userId | ||||
|    * @param deviceId | ||||
|    * | ||||
|    * @returns Promise<string[]> - Array of assetIds belong to the device | ||||
|    */ | ||||
|   async getAllByDeviceId(userId: string, deviceId: string): Promise<string[]> { | ||||
|     const rows = await this.assetRepository.find({ | ||||
|       where: { | ||||
|         userId: userId, | ||||
|         deviceId: deviceId, | ||||
|       }, | ||||
|       select: ['deviceAssetId'], | ||||
|     }); | ||||
|     const res: string[] = []; | ||||
|     rows.forEach((v) => res.push(v.deviceAssetId)); | ||||
|  | ||||
|     return res; | ||||
|   } | ||||
| } | ||||
| @@ -2,7 +2,6 @@ import { | ||||
|   Controller, | ||||
|   Post, | ||||
|   UseInterceptors, | ||||
|   UploadedFiles, | ||||
|   Body, | ||||
|   UseGuards, | ||||
|   Get, | ||||
| @@ -44,6 +43,8 @@ import { CreateAssetDto } from './dto/create-asset.dto'; | ||||
| import { AssetFileUploadResponseDto } from './response-dto/asset-file-upload-response.dto'; | ||||
| import { DeleteAssetResponseDto, DeleteAssetStatusEnum } from './response-dto/delete-asset-response.dto'; | ||||
| import { GetAssetThumbnailDto } from './dto/get-asset-thumbnail.dto'; | ||||
| import { AssetCountByTimeGroupResponseDto } from './response-dto/asset-count-by-time-group-response.dto'; | ||||
| import { GetAssetCountByTimeGroupDto } from './dto/get-asset-count-by-time-group.dto'; | ||||
|  | ||||
| @UseGuards(JwtAuthGuard) | ||||
| @ApiBearerAuth() | ||||
| @@ -117,17 +118,17 @@ export class AssetController { | ||||
|     return this.assetService.getAssetThumbnail(assetId, query); | ||||
|   } | ||||
|  | ||||
|   @Get('/allObjects') | ||||
|   @Get('/curated-objects') | ||||
|   async getCuratedObjects(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedObjectsResponseDto[]> { | ||||
|     return this.assetService.getCuratedObject(authUser); | ||||
|   } | ||||
|  | ||||
|   @Get('/allLocation') | ||||
|   @Get('/curated-locations') | ||||
|   async getCuratedLocations(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedLocationsResponseDto[]> { | ||||
|     return this.assetService.getCuratedLocation(authUser); | ||||
|   } | ||||
|  | ||||
|   @Get('/searchTerm') | ||||
|   @Get('/search-terms') | ||||
|   async getAssetSearchTerms(@GetAuthUser() authUser: AuthUserDto): Promise<string[]> { | ||||
|     return this.assetService.getAssetSearchTerm(authUser); | ||||
|   } | ||||
| @@ -140,6 +141,14 @@ export class AssetController { | ||||
|     return this.assetService.searchAsset(authUser, searchAssetDto); | ||||
|   } | ||||
|  | ||||
|   @Get('/count-by-date') | ||||
|   async getAssetCountByTimeGroup( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|     @Body(ValidationPipe) getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, | ||||
|   ): Promise<AssetCountByTimeGroupResponseDto> { | ||||
|     return this.assetService.getAssetCountByTimeGroup(authUser, getAssetCountByTimeGroupDto); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get all AssetEntity belong to the user | ||||
|    */ | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import { BackgroundTaskModule } from '../../modules/background-task/background-t | ||||
| import { BackgroundTaskService } from '../../modules/background-task/background-task.service'; | ||||
| import { CommunicationModule } from '../communication/communication.module'; | ||||
| import { assetUploadedQueueName } from '@app/job/constants/queue-name.constant'; | ||||
| import { AssetRepository, ASSET_REPOSITORY } from './asset-repository'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
| @@ -24,7 +25,14 @@ import { assetUploadedQueueName } from '@app/job/constants/queue-name.constant'; | ||||
|     }), | ||||
|   ], | ||||
|   controllers: [AssetController], | ||||
|   providers: [AssetService, BackgroundTaskService], | ||||
|   providers: [ | ||||
|     AssetService, | ||||
|     BackgroundTaskService, | ||||
|     { | ||||
|       provide: ASSET_REPOSITORY, | ||||
|       useClass: AssetRepository, | ||||
|     }, | ||||
|   ], | ||||
|   exports: [AssetService], | ||||
| }) | ||||
| export class AssetModule {} | ||||
|   | ||||
							
								
								
									
										92
									
								
								server/apps/immich/src/api-v1/asset/asset.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								server/apps/immich/src/api-v1/asset/asset.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| import { AssetRepository, IAssetRepository } from './asset-repository'; | ||||
| import { AuthUserDto } from '../../decorators/auth-user.decorator'; | ||||
| import { AssetService } from './asset.service'; | ||||
| import { Repository } from 'typeorm'; | ||||
| import { AssetEntity, AssetType } from '@app/database/entities/asset.entity'; | ||||
| import { CreateAssetDto } from './dto/create-asset.dto'; | ||||
|  | ||||
| describe('AssetService', () => { | ||||
|   let sui: AssetService; | ||||
|   let a: Repository<AssetEntity>; // TO BE DELETED AFTER FINISHED REFACTORING | ||||
|   let assetRepositoryMock: jest.Mocked<IAssetRepository>; | ||||
|  | ||||
|   const authUser: AuthUserDto = Object.freeze({ | ||||
|     id: '3ea54709-e168-42b7-90b0-a0dfe8a7ecbd', | ||||
|     email: 'auth@test.com', | ||||
|   }); | ||||
|  | ||||
|   const _getCreateAssetDto = (): CreateAssetDto => { | ||||
|     const createAssetDto = new CreateAssetDto(); | ||||
|     createAssetDto.deviceAssetId = 'deviceAssetId'; | ||||
|     createAssetDto.deviceId = 'deviceId'; | ||||
|     createAssetDto.assetType = AssetType.OTHER; | ||||
|     createAssetDto.createdAt = '2022-06-19T23:41:36.910Z'; | ||||
|     createAssetDto.modifiedAt = '2022-06-19T23:41:36.910Z'; | ||||
|     createAssetDto.isFavorite = false; | ||||
|     createAssetDto.duration = '0:00:00.000000'; | ||||
|  | ||||
|     return createAssetDto; | ||||
|   }; | ||||
|   const _getAsset = () => { | ||||
|     const assetEntity = new AssetEntity(); | ||||
|  | ||||
|     assetEntity.id = 'e8edabfd-7d8a-45d0-9d61-7c7ca60f2c67'; | ||||
|     assetEntity.userId = '3ea54709-e168-42b7-90b0-a0dfe8a7ecbd'; | ||||
|     assetEntity.deviceAssetId = '4967046344801'; | ||||
|     assetEntity.deviceId = '116766fd-2ef2-52dc-a3ef-149988997291'; | ||||
|     assetEntity.type = AssetType.VIDEO; | ||||
|     assetEntity.originalPath = | ||||
|       'upload/3ea54709-e168-42b7-90b0-a0dfe8a7ecbd/original/116766fd-2ef2-52dc-a3ef-149988997291/51c97f95-244f-462d-bdf0-e1dc19913516.jpg'; | ||||
|     assetEntity.resizePath = ''; | ||||
|     assetEntity.createdAt = '2022-06-19T23:41:36.910Z'; | ||||
|     assetEntity.modifiedAt = '2022-06-19T23:41:36.910Z'; | ||||
|     assetEntity.isFavorite = false; | ||||
|     assetEntity.mimeType = 'image/jpeg'; | ||||
|     assetEntity.webpPath = ''; | ||||
|     assetEntity.encodedVideoPath = ''; | ||||
|     assetEntity.duration = '0:00:00.000000'; | ||||
|  | ||||
|     return assetEntity; | ||||
|   }; | ||||
|  | ||||
|   beforeAll(() => { | ||||
|     assetRepositoryMock = { | ||||
|       create: jest.fn(), | ||||
|       getAllByUserId: jest.fn(), | ||||
|       getAllByDeviceId: jest.fn(), | ||||
|       getAssetCountByTimeGroup: jest.fn(), | ||||
|       getById: jest.fn(), | ||||
|       getDetectedObjectsByUserId: jest.fn(), | ||||
|       getLocationsByUserId: jest.fn(), | ||||
|       getSearchPropertiesByUserId: jest.fn(), | ||||
|     }; | ||||
|  | ||||
|     sui = new AssetService(assetRepositoryMock, a); | ||||
|   }); | ||||
|  | ||||
|   it('create an asset', async () => { | ||||
|     const assetEntity = _getAsset(); | ||||
|  | ||||
|     assetRepositoryMock.create.mockImplementation(() => Promise.resolve<AssetEntity>(assetEntity)); | ||||
|  | ||||
|     const originalPath = | ||||
|       'upload/3ea54709-e168-42b7-90b0-a0dfe8a7ecbd/original/116766fd-2ef2-52dc-a3ef-149988997291/51c97f95-244f-462d-bdf0-e1dc19913516.jpg'; | ||||
|     const mimeType = 'image/jpeg'; | ||||
|     const createAssetDto = _getCreateAssetDto(); | ||||
|     const result = await sui.createUserAsset(authUser, createAssetDto, originalPath, mimeType); | ||||
|  | ||||
|     expect(result.userId).toEqual(authUser.id); | ||||
|     expect(result.resizePath).toEqual(''); | ||||
|     expect(result.webpPath).toEqual(''); | ||||
|   }); | ||||
|  | ||||
|   it('get assets by device id', async () => { | ||||
|     assetRepositoryMock.getAllByDeviceId.mockImplementation(() => Promise.resolve<string[]>(['4967046344801'])); | ||||
|  | ||||
|     const deviceId = '116766fd-2ef2-52dc-a3ef-149988997291'; | ||||
|     const result = await sui.getUserAssetsByDeviceId(authUser, deviceId); | ||||
|  | ||||
|     expect(result.length).toEqual(1); | ||||
|     expect(result[0]).toEqual('4967046344801'); | ||||
|   }); | ||||
| }); | ||||
| @@ -1,5 +1,7 @@ | ||||
| import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto'; | ||||
| import { | ||||
|   BadRequestException, | ||||
|   Inject, | ||||
|   Injectable, | ||||
|   InternalServerErrorException, | ||||
|   Logger, | ||||
| @@ -7,7 +9,7 @@ import { | ||||
|   StreamableFile, | ||||
| } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| import { IsNull, Not, Repository } from 'typeorm'; | ||||
| import { Repository } from 'typeorm'; | ||||
| import { AuthUserDto } from '../../decorators/auth-user.decorator'; | ||||
| import { AssetEntity, AssetType } from '@app/database/entities/asset.entity'; | ||||
| import { constants, createReadStream, ReadStream, stat } from 'fs'; | ||||
| @@ -25,83 +27,49 @@ import { CreateAssetDto } from './dto/create-asset.dto'; | ||||
| import { DeleteAssetResponseDto, DeleteAssetStatusEnum } from './response-dto/delete-asset-response.dto'; | ||||
| import { GetAssetThumbnailDto, GetAssetThumbnailFormatEnum } from './dto/get-asset-thumbnail.dto'; | ||||
| import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto'; | ||||
| import { ASSET_REPOSITORY, IAssetRepository } from './asset-repository'; | ||||
| import { SearchPropertiesDto } from './dto/search-properties.dto'; | ||||
| import { | ||||
|   AssetCountByTimeGroupResponseDto, | ||||
|   mapAssetCountByTimeGroupResponse, | ||||
| } from './response-dto/asset-count-by-time-group-response.dto'; | ||||
| import { GetAssetCountByTimeGroupDto } from './dto/get-asset-count-by-time-group.dto'; | ||||
|  | ||||
| const fileInfo = promisify(stat); | ||||
|  | ||||
| @Injectable() | ||||
| export class AssetService { | ||||
|   constructor( | ||||
|     @Inject(ASSET_REPOSITORY) | ||||
|     private _assetRepository: IAssetRepository, | ||||
|  | ||||
|     @InjectRepository(AssetEntity) | ||||
|     private assetRepository: Repository<AssetEntity>, | ||||
|   ) {} | ||||
|  | ||||
|   public async updateThumbnailInfo(asset: AssetEntity, thumbnailPath: string): Promise<AssetEntity> { | ||||
|     const updatedAsset = await this.assetRepository | ||||
|       .createQueryBuilder('assets') | ||||
|       .update<AssetEntity>(AssetEntity, { ...asset, resizePath: thumbnailPath }) | ||||
|       .where('assets.id = :id', { id: asset.id }) | ||||
|       .returning('*') | ||||
|       .updateEntity(true) | ||||
|       .execute(); | ||||
|  | ||||
|     return updatedAsset.raw[0]; | ||||
|   } | ||||
|  | ||||
|   public async createUserAsset( | ||||
|     authUser: AuthUserDto, | ||||
|     assetInfo: CreateAssetDto, | ||||
|     path: string, | ||||
|     createAssetDto: CreateAssetDto, | ||||
|     originalPath: string, | ||||
|     mimeType: string, | ||||
|   ): Promise<AssetEntity | undefined> { | ||||
|     const asset = new AssetEntity(); | ||||
|     asset.deviceAssetId = assetInfo.deviceAssetId; | ||||
|     asset.userId = authUser.id; | ||||
|     asset.deviceId = assetInfo.deviceId; | ||||
|     asset.type = assetInfo.assetType || AssetType.OTHER; | ||||
|     asset.originalPath = path; | ||||
|     asset.createdAt = assetInfo.createdAt; | ||||
|     asset.modifiedAt = assetInfo.modifiedAt; | ||||
|     asset.isFavorite = assetInfo.isFavorite; | ||||
|     asset.mimeType = mimeType; | ||||
|     asset.duration = assetInfo.duration || null; | ||||
|   ): Promise<AssetEntity> { | ||||
|     const assetEntity = await this._assetRepository.create(createAssetDto, authUser.id, originalPath, mimeType); | ||||
|  | ||||
|     const createdAsset = await this.assetRepository.save(asset); | ||||
|     if (!createdAsset) { | ||||
|       throw new Error('Asset not created'); | ||||
|     } | ||||
|     return createdAsset; | ||||
|     return assetEntity; | ||||
|   } | ||||
|  | ||||
|   public async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) { | ||||
|     const rows = await this.assetRepository.find({ | ||||
|       where: { | ||||
|         userId: authUser.id, | ||||
|         deviceId: deviceId, | ||||
|       }, | ||||
|       select: ['deviceAssetId'], | ||||
|     }); | ||||
|  | ||||
|     const res: string[] = []; | ||||
|     rows.forEach((v) => res.push(v.deviceAssetId)); | ||||
|     return res; | ||||
|     return this._assetRepository.getAllByDeviceId(authUser.id, deviceId); | ||||
|   } | ||||
|  | ||||
|   public async getAllAssets(authUser: AuthUserDto): Promise<AssetResponseDto[]> { | ||||
|     const assets = await this.assetRepository.find({ | ||||
|       where: { | ||||
|         userId: authUser.id, | ||||
|         resizePath: Not(IsNull()), | ||||
|       }, | ||||
|       relations: ['exifInfo'], | ||||
|       order: { | ||||
|         createdAt: 'DESC', | ||||
|       }, | ||||
|     }); | ||||
|     const assets = await this._assetRepository.getAllByUserId(authUser.id); | ||||
|  | ||||
|     return assets.map((asset) => mapAsset(asset)); | ||||
|   } | ||||
|  | ||||
|   public async findAssetOfDevice(deviceId: string, assetId: string): Promise<AssetResponseDto> { | ||||
|   // TODO - Refactor this to get asset by its own id | ||||
|   private async findAssetOfDevice(deviceId: string, assetId: string): Promise<AssetResponseDto> { | ||||
|     const rows = await this.assetRepository.query( | ||||
|       'SELECT * FROM assets a WHERE a."deviceAssetId" = $1 AND a."deviceId" = $2', | ||||
|       [assetId, deviceId], | ||||
| @@ -117,16 +85,7 @@ export class AssetService { | ||||
|   } | ||||
|  | ||||
|   public async getAssetById(authUser: AuthUserDto, assetId: string): Promise<AssetResponseDto> { | ||||
|     const asset = await this.assetRepository.findOne({ | ||||
|       where: { | ||||
|         id: assetId, | ||||
|       }, | ||||
|       relations: ['exifInfo'], | ||||
|     }); | ||||
|  | ||||
|     if (!asset) { | ||||
|       throw new NotFoundException('Asset not found'); | ||||
|     } | ||||
|     const asset = await this._assetRepository.getById(assetId); | ||||
|  | ||||
|     return mapAsset(asset); | ||||
|   } | ||||
| @@ -394,45 +353,35 @@ export class AssetService { | ||||
|  | ||||
|   async getAssetSearchTerm(authUser: AuthUserDto): Promise<string[]> { | ||||
|     const possibleSearchTerm = new Set<string>(); | ||||
|     // TODO: should use query builder | ||||
|     const rows = await this.assetRepository.query( | ||||
|       ` | ||||
|       SELECT DISTINCT si.tags, si.objects, e.orientation, e."lensModel", e.make, e.model , a.type, e.city, e.state, e.country | ||||
|       FROM assets a | ||||
|       LEFT JOIN exif e ON a.id = e."assetId" | ||||
|       LEFT JOIN smart_info si ON a.id = si."assetId" | ||||
|       WHERE a."userId" = $1; | ||||
|       `, | ||||
|       [authUser.id], | ||||
|     ); | ||||
|  | ||||
|     rows.forEach((row: { [x: string]: any }) => { | ||||
|     const rows = await this._assetRepository.getSearchPropertiesByUserId(authUser.id); | ||||
|     rows.forEach((row: SearchPropertiesDto) => { | ||||
|       // tags | ||||
|       row['tags']?.map((tag: string) => possibleSearchTerm.add(tag?.toLowerCase())); | ||||
|       row.tags?.map((tag: string) => possibleSearchTerm.add(tag?.toLowerCase())); | ||||
|  | ||||
|       // objects | ||||
|       row['objects']?.map((object: string) => possibleSearchTerm.add(object?.toLowerCase())); | ||||
|       row.objects?.map((object: string) => possibleSearchTerm.add(object?.toLowerCase())); | ||||
|  | ||||
|       // asset's tyoe | ||||
|       possibleSearchTerm.add(row['type']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row.assetType?.toLowerCase() || ''); | ||||
|  | ||||
|       // image orientation | ||||
|       possibleSearchTerm.add(row['orientation']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row.orientation?.toLowerCase() || ''); | ||||
|  | ||||
|       // Lens model | ||||
|       possibleSearchTerm.add(row['lensModel']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row.lensModel?.toLowerCase() || ''); | ||||
|  | ||||
|       // Make and model | ||||
|       possibleSearchTerm.add(row['make']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row['model']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row.make?.toLowerCase() || ''); | ||||
|       possibleSearchTerm.add(row.model?.toLowerCase() || ''); | ||||
|  | ||||
|       // Location | ||||
|       possibleSearchTerm.add(row['city']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row['state']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row['country']?.toLowerCase()); | ||||
|       possibleSearchTerm.add(row.city?.toLowerCase() || ''); | ||||
|       possibleSearchTerm.add(row.state?.toLowerCase() || ''); | ||||
|       possibleSearchTerm.add(row.country?.toLowerCase() || ''); | ||||
|     }); | ||||
|  | ||||
|     return Array.from(possibleSearchTerm).filter((x) => x != null); | ||||
|     return Array.from(possibleSearchTerm).filter((x) => x != null && x != ''); | ||||
|   } | ||||
|  | ||||
|   async searchAsset(authUser: AuthUserDto, searchAssetDto: SearchAssetDto): Promise<AssetResponseDto[]> { | ||||
| @@ -459,33 +408,12 @@ export class AssetService { | ||||
|     return searchResults.map((asset) => mapAsset(asset)); | ||||
|   } | ||||
|  | ||||
|   async getCuratedLocation(authUser: AuthUserDto) { | ||||
|     return await this.assetRepository.query( | ||||
|       ` | ||||
|         SELECT DISTINCT ON (e.city) a.id, e.city, a."resizePath", a."deviceAssetId", a."deviceId" | ||||
|         FROM assets a | ||||
|         LEFT JOIN exif e ON a.id = e."assetId" | ||||
|         WHERE a."userId" = $1 | ||||
|         AND e.city IS NOT NULL | ||||
|         AND a.type = 'IMAGE'; | ||||
|       `, | ||||
|       [authUser.id], | ||||
|     ); | ||||
|   async getCuratedLocation(authUser: AuthUserDto): Promise<CuratedLocationsResponseDto[]> { | ||||
|     return this._assetRepository.getLocationsByUserId(authUser.id); | ||||
|   } | ||||
|  | ||||
|   async getCuratedObject(authUser: AuthUserDto): Promise<CuratedObjectsResponseDto[]> { | ||||
|     const curatedObjects: CuratedObjectsResponseDto[] = await this.assetRepository.query( | ||||
|       ` | ||||
|         SELECT DISTINCT ON (unnest(si.objects)) a.id, unnest(si.objects) as "object", a."resizePath", a."deviceAssetId", a."deviceId" | ||||
|         FROM assets a | ||||
|         LEFT JOIN smart_info si ON a.id = si."assetId" | ||||
|         WHERE a."userId" = $1 | ||||
|         AND si.objects IS NOT NULL | ||||
|       `, | ||||
|       [authUser.id], | ||||
|     ); | ||||
|  | ||||
|     return curatedObjects; | ||||
|     return this._assetRepository.getDetectedObjectsByUserId(authUser.id); | ||||
|   } | ||||
|  | ||||
|   async checkDuplicatedAsset( | ||||
| @@ -504,4 +432,16 @@ export class AssetService { | ||||
|  | ||||
|     return new CheckDuplicateAssetResponseDto(isDuplicated, res?.id); | ||||
|   } | ||||
|  | ||||
|   async getAssetCountByTimeGroup( | ||||
|     authUser: AuthUserDto, | ||||
|     getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, | ||||
|   ): Promise<AssetCountByTimeGroupResponseDto> { | ||||
|     const result = await this._assetRepository.getAssetCountByTimeGroup( | ||||
|       authUser.id, | ||||
|       getAssetCountByTimeGroupDto.timeGroup, | ||||
|     ); | ||||
|  | ||||
|     return mapAssetCountByTimeGroupResponse(result); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,16 @@ | ||||
| import { ApiProperty } from '@nestjs/swagger'; | ||||
| import { IsNotEmpty } from 'class-validator'; | ||||
|  | ||||
| export enum TimeGroupEnum { | ||||
|   Day = 'day', | ||||
|   Month = 'month', | ||||
| } | ||||
| export class GetAssetCountByTimeGroupDto { | ||||
|   @IsNotEmpty() | ||||
|   @ApiProperty({ | ||||
|     type: String, | ||||
|     enum: TimeGroupEnum, | ||||
|     enumName: 'TimeGroupEnum', | ||||
|   }) | ||||
|   timeGroup!: TimeGroupEnum; | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| export class SearchPropertiesDto { | ||||
|   tags?: string[]; | ||||
|   objects?: string[]; | ||||
|   assetType?: string; | ||||
|   orientation?: string; | ||||
|   lensModel?: string; | ||||
|   make?: string; | ||||
|   model?: string; | ||||
|   city?: string; | ||||
|   state?: string; | ||||
|   country?: string; | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| import { ApiProperty } from '@nestjs/swagger'; | ||||
|  | ||||
| export class AssetCountByTimeGroupDto { | ||||
|   @ApiProperty({ type: 'string' }) | ||||
|   timeGroup!: string; | ||||
|  | ||||
|   @ApiProperty({ type: 'integer' }) | ||||
|   count!: number; | ||||
| } | ||||
|  | ||||
| export class AssetCountByTimeGroupResponseDto { | ||||
|   groups!: AssetCountByTimeGroupDto[]; | ||||
|  | ||||
|   @ApiProperty({ type: 'integer' }) | ||||
|   totalAssets!: number; | ||||
| } | ||||
|  | ||||
| export function mapAssetCountByTimeGroupResponse(result: AssetCountByTimeGroupDto[]): AssetCountByTimeGroupResponseDto { | ||||
|   return { | ||||
|     groups: result, | ||||
|     totalAssets: result.map((group) => group.count).reduce((a, b) => a + b, 0), | ||||
|   }; | ||||
| } | ||||
| @@ -5,7 +5,7 @@ import { Logger } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| import { UserEntity } from '@app/database/entities/user.entity'; | ||||
| import { Repository } from 'typeorm'; | ||||
|  | ||||
| import cookieParser from 'cookie'; | ||||
| @WebSocketGateway({ cors: true }) | ||||
| export class CommunicationGateway implements OnGatewayConnection, OnGatewayDisconnect { | ||||
|   constructor( | ||||
| @@ -26,8 +26,24 @@ export class CommunicationGateway implements OnGatewayConnection, OnGatewayDisco | ||||
|   async handleConnection(client: Socket) { | ||||
|     try { | ||||
|       Logger.log(`New websocket connection: ${client.id}`, 'WebsocketConnectionEvent'); | ||||
|       let accessToken = ''; | ||||
|  | ||||
|       const accessToken = client.handshake.headers.authorization?.split(' ')[1]; | ||||
|       if (client.handshake.headers.cookie != undefined) { | ||||
|         const cookies = cookieParser.parse(client.handshake.headers.cookie); | ||||
|         if (cookies.immich_access_token) { | ||||
|           accessToken = cookies.immich_access_token; | ||||
|         } else { | ||||
|           client.emit('error', 'unauthorized'); | ||||
|           client.disconnect(); | ||||
|           return; | ||||
|         } | ||||
|       } else if (client.handshake.headers.authorization != undefined) { | ||||
|         accessToken = client.handshake.headers.authorization.split(' ')[1]; | ||||
|       } else { | ||||
|         client.emit('error', 'unauthorized'); | ||||
|         client.disconnect(); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       const res: JwtValidationResult = accessToken | ||||
|         ? await this.immichJwtService.validateToken(accessToken) | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -145,6 +145,44 @@ export interface AlbumResponseDto { | ||||
|      */ | ||||
|     'assets': Array<AssetResponseDto>; | ||||
| } | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
|  * @interface AssetCountByTimeGroupDto | ||||
|  */ | ||||
| export interface AssetCountByTimeGroupDto { | ||||
|     /** | ||||
|      *  | ||||
|      * @type {string} | ||||
|      * @memberof AssetCountByTimeGroupDto | ||||
|      */ | ||||
|     'timeGroup': string; | ||||
|     /** | ||||
|      *  | ||||
|      * @type {number} | ||||
|      * @memberof AssetCountByTimeGroupDto | ||||
|      */ | ||||
|     'count': number; | ||||
| } | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
|  * @interface AssetCountByTimeGroupResponseDto | ||||
|  */ | ||||
| export interface AssetCountByTimeGroupResponseDto { | ||||
|     /** | ||||
|      *  | ||||
|      * @type {number} | ||||
|      * @memberof AssetCountByTimeGroupResponseDto | ||||
|      */ | ||||
|     'totalAssets': number; | ||||
|     /** | ||||
|      *  | ||||
|      * @type {Array<AssetCountByTimeGroupDto>} | ||||
|      * @memberof AssetCountByTimeGroupResponseDto | ||||
|      */ | ||||
|     'groups': Array<AssetCountByTimeGroupDto>; | ||||
| } | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
| @@ -720,6 +758,19 @@ export interface ExifResponseDto { | ||||
|      */ | ||||
|     'country'?: string | null; | ||||
| } | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
|  * @interface GetAssetCountByTimeGroupDto | ||||
|  */ | ||||
| export interface GetAssetCountByTimeGroupDto { | ||||
|     /** | ||||
|      *  | ||||
|      * @type {TimeGroupEnum} | ||||
|      * @memberof GetAssetCountByTimeGroupDto | ||||
|      */ | ||||
|     'timeGroup': TimeGroupEnum; | ||||
| } | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
| @@ -996,6 +1047,20 @@ export const ThumbnailFormat = { | ||||
| export type ThumbnailFormat = typeof ThumbnailFormat[keyof typeof ThumbnailFormat]; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
|  * @enum {string} | ||||
|  */ | ||||
|  | ||||
| export const TimeGroupEnum = { | ||||
|     Day: 'day', | ||||
|     Month: 'month' | ||||
| } as const; | ||||
|  | ||||
| export type TimeGroupEnum = typeof TimeGroupEnum[keyof typeof TimeGroupEnum]; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @export | ||||
| @@ -2072,13 +2137,52 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration | ||||
|                 options: localVarRequestOptions, | ||||
|             }; | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {GetAssetCountByTimeGroupDto} getAssetCountByTimeGroupDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         getAssetCountByTimeGroup: async (getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             // verify required parameter 'getAssetCountByTimeGroupDto' is not null or undefined | ||||
|             assertParamExists('getAssetCountByTimeGroup', 'getAssetCountByTimeGroupDto', getAssetCountByTimeGroupDto) | ||||
|             const localVarPath = `/asset/count-by-date`; | ||||
|             // 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) | ||||
|  | ||||
|  | ||||
|      | ||||
|             localVarHeaderParameter['Content-Type'] = 'application/json'; | ||||
|  | ||||
|             setSearchParams(localVarUrlObj, localVarQueryParameter); | ||||
|             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; | ||||
|             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; | ||||
|             localVarRequestOptions.data = serializeDataIfNeeded(getAssetCountByTimeGroupDto, localVarRequestOptions, configuration) | ||||
|  | ||||
|             return { | ||||
|                 url: toPathString(localVarUrlObj), | ||||
|                 options: localVarRequestOptions, | ||||
|             }; | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         getAssetSearchTerms: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             const localVarPath = `/asset/searchTerm`; | ||||
|             const localVarPath = `/asset/search-terms`; | ||||
|             // use dummy base URL string because the URL constructor only accepts absolute URLs. | ||||
|             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); | ||||
|             let baseOptions; | ||||
| @@ -2153,7 +2257,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         getCuratedLocations: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             const localVarPath = `/asset/allLocation`; | ||||
|             const localVarPath = `/asset/curated-locations`; | ||||
|             // use dummy base URL string because the URL constructor only accepts absolute URLs. | ||||
|             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); | ||||
|             let baseOptions; | ||||
| @@ -2186,7 +2290,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         getCuratedObjects: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             const localVarPath = `/asset/allObjects`; | ||||
|             const localVarPath = `/asset/curated-objects`; | ||||
|             // use dummy base URL string because the URL constructor only accepts absolute URLs. | ||||
|             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); | ||||
|             let baseOptions; | ||||
| @@ -2456,6 +2560,16 @@ export const AssetApiFp = function(configuration?: Configuration) { | ||||
|             const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetById(assetId, options); | ||||
|             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {GetAssetCountByTimeGroupDto} getAssetCountByTimeGroupDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         async getAssetCountByTimeGroup(getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetCountByTimeGroupResponseDto>> { | ||||
|             const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetCountByTimeGroup(getAssetCountByTimeGroupDto, options); | ||||
|             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
| @@ -2598,6 +2712,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath | ||||
|         getAssetById(assetId: string, options?: any): AxiosPromise<AssetResponseDto> { | ||||
|             return localVarFp.getAssetById(assetId, options).then((request) => request(axios, basePath)); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {GetAssetCountByTimeGroupDto} getAssetCountByTimeGroupDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         getAssetCountByTimeGroup(getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, options?: any): AxiosPromise<AssetCountByTimeGroupResponseDto> { | ||||
|             return localVarFp.getAssetCountByTimeGroup(getAssetCountByTimeGroupDto, options).then((request) => request(axios, basePath)); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
| @@ -2742,6 +2865,17 @@ export class AssetApi extends BaseAPI { | ||||
|         return AssetApiFp(this.configuration).getAssetById(assetId, options).then((request) => request(this.axios, this.basePath)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  | ||||
|      * @param {GetAssetCountByTimeGroupDto} getAssetCountByTimeGroupDto  | ||||
|      * @param {*} [options] Override http request option. | ||||
|      * @throws {RequiredError} | ||||
|      * @memberof AssetApi | ||||
|      */ | ||||
|     public getAssetCountByTimeGroup(getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto, options?: AxiosRequestConfig) { | ||||
|         return AssetApiFp(this.configuration).getAssetCountByTimeGroup(getAssetCountByTimeGroupDto, options).then((request) => request(this.axios, this.basePath)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  | ||||
|      * @param {*} [options] Override http request option. | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import { Socket, io } from 'socket.io-client'; | ||||
| import { writable } from 'svelte/store'; | ||||
|  | ||||
| let websocket: Socket; | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { serverApi } from '@api'; | ||||
| import { serverApi, TimeGroupEnum } from '@api'; | ||||
| import * as cookieParser from 'cookie'; | ||||
|  | ||||
| import type { LayoutServerLoad } from './$types'; | ||||
| @@ -21,6 +21,9 @@ export const load: LayoutServerLoad = async ({ request }) => { | ||||
| 			user: userInfo | ||||
| 		}; | ||||
| 	} catch (e) { | ||||
| 		console.log('[ERROR] layout.server.ts [LayoutServerLoad]: ', e); | ||||
| 		console.error('[ERROR] layout.server.ts [LayoutServerLoad]: ', e); | ||||
| 		return { | ||||
| 			user: undefined | ||||
| 		}; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -20,11 +20,13 @@ | ||||
| 	import Close from 'svelte-material-icons/Close.svelte'; | ||||
| 	import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
| 	import { onMount } from 'svelte'; | ||||
|  | ||||
| 	import { onMount, onDestroy } from 'svelte'; | ||||
| 	import { | ||||
| 		notificationController, | ||||
| 		NotificationType | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket'; | ||||
|  | ||||
| 	export let data: PageData; | ||||
|  | ||||
| @@ -193,6 +195,18 @@ | ||||
| 			console.error('Error deleteSelectedAssetHandler', e); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	onMount(async () => { | ||||
| 		openWebsocketConnection(); | ||||
|  | ||||
| 		const { data: assets } = await api.assetApi.getAllAssets(); | ||||
|  | ||||
| 		setAssetInfo(assets); | ||||
| 	}); | ||||
|  | ||||
| 	onDestroy(() => { | ||||
| 		closeWebsocketConnection(); | ||||
| 	}); | ||||
| </script> | ||||
|  | ||||
| <svelte:head> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user