Chandra Sekhar
Chandra Sekhar

Reputation: 19492

Update Firebase database on Storage change using Firebase Functions

I am trying to implement the Profile Picture feature in my Android app. So I have used Generate Thumbnail sample from firebase. So whenever I am uploading an full sized image, it generates and thumbnail for me. But I want to update the URL of thumbnail in my realtime database once the thumbnail is generated.

const functions = require('firebase-functions');
const mkdirp = require('mkdirp-promise');
const gcs = require('@google-cloud/storage')();
const spawn = require('child-process-promise').spawn;
const LOCAL_TMP_FOLDER = '/tmp/';

// Max height and width of the thumbnail in pixels.
const THUMB_MAX_HEIGHT = 100;
const THUMB_MAX_WIDTH = 100;
// Thumbnail prefix added to file names.
const THUMB_PREFIX = 'thumb_';

/**
 * When an image is uploaded in the Storage bucket We generate a thumbnail automatically using
 * ImageMagick.
 */
exports.generateThumbnail = functions.storage.object().onChange(event => {
  const filePath = event.data.name;
  const filePathSplit = filePath.split('/');
  const fileName = filePathSplit.pop();
  const fileDir = filePathSplit.join('/') + (filePathSplit.length > 0 ? '/' : '');
  const thumbFilePath = `${fileDir}${THUMB_PREFIX}${fileName}`;
  const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`;
  const tempLocalFile = `${tempLocalDir}${fileName}`;
  const tempLocalThumbFile = `${LOCAL_TMP_FOLDER}${thumbFilePath}`;

  // Exit if this is triggered on a file that is not an image.
  if (!event.data.contentType.startsWith('image/')) {
    console.log('This is not an image.');
    return;
  }

  // Exit if the image is already a thumbnail.
  if (fileName.startsWith(THUMB_PREFIX)) {
    console.log('Already a Thumbnail.');
    return;
  }

  // Exit if this is a move or deletion event.
  if (event.data.resourceState === 'not_exists') {
    console.log('This is a deletion event.');
    return;
  }

  // Create the temp directory where the storage file will be downloaded.
  return mkdirp(tempLocalDir).then(() => {
    // Download file from bucket.
    const bucket = gcs.bucket(event.data.bucket);
    return bucket.file(filePath).download({
      destination: tempLocalFile
    }).then(() => {
      console.log('The file has been downloaded to', tempLocalFile);
      // Generate a thumbnail using ImageMagick.
      return spawn('convert', [tempLocalFile, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile]).then(() => {
        console.log('Thumbnail created at', tempLocalThumbFile);
        // Uploading the Thumbnail.
        return bucket.upload(tempLocalThumbFile, {
          destination: thumbFilePath
        }).then(() => {
          console.log('Thumbnail uploaded to Storage at', thumbFilePath);
          // Don't know what to write here.
        });
      });
    });
  });
});

Once the final promise of this code completes, I want to take the downloadable URL from the generated profile pic at /users/{userId}/profilePic

Upvotes: 1

Views: 1171

Answers (1)

Adam Brocklehurst
Adam Brocklehurst

Reputation: 513

You'll need to add a couple things to achieve what you want here. Firstly you need to require firebase-admin and initialize the app.

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

This should be done at the top of the file after you require the other components.

Once you've got that you can add some code into the final promise to update the database with the new reference.

.then(() => {
      console.log('Thumbnail uploaded to Storage at', thumbFilePath);
       //userID here would be the userID that you want to update. I couldn't see a reference to it in the code you provided.
       var databaseRef = admin.database().ref('users').child(userID).child("profilePic");
       databaseRef.transaction(function(oldValue) {
           return bucket.file(thumbFilePath).getDownloadURL().then(funct‌​ion(url) {
                return url;
           }

       });
});

You can read about the transaction to update the reference here. I've only included the mandatory transactionUpdate parameter and not the optional parameters that you may want. https://firebase.google.com/docs/reference/admin/node/admin.database.Reference#transaction

Upvotes: 3

Related Questions