mirror of
https://github.com/immich-app/immich.git
synced 2025-03-04 15:52:17 +02:00
refactor(server): download endpoints (#6653)
* refactor(server): download controller * chore: open api * chore: fix mobile references
This commit is contained in:
parent
de47a6a330
commit
7ea55c7236
@ -24,11 +24,11 @@ class ImageViewerService {
|
||||
try {
|
||||
// Download LivePhotos image and motion part
|
||||
if (asset.isImage && asset.livePhotoVideoId != null && Platform.isIOS) {
|
||||
var imageResponse = await _apiService.assetApi.downloadFileWithHttpInfo(
|
||||
var imageResponse = await _apiService.assetApi.downloadFileOldWithHttpInfo(
|
||||
asset.remoteId!,
|
||||
);
|
||||
|
||||
var motionReponse = await _apiService.assetApi.downloadFileWithHttpInfo(
|
||||
var motionReponse = await _apiService.assetApi.downloadFileOldWithHttpInfo(
|
||||
asset.livePhotoVideoId!,
|
||||
);
|
||||
|
||||
@ -70,7 +70,7 @@ class ImageViewerService {
|
||||
return entity != null;
|
||||
} else {
|
||||
var res = await _apiService.assetApi
|
||||
.downloadFileWithHttpInfo(asset.remoteId!);
|
||||
.downloadFileOldWithHttpInfo(asset.remoteId!);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
_log.severe(
|
||||
|
@ -166,7 +166,7 @@ class BackupVerificationService {
|
||||
final Uint64List localImage =
|
||||
_fakeDecodeImg(local, await file.readAsBytes());
|
||||
final res = await apiService.assetApi
|
||||
.downloadFileWithHttpInfo(remote.remoteId!);
|
||||
.downloadFileOldWithHttpInfo(remote.remoteId!);
|
||||
final Uint64List remoteImage = _fakeDecodeImg(remote, res.bodyBytes);
|
||||
|
||||
final eq = const ListEquality().equals(remoteImage, localImage);
|
||||
|
@ -32,7 +32,7 @@ class ShareService {
|
||||
final fileName = asset.fileName;
|
||||
final tempFile = await File('${tempDir.path}/$fileName').create();
|
||||
final res = await _apiService.assetApi
|
||||
.downloadFileWithHttpInfo(asset.remoteId!);
|
||||
.downloadFileOldWithHttpInfo(asset.remoteId!);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
_log.severe(
|
||||
|
3
mobile/openapi/.openapi-generator/FILES
generated
3
mobile/openapi/.openapi-generator/FILES
generated
@ -58,6 +58,7 @@ doc/CreateTagDto.md
|
||||
doc/CreateUserDto.md
|
||||
doc/CuratedLocationsResponseDto.md
|
||||
doc/CuratedObjectsResponseDto.md
|
||||
doc/DownloadApi.md
|
||||
doc/DownloadArchiveInfo.md
|
||||
doc/DownloadInfoDto.md
|
||||
doc/DownloadResponseDto.md
|
||||
@ -186,6 +187,7 @@ lib/api/api_key_api.dart
|
||||
lib/api/asset_api.dart
|
||||
lib/api/audit_api.dart
|
||||
lib/api/authentication_api.dart
|
||||
lib/api/download_api.dart
|
||||
lib/api/face_api.dart
|
||||
lib/api/job_api.dart
|
||||
lib/api/library_api.dart
|
||||
@ -419,6 +421,7 @@ test/create_tag_dto_test.dart
|
||||
test/create_user_dto_test.dart
|
||||
test/curated_locations_response_dto_test.dart
|
||||
test/curated_objects_response_dto_test.dart
|
||||
test/download_api_test.dart
|
||||
test/download_archive_info_test.dart
|
||||
test/download_info_dto_test.dart
|
||||
test/download_response_dto_test.dart
|
||||
|
9
mobile/openapi/README.md
generated
9
mobile/openapi/README.md
generated
@ -94,8 +94,8 @@ Class | Method | HTTP request | Description
|
||||
*AssetApi* | [**checkBulkUpload**](doc//AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
|
||||
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist |
|
||||
*AssetApi* | [**deleteAssets**](doc//AssetApi.md#deleteassets) | **DELETE** /asset |
|
||||
*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
|
||||
*AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
|
||||
*AssetApi* | [**downloadArchiveOld**](doc//AssetApi.md#downloadarchiveold) | **POST** /asset/download/archive |
|
||||
*AssetApi* | [**downloadFileOld**](doc//AssetApi.md#downloadfileold) | **POST** /asset/download/{id} |
|
||||
*AssetApi* | [**emptyTrash**](doc//AssetApi.md#emptytrash) | **POST** /asset/trash/empty |
|
||||
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
|
||||
*AssetApi* | [**getAllUserAssetsByDeviceId**](doc//AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} |
|
||||
@ -106,7 +106,7 @@ Class | Method | HTTP request | Description
|
||||
*AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
|
||||
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
|
||||
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
|
||||
*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
|
||||
*AssetApi* | [**getDownloadInfoOld**](doc//AssetApi.md#getdownloadinfoold) | **POST** /asset/download/info |
|
||||
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
|
||||
*AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
|
||||
*AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random |
|
||||
@ -133,6 +133,9 @@ Class | Method | HTTP request | Description
|
||||
*AuthenticationApi* | [**logoutAuthDevices**](doc//AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices |
|
||||
*AuthenticationApi* | [**signUpAdmin**](doc//AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up |
|
||||
*AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken |
|
||||
*DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive |
|
||||
*DownloadApi* | [**downloadFile**](doc//DownloadApi.md#downloadfile) | **POST** /download/asset/{id} |
|
||||
*DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info |
|
||||
*FaceApi* | [**getFaces**](doc//FaceApi.md#getfaces) | **GET** /face |
|
||||
*FaceApi* | [**reassignFacesById**](doc//FaceApi.md#reassignfacesbyid) | **PUT** /face/{id} |
|
||||
*JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs |
|
||||
|
30
mobile/openapi/doc/AssetApi.md
generated
30
mobile/openapi/doc/AssetApi.md
generated
@ -12,8 +12,8 @@ Method | HTTP request | Description
|
||||
[**checkBulkUpload**](AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
|
||||
[**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist |
|
||||
[**deleteAssets**](AssetApi.md#deleteassets) | **DELETE** /asset |
|
||||
[**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
|
||||
[**downloadFile**](AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
|
||||
[**downloadArchiveOld**](AssetApi.md#downloadarchiveold) | **POST** /asset/download/archive |
|
||||
[**downloadFileOld**](AssetApi.md#downloadfileold) | **POST** /asset/download/{id} |
|
||||
[**emptyTrash**](AssetApi.md#emptytrash) | **POST** /asset/trash/empty |
|
||||
[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset |
|
||||
[**getAllUserAssetsByDeviceId**](AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} |
|
||||
@ -24,7 +24,7 @@ Method | HTTP request | Description
|
||||
[**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
|
||||
[**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
|
||||
[**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
|
||||
[**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
|
||||
[**getDownloadInfoOld**](AssetApi.md#getdownloadinfoold) | **POST** /asset/download/info |
|
||||
[**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
|
||||
[**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
|
||||
[**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random |
|
||||
@ -209,8 +209,8 @@ void (empty response body)
|
||||
|
||||
[[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)
|
||||
|
||||
# **downloadArchive**
|
||||
> MultipartFile downloadArchive(assetIdsDto, key)
|
||||
# **downloadArchiveOld**
|
||||
> MultipartFile downloadArchiveOld(assetIdsDto, key)
|
||||
|
||||
|
||||
|
||||
@ -237,10 +237,10 @@ final assetIdsDto = AssetIdsDto(); // AssetIdsDto |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.downloadArchive(assetIdsDto, key);
|
||||
final result = api_instance.downloadArchiveOld(assetIdsDto, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->downloadArchive: $e\n');
|
||||
print('Exception when calling AssetApi->downloadArchiveOld: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
@ -266,8 +266,8 @@ Name | Type | Description | Notes
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **downloadFile**
|
||||
> MultipartFile downloadFile(id, key)
|
||||
# **downloadFileOld**
|
||||
> MultipartFile downloadFileOld(id, key)
|
||||
|
||||
|
||||
|
||||
@ -294,10 +294,10 @@ final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.downloadFile(id, key);
|
||||
final result = api_instance.downloadFileOld(id, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->downloadFile: $e\n');
|
||||
print('Exception when calling AssetApi->downloadFileOld: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
@ -888,8 +888,8 @@ This endpoint does not need any parameter.
|
||||
|
||||
[[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)
|
||||
|
||||
# **getDownloadInfo**
|
||||
> DownloadResponseDto getDownloadInfo(downloadInfoDto, key)
|
||||
# **getDownloadInfoOld**
|
||||
> DownloadResponseDto getDownloadInfoOld(downloadInfoDto, key)
|
||||
|
||||
|
||||
|
||||
@ -916,10 +916,10 @@ final downloadInfoDto = DownloadInfoDto(); // DownloadInfoDto |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.getDownloadInfo(downloadInfoDto, key);
|
||||
final result = api_instance.getDownloadInfoOld(downloadInfoDto, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->getDownloadInfo: $e\n');
|
||||
print('Exception when calling AssetApi->getDownloadInfoOld: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
|
187
mobile/openapi/doc/DownloadApi.md
generated
Normal file
187
mobile/openapi/doc/DownloadApi.md
generated
Normal file
@ -0,0 +1,187 @@
|
||||
# openapi.api.DownloadApi
|
||||
|
||||
## Load the API package
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
```
|
||||
|
||||
All URIs are relative to */api*
|
||||
|
||||
Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**downloadArchive**](DownloadApi.md#downloadarchive) | **POST** /download/archive |
|
||||
[**downloadFile**](DownloadApi.md#downloadfile) | **POST** /download/asset/{id} |
|
||||
[**getDownloadInfo**](DownloadApi.md#getdownloadinfo) | **POST** /download/info |
|
||||
|
||||
|
||||
# **downloadArchive**
|
||||
> MultipartFile downloadArchive(assetIdsDto, key)
|
||||
|
||||
|
||||
|
||||
### 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 = DownloadApi();
|
||||
final assetIdsDto = AssetIdsDto(); // AssetIdsDto |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.downloadArchive(assetIdsDto, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling DownloadApi->downloadArchive: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| |
|
||||
**key** | **String**| | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**MultipartFile**](MultipartFile.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/octet-stream
|
||||
|
||||
[[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)
|
||||
|
||||
# **downloadFile**
|
||||
> MultipartFile downloadFile(id, key)
|
||||
|
||||
|
||||
|
||||
### 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 = DownloadApi();
|
||||
final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.downloadFile(id, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling DownloadApi->downloadFile: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**id** | **String**| |
|
||||
**key** | **String**| | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**MultipartFile**](MultipartFile.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/octet-stream
|
||||
|
||||
[[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)
|
||||
|
||||
# **getDownloadInfo**
|
||||
> DownloadResponseDto getDownloadInfo(downloadInfoDto, key)
|
||||
|
||||
|
||||
|
||||
### 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 = DownloadApi();
|
||||
final downloadInfoDto = DownloadInfoDto(); // DownloadInfoDto |
|
||||
final key = key_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.getDownloadInfo(downloadInfoDto, key);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling DownloadApi->getDownloadInfo: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**downloadInfoDto** | [**DownloadInfoDto**](DownloadInfoDto.md)| |
|
||||
**key** | **String**| | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**DownloadResponseDto**](DownloadResponseDto.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)
|
||||
|
1
mobile/openapi/lib/api.dart
generated
1
mobile/openapi/lib/api.dart
generated
@ -34,6 +34,7 @@ part 'api/album_api.dart';
|
||||
part 'api/asset_api.dart';
|
||||
part 'api/audit_api.dart';
|
||||
part 'api/authentication_api.dart';
|
||||
part 'api/download_api.dart';
|
||||
part 'api/face_api.dart';
|
||||
part 'api/job_api.dart';
|
||||
part 'api/library_api.dart';
|
||||
|
18
mobile/openapi/lib/api/asset_api.dart
generated
18
mobile/openapi/lib/api/asset_api.dart
generated
@ -165,7 +165,7 @@ class AssetApi {
|
||||
/// * [AssetIdsDto] assetIdsDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
Future<Response> downloadArchiveOldWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/download/archive';
|
||||
|
||||
@ -199,8 +199,8 @@ class AssetApi {
|
||||
/// * [AssetIdsDto] assetIdsDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<MultipartFile?> downloadArchive(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
final response = await downloadArchiveWithHttpInfo(assetIdsDto, key: key, );
|
||||
Future<MultipartFile?> downloadArchiveOld(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
final response = await downloadArchiveOldWithHttpInfo(assetIdsDto, key: key, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
@ -220,7 +220,7 @@ class AssetApi {
|
||||
/// * [String] id (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> downloadFileWithHttpInfo(String id, { String? key, }) async {
|
||||
Future<Response> downloadFileOldWithHttpInfo(String id, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/download/{id}'
|
||||
.replaceAll('{id}', id);
|
||||
@ -255,8 +255,8 @@ class AssetApi {
|
||||
/// * [String] id (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<MultipartFile?> downloadFile(String id, { String? key, }) async {
|
||||
final response = await downloadFileWithHttpInfo(id, key: key, );
|
||||
Future<MultipartFile?> downloadFileOld(String id, { String? key, }) async {
|
||||
final response = await downloadFileOldWithHttpInfo(id, key: key, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
@ -853,7 +853,7 @@ class AssetApi {
|
||||
/// * [DownloadInfoDto] downloadInfoDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
Future<Response> getDownloadInfoOldWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/download/info';
|
||||
|
||||
@ -887,8 +887,8 @@ class AssetApi {
|
||||
/// * [DownloadInfoDto] downloadInfoDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<DownloadResponseDto?> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
final response = await getDownloadInfoWithHttpInfo(downloadInfoDto, key: key, );
|
||||
Future<DownloadResponseDto?> getDownloadInfoOld(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
final response = await getDownloadInfoOldWithHttpInfo(downloadInfoDto, key: key, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
|
184
mobile/openapi/lib/api/download_api.dart
generated
Normal file
184
mobile/openapi/lib/api/download_api.dart
generated
Normal file
@ -0,0 +1,184 @@
|
||||
//
|
||||
// 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 DownloadApi {
|
||||
DownloadApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient;
|
||||
|
||||
final ApiClient apiClient;
|
||||
|
||||
/// Performs an HTTP 'POST /download/archive' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [AssetIdsDto] assetIdsDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/download/archive';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = assetIdsDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
if (key != null) {
|
||||
queryParams.addAll(_queryParams('', 'key', key));
|
||||
}
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [AssetIdsDto] assetIdsDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<MultipartFile?> downloadArchive(AssetIdsDto assetIdsDto, { String? key, }) async {
|
||||
final response = await downloadArchiveWithHttpInfo(assetIdsDto, key: key, );
|
||||
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), 'MultipartFile',) as MultipartFile;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /download/asset/{id}' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] id (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> downloadFileWithHttpInfo(String id, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/download/asset/{id}'
|
||||
.replaceAll('{id}', id);
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
if (key != null) {
|
||||
queryParams.addAll(_queryParams('', 'key', key));
|
||||
}
|
||||
|
||||
const contentTypes = <String>[];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] id (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<MultipartFile?> downloadFile(String id, { String? key, }) async {
|
||||
final response = await downloadFileWithHttpInfo(id, key: key, );
|
||||
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), 'MultipartFile',) as MultipartFile;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /download/info' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [DownloadInfoDto] downloadInfoDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<Response> getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/download/info';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody = downloadInfoDto;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
if (key != null) {
|
||||
queryParams.addAll(_queryParams('', 'key', key));
|
||||
}
|
||||
|
||||
const contentTypes = <String>['application/json'];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [DownloadInfoDto] downloadInfoDto (required):
|
||||
///
|
||||
/// * [String] key:
|
||||
Future<DownloadResponseDto?> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
|
||||
final response = await getDownloadInfoWithHttpInfo(downloadInfoDto, key: key, );
|
||||
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), 'DownloadResponseDto',) as DownloadResponseDto;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
12
mobile/openapi/test/asset_api_test.dart
generated
12
mobile/openapi/test/asset_api_test.dart
generated
@ -36,13 +36,13 @@ void main() {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<MultipartFile> downloadArchive(AssetIdsDto assetIdsDto, { String key }) async
|
||||
test('test downloadArchive', () async {
|
||||
//Future<MultipartFile> downloadArchiveOld(AssetIdsDto assetIdsDto, { String key }) async
|
||||
test('test downloadArchiveOld', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<MultipartFile> downloadFile(String id, { String key }) async
|
||||
test('test downloadFile', () async {
|
||||
//Future<MultipartFile> downloadFileOld(String id, { String key }) async
|
||||
test('test downloadFileOld', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
@ -102,8 +102,8 @@ void main() {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<DownloadResponseDto> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String key }) async
|
||||
test('test getDownloadInfo', () async {
|
||||
//Future<DownloadResponseDto> getDownloadInfoOld(DownloadInfoDto downloadInfoDto, { String key }) async
|
||||
test('test getDownloadInfoOld', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
|
36
mobile/openapi/test/download_api_test.dart
generated
Normal file
36
mobile/openapi/test/download_api_test.dart
generated
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// 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 DownloadApi
|
||||
void main() {
|
||||
// final instance = DownloadApi();
|
||||
|
||||
group('tests for DownloadApi', () {
|
||||
//Future<MultipartFile> downloadArchive(AssetIdsDto assetIdsDto, { String key }) async
|
||||
test('test downloadArchive', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<MultipartFile> downloadFile(String id, { String key }) async
|
||||
test('test downloadFile', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
//Future<DownloadResponseDto> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String key }) async
|
||||
test('test getDownloadInfo', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
});
|
||||
}
|
@ -1267,7 +1267,7 @@
|
||||
},
|
||||
"/asset/download/archive": {
|
||||
"post": {
|
||||
"operationId": "downloadArchive",
|
||||
"operationId": "downloadArchiveOld",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
@ -1319,7 +1319,7 @@
|
||||
},
|
||||
"/asset/download/info": {
|
||||
"post": {
|
||||
"operationId": "getDownloadInfo",
|
||||
"operationId": "getDownloadInfoOld",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
@ -1370,7 +1370,7 @@
|
||||
},
|
||||
"/asset/download/{id}": {
|
||||
"post": {
|
||||
"operationId": "downloadFile",
|
||||
"operationId": "downloadFileOld",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
@ -3217,6 +3217,160 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/download/archive": {
|
||||
"post": {
|
||||
"operationId": "downloadArchive",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AssetIdsDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/octet-stream": {
|
||||
"schema": {
|
||||
"format": "binary",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Download"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/download/asset/{id}": {
|
||||
"post": {
|
||||
"operationId": "downloadFile",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"format": "uuid",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "key",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/octet-stream": {
|
||||
"schema": {
|
||||
"format": "binary",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Download"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/download/info": {
|
||||
"post": {
|
||||
"operationId": "getDownloadInfo",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DownloadInfoDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DownloadResponseDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Download"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/face": {
|
||||
"get": {
|
||||
"operationId": "getFaces",
|
||||
|
429
open-api/typescript-sdk/client/api.ts
generated
429
open-api/typescript-sdk/client/api.ts
generated
@ -6891,9 +6891,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
downloadArchiveOld: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'assetIdsDto' is not null or undefined
|
||||
assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
|
||||
assertParamExists('downloadArchiveOld', 'assetIdsDto', assetIdsDto)
|
||||
const localVarPath = `/asset/download/archive`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
@ -6940,9 +6940,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadFile: async (id: string, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
downloadFileOld: async (id: string, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('downloadFile', 'id', id)
|
||||
assertParamExists('downloadFileOld', 'id', id)
|
||||
const localVarPath = `/asset/download/{id}`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
@ -7463,9 +7463,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
getDownloadInfoOld: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'downloadInfoDto' is not null or undefined
|
||||
assertParamExists('getDownloadInfo', 'downloadInfoDto', downloadInfoDto)
|
||||
assertParamExists('getDownloadInfoOld', 'downloadInfoDto', downloadInfoDto)
|
||||
const localVarPath = `/asset/download/info`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
@ -8601,8 +8601,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async downloadArchive(assetIdsDto: AssetIdsDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadArchive(assetIdsDto, key, options);
|
||||
async downloadArchiveOld(assetIdsDto: AssetIdsDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadArchiveOld(assetIdsDto, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
@ -8612,8 +8612,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async downloadFile(id: string, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadFile(id, key, options);
|
||||
async downloadFileOld(id: string, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadFileOld(id, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
@ -8733,8 +8733,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getDownloadInfo(downloadInfoDto: DownloadInfoDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DownloadResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
|
||||
async getDownloadInfoOld(downloadInfoDto: DownloadInfoDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DownloadResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfoOld(downloadInfoDto, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
@ -8996,21 +8996,21 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiDownloadArchiveRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiDownloadArchiveOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadArchive(requestParameters: AssetApiDownloadArchiveRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadArchive(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
downloadArchiveOld(requestParameters: AssetApiDownloadArchiveOldRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadArchiveOld(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiDownloadFileRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiDownloadFileOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadFile(requestParameters: AssetApiDownloadFileRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadFile(requestParameters.id, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
downloadFileOld(requestParameters: AssetApiDownloadFileOldRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadFileOld(requestParameters.id, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
@ -9101,12 +9101,12 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiGetDownloadInfoRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiGetDownloadInfoOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig): AxiosPromise<DownloadResponseDto> {
|
||||
return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
getDownloadInfoOld(requestParameters: AssetApiGetDownloadInfoOldRequest, options?: AxiosRequestConfig): AxiosPromise<DownloadResponseDto> {
|
||||
return localVarFp.getDownloadInfoOld(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
@ -9279,43 +9279,43 @@ export interface AssetApiDeleteAssetsRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for downloadArchive operation in AssetApi.
|
||||
* Request parameters for downloadArchiveOld operation in AssetApi.
|
||||
* @export
|
||||
* @interface AssetApiDownloadArchiveRequest
|
||||
* @interface AssetApiDownloadArchiveOldRequest
|
||||
*/
|
||||
export interface AssetApiDownloadArchiveRequest {
|
||||
export interface AssetApiDownloadArchiveOldRequest {
|
||||
/**
|
||||
*
|
||||
* @type {AssetIdsDto}
|
||||
* @memberof AssetApiDownloadArchive
|
||||
* @memberof AssetApiDownloadArchiveOld
|
||||
*/
|
||||
readonly assetIdsDto: AssetIdsDto
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AssetApiDownloadArchive
|
||||
* @memberof AssetApiDownloadArchiveOld
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for downloadFile operation in AssetApi.
|
||||
* Request parameters for downloadFileOld operation in AssetApi.
|
||||
* @export
|
||||
* @interface AssetApiDownloadFileRequest
|
||||
* @interface AssetApiDownloadFileOldRequest
|
||||
*/
|
||||
export interface AssetApiDownloadFileRequest {
|
||||
export interface AssetApiDownloadFileOldRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AssetApiDownloadFile
|
||||
* @memberof AssetApiDownloadFileOld
|
||||
*/
|
||||
readonly id: string
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AssetApiDownloadFile
|
||||
* @memberof AssetApiDownloadFileOld
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
@ -9496,22 +9496,22 @@ export interface AssetApiGetAssetThumbnailRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for getDownloadInfo operation in AssetApi.
|
||||
* Request parameters for getDownloadInfoOld operation in AssetApi.
|
||||
* @export
|
||||
* @interface AssetApiGetDownloadInfoRequest
|
||||
* @interface AssetApiGetDownloadInfoOldRequest
|
||||
*/
|
||||
export interface AssetApiGetDownloadInfoRequest {
|
||||
export interface AssetApiGetDownloadInfoOldRequest {
|
||||
/**
|
||||
*
|
||||
* @type {DownloadInfoDto}
|
||||
* @memberof AssetApiGetDownloadInfo
|
||||
* @memberof AssetApiGetDownloadInfoOld
|
||||
*/
|
||||
readonly downloadInfoDto: DownloadInfoDto
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof AssetApiGetDownloadInfo
|
||||
* @memberof AssetApiGetDownloadInfoOld
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
@ -10307,24 +10307,24 @@ export class AssetApi extends BaseAPI {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiDownloadArchiveRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiDownloadArchiveOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public downloadArchive(requestParameters: AssetApiDownloadArchiveRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).downloadArchive(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
public downloadArchiveOld(requestParameters: AssetApiDownloadArchiveOldRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).downloadArchiveOld(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiDownloadFileRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiDownloadFileOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public downloadFile(requestParameters: AssetApiDownloadFileRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).downloadFile(requestParameters.id, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
public downloadFileOld(requestParameters: AssetApiDownloadFileOldRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).downloadFileOld(requestParameters.id, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10436,13 +10436,13 @@ export class AssetApi extends BaseAPI {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AssetApiGetDownloadInfoRequest} requestParameters Request parameters.
|
||||
* @param {AssetApiGetDownloadInfoOldRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
public getDownloadInfoOld(requestParameters: AssetApiGetDownloadInfoOldRequest, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).getDownloadInfoOld(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -11628,6 +11628,345 @@ export class AuthenticationApi extends BaseAPI {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DownloadApi - axios parameter creator
|
||||
* @export
|
||||
*/
|
||||
export const DownloadApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AssetIdsDto} assetIdsDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'assetIdsDto' is not null or undefined
|
||||
assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
|
||||
const localVarPath = `/download/archive`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication api_key required
|
||||
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
if (key !== undefined) {
|
||||
localVarQueryParameter['key'] = key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(assetIdsDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadFile: async (id: string, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('downloadFile', 'id', id)
|
||||
const localVarPath = `/download/asset/{id}`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication api_key required
|
||||
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
if (key !== undefined) {
|
||||
localVarQueryParameter['key'] = key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {DownloadInfoDto} downloadInfoDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'downloadInfoDto' is not null or undefined
|
||||
assertParamExists('getDownloadInfo', 'downloadInfoDto', downloadInfoDto)
|
||||
const localVarPath = `/download/info`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication api_key required
|
||||
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
if (key !== undefined) {
|
||||
localVarQueryParameter['key'] = key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(downloadInfoDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DownloadApi - functional programming interface
|
||||
* @export
|
||||
*/
|
||||
export const DownloadApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = DownloadApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AssetIdsDto} assetIdsDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async downloadArchive(assetIdsDto: AssetIdsDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadArchive(assetIdsDto, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async downloadFile(id: string, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<File>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.downloadFile(id, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {DownloadInfoDto} downloadInfoDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getDownloadInfo(downloadInfoDto: DownloadInfoDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DownloadResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DownloadApi - factory interface
|
||||
* @export
|
||||
*/
|
||||
export const DownloadApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||
const localVarFp = DownloadApiFp(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiDownloadArchiveRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadArchive(requestParameters: DownloadApiDownloadArchiveRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadArchive(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiDownloadFileRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
downloadFile(requestParameters: DownloadApiDownloadFileRequest, options?: AxiosRequestConfig): AxiosPromise<File> {
|
||||
return localVarFp.downloadFile(requestParameters.id, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiGetDownloadInfoRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getDownloadInfo(requestParameters: DownloadApiGetDownloadInfoRequest, options?: AxiosRequestConfig): AxiosPromise<DownloadResponseDto> {
|
||||
return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Request parameters for downloadArchive operation in DownloadApi.
|
||||
* @export
|
||||
* @interface DownloadApiDownloadArchiveRequest
|
||||
*/
|
||||
export interface DownloadApiDownloadArchiveRequest {
|
||||
/**
|
||||
*
|
||||
* @type {AssetIdsDto}
|
||||
* @memberof DownloadApiDownloadArchive
|
||||
*/
|
||||
readonly assetIdsDto: AssetIdsDto
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof DownloadApiDownloadArchive
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for downloadFile operation in DownloadApi.
|
||||
* @export
|
||||
* @interface DownloadApiDownloadFileRequest
|
||||
*/
|
||||
export interface DownloadApiDownloadFileRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof DownloadApiDownloadFile
|
||||
*/
|
||||
readonly id: string
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof DownloadApiDownloadFile
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for getDownloadInfo operation in DownloadApi.
|
||||
* @export
|
||||
* @interface DownloadApiGetDownloadInfoRequest
|
||||
*/
|
||||
export interface DownloadApiGetDownloadInfoRequest {
|
||||
/**
|
||||
*
|
||||
* @type {DownloadInfoDto}
|
||||
* @memberof DownloadApiGetDownloadInfo
|
||||
*/
|
||||
readonly downloadInfoDto: DownloadInfoDto
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof DownloadApiGetDownloadInfo
|
||||
*/
|
||||
readonly key?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadApi - object-oriented interface
|
||||
* @export
|
||||
* @class DownloadApi
|
||||
* @extends {BaseAPI}
|
||||
*/
|
||||
export class DownloadApi extends BaseAPI {
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiDownloadArchiveRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DownloadApi
|
||||
*/
|
||||
public downloadArchive(requestParameters: DownloadApiDownloadArchiveRequest, options?: AxiosRequestConfig) {
|
||||
return DownloadApiFp(this.configuration).downloadArchive(requestParameters.assetIdsDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiDownloadFileRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DownloadApi
|
||||
*/
|
||||
public downloadFile(requestParameters: DownloadApiDownloadFileRequest, options?: AxiosRequestConfig) {
|
||||
return DownloadApiFp(this.configuration).downloadFile(requestParameters.id, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DownloadApiGetDownloadInfoRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DownloadApi
|
||||
*/
|
||||
public getDownloadInfo(requestParameters: DownloadApiGetDownloadInfoRequest, options?: AxiosRequestConfig) {
|
||||
return DownloadApiFp(this.configuration).getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FaceApi - axios parameter creator
|
||||
* @export
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
newUserRepositoryMock,
|
||||
} from '@test';
|
||||
import { when } from 'jest-when';
|
||||
import { Readable } from 'stream';
|
||||
import { CacheControl, ImmichFileResponse } from '../domain.util';
|
||||
import { JobName } from '../job';
|
||||
import {
|
||||
AssetStats,
|
||||
@ -32,19 +30,9 @@ import {
|
||||
TimeBucketSize,
|
||||
} from '../repositories';
|
||||
import { AssetService, UploadFieldName } from './asset.service';
|
||||
import { AssetJobName, AssetStatsResponseDto, DownloadResponseDto } from './dto';
|
||||
import { AssetJobName, AssetStatsResponseDto } from './dto';
|
||||
import { mapAsset } from './response-dto';
|
||||
|
||||
const downloadResponse: DownloadResponseDto = {
|
||||
totalSize: 105_000,
|
||||
archives: [
|
||||
{
|
||||
assetIds: ['asset-id', 'asset-id'],
|
||||
size: 105_000,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const stats: AssetStats = {
|
||||
[AssetType.IMAGE]: 10,
|
||||
[AssetType.VIDEO]: 23,
|
||||
@ -460,172 +448,6 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('downloadFile', () => {
|
||||
it('should require the asset.download permission', async () => {
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkAlbumAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
});
|
||||
|
||||
it('should throw an error if the asset is not found', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getByIds.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith(['asset-1']);
|
||||
});
|
||||
|
||||
it('should download a file', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).resolves.toEqual(
|
||||
new ImmichFileResponse({
|
||||
path: '/original/path.jpg',
|
||||
contentType: 'image/jpeg',
|
||||
cacheControl: CacheControl.NONE,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should download an archive', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noWebpPath]);
|
||||
storageMock.createZipStream.mockReturnValue(archiveMock);
|
||||
|
||||
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
|
||||
stream: archiveMock.stream,
|
||||
});
|
||||
|
||||
expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_456.jpg', 'IMG_456.jpg');
|
||||
});
|
||||
|
||||
it('should handle duplicate file names', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noResizePath]);
|
||||
storageMock.createZipStream.mockReturnValue(archiveMock);
|
||||
|
||||
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
|
||||
stream: archiveMock.stream,
|
||||
});
|
||||
|
||||
expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDownloadInfo', () => {
|
||||
it('should throw an error for an invalid dto', async () => {
|
||||
await expect(sut.getDownloadInfo(authStub.admin, {})).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
|
||||
it('should return a list of archives (assetIds)', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image, assetStub.video]);
|
||||
|
||||
const assetIds = ['asset-1', 'asset-2'];
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { assetIds })).resolves.toEqual(downloadResponse);
|
||||
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith(['asset-1', 'asset-2']);
|
||||
});
|
||||
|
||||
it('should return a list of archives (albumId)', async () => {
|
||||
accessMock.album.checkOwnerAccess.mockResolvedValue(new Set(['album-1']));
|
||||
assetMock.getByAlbumId.mockResolvedValue({
|
||||
items: [assetStub.image, assetStub.video],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { albumId: 'album-1' })).resolves.toEqual(downloadResponse);
|
||||
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['album-1']));
|
||||
expect(assetMock.getByAlbumId).toHaveBeenCalledWith({ take: 2500, skip: 0 }, 'album-1');
|
||||
});
|
||||
|
||||
it('should return a list of archives (userId)', async () => {
|
||||
accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id]));
|
||||
assetMock.getByUserId.mockResolvedValue({
|
||||
items: [assetStub.image, assetStub.video],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { userId: authStub.admin.user.id })).resolves.toEqual(
|
||||
downloadResponse,
|
||||
);
|
||||
|
||||
expect(assetMock.getByUserId).toHaveBeenCalledWith({ take: 2500, skip: 0 }, authStub.admin.user.id, {
|
||||
isVisible: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should split archives by size', async () => {
|
||||
accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id]));
|
||||
|
||||
assetMock.getByUserId.mockResolvedValue({
|
||||
items: [
|
||||
{ ...assetStub.image, id: 'asset-1' },
|
||||
{ ...assetStub.video, id: 'asset-2' },
|
||||
{ ...assetStub.withLocation, id: 'asset-3' },
|
||||
{ ...assetStub.noWebpPath, id: 'asset-4' },
|
||||
],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(
|
||||
sut.getDownloadInfo(authStub.admin, {
|
||||
userId: authStub.admin.user.id,
|
||||
archiveSize: 30_000,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
totalSize: 251_456,
|
||||
archives: [
|
||||
{ assetIds: ['asset-1', 'asset-2'], size: 105_000 },
|
||||
{ assetIds: ['asset-3', 'asset-4'], size: 146_456 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should include the video portion of a live photo', async () => {
|
||||
const assetIds = [assetStub.livePhotoStillAsset.id];
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoStillAsset.id])
|
||||
.mockResolvedValue([assetStub.livePhotoStillAsset]);
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoMotionAsset.id])
|
||||
.mockResolvedValue([assetStub.livePhotoMotionAsset]);
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { assetIds })).resolves.toEqual({
|
||||
totalSize: 125_000,
|
||||
archives: [
|
||||
{
|
||||
assetIds: [assetStub.livePhotoStillAsset.id, assetStub.livePhotoMotionAsset.id],
|
||||
size: 125_000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStatistics', () => {
|
||||
it('should get the statistics for a user, excluding archived assets', async () => {
|
||||
assetMock.getStatistics.mockResolvedValue(stats);
|
||||
|
@ -8,7 +8,7 @@ import sanitize from 'sanitize-filename';
|
||||
import { AccessCore, Permission } from '../access';
|
||||
import { AuthDto } from '../auth';
|
||||
import { mimeTypes } from '../domain.constant';
|
||||
import { CacheControl, HumanReadableSize, ImmichFileResponse, usePagination } from '../domain.util';
|
||||
import { usePagination } from '../domain.util';
|
||||
import { IAssetDeletionJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job';
|
||||
import {
|
||||
ClientEvent,
|
||||
@ -20,7 +20,6 @@ import {
|
||||
IStorageRepository,
|
||||
ISystemConfigRepository,
|
||||
IUserRepository,
|
||||
ImmichReadStream,
|
||||
JobItem,
|
||||
TimeBucketOptions,
|
||||
} from '../repositories';
|
||||
@ -29,15 +28,11 @@ import { SystemConfigCore } from '../system-config';
|
||||
import {
|
||||
AssetBulkDeleteDto,
|
||||
AssetBulkUpdateDto,
|
||||
AssetIdsDto,
|
||||
AssetJobName,
|
||||
AssetJobsDto,
|
||||
AssetOrder,
|
||||
AssetSearchDto,
|
||||
AssetStatsDto,
|
||||
DownloadArchiveInfo,
|
||||
DownloadInfoDto,
|
||||
DownloadResponseDto,
|
||||
MapMarkerDto,
|
||||
MemoryLaneDto,
|
||||
TimeBucketAssetDto,
|
||||
@ -278,111 +273,6 @@ export class AssetService {
|
||||
|
||||
return { ...options, userIds };
|
||||
}
|
||||
async downloadFile(auth: AuthDto, id: string): Promise<ImmichFileResponse> {
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, id);
|
||||
|
||||
const [asset] = await this.assetRepository.getByIds([id]);
|
||||
if (!asset) {
|
||||
throw new BadRequestException('Asset not found');
|
||||
}
|
||||
|
||||
if (asset.isOffline) {
|
||||
throw new BadRequestException('Asset is offline');
|
||||
}
|
||||
|
||||
return new ImmichFileResponse({
|
||||
path: asset.originalPath,
|
||||
contentType: mimeTypes.lookup(asset.originalPath),
|
||||
cacheControl: CacheControl.NONE,
|
||||
});
|
||||
}
|
||||
|
||||
async getDownloadInfo(auth: AuthDto, dto: DownloadInfoDto): Promise<DownloadResponseDto> {
|
||||
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
|
||||
const archives: DownloadArchiveInfo[] = [];
|
||||
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
|
||||
|
||||
const assetPagination = await this.getDownloadAssets(auth, dto);
|
||||
for await (const assets of assetPagination) {
|
||||
// motion part of live photos
|
||||
const motionIds = assets.map((asset) => asset.livePhotoVideoId).filter<string>((id): id is string => !!id);
|
||||
if (motionIds.length > 0) {
|
||||
assets.push(...(await this.assetRepository.getByIds(motionIds)));
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
archive.size += Number(asset.exifInfo?.fileSizeInByte || 0);
|
||||
archive.assetIds.push(asset.id);
|
||||
|
||||
if (archive.size > targetSize) {
|
||||
archives.push(archive);
|
||||
archive = { size: 0, assetIds: [] };
|
||||
}
|
||||
}
|
||||
|
||||
if (archive.assetIds.length > 0) {
|
||||
archives.push(archive);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalSize: archives.reduce((total, item) => (total += item.size), 0),
|
||||
archives,
|
||||
};
|
||||
}
|
||||
|
||||
async downloadArchive(auth: AuthDto, dto: AssetIdsDto): Promise<ImmichReadStream> {
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, dto.assetIds);
|
||||
|
||||
const zip = this.storageRepository.createZipStream();
|
||||
const assets = await this.assetRepository.getByIds(dto.assetIds);
|
||||
const paths: Record<string, number> = {};
|
||||
|
||||
for (const { originalPath, originalFileName } of assets) {
|
||||
const ext = extname(originalPath);
|
||||
let filename = `${originalFileName}${ext}`;
|
||||
const count = paths[filename] || 0;
|
||||
paths[filename] = count + 1;
|
||||
if (count !== 0) {
|
||||
filename = `${originalFileName}+${count}${ext}`;
|
||||
}
|
||||
|
||||
zip.addFile(originalPath, filename);
|
||||
}
|
||||
|
||||
void zip.finalize();
|
||||
|
||||
return { stream: zip.stream };
|
||||
}
|
||||
|
||||
private async getDownloadAssets(auth: AuthDto, dto: DownloadInfoDto): Promise<AsyncGenerator<AssetEntity[]>> {
|
||||
const PAGINATION_SIZE = 2500;
|
||||
|
||||
if (dto.assetIds) {
|
||||
const assetIds = dto.assetIds;
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, assetIds);
|
||||
const assets = await this.assetRepository.getByIds(assetIds);
|
||||
return (async function* () {
|
||||
yield assets;
|
||||
})();
|
||||
}
|
||||
|
||||
if (dto.albumId) {
|
||||
const albumId = dto.albumId;
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_DOWNLOAD, albumId);
|
||||
return usePagination(PAGINATION_SIZE, (pagination) => this.assetRepository.getByAlbumId(pagination, albumId));
|
||||
}
|
||||
|
||||
if (dto.userId) {
|
||||
const userId = dto.userId;
|
||||
await this.access.requirePermission(auth, Permission.TIMELINE_DOWNLOAD, userId);
|
||||
return usePagination(PAGINATION_SIZE, (pagination) =>
|
||||
this.assetRepository.getByUserId(pagination, userId, { isVisible: true }),
|
||||
);
|
||||
}
|
||||
|
||||
throw new BadRequestException('assetIds, albumId, or userId is required');
|
||||
}
|
||||
|
||||
async getStatistics(auth: AuthDto, dto: AssetStatsDto) {
|
||||
const stats = await this.assetRepository.getStatistics(auth.user.id, dto);
|
||||
|
@ -2,7 +2,6 @@ export * from './asset-ids.dto';
|
||||
export * from './asset-stack.dto';
|
||||
export * from './asset-statistics.dto';
|
||||
export * from './asset.dto';
|
||||
export * from './download.dto';
|
||||
export * from './map-marker.dto';
|
||||
export * from './memory-lane.dto';
|
||||
export * from './time-bucket.dto';
|
||||
|
@ -7,6 +7,7 @@ import { AssetService } from './asset';
|
||||
import { AuditService } from './audit';
|
||||
import { AuthService } from './auth';
|
||||
import { DatabaseService } from './database';
|
||||
import { DownloadService } from './download';
|
||||
import { JobService } from './job';
|
||||
import { LibraryService } from './library';
|
||||
import { MediaService } from './media';
|
||||
@ -31,6 +32,7 @@ const providers: Provider[] = [
|
||||
AuditService,
|
||||
AuthService,
|
||||
DatabaseService,
|
||||
DownloadService,
|
||||
ImmichLogger,
|
||||
JobService,
|
||||
LibraryService,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsInt, IsPositive } from 'class-validator';
|
||||
import { Optional, ValidateUUID } from '../../domain.util';
|
||||
import { Optional, ValidateUUID } from '../domain.util';
|
||||
|
||||
export class DownloadInfoDto {
|
||||
@ValidateUUID({ each: true, optional: true })
|
219
server/src/domain/download/download.service.spec.ts
Normal file
219
server/src/domain/download/download.service.spec.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import {
|
||||
IAccessRepositoryMock,
|
||||
assetStub,
|
||||
authStub,
|
||||
newAccessRepositoryMock,
|
||||
newAssetRepositoryMock,
|
||||
newStorageRepositoryMock,
|
||||
} from '@test';
|
||||
import { when } from 'jest-when';
|
||||
import { Readable } from 'typeorm/platform/PlatformTools.js';
|
||||
import { CacheControl, ImmichFileResponse } from '../domain.util';
|
||||
import { IAssetRepository, IStorageRepository } from '../repositories';
|
||||
import { DownloadResponseDto } from './download.dto';
|
||||
import { DownloadService } from './download.service';
|
||||
|
||||
const downloadResponse: DownloadResponseDto = {
|
||||
totalSize: 105_000,
|
||||
archives: [
|
||||
{
|
||||
assetIds: ['asset-id', 'asset-id'],
|
||||
size: 105_000,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe(DownloadService.name, () => {
|
||||
let sut: DownloadService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
|
||||
it('should work', () => {
|
||||
expect(sut).toBeDefined();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
assetMock = newAssetRepositoryMock();
|
||||
storageMock = newStorageRepositoryMock();
|
||||
|
||||
sut = new DownloadService(accessMock, assetMock, storageMock);
|
||||
});
|
||||
|
||||
describe('downloadFile', () => {
|
||||
it('should require the asset.download permission', async () => {
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkAlbumAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
});
|
||||
|
||||
it('should throw an error if the asset is not found', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getByIds.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith(['asset-1']);
|
||||
});
|
||||
|
||||
it('should throw an error if the asset is offline', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.offline]);
|
||||
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith(['asset-1']);
|
||||
});
|
||||
|
||||
it('should download a file', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
|
||||
await expect(sut.downloadFile(authStub.admin, 'asset-1')).resolves.toEqual(
|
||||
new ImmichFileResponse({
|
||||
path: '/original/path.jpg',
|
||||
contentType: 'image/jpeg',
|
||||
cacheControl: CacheControl.NONE,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should download an archive', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noWebpPath]);
|
||||
storageMock.createZipStream.mockReturnValue(archiveMock);
|
||||
|
||||
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
|
||||
stream: archiveMock.stream,
|
||||
});
|
||||
|
||||
expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_456.jpg', 'IMG_456.jpg');
|
||||
});
|
||||
|
||||
it('should handle duplicate file names', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noResizePath]);
|
||||
storageMock.createZipStream.mockReturnValue(archiveMock);
|
||||
|
||||
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
|
||||
stream: archiveMock.stream,
|
||||
});
|
||||
|
||||
expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
|
||||
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDownloadInfo', () => {
|
||||
it('should throw an error for an invalid dto', async () => {
|
||||
await expect(sut.getDownloadInfo(authStub.admin, {})).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
|
||||
it('should return a list of archives (assetIds)', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image, assetStub.video]);
|
||||
|
||||
const assetIds = ['asset-1', 'asset-2'];
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { assetIds })).resolves.toEqual(downloadResponse);
|
||||
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith(['asset-1', 'asset-2']);
|
||||
});
|
||||
|
||||
it('should return a list of archives (albumId)', async () => {
|
||||
accessMock.album.checkOwnerAccess.mockResolvedValue(new Set(['album-1']));
|
||||
assetMock.getByAlbumId.mockResolvedValue({
|
||||
items: [assetStub.image, assetStub.video],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { albumId: 'album-1' })).resolves.toEqual(downloadResponse);
|
||||
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['album-1']));
|
||||
expect(assetMock.getByAlbumId).toHaveBeenCalledWith({ take: 2500, skip: 0 }, 'album-1');
|
||||
});
|
||||
|
||||
it('should return a list of archives (userId)', async () => {
|
||||
accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id]));
|
||||
assetMock.getByUserId.mockResolvedValue({
|
||||
items: [assetStub.image, assetStub.video],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { userId: authStub.admin.user.id })).resolves.toEqual(
|
||||
downloadResponse,
|
||||
);
|
||||
|
||||
expect(assetMock.getByUserId).toHaveBeenCalledWith({ take: 2500, skip: 0 }, authStub.admin.user.id, {
|
||||
isVisible: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should split archives by size', async () => {
|
||||
accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id]));
|
||||
|
||||
assetMock.getByUserId.mockResolvedValue({
|
||||
items: [
|
||||
{ ...assetStub.image, id: 'asset-1' },
|
||||
{ ...assetStub.video, id: 'asset-2' },
|
||||
{ ...assetStub.withLocation, id: 'asset-3' },
|
||||
{ ...assetStub.noWebpPath, id: 'asset-4' },
|
||||
],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await expect(
|
||||
sut.getDownloadInfo(authStub.admin, {
|
||||
userId: authStub.admin.user.id,
|
||||
archiveSize: 30_000,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
totalSize: 251_456,
|
||||
archives: [
|
||||
{ assetIds: ['asset-1', 'asset-2'], size: 105_000 },
|
||||
{ assetIds: ['asset-3', 'asset-4'], size: 146_456 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should include the video portion of a live photo', async () => {
|
||||
const assetIds = [assetStub.livePhotoStillAsset.id];
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoStillAsset.id])
|
||||
.mockResolvedValue([assetStub.livePhotoStillAsset]);
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoMotionAsset.id])
|
||||
.mockResolvedValue([assetStub.livePhotoMotionAsset]);
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { assetIds })).resolves.toEqual({
|
||||
totalSize: 125_000,
|
||||
archives: [
|
||||
{
|
||||
assetIds: [assetStub.livePhotoStillAsset.id, assetStub.livePhotoMotionAsset.id],
|
||||
size: 125_000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
129
server/src/domain/download/download.service.ts
Normal file
129
server/src/domain/download/download.service.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import { AssetEntity } from '@app/infra/entities';
|
||||
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
||||
import { extname } from 'path';
|
||||
import { AccessCore, Permission } from '../access';
|
||||
import { AssetIdsDto } from '../asset';
|
||||
import { AuthDto } from '../auth';
|
||||
import { mimeTypes } from '../domain.constant';
|
||||
import { CacheControl, HumanReadableSize, ImmichFileResponse, usePagination } from '../domain.util';
|
||||
import { IAccessRepository, IAssetRepository, IStorageRepository, ImmichReadStream } from '../repositories';
|
||||
import { DownloadArchiveInfo, DownloadInfoDto, DownloadResponseDto } from './download.dto';
|
||||
|
||||
@Injectable()
|
||||
export class DownloadService {
|
||||
private access: AccessCore;
|
||||
|
||||
constructor(
|
||||
@Inject(IAccessRepository) accessRepository: IAccessRepository,
|
||||
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
||||
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
|
||||
) {
|
||||
this.access = AccessCore.create(accessRepository);
|
||||
}
|
||||
|
||||
async downloadFile(auth: AuthDto, id: string): Promise<ImmichFileResponse> {
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, id);
|
||||
|
||||
const [asset] = await this.assetRepository.getByIds([id]);
|
||||
if (!asset) {
|
||||
throw new BadRequestException('Asset not found');
|
||||
}
|
||||
|
||||
if (asset.isOffline) {
|
||||
throw new BadRequestException('Asset is offline');
|
||||
}
|
||||
|
||||
return new ImmichFileResponse({
|
||||
path: asset.originalPath,
|
||||
contentType: mimeTypes.lookup(asset.originalPath),
|
||||
cacheControl: CacheControl.NONE,
|
||||
});
|
||||
}
|
||||
|
||||
async getDownloadInfo(auth: AuthDto, dto: DownloadInfoDto): Promise<DownloadResponseDto> {
|
||||
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
|
||||
const archives: DownloadArchiveInfo[] = [];
|
||||
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
|
||||
|
||||
const assetPagination = await this.getDownloadAssets(auth, dto);
|
||||
for await (const assets of assetPagination) {
|
||||
// motion part of live photos
|
||||
const motionIds = assets.map((asset) => asset.livePhotoVideoId).filter<string>((id): id is string => !!id);
|
||||
if (motionIds.length > 0) {
|
||||
assets.push(...(await this.assetRepository.getByIds(motionIds)));
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
archive.size += Number(asset.exifInfo?.fileSizeInByte || 0);
|
||||
archive.assetIds.push(asset.id);
|
||||
|
||||
if (archive.size > targetSize) {
|
||||
archives.push(archive);
|
||||
archive = { size: 0, assetIds: [] };
|
||||
}
|
||||
}
|
||||
|
||||
if (archive.assetIds.length > 0) {
|
||||
archives.push(archive);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalSize: archives.reduce((total, item) => (total += item.size), 0),
|
||||
archives,
|
||||
};
|
||||
}
|
||||
|
||||
async downloadArchive(auth: AuthDto, dto: AssetIdsDto): Promise<ImmichReadStream> {
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, dto.assetIds);
|
||||
|
||||
const zip = this.storageRepository.createZipStream();
|
||||
const assets = await this.assetRepository.getByIds(dto.assetIds);
|
||||
const paths: Record<string, number> = {};
|
||||
|
||||
for (const { originalPath, originalFileName } of assets) {
|
||||
const ext = extname(originalPath);
|
||||
let filename = `${originalFileName}${ext}`;
|
||||
const count = paths[filename] || 0;
|
||||
paths[filename] = count + 1;
|
||||
if (count !== 0) {
|
||||
filename = `${originalFileName}+${count}${ext}`;
|
||||
}
|
||||
|
||||
zip.addFile(originalPath, filename);
|
||||
}
|
||||
|
||||
void zip.finalize();
|
||||
|
||||
return { stream: zip.stream };
|
||||
}
|
||||
|
||||
private async getDownloadAssets(auth: AuthDto, dto: DownloadInfoDto): Promise<AsyncGenerator<AssetEntity[]>> {
|
||||
const PAGINATION_SIZE = 2500;
|
||||
|
||||
if (dto.assetIds) {
|
||||
const assetIds = dto.assetIds;
|
||||
await this.access.requirePermission(auth, Permission.ASSET_DOWNLOAD, assetIds);
|
||||
const assets = await this.assetRepository.getByIds(assetIds);
|
||||
return (async function* () {
|
||||
yield assets;
|
||||
})();
|
||||
}
|
||||
|
||||
if (dto.albumId) {
|
||||
const albumId = dto.albumId;
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_DOWNLOAD, albumId);
|
||||
return usePagination(PAGINATION_SIZE, (pagination) => this.assetRepository.getByAlbumId(pagination, albumId));
|
||||
}
|
||||
|
||||
if (dto.userId) {
|
||||
const userId = dto.userId;
|
||||
await this.access.requirePermission(auth, Permission.TIMELINE_DOWNLOAD, userId);
|
||||
return usePagination(PAGINATION_SIZE, (pagination) =>
|
||||
this.assetRepository.getByUserId(pagination, userId, { isVisible: true }),
|
||||
);
|
||||
}
|
||||
|
||||
throw new BadRequestException('assetIds, albumId, or userId is required');
|
||||
}
|
||||
}
|
2
server/src/domain/download/index.ts
Normal file
2
server/src/domain/download/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './download.dto';
|
||||
export * from './download.service';
|
@ -10,6 +10,7 @@ export * from './domain.config';
|
||||
export * from './domain.constant';
|
||||
export * from './domain.module';
|
||||
export * from './domain.util';
|
||||
export * from './download';
|
||||
export * from './job';
|
||||
export * from './library';
|
||||
export * from './media';
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
AssetsController,
|
||||
AuditController,
|
||||
AuthController,
|
||||
DownloadController,
|
||||
FaceController,
|
||||
JobController,
|
||||
LibraryController,
|
||||
@ -52,6 +53,7 @@ import { ErrorInterceptor, FileUploadInterceptor } from './interceptors';
|
||||
APIKeyController,
|
||||
AuditController,
|
||||
AuthController,
|
||||
DownloadController,
|
||||
FaceController,
|
||||
JobController,
|
||||
LibraryController,
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
DeviceIdDto,
|
||||
DownloadInfoDto,
|
||||
DownloadResponseDto,
|
||||
DownloadService,
|
||||
MapMarkerDto,
|
||||
MapMarkerResponseDto,
|
||||
MemoryLaneDto,
|
||||
@ -65,7 +66,10 @@ export class AssetsController {
|
||||
@Authenticated()
|
||||
@UseValidation()
|
||||
export class AssetController {
|
||||
constructor(private service: AssetService) {}
|
||||
constructor(
|
||||
private service: AssetService,
|
||||
private downloadService: DownloadService,
|
||||
) {}
|
||||
|
||||
@Get('map-marker')
|
||||
getMapMarkers(@Auth() auth: AuthDto, @Query() options: MapMarkerDto): Promise<MapMarkerResponseDto[]> {
|
||||
@ -82,31 +86,40 @@ export class AssetController {
|
||||
return this.service.getRandom(auth, dto.count ?? 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `/download/info`
|
||||
*/
|
||||
@SharedLinkRoute()
|
||||
@Post('download/info')
|
||||
getDownloadInfo(@Auth() auth: AuthDto, @Body() dto: DownloadInfoDto): Promise<DownloadResponseDto> {
|
||||
return this.service.getDownloadInfo(auth, dto);
|
||||
getDownloadInfoOld(@Auth() auth: AuthDto, @Body() dto: DownloadInfoDto): Promise<DownloadResponseDto> {
|
||||
return this.downloadService.getDownloadInfo(auth, dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `/download/archive`
|
||||
*/
|
||||
@SharedLinkRoute()
|
||||
@Post('download/archive')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@FileResponse()
|
||||
downloadArchive(@Auth() auth: AuthDto, @Body() dto: AssetIdsDto): Promise<StreamableFile> {
|
||||
return this.service.downloadArchive(auth, dto).then(asStreamableFile);
|
||||
downloadArchiveOld(@Auth() auth: AuthDto, @Body() dto: AssetIdsDto): Promise<StreamableFile> {
|
||||
return this.downloadService.downloadArchive(auth, dto).then(asStreamableFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `/download/:id`
|
||||
*/
|
||||
@SharedLinkRoute()
|
||||
@Post('download/:id')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@FileResponse()
|
||||
async downloadFile(
|
||||
async downloadFileOld(
|
||||
@Res() res: Response,
|
||||
@Next() next: NextFunction,
|
||||
@Auth() auth: AuthDto,
|
||||
@Param() { id }: UUIDParamDto,
|
||||
) {
|
||||
await sendFile(res, next, () => this.service.downloadFile(auth, id));
|
||||
await sendFile(res, next, () => this.downloadService.downloadFile(auth, id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
42
server/src/immich/controllers/download.controller.ts
Normal file
42
server/src/immich/controllers/download.controller.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { AssetIdsDto, AuthDto, DownloadInfoDto, DownloadResponseDto, DownloadService } from '@app/domain';
|
||||
import { Body, Controller, HttpCode, HttpStatus, Next, Param, Post, Res, StreamableFile } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { NextFunction, Response } from 'express';
|
||||
import { Auth, Authenticated, FileResponse, SharedLinkRoute } from '../app.guard';
|
||||
import { UseValidation, asStreamableFile, sendFile } from '../app.utils';
|
||||
import { UUIDParamDto } from './dto/uuid-param.dto';
|
||||
|
||||
@ApiTags('Download')
|
||||
@Controller('download')
|
||||
@Authenticated()
|
||||
@UseValidation()
|
||||
export class DownloadController {
|
||||
constructor(private service: DownloadService) {}
|
||||
|
||||
@SharedLinkRoute()
|
||||
@Post('info')
|
||||
getDownloadInfo(@Auth() auth: AuthDto, @Body() dto: DownloadInfoDto): Promise<DownloadResponseDto> {
|
||||
return this.service.getDownloadInfo(auth, dto);
|
||||
}
|
||||
|
||||
@SharedLinkRoute()
|
||||
@Post('archive')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@FileResponse()
|
||||
downloadArchive(@Auth() auth: AuthDto, @Body() dto: AssetIdsDto): Promise<StreamableFile> {
|
||||
return this.service.downloadArchive(auth, dto).then(asStreamableFile);
|
||||
}
|
||||
|
||||
@SharedLinkRoute()
|
||||
@Post('asset/:id')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@FileResponse()
|
||||
async downloadFile(
|
||||
@Res() res: Response,
|
||||
@Next() next: NextFunction,
|
||||
@Auth() auth: AuthDto,
|
||||
@Param() { id }: UUIDParamDto,
|
||||
) {
|
||||
await sendFile(res, next, () => this.service.downloadFile(auth, id));
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ export * from './app.controller';
|
||||
export * from './asset.controller';
|
||||
export * from './audit.controller';
|
||||
export * from './auth.controller';
|
||||
export * from './download.controller';
|
||||
export * from './face.controller';
|
||||
export * from './job.controller';
|
||||
export * from './library.controller';
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
AssetJobName,
|
||||
AuditApi,
|
||||
AuthenticationApi,
|
||||
DownloadApi,
|
||||
FaceApi,
|
||||
JobApi,
|
||||
JobName,
|
||||
@ -29,6 +30,7 @@ import type { ApiParams } from './types';
|
||||
class ImmichApi {
|
||||
public activityApi: ActivityApi;
|
||||
public albumApi: AlbumApi;
|
||||
public downloadApi: DownloadApi;
|
||||
public libraryApi: LibraryApi;
|
||||
public assetApi: AssetApi;
|
||||
public auditApi: AuditApi;
|
||||
@ -58,6 +60,7 @@ class ImmichApi {
|
||||
this.activityApi = new ActivityApi(this.config);
|
||||
this.albumApi = new AlbumApi(this.config);
|
||||
this.auditApi = new AuditApi(this.config);
|
||||
this.downloadApi = new DownloadApi(this.config);
|
||||
this.libraryApi = new LibraryApi(this.config);
|
||||
this.assetApi = new AssetApi(this.config);
|
||||
this.authenticationApi = new AuthenticationApi(this.config);
|
||||
|
@ -47,7 +47,7 @@ export const downloadArchive = async (fileName: string, options: DownloadInfoDto
|
||||
let downloadInfo: DownloadResponseDto | null = null;
|
||||
|
||||
try {
|
||||
const { data } = await api.assetApi.getDownloadInfo({ downloadInfoDto: options, key: api.getKey() });
|
||||
const { data } = await api.downloadApi.getDownloadInfo({ downloadInfoDto: options, key: api.getKey() });
|
||||
downloadInfo = data;
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to download files');
|
||||
@ -71,7 +71,7 @@ export const downloadArchive = async (fileName: string, options: DownloadInfoDto
|
||||
downloadManager.add(downloadKey, archive.size, abort);
|
||||
|
||||
try {
|
||||
const { data } = await api.assetApi.downloadArchive(
|
||||
const { data } = await api.downloadApi.downloadArchive(
|
||||
{ assetIdsDto: { assetIds: archive.assetIds }, key: api.getKey() },
|
||||
{
|
||||
responseType: 'blob',
|
||||
@ -121,7 +121,7 @@ export const downloadFile = async (asset: AssetResponseDto) => {
|
||||
const abort = new AbortController();
|
||||
downloadManager.add(downloadKey, size, abort);
|
||||
|
||||
const { data } = await api.assetApi.downloadFile(
|
||||
const { data } = await api.downloadApi.downloadFile(
|
||||
{ id, key: api.getKey() },
|
||||
{
|
||||
responseType: 'blob',
|
||||
|
Loading…
x
Reference in New Issue
Block a user