I am trying to deploy a callable firebase cloud function to generate an email verification link and then send an email with sendgrid containing the link.
When I deploy I keep getting the error
"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".
I have succesfully deployed 4 other functions so my firebase & other env variables do not seem to be the problem.
Here is my code:
const functions = require("firebase-functions");
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const sgMail = require('#sendgrid/mail');
const API_KEY = functions.config().sendgrid.key;
const TEMPLATE_ID = functions.config().sendgrid.template;
sgMail.setApiKey(API_KEY);
exports.sendEmailVerifications = functions.https.onCall((email,context) => {
admin.auth().generateEmailVerificationLink(context.auth.token.email).then((link) => {
const msg = {
to: context.auth.token.email,
from: 'example#example.com',
template: TEMPLATE_ID,
dynamic_template_data: {
emailLink: link
}
};
sgMail.send(msg);
return {"success": true};
}).catch((error) => {
});
});
Related
I want to send the user a push notification with cloud functions on Firebase if someone commented to a topic on his iOS Device.
This code below works fine if I put the content of the notification manually.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.Push = functions.database.ref('/placeID/{pushId}/')
.onCreate((snapshot, context) => {
var topic = 'weather';
const payload = {
notification: {
title: 'User Max',
body: 'Hi how are you?',
badge: '1',
sound: 'default'
}
};
admin.messaging().sendToTopic(topic,payload);
})
In the next step I want to get the content of the comment the person has sent. Kinda get the value of the snapshot.
I tried it like this and get no error in the Logs Explorer from Google. But also no Push Notification anymore.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.Push = functions.database.ref('/placeID/{autogeneratedplaceID}/')
.onCreate((snapshot, context) => {
var username = snapshot.child("userName").val()
var usercomment = snapshot.child("userComment").val()
var topic = 'weather';
const payload = {
notification: {
title: username,
body: usercomment,
badge: '1',
sound: 'default'
}
};
admin.messaging().sendToTopic(topic,payload);
})
What is wrong here? I also found a video on Youtube with the exact solution. But this is for android and it did not really help me. Youtube
This is how my firebase realtime database structure looks like.
I have updated the question as found the root cause of the issue.
As I have hosted my React SSR app which uses firebase database in the client serving by one of the cloud function named app throwing an error of Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.. When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo?
ORIGINAL Question: Why firebase cloud function throwing an error of 'The default Firebase app does not exist.'?
So I am trying out firebase function for the first time. admin.messaging() throwing me the following error. Help me figure out why?
If I look at the console I get results till console.log('deviceToken', deviceToken);
so whats wrong in const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.updateUnreadCount = functions.database.ref('/chats/{chatId}/{messageId}')
.onCreate(async(snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const adminApp = admin.initializeApp(appOptions, 'app');
const { message, senderId, receiverUid } = snap.val();
console.log(message, senderId, receiverUid);
console.log('------------------------');
const deleteApp = () => adminApp.delete().catch(() => null);
try {
const db = adminApp.database();
const reciverUserRef = await db.ref(`users/${receiverUid}/contacts/${senderId}/`);
console.log('reciverUserRef', reciverUserRef);
const deviceTokenSnapshot = await reciverUserRef.child('deviceToken').once('value');
const deviceToken = await deviceTokenSnapshot.val();
console.log('deviceToken', deviceToken);
const payload = {
notification: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
}
};
const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);
console.log('Successfully sent message: ', JSON.stringify(messageDone));
return deleteApp().then(() => res);
} catch (err) {
console.log('error', err);
return deleteApp().then(() => Promise.reject(err));
}
});
Update1: According to this https://firebase.google.com/docs/cloud-messaging/send-message#send_to_a_topic, admin.messaging().sendToDevice(deviceToken, payload) APIs are only available in the Admin Node.js SDK?
So switched to
const payload = {
data: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
},
token: deviceToken
};
const messageDone = await admin.messaging().send(payload);
Which is not working either. Getting an error Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services. Any lead will be helpful.
EDIT: Finally got the function working.
My index.js is exporting to functions, follwoing
exports.app = functions.https.onRequest(app); //React SSR
exports.updateChat = functions.database.ref('/chats/{chatId}/{messageId}').onCreate(updateChat);
exports.app is a react ssr function, which I am using to host my site. This uses database too. and throwing error of multiple database instance.
When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo? Any suggestions, please?
You can initialise db outside export function.
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(appOptions, 'app')
//continue code
Update:
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(options);
async function initialize(options, apps = 'app') {
try {
const defaultApp = adminApp.name
if(defaultApp) {
const adminApp1 = admin.initializeApp(apps);
}else {
const adminApp1 = admin.initializeApp(options, apps);
}
}catch(err) {
console.error(err);
}
}
Modify this snippet as per your need and try it out
It abstracts initialize of app in another function. Just call this function at appropriate place in your code.
I'm trying to deploy a Firebase Cloud Function that sends a text message to its associated recipient for x number of text messages. The function is triggered in my iOS app when an update is made to the 'send' Realtime Database reference, indicating that the user has pressed the 'send' button.
My Firebase structure is
{
"user1uid": {
"send": false
"messagesToSend": {
"messageuid1": {
"messageText": "What's for dinner?",
"recipientNumber": "+18017378888",
}
"messageuid2:
"messageText": "Who won the Cowboys game?",
"recipientNumber": "+18017377787",
}
}
"user2uid": {
"send": false
"messagesToSend": {
"messageuid1": {
"messageText": "What's for dinner?",
"recipientNumber": "+18017378888",
}
"messageuid2:
"messageText": "Who won the Cowboys game?",
"recipientNumber": "+18017377787",
}
}
}
My code currently only sends one message, and I'm not sure how I can properly iterate through the messagesToSend node for each user and send all the messages in it.
I've been trying to follow the tutorial located here. I have looked at the following Stack Overflow responses but am unable to decipher or derive a solution from them:
Firebase cloud function promises
Am I using ForEach correctly?
My index.js code that sends one message is as follows:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
const twilio = require('twilio')
const accountSid = functions.config().twilio.sid;
const authToken = functions.config().twilio.token;
const client = new twilio(accountSid, authToken);
const twilioNumber = functions.config().twilio.number;
// Start cloud function
exports.sendSecrets = functions.database
.ref('/{uid}/send')
.onUpdate((change,context) => {
const uid = context.params.uid;
return admin.database().ref(uid+'/messagesToSend').once('value').then(snapshot => {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var messageData = childSnapshot.val();
**if (messageData.sanitized) return true;**
var message = messageData.messageText;
var phoneNumber = messageData.recipientNumber;
const textMessage = {
body: `From My App - ${message}`,
from: twilioNumber, // From Twilio number
to: phoneNumber // Text to this number
}
return client.messages.create(textMessage)
})
**return snapshot.ref.toString();**
});
});
Please note that the lines marked with ** at either end indicate that I know I need to return something based on error messages I received indicating that 'Each then() should return a value or throw'.
I make the assumption that you are using the twilio-node library that use promises: https://www.npmjs.com/package/twilio.
Since you want to send several messages in parallel, you have to use Promise.all(), as follows:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
const twilio = require('twilio')
const accountSid = functions.config().twilio.sid;
const authToken = functions.config().twilio.token;
const client = new twilio(accountSid, authToken);
const twilioNumber = functions.config().twilio.number;
// Start cloud function
exports.sendSecrets = functions.database
.ref('/{uid}/send')
.onUpdate((change,context) => {
const uid = context.params.uid;
return admin.database().ref(uid+'/messagesToSend').once('value')
.then(snapshot => {
const promises = [];
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var messageData = childSnapshot.val();
//**if (messageData.sanitized) return true;**
var message = messageData.messageText;
var phoneNumber = messageData.recipientNumber;
const textMessage = {
body: `From My App - ${message}`,
from: twilioNumber, // From Twilio number
to: phoneNumber // Text to this number
}
promises.push(client.messages.create(textMessage));
})
return Promise.all(promises);
})
// Edits made below to parentheses/brackets
.then(results => {
//Do whatever you want !!
// e.g. print the results which will be an array of messages
// (see https://www.twilio.com/docs/libraries/node#testing-your-installation)
})
});
You can also simply return Promise.all() as follows:
....
return Promise.all(promises);
})
});
I am receiving default push notification instead of my own payload data
in notification.
Here you can see the notification in this Picture below
I am getting no errors on firebase log, also receiving data which I want to send through push notification
Here you can see
and here is the code of index.js file of firebase cloud function
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotifications = functions.database.ref(`messages/{notificationId}`).onCreate((event) => {
const receiverId = event.val().recId;
const payload = {
notification: {
title: `New Message from ${event.val().sndrName}!`,
body: event.val().message,
status: "New message",
icon: 'icon-192x192.png'
}
}
console.info(payload);
let tokensList = [];
return admin.database().ref('fcmtokens').orderByValue().equalTo(receiverId).once('value').then((token) => {
console.info(token.val());
if(token.val()) {
tokensList = (Object.keys(token.val()));
console.info(tokensList);
return admin.messaging().sendToDevice(tokensList,payload);
}
})
})
I am very new to firebase cloud functions please tell if I am doing something wrong,TIA
I understand Cloud Functions recently updated to v1.0.
I am trying to write multiple functions from within Android Studio. I plan on having several cloud functions, and want to ensure my data structure is correct. Here is the current setup I have:
index.js
const functions = require('firebase-functions');
const trackVote = require('./trackVote')
const trendingCopy = require('./trendingCopy')
const admin = require('firebase-admin');
admin.initializeApp();
exports.trackVote = functions.firestore.document('Polls/{pollId}/responses/{userId}').onCreate(trackVoteModule.handler);
exports.trendingCopy = functions.firestore.document('Polls').onCreate(trendingCopyModule.handler);
trackVote:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.handler = (change, context => {
const data = change.after.data();
const answerSelected = data.answer;
const answerRef = admin.firestore().doc(`Polls/${event.params.pollId}/answers/${answerSelected}`);
const voteCountRef = admin.firestore.doc(`Polls/${event.params.pollId}/vote_count`);
return admin.firestore().runTransaction(t => {
return t.get(answerRef)
.then(doc => {
if (doc.data()) {
t.update(answerRef, { vote_count: doc.data().vote_count + 1 });
}
})
};
//TODO DO NOT ADD TO GIT
return admin.firestore().runTransaction(t => {
return t.get(voteCountRef)
.then(doc =>){
if (doc.data()){
t.update(voteCountRef, {vote_count:doc.data().vote_count+1});
}
}
});
});
});
Below is my console:
Error: functions predeploy error: Command terminated with non-zero exit code1
EDIT: I have seen this as a proposed solution, however it provides multiple options and unsure of best practice: https://github.com/firebase/functions-samples/issues/170