-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(storage): Firebase Storage for AngularFire #865
Conversation
We found a Contributor License Agreement for you (the sender of this pull request) and all commit authors, but as best as we can tell these commits were authored by someone else. If that's the case, please add them to this pull request and have them confirm that they're okay with these commits being contributed to Google. If we're mistaken and you did author these commits, just reply here to confirm. |
1 similar comment
We found a Contributor License Agreement for you (the sender of this pull request) and all commit authors, but as best as we can tell these commits were authored by someone else. If that's the case, please add them to this pull request and have them confirm that they're okay with these commits being contributed to Google. If we're mistaken and you did author these commits, just reply here to confirm. |
omg man, I need to test this :D |
I would like to propose creating a service similar to Currently the |
// $observe is like $watch but it waits for interpolation | ||
// Ex: <img firebase-src="{{ myUrl }}"/> | ||
attrs.$observe('firebaseSrc', function (newVal) { | ||
if (newVal !== '' && newVal !== null && newVal !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand how this directive should work. It appears the directive's purpose is to generate the url to the file based on a path to the file. This path looks to be provided by the gs-url
attribute. The code though is setup to watch the value myUrl
passed in by the user. What exactly is the user suppose to be passing to the directive? It appears the directive should be using the observed value of the firebase-src
attribute instead of the gs-url
attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an error from an earlier prototype. I have it fixed in a local version. I'm working on some final tests and hope to have it submitted soon!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davideast I see you made the update, but changed it to use attrs.firebaseSrc
instead of the interpolated value newVal
. Does that work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disregard my last comment. I just tested with the recent changes and all appears to be working.
@soumak77 I too would like to have a provider for storage references! This release though will be dedicated to the core storage functionality. I think we could do that in the next release though 😄 |
Oh man @davideast i am following all your updates to this firebase Storage and cant wait until I can try it out. Keep up the good work man, love it |
@davideast Could you add a The use case for such a directive would be when you want to download the file from firebase and only have a path:
This mirrors the usage of
|
Is there by any chance that I can try this out ? and maybe add a example ? The storage feature is the only thing that I feel like I am missing. Firebase is so damn awsome. |
@davideast - FYI that if you merge your branch with |
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that they're okay with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
@@ -11,6 +11,9 @@ | |||
"bugs": { | |||
"url": "https://github.com/firebase/angularfire/issues" | |||
}, | |||
"scripts": { | |||
"start": "grunt" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove it since we got the Travis thing figured out and in Travis, we need to run a special script anyway, not just grunt
.
}); | ||
}, | ||
$error: function $error(callback) { | ||
task.on('state_changed', function () {}, function (err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: for clarity, use null
instead of function () {}
.
$progress: function $progress(callback) { | ||
task.on('state_changed', function () { | ||
$digestFn(function () { | ||
callback([unwrapStorageSnapshot(task.snapshot)]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you want the brackets ([]
) here. Should just be callback(unwrapStorageSnapshot(task.snapshot));
. Same for the callbacks below.
|
||
function _assertStorageRef(storageRef) { | ||
if (!isStorageRef(storageRef)) { | ||
throw new Error('$firebaseStorage expects a storage reference from firebase.storage().ref()'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: "$firebaseStorage expects a Storage reference"
- Capitalizing "Storage"
- Taking out "from firebase.storage().ref()" since it could also come from "app.storage().ref()"
|
||
Storage.utils = { | ||
_unwrapStorageSnapshot: unwrapStorageSnapshot, | ||
_$put: _$put, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doest _$put()
need to be exposed on Storage.utils
? Shouldn't having Storage.$put()
be enough?
expect(browser.getTitle()).toEqual('AngularFire Upload e2e Test'); | ||
}); | ||
|
||
it('starts with an empty list of messages', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test seems unneeded for the upload test suite.
}); | ||
|
||
it('uploads a file', function (done) { | ||
var fileToUpload = './upload/logo.png', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation for this whole test is off. Also, please use a new var
/ line for each variable.
|
||
}); | ||
|
||
describe('_$put', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted above, we shouldn't need to expose this method and should just move these tests under the public $put
method.
// test that $firebaseStorage.$delete() calls storageRef.delete() | ||
var ref = firebase.storage().ref('thing'); | ||
var storage = $firebaseStorage(ref); | ||
var fakePromise = $q(function(resolve, reject) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable.
|
||
describe('$delete', function() { | ||
it('should call the storage ref delete method', function() { | ||
// test that $firebaseStorage.$delete() calls storageRef.delete() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unneeded comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think this is the last major set of review comments. I took a close look at the API of the underlying Firebase SDK and think we should make a few changes to methods to better align there. Other than that, everything looks good!
(function() { | ||
"use strict"; | ||
|
||
function unwrapStorageSnapshot(storageSnapshot) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: You have _assertStorageRef()
below, but don't use a leading underscore in front of unwrapStorageSnapshot()
and isStorageRef()
. Let's put a leading underscore in front of each of them for consistency.
var Storage = function Storage(storageRef) { | ||
_assertStorageRef(storageRef); | ||
return { | ||
$put: function $put(file) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave a look through the API reference for firebase.storage.Reference
, and I notice there are two methods which we do not have listed here:
putString()
- I think this method was added after you started this proposal, but we should include it since it allows for some use cases that the regularput()
doesn't cover. It should be easy enough to refactor the code you wrote for$put()
to implement$putString()
as well.toString()
- I assume we don't technically need to include this since it is a synchronous method and you could always just use the underlying method on thestorageRef
you pass in here, but it is probably good to include a$toString()
method here for completeness.
$pause: task.pause, | ||
then: task.then, | ||
catch: task.catch, | ||
_task: task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like in the underlying SDK, UploadTask
has a snapshot
property. Since we are returning an object which is the AngularFire version of UploadTask
, we should probably have $snapshot: task.snapshot
here instead of _task: task
.
// $observe is like $watch but it waits for interpolation | ||
// Ex: <img firebase-src="{{ myUrl }}"/> | ||
attrs.$observe('firebaseSrc', function (newFirebaseSrcVal) { | ||
if (newFirebaseSrcVal !== '' && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I think my comment last time around was confusing. This conditional can be simplified to:
if (typeof newFirebaseSrcVal === 'string' && newFirebaseSrcVal !== '')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if the passed value of newFirebaseSrcVal
is invalid, do we want to throw an error? Seems like we are just silently failing in that case which will be hard for developers to track down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, upon further testing and research I found out the attrs.$observe
converts any value into a string. Therefore if you pass in an object, number, or bool it is automatically handled which makes the string check extra work. If you pass a null
or undefined
it is converted to an empty string, which is the only thing we need to check for.
var app = angular.module('upload', ['firebase.storage']); | ||
|
||
app.controller('UploadCtrl', function Upload($scope, $firebaseStorage, $timeout) { | ||
// Create a reference (possible create a provider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the part of this comment within parentheses required?
$scope.upload = function() { | ||
$scope.isUploading = true; | ||
$scope.metadata = {bytesTransferred: 0, totalBytes: 1}; | ||
$scope.error = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: use null
instead of {}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we never actually use $scope.error
in the HTML file. We should add a conditional <div>
which shows the error if there is one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with four last minor testing related comments.
task.catch(); | ||
expect(mockTask.catch).toHaveBeenCalled(); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test for $snapshot
as well.
}); | ||
|
||
describe('$putString', function() { | ||
it('should call a storage ref put', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/put/putString
}); | ||
}); | ||
|
||
function setupPutTests(file, mockTask, isPutString) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/file/fileOrRawString
} else { | ||
spyOn(ref, putMethod); | ||
} | ||
task = storage['$' + putMethod](file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of isPutString
, let's actually pass "raw"
as the second parameter after fileOrRawString
.
Let's also pass some file metadata for both put()
and putString()
to make sure that is getting carried on as well:
var metadata = {
contentType: 'image/jpeg',
};
if (isPutString) {
task = storage.putString(fileOrRawString, 'raw', metadata);
} else {
task = storage.put(fileOrRawString, metadata);
}
Then you'll need to update the tests below which check the arguments passed to put()
and putString()
.
LGTM. Nice work! |
Does that mean we can use the storage right now ? :) |
@fallais Not yet, but soon! I'm writing up docs and then we'll do a release :) |
Yes, can we? :) |
This is so perfect, well done all
…On Sat, 14 Jan 2017 at 05:34, bpkennedy ***@***.***> wrote:
Yes, can we? :)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#865 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AE0dz-UVO3pDgrLKaGNFp3ihSn2CQdhVks5rSFBPgaJpZM4KaC-->
.
|
Firebase Storage for AngularFire!
Addresses #785. This is a WIP PR, do not merge yet.
Description
This PR adds two new services to AngularFire,
$firebaseStorage
and the[firebase-src]
directive.API Reference
Code sample