Twilio not sending SMS inside firebase cloud function - javascript

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

functions: Error: Request failed with status code 401, twitter api auth error

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);
});

Stubbing auth0 in firebase functions

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.

Get Firebase Database Value into a Cloud 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.

Firebase TypeError: Cannot read property 'val' of undefined

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');
});
});
});

Return Promise<String> from Cloud Function

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!");
});
});

Categories