mirror of
https://github.com/immich-app/immich.git
synced 2025-03-01 15:11:21 +01: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
22 changed files with 817 additions and 386 deletions
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/AssetBulkUploadCheckItem.md
|
||||||
doc/AssetBulkUploadCheckResponseDto.md
|
doc/AssetBulkUploadCheckResponseDto.md
|
||||||
doc/AssetBulkUploadCheckResult.md
|
doc/AssetBulkUploadCheckResult.md
|
||||||
|
doc/AssetDeltaSyncDto.md
|
||||||
doc/AssetDeltaSyncResponseDto.md
|
doc/AssetDeltaSyncResponseDto.md
|
||||||
doc/AssetFaceResponseDto.md
|
doc/AssetFaceResponseDto.md
|
||||||
doc/AssetFaceUpdateDto.md
|
doc/AssetFaceUpdateDto.md
|
||||||
doc/AssetFaceUpdateItem.md
|
doc/AssetFaceUpdateItem.md
|
||||||
doc/AssetFaceWithoutPersonResponseDto.md
|
doc/AssetFaceWithoutPersonResponseDto.md
|
||||||
doc/AssetFileUploadResponseDto.md
|
doc/AssetFileUploadResponseDto.md
|
||||||
|
doc/AssetFullSyncDto.md
|
||||||
doc/AssetIdsDto.md
|
doc/AssetIdsDto.md
|
||||||
doc/AssetIdsResponseDto.md
|
doc/AssetIdsResponseDto.md
|
||||||
doc/AssetJobName.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_item.dart
|
||||||
lib/model/asset_bulk_upload_check_response_dto.dart
|
lib/model/asset_bulk_upload_check_response_dto.dart
|
||||||
lib/model/asset_bulk_upload_check_result.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_delta_sync_response_dto.dart
|
||||||
lib/model/asset_face_response_dto.dart
|
lib/model/asset_face_response_dto.dart
|
||||||
lib/model/asset_face_update_dto.dart
|
lib/model/asset_face_update_dto.dart
|
||||||
lib/model/asset_face_update_item.dart
|
lib/model/asset_face_update_item.dart
|
||||||
lib/model/asset_face_without_person_response_dto.dart
|
lib/model/asset_face_without_person_response_dto.dart
|
||||||
lib/model/asset_file_upload_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_dto.dart
|
||||||
lib/model/asset_ids_response_dto.dart
|
lib/model/asset_ids_response_dto.dart
|
||||||
lib/model/asset_job_name.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_item_test.dart
|
||||||
test/asset_bulk_upload_check_response_dto_test.dart
|
test/asset_bulk_upload_check_response_dto_test.dart
|
||||||
test/asset_bulk_upload_check_result_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_delta_sync_response_dto_test.dart
|
||||||
test/asset_face_response_dto_test.dart
|
test/asset_face_response_dto_test.dart
|
||||||
test/asset_face_update_dto_test.dart
|
test/asset_face_update_dto_test.dart
|
||||||
test/asset_face_update_item_test.dart
|
test/asset_face_update_item_test.dart
|
||||||
test/asset_face_without_person_response_dto_test.dart
|
test/asset_face_without_person_response_dto_test.dart
|
||||||
test/asset_file_upload_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_dto_test.dart
|
||||||
test/asset_ids_response_dto_test.dart
|
test/asset_ids_response_dto_test.dart
|
||||||
test/asset_job_name_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* | [**removeSharedLink**](doc//SharedLinkApi.md#removesharedlink) | **DELETE** /shared-link/{id} |
|
||||||
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets |
|
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets |
|
||||||
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} |
|
*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) | **POST** /sync/delta-sync |
|
||||||
*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **GET** /sync/delta-sync |
|
*SyncApi* | [**getFullSyncForUser**](doc//SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync |
|
||||||
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
|
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
|
||||||
*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
|
*SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
|
||||||
*SystemConfigApi* | [**getMapStyle**](doc//SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json |
|
*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)
|
- [AssetBulkUploadCheckItem](doc//AssetBulkUploadCheckItem.md)
|
||||||
- [AssetBulkUploadCheckResponseDto](doc//AssetBulkUploadCheckResponseDto.md)
|
- [AssetBulkUploadCheckResponseDto](doc//AssetBulkUploadCheckResponseDto.md)
|
||||||
- [AssetBulkUploadCheckResult](doc//AssetBulkUploadCheckResult.md)
|
- [AssetBulkUploadCheckResult](doc//AssetBulkUploadCheckResult.md)
|
||||||
|
- [AssetDeltaSyncDto](doc//AssetDeltaSyncDto.md)
|
||||||
- [AssetDeltaSyncResponseDto](doc//AssetDeltaSyncResponseDto.md)
|
- [AssetDeltaSyncResponseDto](doc//AssetDeltaSyncResponseDto.md)
|
||||||
- [AssetFaceResponseDto](doc//AssetFaceResponseDto.md)
|
- [AssetFaceResponseDto](doc//AssetFaceResponseDto.md)
|
||||||
- [AssetFaceUpdateDto](doc//AssetFaceUpdateDto.md)
|
- [AssetFaceUpdateDto](doc//AssetFaceUpdateDto.md)
|
||||||
- [AssetFaceUpdateItem](doc//AssetFaceUpdateItem.md)
|
- [AssetFaceUpdateItem](doc//AssetFaceUpdateItem.md)
|
||||||
- [AssetFaceWithoutPersonResponseDto](doc//AssetFaceWithoutPersonResponseDto.md)
|
- [AssetFaceWithoutPersonResponseDto](doc//AssetFaceWithoutPersonResponseDto.md)
|
||||||
- [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md)
|
- [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md)
|
||||||
|
- [AssetFullSyncDto](doc//AssetFullSyncDto.md)
|
||||||
- [AssetIdsDto](doc//AssetIdsDto.md)
|
- [AssetIdsDto](doc//AssetIdsDto.md)
|
||||||
- [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
|
- [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
|
||||||
- [AssetJobName](doc//AssetJobName.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
|
Method | HTTP request | Description
|
||||||
------------- | ------------- | -------------
|
------------- | ------------- | -------------
|
||||||
[**getAllForUserFullSync**](SyncApi.md#getallforuserfullsync) | **GET** /sync/full-sync |
|
[**getDeltaSync**](SyncApi.md#getdeltasync) | **POST** /sync/delta-sync |
|
||||||
[**getDeltaSync**](SyncApi.md#getdeltasync) | **GET** /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**
|
# **getDeltaSync**
|
||||||
> AssetDeltaSyncResponseDto getDeltaSync(updatedAfter, userIds)
|
> AssetDeltaSyncResponseDto getDeltaSync(assetDeltaSyncDto)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,11 +37,10 @@ import 'package:openapi/api.dart';
|
||||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
||||||
|
|
||||||
final api_instance = SyncApi();
|
final api_instance = SyncApi();
|
||||||
final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
|
final assetDeltaSyncDto = AssetDeltaSyncDto(); // AssetDeltaSyncDto |
|
||||||
final userIds = []; // List<String> |
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final result = api_instance.getDeltaSync(updatedAfter, userIds);
|
final result = api_instance.getDeltaSync(assetDeltaSyncDto);
|
||||||
print(result);
|
print(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Exception when calling SyncApi->getDeltaSync: $e\n');
|
print('Exception when calling SyncApi->getDeltaSync: $e\n');
|
||||||
|
@ -115,8 +51,7 @@ try {
|
||||||
|
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------- | ------------- | ------------- | -------------
|
------------- | ------------- | ------------- | -------------
|
||||||
**updatedAfter** | **DateTime**| |
|
**assetDeltaSyncDto** | [**AssetDeltaSyncDto**](AssetDeltaSyncDto.md)| |
|
||||||
**userIds** | [**List<String>**](String.md)| | [default to const []]
|
|
||||||
|
|
||||||
### Return type
|
### Return type
|
||||||
|
|
||||||
|
@ -128,7 +63,62 @@ Name | Type | Description | Notes
|
||||||
|
|
||||||
### HTTP request headers
|
### 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
|
- **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)
|
[[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_item.dart';
|
||||||
part 'model/asset_bulk_upload_check_response_dto.dart';
|
part 'model/asset_bulk_upload_check_response_dto.dart';
|
||||||
part 'model/asset_bulk_upload_check_result.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_delta_sync_response_dto.dart';
|
||||||
part 'model/asset_face_response_dto.dart';
|
part 'model/asset_face_response_dto.dart';
|
||||||
part 'model/asset_face_update_dto.dart';
|
part 'model/asset_face_update_dto.dart';
|
||||||
part 'model/asset_face_update_item.dart';
|
part 'model/asset_face_update_item.dart';
|
||||||
part 'model/asset_face_without_person_response_dto.dart';
|
part 'model/asset_face_without_person_response_dto.dart';
|
||||||
part 'model/asset_file_upload_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_dto.dart';
|
||||||
part 'model/asset_ids_response_dto.dart';
|
part 'model/asset_ids_response_dto.dart';
|
||||||
part 'model/asset_job_name.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;
|
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:
|
/// Parameters:
|
||||||
///
|
///
|
||||||
/// * [int] limit (required):
|
/// * [AssetDeltaSyncDto] assetDeltaSyncDto (required):
|
||||||
///
|
Future<Response> getDeltaSyncWithHttpInfo(AssetDeltaSyncDto assetDeltaSyncDto,) async {
|
||||||
/// * [DateTime] updatedUntil (required):
|
|
||||||
///
|
|
||||||
/// * [DateTime] lastCreationDate:
|
|
||||||
///
|
|
||||||
/// * [String] lastId:
|
|
||||||
///
|
|
||||||
/// * [String] userId:
|
|
||||||
Future<Response> getAllForUserFullSyncWithHttpInfo(int limit, DateTime updatedUntil, { DateTime? lastCreationDate, String? lastId, String? userId, }) async {
|
|
||||||
// ignore: prefer_const_declarations
|
// ignore: prefer_const_declarations
|
||||||
final path = r'/sync/full-sync';
|
final path = r'/sync/delta-sync';
|
||||||
|
|
||||||
// ignore: prefer_final_locals
|
// ignore: prefer_final_locals
|
||||||
Object? postBody;
|
Object? postBody = assetDeltaSyncDto;
|
||||||
|
|
||||||
final queryParams = <QueryParam>[];
|
final queryParams = <QueryParam>[];
|
||||||
final headerParams = <String, String>{};
|
final headerParams = <String, String>{};
|
||||||
final formParams = <String, String>{};
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
if (lastCreationDate != null) {
|
const contentTypes = <String>['application/json'];
|
||||||
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>[];
|
|
||||||
|
|
||||||
|
|
||||||
return apiClient.invokeAPI(
|
return apiClient.invokeAPI(
|
||||||
path,
|
path,
|
||||||
'GET',
|
'POST',
|
||||||
queryParams,
|
queryParams,
|
||||||
postBody,
|
postBody,
|
||||||
headerParams,
|
headerParams,
|
||||||
|
@ -67,17 +47,56 @@ class SyncApi {
|
||||||
|
|
||||||
/// Parameters:
|
/// 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:
|
/// * [AssetFullSyncDto] assetFullSyncDto (required):
|
||||||
///
|
Future<List<AssetResponseDto>?> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto,) async {
|
||||||
/// * [String] lastId:
|
final response = await getFullSyncForUserWithHttpInfo(assetFullSyncDto,);
|
||||||
///
|
|
||||||
/// * [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, );
|
|
||||||
if (response.statusCode >= HttpStatus.badRequest) {
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
}
|
}
|
||||||
|
@ -93,58 +112,4 @@ class SyncApi {
|
||||||
}
|
}
|
||||||
return null;
|
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);
|
return AssetBulkUploadCheckResponseDto.fromJson(value);
|
||||||
case 'AssetBulkUploadCheckResult':
|
case 'AssetBulkUploadCheckResult':
|
||||||
return AssetBulkUploadCheckResult.fromJson(value);
|
return AssetBulkUploadCheckResult.fromJson(value);
|
||||||
|
case 'AssetDeltaSyncDto':
|
||||||
|
return AssetDeltaSyncDto.fromJson(value);
|
||||||
case 'AssetDeltaSyncResponseDto':
|
case 'AssetDeltaSyncResponseDto':
|
||||||
return AssetDeltaSyncResponseDto.fromJson(value);
|
return AssetDeltaSyncResponseDto.fromJson(value);
|
||||||
case 'AssetFaceResponseDto':
|
case 'AssetFaceResponseDto':
|
||||||
|
@ -236,6 +238,8 @@ class ApiClient {
|
||||||
return AssetFaceWithoutPersonResponseDto.fromJson(value);
|
return AssetFaceWithoutPersonResponseDto.fromJson(value);
|
||||||
case 'AssetFileUploadResponseDto':
|
case 'AssetFileUploadResponseDto':
|
||||||
return AssetFileUploadResponseDto.fromJson(value);
|
return AssetFileUploadResponseDto.fromJson(value);
|
||||||
|
case 'AssetFullSyncDto':
|
||||||
|
return AssetFullSyncDto.fromJson(value);
|
||||||
case 'AssetIdsDto':
|
case 'AssetIdsDto':
|
||||||
return AssetIdsDto.fromJson(value);
|
return AssetIdsDto.fromJson(value);
|
||||||
case 'AssetIdsResponseDto':
|
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();
|
// final instance = SyncApi();
|
||||||
|
|
||||||
group('tests for SyncApi', () {
|
group('tests for SyncApi', () {
|
||||||
//Future<List<AssetResponseDto>> getAllForUserFullSync(int limit, DateTime updatedUntil, { DateTime lastCreationDate, String lastId, String userId }) async
|
//Future<AssetDeltaSyncResponseDto> getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto) async
|
||||||
test('test getAllForUserFullSync', () async {
|
test('test getDeltaSync', () async {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
//Future<AssetDeltaSyncResponseDto> getDeltaSync(DateTime updatedAfter, List<String> userIds) async
|
//Future<List<AssetResponseDto>> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto) async
|
||||||
test('test getDeltaSync', () async {
|
test('test getFullSyncForUser', () async {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4958,31 +4958,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/sync/delta-sync": {
|
"/sync/delta-sync": {
|
||||||
"get": {
|
"post": {
|
||||||
"operationId": "getDeltaSync",
|
"operationId": "getDeltaSync",
|
||||||
"parameters": [
|
"parameters": [],
|
||||||
{
|
"requestBody": {
|
||||||
"name": "updatedAfter",
|
"content": {
|
||||||
"required": true,
|
"application/json": {
|
||||||
"in": "query",
|
"schema": {
|
||||||
"schema": {
|
"$ref": "#/components/schemas/AssetDeltaSyncDto"
|
||||||
"format": "date-time",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userIds",
|
|
||||||
"required": true,
|
|
||||||
"in": "query",
|
|
||||||
"schema": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
"required": true
|
||||||
|
},
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"content": {
|
"content": {
|
||||||
|
@ -5012,55 +5000,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/sync/full-sync": {
|
"/sync/full-sync": {
|
||||||
"get": {
|
"post": {
|
||||||
"operationId": "getAllForUserFullSync",
|
"operationId": "getFullSyncForUser",
|
||||||
"parameters": [
|
"parameters": [],
|
||||||
{
|
"requestBody": {
|
||||||
"name": "lastCreationDate",
|
"content": {
|
||||||
"required": false,
|
"application/json": {
|
||||||
"in": "query",
|
"schema": {
|
||||||
"schema": {
|
"$ref": "#/components/schemas/AssetFullSyncDto"
|
||||||
"format": "date-time",
|
}
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"required": true
|
||||||
"name": "lastId",
|
},
|
||||||
"required": false,
|
|
||||||
"in": "query",
|
|
||||||
"schema": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"content": {
|
"content": {
|
||||||
|
@ -7023,6 +6975,26 @@
|
||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"AssetDeltaSyncDto": {
|
||||||
|
"properties": {
|
||||||
|
"updatedAfter": {
|
||||||
|
"format": "date-time",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userIds": {
|
||||||
|
"items": {
|
||||||
|
"format": "uuid",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"updatedAfter",
|
||||||
|
"userIds"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"AssetDeltaSyncResponseDto": {
|
"AssetDeltaSyncResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
|
@ -7175,6 +7147,35 @@
|
||||||
],
|
],
|
||||||
"type": "object"
|
"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": {
|
"AssetIdsDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"assetIds": {
|
"assetIds": {
|
||||||
|
|
|
@ -836,11 +836,22 @@ export type AssetIdsResponseDto = {
|
||||||
error?: Error2;
|
error?: Error2;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
};
|
};
|
||||||
|
export type AssetDeltaSyncDto = {
|
||||||
|
updatedAfter: string;
|
||||||
|
userIds: string[];
|
||||||
|
};
|
||||||
export type AssetDeltaSyncResponseDto = {
|
export type AssetDeltaSyncResponseDto = {
|
||||||
deleted: string[];
|
deleted: string[];
|
||||||
needsFullSync: boolean;
|
needsFullSync: boolean;
|
||||||
upserted: AssetResponseDto[];
|
upserted: AssetResponseDto[];
|
||||||
};
|
};
|
||||||
|
export type AssetFullSyncDto = {
|
||||||
|
lastCreationDate?: string;
|
||||||
|
lastId?: string;
|
||||||
|
limit: number;
|
||||||
|
updatedUntil: string;
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
export type SystemConfigFFmpegDto = {
|
export type SystemConfigFFmpegDto = {
|
||||||
accel: TranscodeHWAccel;
|
accel: TranscodeHWAccel;
|
||||||
acceptedAudioCodecs: AudioCodec[];
|
acceptedAudioCodecs: AudioCodec[];
|
||||||
|
@ -2372,39 +2383,29 @@ export function addSharedLinkAssets({ id, key, assetIdsDto }: {
|
||||||
body: assetIdsDto
|
body: assetIdsDto
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
export function getDeltaSync({ updatedAfter, userIds }: {
|
export function getDeltaSync({ assetDeltaSyncDto }: {
|
||||||
updatedAfter: string;
|
assetDeltaSyncDto: AssetDeltaSyncDto;
|
||||||
userIds: string[];
|
|
||||||
}, opts?: Oazapfts.RequestOpts) {
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
return oazapfts.ok(oazapfts.fetchJson<{
|
return oazapfts.ok(oazapfts.fetchJson<{
|
||||||
status: 200;
|
status: 200;
|
||||||
data: AssetDeltaSyncResponseDto;
|
data: AssetDeltaSyncResponseDto;
|
||||||
}>(`/sync/delta-sync${QS.query(QS.explode({
|
}>("/sync/delta-sync", oazapfts.json({
|
||||||
updatedAfter,
|
...opts,
|
||||||
userIds
|
method: "POST",
|
||||||
}))}`, {
|
body: assetDeltaSyncDto
|
||||||
...opts
|
})));
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
export function getAllForUserFullSync({ lastCreationDate, lastId, limit, updatedUntil, userId }: {
|
export function getFullSyncForUser({ assetFullSyncDto }: {
|
||||||
lastCreationDate?: string;
|
assetFullSyncDto: AssetFullSyncDto;
|
||||||
lastId?: string;
|
|
||||||
limit: number;
|
|
||||||
updatedUntil: string;
|
|
||||||
userId?: string;
|
|
||||||
}, opts?: Oazapfts.RequestOpts) {
|
}, opts?: Oazapfts.RequestOpts) {
|
||||||
return oazapfts.ok(oazapfts.fetchJson<{
|
return oazapfts.ok(oazapfts.fetchJson<{
|
||||||
status: 200;
|
status: 200;
|
||||||
data: AssetResponseDto[];
|
data: AssetResponseDto[];
|
||||||
}>(`/sync/full-sync${QS.query(QS.explode({
|
}>("/sync/full-sync", oazapfts.json({
|
||||||
lastCreationDate,
|
...opts,
|
||||||
lastId,
|
method: "POST",
|
||||||
limit,
|
body: assetFullSyncDto
|
||||||
updatedUntil,
|
})));
|
||||||
userId
|
|
||||||
}))}`, {
|
|
||||||
...opts
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
export function getConfig(opts?: Oazapfts.RequestOpts) {
|
export function getConfig(opts?: Oazapfts.RequestOpts) {
|
||||||
return oazapfts.ok(oazapfts.fetchJson<{
|
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 { ApiTags } from '@nestjs/swagger';
|
||||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
|
@ -12,13 +12,15 @@ import { SyncService } from 'src/services/sync.service';
|
||||||
export class SyncController {
|
export class SyncController {
|
||||||
constructor(private service: SyncService) {}
|
constructor(private service: SyncService) {}
|
||||||
|
|
||||||
@Get('full-sync')
|
@Post('full-sync')
|
||||||
getAllForUserFullSync(@Auth() auth: AuthDto, @Query() dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
|
@HttpCode(HttpStatus.OK)
|
||||||
return this.service.getAllAssetsForUserFullSync(auth, dto);
|
getFullSyncForUser(@Auth() auth: AuthDto, @Body() dto: AssetFullSyncDto): Promise<AssetResponseDto[]> {
|
||||||
|
return this.service.getFullSync(auth, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('delta-sync')
|
@Post('delta-sync')
|
||||||
getDeltaSync(@Auth() auth: AuthDto, @Query() dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
|
@HttpCode(HttpStatus.OK)
|
||||||
return this.service.getChangesForDeltaSync(auth, dto);
|
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 { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { IsInt, IsPositive } from 'class-validator';
|
import { IsInt, IsPositive } from 'class-validator';
|
||||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||||
import { ValidateDate, ValidateUUID } from 'src/validation';
|
import { ValidateDate, ValidateUUID } from 'src/validation';
|
||||||
|
@ -16,7 +15,6 @@ export class AssetFullSyncDto {
|
||||||
|
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@IsPositive()
|
@IsPositive()
|
||||||
@Type(() => Number)
|
|
||||||
@ApiProperty({ type: 'integer' })
|
@ApiProperty({ type: 'integer' })
|
||||||
limit!: number;
|
limit!: number;
|
||||||
|
|
||||||
|
@ -27,6 +25,7 @@ export class AssetFullSyncDto {
|
||||||
export class AssetDeltaSyncDto {
|
export class AssetDeltaSyncDto {
|
||||||
@ValidateDate()
|
@ValidateDate()
|
||||||
updatedAfter!: Date;
|
updatedAfter!: Date;
|
||||||
|
|
||||||
@ValidateUUID({ each: true })
|
@ValidateUUID({ each: true })
|
||||||
userIds!: string[];
|
userIds!: string[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,8 @@ export interface AssetFullSyncOptions {
|
||||||
lastCreationDate?: Date;
|
lastCreationDate?: Date;
|
||||||
lastId?: string;
|
lastId?: string;
|
||||||
updatedUntil: Date;
|
updatedUntil: Date;
|
||||||
|
isArchived?: false;
|
||||||
|
withStacked?: true;
|
||||||
limit: number;
|
limit: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -798,16 +798,47 @@ SELECT
|
||||||
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
|
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
|
||||||
"exifInfo"."fps" AS "exifInfo_fps",
|
"exifInfo"."fps" AS "exifInfo_fps",
|
||||||
"stack"."id" AS "stack_id",
|
"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
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
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
|
WHERE
|
||||||
"asset"."ownerId" = $1
|
"asset"."isVisible" = true
|
||||||
|
AND "asset"."ownerId" IN ($1)
|
||||||
AND ("asset"."fileCreatedAt", "asset"."id") < ($2, $3)
|
AND ("asset"."fileCreatedAt", "asset"."id") < ($2, $3)
|
||||||
AND "asset"."updatedAt" <= $4
|
AND "asset"."updatedAt" <= $4
|
||||||
AND "asset"."isVisible" = true
|
|
||||||
ORDER BY
|
ORDER BY
|
||||||
"asset"."fileCreatedAt" DESC,
|
"asset"."fileCreatedAt" DESC,
|
||||||
"asset"."id" DESC
|
"asset"."id" DESC
|
||||||
|
@ -816,72 +847,105 @@ LIMIT
|
||||||
|
|
||||||
-- AssetRepository.getChangedDeltaSync
|
-- AssetRepository.getChangedDeltaSync
|
||||||
SELECT
|
SELECT
|
||||||
"AssetEntity"."id" AS "AssetEntity_id",
|
"asset"."id" AS "asset_id",
|
||||||
"AssetEntity"."deviceAssetId" AS "AssetEntity_deviceAssetId",
|
"asset"."deviceAssetId" AS "asset_deviceAssetId",
|
||||||
"AssetEntity"."ownerId" AS "AssetEntity_ownerId",
|
"asset"."ownerId" AS "asset_ownerId",
|
||||||
"AssetEntity"."libraryId" AS "AssetEntity_libraryId",
|
"asset"."libraryId" AS "asset_libraryId",
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"asset"."type" AS "asset_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
"asset"."previewPath" AS "asset_previewPath",
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
"AssetEntity"."updatedAt" AS "AssetEntity_updatedAt",
|
"asset"."updatedAt" AS "asset_updatedAt",
|
||||||
"AssetEntity"."deletedAt" AS "AssetEntity_deletedAt",
|
"asset"."deletedAt" AS "asset_deletedAt",
|
||||||
"AssetEntity"."fileCreatedAt" AS "AssetEntity_fileCreatedAt",
|
"asset"."fileCreatedAt" AS "asset_fileCreatedAt",
|
||||||
"AssetEntity"."localDateTime" AS "AssetEntity_localDateTime",
|
"asset"."localDateTime" AS "asset_localDateTime",
|
||||||
"AssetEntity"."fileModifiedAt" AS "AssetEntity_fileModifiedAt",
|
"asset"."fileModifiedAt" AS "asset_fileModifiedAt",
|
||||||
"AssetEntity"."isFavorite" AS "AssetEntity_isFavorite",
|
"asset"."isFavorite" AS "asset_isFavorite",
|
||||||
"AssetEntity"."isArchived" AS "AssetEntity_isArchived",
|
"asset"."isArchived" AS "asset_isArchived",
|
||||||
"AssetEntity"."isExternal" AS "AssetEntity_isExternal",
|
"asset"."isExternal" AS "asset_isExternal",
|
||||||
"AssetEntity"."isReadOnly" AS "AssetEntity_isReadOnly",
|
"asset"."isReadOnly" AS "asset_isReadOnly",
|
||||||
"AssetEntity"."isOffline" AS "AssetEntity_isOffline",
|
"asset"."isOffline" AS "asset_isOffline",
|
||||||
"AssetEntity"."checksum" AS "AssetEntity_checksum",
|
"asset"."checksum" AS "asset_checksum",
|
||||||
"AssetEntity"."duration" AS "AssetEntity_duration",
|
"asset"."duration" AS "asset_duration",
|
||||||
"AssetEntity"."isVisible" AS "AssetEntity_isVisible",
|
"asset"."isVisible" AS "asset_isVisible",
|
||||||
"AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId",
|
"asset"."livePhotoVideoId" AS "asset_livePhotoVideoId",
|
||||||
"AssetEntity"."originalFileName" AS "AssetEntity_originalFileName",
|
"asset"."originalFileName" AS "asset_originalFileName",
|
||||||
"AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"AssetEntity"."stackId" AS "AssetEntity_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."assetId" AS "AssetEntity__AssetEntity_exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."description" AS "AssetEntity__AssetEntity_exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."exifImageWidth" AS "AssetEntity__AssetEntity_exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."exifImageHeight" AS "AssetEntity__AssetEntity_exifInfo_exifImageHeight",
|
"exifInfo"."exifImageHeight" AS "exifInfo_exifImageHeight",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."fileSizeInByte" AS "AssetEntity__AssetEntity_exifInfo_fileSizeInByte",
|
"exifInfo"."fileSizeInByte" AS "exifInfo_fileSizeInByte",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."orientation" AS "AssetEntity__AssetEntity_exifInfo_orientation",
|
"exifInfo"."orientation" AS "exifInfo_orientation",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."dateTimeOriginal" AS "AssetEntity__AssetEntity_exifInfo_dateTimeOriginal",
|
"exifInfo"."dateTimeOriginal" AS "exifInfo_dateTimeOriginal",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."modifyDate" AS "AssetEntity__AssetEntity_exifInfo_modifyDate",
|
"exifInfo"."modifyDate" AS "exifInfo_modifyDate",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."timeZone" AS "AssetEntity__AssetEntity_exifInfo_timeZone",
|
"exifInfo"."timeZone" AS "exifInfo_timeZone",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."latitude" AS "AssetEntity__AssetEntity_exifInfo_latitude",
|
"exifInfo"."latitude" AS "exifInfo_latitude",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."longitude" AS "AssetEntity__AssetEntity_exifInfo_longitude",
|
"exifInfo"."longitude" AS "exifInfo_longitude",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."projectionType" AS "AssetEntity__AssetEntity_exifInfo_projectionType",
|
"exifInfo"."projectionType" AS "exifInfo_projectionType",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."city" AS "AssetEntity__AssetEntity_exifInfo_city",
|
"exifInfo"."city" AS "exifInfo_city",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."livePhotoCID" AS "AssetEntity__AssetEntity_exifInfo_livePhotoCID",
|
"exifInfo"."livePhotoCID" AS "exifInfo_livePhotoCID",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."autoStackId" AS "AssetEntity__AssetEntity_exifInfo_autoStackId",
|
"exifInfo"."autoStackId" AS "exifInfo_autoStackId",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."state" AS "AssetEntity__AssetEntity_exifInfo_state",
|
"exifInfo"."state" AS "exifInfo_state",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."country" AS "AssetEntity__AssetEntity_exifInfo_country",
|
"exifInfo"."country" AS "exifInfo_country",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."make" AS "AssetEntity__AssetEntity_exifInfo_make",
|
"exifInfo"."make" AS "exifInfo_make",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."model" AS "AssetEntity__AssetEntity_exifInfo_model",
|
"exifInfo"."model" AS "exifInfo_model",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."lensModel" AS "AssetEntity__AssetEntity_exifInfo_lensModel",
|
"exifInfo"."lensModel" AS "exifInfo_lensModel",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."fNumber" AS "AssetEntity__AssetEntity_exifInfo_fNumber",
|
"exifInfo"."fNumber" AS "exifInfo_fNumber",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."focalLength" AS "AssetEntity__AssetEntity_exifInfo_focalLength",
|
"exifInfo"."focalLength" AS "exifInfo_focalLength",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."iso" AS "AssetEntity__AssetEntity_exifInfo_iso",
|
"exifInfo"."iso" AS "exifInfo_iso",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."exposureTime" AS "AssetEntity__AssetEntity_exifInfo_exposureTime",
|
"exifInfo"."exposureTime" AS "exifInfo_exposureTime",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."profileDescription" AS "AssetEntity__AssetEntity_exifInfo_profileDescription",
|
"exifInfo"."profileDescription" AS "exifInfo_profileDescription",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."colorspace" AS "AssetEntity__AssetEntity_exifInfo_colorspace",
|
"exifInfo"."colorspace" AS "exifInfo_colorspace",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."bitsPerSample" AS "AssetEntity__AssetEntity_exifInfo_bitsPerSample",
|
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
|
||||||
"AssetEntity__AssetEntity_exifInfo"."fps" AS "AssetEntity__AssetEntity_exifInfo_fps",
|
"exifInfo"."fps" AS "exifInfo_fps",
|
||||||
"AssetEntity__AssetEntity_stack"."id" AS "AssetEntity__AssetEntity_stack_id",
|
"stack"."id" AS "stack_id",
|
||||||
"AssetEntity__AssetEntity_stack"."primaryAssetId" AS "AssetEntity__AssetEntity_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
|
FROM
|
||||||
"assets" "AssetEntity"
|
"assets" "asset"
|
||||||
LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "AssetEntity__AssetEntity_stack" ON "AssetEntity__AssetEntity_stack"."id" = "AssetEntity"."stackId"
|
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
|
WHERE
|
||||||
(
|
"asset"."isVisible" = true
|
||||||
("AssetEntity"."ownerId" IN ($1))
|
AND "asset"."ownerId" IN ($1)
|
||||||
AND ("AssetEntity"."isVisible" = $2)
|
AND (
|
||||||
AND ("AssetEntity"."updatedAt" > $3)
|
"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[]> {
|
getAllForUserFullSync(options: AssetFullSyncOptions): Promise<AssetEntity[]> {
|
||||||
const { ownerId, lastCreationDate, lastId, updatedUntil, limit } = options;
|
const { ownerId, isArchived, withStacked, lastCreationDate, lastId, updatedUntil, limit } = options;
|
||||||
const builder = this.repository
|
const builder = this.getBuilder({
|
||||||
.createQueryBuilder('asset')
|
userIds: [ownerId],
|
||||||
.leftJoinAndSelect('asset.exifInfo', 'exifInfo')
|
exifInfo: true,
|
||||||
.leftJoinAndSelect('asset.stack', 'stack')
|
withStacked,
|
||||||
.where('asset.ownerId = :ownerId', { ownerId });
|
isArchived,
|
||||||
|
});
|
||||||
|
|
||||||
if (lastCreationDate !== undefined && lastId !== undefined) {
|
if (lastCreationDate !== undefined && lastId !== undefined) {
|
||||||
builder.andWhere('(asset.fileCreatedAt, asset.id) < (:lastCreationDate, :lastId)', {
|
builder.andWhere('(asset.fileCreatedAt, asset.id) < (:lastCreationDate, :lastId)', {
|
||||||
lastCreationDate,
|
lastCreationDate,
|
||||||
lastId,
|
lastId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder
|
return builder
|
||||||
.andWhere('asset.updatedAt <= :updatedUntil', { updatedUntil })
|
.andWhere('asset.updatedAt <= :updatedUntil', { updatedUntil })
|
||||||
.andWhere('asset.isVisible = true')
|
|
||||||
.orderBy('asset.fileCreatedAt', 'DESC')
|
.orderBy('asset.fileCreatedAt', 'DESC')
|
||||||
.addOrderBy('asset.id', 'DESC')
|
.addOrderBy('asset.id', 'DESC')
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -734,18 +736,11 @@ export class AssetRepository implements IAssetRepository {
|
||||||
|
|
||||||
@GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE }] })
|
@GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE }] })
|
||||||
getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]> {
|
getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]> {
|
||||||
return this.repository.find({
|
const builder = this.getBuilder({ userIds: options.userIds, exifInfo: true, withStacked: true })
|
||||||
where: {
|
.andWhere({ updatedAt: MoreThan(options.updatedAfter) })
|
||||||
ownerId: In(options.userIds),
|
.take(options.limit)
|
||||||
isVisible: true,
|
.withDeleted();
|
||||||
updatedAt: MoreThan(options.updatedAfter),
|
|
||||||
},
|
return builder.getMany();
|
||||||
relations: {
|
|
||||||
exifInfo: true,
|
|
||||||
stack: true,
|
|
||||||
},
|
|
||||||
take: options.limit,
|
|
||||||
withDeleted: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,13 +39,12 @@ describe(SyncService.name, () => {
|
||||||
describe('getAllAssetsForUserFullSync', () => {
|
describe('getAllAssetsForUserFullSync', () => {
|
||||||
it('should return a list of all assets owned by the user', async () => {
|
it('should return a list of all assets owned by the user', async () => {
|
||||||
assetMock.getAllForUserFullSync.mockResolvedValue([assetStub.external, assetStub.hasEncodedVideo]);
|
assetMock.getAllForUserFullSync.mockResolvedValue([assetStub.external, assetStub.hasEncodedVideo]);
|
||||||
await expect(
|
await expect(sut.getFullSync(authStub.user1, { limit: 2, updatedUntil: untilDate })).resolves.toEqual([
|
||||||
sut.getAllAssetsForUserFullSync(authStub.user1, { limit: 2, updatedUntil: untilDate }),
|
|
||||||
).resolves.toEqual([
|
|
||||||
mapAsset(assetStub.external, mapAssetOpts),
|
mapAsset(assetStub.external, mapAssetOpts),
|
||||||
mapAsset(assetStub.hasEncodedVideo, mapAssetOpts),
|
mapAsset(assetStub.hasEncodedVideo, mapAssetOpts),
|
||||||
]);
|
]);
|
||||||
expect(assetMock.getAllForUserFullSync).toHaveBeenCalledWith({
|
expect(assetMock.getAllForUserFullSync).toHaveBeenCalledWith({
|
||||||
|
withStacked: true,
|
||||||
ownerId: authStub.user1.user.id,
|
ownerId: authStub.user1.user.id,
|
||||||
updatedUntil: untilDate,
|
updatedUntil: untilDate,
|
||||||
limit: 2,
|
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 () => {
|
it('should return a response requiring a full sync when partners are out of sync', async () => {
|
||||||
partnerMock.getAll.mockResolvedValue([partnerStub.adminToUser1]);
|
partnerMock.getAll.mockResolvedValue([partnerStub.adminToUser1]);
|
||||||
await expect(
|
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: [] });
|
).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
|
||||||
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
||||||
expect(auditMock.getAfter).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 () => {
|
it('should return a response requiring a full sync when last sync was too long ago', async () => {
|
||||||
partnerMock.getAll.mockResolvedValue([]);
|
partnerMock.getAll.mockResolvedValue([]);
|
||||||
await expect(
|
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: [] });
|
).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
|
||||||
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(0);
|
||||||
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
||||||
|
@ -78,7 +77,7 @@ describe(SyncService.name, () => {
|
||||||
Array.from<AssetEntity>({ length: 10_000 }).fill(assetStub.image),
|
Array.from<AssetEntity>({ length: 10_000 }).fill(assetStub.image),
|
||||||
);
|
);
|
||||||
await expect(
|
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: [] });
|
).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] });
|
||||||
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(1);
|
expect(assetMock.getChangedDeltaSync).toHaveBeenCalledTimes(1);
|
||||||
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
expect(auditMock.getAfter).toHaveBeenCalledTimes(0);
|
||||||
|
@ -89,7 +88,7 @@ describe(SyncService.name, () => {
|
||||||
assetMock.getChangedDeltaSync.mockResolvedValue([assetStub.image1]);
|
assetMock.getChangedDeltaSync.mockResolvedValue([assetStub.image1]);
|
||||||
auditMock.getAfter.mockResolvedValue([assetStub.external.id]);
|
auditMock.getAfter.mockResolvedValue([assetStub.external.id]);
|
||||||
await expect(
|
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({
|
).resolves.toEqual({
|
||||||
needsFullSync: false,
|
needsFullSync: false,
|
||||||
upserted: [mapAsset(assetStub.image1, mapAssetOpts)],
|
upserted: [mapAsset(assetStub.image1, mapAssetOpts)],
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Inject } from '@nestjs/common';
|
import { Inject } from '@nestjs/common';
|
||||||
import _ from 'lodash';
|
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { AUDIT_LOG_MAX_DURATION } from 'src/constants';
|
import { AUDIT_LOG_MAX_DURATION } from 'src/constants';
|
||||||
import { AccessCore, Permission } from 'src/cores/access.core';
|
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 { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||||
import { IAuditRepository } from 'src/interfaces/audit.interface';
|
import { IAuditRepository } from 'src/interfaces/audit.interface';
|
||||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||||
|
import { setIsEqual } from 'src/utils/set';
|
||||||
|
|
||||||
|
const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] };
|
||||||
|
|
||||||
export class SyncService {
|
export class SyncService {
|
||||||
private access: AccessCore;
|
private access: AccessCore;
|
||||||
|
@ -24,52 +26,69 @@ export class SyncService {
|
||||||
this.access = AccessCore.create(accessRepository);
|
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;
|
const userId = dto.userId || auth.user.id;
|
||||||
await this.access.requirePermission(auth, Permission.TIMELINE_READ, userId);
|
await this.access.requirePermission(auth, Permission.TIMELINE_READ, userId);
|
||||||
const assets = await this.assetRepository.getAllForUserFullSync({
|
const assets = await this.assetRepository.getAllForUserFullSync({
|
||||||
ownerId: userId,
|
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,
|
lastCreationDate: dto.lastCreationDate,
|
||||||
updatedUntil: dto.updatedUntil,
|
updatedUntil: dto.updatedUntil,
|
||||||
lastId: dto.lastId,
|
lastId: dto.lastId,
|
||||||
limit: dto.limit,
|
limit: dto.limit,
|
||||||
});
|
});
|
||||||
const options = { auth, stripMetadata: false, withStack: true };
|
return assets.map((a) => mapAsset(a, { auth, stripMetadata: false, withStack: true }));
|
||||||
return assets.map((a) => mapAsset(a, options));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getChangesForDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
|
async getDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise<AssetDeltaSyncResponseDto> {
|
||||||
await this.access.requirePermission(auth, Permission.TIMELINE_READ, dto.userIds);
|
// app has not synced in the last 100 days
|
||||||
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();
|
|
||||||
const duration = DateTime.now().diff(DateTime.fromJSDate(dto.updatedAfter));
|
const duration = DateTime.now().diff(DateTime.fromJSDate(dto.updatedAfter));
|
||||||
|
if (duration > AUDIT_LOG_MAX_DURATION) {
|
||||||
if (!_.isEqual(userIds, dto.userIds) || duration > AUDIT_LOG_MAX_DURATION) {
|
return FULL_SYNC;
|
||||||
// app does not have the correct partners synced
|
|
||||||
// or app has not synced in the last 100 days
|
|
||||||
return { needsFullSync: true, deleted: [], upserted: [] };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 limit = 10_000;
|
||||||
const upserted = await this.assetRepository.getChangedDeltaSync({ limit, updatedAfter: dto.updatedAfter, userIds });
|
const upserted = await this.assetRepository.getChangedDeltaSync({ limit, updatedAfter: dto.updatedAfter, userIds });
|
||||||
|
|
||||||
|
// too many changes, need to do a full sync
|
||||||
if (upserted.length === limit) {
|
if (upserted.length === limit) {
|
||||||
// too many changes -> do a full sync (paginated) instead
|
return FULL_SYNC;
|
||||||
return { needsFullSync: true, deleted: [], upserted: [] };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleted = await this.auditRepository.getAfter(dto.updatedAfter, {
|
const deleted = await this.auditRepository.getAfter(dto.updatedAfter, {
|
||||||
userIds: userIds,
|
userIds,
|
||||||
entityType: EntityType.ASSET,
|
entityType: EntityType.ASSET,
|
||||||
action: DatabaseAction.DELETE,
|
action: DatabaseAction.DELETE,
|
||||||
});
|
});
|
||||||
|
|
||||||
const options = { auth, stripMetadata: false, withStack: true };
|
|
||||||
const result = {
|
const result = {
|
||||||
needsFullSync: false,
|
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,
|
deleted,
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Add table
Reference in a new issue