i am trying to send sms using twilio api for node.js through a firebase cloud function but the sms is not sent. however if the same code i run as an independent java script code, then it works fine.can someone
please help why this is not happening inside the firebase cloud function. the code is attached below:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotfication = functions.database.ref('/kakuh/{pushId}/firstName')
.onCreate((snapshot, context) => {
const original = snapshot.val();
const accountSid = 'ACb6b4820df073e63312382f95b0314d07';
const authTcoken = 'c60923ca097368662b39dfab470f2fd1';
const client = require('twilio')(accountSid, authToken);
client.messages
.create({
from: '+16304263296',
body: original,
to: '+918169813384'
});
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
return snapshot.ref.parent.child('firstName').set(uppercase);
});
You'll need to wait for Twilio to respond, then return to Firebase.
Try this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotfication = functions.database.ref('/kakuh/{pushId}/firstName')
.onCreate((snapshot, context) => {
const original = snapshot.val();
const accountSid = 'ACb6b4820df073e63312382f95b0314d07';
const authToken = 'c60923ca097368662b39dfab470f2fd1';
const client = require('twilio')(accountSid, authToken);
client.messages
.create({
from: '+16304263296',
body: original,
to: '+918169813384'
})
.then((message) => {
console.log(message.sid);
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
return snapshot.ref.parent.child('firstName').set(uppercase);
})
.catch((err) => {
throw (err);
});
});
Related
I am writing code to automatically tweet, and it used to work just fine. After implementing some code changes and a cron job it began giving me this error. My code uses the twitter api v2 and auth2.0. as well as firebase/firestore and node.js to create and host servers to run the functions.
! functions: Error: Request failed with status code 401
at createError (C:\Users\EASYHOME\OneDrive\Desktop\AI twitter bot\functions\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Users\EASYHOME\OneDrive\Desktop\AI twitter bot\functions\node_modules\axios\lib\core\settle.js:17:12)
at IncomingMessage.handleStreamEnd (C:\Users\EASYHOME\OneDrive\Desktop\AI twitter bot\functions\node_modules\axios\lib\adapters\http.js:322:11)
at IncomingMessage.emit (events.js:228:7)
at endReadableNT (_stream_readable.js:1185:12)
at processTicksAndRejections (internal/process/task_queues.js:81:21)
I am pretty sure it has to do with the authentication, I tried regenerating the access tokens and every other token, but to no avail. I did notice that on the twitter developer platform it says my access token and secret was "Created with Read Only permissions"
Here is the code in question
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const dbRef = admin.firestore().doc("tokens/demo");
const TwitterApi = require("twitter-api-v2").default;
const twitterClient = new TwitterApi({
clientId: "client id goes here",
clientSecret: "client secret goes here",
});
const {Configuration, OpenAIApi} = require("openai");
const configuration = new Configuration({
organization: "org goes here",
apiKey: "api key goes here",
});
const openai = new OpenAIApi(configuration);
const callbackURL = "http://127.0.0.1:5001/twbot-ad868/us-central1/callback";
// STEP 1 - Auth URL
exports.auth = functions.https.onRequest(async (request, response) => {
const {url, codeVerifier, state} = twitterClient.generateOAuth2AuthLink(
callbackURL,
{scope: ["tweet.read", "tweet.write", "users.read", "offline.access"]},
);
// store verifier
await dbRef.set({codeVerifier, state});
response.redirect(url);
});
exports.callback = functions.https.onRequest(async (request, response) => {
const {state, code} = request.query;
const dbSnapshot = await dbRef.get();
const {codeVerifier, state: storedState} = dbSnapshot.data();
if (state != storedState) {
return response.status(400).send("Stored tokens do not match!");
}
const {
client: LoggedClient,
accessToken,
refreshToken,
} = await twitterClient.loginWithOAuth2({
code,
codeVerifier,
redirectUri: callbackURL,
});
await dbRef.set({accessToken, refreshToken});
const {data} = await LoggedClient.v2.me();
response.send(data);
});
exports.tweet = functions.https.onRequest(async (request, respone) => {
const {refreshToken} = (await dbRef.get()).data();
const {
client: refreshedClient,
accessToken,
refreshToken: newRefreshToken,
} = await twitterClient.refreshOAuth2Token(refreshToken);
await dbRef.set({accessToken, refreshToken: newRefreshToken});
const i = Math.floor(Math.random() * prs.length);
const nextTweet = await openai.createCompletion("text-davinci-001", {
prompt: prs[i],
temperature: 1,
max_tokens: 64,
});
const {data} = await refreshedClient.v2.tweet(
nextTweet.data.choices[0].text,
);
console.log(data);
});
exports.tweetHourly = functions.pubsub
.schedule("0 * * * *")
.onRun(async (context) => {
const {refreshToken} = (await dbRef.get()).data();
const {
client: refreshedClient,
accessToken,
refreshToken: newRefreshToken,
} = await twitterClient.refreshOAuth2Token(refreshToken);
await dbRef.set({accessToken, refreshToken: newRefreshToken});
const i = Math.floor(Math.random() * prs.length);
const nextTweet = await openai.createCompletion("text-davinci-001", {
prompt: prs[i],
temperature: 1,
max_tokens: 64,
});
const {data} = await refreshedClient.v2.tweet(
nextTweet.data.choices[0].text,
);
console.log(data);
});
I have the following Firebase Function that makes use of Auth0 to get a user profile.
'use strict';
const {
dialogflow,
Image,
} = require('actions-on-google')
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
// database collection and key names
const DB_BANK_COLLECTION_KEY = 'bank'
// the action name from all Dialogflow intents
const INTENT_WELCOME_USER = 'Default Welcome Intent';
// Initialize the Auth0 client
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: functions.config().familybank.auth0.domain,
clientID: functions.config().familybank.auth0.clientid
});
const app = dialogflow();
app.intent(INTENT_WELCOME_USER, async (conv) => {
console.log('Request: ' + JSON.stringify(conv.request));
const userInfo = await auth0.getProfile(conv.user.access.token)
.catch( function(err) {
console.error('Error getting userProfile from Auth0: ' + err);
conv.close("Something went wrong. Please try again in a few minutes. " + err)
});
console.log('userInfo: ' + JSON.stringify(userInfo));
// check for existing bank, if not present, create it
var bankRef = db.collection(DB_BANK_COLLECTION_KEY).doc(userInfo.email);
const bankSnapshot = await bankRef.get()
})
exports.accessAccount = functions.https.onRequest(app);
I tried to mock auth0 in my tests using the following code (and several permutations), but the actual function always gets called instead of the mock.
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');
// Require firebase-admin so we can stub out some of its methods.
const admin = require('firebase-admin');
const test = require('firebase-functions-test')();
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: "mock",
clientID: "mock"
});
describe('Cloud Functions', () => {
let myFunctions, adminInitStub;
before(() => {
test.mockConfig({"familybank": {"auth0": {"domain": "mockdomain", "clientid": "mockid"}}});
adminInitStub = sinon.stub(admin, 'initializeApp');
sinon.stub(admin, 'firestore')
.get(function() {
return function() {
return "data";
}
});
sinon.stub(auth0, 'getProfile').callsFake( function fakeGetProfile(accessToken) {
return Promise.resolve({"email": "daniel.watrous#gmail.com", "accessToken": accessToken});
});
myFunctions = require('../index');
});
after(() => {
adminInitStub.restore();
test.cleanup();
});
describe('accessAccount', () => {
it('should return a 200', (done) => {
const req = {REQUESTDATA};
const res = {
redirect: (code, url) => {
assert.equal(code, 200);
done();
}
};
myFunctions.accessAccount(req, res);
});
});
})
Is there some way to mock auth0 for my offline tests?
I discovered that rather than initialize the Auth0 AuthenticationClient, I could first require the UsersManager, where the getProfile (which wraps getInfo) is defined.
var UsersManager = require('auth0/src/auth/UsersManager');
In my before() method, I can then create a stub for getInfo, like this
sinon.stub(UsersManager.prototype, 'getInfo').callsFake( function fakeGetProfile() {
return Promise.resolve({"email": "some.user#company.com"});
});
All the calls to auth0.getProfile then return a Promise that resolves to the document shown in my stub fake function.
I'm currently using Firebase Functions to send automatic push notifications when the database is uploaded. It's working perfectly, I'm just wondering how I can get a specific value from my database, for example PostTitle and display it on, for example title.
In Firebase my database is /post/(postId)/PostTitle
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// database tree
exports.sendPushNotification = functions.database.ref('/posts/{id}').onWrite(event =>{
const payload = {
notification: {
title: 'This is the title.',
body: 'There is a new post available.',
badge: '0',
sound: 'default',
}
};
return admin.database().ref('fcmToken').once('value').then(allToken => {
if (allToken.val()){
const token = Object.keys(allToken.val());
console.log(`token? ${token}`);
return admin.messaging().sendToDevice(token, payload).then(response =>{
return null;
});
}
return null;
});
});
If I understand correctly that you want to get the PostTitle from the node that triggers the Cloud Function, the following should do the trick:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// database tree
exports.sendPushNotification = functions.database.ref('/posts/{id}').onWrite(event =>{
const afterData = event.data.val();
const postTitle = afterData.PostTitle; //You get the value of PostTitle
const payload = {
notification: {
title: postTitle, //You then use this value in your payload
body: 'There is a new post available.',
badge: '0',
sound: 'default',
}
};
return admin.database().ref('fcmToken').once('value').then(allToken => {
if (allToken.val()){
const token = Object.keys(allToken.val());
console.log(`token? ${token}`);
return admin.messaging().sendToDevice(token, payload)
} else {
throw new Error('error message to adapt');
}
})
.catch(err => {
console.error('ERROR:', err);
return false;
});
});
Note the following points:
You are using the old syntax for Cloud Functions, i.e. the one of versions <= v0.9.1. You should migrate to the new version and syntax, as explained here: https://firebase.google.com/docs/functions/beta-v1-diff#realtime-database
I have re-organised your promise chaining and also added a catch() at the end of the chain.
I'd use ...
var postTitle = event.data.child("PostTitle").val;
while possibly checking, it the title even has a value
... before sending out any notifications.
I have tried Firebase cloud function for sending a notification.My project structure
and this is the index.js,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
console.log('Push notification event triggered');
const message = event.data.val();
const user = event.data.val();
console.log(message);
console.log(user);
const topic = "myTopic";
const payload = {
"data": {
"title": "New Message from " + user,
"detail":message,
}
};
return admin.messaging().sendToTopic(topic, payload);
});
The above code is misconfigured, when I deploy in Node.js, LOG in Function shows:
"TypeError: Cannot read property 'val' of undefined".
What Actually I am trying to do :
I am trying to extract info from snapshot load into that index.js so that when a new child gets added to Real-time database, it should trigger a notification payload with a title and body.
In Android, I use a child listener, for listening when a new record is added
FirebaseDatabase.getInstance().getReference().child("messages")
OnChildAdded(.....){
if (dataSnapshot != null) {
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
// do whatever
}
}
But in index.js, I could not able to parse that.
A bit guidance how to fixate index.js according to my database structure would be immensely appreciated.
PS- I have never done coding in JS
If you want more context, I'd be happy to provide it.
Change this:
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
const message = event.data.val();
const user = event.data.val();
});
to this:
exports.pushNotification = functions.database.ref('/messages').onWrite(( change,context) => {
const message = change.after.val();
});
Please check this:
https://firebase.google.com/docs/functions/beta-v1-diff#realtime-database
The cloud functions were changed and now onWrite has two parameters change and context
The change has two properties before and after and each of these is a DataSnapshot with the methods listed here:
https://firebase.google.com/docs/reference/admin/node/admin.database.DataSnapshot
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/NOTIFICATIONS/{UserId}/{{notification_id}').onWrite((change, context) =>
{
const UserId = context.params.UserId;
const notification = context.params.notification;
console.log('The user Id is : ', UserId);
if(!change.after.exists())
{
return console.log('A Notification has been deleted from the database : ', notification_id);
}
if (!change.after.exists())
{
return console.log('A notification has been deleted from the database:', notification);
return null;
}
const deviceToken = admin.database().ref(`/USER/${UserId}/device_token`).once('value');
return deviceToken.then(result =>
{
const token_id = result.val();
const payload = {
notification : {
title : "Friend Request",
body : "You've received a new Friend Request",
icon : "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
console.log('This was the notification Feature');
});
});
});
I want to return the myref as the promise as the reponse from this function to the calling end.Please help i am new at this.
const functions = require("firebase-functions");
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.createService = functions.https.onRequest((req, res) => {
// Grab the text parameter.
const serviceName = req.query.serviceName;
const ttlHour = req.query.ttlHour;
const promise = [];
const myref = admin.database().ref("/root/events");
promise.push(myref);
// Push the new message into the Realtime Database using the Firebase
Admin SDK.
myref.set({ name: serviceName, ttl: ttlHour, startTs: 0 }).then(snapshot => {
res.send("Write succeeded!");
});
});