After attempting to delete a file I get the notification that it was successful. However, when I check the storage console page the document is still there.
If I manually specify the name of a file that was previously uploaded then that one will be deleted successfully.
Any idea what I'm doing wrong here? Is it somehow related to the fact that I just uploaded the file and now I'm deleting it? Is there some kind of cache on the storage ref that I have to query again in order for it to know that the new file exists?
I am following the documentation provided by Google here.
https://firebase.google.com/docs/storage/web/delete-files
Here is my code
const storage = firebase.storage();
const picture = storage.ref().child('images/' + file.name);
picture
.delete()
.then(function () {
notification.success({
message: 'File Deleted',
placement: 'bottomLeft',
});
})
.catch(function (error) {
console.error(error);
notification.warning({
message: 'There was an error',
placement: 'bottomLeft',
});
});
Update
When I say, "manually specifying the file" I mean that I can do this
const picture = storage.ref().child('images/alreadyUploadedImage.png');
Then run the same code to delete. This is why I asked about caching since it seems that if I reload my browser session by changing this text in my code that I can now delete a file. Also, this doesn't work for the file I just uploaded (before I refresh my browser). If I change the name in the code to, 'images/image.png' and then upload an image with that name and then immediately try to delete it, it doesn't work. But if I then refresh the browser and add another image, then delete that one, the 'image.png' file is gone from storage.
Here is a gif showing the file and firebase storage after the delete is complete on the client.
It turns out I was calling the put method again after I was calling the delete method. I'm using AntD and the Upload component, which has getValueFromEvent={normFile}. This, "normFile" function gets called every time a file is uploaded or removed. So I just had to return from that function if the event was, event.status === 'removed'.
Related
I am returning a CSV download from my server like so:
$headers = ['Content-Type' => 'application/csv'];
return response()->download($filepath, $filename, $headers)->deleteFileAfterSend(true);
This is actually working and downloading to the browser like I want.
The problem is that I am trying to change a class on a button from a download icon to a spinning icon and back to the original download icon once the response from the back-end has returned successfully - I am attempting this in my .then function in vue:
The icon within a button with said class I am trying to affect, in the <template> section of my Vue:
<button #click="formSubmit($event)"<i id="loadSpinner" class='zmdi zmdi-download' :class="spin"></i></button>
Vue data attribute bound to "spin" variable which holds the class name:
export default {
data() {
return {
spin: ''
selected: ''
}
}
Methods containing the formSubmit method and subsequent logic:
formSubmit(e) {
let currentObj = this;
currentObj.spin = 'zmdi zmdi-rotate-right zmdi-hc-spin';
if(this.selected.length > 0){
axios.post('/commercial', {
responseType: 'blob',
ratecard: currentObj.selected
}).then(function (response) {
currentObj.spin = 'zmdi zmdi-download';
console.log(response);
}).catch(function (error) {
currentObj.output = error;
console.log(currentObj.output);
});
}else {
currentObj.spin = 'zmdi zmdi-download';
swal({
type: 'error',
title: 'Oops...',
text: 'Please select an account reference'
});
e.preventDefault(); //to prevent white-page issue and page refresh
}
}
The response is a blob - so the selected value is sent through fine and response is fine in terms of desired functionality i.e. return a CSV download to the users browser. However, where I am trying to change the 'spin' class this only seems to work in Chrome - even then, the console.log(response.data) does not appear in my console even in Chrome - it's as if this function is partially entered (if that's even a thing) or not entered at all as is seemingly the case with Firefox/Safari.
The initial class change to the 'spin' icon works - it's the change back that does not work.
I have tried pure javascript attempt also using document.getElementsbyID and attempting to affect the class using .className attribute directly and the same can be said using JQuery
If anybody can point me in the right direction that would be much appreciated - I am on hand to provide further information if required.
I can't figure out/isolate if this is a browser specific issue or an issue with Vue/Laravel.
Thanks.
Problem with this was how the request/response cycle was being caught in the front-end. Had to use a npm JS package that handled response and downloaded files on the front-end called JS FileDownloader in order for the files to be "seen" as downloaded and the proceeding JS scripts/CSS styling etc to kick-in after.
Is there a simple way to get the download URL of a file uploaded to Firebase?
(I've tried playing around with the snapshot returned by my upload function and couldn't find anything...)
fileref.put(file).then(function(snapshot){
self.addEntry(snapshot);
/// return snapshot.url???
});
The documentation referenced by Yamil - Firebase javascript SDK file upload - recommends using the snapshot's ref property to invoke the getDownloadURL method, which returns a promise containing the download link:
Using your code as a starting point:
fileref.put(file)
.then(snapshot => {
return snapshot.ref.getDownloadURL(); // Will return a promise with the download link
})
.then(downloadURL => {
console.log(`Successfully uploaded file and got download link - ${downloadURL}`);
return downloadURL;
})
.catch(error => {
// Use to signal error if something goes wrong.
console.log(`Failed to upload file and get link - ${error}`);
});
I know it seems like unnecessary effort and that you should be able to get the link via a property of the snapshot, but this is what the Firebase team recommends - they probably have a good reason for doing it this way.
To get the Url created by default from the snapshot you can use downloadURL, meaning snapshot.downloadURL.
Remember to always keep tracking the progress of the upload by using .on('state_changed'), Documentation here.
When using user based security rules as given in official docs
// Only an individual user can write to "their" images
match /{userId}/{imageId} {
allow write: if request.auth.uid == userId;
}
url retrieved by snapshot.downloadURL is exposing userId. How to overcome this security risk.
I know how to add data to the firebase database, I know how to upload image to the firebase storage. I am doing this in javascript.
I am not able to figure out how to link the image to my database object.
My database object is something like this
{
name:'alex',
age:23,
profession:'superhero'
image:*what to put here ???*
}
One idea is to use the object reference that is created and store the image using the same reference.
Any tutorial or ideas appreciated.
We often recommend storing the gs://bucket/path/to/object reference, otherwise store the https://... URL.
See Zero to App and it's associated source code (here we use the https://... version) for a practical example.
var storageRef = firebase.storage().ref('some/storage/bucket');
var saveDataRef = firebase.database().ref('users/');
var uploadTask = storageRef.put(file);
uploadTask.on('state_changed', uploadTick, (err)=> {
console.log('Upload error:', err);
}, ()=> {
saveDataRef.update({
name:'alex',
age:23,
profession:'superhero'
image:uploadTask.snapshot.downloadURL
});
});
This upload function sits inside a ES6 class and is passed a callback (uploadTick) for the .on('state_changed') from the calling component. That way you can pass back upload status and display that in the UI.
uploadTick(snap){
console.log("update ticked", snap)
this.setState({
bytesTransferred:snap.bytesTransferred,
totalBytes:snap.totalBytes
})
}
The file to upload is passed to this upload function, but I am just using a react form upload to get the file and doing a little processing on it, your approach may vary.
I have a products collection and I want to allow users to add multiple images to them.
The catch is I want images to upload instantly but because the product isnt saved yet the images can't be embedded or joined by foreign key.
Is it possible to store the images clientside then after the product gets saved. I add the images to the product database?
How should I solve this?
Thanks
var imageStore = new FS.Store.GridFS("images");
Images = new FS.Collection("images", {
stores: [
new FS.Store.FileSystem("original")
],
filter: {allow: {contentTypes: ['image/*']}}
});
In Meteor, images will upload "instantly" due to the "db everywhere" paradigm,ie they will be stored optimistically in the MiniMongo client-side db and then sent to the server. If they are rejected by the server, an error should be generated re the reason for the rejection (in your server logs.)
For code samples of how to upload files using CollectionFS, take a look at these code samples at the CollectionFS wiki.
This one, for example, seems to be what you are looking for:
Template.myForm.events({
'change .myFileInput': function(event, template) {
FS.Utility.eachFile(event, function(file) {
Images.insert(file, function (err, fileObj) {
//If !err, we have inserted new doc with ID fileObj._id, and
//kicked off the data upload using HTTP
});
});
}
});
Once the files are have been stored in the client db, you should be able to display them instantly, such as using this method.
If this doesn't help, please provide a link to a repo or more details re. the issue, such as any errors that are being generated, esp server-side errors.
There are two conditionals involved here:
1) When the user first enters the page, an image may not already be uploaded and nothing is shown.
2) An image may already be uploaded, in which case it should show and be overridden in real time when a new image is uploaded to replace it.
The whole uploading thing and displaying it right away is taken care of, it's just updating the image in case 2 that I'm struggling with.
When I upload the image, two things happen as can be seen here:
uploadImage('myDirective', d_canvas, 'image/png', function (error, downloadUrl) {
if (! error) {
Meteor.call('updateDatabase', versionId, downloadUrl)
Session.set('imageAvailableAt', downloadUrl)
}
})
First it calls a method to update the database to add the new url. Second it sets the same url in a Session variable. Note that no matter if an image exists or not, the url will be the same and it will overridden automatically if it does.
The image review looks like this in the template:
{{#with uploadedImage}}
<div class="preview-of-uploaded-image">
<img src="{{this}}">
</div>
{{/with}}
And the helper:
var image = Session.get('imageAvailableAt')
return image
All right, this takes care of case 1, and it will display the image very neatly when it is uploaded.
But clearly nothing will show when an image is already uploaded here, and I have played with setting the same Session variable on onRendered, but then it won't update when I upload something new. I've tried different Session variables and conditionals but no luck. I've also tried Tracker.autorun but that doesn't work at all as described in the docs so I gave that up pretty quickly as well.
What should I do?
You are facing a caching issue, the image URL is being cached by the browser and it will continue showing the old version for some time although the actual resource pointed at has been updated.
What you need to do to solve your problem is append a timestamp to the URL when modifying the collection server-side.
In your Meteor method, when updating the collection, be sure to decorate the URL with the current timestamp using something like :
Meteor.methods({
updateDatabase: function(versionId, downloadUrl){
check(versionId, String);
check(downloadUrl, String);
[...]
Collection.update({
downloadUrl: downloadUrl + "?timestamp=" + Date.now()
});
}
});