From cf1cd4ad40af88647b4297dc917daaf6d4bf5c78 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:54:27 -0700 Subject: [PATCH] chore: update download apis to use path (#4561) * chore: add `StoragePath` * chore: add `S3PathResolver` * chore: update `getUrl` and `getProperties` API * chore: update S3UploadTask * chore: fix tests * chore: validate storage path * chore: add tests for S3PathResolver * feat: Gen 2 Upload APIs (#4542) * feat: add path parameter and made key optional Co-Authored-By: Jordan Nelson <20613561+Jordan-Nelson@users.noreply.github.com> * chore: added/modified unit tests and added a missing deprecation tag Co-Authored-By: Jordan Nelson <20613561+Jordan-Nelson@users.noreply.github.com> * chore: added extra assert statement to make sure users don't put in both path and key into upload method Co-Authored-By: Jordan Nelson <20613561+Jordan-Nelson@users.noreply.github.com> * chore: add ignore statements to ignore key deprecated warnings * chore: add ignore statements for deprecated members --------- Co-authored-by: Jordan Nelson <20613561+Jordan-Nelson@users.noreply.github.com> * chore: refactor StoragePath (#4544) * chore: remove `key` from public APIs * chore: update tests to adjust for using path * chore: fix lint issues * chore: fix formatting * chore: fix test * chore: remove lint ignored * chore: update comment * chore: remove unused method * chore: update download apis to use path * chore: skip tests other than main * chore: run dart format on both files that are receiving analyze warnings * chore: used dart fix to add trailing commas * chore: fixed formatting * chore: run format on test files * chore: fix formatting in integration tests * chore: update generated code * chore: add leading `/` * chore: remove access level from e2e test * fix(auth): device metadata migration (#4503) * merge main * chore: added a bracket and removed new keywords * chore: changed signature of deleteLegacyDeviceSecrets and regenerated pigeons. Changed legacysecrethandler.kt file to .txt to "comment" it out * chore: run dart format on generated file * chore: migrateLegacyDeviceSecrets now gets called before deleteLegacyCredentials. Cognito_device_secrets return type fixed * chore: add delete and fetch methods to the cognito swift file * fix: various issues with implementation * chore: fix lint issues * test: update test to include mfa and token refresh * chore: use coroutines, add plugin * chore: remove generate code in iOS * chore: fetch asf deviceId from shared prefs directly * chore: update error name * chore: remove native auth plugin * chore: remove old legacy handler * chore: remove check for null device metadata * chore: flatten nested if statements * chore: remove unused type --------- Co-authored-by: Kha Truong <64438356+khatruong2009@users.noreply.github.com> * fix(auth): Allow retries with verifyTotpSetup() (#4532) * chore(version): cherry pick Bump version (#4545) * fix(auth): verifyTotp throw EnableSoftwareTokenMfaException (#4558) * chore(version): cherry pick Bump version (#4560) * chore: Update BUG-REPORT.yaml (#4568) * fix: correct `package_info_plus` version constraint (#4583) chore: fix version constraint * feat(storage): copy and move APIs (#4569) * chore: update copy api * chore: update integ tests for copy * chore: removed unused code * chore: add back test * chore: update download apis to use path * chore: remove duplicate code from rebase * chore: removed random text file * chore: remove commented code * chore: fix failing tests * chore: update options, tests * chore: update options classes * chore: add back temp dir * chore: fix integ test * chore: add skip back to io specific test * chore: skip test set up in configs other than main --------- Co-authored-by: Jordan Nelson Co-authored-by: Jordan Nelson <20613561+Jordan-Nelson@users.noreply.github.com> Co-authored-by: Jordan Nelson Co-authored-by: Elijah Quartey --- .../category/amplify_storage_category.dart | 12 +- .../amplify_storage_plugin_interface.dart | 4 +- .../types/storage/download_data_request.dart | 6 +- .../types/storage/download_file_options.dart | 4 +- .../types/storage/download_file_request.dart | 6 +- .../transfer_acceleration.dart | 14 +- .../integration_test/use_case_test.dart | 47 +++-- .../amplify_storage_s3/example/lib/main.dart | 4 +- .../example/bin/example.dart | 8 +- .../lib/src/amplify_storage_s3_dart_impl.dart | 12 +- .../src/model/s3_download_data_options.dart | 27 --- .../s3_download_data_plugin_options.dart | 24 --- .../src/model/s3_download_file_options.dart | 28 --- .../s3_download_file_plugin_options.dart | 22 --- .../download_file/download_file_html.dart | 47 ++--- .../download_file/download_file_io.dart | 26 +-- .../download_file/download_file_stub.dart | 2 +- .../service/storage_s3_service_impl.dart | 8 +- .../service/task/s3_download_task.dart | 44 ++--- .../test/amplify_storage_s3_dart_test.dart | 22 ++- .../download_file_html_test.dart | 73 ++----- .../platform_impl/download_file_io_test.dart | 180 ++++-------------- .../task/s3_download_task_test.dart | 95 +++------ 23 files changed, 193 insertions(+), 522 deletions(-) diff --git a/packages/amplify_core/lib/src/category/amplify_storage_category.dart b/packages/amplify_core/lib/src/category/amplify_storage_category.dart index 87e2913c7e..cfc6683b0b 100644 --- a/packages/amplify_core/lib/src/category/amplify_storage_category.dart +++ b/packages/amplify_core/lib/src/category/amplify_storage_category.dart @@ -91,7 +91,7 @@ class StorageCategory extends AmplifyCategory { } /// {@template amplify_core.amplify_storage_category.download_data} - /// Downloads bytes of object specified by [key] into memory with optional + /// Downloads bytes of object specified by [path] into memory with optional /// [onProgress] and [StorageDownloadDataOptions], and returns a /// [StorageDownloadDataOperation]. /// @@ -99,14 +99,14 @@ class StorageCategory extends AmplifyCategory { /// memory leaks. /// {@endtemplate} StorageDownloadDataOperation downloadData({ - required String key, + required StoragePath path, void Function(StorageTransferProgress)? onProgress, StorageDownloadDataOptions? options, }) { return identifyCall( StorageCategoryMethod.downloadData, () => defaultPlugin.downloadData( - key: key, + path: path, onProgress: onProgress, options: options, ), @@ -114,12 +114,12 @@ class StorageCategory extends AmplifyCategory { } /// {@template amplify_core.amplify_storage_category.download_file} - /// Downloads the object specified by [key] to [localFile] with optional + /// Downloads the object specified by [path] to [localFile] with optional /// [onProgress] and [StorageDownloadFileOptions], and returns a /// [StorageDownloadFileOperation]. /// {@endtemplate} StorageDownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, void Function(StorageTransferProgress)? onProgress, StorageDownloadFileOptions? options, @@ -127,7 +127,7 @@ class StorageCategory extends AmplifyCategory { return identifyCall( StorageCategoryMethod.downloadFile, () => defaultPlugin.downloadFile( - key: key, + path: path, localFile: localFile, onProgress: onProgress, options: options, diff --git a/packages/amplify_core/lib/src/plugin/amplify_storage_plugin_interface.dart b/packages/amplify_core/lib/src/plugin/amplify_storage_plugin_interface.dart index 5dff8be3d6..c845baf526 100644 --- a/packages/amplify_core/lib/src/plugin/amplify_storage_plugin_interface.dart +++ b/packages/amplify_core/lib/src/plugin/amplify_storage_plugin_interface.dart @@ -40,7 +40,7 @@ abstract class StoragePluginInterface extends AmplifyPluginInterface { /// {@macro amplify_core.amplify_storage_category.download_data} StorageDownloadDataOperation downloadData({ - required String key, + required StoragePath path, void Function(StorageTransferProgress)? onProgress, StorageDownloadDataOptions? options, }) { @@ -49,7 +49,7 @@ abstract class StoragePluginInterface extends AmplifyPluginInterface { /// {@macro amplify_core.amplify_storage_category.download_file} StorageDownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, void Function(StorageTransferProgress)? onProgress, StorageDownloadFileOptions? options, diff --git a/packages/amplify_core/lib/src/types/storage/download_data_request.dart b/packages/amplify_core/lib/src/types/storage/download_data_request.dart index 3f5bcb9525..5a2ca3c730 100644 --- a/packages/amplify_core/lib/src/types/storage/download_data_request.dart +++ b/packages/amplify_core/lib/src/types/storage/download_data_request.dart @@ -9,12 +9,12 @@ import 'package:amplify_core/amplify_core.dart'; class StorageDownloadDataRequest { /// {@macro amplify_core.storage.download_data_request} const StorageDownloadDataRequest({ - required this.key, + required this.path, this.options, }); - /// Key of the object to download. - final String key; + /// Path of the object to download. + final StoragePath path; /// Configurable options of the [StorageDownloadDataRequest]. final StorageDownloadDataOptions? options; diff --git a/packages/amplify_core/lib/src/types/storage/download_file_options.dart b/packages/amplify_core/lib/src/types/storage/download_file_options.dart index 7153e701df..bb131f4e53 100644 --- a/packages/amplify_core/lib/src/types/storage/download_file_options.dart +++ b/packages/amplify_core/lib/src/types/storage/download_file_options.dart @@ -14,7 +14,6 @@ class StorageDownloadFileOptions extends StorageOperationOptions AWSDebuggable { /// {@macro amplify_core.storage.download_file_options} const StorageDownloadFileOptions({ - super.accessLevel, this.pluginOptions, }); @@ -22,14 +21,13 @@ class StorageDownloadFileOptions extends StorageOperationOptions final StorageDownloadFilePluginOptions? pluginOptions; @override - List get props => [accessLevel, pluginOptions]; + List get props => [pluginOptions]; @override String get runtimeTypeName => 'StorageDownloadFileOptions'; @override Map toJson() => { - 'accessLevel': accessLevel?.name, 'pluginOptions': pluginOptions?.toJson(), }; } diff --git a/packages/amplify_core/lib/src/types/storage/download_file_request.dart b/packages/amplify_core/lib/src/types/storage/download_file_request.dart index 55cd835b13..c2457e02c5 100644 --- a/packages/amplify_core/lib/src/types/storage/download_file_request.dart +++ b/packages/amplify_core/lib/src/types/storage/download_file_request.dart @@ -9,13 +9,13 @@ import 'package:amplify_core/amplify_core.dart'; class StorageDownloadFileRequest { /// {@macro amplify_core.storage.download_file_request} const StorageDownloadFileRequest({ - required this.key, + required this.path, required this.localFile, this.options, }); - /// Key of the object to download. - final String key; + /// Path of the object to download. + final StoragePath path; /// Reference to the local file that download the object to. final AWSFile localFile; diff --git a/packages/storage/amplify_storage_s3/example/integration_test/transfer_acceleration/transfer_acceleration.dart b/packages/storage/amplify_storage_s3/example/integration_test/transfer_acceleration/transfer_acceleration.dart index 144c9dbacf..c4817ba313 100644 --- a/packages/storage/amplify_storage_s3/example/integration_test/transfer_acceleration/transfer_acceleration.dart +++ b/packages/storage/amplify_storage_s3/example/integration_test/transfer_acceleration/transfer_acceleration.dart @@ -72,10 +72,11 @@ void testTransferAcceleration({ test('S3DataPayload ${entry.key}', () async { final dataPayload = entry.value; final result = await Amplify.Storage.downloadData( - key: dataPayload.targetKey, - options: StorageDownloadDataOptions( - accessLevel: dataPayload.targetAccessLevel, - pluginOptions: const S3DownloadDataPluginOptions( + path: StoragePath.fromString( + '/${dataPayload.targetAccessLevel}/${dataPayload.targetKey}', + ), + options: const StorageDownloadDataOptions( + pluginOptions: S3DownloadDataPluginOptions( useAccelerateEndpoint: true, ), ), @@ -156,9 +157,10 @@ void testTransferAcceleration({ const end = 5 * 1024 + 12; final awsFile = entry.value; final result = await Amplify.Storage.downloadData( - key: awsFile.targetKey, + path: StoragePath.fromString( + '${awsFile.targetAccessLevel}/${awsFile.targetKey}', + ), options: StorageDownloadDataOptions( - accessLevel: awsFile.targetAccessLevel, pluginOptions: S3DownloadDataPluginOptions( useAccelerateEndpoint: true, bytesRange: S3DataBytesRange(start: start, end: end), diff --git a/packages/storage/amplify_storage_s3/example/integration_test/use_case_test.dart b/packages/storage/amplify_storage_s3/example/integration_test/use_case_test.dart index 3fbb0cd447..44870608cc 100644 --- a/packages/storage/amplify_storage_s3/example/integration_test/use_case_test.dart +++ b/packages/storage/amplify_storage_s3/example/integration_test/use_case_test.dart @@ -64,11 +64,10 @@ void main() { const testObjectFileName2 = 'user1Protected.jpg'; const testObjectFileName3 = 'user1Private.large'; - for (final entry in amplifyEnvironments.entries) { - group( - // TODO(Jordan-Nelson): enable dots-in-name, remove custom-prefix - skip: entry.key != 'main', - '[Environment ${entry.key}]', () { + // TODO(Jordan-Nelson): enable dots-in-name, remove custom-prefix + for (final entry in amplifyEnvironments.entries + .where((element) => element.key == 'main')) { + group('[Environment ${entry.key}]', () { S3PrefixResolver? prefixResolver; late String user1IdentityId; late String object1Etag; @@ -320,13 +319,13 @@ void main() { }); testWidgets( - skip: true, 'download object as bytes data in memory with access level private' ' for the currently signed in user', (WidgetTester tester) async { final result = await Amplify.Storage.downloadData( - key: testObjectKey3, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testObjectKey3', + ), options: const StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadDataPluginOptions( getProperties: true, ), @@ -338,15 +337,15 @@ void main() { }); testWidgets( - skip: true, 'download a range of bytes of an object with access level private' ' for the currently signed in user', (WidgetTester tester) async { const start = 5 * 1024; const end = 5 * 1024 + 12; final result = await Amplify.Storage.downloadData( - key: testObjectKey3, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testObjectKey3', + ), options: StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadDataPluginOptions( getProperties: true, bytesRange: S3DataBytesRange( @@ -366,7 +365,6 @@ void main() { }); testWidgets( - skip: true, 'download file with access level private for the currently signed in user', (WidgetTester tester) async { final s3Plugin = @@ -377,10 +375,11 @@ void main() { final result = await s3Plugin .downloadFile( - key: testObjectKey3, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testObjectKey3', + ), localFile: localFile, options: const StorageDownloadFileOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadFilePluginOptions( getProperties: true, ), @@ -396,8 +395,7 @@ void main() { }, // Web download relies on getUrl which has been covered in the getUrl // integration test run. - // TODO(khatruong2009): Re-enable this test after download apis completed. - // skip: zIsWeb, + skip: zIsWeb, ); testWidgets( @@ -618,16 +616,15 @@ void main() { }); testWidgets( - skip: true, 'download data of object with access level protected and a target' ' identity id for the currently signed user', (WidgetTester tester) async { final result = await Amplify.Storage.downloadData( - key: testObjectKey2, - options: StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.protected, - pluginOptions: S3DownloadDataPluginOptions.forIdentity( - user1IdentityId, + path: StoragePath.fromString( + '/protected/$user1IdentityId/$testObjectKey2', + ), + options: const StorageDownloadDataOptions( + pluginOptions: S3DownloadDataPluginOptions( getProperties: true, ), ), @@ -637,14 +634,14 @@ void main() { }); testWidgets( - skip: true, 'download data of object (belongs to other user) with access level' ' private for the currently signed user', (WidgetTester tester) async { final operation = Amplify.Storage.downloadData( - key: testObjectKey3, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testObjectKey3', + ), options: const StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadDataPluginOptions( getProperties: true, ), diff --git a/packages/storage/amplify_storage_s3/example/lib/main.dart b/packages/storage/amplify_storage_s3/example/lib/main.dart index 94bae65d3d..2329e81f58 100644 --- a/packages/storage/amplify_storage_s3/example/lib/main.dart +++ b/packages/storage/amplify_storage_s3/example/lib/main.dart @@ -181,7 +181,7 @@ class _HomeScreenState extends State { final filepath = '${documentsDir.path}/$key'; try { await Amplify.Storage.downloadFile( - key: key, + path: StoragePath.fromString(key), localFile: AWSFile.fromPath(filepath), onProgress: (p0) => _logger .debug('Progress: ${(p0.transferredBytes / p0.totalBytes) * 100}%'), @@ -196,7 +196,7 @@ class _HomeScreenState extends State { Future downloadFileWeb(String key) async { try { await Amplify.Storage.downloadFile( - key: key, + path: StoragePath.fromString(key), localFile: AWSFile.fromPath(key), onProgress: (p0) => _logger .debug('Progress: ${(p0.transferredBytes / p0.totalBytes) * 100}%'), diff --git a/packages/storage/amplify_storage_s3_dart/example/bin/example.dart b/packages/storage/amplify_storage_s3_dart/example/bin/example.dart index 335667be33..ca18ef86f8 100644 --- a/packages/storage/amplify_storage_s3_dart/example/bin/example.dart +++ b/packages/storage/amplify_storage_s3_dart/example/bin/example.dart @@ -207,7 +207,7 @@ Future downloadDataOperation() async { final s3Plugin = Amplify.Storage.getPlugin(AmplifyStorageS3Dart.pluginKey); final downloadDataOperation = s3Plugin.downloadData( - key: key, + path: StoragePath.fromString(key), options: StorageDownloadDataOptions( accessLevel: accessLevel, pluginOptions: const S3DownloadDataPluginOptions( @@ -239,9 +239,6 @@ Future downloadDataOperation() async { Future downloadFileOperation() async { final key = prompt('Enter the key of the object to download: '); - final accessLevel = promptStorageAccessLevel( - 'Choose the storage access level associated with the object: ', - ); final destinationPath = prompt( 'Enter the destination file path (ensure the file path is writable): ', ); @@ -251,10 +248,9 @@ Future downloadFileOperation() async { final s3Plugin = Amplify.Storage.getPlugin(AmplifyStorageS3Dart.pluginKey); final downloadFileOperation = s3Plugin.downloadFile( - key: key, + path: StoragePath.fromString(key), localFile: localFile, options: StorageDownloadFileOptions( - accessLevel: accessLevel, pluginOptions: S3DownloadFilePluginOptions( getProperties: true, useAccelerateEndpoint: useAccelerateEndpoint, diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/amplify_storage_s3_dart_impl.dart b/packages/storage/amplify_storage_s3_dart/lib/src/amplify_storage_s3_dart_impl.dart index c12f56058a..8759030944 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/amplify_storage_s3_dart_impl.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/amplify_storage_s3_dart_impl.dart @@ -222,7 +222,7 @@ class AmplifyStorageS3Dart extends StoragePluginInterface @override S3DownloadDataOperation downloadData({ - required String key, + required StoragePath path, StorageDownloadDataOptions? options, void Function(S3TransferProgress)? onProgress, }) { @@ -232,13 +232,12 @@ class AmplifyStorageS3Dart extends StoragePluginInterface ); final s3Options = StorageDownloadDataOptions( - accessLevel: options?.accessLevel, pluginOptions: s3PluginOptions, ); final bytes = BytesBuilder(); final downloadTask = storageS3Service.downloadData( - key: key, + path: path, options: s3Options, onProgress: onProgress, onData: bytes.add, @@ -246,7 +245,7 @@ class AmplifyStorageS3Dart extends StoragePluginInterface return S3DownloadDataOperation( request: StorageDownloadDataRequest( - key: key, + path: path, options: options, ), result: downloadTask.result.then( @@ -263,7 +262,7 @@ class AmplifyStorageS3Dart extends StoragePluginInterface @override S3DownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, void Function(S3TransferProgress)? onProgress, StorageDownloadFileOptions? options, @@ -273,11 +272,10 @@ class AmplifyStorageS3Dart extends StoragePluginInterface defaultPluginOptions: const S3DownloadFilePluginOptions(), ); options = StorageDownloadFileOptions( - accessLevel: options?.accessLevel, pluginOptions: s3PluginOptions, ); return download_file_impl.downloadFile( - key: key, + path: path, localFile: localFile, options: options, s3pluginConfig: s3pluginConfig, diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_options.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_options.dart index 87e99bb7fc..291d12afca 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_options.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_options.dart @@ -33,39 +33,12 @@ class S3DownloadDataOptions extends StorageDownloadDataOptions { super.accessLevel = StorageAccessLevel.guest, this.getProperties = false, this.bytesRange, - this.targetIdentityId, this.useAccelerateEndpoint = false, }); - /// {@macro storage.amplify_storage_s3.download_data_options} - /// - /// Use this when calling `downloadData` on an object that belongs to another - /// user (identified by [targetIdentityId]) rather than the currently - /// signed-in user. - @Deprecated( - 'use StorageDownloadDataOptions(pluginOptions:S3DownloadDataPluginOptions(...)) instead.', - ) - const S3DownloadDataOptions.forIdentity( - String targetIdentityId, { - bool getProperties = false, - S3DataBytesRange? bytesRange, - bool useAccelerateEndpoint = false, - }) : this._( - accessLevel: StorageAccessLevel.protected, - targetIdentityId: targetIdentityId, - getProperties: getProperties, - bytesRange: bytesRange, - useAccelerateEndpoint: useAccelerateEndpoint, - ); - /// The byte range to download from the object. final S3DataBytesRange? bytesRange; - /// The identity ID of another user who uploaded the object. - /// - /// This can be set by using [S3DownloadDataOptions.forIdentity]. - final String? targetIdentityId; - /// Whether to retrieve properties for the downloaded object using the /// `getProperties` API. final bool getProperties; diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_plugin_options.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_plugin_options.dart index 526ebdb757..d86a188b36 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_plugin_options.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_data_plugin_options.dart @@ -25,27 +25,9 @@ class S3DownloadDataPluginOptions extends StorageDownloadDataPluginOptions { const S3DownloadDataPluginOptions._({ this.getProperties = false, this.bytesRange, - this.targetIdentityId, this.useAccelerateEndpoint = false, }); - /// {@macro storage.amplify_storage_s3.download_data_plugin_options} - /// - /// Use this when calling `downloadData` on an object that belongs to another - /// user (identified by [targetIdentityId]) rather than the currently - /// signed-in user. - const S3DownloadDataPluginOptions.forIdentity( - String targetIdentityId, { - bool getProperties = false, - S3DataBytesRange? bytesRange, - bool useAccelerateEndpoint = false, - }) : this._( - targetIdentityId: targetIdentityId, - getProperties: getProperties, - bytesRange: bytesRange, - useAccelerateEndpoint: useAccelerateEndpoint, - ); - /// {@macro storage.amplify_storage_s3.download_data_plugin_options} factory S3DownloadDataPluginOptions.fromJson(Map json) => _$S3DownloadDataPluginOptionsFromJson(json); @@ -53,11 +35,6 @@ class S3DownloadDataPluginOptions extends StorageDownloadDataPluginOptions { /// The byte range to download from the object. final S3DataBytesRange? bytesRange; - /// The identity ID of another user who uploaded the object. - /// - /// This can be set by using [S3DownloadDataPluginOptions.forIdentity]. - final String? targetIdentityId; - /// Whether to retrieve properties for the downloaded object using the /// `getProperties` API. final bool getProperties; @@ -73,7 +50,6 @@ class S3DownloadDataPluginOptions extends StorageDownloadDataPluginOptions { getProperties, useAccelerateEndpoint, bytesRange, - targetIdentityId, ]; @override diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_options.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_options.dart index 8cc40ca3be..c151fd1ae3 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_options.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_options.dart @@ -15,11 +15,9 @@ class S3DownloadFileOptions extends StorageDownloadFileOptions { 'use StorageDownloadFileOptions(pluginOptions:S3DownloadFilePluginOptions(...)) instead.', ) const S3DownloadFileOptions({ - StorageAccessLevel accessLevel = StorageAccessLevel.guest, bool getProperties = false, bool useAccelerateEndpoint = false, }) : this._( - accessLevel: accessLevel, getProperties: getProperties, useAccelerateEndpoint: useAccelerateEndpoint, ); @@ -28,36 +26,10 @@ class S3DownloadFileOptions extends StorageDownloadFileOptions { 'use StorageDownloadFileOptions(pluginOptions:S3DownloadFilePluginOptions(...)) instead.', ) const S3DownloadFileOptions._({ - super.accessLevel = StorageAccessLevel.guest, this.getProperties = false, - this.targetIdentityId, this.useAccelerateEndpoint = false, }); - /// {@macro storage.amplify_storage_s3.download_data_options} - /// - /// Use this when calling `downloadFile` on an object that belongs to other - /// user (identified by [targetIdentityId]) rather than the currently signed - /// user. - @Deprecated( - 'use StorageDownloadFileOptions(pluginOptions:S3DownloadFilePluginOptions.forIdentity(...)) instead.', - ) - const S3DownloadFileOptions.forIdentity( - String targetIdentityId, { - bool getProperties = false, - bool useAccelerateEndpoint = false, - }) : this._( - accessLevel: StorageAccessLevel.protected, - targetIdentityId: targetIdentityId, - getProperties: getProperties, - useAccelerateEndpoint: useAccelerateEndpoint, - ); - - /// The identity ID of the user who uploaded the object. - /// - /// This can be set by using [S3DownloadFileOptions.forIdentity]. - final String? targetIdentityId; - /// Whether to retrieve properties for the downloaded object using the /// `getProperties` API. final bool getProperties; diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_plugin_options.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_plugin_options.dart index fad767b307..43d159d297 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_plugin_options.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_download_file_plugin_options.dart @@ -21,34 +21,13 @@ class S3DownloadFilePluginOptions extends StorageDownloadFilePluginOptions { const S3DownloadFilePluginOptions._({ this.getProperties = false, - this.targetIdentityId, this.useAccelerateEndpoint = false, }); - /// {@macro storage.amplify_storage_s3.download_file_plugin_options} - /// - /// Use this when calling `downloadFile` on an object that belongs to other - /// user (identified by [targetIdentityId]) rather than the currently signed - /// user. - const S3DownloadFilePluginOptions.forIdentity( - String targetIdentityId, { - bool getProperties = false, - bool useAccelerateEndpoint = false, - }) : this._( - targetIdentityId: targetIdentityId, - getProperties: getProperties, - useAccelerateEndpoint: useAccelerateEndpoint, - ); - /// {@macro storage.amplify_storage_s3.download_file_plugin_options} factory S3DownloadFilePluginOptions.fromJson(Map json) => _$S3DownloadFilePluginOptionsFromJson(json); - /// The identity ID of the user who uploaded the object. - /// - /// This can be set by using [S3DownloadFilePluginOptions.forIdentity]. - final String? targetIdentityId; - /// Whether to retrieve properties for the downloaded object using the /// `getProperties` API. final bool getProperties; @@ -60,7 +39,6 @@ class S3DownloadFilePluginOptions extends StorageDownloadFilePluginOptions { List get props => [ getProperties, useAccelerateEndpoint, - targetIdentityId, ]; @override diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_html.dart b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_html.dart index 93cbed3d6d..7c3801c82b 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_html.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_html.dart @@ -8,7 +8,7 @@ import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_servic /// The html implementation of `downloadFile` API. S3DownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, required StorageDownloadFileOptions options, required S3PluginConfig s3pluginConfig, @@ -20,12 +20,12 @@ S3DownloadFileOperation downloadFile({ return S3DownloadFileOperation( request: StorageDownloadFileRequest( - key: key, + path: path, localFile: localFile, options: options, ), result: _downloadFromUrl( - key: key, + path: path, localFile: localFile, options: options, s3pluginConfig: s3pluginConfig, @@ -40,14 +40,13 @@ S3DownloadFileOperation downloadFile({ } Future _downloadFromUrl({ - required String key, + required StoragePath path, required AWSFile localFile, required StorageDownloadFileOptions options, required S3PluginConfig s3pluginConfig, required StorageS3Service storageS3Service, }) async { - final s3PluginOptions = options.pluginOptions as S3DownloadFilePluginOptions; - final targetIdentityId = s3PluginOptions.targetIdentityId; + final s3PluginOptions = options.pluginOptions as S3DownloadFilePluginOptions?; // Calling the `getProperties` by default to verify the existence of the object // before downloading from the presigned URL, as the 404 or 403 should be // handled by the plugin but not be thrown to an end user in browser. @@ -56,17 +55,8 @@ Future _downloadFromUrl({ // Exception thrown from the getProperties will be thrown as download // operation. final downloadedItem = (await storageS3Service.getProperties( - // TODO(Jordan-Nelson): update to use path from customer - path: StoragePath.fromString(key), - options: targetIdentityId == null - ? StorageGetPropertiesOptions( - accessLevel: options.accessLevel, - ) - : StorageGetPropertiesOptions( - accessLevel: options.accessLevel, - pluginOptions: - S3GetPropertiesPluginOptions.forIdentity(targetIdentityId), - ), + path: path, + options: const StorageGetPropertiesOptions(), )) .storageItem; @@ -74,20 +64,14 @@ Future _downloadFromUrl({ // We are not setting validateObjectExistence to true here as we are not // able to directly get the result of underlying HeadObject result. final url = (await storageS3Service.getUrl( - // TODO(Jordan-Nelson): update to use path from customer - path: StoragePath.fromString(key), - options: targetIdentityId == null - ? StorageGetUrlOptions( - pluginOptions: S3GetUrlPluginOptions( + path: path, + options: StorageGetUrlOptions( + pluginOptions: s3PluginOptions == null + ? null + : S3GetUrlPluginOptions( useAccelerateEndpoint: s3PluginOptions.useAccelerateEndpoint, ), - ) - : StorageGetUrlOptions( - pluginOptions: S3GetUrlPluginOptions.forIdentity( - targetIdentityId, - useAccelerateEndpoint: s3PluginOptions.useAccelerateEndpoint, - ), - ), + ), )) .url; @@ -100,8 +84,9 @@ Future _downloadFromUrl({ ); return S3DownloadFileResult( - downloadedItem: - s3PluginOptions.getProperties ? downloadedItem : S3Item(key: key), + downloadedItem: s3PluginOptions != null && s3PluginOptions.getProperties + ? downloadedItem + : S3Item(key: downloadedItem.key), localFile: localFile, ); } diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_io.dart b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_io.dart index 52e9a1e501..246cf8a3ae 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_io.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_io.dart @@ -7,12 +7,12 @@ import 'package:amplify_core/amplify_core.dart'; import 'package:amplify_storage_s3_dart/amplify_storage_s3_dart.dart'; import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_service.dart'; import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; +import 'package:path/path.dart' as p; /// The io implementation of `downloadFile` API. @internal S3DownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, required StorageDownloadFileOptions options, required S3PluginConfig s3pluginConfig, @@ -25,30 +25,22 @@ S3DownloadFileOperation downloadFile({ late final File tempFile; final s3PluginOptions = options.pluginOptions as S3DownloadFilePluginOptions; - final targetIdentityId = s3PluginOptions.targetIdentityId; final downloadDataOptions = StorageDownloadDataOptions( - accessLevel: options.accessLevel, - pluginOptions: targetIdentityId == null - ? S3DownloadDataPluginOptions( - getProperties: s3PluginOptions.getProperties, - useAccelerateEndpoint: s3PluginOptions.useAccelerateEndpoint, - ) - : S3DownloadDataPluginOptions.forIdentity( - targetIdentityId, - getProperties: s3PluginOptions.getProperties, - useAccelerateEndpoint: s3PluginOptions.useAccelerateEndpoint, - ), + pluginOptions: S3DownloadDataPluginOptions( + getProperties: s3PluginOptions.getProperties, + useAccelerateEndpoint: s3PluginOptions.useAccelerateEndpoint, + ), ); final downloadDataTask = storageS3Service.downloadData( - key: key, + path: path, options: downloadDataOptions, // Ensure destination file is writable. Exception thrown in the check // will be forwarded to the Future, downloadDataTask.result below preStart: () async { destinationPath = await _ensureDestinationWritable(localFile); tempFile = File( - path.join( + p.join( await appPathProvider.getTemporaryPath(), 'amplify_storage_s3_temp_${uuid()}', ), @@ -78,7 +70,7 @@ S3DownloadFileOperation downloadFile({ return S3DownloadFileOperation( request: StorageDownloadFileRequest( - key: key, + path: path, localFile: localFile, options: options, ), diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_stub.dart b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_stub.dart index 81fd034fd1..94eb03c0e9 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_stub.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/platform_impl/download_file/download_file_stub.dart @@ -7,7 +7,7 @@ import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_servic /// Interface of the platform implementation of the `downloadFile` API. S3DownloadFileOperation downloadFile({ - required String key, + required StoragePath path, required AWSFile localFile, required StorageDownloadFileOptions options, required S3PluginConfig s3pluginConfig, diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/storage_s3_service_impl.dart b/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/storage_s3_service_impl.dart index c5a8227464..016e69d891 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/storage_s3_service_impl.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/storage_s3_service_impl.dart @@ -315,7 +315,7 @@ class StorageS3Service { /// /// {@macro amplify_storage_s3_dart.download_task.on_done} S3DownloadTask downloadData({ - required String key, + required StoragePath path, required StorageDownloadDataOptions options, FutureOr Function()? preStart, void Function(S3TransferProgress)? onProgress, @@ -327,11 +327,9 @@ class StorageS3Service { s3Client: _defaultS3Client, defaultS3ClientConfig: _defaultS3ClientConfig, bucket: _s3PluginConfig.bucket, - defaultAccessLevel: _s3PluginConfig.defaultAccessLevel, - key: key, + path: path, options: options, - prefixResolver: _prefixResolver, - logger: _logger, + pathResolver: _pathResolver, onProgress: onProgress, onData: onData, preStart: preStart, diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/task/s3_download_task.dart b/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/task/s3_download_task.dart index 20553a3e61..6a2160b3ce 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/task/s3_download_task.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/storage_s3_service/service/task/s3_download_task.dart @@ -7,8 +7,8 @@ import 'package:amplify_core/amplify_core.dart'; import 'package:amplify_storage_s3_dart/amplify_storage_s3_dart.dart'; import 'package:amplify_storage_s3_dart/src/exception/s3_storage_exception.dart' as s3_exception; +import 'package:amplify_storage_s3_dart/src/path_resolver/s3_path_resolver.dart'; import 'package:amplify_storage_s3_dart/src/sdk/s3.dart' as s3; -import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_service.dart'; import 'package:meta/meta.dart'; import 'package:smithy/smithy.dart' as smithy; import 'package:smithy_aws/smithy_aws.dart' as smithy_aws; @@ -50,31 +50,26 @@ class S3DownloadTask { S3DownloadTask({ required s3.S3Client s3Client, required smithy_aws.S3ClientConfig defaultS3ClientConfig, - required S3PrefixResolver prefixResolver, - required StorageAccessLevel defaultAccessLevel, + required S3PathResolver pathResolver, required String bucket, - required String key, + required StoragePath path, required StorageDownloadDataOptions options, FutureOr Function()? preStart, void Function(S3TransferProgress)? onProgress, void Function(List)? onData, FutureOr Function()? onDone, FutureOr Function()? onError, - required AWSLogger logger, }) : _downloadCompleter = Completer(), _s3Client = s3Client, _defaultS3ClientConfig = defaultS3ClientConfig, - _prefixResolver = prefixResolver, + _pathResolver = pathResolver, _bucket = bucket, - _defaultAccessLevel = defaultAccessLevel, - _key = key, - _downloadDataOptions = options, + _path = path, _preStart = preStart, _onProgress = onProgress, _onData = onData, _onDone = onDone, _onError = onError, - _logger = logger, _downloadedBytesSize = 0, _s3PluginOptions = options.pluginOptions as S3DownloadDataPluginOptions? ?? @@ -85,17 +80,14 @@ class S3DownloadTask { final s3.S3Client _s3Client; final smithy_aws.S3ClientConfig _defaultS3ClientConfig; - final S3PrefixResolver _prefixResolver; + final S3PathResolver _pathResolver; final String _bucket; - final StorageAccessLevel _defaultAccessLevel; - final String _key; - final StorageDownloadDataOptions _downloadDataOptions; + final StoragePath _path; final FutureOr Function()? _preStart; final void Function(S3TransferProgress)? _onProgress; final void Function(List bytes)? _onData; final FutureOr Function()? _onDone; final FutureOr Function()? _onError; - final AWSLogger _logger; final S3DownloadDataPluginOptions _s3PluginOptions; int _downloadedBytesSize; @@ -110,7 +102,7 @@ class S3DownloadTask { Completer? _pauseCompleter; late StorageTransferState _state; - late final String _resolvedKey; + late final String _resolvedPath; late final S3Item _downloadedS3Item; // Total bytes that need to be downloaded, this field is set when the @@ -145,19 +137,12 @@ class S3DownloadTask { return; } - final resolvedPrefix = await StorageS3Service.getResolvedPrefix( - prefixResolver: _prefixResolver, - logger: _logger, - accessLevel: _downloadDataOptions.accessLevel ?? _defaultAccessLevel, - identityId: _s3PluginOptions.targetIdentityId, - ); - - _resolvedKey = '$resolvedPrefix$_key'; + _resolvedPath = await _pathResolver.resolvePath(path: _path); try { final getObjectOutput = await _getObject( bucket: _bucket, - key: _resolvedKey, + key: _resolvedPath, bytesRange: _s3PluginOptions.bytesRange, ); @@ -175,11 +160,8 @@ class S3DownloadTask { _totalBytes = remoteSize; _listenToBytesSteam(getObjectOutput.body); - _downloadedS3Item = S3Item.fromGetObjectOutput( - getObjectOutput, - key: _key, - path: _resolvedKey, - ); + _downloadedS3Item = + S3Item.fromGetObjectOutput(getObjectOutput, path: _resolvedPath); } on Exception catch (error, stackTrace) { await _completeDownloadWithError(error, stackTrace); } @@ -230,7 +212,7 @@ class S3DownloadTask { try { final getObjectOutput = await _getObject( bucket: _bucket, - key: _resolvedKey, + key: _resolvedPath, bytesRange: bytesRangeToDownload, ); _listenToBytesSteam(getObjectOutput.body); diff --git a/packages/storage/amplify_storage_s3_dart/test/amplify_storage_s3_dart_test.dart b/packages/storage/amplify_storage_s3_dart/test/amplify_storage_s3_dart_test.dart index c2f812e7ee..912d126526 100644 --- a/packages/storage/amplify_storage_s3_dart/test/amplify_storage_s3_dart_test.dart +++ b/packages/storage/amplify_storage_s3_dart/test/amplify_storage_s3_dart_test.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import 'package:amplify_core/amplify_core.dart'; +import 'package:amplify_core/src/types/storage/storage_path_with_identity_id.dart'; import 'package:amplify_storage_s3_dart/amplify_storage_s3_dart.dart'; import 'package:amplify_storage_s3_dart/src/prefix_resolver/storage_access_level_aware_prefix_resolver.dart'; import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_service.dart'; @@ -452,6 +453,12 @@ void main() { registerFallbackValue( const StorageDownloadDataOptions(), ); + registerFallbackValue(const StoragePath.fromString('/public/$testKey')); + registerFallbackValue( + StoragePathWithIdentityId( + (identityId) => '/private/$identityId/$testKey', + ), + ); }); test( @@ -463,7 +470,7 @@ void main() { when( () => storageS3Service.downloadData( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), options: defaultOptions, preStart: any(named: 'preStart'), onProgress: any(named: 'onProgress'), @@ -475,12 +482,12 @@ void main() { when(() => testS3DownloadTask.result).thenAnswer((_) async => testItem); downloadDataOperation = storageS3Plugin.downloadData( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), ); final capturedOptions = verify( () => storageS3Service.downloadData( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), options: captureAny( named: 'options', ), @@ -504,7 +511,6 @@ void main() { test('should forward options to StorageS3Service.downloadData API', () async { const testOptions = StorageDownloadDataOptions( - accessLevel: testAccessLevelProtected, pluginOptions: S3DownloadDataPluginOptions( useAccelerateEndpoint: true, getProperties: true, @@ -513,7 +519,7 @@ void main() { when( () => storageS3Service.downloadData( - key: testKey, + path: any(named: 'path'), options: any(named: 'options'), onData: any(named: 'onData'), ), @@ -522,13 +528,15 @@ void main() { when(() => testS3DownloadTask.result).thenAnswer((_) async => testItem); downloadDataOperation = storageS3Plugin.downloadData( - key: testKey, + path: StoragePath.withIdentityId( + (identityId) => '/protected/$identityId/$testKey', + ), options: testOptions, ); final capturedOptions = verify( () => storageS3Service.downloadData( - key: testKey, + path: any(named: 'path'), onData: any(named: 'onData'), options: captureAny( named: 'options', diff --git a/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_html_test.dart b/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_html_test.dart index 7306a658fc..7acc2ab210 100644 --- a/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_html_test.dart +++ b/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_html_test.dart @@ -27,9 +27,7 @@ class DummyPathProvider implements AppPathProvider { } void main() { - group('downloadFile() html implementation', - // TODO(Jordan-Nelson): remove skip - skip: true, () { + group('downloadFile() html implementation', () { late StorageS3Service storageS3Service; const testKey = 'upload-key.text'; const testS3pluginConfig = S3PluginConfig( @@ -65,23 +63,21 @@ void main() { ); registerFallbackValue( - StorageGetPropertiesOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - ), + const StorageGetPropertiesOptions(), ); + registerFallbackValue(const StoragePath.fromString(testKey)); + when( () => storageS3Service.getProperties( - // TODO(Jordan-Nelson): update - path: const StoragePath.fromString('key'), + path: any(named: 'path'), options: any(named: 'options'), ), ).thenAnswer((_) async => testGetPropertiesResult); when( () => storageS3Service.getUrl( - // TODO(Jordan-Nelson): update - path: const StoragePath.fromString('key'), + path: any(named: 'path'), options: any(named: 'options'), ), ).thenAnswer((_) async => testGetUrlResult); @@ -90,86 +86,47 @@ void main() { test( 'should invoke StorageS3Service.getUrl with converted S3DownloadFilePluginOptions', () async { - const testTargetIdentity = 'someone-else'; final operation = downloadFile( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), localFile: AWSFile.fromPath('file_name.jpg'), - options: StorageDownloadFileOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - pluginOptions: - const S3DownloadFilePluginOptions.forIdentity(testTargetIdentity), - ), + options: const StorageDownloadFileOptions(), s3pluginConfig: testS3pluginConfig, storageS3Service: storageS3Service, appPathProvider: const DummyPathProvider(), ); await operation.result; - - final capturedGetPropertiesOptions = verify( + verify( () => storageS3Service.getProperties( - // TODO(Jordan-Nelson): update - path: const StoragePath.fromString('key'), + path: any(named: 'path'), options: captureAny( named: 'options', ), ), ).captured.last; - expect( - capturedGetPropertiesOptions, - isA() - .having( - (o) => o.accessLevel, - 'accessLevel', - testS3pluginConfig.defaultAccessLevel, - ) - .having( - (o) => (o.pluginOptions! as S3GetPropertiesPluginOptions) - .targetIdentityId, - 'targetIdentityId', - testTargetIdentity, - ), - ); - - final capturedUrlOptions = verify( + verify( () => storageS3Service.getUrl( - // TODO(Jordan-Nelson): update - path: const StoragePath.fromString('key'), + path: any(named: 'path'), options: captureAny( named: 'options', ), ), ).captured.last; - - expect( - capturedUrlOptions, - isA() - .having( - (o) => o.accessLevel, - 'accessLevel', - testS3pluginConfig.defaultAccessLevel, - ) - .having( - (o) => - (o.pluginOptions! as S3GetUrlPluginOptions).targetIdentityId, - 'targetIdentityId', - testTargetIdentity, - ), - ); }); test( 'download result should include metadata when options.getProperties is set to true', () async { const options = StorageDownloadFileOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadFilePluginOptions( getProperties: true, ), ); final result = await downloadFile( - key: testKey, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testKey', + ), localFile: AWSFile.fromPath('download.jpg'), options: options, s3pluginConfig: testS3pluginConfig, diff --git a/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_io_test.dart b/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_io_test.dart index 978ecc620b..90e9db235b 100644 --- a/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_io_test.dart +++ b/packages/storage/amplify_storage_s3_dart/test/platform_impl/download_file_io_test.dart @@ -8,6 +8,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:amplify_core/amplify_core.dart'; +import 'package:amplify_core/src/types/storage/storage_path_with_identity_id.dart'; import 'package:amplify_storage_s3_dart/amplify_storage_s3_dart.dart'; import 'package:amplify_storage_s3_dart/src/platform_impl/download_file/download_file.dart'; import 'package:amplify_storage_s3_dart/src/storage_s3_service/storage_s3_service.dart'; @@ -43,14 +44,18 @@ void main() { storageS3Service = MockStorageS3Service(); downloadTask = MockS3DownloadTask(); registerFallbackValue( - const StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.guest, + const StorageDownloadDataOptions(), + ); + registerFallbackValue(const StoragePath.fromString('/public/$testKey')); + registerFallbackValue( + StoragePathWithIdentityId( + (identityId) => '/private/$identityId/$testKey', ), ); when( () => storageS3Service.downloadData( - key: testKey, + path: any(named: 'path'), options: any(named: 'options'), preStart: any(named: 'preStart'), onProgress: any(named: 'onProgress'), @@ -68,13 +73,14 @@ void main() { test('should invoke StorageS3Service.downloadData with expected parameters', () async { const options = StorageDownloadFileOptions( - accessLevel: StorageAccessLevel.private, pluginOptions: S3DownloadFilePluginOptions( getProperties: true, ), ); final downloadFileOperation = downloadFile( - key: testKey, + path: StoragePath.withIdentityId( + (identityId) => '/private/$identityId/$testKey', + ), localFile: AWSFile.fromPath(testDestinationPath), options: options, s3pluginConfig: testS3pluginConfig, @@ -87,7 +93,7 @@ void main() { final captureParams = verify( () => storageS3Service.downloadData( - key: testKey, + path: captureAny(named: 'path'), options: captureAny( named: 'options', ), @@ -101,30 +107,26 @@ void main() { ), ).captured; + final capturedOptions = captureParams[1]; + expect( - captureParams[0], - isA() - .having( - (o) => o.accessLevel, - 'accessLevel', - options.accessLevel, - ) - .having( - (o) => (o.pluginOptions! as S3DownloadDataPluginOptions) - .getProperties, - 'getProperties', - isTrue, - ), + capturedOptions, + isA().having( + (o) => + (o.pluginOptions! as S3DownloadDataPluginOptions).getProperties, + 'getProperties', + isTrue, + ), ); - expect(captureParams[1] is Function, true); - preStart = captureParams[1] as FutureOr Function(); expect(captureParams[2] is Function, true); - onProgress = captureParams[2] as void Function(S3TransferProgress); + preStart = captureParams[2] as FutureOr Function(); expect(captureParams[3] is Function, true); - onData = captureParams[3] as void Function(List); + onProgress = captureParams[3] as void Function(S3TransferProgress); expect(captureParams[4] is Function, true); - onDone = captureParams[4] as FutureOr Function(); + onData = captureParams[4] as void Function(List); + expect(captureParams[5] is Function, true); + onDone = captureParams[5] as FutureOr Function(); final result = await downloadFileOperation.result; expect(result.downloadedItem, testItem); @@ -155,121 +157,15 @@ void main() { await downloadedFile.delete(); }); - test( - 'should correctly create S3DownloadDataOptions with default storage access level', - () { - downloadFile( - key: testKey, - localFile: AWSFile.fromPath('path'), - options: StorageDownloadFileOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - pluginOptions: const S3DownloadFilePluginOptions(), - ), - s3pluginConfig: testS3pluginConfig, - storageS3Service: storageS3Service, - appPathProvider: appPathProvider, - onProgress: (progress) { - expectedProgress = progress; - }, - ); - - final capturedOptions = verify( - () => storageS3Service.downloadData( - key: testKey, - options: captureAny( - named: 'options', - ), - preStart: any(named: 'preStart'), - onProgress: any(named: 'onProgress'), - onData: any(named: 'onData'), - onDone: any(named: 'onDone'), - onError: any(named: 'onError'), - ), - ).captured.last; - - expect( - capturedOptions, - isA().having( - (o) => o.accessLevel, - 'accessLevel', - testS3pluginConfig.defaultAccessLevel, - ), - ); - }); - - test( - 'should correctly create S3DownloadDataOptions with correct targetIdentityId', - () { - const testTargetIdentity = 'someone-else'; - const testAccessLevel = StorageAccessLevel.protected; - downloadFile( - key: testKey, - localFile: AWSFile.fromPath('path'), - options: const StorageDownloadFileOptions( - accessLevel: testAccessLevel, - pluginOptions: S3DownloadFilePluginOptions.forIdentity( - testTargetIdentity, - ), - ), - s3pluginConfig: testS3pluginConfig, - storageS3Service: storageS3Service, - appPathProvider: appPathProvider, - onProgress: (progress) { - expectedProgress = progress; - }, - ); - - final capturedOptions = verify( - () => storageS3Service.downloadData( - key: testKey, - options: captureAny( - named: 'options', - ), - preStart: any(named: 'preStart'), - onProgress: any(named: 'onProgress'), - onData: any(named: 'onData'), - onDone: any(named: 'onDone'), - onError: any(named: 'onError'), - ), - ).captured.last; - - expect( - capturedOptions, - isA() - .having( - (o) => o.accessLevel, - 'accessLevel', - testAccessLevel, - ) - .having( - (o) => (o.pluginOptions! as S3DownloadDataPluginOptions) - .targetIdentityId, - 'targetIdentityId', - testTargetIdentity, - ), - ); - - expect( - capturedOptions, - isA().having( - (o) => (o.pluginOptions! as S3DownloadDataPluginOptions) - .targetIdentityId, - 'targetIdentityId', - testTargetIdentity, - ), - ); - }); - group('preStart callback should throw exceptions', () { test( 'when destination path is null is throws StorageLocalFileNotFoundException', () { downloadFile( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), localFile: AWSFile.fromData([101]), - options: StorageDownloadFileOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - pluginOptions: const S3DownloadFilePluginOptions(), + options: const StorageDownloadFileOptions( + pluginOptions: S3DownloadFilePluginOptions(), ), s3pluginConfig: testS3pluginConfig, storageS3Service: storageS3Service, @@ -281,7 +177,7 @@ void main() { final capturedPreStart = verify( () => storageS3Service.downloadData( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), options: any(named: 'options'), preStart: captureAny Function()?>(named: 'preStart'), onProgress: any(named: 'onProgress'), @@ -298,11 +194,10 @@ void main() { 'when destination path is a directory instead of a file it throws StorageLocalFileNotFoundException', () { downloadFile( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), localFile: AWSFile.fromPath(Directory.systemTemp.path), - options: StorageDownloadFileOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - pluginOptions: const S3DownloadFilePluginOptions(), + options: const StorageDownloadFileOptions( + pluginOptions: S3DownloadFilePluginOptions(), ), s3pluginConfig: testS3pluginConfig, storageS3Service: storageS3Service, @@ -314,7 +209,7 @@ void main() { final capturedPreStart = verify( () => storageS3Service.downloadData( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), options: any(named: 'options'), preStart: captureAny Function()?>(named: 'preStart'), onProgress: any(named: 'onProgress'), @@ -337,11 +232,10 @@ void main() { when(downloadTask.cancel).thenAnswer((_) async {}); final downloadFileOperation = downloadFile( - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), localFile: AWSFile.fromPath('path'), - options: StorageDownloadFileOptions( - accessLevel: testS3pluginConfig.defaultAccessLevel, - pluginOptions: const S3DownloadFilePluginOptions(), + options: const StorageDownloadFileOptions( + pluginOptions: S3DownloadFilePluginOptions(), ), s3pluginConfig: testS3pluginConfig, storageS3Service: storageS3Service, diff --git a/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/task/s3_download_task_test.dart b/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/task/s3_download_task_test.dart index c1fa8b60f1..2d5ca4095c 100644 --- a/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/task/s3_download_task_test.dart +++ b/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/task/s3_download_task_test.dart @@ -15,24 +15,20 @@ import 'package:test/test.dart'; import '../../test_utils/helper_types.dart'; import '../../test_utils/mocks.dart'; -import '../storage_s3_service_test.dart'; +import '../../test_utils/test_path_resolver.dart'; void main() { group('S3DownloadTask', () { const testBucket = 'bucket1'; - const testDefaultAccessLevel = StorageAccessLevel.guest; const testKey = 'some-object'; const defaultTestOptions = StorageDownloadDataOptions( accessLevel: StorageAccessLevel.private, ); - final testPrefixResolver = TestPrefixResolver(); const defaultS3ClientConfig = S3ClientConfig(); late S3Client s3Client; - late AWSLogger logger; setUpAll(() { s3Client = MockS3Client(); - logger = MockAWSLogger(); registerFallbackValue( GetObjectRequest( @@ -63,12 +59,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString(testKey), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, preStart: testPreStart, ); @@ -102,12 +96,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString(testKey), + pathResolver: TestPathResolver(), options: const StorageDownloadDataOptions(), - logger: logger, onProgress: (progress) { finalState = progress.state; }, @@ -128,9 +120,7 @@ void main() { expect(request.bucket, testBucket); expect( request.key, - '${await testPrefixResolver.resolvePrefix( - accessLevel: testDefaultAccessLevel, - )}$testKey', + TestPathResolver.path, ); expect(request.checksumMode, ChecksumMode.enabled); @@ -169,12 +159,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString(testKey), + pathResolver: TestPathResolver(), options: testOptions, - logger: logger, ); await downloadTask.start(); @@ -219,12 +207,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString(testKey), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onError: () { onErrorHasBeenCalled = true; }, @@ -245,16 +231,14 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: const S3ClientConfig(usePathStyle: true), - prefixResolver: testPrefixResolver, bucket: 'bucket.name.has.dots.com', - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: const StorageDownloadDataOptions( pluginOptions: S3DownloadDataPluginOptions( useAccelerateEndpoint: true, ), ), - logger: logger, ); unawaited(downloadTask.start()); @@ -296,12 +280,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onProgress: (progress) { receivedState.add(progress.state); }, @@ -343,12 +325,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onProgress: (progress) { receivedState.add(progress.state); }, @@ -414,12 +394,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onProgress: (progress) { receivedState.add(progress.state); }, @@ -487,12 +465,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, ); unawaited(downloadTask.start()); @@ -506,12 +482,10 @@ void main() { downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, ); }); @@ -559,12 +533,10 @@ void main() { downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, ); }); @@ -614,12 +586,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onProgress: (progress) { finalState = progress.state; }, @@ -658,12 +628,10 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - prefixResolver: testPrefixResolver, bucket: testBucket, - defaultAccessLevel: testDefaultAccessLevel, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: defaultTestOptions, - logger: logger, onDone: () async { onDoneHasBeenCalled = true; throw testOnDoneException; @@ -726,17 +694,14 @@ void main() { final downloadTask = S3DownloadTask( s3Client: s3Client, defaultS3ClientConfig: defaultS3ClientConfig, - defaultAccessLevel: testDefaultAccessLevel, - prefixResolver: testPrefixResolver, bucket: testBucket, - key: testKey, + path: const StoragePath.fromString('/public/$testKey'), + pathResolver: TestPathResolver(), options: StorageDownloadDataOptions( - accessLevel: StorageAccessLevel.guest, pluginOptions: S3DownloadDataPluginOptions( getProperties: item.getPropertiesValue, ), ), - logger: logger, ); unawaited(downloadTask.start());