I have a firebase cloud function:
exports.copyImage = functions.region('us-central1').https.onCall(async (data, context) => {
const { auth } = context || {}
const { uid } = auth || {}
if (!uid) throw 'Unauthenticated'
const srcBucketName = <bucket-name>'
const destinationBucketName = '<bucket-name'
const { imageFile, archiveId, sessionId } = data
const srcFileName = `message-attachments/${imageFile}`
const destinationFileName = `archived-attachments/${uid}/${imageFile}`
console.log(`source path: ${srcFileName}\ndestination path: ${destinationFileName}`)
const storage = new Storage()
storage
.bucket(srcBucketName)
.file(srcFileName)
.copy(storage.bucket(destinationBucketName).file(destinationFileName))
.then(() => {
console.log(`COPY SUCCESS: gs://${destinationBucketName}/${destinationFileName}`)
})
.catch(err => console.error('COPY ERROR: ' + err))
})
and I have a react-native project (v61.5) using react-native-firebase (v5) which calls this function:
firebase.functions().httpsCallable('copyFile')({
imageFile: fileName,
archiveId: uid,
sessionId
})
.then(() => {
// copied file
const ref = firebase.storage()
.ref('archived-attachments')
.child(uid)
.child(fileName)
ref.getDownloadURL()
.then(url => {
// do more
})
.catch(err => alert(err.message))
})
.catch(err => {
// copy error
})
the problem is im not getting any log output in the functions console when executing this function. the functions been successfully deployed as well. Any advice?
Updating my comment in this answer as it solves the issue.
The issue occurred because Jim has been triggering a different function copyFile
instead of copyImage.
mismatch between the function name exports.copyImage vs httpsCallable('copyFile').
Updating the function name solved the issue!
Related
In my expo react native app, I use firebase and expo to authenticate. But when I try to run signInWithCredential, I get this error for Apple auth. [TypeError: undefined is not an object (evaluating 'credential._getIdTokenResponse')]
Here is my code.
const signInWithApple = () => {
const nonce = Math.random().toString(36).substring(2, 10);
return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce)
.then((hashedNonce) =>
AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL
],
nonce: hashedNonce
})
)
.then((appleCredential) => {
const { identityToken } = appleCredential;
const provider = new OAuthProvider('apple.com')
const credential = provider.credential({
idToken: identityToken,
rawNonce: nonce
});
return signInWithCredential(credential); // Line causing error
})
.catch((error) => {
console.log(error)
});
};
I found the error.
Instead of signInWithCredential(credential), I put signInWithCredential(auth,credential).
I also added a service ID in the firebase console.
I want to use next.js routes api as a backend service and serve database result in json format. I see, there is no way to keep database up and running since all files located at pages/api/ it's ephemeral
Below it's my code
import { models } from "../models/index"
export default async function handler(req, res) {
const User = models.User
try {
const result = await User.findAll()
return res.json({ result })
} catch (err) {
console.error("Error occured ", err)
return res.json({ result: [] })
}
}
anyone who has encountered this problem?
The only possible way that I found is to use node js server and attach database model to request object. By doing this we pass database conection/models through routes api
my node.js server
const express = require("express")
const { sequelize } = require("./models/index")
const next = require("next")
const dev = process.env.NODE_ENV !== "production"
const app = next({ dev })
const handle = app.getRequestHandler()
const appExpress = express()
app.prepare().then(() => {
appExpress.use(express.json())
appExpress.get("*", (req, res) => {
req.db = sequelize
handle(req, res)
})
appExpress.listen(5000, () => console.log("> Ready on http://localhost:5000"))
}).catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
my routes api file changed to
export default async function handler(req, res) {
const User = req.db.models.User
try {
const result = await User.findAll()
return res.json({ result })
} catch (err) {
console.error("Error occured ", err)
return res.json({ result: [] })
}
}
with these changes the database is always up and running and used from all routes api files.
I tested and work like charm
I'm having issues in retrieving a token saved in realtime database using cloud function's admin.database(). There is only one token to read from the child.
Firebase Database structure
Here's my code in Index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database
.ref('/Logs/{LogsID}')
.onWrite( (change, context) => {
const notificationSnapshot = change.after.val();
const status = notificationSnapshot.Status;
const time = notificationSnapshot.Time;
const payload = {
notification: {
title : status,
body : time
}
}
console.info(notificationSnapshot);
const pushToken = admin.database().ref('/Tokens').once('child_added').then( (data) => {
const tokenSnapshot = data.val();
const finaltoken = tokenSnapshot.token;
console.info(finaltoken);
})
// Need help down here.
admin.messaging().sendToDevice(finaltoken, payload)
.then( () => {
console.log('Notification sent');
})
.catch( () =>{
console.log('Notification failed');
})
return null;
});
finalToken shows the correct token in log as expected. Log Showing the token
But I'm getting error while I'm passing the same token to admin.messaging(). Console is logging 'Notification sent' but not receiving a notification.
ReferenceError: finaltoken is not defined
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:43:36)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:827:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
It works when I directly pass the token like,
var finalToken = 'ephrj1........kndji'
so the admin.messaging() works, only passing the token is not working.
I'm new to Cloud Functions and javascript, so any help is much appreciated.
Final token is being retrieved in callback / async function.
That means that when you add it to .sendToDevice() the token is undefined because the async function has not retrieved the token from the database... yet.
const pushToken = admin.database().ref('/Tokens').once('child_added').then( (data) => {
const tokenSnapshot = data.val();
const finaltoken = tokenSnapshot.token;
console.info(finaltoken);
admin.messaging().sendToDevice(finaltoken, payload)
.then( () => {
console.log('Notification sent');
})
.catch( () =>{
console.log('Notification failed');
})
// I moved admin.messaging above this bracket
})
// It used to be here
return null;
Try putting the admin.messaging code within the code block of (data) => {}
By doing this we ensure that whenever we call sendToDevice() the token is defined.
I am trying to download an image from my firebase storage to render it in my Vue app, the upload from the application to the firebase storage is successful, however upon retrieval it gives me an error cannot read property '0' of undefined, i am using the firebase SDK in a Vue CLI 3 setup and vuex to manage my state. Here is the function setting in my actions in the main store.js file
let imageUrl
let key
firebase.database().ref('meetups').push(meetup)
.then((data) => {
key = data.key
return key
})
.then(key => {
const filename = payload.image.name
const ext = filename.slice(filename.lastIndexOf('.'))
return firebase.storage().ref('meetups/' + key + '.' + ext).put(payload.image)
})
.then(fileData => {
imageUrl = fileData.metadata.downloadURLs[0]
return firebase.database().ref('meetups').child(key).update({imageUrl: imageUrl})
})
.then(() => {
commit('createMeetup', {
...meetup,
imageUrl: imageUrl,
id: key
})
})
.catch((error) => {
console.log(error)
})
So it would seem you are doing Max's course on Vue. Excellent course but there are some slight changes to firebase since it was published. You can try this as I think the problem is you are not retrieving the image URL from storage so it isn't being inserted into your database so the app can't call it. It's trying to call "0". So change your createMeetup function to something like this:
createMeetup ({commit, getters}, payload) {
const meetup = {
title: payload.title,
location: payload.location,
description: payload.description,
preview: payload.preview,
date: payload.date,
creatorId: getters.user.id
}
let storageRef
let uploadTask
let key
firebase.database().ref('meetups').push(meetup)
.then((data) => {
key = data.key
return key
})
.then(key => {
const filename = payload.image.name
const ext = filename.slice(filename.lastIndexOf('.'))
storageRef = firebase.storage().ref();
uploadTask = storageRef.child('meetups/' + key + ext).put(payload.image)
return uploadTask
})
.then((uploadTask) => {
// Upload completed successfully, now we can get the download URL
uploadTask.ref.getDownloadURL().then((downloadURL) => {
firebase.database().ref('meetups').child(key).update({imageUrl: downloadURL})
.then(() => {
commit('createMeetup', {
...meetup,
imageUrl: downloadURL,
id: key
})
})
.catch((error) => {
})
})
})
},
And I think that should solve the problem.
I have following sample function from this tutorial: Asynchronous Programming (I Promise!) with Cloud Functions for Firebase - Firecasts
exports.emailEmployeeReport = functions.database
.ref('/employees/${eid}/reports/${rid}')
.onWrite(event => {
const eid = event.params.eid;
const report = event.data.val().report;
const root = event.data.ref.root;
const mgr_promise = root.child(`/employees/${eid}/manager`).once('value');
const then_promise = mgr_promise.then(snap => {
const mgr_id = snap.val();
const email_promise = root.child(`/employees/${mgr_id}/email`).once('value');
return email_promise;
}).catch(reason => {
// Handle the error
console.log(reason);
});;
const then_promise2 = then_promise.then(snap => {
const email = snap.val();
const emailReportPromise = sendReportEmail(email, report);
return emailReportPromise;
}).catch(reason => {
// Handle the error
console.log(reason);
});
return then_promise2;
});
var sendReportEmail = function (email, report) {
const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
setTimeout(function () {
try {
var someValue = "sendReportEmail";
console.log(someValue);
// fulfilled
resolve(someValue);
}
catch (ex) {
// rejected
reject(ex);
}
}, 2000);
});
return myFirstPromise;
}
once I run firebase deploy command, eventually I am getting following error:
functions[emailEmployeeReport]: Deploy Error: Failed to configure
trigger
providers/google.firebase.database/eventTypes/ref.write#firebaseio.com
(emailEmployeeReport)
I also have a simple hello-world method and a similar trigger method, and they deploy fine.
Am I missing something here?
The syntax for wildcards in the database reference does not have "$".
Try the following:
exports.emailEmployeeReport = functions.database
.ref('/employees/{eid}/reports/{rid}')