Delete image on S3


#1

I use Slingshot for upload to S3. How do I delete an image from S3?

I tried peerlibrary:aws-sdk. That works but I don’t know how to set AWSAccessKeyId in client without making in public. I guess it’s not a good idea to add in pure text in the helper or can I do that?


#2

The regular node.js S3 library (aws-sdk on npm) works well for deleting and manipulating objects (run this on the server; you can call it from a method):

    var AWS = Meteor.npmRequire('aws-sdk');
    var s3 = new AWS.S3({
      accessKeyId: /* pull from Meteor.settings */, 
      secretAccessKey: /* pull from Meteor.settings */
    });
    s3.deleteObject({
      Bucket: /* bucket name */, 
      Key: /* key name */
    });

#3

Thanks. Got an error. Error invoking Method …: Internal server error [500]

My fault. No error now.


#4

I just figured this out myself and wanted to contribute my full method. I’d appreciate any criticism if I’m doing anything wrong. I was trying to figure out how to prevent the database from deleting my user’s entry until after Amazon confirmed the file was deleted with async, but couldn’t get it to work.

An authenticated client-side event triggers the Server-Side method (Is this secure?)

Template.file.events = {
  "click .delete-photo" : function () {
    // Remove from S3 and Database.
    Meteor.call('removePhotoData', this._id);
  }
};

This is the server-side method:

Meteor.methods({
  'removePhotoData': function (selectedPhoto){
    check( selectedPhoto, String );

    // Current User
    var currentUserId = Meteor.userId();

    // Get the URL of the photo they are trying to remove.
    var currentPhoto = Files.findOne( { '_id': selectedPhoto, 'userId': currentUserId }, { fields: { 'url': 1 } } );

    // Our photo bucket, e.g. 'mybucket'
    var bucket = /* pull from Meteor.settings */;

    // URL string: e.g. https://mybucket.s3.amazonaws.com/images/myimage.jpg is saved in DB,
    // I only want: 'images/myimage.jpg'
    var currentPhotoURL = currentPhoto.url.replace('https://' + bucket + '.s3.amazonaws.com/', '');


    AWS.config.update({
      accessKeyId: /* pull from Meteor.settings */,
      secretAccessKey: /* pull from Meteor.settings */,
    });

    var s3 = new AWS.S3();
    var params = {
      Bucket: bucket, // 'mybucket'
      Key: currentPhotoURL // 'images/myimage.jpg'
    };

    var deleteObject = Meteor.wrapAsync(
      s3.deleteObject(params, function (error, data) {
        if (error) {
          console.log(error);
        }
        else {
          console.log(data);
        }
      })
    );
    // Remove the entry in the database. (Want to only trigger this if there is no error from Amazon).
    Files.remove({_id: selectedPhoto, userId: currentUserId});
  }
});

#5

I was wrong again. I get “Error invoking Method ‘deleteS3’: Internal server error [500]” when using your example brianlukoff. What could be wrong?


#6

Watch the server console for the real error? Of is there nothing visible?


#7

Server console, of course :slight_smile: There it was. Got it working now. Thanks for the help.


#8

Think so. Looks like my solution. Authentication on the server.


#9

Very useful post, thank you. I had to add aws-sdk first:

meteor add peerlibrary:aws-sdk

And I had to restructure my URL replacement a bit because I’m not using the standard region. But it was easy enough to write the current URL to the console and see what to cut away.

My only other comment is that for a while I didn’t think it was working because my browser cached the deleted image so it was still visible!


#10

This construction lets me remove the image from the collection only if the delete succeeded:

s3.deleteObject(params, Meteor.bindEnvironment(function (error, data) {
      if (!error) {
        Images.remove({_id: image_id});
      }
    }));

However I haven’t figured out a way to send a callback to the client.


#11

Hello! Thank you for the post. Can you show me the code of the template?:stuck_out_tongue_winking_eye:


#12

use aws-sdk npm package. It would be helpfull.