How to send a message to Telegram from Zapier - telegram

Zapier does not offer native integration for Telegram. How can one send a message to Telegram chat from Zapier?

Zapier offers Code actions that can execute JavaScript or Python code. You can use JavaScript fetch and Telegram HTTP API to post messages to Telegram chats through your bot.
// TG bot API documentation https://core.telegram.org/bots/api
// Set up the bot with BotFather and the API token https://telegram.me/BotFather
const TG_API_TOKEN = "xxx";
// Add the bot to a chat
// In chat type: /start to make the bot to recognise the chat
// Get chat it by calling TG getUpdates API in terminal and picking
// the chat id from the output by hand
//
// curl https://api.telegram.org/bot$TG_API_TOKEN/getUpdates | jq
//
const CHAT_ID = "xxx";
async function postData(url, data) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
// Create the message using uptick formatting from whatever inputData field
// you choose in Zapier
const message = `Hello my old friend ${inputData.id}`;
console.log("Sending out", message);
// Create sendMessage payload
const payload = {chat_id: CHAT_ID, text: message, disable_notification: false};
// Which endpoint we are calling
const endpoint = `https://api.telegram.org/bot${TG_API_TOKEN}/sendMessage`;
// Call Telegram HTTP API
const resp = await postData(endpoint, payload);
console.log("We got", resp);
// Zapier scripts needed output - pass Telegram API response
output = resp;

There's no need to do this using Python or Javascript. You can use the POST function in Zapier's Webhooks to send a message directly via the Bot API:
URL https://api.telegram.org/bot{BOT_API_TOKEN}/sendMessage
Payload Type json
Data
text your message
chat_id -{CHANNEL_OR_GROUP_ID}
Note the use of the - symbol in front of the chat_id; you must have this in order for it to work.

Related

Send SMS using POST request from Firebase Cloud Function

I have an SMS API from textlocal which I want to use to send SMS using Cloud function when a new Document is created in Firestore Collection.
Collection name: Booking SMS. It will have a document created with fields 'number', 'name' & 'service'. Now SMY API need few parameters to send SMS.
API URL: 'https://api.textlocal.in/send/'
Apikey
Sender
Message. Message will be constructed as 'Hi, 'name' your booking of 'service' is confirmed.
Name, service & number will be from Firestone document and apikey and sender will be coded in cloudfunction code.
Now I want to create cloudfunction trigger which will send sms when document is created. Below is incomplete code I tried please help me to complete it.
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const axios = require("axios");
admin.initializeApp()
exports.sendSMS = functions.firestore
.document('BookingSMS/{BookingSMSId}')
.onCreate((snap, context) => {
const smsOptions = axios.create( {
baseURL: "https://api.textlocal.in/",
params: {
apiKey: "xQ1Fvg7uv14NaAEQHl2D", //Text local api key
sender: "ASDASD",
test: "true",
number: snap.data().phone,
service: snap.data().service,
message: `Hi, Your Booking for ${snap.data().service} is
Confirmed. Thank You.`
}
});
smsOptions.post("/send");
});
I also want to add +91 before number. and construct message using name and service.
As per the documentation, there is no direct support for node.js. You should be able to use their get request though. (Hope you're familiar with async/await)
Try:
async function bookSMS(user) {
// 5. Send booking SMS to users
const smsoption = {
apikey: 'asasasasasasasasas',
sender: 'DDDDDD'
to: '${user.phone}',
message: 'Welcome!',
}
// 6. Process the sending of this SMS
await fetch(`https://api.textlocal.in/send/?apikey=${apiKey}&numbers=${user.phone}&message=Welcome!&sender=DDDDDD`)
}
You must enable billing to access external APIs in firebase

Sync data between Google Firestore and Google Sheets using Cloud Functions/Admin SDK

While using Cloud Firestore as data backend, I need to share some data collections with non-tech site managers (editors, sales teams, etc.). Also, I wish to give these people access to edit the data stored in Cloud Firestore.
Google Sheets is a very familiar tool with site managers which can save me time in developing a CRUD admin panel like the interface from scratch for data updating and viewing.
This Stack Overflow answer shows how to send data using cloud function and levels deep, and this Github library can get data from Firestore using Google Apps Script (I wish to do it using Cloud Functions or Firebase Admin SDK), but I am still trying to figure out how to make an end-to-end Sheets based interface.
Please guide if there are any better alternatives to achieve the same objective. I'm facing some difficulties switching from SQL databases and Django auto-created admin interfaces to the Firebase-Firestore NoSQL world.
I understand that you want to be able to call a Cloud Function from a Google Sheet in order to build an "end-to-end Sheets based interface" for Firestore.
You can use the UrlFetchApp Class to make a request to fetch the URL of an HTTP Cloud Function.
You Apps Script code would be like:
function callSimpleHTTPCloudFunction() {
const url = "https://xxxxxxxx.cloudfunctions.net/simpleHttp";
response = UrlFetchApp.fetch(url, {
method: 'get'
})
respObj = JSON.parse(response.getContentText());
Logger.log(respObj);
}
While your Cloud Function would be like:
exports.simpleHttp = functions.https.onRequest((req, res) => {
res.send({ msg: 'simpleHttp' });
});
This is a very simple example of Cloud Function, but you can adapt this Cloud Function to read and write data from/to Firestore. Have a look at this official video for a starting point: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
Now, if you want to authenticate your users in such a way you can control who can access your data through the Cloud Function, it is going to be a bit more complex.
There is an official Cloud Function Sample which shows "how to restrict an HTTPS Function to only the Firebase users of your app": https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint
As explained in the code comments: "The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this: Authorization: Bearer <Firebase ID Token>. When decoded successfully, the ID Token content will be added as req.user."
So you need, in your Apps Script code, to generate a Firebase ID Token for the Firebase user. For that we will use the Firebase Auth REST API. In this example we will use the email of the user authenticated in the Google Sheet (Session.getActiveUser().getEmail()) as the Firebase User Name.
As explained in the doc, to call the Firebase Auth REST API, you need to obtain a Web API Key for your Firebase project, through the project settings page in your Firebase admin console.
The following Apps Script function will do the job:
function getToken() { {
const userName = Session.getActiveUser().getEmail();
const pwd = 'xyz' //For example get the password via a prompt.
//This is NOT the password of the account authenticated with Google Sheet, but the password of the Firebase user. In this example, the emails are the same but they are different accounts.
const verifyPasswordUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=[API_KEY]" //Replace with your Web API Key
const payload = JSON.stringify({"email":userName,"password": pwd,"returnSecureToken": true});
const verifyPasswordResponse = UrlFetchApp.fetch(verifyPasswordUrl, {
method: 'post',
contentType: 'application/json',
muteHttpExceptions: true,
payload : payload
});
const token = JSON.parse(verifyPasswordResponse.getContentText()).idToken;
return token;
}
Then, still in Apps Script, you use the token in the call to the Cloud Function, as follows:
function callSecuredHTTPCloudFunction() {
const authHeader = {"Authorization": "Bearer " + getToken()};
const url = "https://us-central1-<yourproject>.cloudfunctions.net/securedHttp/";
const response = UrlFetchApp.fetch(url, {
method: 'get',
headers: authHeader,
muteHttpExceptions: true,
});
Logger.log(response);
//Here do what you want with the response from the Cloud Function, e.g. populate the Sheet
}
The Cloud Function code would be as follows, adapted from the official example.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({
origin: true
});
const express = require('express');
const cookieParser = require('cookie-parser')();
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith('Bearer ')
) {
console.error(
'No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>'
);
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (
req.headers.authorization &&
req.headers.authorization.startsWith('Bearer ')
) {
console.log('Found "Authorization" header');
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
console.log(idToken);
} else {
// No cookie
res.status(403).send('Unauthorized');
return;
}
admin
.auth()
.verifyIdToken(idToken)
.then(decodedIdToken => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
return next();
})
.catch(error => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
};
app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/', (req, res) => {
res.send(`Your email is ${req.user.email}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.securedHttp = functions.https.onRequest(app);
You can very well write a similar function with a POST and a payload in order to send data from the Google Sheet to the Cloud Function and then write to Firestore.
Finally, note that you could implement the same approach for calling, from the Google Sheet, the Firestore REST API instead of calling Cloud Functions.

Unable to send FCM Message using Cloud Functions for Firebase

I am trying to send a basic use-case of sending FCM message using Cloud Functions for Firebase. The function is timing out and the message never got send. Here is the function.
exports.sendNotification = functions.https.onRequest((req, res) => {
const keyword = req.query.keyword;
const username = req.query.username;
var payload = {
data: {
SearchKeyword: keyword,
user: username
}
};
const token = "real_fcm_token";
return admin.messaging().sendToDevice(token, payload);
});
How can I update the above code block to be able to send a data message to a device?
In addition to returning the Promise from sendToDevice(), you must also send HTTP status. For example:
res.status(200).send('Success');
const token = "real_fcm_token";
return admin.messaging().sendToDevice(token, payload);

How to send email verification after user creation with Firebase Cloud functions?

I'm trying to send the verification email after the user is created. Since there's no way on Firebase itself, I'm trying it with cloud functions.
I cannot really find a lot of documentation about it. What I tried to do so far is:
exports.sendEmailVerification = functions.auth.user().onCreate(event => {
return user.sendEmailVerification()
});
But I get the error that user is not defined.
How can I create this function?
Thanks!
There are two possibilities to send an "email verification" email to a user:
The signed-in user requests that a verification email be sent. For that, you call, from the front-end, the sendEmailVerification() method from the appropriate Client SDK.
Through one of the Admin SDKs, you generate a link for email verification via the corresponding method (e.g. auth.generateEmailVerificationLink() for the Node.js Admin SDK) and you send this link via an email sent through your own mechanism. All of that is done in the back-end, and can be done in a Cloud Function.
Note that the second option with the Admin SDKs is not exactly similar to the first option with the Client SDKs: in the second option you need to send the email through your own mechanism, while in the first case, the email is automatically sent by the Firebase platform
If you'd like that ability to be added to the Admin SDK, I'd recommend you file a feature request.
This is how I implemented it successfully using Firebase cloud functions along with a small express backend server
Firebase Cloud function (background) triggered with every new user created
This function sends a "user" object to your api endpoint
const functions = require('firebase-functions');
const fetch = require('node-fetch');
// Send email verification through express server
exports.sendVerificationEmail = functions.auth.user().onCreate((user) => {
// Example of API ENPOINT URL 'https://mybackendapi.com/api/verifyemail/'
return fetch( < API ENDPOINT URL > , {
method: 'POST',
body: JSON.stringify({
user: user
}),
headers: {
"Content-Type": "application/json"
}
}).then(res => console.log(res))
.catch(err => console.log(err));
});
Server Middleware code
verifyEmail here is used as middleware
// File name 'middleware.js'
import firebase from 'firebase';
import admin from 'firebase-admin';
// Get Service account file from firebase console
// Store it locally - make sure not to commit it to GIT
const serviceAccount = require('<PATH TO serviceAccount.json FILE>');
// Get if from Firebase console and either use environment variables or copy and paste them directly
// review security issues for the second approach
const config = {
apiKey: process.env.APIKEY,
authDomain: process.env.AUTHDOMAIN,
projectId: process.env.PROJECT_ID,
};
// Initialize Firebase Admin
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
// Initialize firebase Client
firebase.initializeApp(config);
export const verifyEmail = async(req, res, next) => {
const sentUser = req.body.user;
try {
const customToken = await admin.auth().createCustomToken(sentUser.uid);
await firebase.auth().signInWithCustomToken(customToken);
const mycurrentUser = firebase.auth().currentUser;
await mycurrentUser.sendEmailVerification();
res.locals.data = mycurrentUser;
next();
} catch (err) {
next(err);
}
};
Server code
// Filename 'app.js'
import express from 'express';
import bodyParser from 'body-parser';
// If you don't use cors, the api will reject request if u call it from Cloud functions
import cors from 'cors';
import {
verifyEmail
} from './middleware'
app.use(cors());
app.use(bodyParser.urlencoded({
extended: true,
}));
app.use(bodyParser.json());
const app = express();
// If you use the above example for endpoint then here will be
// '/api/verifyemail/'
app.post('<PATH TO ENDPOINT>', verifyEmail, (req, res, next) => {
res.json({
status: 'success',
data: res.locals.data
});
next()
})
This endpoint will return back the full user object and will send the verification email to user.
I hope this helps.
First view the documentation by Firebase here.
As the registration phase completes and result in success, trigger the following function asynchronously :
private void sendVerification() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
system.print.out("Verification Email sent Champion")
}
}
});
}
The user will now be provided with a verification Email. Upon clicking the hyper linked the user will be verified by your project server with Firebase.
How do you determine whether or not a user did verify their Email?
private void checkEmail() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user.isEmailVerified()) {
// email verified ...
} else {
// error : email not verified ...
}
}
Sadly, you may not customize the content/body of your verification Email ( I have been heavily corresponding with Firebase to provide alternative less hideous looking templates ). You may change the title or the message sender ID, but that's all there is to it.
Not unless you relink your application with your own supported Web. Here.
Since the release of the Version 6.2.0 of the Node.js Admin SDK on November 19, 2018 it is possible to generate, in a Cloud Function, a link for email verification via the auth.generateEmailVerificationLink() method.
You will find more details and some code samples in the documentation.
You can then send an email containing this link via Mailgun, Sendgrid or any other email microservice. You'll find here a Cloud Function sample that shows how to send an email from a Cloud Function.
If you want to let Admin SDK do it, as of now there is no option other than generating the email verification link and sending with your own email delivery system.
However
You can write a REST request on cloud functions and initiate the email verification mail this way.
export async function verifyEmail(apiKey : string, accessToken : string) {
// Create date for POST request
const options = {
method: 'POST',
url: 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode',
params: {
key: apiKey
},
data: {
requestType : "VERIFY_EMAIL",
idToken : accessToken
}
};
return await processRequest(options); //This is just to fire the request
}
As soon as you signup, pass the access token to this method and it should send a mail to the signup user.
apiKey : Is the "Web API key" listed in General tab of your project settings in firebase console
access token : Access token of the current user (I use signup rest api internally so there is an option to request token in response)

How to use the Firebase refreshToken to reauthenticate?

I use the JS library call firebase.auth().signInWithEmailAndPassword(email, password) and get back a User object. The User object contains a refreshToken.
I use curl 'https://docs-examples.firebaseio.com/rest/saving-data/auth-example.json?auth=TOKEN' to make calls to Firebase.
The token will eventually expire. In order to make it look like the application (iOS and macOS) has persistent login, I want to refresh the token, how do I do that with using either the REST or JS library? I can't find any calls in the documentation that allow me to use the refreshToken to get a new token.
When you make call from a browser .getIdToken(true) will automatically refresh your token. Make call like this:
firebase.auth().currentUser.getIdToken(/ forceRefresh / true)
.then(function(idToken) {
}).catch(function(error) {
});
More info here https://firebase.google.com/docs/reference/js/firebase.User#getIdToken
** UPDATE ** this is also now documented in Firebase REST docs under Exchange a refresh token for an ID token section:
https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token
Currently the only way I found to do this is here:
https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token
You must make an HTTP request:
POST https://securetoken.googleapis.com/v1/token?key=YOUR_KEY
Where YOUR_KEY can be found in the Google developers console > API Manager > Credentials. It's under the API Keys section.
Make sure request body is structured in the following format:
grant_type=refresh_token&refresh_token=REFRESH_TOKEN
Where REFRESH_TOKEN is the refresh token from Firebase user object when they signed in.
You must set the header Content-Type: application/json or you will get errors (e.g. "MISSING_GRANT_TYPE").
The POST call will return a new idToken (used to be called access_token)
I guess most people here are looking for a way to persist their authentication not in a browser but e.g. on a node backend. Turns out there actually is a way to do this:
Trade the refresh-token for an access-token (using google's public api)
Trade the access-token for a custom-token (using a firebase-function, see below)
Login with custom-token
Here's the essence of the code:
const requestP = require('request-promise');
const fsP = require('fs').promises;
const refreshToken = await fsP.readFile('./refresh_token.txt');
const res = await requestP.post({
headers: {'content-type': 'application/x-www-form-urlencoded'},
url: 'https://securetoken.googleapis.com/v1/token?key=' + firebaseConf.apiKey,
body: 'grant_type=refresh_token&refresh_token=' + refreshToken,
json: true
});
const customToken = await requestP.post({
headers: {'content-type': 'text/plain'},
url: 'https://<yourFirebaseApp>.cloudfunctions.net/createCustomToken',
body: {token: res.access_token},
json: true
});
await firebaseApp.auth().signInWithCustomToken(customToken);
And the firebase function:
export const createCustomToken = functions.https.onRequest(async (request, response) => {
response.set('Access-Control-Allow-Origin', '*');
try {
const token = JSON.parse(request.body).token;
const decodedToken = await admin.auth().verifyIdToken(token);
const customToken = await admin.auth().createCustomToken(decodedToken.uid);
response.send(customToken);
} catch(e) {
console.log(e);
response.sendStatus(500);
}
});
// Create a callback which logs the current auth state
function authDataCallback(authData) {
if (authData) {
console.log("User " + authData['uid'] + " is logged with token" + authData['ie']);
} else {
console.log("User is logged out");
}
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(authDataCallback);
Event onAuth will be called on page refresh, if user was logged out authData will be null, else not. You can find token in authdata['ie']. In the screenshot bellow I have printed the token after auth and authdata object, how you can see authData['ie'] and token are similar.

Resources