From 81a4c7a13f7931440e8272e21c2ed737846fe579 Mon Sep 17 00:00:00 2001 From: Ekjot <43255916+ekjotmultani@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:07:01 -0700 Subject: [PATCH] feat(storage): multi bucket get properties api (#5577) --- .../category/amplify_storage_category.dart | 1 + .../types/storage/get_properties_options.dart | 9 +- .../integration_test/get_properties_test.dart | 114 ++++++++++++++++++ .../lib/src/amplify_storage_s3_dart_impl.dart | 1 + .../service/storage_s3_service_impl.dart | 4 +- .../test/amplify_storage_s3_dart_test.dart | 3 + 6 files changed, 128 insertions(+), 4 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 c3f4cfbe2f..84c9603c03 100644 --- a/packages/amplify_core/lib/src/category/amplify_storage_category.dart +++ b/packages/amplify_core/lib/src/category/amplify_storage_category.dart @@ -153,6 +153,7 @@ class StorageCategory extends AmplifyCategory { data: data, onProgress: onProgress, options: options, + bucket: bucket, ), ); } diff --git a/packages/amplify_core/lib/src/types/storage/get_properties_options.dart b/packages/amplify_core/lib/src/types/storage/get_properties_options.dart index bef609f7a7..dbc5b8c112 100644 --- a/packages/amplify_core/lib/src/types/storage/get_properties_options.dart +++ b/packages/amplify_core/lib/src/types/storage/get_properties_options.dart @@ -1,7 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'package:aws_common/aws_common.dart'; +import 'package:amplify_core/amplify_core.dart'; /// {@template amplify_core.storage.get_properties_options} /// Configurable options for `Amplify.Storage.getProperties`. @@ -14,13 +14,17 @@ class StorageGetPropertiesOptions /// {@macro amplify_core.storage.get_properties_options} const StorageGetPropertiesOptions({ this.pluginOptions, + this.bucket, }); /// {@macro amplify_core.storage.download_get_properties_plugin_options} final StorageGetPropertiesPluginOptions? pluginOptions; + /// Optionally specify which bucket to retrieve + final StorageBucket? bucket; + @override - List get props => [pluginOptions]; + List get props => [pluginOptions, bucket]; @override String get runtimeTypeName => 'StorageGetPropertiesOptions'; @@ -28,6 +32,7 @@ class StorageGetPropertiesOptions @override Map toJson() => { 'pluginOptions': pluginOptions?.toJson(), + 'bucket': bucket, }; } diff --git a/packages/storage/amplify_storage_s3/example/integration_test/get_properties_test.dart b/packages/storage/amplify_storage_s3/example/integration_test/get_properties_test.dart index 9540e49650..06116cbb75 100644 --- a/packages/storage/amplify_storage_s3/example/integration_test/get_properties_test.dart +++ b/packages/storage/amplify_storage_s3/example/integration_test/get_properties_test.dart @@ -101,5 +101,119 @@ void main() { expect(result.storageItem.size, data.length); }); }); + group('multibucket config', () { + final mainBucket = + StorageBucket.fromOutputs('Storage Integ Test main bucket'); + final secondaryBucket = + StorageBucket.fromOutputs('Storage Integ Test secondary bucket'); + setUpAll(() async { + await configure(amplifyEnvironments['main']!); + addTearDownPath(StoragePath.fromString(path)); + await Amplify.Storage.uploadData( + data: StorageDataPayload.bytes(data), + path: StoragePath.fromString(path), + options: const StorageUploadDataOptions(metadata: metadata), + bucket: mainBucket, + ).result; + await Amplify.Storage.uploadData( + data: StorageDataPayload.bytes(data), + path: StoragePath.fromString(path), + options: const StorageUploadDataOptions(metadata: metadata), + bucket: secondaryBucket, + ).result; + }); + + testWidgets('String StoragePath', (_) async { + final result = await Amplify.Storage.getProperties( + path: StoragePath.fromString(path), + options: StorageGetPropertiesOptions( + bucket: mainBucket, + ), + ).result; + expect(result.storageItem.path, path); + expect(result.storageItem.metadata, metadata); + expect(result.storageItem.eTag, isNotNull); + expect(result.storageItem.size, data.length); + + final resultSecondaryBucket = await Amplify.Storage.getProperties( + path: StoragePath.fromString(path), + options: StorageGetPropertiesOptions( + bucket: secondaryBucket, + ), + ).result; + expect(resultSecondaryBucket.storageItem.path, path); + expect(resultSecondaryBucket.storageItem.metadata, metadata); + expect(resultSecondaryBucket.storageItem.eTag, isNotNull); + expect(resultSecondaryBucket.storageItem.size, data.length); + }); + + testWidgets('with identity ID', (_) async { + final userIdentityId = await signInNewUser(); + final name = 'get-properties-with-identity-id-${uuid()}'; + final data = 'with identity ID'.codeUnits; + final expectedResolvedPath = 'private/$userIdentityId/$name'; + addTearDownPath(StoragePath.fromString(expectedResolvedPath)); + await Amplify.Storage.uploadData( + data: StorageDataPayload.bytes(data), + path: StoragePath.fromString(expectedResolvedPath), + options: const StorageUploadDataOptions(metadata: metadata), + bucket: secondaryBucket, + ).result; + final result = await Amplify.Storage.getProperties( + path: StoragePath.fromIdentityId( + ((identityId) => 'private/$identityId/$name'), + ), + options: StorageGetPropertiesOptions( + bucket: secondaryBucket, + ), + ).result; + expect(result.storageItem.path, expectedResolvedPath); + expect(result.storageItem.metadata, metadata); + expect(result.storageItem.eTag, isNotNull); + expect(result.storageItem.size, data.length); + }); + + testWidgets('not existent path', (_) async { + // we expect StorageNotFoundException here since there is no data uploaded to either bucket on this path + await expectLater( + () => Amplify.Storage.getProperties( + path: const StoragePath.fromString('public/not-existent-path'), + options: StorageGetPropertiesOptions( + bucket: mainBucket, + ), + ).result, + throwsA(isA()), + ); + await expectLater( + () => Amplify.Storage.getProperties( + path: const StoragePath.fromString('public/not-existent-path'), + options: StorageGetPropertiesOptions( + bucket: secondaryBucket, + ), + ).result, + throwsA(isA()), + ); + }); + testWidgets('unauthorized path', (_) async { + await expectLater( + () => Amplify.Storage.getProperties( + path: const StoragePath.fromString('unauthorized/path'), + options: StorageGetPropertiesOptions( + bucket: mainBucket, + ), + ).result, + throwsA(isA()), + ); + await expectLater( + () => Amplify.Storage.getProperties( + path: const StoragePath.fromString('unauthorized/path'), + options: StorageGetPropertiesOptions( + bucket: secondaryBucket, + ), + ).result, + throwsA(isA()), + ); + }); + }); }); } 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 f4ec4035c4..5134b7a704 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 @@ -163,6 +163,7 @@ class AmplifyStorageS3Dart extends StoragePluginInterface final s3Options = StorageGetPropertiesOptions( pluginOptions: s3PluginOptions, + bucket: options?.bucket, ); return S3GetPropertiesOperation( 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 86a355eac9..a6feeb334d 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 @@ -197,12 +197,12 @@ class StorageS3Service { required StorageGetPropertiesOptions options, }) async { final resolvedPath = await _pathResolver.resolvePath(path: path); - + final s3ClientInfo = getS3ClientInfo(storageBucket: options.bucket); return S3GetPropertiesResult( storageItem: S3Item.fromHeadObjectOutput( await headObject( s3client: _defaultS3Client, - bucket: _storageOutputs.bucketName, + bucket: s3ClientInfo.bucketName, key: resolvedPath, ), path: resolvedPath, 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 405b5c9bf8..3968db24ed 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 @@ -245,6 +245,9 @@ void main() { () async { const testOptions = StorageGetPropertiesOptions( pluginOptions: S3GetPropertiesPluginOptions(), + bucket: StorageBucket.fromBucketInfo( + BucketInfo(bucketName: 'unit-test-bucket', region: 'us-east-2'), + ), ); when(