I've got an onDelete trigger function to delete all files within a folder, and I am following it as per this post from GDE: https://medium.com/google-developer-experts/automatically-delete-your-firebase-storage-files-from-firestore-with-cloud-functions-for-firebase-36542c39ba0d
I initialise my app
const admin = require('firebase-admin');
admin.initializeApp();
And then have my onDelete function
const functions = require('firebase-functions');
const {deleteFiles} = require('../helpers/storageService');
module.exports = functions.firestore.document("designs/{userId}/designs/{designId}").onDelete((snap, context) => {
console.log("triggered");
context.params;
return deleteFiles(context.params)
});
This all works fine, however its within the deleteFiles function that it fails
exports.deleteFiles = async function(params) {
return admin.storage().bucket().deleteFiles({
prefix: `designs/${params.userId}/designs/${params.designId}"`
})
};
When this part of the function runs, it fails with Bucket name not specified or invalid. Specify a valid bucket name via the storageBucket option when initializing the app.
Does anyone know what is happening here? As far as i'm aware, I don't need to provide credentials to the Admin SDK when initialising because the triggers already have sufficient credentials.
Related
I am having some issues connecting my firebase storage with my google action. I need to be able to "download" the json files inside in order to be able to read and pick out what a user may need given data that they provide when they call the action.
Below is the code that I currently have, complied from the different APIs and other stackoverflow questions I have found.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore();
var storage = require('#google-cloud/storage');
const gcs = storage({projectId: 'aur-healthcare-group'});
const bucket = gcs.bucket('gs://aur-healthcare-group');
admin.storage().bucket().file('aur-healthcare-group/aur_members.json').download(function(errr, contents){
if(!err){
var jsObjext = JSON.parse(contents.toString('utf8'));
}
});
The current error I am receiving is "code":3,"message":"Function failed on loading user code. This is likely due to a bug in the user code. Error message: Error: please examine your function logs to see the error cause. When I check the logs I only get the above mentioned message again.
I believe that I am not accessing my firebase storage correctly and have trouble finding a good resource on how to access this correctly. Would somebody be able to give me an example of how to access the storage correctly so I will be able to apply it to my project?
Since you're running in Firebase Functions, you shouldn't need to require the #google-cloud/storage dependency directly. Rather, you can get the correctly authenticated storage component via admin.storage()
Following that, you shouldn't download the file to your function, as you would be better off reading directly into memory via a readStream.
With regards to your existing code error, it may be because you're checking if (!err) when the callback variable is errr.
I've done this in the past and here's a code snippet of how I achieved it. It's written in Typescript specifically, but I think you should be able to port it to JS if you're using that directly.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
import { Bucket } from '#google-cloud/storage';
admin.initializeApp()
const db = admin.firestore()
const bucket = admin.storage().bucket('project-id.appspot.com') // Use your project-id here.
const readFile = async (bucket: Bucket, fileName: string) => {
const stream = bucket.file(fileName).createReadStream();
return new Promise((resolve, reject) => {
let buffer = '';
stream.on('data', function(d: string) {
buffer += d;
}).on('end', function() {
resolve(buffer)
});
})
}
app.handle('my-intent-handler', async (conv) => {
const contents = await readArticle(bucket, 'filename.txt')
conv.add(`Your content is ${contents}`)
})
exports.fulfillment = functions.https.onRequest(app)
I'm trying to use firebase-admin sdk to update my users passwords manually, the idea is to use a onCreate trigger to achieve this by creating a new document in firestore (with the right rules obviously).
According to firebase documentation i don't need to use anything else than this to autenticate from my firebase functions environment:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
In order to test the function i just manually added the document right from the firebase console ui for firestore, and as i can see the trigger is just doing it's work, the problem is when updatin the user password using the firebase-admin sdk.
I'm getting the next error message from the logs:
Error updating user: { Error: Credential implementation provided to
initializeApp() via the "credential" property failed to fetch a valid
Google OAuth2 access token with the following error: "Error fetching
access token
this is the whole firebase cloud function if you want to see how it's implemented:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
triggerNewDocument();
function triggerNewDocument() {
exports.updateUserData = functions.firestore
.document('updateUserPasswords/{userId}')
.onCreate((snap, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = snap.data();
console.log(newValue);
// access a particular field as you would any JS property
const uid = newValue.uid;
const newPassword = newValue.password;
return updateUserPassword(uid, newPassword);
// perform desired operations ...
});
}
function updateUserPassword(uid, newPassword) {
admin.auth().updateUser(uid, {
password: newPassword,
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
return userRecord.toJSON();
})
.catch(function(error) {
return error;
});
}
Is there anything may i be missing here?, thanks in advance for any hint or help you could provide.
The whole issue was somehow the service account autogenerated with the admin-sdk was inactive.
Anyway i had to disable and enable the service account at least 3 times to make it work, hopefully this can be helpful for anyone having the same issue.
A simple mistake
so I make http trigger function to get all events from my firestore like the image above.
firestore.js
const functions = require('firebase-functions')
const admin = require("firebase-admin")
// initialize database
admin.initializeApp()
const db = admin.firestore();
const settings = {timestampsInSnapshots: true};
db.settings(settings)
const eventRef = db.collection('event')
module.getAllEventsFromFirestore = functions.https.onRequest(async (request,response) => {
try {
const events = await eventRef.get()
response.status(200).send(`number of event is ${event.size}`)
} catch (error) {
response.status(500).send(error)
}
})
and my index.js
const {getAllEventsFromFirestore} = require("./firestore")
after deploying the function, I expect will get the URL to access that http trigger function on my terminal, but I can't find it.
The Firebase CLI will only give you a URL the first time you deploy the function. If you update the function after the first deploy, it won't print the URL. You can get the URL of the function by going to the Firebase console and view your functions there. The URL will be available on the Functions dashboard page.
If you would like to see a change in behavior of the Firebase CLI, file a feature request with Firebase support.
My ultimate target is to generate a pdf and send it via email through Firebase Cloud Function but I'm still testing things out. I am sending emails using Nodemailer. My next step is to include an image I have store in the same project on Firebase Storage.
How can I access the files I have in Storage to include as an attachment? My trigger for the function is onCreate() for a node in RTDB.
functions.database
.ref("/jobs/draft/{id}")
.onCreate((snapshot: any, context: any) => {
To "access the files you have in Storage" you have to use the Admin SDK, as follows:
//.....
const admin = require('firebase-admin');
//.....
functions.database
.ref("/jobs/draft/{id}")
.onCreate((snapshot: any, context: any) => {
const fileBucket = 'gs://bucket.appspot.com';
const filePath = 'path/to/file';
const bucket = admin.storage().bucket(fileBucket);
const file = bucket.file(filePath);
//.....
});
See also https://googleapis.dev/nodejs/storage/latest/Storage.html
I need to create a Cloud Function that will access the Firebase DB that is running in another project. If it was accessing the db in the current project, I could use code such as
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
however, what I want is for functions.config().firebase to return the information (and, most importantly, credentials) for the other project. Is there any easy way to do this?
functions.config().firebase is a reserved namespace and you won't be able to override it. However, you can do cross-project initialization yourself. Here's how I would do it:
First, download a service account for your other project into your functions directory. Name it <project_id>-sa.json. Next, set up some environment config (app.other_project_id is just an example name, not a requirement):
firebase functions:config:set app.other_project_id="<the_project_id>"
Now in your code, you can initialize the Admin SDK like so:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
if (!functions.config().app || !functions.config().app.other_project_id) {
throw new Error('Cannot start app without app.other_project_id config.');
}
const FB_PROJECT_ID = functions.config().app.other_project_id;
const SERVICE_ACCOUNT = require(`./${FB_PROJECT_ID}-sa.json`);
admin.initializeApp({
databaseURL: `https://${FB_PROJECT_ID}.firebaseio.com`,
credential: admin.credential.cert(SERVICE_ACCOUNT)
});
This will have initialized the Admin SDK for the other project.
instead of
if (!functions.config().app || !functions.config().app.project_id) {
You should use
if (!functions.config().app || !functions.config().app.fb_project_id) {
NOTE: the typo in project_id