refactor(server): download assets (#3032)

* refactor: download assets

* chore: open api

* chore: finish tests, make size configurable

* chore: defualt to 4GiB

* chore: open api

* fix: optional archive size

* fix: bugs

* chore: cleanup
This commit is contained in:
Jason Rasmussen
2023-06-30 12:24:28 -04:00
committed by GitHub
parent df9c05bef3
commit ad343b7b32
53 changed files with 1455 additions and 1403 deletions

View File

@@ -81,7 +81,8 @@ part 'model/curated_objects_response_dto.dart';
part 'model/delete_asset_dto.dart';
part 'model/delete_asset_response_dto.dart';
part 'model/delete_asset_status.dart';
part 'model/download_files_dto.dart';
part 'model/download_archive_info.dart';
part 'model/download_response_dto.dart';
part 'model/exif_response_dto.dart';
part 'model/get_asset_by_time_bucket_dto.dart';
part 'model/get_asset_count_by_time_bucket_dto.dart';

View File

@@ -215,76 +215,6 @@ class AlbumApi {
}
}
/// Performs an HTTP 'GET /album/{id}/download' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
///
/// * [String] name:
///
/// * [num] skip:
///
/// * [String] key:
Future<Response> downloadArchiveWithHttpInfo(String id, { String? name, num? skip, String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/album/{id}/download'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (name != null) {
queryParams.addAll(_queryParams('', 'name', name));
}
if (skip != null) {
queryParams.addAll(_queryParams('', 'skip', skip));
}
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
///
/// * [String] name:
///
/// * [num] skip:
///
/// * [String] key:
Future<MultipartFile?> downloadArchive(String id, { String? name, num? skip, String? key, }) async {
final response = await downloadArchiveWithHttpInfo(id, name: name, skip: skip, 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 'GET /album/count' operation and returns the [Response].
Future<Response> getAlbumCountWithHttpInfo() async {
// ignore: prefer_const_declarations

View File

@@ -230,7 +230,62 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'GET /asset/download/{id}' operation and returns the [Response].
/// Performs an HTTP 'POST /asset/download' 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'/asset/download';
// 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 /asset/download/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -257,7 +312,7 @@ class AssetApi {
return apiClient.invokeAPI(
path,
'GET',
'POST',
queryParams,
postBody,
headerParams,
@@ -286,131 +341,6 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'POST /asset/download-files' operation and returns the [Response].
/// Parameters:
///
/// * [DownloadFilesDto] downloadFilesDto (required):
///
/// * [String] key:
Future<Response> downloadFilesWithHttpInfo(DownloadFilesDto downloadFilesDto, { String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/download-files';
// ignore: prefer_final_locals
Object? postBody = downloadFilesDto;
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:
///
/// * [DownloadFilesDto] downloadFilesDto (required):
///
/// * [String] key:
Future<MultipartFile?> downloadFiles(DownloadFilesDto downloadFilesDto, { String? key, }) async {
final response = await downloadFilesWithHttpInfo(downloadFilesDto, 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;
}
/// Current this is not used in any UI element
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] name:
///
/// * [num] skip:
///
/// * [String] key:
Future<Response> downloadLibraryWithHttpInfo({ String? name, num? skip, String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/download-library';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (name != null) {
queryParams.addAll(_queryParams('', 'name', name));
}
if (skip != null) {
queryParams.addAll(_queryParams('', 'skip', skip));
}
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Current this is not used in any UI element
///
/// Parameters:
///
/// * [String] name:
///
/// * [num] skip:
///
/// * [String] key:
Future<MultipartFile?> downloadLibrary({ String? name, num? skip, String? key, }) async {
final response = await downloadLibraryWithHttpInfo( name: name, skip: skip, 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;
}
/// Get all AssetEntity belong to the user
///
/// Note: This method returns the HTTP [Response].
@@ -945,6 +875,85 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'GET /asset/download' operation and returns the [Response].
/// Parameters:
///
/// * [List<String>] assetIds:
///
/// * [String] albumId:
///
/// * [String] userId:
///
/// * [num] archiveSize:
///
/// * [String] key:
Future<Response> getDownloadInfoWithHttpInfo({ List<String>? assetIds, String? albumId, String? userId, num? archiveSize, String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/download';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (assetIds != null) {
queryParams.addAll(_queryParams('multi', 'assetIds', assetIds));
}
if (albumId != null) {
queryParams.addAll(_queryParams('', 'albumId', albumId));
}
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
if (archiveSize != null) {
queryParams.addAll(_queryParams('', 'archiveSize', archiveSize));
}
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [List<String>] assetIds:
///
/// * [String] albumId:
///
/// * [String] userId:
///
/// * [num] archiveSize:
///
/// * [String] key:
Future<DownloadResponseDto?> getDownloadInfo({ List<String>? assetIds, String? albumId, String? userId, num? archiveSize, String? key, }) async {
final response = await getDownloadInfoWithHttpInfo( assetIds: assetIds, albumId: albumId, userId: userId, archiveSize: archiveSize, 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;
}
/// Performs an HTTP 'GET /asset/map-marker' operation and returns the [Response].
/// Parameters:
///

View File

@@ -257,8 +257,10 @@ class ApiClient {
return DeleteAssetResponseDto.fromJson(value);
case 'DeleteAssetStatus':
return DeleteAssetStatusTypeTransformer().decode(value);
case 'DownloadFilesDto':
return DownloadFilesDto.fromJson(value);
case 'DownloadArchiveInfo':
return DownloadArchiveInfo.fromJson(value);
case 'DownloadResponseDto':
return DownloadResponseDto.fromJson(value);
case 'ExifResponseDto':
return ExifResponseDto.fromJson(value);
case 'GetAssetByTimeBucketDto':

View File

@@ -10,40 +10,47 @@
part of openapi.api;
class DownloadFilesDto {
/// Returns a new [DownloadFilesDto] instance.
DownloadFilesDto({
class DownloadArchiveInfo {
/// Returns a new [DownloadArchiveInfo] instance.
DownloadArchiveInfo({
required this.size,
this.assetIds = const [],
});
int size;
List<String> assetIds;
@override
bool operator ==(Object other) => identical(this, other) || other is DownloadFilesDto &&
bool operator ==(Object other) => identical(this, other) || other is DownloadArchiveInfo &&
other.size == size &&
other.assetIds == assetIds;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(size.hashCode) +
(assetIds.hashCode);
@override
String toString() => 'DownloadFilesDto[assetIds=$assetIds]';
String toString() => 'DownloadArchiveInfo[size=$size, assetIds=$assetIds]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'size'] = this.size;
json[r'assetIds'] = this.assetIds;
return json;
}
/// Returns a new [DownloadFilesDto] instance and imports its values from
/// Returns a new [DownloadArchiveInfo] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static DownloadFilesDto? fromJson(dynamic value) {
static DownloadArchiveInfo? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return DownloadFilesDto(
return DownloadArchiveInfo(
size: mapValueOfType<int>(json, r'size')!,
assetIds: json[r'assetIds'] is Iterable
? (json[r'assetIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
@@ -52,11 +59,11 @@ class DownloadFilesDto {
return null;
}
static List<DownloadFilesDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <DownloadFilesDto>[];
static List<DownloadArchiveInfo> listFromJson(dynamic json, {bool growable = false,}) {
final result = <DownloadArchiveInfo>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = DownloadFilesDto.fromJson(row);
final value = DownloadArchiveInfo.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -65,12 +72,12 @@ class DownloadFilesDto {
return result.toList(growable: growable);
}
static Map<String, DownloadFilesDto> mapFromJson(dynamic json) {
final map = <String, DownloadFilesDto>{};
static Map<String, DownloadArchiveInfo> mapFromJson(dynamic json) {
final map = <String, DownloadArchiveInfo>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = DownloadFilesDto.fromJson(entry.value);
final value = DownloadArchiveInfo.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -79,14 +86,14 @@ class DownloadFilesDto {
return map;
}
// maps a json object with a list of DownloadFilesDto-objects as value to a dart map
static Map<String, List<DownloadFilesDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<DownloadFilesDto>>{};
// maps a json object with a list of DownloadArchiveInfo-objects as value to a dart map
static Map<String, List<DownloadArchiveInfo>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<DownloadArchiveInfo>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = DownloadFilesDto.listFromJson(entry.value, growable: growable,);
map[entry.key] = DownloadArchiveInfo.listFromJson(entry.value, growable: growable,);
}
}
return map;
@@ -94,6 +101,7 @@ class DownloadFilesDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'size',
'assetIds',
};
}

View File

@@ -0,0 +1,106 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class DownloadResponseDto {
/// Returns a new [DownloadResponseDto] instance.
DownloadResponseDto({
required this.totalSize,
this.archives = const [],
});
int totalSize;
List<DownloadArchiveInfo> archives;
@override
bool operator ==(Object other) => identical(this, other) || other is DownloadResponseDto &&
other.totalSize == totalSize &&
other.archives == archives;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(totalSize.hashCode) +
(archives.hashCode);
@override
String toString() => 'DownloadResponseDto[totalSize=$totalSize, archives=$archives]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'totalSize'] = this.totalSize;
json[r'archives'] = this.archives;
return json;
}
/// Returns a new [DownloadResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static DownloadResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return DownloadResponseDto(
totalSize: mapValueOfType<int>(json, r'totalSize')!,
archives: DownloadArchiveInfo.listFromJson(json[r'archives']),
);
}
return null;
}
static List<DownloadResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <DownloadResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = DownloadResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, DownloadResponseDto> mapFromJson(dynamic json) {
final map = <String, DownloadResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = DownloadResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of DownloadResponseDto-objects as value to a dart map
static Map<String, List<DownloadResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<DownloadResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = DownloadResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'totalSize',
'archives',
};
}