From 0b2194a28d21571747f03fbb9f217517194c9990 Mon Sep 17 00:00:00 2001 From: Andrew Hahn Date: Wed, 3 Jul 2024 12:12:21 -0700 Subject: [PATCH 1/4] feat: adding delimiter support in classes --- packages/amplify_core/lib/src/types/storage/list_options.dart | 3 +++ packages/amplify_core/lib/src/types/storage/list_result.dart | 3 +++ .../lib/src/model/s3_list_plugin_options.dart | 2 ++ .../amplify_storage_s3_dart/lib/src/model/s3_list_result.dart | 1 + 4 files changed, 9 insertions(+) diff --git a/packages/amplify_core/lib/src/types/storage/list_options.dart b/packages/amplify_core/lib/src/types/storage/list_options.dart index c046f90d55..b4b9600245 100644 --- a/packages/amplify_core/lib/src/types/storage/list_options.dart +++ b/packages/amplify_core/lib/src/types/storage/list_options.dart @@ -16,8 +16,11 @@ class StorageListOptions this.pageSize = 1000, this.nextToken, this.pluginOptions, + // this.subpathStrategy, }); + // final SubpathStrategy subpathStrategy; + /// The number of object to be listed in each page. final int pageSize; diff --git a/packages/amplify_core/lib/src/types/storage/list_result.dart b/packages/amplify_core/lib/src/types/storage/list_result.dart index aa65cd8d37..027e8c6ac4 100644 --- a/packages/amplify_core/lib/src/types/storage/list_result.dart +++ b/packages/amplify_core/lib/src/types/storage/list_result.dart @@ -12,11 +12,14 @@ class StorageListResult { this.items, { required this.hasNextPage, this.nextToken, + // this.excludedSubpaths, }); /// The objects listed in the current page. final List items; + // final List excludedSubpaths; + /// Whether has next page that can be listed using [nextToken]. final bool hasNextPage; diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_plugin_options.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_plugin_options.dart index 17480ee70e..75171561cf 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_plugin_options.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_plugin_options.dart @@ -41,10 +41,12 @@ class S3ListPluginOptions extends StorageListPluginOptions { /// Whether to exclude objects under the sub paths of the path to list. The /// default value is `false`. + // @Deprecated('use StorageListOptions.subpathStrategy instead') final bool excludeSubPaths; /// The delimiter to use when evaluating sub paths. If [excludeSubPaths] is /// false, this value has no impact on behavior. + // @Deprecated('use StorageListOptions.subpathStrategy instead') final String delimiter; /// Whether to list all objects under a given path without pagination. The diff --git a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_result.dart b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_result.dart index a9ba5ca0fe..2e4d97612d 100644 --- a/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_result.dart +++ b/packages/storage/amplify_storage_s3_dart/lib/src/model/s3_list_result.dart @@ -57,6 +57,7 @@ class S3ListResult extends StorageListResult { } /// The metadata returned from the Storage S3 plugin `list` API. +// @Deprecated('use StorageListResult.excludedSubpaths instead') class S3ListMetadata { /// Creates a S3ListMetadata from the `commonPrefix` and `delimiter` /// properties of the [s3.ListObjectsV2Output]. From 9bb6b5aac46736ab607af75341f0edc3d0a87d5d Mon Sep 17 00:00:00 2001 From: Andrew Hahn Date: Wed, 3 Jul 2024 12:13:52 -0700 Subject: [PATCH 2/4] feat: add subpath class --- .../src/types/storage/subpath_strategy.dart | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/amplify_core/lib/src/types/storage/subpath_strategy.dart diff --git a/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart new file mode 100644 index 0000000000..79a23c7872 --- /dev/null +++ b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart @@ -0,0 +1,21 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_core/amplify_core.dart'; + +/// {@template amplify_core.storage.subpath_strategy} +/// Presents .. +/// {@endtemplate} +class StorageSubpathStrategy { + /// {@macro amplify_core.storage.subpath_strategy} + const StorageSubpathStrategy({ + required this.path, + this.options, + }); + + /// .. + final StoragePath path; + + /// .. + final StorageListOptions? options; +} From 2eaf49947a5d22a7246d4c770c4e231f135f423e Mon Sep 17 00:00:00 2001 From: Andrew Hahn Date: Wed, 3 Jul 2024 12:13:52 -0700 Subject: [PATCH 3/4] feat: add subpath class --- .../src/types/storage/subpath_strategy.dart | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart index 79a23c7872..8358261120 100644 --- a/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart +++ b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart @@ -1,21 +1,21 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:amplify_core/amplify_core.dart'; - -/// {@template amplify_core.storage.subpath_strategy} -/// Presents .. -/// {@endtemplate} -class StorageSubpathStrategy { - /// {@macro amplify_core.storage.subpath_strategy} - const StorageSubpathStrategy({ - required this.path, - this.options, - }); - - /// .. - final StoragePath path; - - /// .. - final StorageListOptions? options; -} +// // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// // SPDX-License-Identifier: Apache-2.0 +// +// import 'package:amplify_core/amplify_core.dart'; +// +// /// {@template amplify_core.storage.subpath_strategy} +// /// Presents .. +// /// {@endtemplate} +// class StorageSubpathStrategy { +// /// {@macro amplify_core.storage.subpath_strategy} +// const StorageSubpathStrategy({ +// required this.path, +// this.options, +// }); +// +// /// .. +// final StoragePath path; +// +// /// .. +// final StorageListOptions? options; +// } From dc33ce17a84f4d6063962655c48665d16e088e42 Mon Sep 17 00:00:00 2001 From: Andrew Hahn Date: Wed, 3 Jul 2024 13:05:46 -0700 Subject: [PATCH 4/4] chore(storage): add unit & integration test scaffold --- .../lib/src/types/storage/list_result.dart | 2 +- .../src/types/storage/subpath_strategy.dart | 6 +- .../example/integration_test/list_test.dart | 42 ++++++++++++- .../storage_s3_service_test.dart | 63 ++++++++++++++++++- 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/packages/amplify_core/lib/src/types/storage/list_result.dart b/packages/amplify_core/lib/src/types/storage/list_result.dart index 027e8c6ac4..f3e6c7b168 100644 --- a/packages/amplify_core/lib/src/types/storage/list_result.dart +++ b/packages/amplify_core/lib/src/types/storage/list_result.dart @@ -9,10 +9,10 @@ import 'package:amplify_core/amplify_core.dart'; class StorageListResult { /// {@macro amplify_core.storage.list_result} const StorageListResult( + // this.excludedSubpaths, this.items, { required this.hasNextPage, this.nextToken, - // this.excludedSubpaths, }); /// The objects listed in the current page. diff --git a/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart index 8358261120..ca05c84d11 100644 --- a/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart +++ b/packages/amplify_core/lib/src/types/storage/subpath_strategy.dart @@ -4,11 +4,11 @@ // import 'package:amplify_core/amplify_core.dart'; // // /// {@template amplify_core.storage.subpath_strategy} -// /// Presents .. +// /// Presents .. // /// {@endtemplate} -// class StorageSubpathStrategy { +// class SubpathStrategy { // /// {@macro amplify_core.storage.subpath_strategy} -// const StorageSubpathStrategy({ +// const SubpathStrategy({ // required this.path, // this.options, // }); diff --git a/packages/storage/amplify_storage_s3/example/integration_test/list_test.dart b/packages/storage/amplify_storage_s3/example/integration_test/list_test.dart index 0f2595c02d..eeec19b419 100644 --- a/packages/storage/amplify_storage_s3/example/integration_test/list_test.dart +++ b/packages/storage/amplify_storage_s3/example/integration_test/list_test.dart @@ -71,7 +71,9 @@ void main() { }); group('list() with options', () { - group('excluding sub paths', () { + group( + '@Deprecated for StorageListOptions.subpathStrategy, excluding sub paths with excludeSubPaths & delimiter', + () { testWidgets('default delimiter', (_) async { final listResult = await Amplify.Storage.list( path: StoragePath.fromString('$uniquePrefix/'), @@ -113,6 +115,44 @@ void main() { }); }); + group('excluding sub paths with StorageListOptions.subpathStrategy', + () { + // testWidgets('default delimiter', (_) async { + // final listResult = await Amplify.Storage.list( + // path: StoragePath.fromString('$uniquePrefix/'), + // options: const StorageListOptions( + // subpaths: Subpaths.exclude(delimiter: "-"), + // ), + // ).result as S3ListResult; + // + // expect(listResult.items.length, 3); + // expect(listResult.items.first.path, contains('file1.txt')); + // + // expect(listResult.metadata.subPaths.length, 1); + // expect(listResult.metadata.subPaths.first, '$uniquePrefix/subdir/'); + // expect(listResult.metadata.delimiter, '/'); + // }); + // + // testWidgets('custom delimiter', (_) async { + // final listResult = await Amplify.Storage.list( + // path: StoragePath.fromString('$uniquePrefix/'), + // options: const StorageListOptions( + // subpaths: Subpaths.exclude(delimiter: "-"), + // ), + // ).result as S3ListResult; + // + // expect(listResult.items.length, 3); + // expect(listResult.items.first.path, contains('file1.txt')); + // + // expect(listResult.metadata.subPaths.length, 1); + // expect( + // listResult.metadata.subPaths.first, + // '$uniquePrefix/subdir2#', + // ); + // expect(listResult.metadata.delimiter, '-'); + // }); + }); + testWidgets('should respect pageSize limitation', (_) async { final listResult = await Amplify.Storage.list( path: StoragePath.fromString(uniquePrefix), diff --git a/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/storage_s3_service_test.dart b/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/storage_s3_service_test.dart index aec65db336..2203ce588a 100644 --- a/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/storage_s3_service_test.dart +++ b/packages/storage/amplify_storage_s3_dart/test/storage_s3_service/storage_s3_service_test.dart @@ -153,7 +153,7 @@ void main() { }); test( - 'should attach delimiter to the ListObjectV2Request when options excludeSubPaths is set to true', + 'Deprecated for StorageListOptions.subpathStrategy, should attach delimiter to the ListObjectV2Request when options excludeSubPaths is set to true', () async { final testS3Objects = [1, 2, 3, 4, 5] .map( @@ -213,6 +213,67 @@ void main() { expect(result.metadata.subPaths, equals(testSubPaths)); }); + test( + 'StorageListOptions.subpathStrategy, should attach delimiter to the ListObjectV2Request when StorageListOptions.subpathStrategy.exclude() is called', + () async { + // final testS3Objects = [1, 2, 3, 4, 5] + // .map( + // (e) => S3Object( + // key: '${testPrefix}object-$e', + // size: Int64(100 * 4), + // eTag: 'object-$e-eTag', + // ), + // ) + // .toList(); + // const testPath = StoragePath.fromString('album'); + // const testOptions = StorageListOptions( + // pageSize: testPageSize, + // pluginOptions: S3ListPluginOptions(excludeSubPaths: true), + // ); + // const testSubPaths = [ + // 'album#folder1', + // 'album#folder2', + // 'album#folder1#sub-folder1', + // ]; + // final testPaginatedResult = + // PaginatedResult( + // ListObjectsV2Output( + // contents: testS3Objects, + // commonPrefixes: [ + // CommonPrefix(prefix: testSubPaths[0]), + // CommonPrefix(prefix: testSubPaths[1]), + // CommonPrefix( + // prefix: testSubPaths[2], + // ), + // ], + // delimiter: testDelimiter, + // name: testBucketName, + // maxKeys: testPageSize, + // ), + // next: ([int? pageSize]) { + // throw UnimplementedError(); + // }, + // nextContinuationToken: testNextContinuationToken, + // ); + // final smithyOperation = MockSmithyOperation< + // PaginatedResult>(); + // + // when( + // () => smithyOperation.result, + // ).thenAnswer((_) async => testPaginatedResult); + // + // when( + // () => s3Client.listObjectsV2(any()), + // ).thenAnswer((_) => smithyOperation); + // + // final result = await storageS3Service.list( + // path: testPath, + // options: testOptions, + // ); + // + // expect(result.metadata.subPaths, equals(testSubPaths)); + }); + test( 'should throw StorageAccessDeniedException when UnknownSmithyHttpException' ' with status code 403 returned from service', () async {