From 2af5780b135bafd398a09abfd33b3a6ebe8c4a07 Mon Sep 17 00:00:00 2001 From: Sarah Zakarias Date: Mon, 23 Apr 2018 13:57:02 +0200 Subject: [PATCH] Add support for updateMetadata (#503) --- packages/firebase_storage/CHANGELOG.md | 4 ++ .../storage/FirebaseStoragePlugin.java | 60 +++++++++++++----- .../ios/Classes/FirebaseStoragePlugin.m | 60 ++++++++++++------ .../lib/firebase_storage.dart | 33 +++++++--- packages/firebase_storage/pubspec.yaml | 2 +- .../test/firebase_storage_test.dart | 62 +++++++++++++++++++ 6 files changed, 175 insertions(+), 46 deletions(-) diff --git a/packages/firebase_storage/CHANGELOG.md b/packages/firebase_storage/CHANGELOG.md index 4e09bef39055..6af0b97ac6b3 100644 --- a/packages/firebase_storage/CHANGELOG.md +++ b/packages/firebase_storage/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.6 + +* Added support for updateMetadata. + ## 0.2.5 * Added StorageMetadata class, support for getMetadata, and support for uploading file with metadata. diff --git a/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java index 32781cf58f13..dfadc2f2fc28 100755 --- a/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java +++ b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java @@ -56,6 +56,9 @@ public void onMethodCall(MethodCall call, final Result result) { case "StorageReference#getMetadata": getMetadata(call, result); break; + case "StorageReference#updateMetadata": + updateMetadata(call, result); + break; default: result.notImplemented(); break; @@ -70,22 +73,28 @@ private void getMetadata(MethodCall call, final Result result) { new OnSuccessListener() { @Override public void onSuccess(StorageMetadata storageMetadata) { - Map map = new HashMap<>(); - map.put("name", storageMetadata.getName()); - map.put("bucket", storageMetadata.getBucket()); - map.put("generation", storageMetadata.getGeneration()); - map.put("metadataGeneration", storageMetadata.getMetadataGeneration()); - map.put("path", storageMetadata.getPath()); - map.put("sizeBytes", storageMetadata.getSizeBytes()); - map.put("creationTimeMillis", storageMetadata.getCreationTimeMillis()); - map.put("updatedTimeMillis", storageMetadata.getUpdatedTimeMillis()); - map.put("md5Hash", storageMetadata.getMd5Hash()); - map.put("cacheControl", storageMetadata.getCacheControl()); - map.put("contentDisposition", storageMetadata.getContentDisposition()); - map.put("contentEncoding", storageMetadata.getContentEncoding()); - map.put("contentLanguage", storageMetadata.getContentLanguage()); - map.put("contentType", storageMetadata.getContentType()); - result.success(map); + result.success(buildMapFromMetadata(storageMetadata)); + } + }) + .addOnFailureListener( + new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + result.error("metadata_error", e.getMessage(), null); + } + }); + } + + private void updateMetadata(MethodCall call, final Result result) { + String path = call.argument("path"); + Map metadata = call.argument("metadata"); + StorageReference ref = firebaseStorage.getReference().child(path); + ref.updateMetadata(buildMetadataFromMap(metadata)) + .addOnSuccessListener( + new OnSuccessListener() { + @Override + public void onSuccess(StorageMetadata storageMetadata) { + result.success(buildMapFromMetadata(storageMetadata)); } }) .addOnFailureListener( @@ -175,6 +184,25 @@ private StorageMetadata buildMetadataFromMap(Map map) { return builder.build(); } + private Map buildMapFromMetadata(StorageMetadata storageMetadata) { + Map map = new HashMap<>(); + map.put("name", storageMetadata.getName()); + map.put("bucket", storageMetadata.getBucket()); + map.put("generation", storageMetadata.getGeneration()); + map.put("metadataGeneration", storageMetadata.getMetadataGeneration()); + map.put("path", storageMetadata.getPath()); + map.put("sizeBytes", storageMetadata.getSizeBytes()); + map.put("creationTimeMillis", storageMetadata.getCreationTimeMillis()); + map.put("updatedTimeMillis", storageMetadata.getUpdatedTimeMillis()); + map.put("md5Hash", storageMetadata.getMd5Hash()); + map.put("cacheControl", storageMetadata.getCacheControl()); + map.put("contentDisposition", storageMetadata.getContentDisposition()); + map.put("contentEncoding", storageMetadata.getContentEncoding()); + map.put("contentLanguage", storageMetadata.getContentLanguage()); + map.put("contentType", storageMetadata.getContentType()); + return map; + } + private void getData(MethodCall call, final Result result) { Integer maxSize = call.argument("maxSize"); String path = call.argument("path"); diff --git a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m index b16e7b4839f9..87e21113f32a 100644 --- a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m +++ b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m @@ -50,6 +50,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self delete:call result:result]; } else if ([@"StorageReference#getMetadata" isEqualToString:call.method]) { [self getMetadata:call result:result]; + } else if ([@"StorageReference#updateMetadata" isEqualToString:call.method]) { + [self updateMetadata:call result:result]; } else { result(FlutterMethodNotImplemented); } @@ -93,6 +95,29 @@ - (FIRStorageMetadata *)buildMetadataFromDictionary:(NSDictionary *)dictionary { return metadata; } +- (NSDictionary *)buildDictionaryFromMetadata:(FIRStorageMetadata *)metadata { + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + [dictionary setValue:[metadata bucket] forKey:@"bucket"]; + [dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata generation]] + forKey:@"generation"]; + [dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata metageneration]] + forKey:@"metadataGeneration"]; + [dictionary setValue:[metadata path] forKey:@"path"]; + [dictionary setValue:@((long)([[metadata timeCreated] timeIntervalSince1970] * 1000.0)) + forKey:@"creationTimeMillis"]; + [dictionary setValue:@((long)([[metadata updated] timeIntervalSince1970] * 1000.0)) + forKey:@"updatedTimeMillis"]; + [dictionary setValue:@([metadata size]) forKey:@"sizeBytes"]; + [dictionary setValue:[metadata md5Hash] forKey:@"md5Hash"]; + [dictionary setValue:[metadata cacheControl] forKey:@"cacheControl"]; + [dictionary setValue:[metadata contentDisposition] forKey:@"contentDisposition"]; + [dictionary setValue:[metadata contentEncoding] forKey:@"contentEncoding"]; + [dictionary setValue:[metadata contentLanguage] forKey:@"contentLanguage"]; + [dictionary setValue:[metadata contentType] forKey:@"contentType"]; + [dictionary setValue:[metadata name] forKey:@"name"]; + return dictionary; +} + - (void)getData:(FlutterMethodCall *)call result:(FlutterResult)result { NSNumber *maxSize = call.arguments[@"maxSize"]; NSString *path = call.arguments[@"path"]; @@ -121,30 +146,25 @@ - (void)getMetadata:(FlutterMethodCall *)call result:(FlutterResult)result { if (error != nil) { result(error.flutterError); } else { - NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; - [dictionary setValue:[metadata bucket] forKey:@"bucket"]; - [dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata generation]] - forKey:@"generation"]; - [dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata metageneration]] - forKey:@"metadataGeneration"]; - [dictionary setValue:[metadata path] forKey:@"path"]; - [dictionary setValue:@((long)([[metadata timeCreated] timeIntervalSince1970] * 1000.0)) - forKey:@"creationTimeMillis"]; - [dictionary setValue:@((long)([[metadata updated] timeIntervalSince1970] * 1000.0)) - forKey:@"updatedTimeMillis"]; - [dictionary setValue:@([metadata size]) forKey:@"sizeBytes"]; - [dictionary setValue:[metadata md5Hash] forKey:@"md5Hash"]; - [dictionary setValue:[metadata cacheControl] forKey:@"cacheControl"]; - [dictionary setValue:[metadata contentDisposition] forKey:@"contentDisposition"]; - [dictionary setValue:[metadata contentEncoding] forKey:@"contentEncoding"]; - [dictionary setValue:[metadata contentLanguage] forKey:@"contentLanguage"]; - [dictionary setValue:[metadata contentType] forKey:@"contentType"]; - [dictionary setValue:[metadata name] forKey:@"name"]; - result(dictionary); + result([self buildDictionaryFromMetadata:metadata]); } }]; } +- (void)updateMetadata:(FlutterMethodCall *)call result:(FlutterResult)result { + NSString *path = call.arguments[@"path"]; + NSDictionary *metadataDictionary = call.arguments[@"metadata"]; + FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + [ref updateMetadata:[self buildMetadataFromDictionary:metadataDictionary] + completion:^(FIRStorageMetadata *metadata, NSError *error) { + if (error != nil) { + result(error.flutterError); + } else { + result([self buildDictionaryFromMetadata:metadata]); + } + }]; +} + - (void)getDownloadUrl:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; diff --git a/packages/firebase_storage/lib/firebase_storage.dart b/packages/firebase_storage/lib/firebase_storage.dart index 36ceba6bcb24..e36222f4c198 100755 --- a/packages/firebase_storage/lib/firebase_storage.dart +++ b/packages/firebase_storage/lib/firebase_storage.dart @@ -69,6 +69,21 @@ class StorageReference { })); } + /// Updates the metadata associated with this [StorageReference]. + /// + /// Returns a [Future] that will complete to the updated [StorageMetadata]. + /// + /// This method ignores fields of [metadata] that cannot be set by the public + /// [StorageMetadata] constructor. Writable metadata properties can be deleted + /// by passing the empty string. + Future updateMetadata(StorageMetadata metadata) async { + return new StorageMetadata._fromMap(await FirebaseStorage.channel + .invokeMethod("StorageReference#updateMetadata", { + 'path': _pathComponents.join("/"), + 'metadata': metadata == null ? null : _buildMetadataUploadMap(metadata), + })); + } + String get path => _pathComponents.join('/'); } @@ -174,16 +189,16 @@ class StorageUploadTask { _completer .complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl))); } +} - Map _buildMetadataUploadMap(StorageMetadata metadata) { - return { - 'cacheControl': metadata.cacheControl, - 'contentDisposition': metadata.contentDisposition, - 'contentLanguage': metadata.contentLanguage, - 'contentType': metadata.contentType, - 'contentEncoding': metadata.contentEncoding, - }; - } +Map _buildMetadataUploadMap(StorageMetadata metadata) { + return { + 'cacheControl': metadata.cacheControl, + 'contentDisposition': metadata.contentDisposition, + 'contentLanguage': metadata.contentLanguage, + 'contentType': metadata.contentType, + 'contentEncoding': metadata.contentEncoding, + }; } class UploadTaskSnapshot { diff --git a/packages/firebase_storage/pubspec.yaml b/packages/firebase_storage/pubspec.yaml index 966b7b40a8fe..dded619f8046 100755 --- a/packages/firebase_storage/pubspec.yaml +++ b/packages/firebase_storage/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Firebase Cloud Storage, a powerful, simple, and cost-effective object storage service for Android and iOS. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/firebase_storage -version: 0.2.5 +version: 0.2.6 flutter: plugin: diff --git a/packages/firebase_storage/test/firebase_storage_test.dart b/packages/firebase_storage/test/firebase_storage_test.dart index 0052b4d4447e..d73a8c62e127 100644 --- a/packages/firebase_storage/test/firebase_storage_test.dart +++ b/packages/firebase_storage/test/firebase_storage_test.dart @@ -86,6 +86,68 @@ void main() { }); }); + group('updateMetadata', () { + final List log = []; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + switch (methodCall.method) { + case 'StorageReference#getMetadata': + return { + 'name': 'image.jpg', + }; + break; + case 'StorageReference#updateMetadata': + return { + 'name': 'image.jpg', + 'contentLanguage': 'en' + }; + break; + default: + break; + } + }); + ref = FirebaseStorage.instance + .ref() + .child('avatars') + .child('large') + .child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.updateMetadata(const StorageMetadata(contentLanguage: 'en')); + + expect(log, [ + isMethodCall( + 'StorageReference#updateMetadata', + arguments: { + 'path': 'avatars/large/image.jpg', + 'metadata': { + 'cacheControl': null, + 'contentDisposition': null, + 'contentLanguage': 'en', + 'contentType': null, + 'contentEncoding': null + }, + }, + ), + ]); + }); + + test('returns correct result', () async { + expect((await ref.getMetadata()).contentLanguage, null); + expect( + (await ref.updateMetadata( + const StorageMetadata(contentLanguage: 'en'))) + .contentLanguage, + 'en'); + }); + }); + group('getDownloadUrl', () { final List log = [];