0
votes

I want to be able to delete a folder in firebase storage while onDelete in functions is triggered.

here is my firebase node code, once deleted, it will trigger functions to delete the corresponding folder in firebase storage. I am allowing user to delete their message conversion that includes images. I was able to delete the folder without using the {friendId} but {friendId} is needed in case the user have conversions with two different users.

firebase node example

My Firebase storage is as follow

messages_image_from_friends/

  iLJ6nGJodeat2HRi5Q2xdTUmZnw2/

    MXGCZv96aVUkSHZeU8kNTZqTQ0n2/

      image.png

and Firebase Functions

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const firebase = admin.initializeApp();

exports.deletePhotos = functions.database.ref('/messagesFriends/{userId}/{friendId}')
                .onDelete((snap, context) => {

               const { userId } = context.params;

         <---- const { friendId } = context.params.friendId; ????? ---- >

               const bucket = firebase.storage().bucket();


         return bucket.deleteFiles({
         prefix: `messages_image_from_friends/${userId}/{friendId}`
             }, function(err) {

              if (err) {
                 console.log(err);
                } else {
             console.log(`All the Firebase Storage files in 
            messages_image_from_friends/${userId}/{friendId} have been deleted`);
                    }

                  });
  });

Log states that {friendId} is undefined. How do i get {friendId} from exports into prefix.

I have tried "snapshot" and "then()" but do not really know how to implement it as I am new to functions. Please help.

Update!!! 9/12/2020

I was able to get this working by changing onDelete to functions.https.onCall to use hashmap instead.. hope this help others

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const firebase = admin.initializeApp();

exports.deletePhotos = functions.https.onCall((data, context) => {

const userId = data.userId;
const friendId = data.friendId;

console.log(userId, friendId); 

const bucket = firebase.storage().bucket();

return bucket.deleteFiles({
    prefix: `messages_image_from_friends/`+userId+`/`+friendId+`/`
    }, function(err) {
        if (err) {
            console.log(err);
            } else {
                
console.log(`messages_image_from_friends/`+userId+`/`+friendId);
                }
                });

// return {response:"This means success"};

});

and the code to call the function from your android app

private FirebaseFunctions mFunctions;

protected void onCreate(Bundle savedInstanceState) {
mFunctions = FirebaseFunctions.getInstance();

 
////String userId is current firebase user id
////String friendId is from getIntent(), etc 

deletePhotos(userId, friendId);

}

private Task<String> deletePhotos(String userId, String friendId) {
    // Create the arguments to the callable function.
    Map<String, Object> data = new HashMap<>();
    data.put("userId", userId);
    data.put("friendId", friendId);

    return mFunctions
            .getHttpsCallable("deletePhotos")
            .call(data)
            .continueWith(new Continuation<HttpsCallableResult, 
       String>() {
                @Override
                public String then(@NonNull Task<HttpsCallableResult> 
       task) throws Exception {
                    // This continuation runs on either success or 
        failure, but if the task
                    // has failed then getResult() will throw an 
        Exception which will be
                    // propagated down.
                    String result = (String) 
       task.getResult().getData();
                    return result;
                }
            });
      }

MAKE SURE YOU MAKE A NEW FIREBASE INIT FOLDER.. I MADE THE MISTAKE OF REDEPLOYING THIS DIRECTLY IN CLOUD FUNCTION CONSOLE WHILE IT WAS CONNECTED AS onDelete and IT WAS UPDATING THE index.js ONLY INSTEAD OF THE WHOLE FUNCTION FOLDER. SO DON'T DO WHAT I DID BECAUSE YOU WILL GET A TypeError: Cannot read property 'origin' of undefined at /srv/node_modules/cors/lib/

HOPE THIS HELPS OTHERS!!!

Update 9/18/20

I was able to make it work with onDelete with this

'use-strict'

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const firebase = admin.initializeApp();

exports.deletePhotos = 
functions.database.ref('/messagesFriends/{userId}/{friendId}')
            .onDelete((snap, context) => {

const userId = context.params.userId;
const friendId = context.params.friendId;

const bucket = firebase.storage().bucket();

console.log(userId + ' ' + friendId + " found");

return bucket.deleteFiles({
    prefix: `messages_image_from_friends/`+userId+`/`+friendId
    }, function(err) {
        if (err) {
            
console.log(`messages_image_from_friends/`+userId+`/`+friendId + ` 
remove error`);
            } else {
                
 console.log(`messages_image_from_friends/`+userId+`/`+friendId + ` 
 removed`);
                }
                });


 });
1

1 Answers

0
votes

context.params is an object whose properties are populated with each of the wildcards from the trigger path. You're not using it correctly.

const userId = context.params.userId;
const friendId = context.params.friendId;

I suggest reviewing the documentation for database triggers, especially the part on specifying the path:

You can specify a path component as a wildcard by surrounding it with curly brackets; ref('foo/{bar}') matches any child of /foo. The values of these wildcard path components are available within the EventContext.params object of your function. In this example, the value is available as event.params.bar.