0
votes

So there were some wrong records in my firestore collection users : the image field (the wrong path: users/uid/name.jpg, expected output :

https://firebasestorage.googleapis.com/v0/b/project-id.appspot.com/o/users%2F4yWeML3ktpVt6oWowtEhg8oJx1I3%2Fcropped828392415291985722.jpg?alt=media&token=6daeeab9-6b34-4a27-a4d5-0789a7d773c3

) - The image in the storage is saved as :

users > user_id > cropped{fileName}.jpg

So I wrote a cloud function to take all the files from bucket 'users'

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import { Storage } from "@google-cloud/storage";
admin.initializeApp({
  credential: admin.credential.cert({
    projectId: "myProjectId",
    clientEmail:
      "[email protected]",
    privateKey:
      "-----BEGIN PRIVATE KEY-----\nmyprivatekey=\n-----END PRIVATE KEY-----\n"
  }),
  storageBucket: "myProject.appspot.com"
});

const db = admin.firestore();
const storage = new Storage({
  projectId: "myProjectId",
  credentials: {
    client_email: "[email protected]",
    private_key:  "-----BEGIN PRIVATE KEY-----\nMyPrivateKey=\n-----END PRIVATE KEY-----\n"
  }
});

export const updateUserImage = functions.https.onRequest((request, response) => {
    const wrongData: any = [];
    db.collection("users")
      .where("image", ">=", "/users")
      .orderBy("image", "asc")
      .get()
      .then(res => {
        res.forEach(ele => {
          if (ele.data().hasOwnProperty("image")) {
            console.log(ele.data().image.includes("/firebasestorage"));
            if (!ele.data().image.includes("/firebasestorage")) {
              wrongData.push(ele);
            }
          }
        });
        console.log('Wrong docs: ' + wrongData.length);
        for (const doc of wrongData) {
          const getFileName = doc.data().image.split("/")[3];
          const subFolder = doc.data().image.split("/")[2];
          console.log(getFileName);
          storage.bucket('users').file(`${subFolder}/${getFileName}`).get()
          .then((fileData: any) => {
            console.log(fileData);
          }).catch(err => console.log(err))
        }
      })
      .catch(err => console.log(err));
  }
);

I deployed this function then test locally with firebase emulators, all the packages are updated to latest in package.json :

"dependencies": {
    "@google-cloud/firestore": "^2.2.6",
    "@google-cloud/storage": "^3.1.0",
    "@google/maps": "^0.5.5",
    "@types/google__maps": "^0.5.5",
    "express": "^4.17.1",
    "firebase": "^6.3.5",
    "firebase-admin": "^8.3.0",
    "firebase-functions": "^3.2.0"
  },

However when I debug by the command : firebase serve --only functions even though the admin SDK can get the data but when get the files from storage it's throwing the error:

{ Error: [email protected] does not have storage.objects.get access to users/4yWeML3ktpVt6oWowtEhg8oJx1I3/cropped828392415291985722.jpg. }

I surfed over the internet and setted the permission on Google cloud storage - Google Cloud platform console for this account, including roles:

  1. Firebase admin SDK Administrative Agents (default by Google when generating the json)

  2. Storage admin

  3. Owner

  4. Storage object admin

then waits for 5 minutes but still got that same error when I tried to call the function locally. Is it something missing in configs ? I'm kinda new to Cloud functions and Cloud storage

1

1 Answers

0
votes

Your code is trying to access files in a bucket called "users":

storage.bucket('users')

But I'm 100% certain that your bucket name is not "users". Bucket name is not the same as the names of "folders" that appear inside your bucket. Your bucket is more likely to have a name that matches your project ID, or it's a globally unique name (among all buckets in all projects in all of Google Cloud) you made up at the time you created it.