mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	fix(server): stacked assets for full sync, userIds as array for delta sync (#9100)
* fix(server): stacked assets for full sync, userIds as array for delta sync * refactor(server): sync * fix getDeltaSync after partner removal --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
		
							parent
							
								
									fc2e709ad4
								
							
						
					
					
						commit
						32e7cfea3d
					
				
							
								
								
									
										6
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							@ -28,12 +28,14 @@ doc/AssetBulkUploadCheckDto.md
 | 
			
		||||
doc/AssetBulkUploadCheckItem.md
 | 
			
		||||
doc/AssetBulkUploadCheckResponseDto.md
 | 
			
		||||
doc/AssetBulkUploadCheckResult.md
 | 
			
		||||
doc/AssetDeltaSyncDto.md
 | 
			
		||||
doc/AssetDeltaSyncResponseDto.md
 | 
			
		||||
doc/AssetFaceResponseDto.md
 | 
			
		||||
doc/AssetFaceUpdateDto.md
 | 
			
		||||
doc/AssetFaceUpdateItem.md
 | 
			
		||||
doc/AssetFaceWithoutPersonResponseDto.md
 | 
			
		||||
doc/AssetFileUploadResponseDto.md
 | 
			
		||||
doc/AssetFullSyncDto.md
 | 
			
		||||
doc/AssetIdsDto.md
 | 
			
		||||
doc/AssetIdsResponseDto.md
 | 
			
		||||
doc/AssetJobName.md
 | 
			
		||||
@ -265,12 +267,14 @@ lib/model/asset_bulk_upload_check_dto.dart
 | 
			
		||||
lib/model/asset_bulk_upload_check_item.dart
 | 
			
		||||
lib/model/asset_bulk_upload_check_response_dto.dart
 | 
			
		||||
lib/model/asset_bulk_upload_check_result.dart
 | 
			
		||||
lib/model/asset_delta_sync_dto.dart
 | 
			
		||||
lib/model/asset_delta_sync_response_dto.dart
 | 
			
		||||
lib/model/asset_face_response_dto.dart
 | 
			
		||||
lib/model/asset_face_update_dto.dart
 | 
			
		||||
lib/model/asset_face_update_item.dart
 | 
			
		||||
lib/model/asset_face_without_person_response_dto.dart
 | 
			
		||||
lib/model/asset_file_upload_response_dto.dart
 | 
			
		||||
lib/model/asset_full_sync_dto.dart
 | 
			
		||||
lib/model/asset_ids_dto.dart
 | 
			
		||||
lib/model/asset_ids_response_dto.dart
 | 
			
		||||
lib/model/asset_job_name.dart
 | 
			
		||||
@ -449,12 +453,14 @@ test/asset_bulk_upload_check_dto_test.dart
 | 
			
		||||
test/asset_bulk_upload_check_item_test.dart
 | 
			
		||||
test/asset_bulk_upload_check_response_dto_test.dart
 | 
			
		||||
test/asset_bulk_upload_check_result_test.dart
 | 
			
		||||
test/asset_delta_sync_dto_test.dart
 | 
			
		||||
test/asset_delta_sync_response_dto_test.dart
 | 
			
		||||
test/asset_face_response_dto_test.dart
 | 
			
		||||
test/asset_face_update_dto_test.dart
 | 
			
		||||
test/asset_face_update_item_test.dart
 | 
			
		||||
test/asset_face_without_person_response_dto_test.dart
 | 
			
		||||
test/asset_file_upload_response_dto_test.dart
 | 
			
		||||
test/asset_full_sync_dto_test.dart
 | 
			
		||||
test/asset_ids_dto_test.dart
 | 
			
		||||
test/asset_ids_response_dto_test.dart
 | 
			
		||||
test/asset_job_name_test.dart
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							@ -186,8 +186,8 @@ Class | Method | HTTP request | Description
 | 
			
		||||
*SharedLinkApi* | [**removeSharedLink**](doc//SharedLinkApi.md#removesharedlink) | **DELETE** /shared-link/{id} | 
 | 
			
		||||
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets | 
 | 
			
		||||
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} | 
 | 
			
		||||
*SyncApi* | [**getAllForUserFullSync**](doc//SyncApi.md#getallforuserfullsync) | **GET** /sync/full-sync | 
 | 
			
		||||
*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **GET** /sync/delta-sync | 
 | 
			
		||||
*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **POST** /sync/delta-sync | 
 | 
			
		||||
*SyncApi* | [**getFullSyncForUser**](doc//SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync | 
 | 
			
		||||
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config | 
 | 
			
		||||
*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults | 
 | 
			
		||||
*SystemConfigApi* | [**getMapStyle**](doc//SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json | 
 | 
			
		||||
@ -244,12 +244,14 @@ Class | Method | HTTP request | Description
 | 
			
		||||
 - [AssetBulkUploadCheckItem](doc//AssetBulkUploadCheckItem.md)
 | 
			
		||||
 - [AssetBulkUploadCheckResponseDto](doc//AssetBulkUploadCheckResponseDto.md)
 | 
			
		||||
 - [AssetBulkUploadCheckResult](doc//AssetBulkUploadCheckResult.md)
 | 
			
		||||
 - [AssetDeltaSyncDto](doc//AssetDeltaSyncDto.md)
 | 
			
		||||
 - [AssetDeltaSyncResponseDto](doc//AssetDeltaSyncResponseDto.md)
 | 
			
		||||
 - [AssetFaceResponseDto](doc//AssetFaceResponseDto.md)
 | 
			
		||||
 - [AssetFaceUpdateDto](doc//AssetFaceUpdateDto.md)
 | 
			
		||||
 - [AssetFaceUpdateItem](doc//AssetFaceUpdateItem.md)
 | 
			
		||||
 - [AssetFaceWithoutPersonResponseDto](doc//AssetFaceWithoutPersonResponseDto.md)
 | 
			
		||||
 - [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md)
 | 
			
		||||
 - [AssetFullSyncDto](doc//AssetFullSyncDto.md)
 | 
			
		||||
 - [AssetIdsDto](doc//AssetIdsDto.md)
 | 
			
		||||
 - [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
 | 
			
		||||
 - [AssetJobName](doc//AssetJobName.md)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/AssetDeltaSyncDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/AssetDeltaSyncDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
# openapi.model.AssetDeltaSyncDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**updatedAfter** | [**DateTime**](DateTime.md) |  | 
 | 
			
		||||
**userIds** | **List<String>** |  | [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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								mobile/openapi/doc/AssetFullSyncDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								mobile/openapi/doc/AssetFullSyncDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
# openapi.model.AssetFullSyncDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**lastCreationDate** | [**DateTime**](DateTime.md) |  | [optional] 
 | 
			
		||||
**lastId** | **String** |  | [optional] 
 | 
			
		||||
**limit** | **int** |  | 
 | 
			
		||||
**updatedUntil** | [**DateTime**](DateTime.md) |  | 
 | 
			
		||||
**userId** | **String** |  | [optional] 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										134
									
								
								mobile/openapi/doc/SyncApi.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										134
									
								
								mobile/openapi/doc/SyncApi.md
									
									
									
										generated
									
									
									
								
							@ -9,75 +9,12 @@ All URIs are relative to */api*
 | 
			
		||||
 | 
			
		||||
Method | HTTP request | Description
 | 
			
		||||
------------- | ------------- | -------------
 | 
			
		||||
[**getAllForUserFullSync**](SyncApi.md#getallforuserfullsync) | **GET** /sync/full-sync | 
 | 
			
		||||
[**getDeltaSync**](SyncApi.md#getdeltasync) | **GET** /sync/delta-sync | 
 | 
			
		||||
[**getDeltaSync**](SyncApi.md#getdeltasync) | **POST** /sync/delta-sync | 
 | 
			
		||||
[**getFullSyncForUser**](SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync | 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# **getAllForUserFullSync**
 | 
			
		||||
> List<AssetResponseDto> getAllForUserFullSync(limit, updatedUntil, lastCreationDate, lastId, userId)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure API key authorization: cookie
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
 | 
			
		||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
 | 
			
		||||
// TODO Configure API key authorization: api_key
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
 | 
			
		||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
 | 
			
		||||
// 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 = SyncApi();
 | 
			
		||||
final limit = 56; // int | 
 | 
			
		||||
final updatedUntil = 2013-10-20T19:20:30+01:00; // DateTime | 
 | 
			
		||||
final lastCreationDate = 2013-10-20T19:20:30+01:00; // DateTime | 
 | 
			
		||||
final lastId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | 
 | 
			
		||||
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getAllForUserFullSync(limit, updatedUntil, lastCreationDate, lastId, userId);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling SyncApi->getAllForUserFullSync: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **limit** | **int**|  | 
 | 
			
		||||
 **updatedUntil** | **DateTime**|  | 
 | 
			
		||||
 **lastCreationDate** | **DateTime**|  | [optional] 
 | 
			
		||||
 **lastId** | **String**|  | [optional] 
 | 
			
		||||
 **userId** | **String**|  | [optional] 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**List<AssetResponseDto>**](AssetResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [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)
 | 
			
		||||
 | 
			
		||||
# **getDeltaSync**
 | 
			
		||||
> AssetDeltaSyncResponseDto getDeltaSync(updatedAfter, userIds)
 | 
			
		||||
> AssetDeltaSyncResponseDto getDeltaSync(assetDeltaSyncDto)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -100,11 +37,10 @@ import 'package:openapi/api.dart';
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = SyncApi();
 | 
			
		||||
final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime | 
 | 
			
		||||
final userIds = []; // List<String> | 
 | 
			
		||||
final assetDeltaSyncDto = AssetDeltaSyncDto(); // AssetDeltaSyncDto | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getDeltaSync(updatedAfter, userIds);
 | 
			
		||||
    final result = api_instance.getDeltaSync(assetDeltaSyncDto);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling SyncApi->getDeltaSync: $e\n');
 | 
			
		||||
@ -115,8 +51,7 @@ try {
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **updatedAfter** | **DateTime**|  | 
 | 
			
		||||
 **userIds** | [**List<String>**](String.md)|  | [default to const []]
 | 
			
		||||
 **assetDeltaSyncDto** | [**AssetDeltaSyncDto**](AssetDeltaSyncDto.md)|  | 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
@ -128,7 +63,62 @@ Name | Type | Description  | Notes
 | 
			
		||||
 | 
			
		||||
### HTTP request headers
 | 
			
		||||
 | 
			
		||||
 - **Content-Type**: Not defined
 | 
			
		||||
 - **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)
 | 
			
		||||
 | 
			
		||||
# **getFullSyncForUser**
 | 
			
		||||
> List<AssetResponseDto> getFullSyncForUser(assetFullSyncDto)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure API key authorization: cookie
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
 | 
			
		||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
 | 
			
		||||
// TODO Configure API key authorization: api_key
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
 | 
			
		||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
 | 
			
		||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
 | 
			
		||||
// 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 = SyncApi();
 | 
			
		||||
final assetFullSyncDto = AssetFullSyncDto(); // AssetFullSyncDto | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.getFullSyncForUser(assetFullSyncDto);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling SyncApi->getFullSyncForUser: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **assetFullSyncDto** | [**AssetFullSyncDto**](AssetFullSyncDto.md)|  | 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**List<AssetResponseDto>**](AssetResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							@ -77,12 +77,14 @@ part 'model/asset_bulk_upload_check_dto.dart';
 | 
			
		||||
part 'model/asset_bulk_upload_check_item.dart';
 | 
			
		||||
part 'model/asset_bulk_upload_check_response_dto.dart';
 | 
			
		||||
part 'model/asset_bulk_upload_check_result.dart';
 | 
			
		||||
part 'model/asset_delta_sync_dto.dart';
 | 
			
		||||
part 'model/asset_delta_sync_response_dto.dart';
 | 
			
		||||
part 'model/asset_face_response_dto.dart';
 | 
			
		||||
part 'model/asset_face_update_dto.dart';
 | 
			
		||||
part 'model/asset_face_update_item.dart';
 | 
			
		||||
part 'model/asset_face_without_person_response_dto.dart';
 | 
			
		||||
part 'model/asset_file_upload_response_dto.dart';
 | 
			
		||||
part 'model/asset_full_sync_dto.dart';
 | 
			
		||||
part 'model/asset_ids_dto.dart';
 | 
			
		||||
part 'model/asset_ids_response_dto.dart';
 | 
			
		||||
part 'model/asset_job_name.dart';
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										145
									
								
								mobile/openapi/lib/api/sync_api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										145
									
								
								mobile/openapi/lib/api/sync_api.dart
									
									
									
										generated
									
									
									
								
							@ -16,47 +16,27 @@ class SyncApi {
 | 
			
		||||
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /sync/full-sync' operation and returns the [Response].
 | 
			
		||||
  /// Performs an HTTP 'POST /sync/delta-sync' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [int] limit (required):
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] updatedUntil (required):
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] lastCreationDate:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [String] lastId:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [String] userId:
 | 
			
		||||
  Future<Response> getAllForUserFullSyncWithHttpInfo(int limit, DateTime updatedUntil, { DateTime? lastCreationDate, String? lastId, String? userId, }) async {
 | 
			
		||||
  /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required):
 | 
			
		||||
  Future<Response> getDeltaSyncWithHttpInfo(AssetDeltaSyncDto assetDeltaSyncDto,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/sync/full-sync';
 | 
			
		||||
    final path = r'/sync/delta-sync';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody;
 | 
			
		||||
    Object? postBody = assetDeltaSyncDto;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
    if (lastCreationDate != null) {
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'lastCreationDate', lastCreationDate));
 | 
			
		||||
    }
 | 
			
		||||
    if (lastId != null) {
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'lastId', lastId));
 | 
			
		||||
    }
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'limit', limit));
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'updatedUntil', updatedUntil));
 | 
			
		||||
    if (userId != null) {
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'userId', userId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>[];
 | 
			
		||||
    const contentTypes = <String>['application/json'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'GET',
 | 
			
		||||
      'POST',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
@ -67,17 +47,56 @@ class SyncApi {
 | 
			
		||||
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [int] limit (required):
 | 
			
		||||
  /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required):
 | 
			
		||||
  Future<AssetDeltaSyncResponseDto?> getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto,) async {
 | 
			
		||||
    final response = await getDeltaSyncWithHttpInfo(assetDeltaSyncDto,);
 | 
			
		||||
    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), 'AssetDeltaSyncResponseDto',) as AssetDeltaSyncResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'POST /sync/full-sync' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] updatedUntil (required):
 | 
			
		||||
  /// * [AssetFullSyncDto] assetFullSyncDto (required):
 | 
			
		||||
  Future<Response> getFullSyncForUserWithHttpInfo(AssetFullSyncDto assetFullSyncDto,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/sync/full-sync';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody = assetFullSyncDto;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>['application/json'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'POST',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
      formParams,
 | 
			
		||||
      contentTypes.isEmpty ? null : contentTypes.first,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] lastCreationDate:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [String] lastId:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [String] userId:
 | 
			
		||||
  Future<List<AssetResponseDto>?> getAllForUserFullSync(int limit, DateTime updatedUntil, { DateTime? lastCreationDate, String? lastId, String? userId, }) async {
 | 
			
		||||
    final response = await getAllForUserFullSyncWithHttpInfo(limit, updatedUntil,  lastCreationDate: lastCreationDate, lastId: lastId, userId: userId, );
 | 
			
		||||
  /// * [AssetFullSyncDto] assetFullSyncDto (required):
 | 
			
		||||
  Future<List<AssetResponseDto>?> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto,) async {
 | 
			
		||||
    final response = await getFullSyncForUserWithHttpInfo(assetFullSyncDto,);
 | 
			
		||||
    if (response.statusCode >= HttpStatus.badRequest) {
 | 
			
		||||
      throw ApiException(response.statusCode, await _decodeBodyBytes(response));
 | 
			
		||||
    }
 | 
			
		||||
@ -93,58 +112,4 @@ class SyncApi {
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'GET /sync/delta-sync' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] updatedAfter (required):
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [List<String>] userIds (required):
 | 
			
		||||
  Future<Response> getDeltaSyncWithHttpInfo(DateTime updatedAfter, List<String> userIds,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/sync/delta-sync';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody;
 | 
			
		||||
 | 
			
		||||
    final queryParams = <QueryParam>[];
 | 
			
		||||
    final headerParams = <String, String>{};
 | 
			
		||||
    final formParams = <String, String>{};
 | 
			
		||||
 | 
			
		||||
      queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter));
 | 
			
		||||
      queryParams.addAll(_queryParams('multi', 'userIds', userIds));
 | 
			
		||||
 | 
			
		||||
    const contentTypes = <String>[];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return apiClient.invokeAPI(
 | 
			
		||||
      path,
 | 
			
		||||
      'GET',
 | 
			
		||||
      queryParams,
 | 
			
		||||
      postBody,
 | 
			
		||||
      headerParams,
 | 
			
		||||
      formParams,
 | 
			
		||||
      contentTypes.isEmpty ? null : contentTypes.first,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [DateTime] updatedAfter (required):
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [List<String>] userIds (required):
 | 
			
		||||
  Future<AssetDeltaSyncResponseDto?> getDeltaSync(DateTime updatedAfter, List<String> userIds,) async {
 | 
			
		||||
    final response = await getDeltaSyncWithHttpInfo(updatedAfter, userIds,);
 | 
			
		||||
    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), 'AssetDeltaSyncResponseDto',) as AssetDeltaSyncResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							@ -224,6 +224,8 @@ class ApiClient {
 | 
			
		||||
          return AssetBulkUploadCheckResponseDto.fromJson(value);
 | 
			
		||||
        case 'AssetBulkUploadCheckResult':
 | 
			
		||||
          return AssetBulkUploadCheckResult.fromJson(value);
 | 
			
		||||
        case 'AssetDeltaSyncDto':
 | 
			
		||||
          return AssetDeltaSyncDto.fromJson(value);
 | 
			
		||||
        case 'AssetDeltaSyncResponseDto':
 | 
			
		||||
          return AssetDeltaSyncResponseDto.fromJson(value);
 | 
			
		||||
        case 'AssetFaceResponseDto':
 | 
			
		||||
@ -236,6 +238,8 @@ class ApiClient {
 | 
			
		||||
          return AssetFaceWithoutPersonResponseDto.fromJson(value);
 | 
			
		||||
        case 'AssetFileUploadResponseDto':
 | 
			
		||||
          return AssetFileUploadResponseDto.fromJson(value);
 | 
			
		||||
        case 'AssetFullSyncDto':
 | 
			
		||||
          return AssetFullSyncDto.fromJson(value);
 | 
			
		||||
        case 'AssetIdsDto':
 | 
			
		||||
          return AssetIdsDto.fromJson(value);
 | 
			
		||||
        case 'AssetIdsResponseDto':
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										108
									
								
								mobile/openapi/lib/model/asset_delta_sync_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								mobile/openapi/lib/model/asset_delta_sync_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,108 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AssetDeltaSyncDto {
 | 
			
		||||
  /// Returns a new [AssetDeltaSyncDto] instance.
 | 
			
		||||
  AssetDeltaSyncDto({
 | 
			
		||||
    required this.updatedAfter,
 | 
			
		||||
    this.userIds = const [],
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  DateTime updatedAfter;
 | 
			
		||||
 | 
			
		||||
  List<String> userIds;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is AssetDeltaSyncDto &&
 | 
			
		||||
    other.updatedAfter == updatedAfter &&
 | 
			
		||||
    _deepEquality.equals(other.userIds, userIds);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (updatedAfter.hashCode) +
 | 
			
		||||
    (userIds.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'AssetDeltaSyncDto[updatedAfter=$updatedAfter, userIds=$userIds]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
      json[r'updatedAfter'] = this.updatedAfter.toUtc().toIso8601String();
 | 
			
		||||
      json[r'userIds'] = this.userIds;
 | 
			
		||||
    return json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [AssetDeltaSyncDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static AssetDeltaSyncDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      return AssetDeltaSyncDto(
 | 
			
		||||
        updatedAfter: mapDateTime(json, r'updatedAfter', r'')!,
 | 
			
		||||
        userIds: json[r'userIds'] is Iterable
 | 
			
		||||
            ? (json[r'userIds'] as Iterable).cast<String>().toList(growable: false)
 | 
			
		||||
            : const [],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<AssetDeltaSyncDto> listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <AssetDeltaSyncDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = AssetDeltaSyncDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, AssetDeltaSyncDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, AssetDeltaSyncDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = AssetDeltaSyncDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of AssetDeltaSyncDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<AssetDeltaSyncDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<AssetDeltaSyncDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      // ignore: parameter_assignments
 | 
			
		||||
      json = json.cast<String, dynamic>();
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        map[entry.key] = AssetDeltaSyncDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'updatedAfter',
 | 
			
		||||
    'userIds',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										158
									
								
								mobile/openapi/lib/model/asset_full_sync_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								mobile/openapi/lib/model/asset_full_sync_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,158 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AssetFullSyncDto {
 | 
			
		||||
  /// Returns a new [AssetFullSyncDto] instance.
 | 
			
		||||
  AssetFullSyncDto({
 | 
			
		||||
    this.lastCreationDate,
 | 
			
		||||
    this.lastId,
 | 
			
		||||
    required this.limit,
 | 
			
		||||
    required this.updatedUntil,
 | 
			
		||||
    this.userId,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
  /// does not include a default value (using the "default:" property), however, the generated
 | 
			
		||||
  /// source code must fall back to having a nullable type.
 | 
			
		||||
  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
			
		||||
  ///
 | 
			
		||||
  DateTime? lastCreationDate;
 | 
			
		||||
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
  /// does not include a default value (using the "default:" property), however, the generated
 | 
			
		||||
  /// source code must fall back to having a nullable type.
 | 
			
		||||
  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
			
		||||
  ///
 | 
			
		||||
  String? lastId;
 | 
			
		||||
 | 
			
		||||
  /// Minimum value: 1
 | 
			
		||||
  int limit;
 | 
			
		||||
 | 
			
		||||
  DateTime updatedUntil;
 | 
			
		||||
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
  /// does not include a default value (using the "default:" property), however, the generated
 | 
			
		||||
  /// source code must fall back to having a nullable type.
 | 
			
		||||
  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
			
		||||
  ///
 | 
			
		||||
  String? userId;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is AssetFullSyncDto &&
 | 
			
		||||
    other.lastCreationDate == lastCreationDate &&
 | 
			
		||||
    other.lastId == lastId &&
 | 
			
		||||
    other.limit == limit &&
 | 
			
		||||
    other.updatedUntil == updatedUntil &&
 | 
			
		||||
    other.userId == userId;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (lastCreationDate == null ? 0 : lastCreationDate!.hashCode) +
 | 
			
		||||
    (lastId == null ? 0 : lastId!.hashCode) +
 | 
			
		||||
    (limit.hashCode) +
 | 
			
		||||
    (updatedUntil.hashCode) +
 | 
			
		||||
    (userId == null ? 0 : userId!.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'AssetFullSyncDto[lastCreationDate=$lastCreationDate, lastId=$lastId, limit=$limit, updatedUntil=$updatedUntil, userId=$userId]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
    if (this.lastCreationDate != null) {
 | 
			
		||||
      json[r'lastCreationDate'] = this.lastCreationDate!.toUtc().toIso8601String();
 | 
			
		||||
    } else {
 | 
			
		||||
    //  json[r'lastCreationDate'] = null;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.lastId != null) {
 | 
			
		||||
      json[r'lastId'] = this.lastId;
 | 
			
		||||
    } else {
 | 
			
		||||
    //  json[r'lastId'] = null;
 | 
			
		||||
    }
 | 
			
		||||
      json[r'limit'] = this.limit;
 | 
			
		||||
      json[r'updatedUntil'] = this.updatedUntil.toUtc().toIso8601String();
 | 
			
		||||
    if (this.userId != null) {
 | 
			
		||||
      json[r'userId'] = this.userId;
 | 
			
		||||
    } else {
 | 
			
		||||
    //  json[r'userId'] = null;
 | 
			
		||||
    }
 | 
			
		||||
    return json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [AssetFullSyncDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static AssetFullSyncDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      return AssetFullSyncDto(
 | 
			
		||||
        lastCreationDate: mapDateTime(json, r'lastCreationDate', r''),
 | 
			
		||||
        lastId: mapValueOfType<String>(json, r'lastId'),
 | 
			
		||||
        limit: mapValueOfType<int>(json, r'limit')!,
 | 
			
		||||
        updatedUntil: mapDateTime(json, r'updatedUntil', r'')!,
 | 
			
		||||
        userId: mapValueOfType<String>(json, r'userId'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<AssetFullSyncDto> listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <AssetFullSyncDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = AssetFullSyncDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, AssetFullSyncDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, AssetFullSyncDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = AssetFullSyncDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of AssetFullSyncDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<AssetFullSyncDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<AssetFullSyncDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      // ignore: parameter_assignments
 | 
			
		||||
      json = json.cast<String, dynamic>();
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        map[entry.key] = AssetFullSyncDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'limit',
 | 
			
		||||
    'updatedUntil',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								mobile/openapi/test/asset_delta_sync_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/openapi/test/asset_delta_sync_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
//
 | 
			
		||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
			
		||||
//
 | 
			
		||||
// @dart=2.12
 | 
			
		||||
 | 
			
		||||
// ignore_for_file: unused_element, unused_import
 | 
			
		||||
// ignore_for_file: always_put_required_named_parameters_first
 | 
			
		||||
// ignore_for_file: constant_identifier_names
 | 
			
		||||
// ignore_for_file: lines_longer_than_80_chars
 | 
			
		||||
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
import 'package:test/test.dart';
 | 
			
		||||
 | 
			
		||||
// tests for AssetDeltaSyncDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = AssetDeltaSyncDto();
 | 
			
		||||
 | 
			
		||||
  group('test AssetDeltaSyncDto', () {
 | 
			
		||||
    // DateTime updatedAfter
 | 
			
		||||
    test('to test the property `updatedAfter`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // List<String> userIds (default value: const [])
 | 
			
		||||
    test('to test the property `userIds`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								mobile/openapi/test/asset_full_sync_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								mobile/openapi/test/asset_full_sync_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 AssetFullSyncDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = AssetFullSyncDto();
 | 
			
		||||
 | 
			
		||||
  group('test AssetFullSyncDto', () {
 | 
			
		||||
    // DateTime lastCreationDate
 | 
			
		||||
    test('to test the property `lastCreationDate`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String lastId
 | 
			
		||||
    test('to test the property `lastId`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // int limit
 | 
			
		||||
    test('to test the property `limit`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // DateTime updatedUntil
 | 
			
		||||
    test('to test the property `updatedUntil`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String userId
 | 
			
		||||
    test('to test the property `userId`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								mobile/openapi/test/sync_api_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								mobile/openapi/test/sync_api_test.dart
									
									
									
										generated
									
									
									
								
							@ -17,13 +17,13 @@ void main() {
 | 
			
		||||
  // final instance = SyncApi();
 | 
			
		||||
 | 
			
		||||
  group('tests for SyncApi', () {
 | 
			
		||||
    //Future<List<AssetResponseDto>> getAllForUserFullSync(int limit, DateTime updatedUntil, { DateTime lastCreationDate, String lastId, String userId }) async
 | 
			
		||||
    test('test getAllForUserFullSync', () async {
 | 
			
		||||
    //Future<AssetDeltaSyncResponseDto> getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto) async
 | 
			
		||||
    test('test getDeltaSync', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //Future<AssetDeltaSyncResponseDto> getDeltaSync(DateTime updatedAfter, List<String> userIds) async
 | 
			
		||||
    test('test getDeltaSync', () async {
 | 
			
		||||
    //Future<List<AssetResponseDto>> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto) async
 | 
			
		||||
    test('test getFullSyncForUser', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4958,31 +4958,19 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "/sync/delta-sync": {
 | 
			
		||||
      "get": {
 | 
			
		||||
      "post": {
 | 
			
		||||
        "operationId": "getDeltaSync",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "updatedAfter",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
        "parameters": [],
 | 
			
		||||
        "requestBody": {
 | 
			
		||||
          "content": {
 | 
			
		||||
            "application/json": {
 | 
			
		||||
              "schema": {
 | 
			
		||||
              "format": "date-time",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
                "$ref": "#/components/schemas/AssetDeltaSyncDto"
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "userIds",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "format": "uuid",
 | 
			
		||||
              "type": "array",
 | 
			
		||||
              "items": {
 | 
			
		||||
                "type": "string"
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
          "required": true
 | 
			
		||||
        },
 | 
			
		||||
        "responses": {
 | 
			
		||||
          "200": {
 | 
			
		||||
            "content": {
 | 
			
		||||
@ -5012,55 +5000,19 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "/sync/full-sync": {
 | 
			
		||||
      "get": {
 | 
			
		||||
        "operationId": "getAllForUserFullSync",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "lastCreationDate",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
      "post": {
 | 
			
		||||
        "operationId": "getFullSyncForUser",
 | 
			
		||||
        "parameters": [],
 | 
			
		||||
        "requestBody": {
 | 
			
		||||
          "content": {
 | 
			
		||||
            "application/json": {
 | 
			
		||||
              "schema": {
 | 
			
		||||
              "format": "date-time",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
                "$ref": "#/components/schemas/AssetFullSyncDto"
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "lastId",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "format": "uuid",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          "required": true
 | 
			
		||||
        },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "limit",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "minimum": 1,
 | 
			
		||||
              "type": "integer"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "updatedUntil",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "format": "date-time",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "userId",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "format": "uuid",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": {
 | 
			
		||||
          "200": {
 | 
			
		||||
            "content": {
 | 
			
		||||
@ -7023,6 +6975,26 @@
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "AssetDeltaSyncDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "updatedAfter": {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "userIds": {
 | 
			
		||||
            "items": {
 | 
			
		||||
              "format": "uuid",
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "required": [
 | 
			
		||||
          "updatedAfter",
 | 
			
		||||
          "userIds"
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "AssetDeltaSyncResponseDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "deleted": {
 | 
			
		||||
@ -7175,6 +7147,35 @@
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "AssetFullSyncDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "lastCreationDate": {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "lastId": {
 | 
			
		||||
            "format": "uuid",
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "limit": {
 | 
			
		||||
            "minimum": 1,
 | 
			
		||||
            "type": "integer"
 | 
			
		||||
          },
 | 
			
		||||
          "updatedUntil": {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "userId": {
 | 
			
		||||
            "format": "uuid",
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "required": [
 | 
			
		||||
          "limit",
 | 
			
		||||
          "updatedUntil"
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object"
 | 
			
		||||
      },
 | 
			
		||||
      "AssetIdsDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "assetIds": {
 | 
			
		||||
 | 
			
		||||
@ -836,11 +836,22 @@ export type AssetIdsResponseDto = {
 | 
			
		||||
    error?: Error2;
 | 
			
		||||
    success: boolean;
 | 
			
		||||
};
 | 
			
		||||
export type AssetDeltaSyncDto = {
 | 
			
		||||
    updatedAfter: string;
 | 
			
		||||
    userIds: string[];
 | 
			
		||||
};
 | 
			
		||||
export type AssetDeltaSyncResponseDto = {
 | 
			
		||||
    deleted: string[];
 | 
			
		||||
    needsFullSync: boolean;
 | 
			
		||||
    upserted: AssetResponseDto[];
 | 
			
		||||
};
 | 
			
		||||
export type AssetFullSyncDto = {
 | 
			
		||||
    lastCreationDate?: string;
 | 
			
		||||
    lastId?: string;
 | 
			
		||||
    limit: number;
 | 
			
		||||
    updatedUntil: string;
 | 
			
		||||
    userId?: string;
 | 
			
		||||
};
 | 
			
		||||
export type SystemConfigFFmpegDto = {
 | 
			
		||||
    accel: TranscodeHWAccel;
 | 
			
		||||
    acceptedAudioCodecs: AudioCodec[];
 | 
			
		||||
@ -2372,39 +2383,29 @@ export function addSharedLinkAssets({ id, key, assetIdsDto }: {
 | 
			
		||||
        body: assetIdsDto
 | 
			
		||||
    })));
 | 
			
		||||
}
 | 
			
		||||
export function getDeltaSync({ updatedAfter, userIds }: {
 | 
			
		||||
    updatedAfter: string;
 | 
			
		||||
    userIds: string[];
 | 
			
		||||
export function getDeltaSync({ assetDeltaSyncDto }: {
 | 
			
		||||
    assetDeltaSyncDto: AssetDeltaSyncDto;
 | 
			
		||||
}, opts?: Oazapfts.RequestOpts) {
 | 
			
		||||
    return oazapfts.ok(oazapfts.fetchJson<{
 | 
			
		||||
        status: 200;
 | 
			
		||||
        data: AssetDeltaSyncResponseDto;
 | 
			
		||||
    }>(`/sync/delta-sync${QS.query(QS.explode({
 | 
			
		||||
        updatedAfter,
 | 
			
		||||
        userIds
 | 
			
		||||
    }))}`, {
 | 
			
		||||
        ...opts
 | 
			
		||||
    }));
 | 
			
		||||
    }>("/sync/delta-sync", oazapfts.json({
 | 
			
		||||
        ...opts,
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        body: assetDeltaSyncDto
 | 
			
		||||
    })));
 | 
			
		||||
}
 | 
			
		||||
export function getAllForUserFullSync({ lastCreationDate, lastId, limit, updatedUntil, userId }: {
 | 
			
		||||
    lastCreationDate?: string;
 | 
			
		||||
    lastId?: string;
 | 
			
		||||
    limit: number;
 | 
			
		||||
    updatedUntil: string;
 | 
			
		||||
    userId?: string;
 | 
			
		||||
export function getFullSyncForUser({ assetFullSyncDto }: {
 | 
			
		||||
    assetFullSyncDto: AssetFullSyncDto;
 | 
			
		||||
}, opts?: Oazapfts.RequestOpts) {
 | 
			
		||||
    return oazapfts.ok(oazapfts.fetchJson<{
 | 
			
		||||
        status: 200;
 | 
			
		||||
        data: AssetResponseDto[];
 | 
			
		||||
    }>(`/sync/full-sync${QS.query(QS.explode({
 | 
			
		||||
        lastCreationDate,
 | 
			
		||||
        lastId,
 | 
			
		||||
        limit,
 | 
			
		||||
        updatedUntil,
 | 
			
		||||
        userId
 | 
			
		||||
    }))}`, {
 | 
			
		||||
        ...opts
 | 
			
		||||
    }));
 | 
			
		||||
    }>("/sync/full-sync", oazapfts.json({
 | 
			
		||||
        ...opts,
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        body: assetFullSyncDto
 | 
			
		||||
    })));
 | 
			
		||||
}
 | 
			
		||||
export function getConfig(opts?: Oazapfts.RequestOpts) {
 | 
			
		||||
    return oazapfts.ok(oazapfts.fetchJson<{
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Controller, Get, Query } from '@nestjs/common';
 | 
			
		||||
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
 | 
			
		||||
import { ApiTags } from '@nestjs/swagger';
 | 
			
		||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
			
		||||
@ -12,13 +12,15 @@ import { SyncService } from 'src/services/sync.service';
 | 
			
		||||
export class SyncController {
 | 
			
		||||
  constructor(private service: SyncService) {}
 | 
			
		||||
 | 
			
		||||
  @Get('full-sync')
 | 
			
		||||
  getAllForUserFullSync(@Auth() auth: AuthDto, @Query() dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
 | 
			
		||||
    return this.service.getAllAssetsForUserFullSync(auth, dto);
 | 
			
		||||
  @Post('full-sync')
 | 
			
		||||
  @HttpCode(HttpStatus.OK)
 | 
			
		||||
  getFullSyncForUser(@Auth() auth: AuthDto, @Body() dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
 | 
			
		||||
    return this.service.getFullSync(auth, dto);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Get('delta-sync')
 | 
			
		||||
  getDeltaSync(@Auth() auth: AuthDto, @Query() dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
 | 
			
		||||
    return this.service.getChangesForDeltaSync(auth, dto);
 | 
			
		||||
  @Post('delta-sync')
 | 
			
		||||
  @HttpCode(HttpStatus.OK)
 | 
			
		||||
  getDeltaSync(@Auth() auth: AuthDto, @Body() dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
 | 
			
		||||
    return this.service.getDeltaSync(auth, dto);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsInt, IsPositive } from 'class-validator';
 | 
			
		||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
 | 
			
		||||
import { ValidateDate, ValidateUUID } from 'src/validation';
 | 
			
		||||
@ -16,7 +15,6 @@ export class AssetFullSyncDto {
 | 
			
		||||
 | 
			
		||||
  @IsInt()
 | 
			
		||||
  @IsPositive()
 | 
			
		||||
  @Type(() => Number)
 | 
			
		||||
  @ApiProperty({ type: 'integer' })
 | 
			
		||||
  limit!: number;
 | 
			
		||||
 | 
			
		||||
@ -27,6 +25,7 @@ export class AssetFullSyncDto {
 | 
			
		||||
export class AssetDeltaSyncDto {
 | 
			
		||||
  @ValidateDate()
 | 
			
		||||
  updatedAfter!: Date;
 | 
			
		||||
 | 
			
		||||
  @ValidateUUID({ each: true })
 | 
			
		||||
  userIds!: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -134,6 +134,8 @@ export interface AssetFullSyncOptions {
 | 
			
		||||
  lastCreationDate?: Date;
 | 
			
		||||
  lastId?: string;
 | 
			
		||||
  updatedUntil: Date;
 | 
			
		||||
  isArchived?: false;
 | 
			
		||||
  withStacked?: true;
 | 
			
		||||
  limit: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -798,16 +798,47 @@ SELECT
 | 
			
		||||
  "exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
 | 
			
		||||
  "exifInfo"."fps" AS "exifInfo_fps",
 | 
			
		||||
  "stack"."id" AS "stack_id",
 | 
			
		||||
  "stack"."primaryAssetId" AS "stack_primaryAssetId"
 | 
			
		||||
  "stack"."primaryAssetId" AS "stack_primaryAssetId",
 | 
			
		||||
  "stackedAssets"."id" AS "stackedAssets_id",
 | 
			
		||||
  "stackedAssets"."deviceAssetId" AS "stackedAssets_deviceAssetId",
 | 
			
		||||
  "stackedAssets"."ownerId" AS "stackedAssets_ownerId",
 | 
			
		||||
  "stackedAssets"."libraryId" AS "stackedAssets_libraryId",
 | 
			
		||||
  "stackedAssets"."deviceId" AS "stackedAssets_deviceId",
 | 
			
		||||
  "stackedAssets"."type" AS "stackedAssets_type",
 | 
			
		||||
  "stackedAssets"."originalPath" AS "stackedAssets_originalPath",
 | 
			
		||||
  "stackedAssets"."previewPath" AS "stackedAssets_previewPath",
 | 
			
		||||
  "stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
 | 
			
		||||
  "stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
 | 
			
		||||
  "stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
 | 
			
		||||
  "stackedAssets"."createdAt" AS "stackedAssets_createdAt",
 | 
			
		||||
  "stackedAssets"."updatedAt" AS "stackedAssets_updatedAt",
 | 
			
		||||
  "stackedAssets"."deletedAt" AS "stackedAssets_deletedAt",
 | 
			
		||||
  "stackedAssets"."fileCreatedAt" AS "stackedAssets_fileCreatedAt",
 | 
			
		||||
  "stackedAssets"."localDateTime" AS "stackedAssets_localDateTime",
 | 
			
		||||
  "stackedAssets"."fileModifiedAt" AS "stackedAssets_fileModifiedAt",
 | 
			
		||||
  "stackedAssets"."isFavorite" AS "stackedAssets_isFavorite",
 | 
			
		||||
  "stackedAssets"."isArchived" AS "stackedAssets_isArchived",
 | 
			
		||||
  "stackedAssets"."isExternal" AS "stackedAssets_isExternal",
 | 
			
		||||
  "stackedAssets"."isReadOnly" AS "stackedAssets_isReadOnly",
 | 
			
		||||
  "stackedAssets"."isOffline" AS "stackedAssets_isOffline",
 | 
			
		||||
  "stackedAssets"."checksum" AS "stackedAssets_checksum",
 | 
			
		||||
  "stackedAssets"."duration" AS "stackedAssets_duration",
 | 
			
		||||
  "stackedAssets"."isVisible" AS "stackedAssets_isVisible",
 | 
			
		||||
  "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId",
 | 
			
		||||
  "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName",
 | 
			
		||||
  "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath",
 | 
			
		||||
  "stackedAssets"."stackId" AS "stackedAssets_stackId"
 | 
			
		||||
FROM
 | 
			
		||||
  "assets" "asset"
 | 
			
		||||
  LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
 | 
			
		||||
  LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
 | 
			
		||||
  LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
 | 
			
		||||
  AND ("stackedAssets"."deletedAt" IS NULL)
 | 
			
		||||
WHERE
 | 
			
		||||
  "asset"."ownerId" = $1
 | 
			
		||||
  "asset"."isVisible" = true
 | 
			
		||||
  AND "asset"."ownerId" IN ($1)
 | 
			
		||||
  AND ("asset"."fileCreatedAt", "asset"."id") < ($2, $3)
 | 
			
		||||
  AND "asset"."updatedAt" <= $4
 | 
			
		||||
  AND "asset"."isVisible" = true
 | 
			
		||||
ORDER BY
 | 
			
		||||
  "asset"."fileCreatedAt" DESC,
 | 
			
		||||
  "asset"."id" DESC
 | 
			
		||||
@ -816,72 +847,105 @@ LIMIT
 | 
			
		||||
 | 
			
		||||
-- AssetRepository.getChangedDeltaSync
 | 
			
		||||
SELECT
 | 
			
		||||
  "AssetEntity"."id" AS "AssetEntity_id",
 | 
			
		||||
  "AssetEntity"."deviceAssetId" AS "AssetEntity_deviceAssetId",
 | 
			
		||||
  "AssetEntity"."ownerId" AS "AssetEntity_ownerId",
 | 
			
		||||
  "AssetEntity"."libraryId" AS "AssetEntity_libraryId",
 | 
			
		||||
  "AssetEntity"."deviceId" AS "AssetEntity_deviceId",
 | 
			
		||||
  "AssetEntity"."type" AS "AssetEntity_type",
 | 
			
		||||
  "AssetEntity"."originalPath" AS "AssetEntity_originalPath",
 | 
			
		||||
  "AssetEntity"."previewPath" AS "AssetEntity_previewPath",
 | 
			
		||||
  "AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
 | 
			
		||||
  "AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
 | 
			
		||||
  "AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
 | 
			
		||||
  "AssetEntity"."createdAt" AS "AssetEntity_createdAt",
 | 
			
		||||
  "AssetEntity"."updatedAt" AS "AssetEntity_updatedAt",
 | 
			
		||||
  "AssetEntity"."deletedAt" AS "AssetEntity_deletedAt",
 | 
			
		||||
  "AssetEntity"."fileCreatedAt" AS "AssetEntity_fileCreatedAt",
 | 
			
		||||
  "AssetEntity"."localDateTime" AS "AssetEntity_localDateTime",
 | 
			
		||||
  "AssetEntity"."fileModifiedAt" AS "AssetEntity_fileModifiedAt",
 | 
			
		||||
  "AssetEntity"."isFavorite" AS "AssetEntity_isFavorite",
 | 
			
		||||
  "AssetEntity"."isArchived" AS "AssetEntity_isArchived",
 | 
			
		||||
  "AssetEntity"."isExternal" AS "AssetEntity_isExternal",
 | 
			
		||||
  "AssetEntity"."isReadOnly" AS "AssetEntity_isReadOnly",
 | 
			
		||||
  "AssetEntity"."isOffline" AS "AssetEntity_isOffline",
 | 
			
		||||
  "AssetEntity"."checksum" AS "AssetEntity_checksum",
 | 
			
		||||
  "AssetEntity"."duration" AS "AssetEntity_duration",
 | 
			
		||||
  "AssetEntity"."isVisible" AS "AssetEntity_isVisible",
 | 
			
		||||
  "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId",
 | 
			
		||||
  "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName",
 | 
			
		||||
  "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath",
 | 
			
		||||
  "AssetEntity"."stackId" AS "AssetEntity_stackId",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."assetId" AS "AssetEntity__AssetEntity_exifInfo_assetId",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."description" AS "AssetEntity__AssetEntity_exifInfo_description",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."exifImageWidth" AS "AssetEntity__AssetEntity_exifInfo_exifImageWidth",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."exifImageHeight" AS "AssetEntity__AssetEntity_exifInfo_exifImageHeight",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."fileSizeInByte" AS "AssetEntity__AssetEntity_exifInfo_fileSizeInByte",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."orientation" AS "AssetEntity__AssetEntity_exifInfo_orientation",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."dateTimeOriginal" AS "AssetEntity__AssetEntity_exifInfo_dateTimeOriginal",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."modifyDate" AS "AssetEntity__AssetEntity_exifInfo_modifyDate",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."timeZone" AS "AssetEntity__AssetEntity_exifInfo_timeZone",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."latitude" AS "AssetEntity__AssetEntity_exifInfo_latitude",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."longitude" AS "AssetEntity__AssetEntity_exifInfo_longitude",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."projectionType" AS "AssetEntity__AssetEntity_exifInfo_projectionType",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."city" AS "AssetEntity__AssetEntity_exifInfo_city",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."livePhotoCID" AS "AssetEntity__AssetEntity_exifInfo_livePhotoCID",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."autoStackId" AS "AssetEntity__AssetEntity_exifInfo_autoStackId",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."state" AS "AssetEntity__AssetEntity_exifInfo_state",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."country" AS "AssetEntity__AssetEntity_exifInfo_country",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."make" AS "AssetEntity__AssetEntity_exifInfo_make",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."model" AS "AssetEntity__AssetEntity_exifInfo_model",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."lensModel" AS "AssetEntity__AssetEntity_exifInfo_lensModel",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."fNumber" AS "AssetEntity__AssetEntity_exifInfo_fNumber",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."focalLength" AS "AssetEntity__AssetEntity_exifInfo_focalLength",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."iso" AS "AssetEntity__AssetEntity_exifInfo_iso",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."exposureTime" AS "AssetEntity__AssetEntity_exifInfo_exposureTime",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."profileDescription" AS "AssetEntity__AssetEntity_exifInfo_profileDescription",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."colorspace" AS "AssetEntity__AssetEntity_exifInfo_colorspace",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."bitsPerSample" AS "AssetEntity__AssetEntity_exifInfo_bitsPerSample",
 | 
			
		||||
  "AssetEntity__AssetEntity_exifInfo"."fps" AS "AssetEntity__AssetEntity_exifInfo_fps",
 | 
			
		||||
  "AssetEntity__AssetEntity_stack"."id" AS "AssetEntity__AssetEntity_stack_id",
 | 
			
		||||
  "AssetEntity__AssetEntity_stack"."primaryAssetId" AS "AssetEntity__AssetEntity_stack_primaryAssetId"
 | 
			
		||||
  "asset"."id" AS "asset_id",
 | 
			
		||||
  "asset"."deviceAssetId" AS "asset_deviceAssetId",
 | 
			
		||||
  "asset"."ownerId" AS "asset_ownerId",
 | 
			
		||||
  "asset"."libraryId" AS "asset_libraryId",
 | 
			
		||||
  "asset"."deviceId" AS "asset_deviceId",
 | 
			
		||||
  "asset"."type" AS "asset_type",
 | 
			
		||||
  "asset"."originalPath" AS "asset_originalPath",
 | 
			
		||||
  "asset"."previewPath" AS "asset_previewPath",
 | 
			
		||||
  "asset"."thumbnailPath" AS "asset_thumbnailPath",
 | 
			
		||||
  "asset"."thumbhash" AS "asset_thumbhash",
 | 
			
		||||
  "asset"."encodedVideoPath" AS "asset_encodedVideoPath",
 | 
			
		||||
  "asset"."createdAt" AS "asset_createdAt",
 | 
			
		||||
  "asset"."updatedAt" AS "asset_updatedAt",
 | 
			
		||||
  "asset"."deletedAt" AS "asset_deletedAt",
 | 
			
		||||
  "asset"."fileCreatedAt" AS "asset_fileCreatedAt",
 | 
			
		||||
  "asset"."localDateTime" AS "asset_localDateTime",
 | 
			
		||||
  "asset"."fileModifiedAt" AS "asset_fileModifiedAt",
 | 
			
		||||
  "asset"."isFavorite" AS "asset_isFavorite",
 | 
			
		||||
  "asset"."isArchived" AS "asset_isArchived",
 | 
			
		||||
  "asset"."isExternal" AS "asset_isExternal",
 | 
			
		||||
  "asset"."isReadOnly" AS "asset_isReadOnly",
 | 
			
		||||
  "asset"."isOffline" AS "asset_isOffline",
 | 
			
		||||
  "asset"."checksum" AS "asset_checksum",
 | 
			
		||||
  "asset"."duration" AS "asset_duration",
 | 
			
		||||
  "asset"."isVisible" AS "asset_isVisible",
 | 
			
		||||
  "asset"."livePhotoVideoId" AS "asset_livePhotoVideoId",
 | 
			
		||||
  "asset"."originalFileName" AS "asset_originalFileName",
 | 
			
		||||
  "asset"."sidecarPath" AS "asset_sidecarPath",
 | 
			
		||||
  "asset"."stackId" AS "asset_stackId",
 | 
			
		||||
  "exifInfo"."assetId" AS "exifInfo_assetId",
 | 
			
		||||
  "exifInfo"."description" AS "exifInfo_description",
 | 
			
		||||
  "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
 | 
			
		||||
  "exifInfo"."exifImageHeight" AS "exifInfo_exifImageHeight",
 | 
			
		||||
  "exifInfo"."fileSizeInByte" AS "exifInfo_fileSizeInByte",
 | 
			
		||||
  "exifInfo"."orientation" AS "exifInfo_orientation",
 | 
			
		||||
  "exifInfo"."dateTimeOriginal" AS "exifInfo_dateTimeOriginal",
 | 
			
		||||
  "exifInfo"."modifyDate" AS "exifInfo_modifyDate",
 | 
			
		||||
  "exifInfo"."timeZone" AS "exifInfo_timeZone",
 | 
			
		||||
  "exifInfo"."latitude" AS "exifInfo_latitude",
 | 
			
		||||
  "exifInfo"."longitude" AS "exifInfo_longitude",
 | 
			
		||||
  "exifInfo"."projectionType" AS "exifInfo_projectionType",
 | 
			
		||||
  "exifInfo"."city" AS "exifInfo_city",
 | 
			
		||||
  "exifInfo"."livePhotoCID" AS "exifInfo_livePhotoCID",
 | 
			
		||||
  "exifInfo"."autoStackId" AS "exifInfo_autoStackId",
 | 
			
		||||
  "exifInfo"."state" AS "exifInfo_state",
 | 
			
		||||
  "exifInfo"."country" AS "exifInfo_country",
 | 
			
		||||
  "exifInfo"."make" AS "exifInfo_make",
 | 
			
		||||
  "exifInfo"."model" AS "exifInfo_model",
 | 
			
		||||
  "exifInfo"."lensModel" AS "exifInfo_lensModel",
 | 
			
		||||
  "exifInfo"."fNumber" AS "exifInfo_fNumber",
 | 
			
		||||
  "exifInfo"."focalLength" AS "exifInfo_focalLength",
 | 
			
		||||
  "exifInfo"."iso" AS "exifInfo_iso",
 | 
			
		||||
  "exifInfo"."exposureTime" AS "exifInfo_exposureTime",
 | 
			
		||||
  "exifInfo"."profileDescription" AS "exifInfo_profileDescription",
 | 
			
		||||
  "exifInfo"."colorspace" AS "exifInfo_colorspace",
 | 
			
		||||
  "exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
 | 
			
		||||
  "exifInfo"."fps" AS "exifInfo_fps",
 | 
			
		||||
  "stack"."id" AS "stack_id",
 | 
			
		||||
  "stack"."primaryAssetId" AS "stack_primaryAssetId",
 | 
			
		||||
  "stackedAssets"."id" AS "stackedAssets_id",
 | 
			
		||||
  "stackedAssets"."deviceAssetId" AS "stackedAssets_deviceAssetId",
 | 
			
		||||
  "stackedAssets"."ownerId" AS "stackedAssets_ownerId",
 | 
			
		||||
  "stackedAssets"."libraryId" AS "stackedAssets_libraryId",
 | 
			
		||||
  "stackedAssets"."deviceId" AS "stackedAssets_deviceId",
 | 
			
		||||
  "stackedAssets"."type" AS "stackedAssets_type",
 | 
			
		||||
  "stackedAssets"."originalPath" AS "stackedAssets_originalPath",
 | 
			
		||||
  "stackedAssets"."previewPath" AS "stackedAssets_previewPath",
 | 
			
		||||
  "stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
 | 
			
		||||
  "stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
 | 
			
		||||
  "stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
 | 
			
		||||
  "stackedAssets"."createdAt" AS "stackedAssets_createdAt",
 | 
			
		||||
  "stackedAssets"."updatedAt" AS "stackedAssets_updatedAt",
 | 
			
		||||
  "stackedAssets"."deletedAt" AS "stackedAssets_deletedAt",
 | 
			
		||||
  "stackedAssets"."fileCreatedAt" AS "stackedAssets_fileCreatedAt",
 | 
			
		||||
  "stackedAssets"."localDateTime" AS "stackedAssets_localDateTime",
 | 
			
		||||
  "stackedAssets"."fileModifiedAt" AS "stackedAssets_fileModifiedAt",
 | 
			
		||||
  "stackedAssets"."isFavorite" AS "stackedAssets_isFavorite",
 | 
			
		||||
  "stackedAssets"."isArchived" AS "stackedAssets_isArchived",
 | 
			
		||||
  "stackedAssets"."isExternal" AS "stackedAssets_isExternal",
 | 
			
		||||
  "stackedAssets"."isReadOnly" AS "stackedAssets_isReadOnly",
 | 
			
		||||
  "stackedAssets"."isOffline" AS "stackedAssets_isOffline",
 | 
			
		||||
  "stackedAssets"."checksum" AS "stackedAssets_checksum",
 | 
			
		||||
  "stackedAssets"."duration" AS "stackedAssets_duration",
 | 
			
		||||
  "stackedAssets"."isVisible" AS "stackedAssets_isVisible",
 | 
			
		||||
  "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId",
 | 
			
		||||
  "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName",
 | 
			
		||||
  "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath",
 | 
			
		||||
  "stackedAssets"."stackId" AS "stackedAssets_stackId"
 | 
			
		||||
FROM
 | 
			
		||||
  "assets" "AssetEntity"
 | 
			
		||||
  LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id"
 | 
			
		||||
  LEFT JOIN "asset_stack" "AssetEntity__AssetEntity_stack" ON "AssetEntity__AssetEntity_stack"."id" = "AssetEntity"."stackId"
 | 
			
		||||
  "assets" "asset"
 | 
			
		||||
  LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
 | 
			
		||||
  LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
 | 
			
		||||
  LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
 | 
			
		||||
  AND ("stackedAssets"."deletedAt" IS NULL)
 | 
			
		||||
WHERE
 | 
			
		||||
  (
 | 
			
		||||
    ("AssetEntity"."ownerId" IN ($1))
 | 
			
		||||
    AND ("AssetEntity"."isVisible" = $2)
 | 
			
		||||
    AND ("AssetEntity"."updatedAt" > $3)
 | 
			
		||||
  "asset"."isVisible" = true
 | 
			
		||||
  AND "asset"."ownerId" IN ($1)
 | 
			
		||||
  AND (
 | 
			
		||||
    "stack"."primaryAssetId" = "asset"."id"
 | 
			
		||||
    OR "asset"."stackId" IS NULL
 | 
			
		||||
  )
 | 
			
		||||
  AND "asset"."updatedAt" > $2
 | 
			
		||||
 | 
			
		||||
@ -710,21 +710,23 @@ export class AssetRepository implements IAssetRepository {
 | 
			
		||||
    ],
 | 
			
		||||
  })
 | 
			
		||||
  getAllForUserFullSync(options: AssetFullSyncOptions): Promise<AssetEntity[]> {
 | 
			
		||||
    const { ownerId, lastCreationDate, lastId, updatedUntil, limit } = options;
 | 
			
		||||
    const builder = this.repository
 | 
			
		||||
      .createQueryBuilder('asset')
 | 
			
		||||
      .leftJoinAndSelect('asset.exifInfo', 'exifInfo')
 | 
			
		||||
      .leftJoinAndSelect('asset.stack', 'stack')
 | 
			
		||||
      .where('asset.ownerId = :ownerId', { ownerId });
 | 
			
		||||
    const { ownerId, isArchived, withStacked, lastCreationDate, lastId, updatedUntil, limit } = options;
 | 
			
		||||
    const builder = this.getBuilder({
 | 
			
		||||
      userIds: [ownerId],
 | 
			
		||||
      exifInfo: true,
 | 
			
		||||
      withStacked,
 | 
			
		||||
      isArchived,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (lastCreationDate !== undefined && lastId !== undefined) {
 | 
			
		||||
      builder.andWhere('(asset.fileCreatedAt, asset.id) < (:lastCreationDate, :lastId)', {
 | 
			
		||||
        lastCreationDate,
 | 
			
		||||
        lastId,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return builder
 | 
			
		||||
      .andWhere('asset.updatedAt <= :updatedUntil', { updatedUntil })
 | 
			
		||||
      .andWhere('asset.isVisible = true')
 | 
			
		||||
      .orderBy('asset.fileCreatedAt', 'DESC')
 | 
			
		||||
      .addOrderBy('asset.id', 'DESC')
 | 
			
		||||
      .limit(limit)
 | 
			
		||||
@ -734,18 +736,11 @@ export class AssetRepository implements IAssetRepository {
 | 
			
		||||
 | 
			
		||||
  @GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE }] })
 | 
			
		||||
  getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]> {
 | 
			
		||||
    return this.repository.find({
 | 
			
		||||
      where: {
 | 
			
		||||
        ownerId: In(options.userIds),
 | 
			
		||||
        isVisible: true,
 | 
			
		||||
        updatedAt: MoreThan(options.updatedAfter),
 | 
			
		||||
      },
 | 
			
		||||
      relations: {
 | 
			
		||||
        exifInfo: true,
 | 
			
		||||
        stack: true,
 | 
			
		||||
      },
 | 
			
		||||
      take: options.limit,
 | 
			
		||||
      withDeleted: true,
 | 
			
		||||
    });
 | 
			
		||||
    const builder = this.getBuilder({ userIds: options.userIds, exifInfo: true, withStacked: true })
 | 
			
		||||
      .andWhere({ updatedAt: MoreThan(options.updatedAfter) })
 | 
			
		||||
      .take(options.limit)
 | 
			
		||||
      .withDeleted();
 | 
			
		||||
 | 
			
		||||
    return builder.getMany();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,13 +39,12 @@ describe(SyncService.name, () => {
 | 
			
		||||
  describe('getAllAssetsForUserFullSync', () => {
 | 
			
		||||
    it('should return a list of all assets owned by the user', async () => {
 | 
			
		||||
      assetMock.getAllForUserFullSync.mockResolvedValue([assetStub.external, assetStub.hasEncodedVideo]);
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.getAllAssetsForUserFullSync(authStub.user1, { limit: 2, updatedUntil: untilDate }),
 | 
			
		||||
      ).resolves.toEqual([
 | 
			
		||||
      await expect(sut.getFullSync(authStub.user1, { limit: 2, updatedUntil: untilDate })).resolves.toEqual([
 | 
			
		||||
        mapAsset(assetStub.external, mapAssetOpts),
 | 
			
		||||
        mapAsset(assetStub.hasEncodedVideo, mapAssetOpts),
 | 
			
		||||
      ]);
 | 
			
		||||
      expect(assetMock.getAllForUserFullSync).toHaveBeenCalledWith({
 | 
			
		||||
        withStacked: true,
 | 
			
		||||
        ownerId: authStub.user1.user.id,
 | 
			
		||||
        updatedUntil: untilDate,
 | 
			
		||||
        limit: 2,
 | 
			
		||||
@ -57,7 +56,7 @@ describe(SyncService.name, () => {
 | 
			
		||||
    it('should return a response requiring a full sync when partners are out of sync', async () => {
 | 
			
		||||
      partnerMock.getAll.mockResolvedValue([partnerStub.adminToUser1]);
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.getChangesForDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
        sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
      ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
 | 
			
		||||
      expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
 | 
			
		||||
      expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
 | 
			
		||||
@ -66,7 +65,7 @@ describe(SyncService.name, () => {
 | 
			
		||||
    it('should return a response requiring a full sync when last sync was too long ago', async () => {
 | 
			
		||||
      partnerMock.getAll.mockResolvedValue([]);
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.getChangesForDeltaSync(authStub.user1, { updatedAfter: new Date(2000), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
        sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(2000), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
      ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
 | 
			
		||||
      expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
 | 
			
		||||
      expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
 | 
			
		||||
@ -78,7 +77,7 @@ describe(SyncService.name, () => {
 | 
			
		||||
        Array.from<AssetEntity>({ length: 10_000 }).fill(assetStub.image),
 | 
			
		||||
      );
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.getChangesForDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
        sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
      ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
 | 
			
		||||
      expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(1);
 | 
			
		||||
      expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
 | 
			
		||||
@ -89,7 +88,7 @@ describe(SyncService.name, () => {
 | 
			
		||||
      assetMock.getChangedDeltaSync.mockResolvedValue([assetStub.image1]);
 | 
			
		||||
      auditMock.getAfter.mockResolvedValue([assetStub.external.id]);
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.getChangesForDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
        sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }),
 | 
			
		||||
      ).resolves.toEqual({
 | 
			
		||||
        needsFullSync: false,
 | 
			
		||||
        upserted: [mapAsset(assetStub.image1, mapAssetOpts)],
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { Inject } from '@nestjs/common';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
import { DateTime } from 'luxon';
 | 
			
		||||
import { AUDIT_LOG_MAX_DURATION } from 'src/constants';
 | 
			
		||||
import { AccessCore, Permission } from 'src/cores/access.core';
 | 
			
		||||
@ -11,6 +10,9 @@ import { IAccessRepository } from 'src/interfaces/access.interface';
 | 
			
		||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
 | 
			
		||||
import { IAuditRepository } from 'src/interfaces/audit.interface';
 | 
			
		||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
 | 
			
		||||
import { setIsEqual } from 'src/utils/set';
 | 
			
		||||
 | 
			
		||||
const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] };
 | 
			
		||||
 | 
			
		||||
export class SyncService {
 | 
			
		||||
  private access: AccessCore;
 | 
			
		||||
@ -24,52 +26,69 @@ export class SyncService {
 | 
			
		||||
    this.access = AccessCore.create(accessRepository);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getAllAssetsForUserFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
 | 
			
		||||
  async getFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
 | 
			
		||||
    // mobile implementation is faster if this is a single id
 | 
			
		||||
    const userId = dto.userId || auth.user.id;
 | 
			
		||||
    await this.access.requirePermission(auth, Permission.TIMELINE_READ, userId);
 | 
			
		||||
    const assets = await this.assetRepository.getAllForUserFullSync({
 | 
			
		||||
      ownerId: userId,
 | 
			
		||||
      // no archived assets for partner user
 | 
			
		||||
      isArchived: userId === auth.user.id ? undefined : false,
 | 
			
		||||
      // no stack for partner user
 | 
			
		||||
      withStacked: userId === auth.user.id ? true : undefined,
 | 
			
		||||
      lastCreationDate: dto.lastCreationDate,
 | 
			
		||||
      updatedUntil: dto.updatedUntil,
 | 
			
		||||
      lastId: dto.lastId,
 | 
			
		||||
      limit: dto.limit,
 | 
			
		||||
    });
 | 
			
		||||
    const options = { auth, stripMetadata: false, withStack: true };
 | 
			
		||||
    return assets.map((a) => mapAsset(a, options));
 | 
			
		||||
    return assets.map((a) => mapAsset(a, { auth, stripMetadata: false, withStack: true }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getChangesForDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
 | 
			
		||||
    await this.access.requirePermission(auth, Permission.TIMELINE_READ, dto.userIds);
 | 
			
		||||
    const partner = await this.partnerRepository.getAll(auth.user.id);
 | 
			
		||||
    const userIds = [auth.user.id, ...partner.filter((p) => p.sharedWithId == auth.user.id).map((p) => p.sharedById)];
 | 
			
		||||
    userIds.sort();
 | 
			
		||||
    dto.userIds.sort();
 | 
			
		||||
  async getDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
 | 
			
		||||
    // app has not synced in the last 100 days
 | 
			
		||||
    const duration = DateTime.now().diff(DateTime.fromJSDate(dto.updatedAfter));
 | 
			
		||||
 | 
			
		||||
    if (!_.isEqual(userIds, dto.userIds) || duration > AUDIT_LOG_MAX_DURATION) {
 | 
			
		||||
      // app does not have the correct partners synced
 | 
			
		||||
      // or app has not synced in the last 100 days
 | 
			
		||||
      return { needsFullSync: true, deleted: [], upserted: [] };
 | 
			
		||||
    if (duration > AUDIT_LOG_MAX_DURATION) {
 | 
			
		||||
      return FULL_SYNC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const authUserId = auth.user.id;
 | 
			
		||||
 | 
			
		||||
    // app does not have the correct partners synced
 | 
			
		||||
    const partner = await this.partnerRepository.getAll(authUserId);
 | 
			
		||||
    const userIds = [authUserId, ...partner.filter((p) => p.sharedWithId == auth.user.id).map((p) => p.sharedById)];
 | 
			
		||||
    if (!setIsEqual(new Set(userIds), new Set(dto.userIds))) {
 | 
			
		||||
      return FULL_SYNC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await this.access.requirePermission(auth, Permission.TIMELINE_READ, dto.userIds);
 | 
			
		||||
 | 
			
		||||
    const limit = 10_000;
 | 
			
		||||
    const upserted = await this.assetRepository.getChangedDeltaSync({ limit, updatedAfter: dto.updatedAfter, userIds });
 | 
			
		||||
 | 
			
		||||
    // too many changes, need to do a full sync
 | 
			
		||||
    if (upserted.length === limit) {
 | 
			
		||||
      // too many changes -> do a full sync (paginated) instead
 | 
			
		||||
      return { needsFullSync: true, deleted: [], upserted: [] };
 | 
			
		||||
      return FULL_SYNC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const deleted = await this.auditRepository.getAfter(dto.updatedAfter, {
 | 
			
		||||
      userIds: userIds,
 | 
			
		||||
      userIds,
 | 
			
		||||
      entityType: EntityType.ASSET,
 | 
			
		||||
      action: DatabaseAction.DELETE,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const options = { auth, stripMetadata: false, withStack: true };
 | 
			
		||||
    const result = {
 | 
			
		||||
      needsFullSync: false,
 | 
			
		||||
      upserted: upserted.map((a) => mapAsset(a, options)),
 | 
			
		||||
      upserted: upserted
 | 
			
		||||
        // do not return archived assets for partner users
 | 
			
		||||
        .filter((a) => a.ownerId === auth.user.id || (a.ownerId !== auth.user.id && !a.isArchived))
 | 
			
		||||
        .map((a) =>
 | 
			
		||||
          mapAsset(a, {
 | 
			
		||||
            auth,
 | 
			
		||||
            stripMetadata: false,
 | 
			
		||||
            // ignore stacks for non partner users
 | 
			
		||||
            withStack: a.ownerId === authUserId,
 | 
			
		||||
          }),
 | 
			
		||||
        ),
 | 
			
		||||
      deleted,
 | 
			
		||||
    };
 | 
			
		||||
    return result;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user