How to read RTDB randomly generated node and it's value? - node.js

Below is my typescript code and its already connected to telegram and managed to sent a message.
Currently I'm trying to tinker with it even more by reading the randomly generated node Arduino and MQ7 created and sending it as a message on telegram.
import * as functions from "firebase-functions";
import * as express from "express";
import * as cors from "cors";
import * as admin from "firebase-admin";
admin.initializeApp();
const bot = express();
bot.use(cors( {origin: true}));
bot.post("/", async function(req, res) {
const telegramText = req.body;
req.body.message &&
req.body.message.chat &&
req.body.message.chat.id &&
req.body.message.from &&
req.body.message.from.first_name;
if (telegramText) {
const chat_id = req.body.message.chat.id;
const first_name = req.body.message.from.first_name;
const receivedMessage = req.body.message.text;
// Define your RTDB Reference
const rtdbReference = admin.database().ref("Sensor MQ7");
const mq7ref = rtdbReference.child("-NHi7dBPMlVi6hXrnI03");
const valref = mq7ref.child("MQ7");
// Fetch the data
const snap = await valref.get();
const snapValue = snap.val();
// Inject snapvalue in the response
return res.status(200).send({
method: "sendMessage",
chat_id,
text: `${first_name}\n${receivedMessage}\n${snapValue}`,
});
}
return res.status(200).send({status: "An error occured"});
});
export const router = functions.https.onRequest(bot);
The typescript code works I figured out how to read entries from the database and write it into telegram as well as learning a little bit about the reference and functions. Right now I'm trying to figure out how to output the value whenever a new node is created. The new node are randomly generated # Arduino and mq7 gas sensor. Basically whenever the sensor picks up dangerous amount of carbon monoxide, it'll send the input to firebase, and a new node is created with a new value. I've classified the Parent = Sensor MQ7, Middle child = "randomly generated node", Last child = MQ7. Any help, advice, or recommendation is greatly appreciated. Please explain like I'm 5 because I just started doing all of it this week and I'm really really new to cloud functions. Thank you!
RTDB

The typescript code (for sending to Telegram) works and right now I'm
trying to figure out how to read entries from the database and write
it into telegram
In a Cloud Function you need to use the Node.js Admin SDK to interact with the Firebase services.
Here is how to read the data at a specific Reference in the Realtime Database:
import * as functions from "firebase-functions";
import * as express from "express";
import * as cors from "cors";
import * as admin from 'firebase-admin'; <== NEW
admin.initializeApp(); <== NEW
const bot = express();
bot.use(cors( {origin: true}));
bot.post("/", async function(req, res) {
const telegramText = req.body;
req.body.message &&
req.body.message.chat &&
req.body.message.chat.id &&
req.body.message.from &&
req.body.message.from.first_name;
if (telegramText) {
const chat_id = req.body.message.chat.id;
const first_name = req.body.message.from.first_name;
const receivedMessage = req.body.message.text;
//Define your RTDB Reference
const rtdbReference = admin.admin.database().ref('foo/bar');
// Fetch the date
const snap = await rtdbReference.get();
const snapValue = snap.val();
// Do whatever you need with snapValue to inject it in your response...
return res.status(200).send({
method: "sendMessage",
chat_id,
text: `Hello ${first_name}, \n You sent us message: ${receivedMessage}`,
});
}
return res.status(200).send({status: "An error occured"});
});
export const router = functions.https.onRequest(bot);

Related

Firebase CLI not deploying any Cloud Functions

I have an Angular project where I am trying to deploy a single firebase function.
This is what my functions directory looks like:
When I deploy these function with the command firebase deploy --only functions the output looks normal and no errors:
PS C:\Users\project-directory> firebase deploy --only functions
=== Deploying to 'firebase-project-name'...
i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run build
> build
> tsc
+ functions: Finished running predeploy script.
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
+ functions: required API cloudfunctions.googleapis.com is enabled
+ functions: required API cloudbuild.googleapis.com is enabled
i functions: cleaning up build files...
+ Deploy complete!
Project Console: https://console.firebase.google.com/project/project-name/overview
src/user/index.ts file with the function I am trying to deploy:
import functions = require('firebase-functions');
import admin = require('firebase-admin');
// import * as functions from "firebase-functions";
// import * as admin from 'firebase-admin';
const FieldValue = require('firebase-admin').firestore.FieldValue;
const db = admin.firestore();
/**
* Add user to firestore
*/
export const createProfile = async (userRecord: any) => {
const uid = userRecord.uid;
const admin = false;
const email = userRecord.email;
const photoURL = userRecord.photoUrl || 'enter shortened url for default image';
const name = userRecord.displayName || 'New User';
const spouse = userRecord.spouse || 'TBA';
const forumUserName = userRecord.forumUserName || 'New Username set by admin';
const address = userRecord.address || 'TBA';
const suburb = userRecord.suburb || 'TBA';
const state = userRecord.state || 'QLD';
const postCode = userRecord.postCode || '2000';
const homePhone = userRecord.homePhone || '02 1234 5678';
const mobilePhone = userRecord.mobilePhone || '0400 123 456';
const memNum = userRecord.memNum || 123;
const timestamp = FieldValue.serverTimestamp();
const memType = userRecord.memType || 'Nominated';
const memStatus = userRecord.memStatus || `Pending`;
const isStateCoord = userRecord.isStateCoord || false;
const stateCoordState = userRecord.stateCoordState || 'QLD';
//const newUserRef = db.doc(`users/${uid}`)
// Convert any date to timestamp for consistency
try {
return await db
.collection(`users`)
.doc(userRecord.uid)
.set({
uid: uid,
email: email,
photoURL: photoURL,
fullName: name,
mDOB: timestamp,
spouse: spouse,
sDOB: timestamp,
forumUserName: forumUserName,
address: address,
suburb: suburb,
state: state,
postCode: postCode,
homePhone: homePhone,
mobilePhone: mobilePhone,
memNum: memNum,
memType: memType,
memStatus: memStatus,
memDueDate: timestamp,
lastLoginDate: timestamp,
joined: timestamp,
updated: timestamp,
admin: admin,
isAdmin: admin,
isStateCoord: isStateCoord,
stateCoordState: stateCoordState,
});
} catch (message) {
return console.error(message);
}
};
exports.authOnCreate = functions.auth.user().onCreate(createProfile);
src/index.ts file imports the above file:
import * as user from './user';
export const createProfile = user.createProfile
The issue is that I am not seeing the function appear in the Firebase console.
What am I overlooking?
You have two different export syntaxes in src/user/index.ts:
export const createProfile = async (userRecord: any) => { /* ... */ }
exports.authOnCreate = functions.auth.user().onCreate(createProfile);
Use one, or the other, not both. They are incompatible with each other.
export const createProfile = async (userRecord: any) => { /* ... */ }
export const authOnCreate = functions.auth.user().onCreate(createProfile);
Then in your main src/index.ts, import the Cloud Function export, not the plain function:
import { authOnCreate } from './user'; // import specific parts for the best performance when transpiled
export const createProfile = authOnCreate;
In the original code I posted for you, createProfile was a const not an export.
Out of the box, should work just fine. The only difference I see is you've dropped the code into a user sub directory.
Again no issue and probably ok for readability.
Might be poor practice on my part, but ALL of my functions are in one file. Even when extensions are installed, they go into the same index.js(ts) file. Then if I modify a function I use firebase deploy --only functions:functionName

Error upon Cloud Function for Firebase deployment

I've been trying to deploy a Cloud Function to my Firebase project.
It's my first time doing so, also my first time programming with JavaScript.
Here's my code in Node.JS:
'use strict'
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
const firebaseTriggers = functions.region('europe-west1').firestore;
const db = admin.firestore();
exports.postNotification = firebaseTriggers
.document('/post notifications/{notificatioId}').onWrite((snap, context) => {
const notifcationRecieverId = snap.data().mReciever;
const payload = {
data: {
notification_type: 'POST',
title: snap.data().mTitle,
body: snap.data().mDescription,
sender_id: snap.data().mSender,
reciever_id: snap.data().mReciever,
notification_id: context.params.notificatioId
}
};
return db.collection('dog owners')
.document(notifcationRecieverId)
.get()
.then(recieverDoc => {
console.log('Retrieving FCM tokens');
const tokens = recieverDoc.data().mTokens;
console.log('Sending notification payload');
return admin.message().sendToDevice(tokens, payload);
});
});
Upong deployment, I'm getting the following error:
Can someone help me understand why?
Firstly you have got space in your colleciton name. This is bad convetion.
post notifications => postNotifications

Promise not returning value on request

I have been trying to get this to work, but am new to NodeJS. I suspect the issue is due to async, but am not familiar with how it works.
The idea behind this code is that it monitors a firebase database change and sends an email to the users. I am getting everything from the change snapshot, and using the values to check another table for user data. The request is not returning before the email gets sent and I am unsure why.
Edit I should specify that the email function sgMail is firing off before I get the results from the requests. I've tried putting a delay, but I am still not getting the result to return in time.
Here's my index.js
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
var requestify = require('requestify');
//SendGrid
const SENDGRID_API_KEY = functions.config().sendgrid.key;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.packingListEmail = functions.database.ref('Order/{orderID}')
.onUpdate(event => {
// Grab the current value of what was written to the Realtime Database.
const eventSnapshot = event.data;
//Here You can get value through key
var shipperInfo = eventSnapshot.child("fk_shipper_id").val();
var travelerInfo = eventSnapshot.child("fk_traveler_id").val();
//Print value of string
console.log(shipperInfo);
//Get Shipper Info
const shipperPath = 'https://shlep-me-f516e.firebaseio.com/User/'+shipperInfo+'.json';
requestify.get(shipperPath)
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
shipperResult = response.getBody();
console.log(shipperResult.email);
return shipperResult;
});
function getTravelerData() {
return new Promise(resolve => {
requestify.get('https://shlep-me-f516e.firebaseio.com/User/' + travelerInfo + '.json')
.then(function (response) {
resolve(response.getBody())
});
});
}
var TravelD = getTravelerData();
//Send an email
const msg = {
to: 'andrew#shlepme.com',
from: 'support#shlepme.com',
subject: 'New Follower',
// text: `Hey ${toName}. You have a new follower!!! `,
// html: `<strong>Hey ${toName}. You have a new follower!!!</strong>`,
// custom templates
templateId: 'd1ccfeb9-2e2d-4979-a3ca-c53975fe486e',
substitutionWrappers: ['%', '%'],
substitutions: {
'%shipper_name%': "Test",
'traveler_name': TravelD.name
// and other custom properties here
}
};
console.log('Sending email');
console.log(TravelD);
return sgMail.send(msg)
});
Any ideas? I have been trying to figure this out.
It seems that you need to understand about Promises first.
When you start using promises you will need to ALWAYS use them and chain one with the other.
So I would rewrite your code like this: (not tested)
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require("firebase-functions");
var requestify = require("requestify");
//SendGrid
const SENDGRID_API_KEY = functions.config().sendgrid.key;
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(SENDGRID_API_KEY);
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.packingListEmail = functions.database
.ref("Order/{orderID}")
.onUpdate(event => {
// Grab the current value of what was written to the Realtime Database.
const eventSnapshot = event.data;
//Here You can get value through key
var shipperInfo = eventSnapshot.child("fk_shipper_id").val();
var travelerInfo = eventSnapshot.child("fk_traveler_id").val();
//Print value of string
console.log(shipperInfo);
//Get Shipper Info
const shipperPath = "https://shlep-me-f516e.firebaseio.com/User/" + shipperInfo + ".json";
requestify.get(shipperPath)
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
var shipperResult = response.getBody();
console.log(shipperResult.email);
return shipperResult;
})
.then(function (shipperResult) {
//Send an email
const msg = {
to: "andrew#shlepme.com",
from: "support#shlepme.com",
subject: "New Follower",
// text: `Hey ${toName}. You have a new follower!!! `,
// html: `<strong>Hey ${toName}. You have a new follower!!!</strong>`,
// custom templates
templateId: "d1ccfeb9-2e2d-4979-a3ca-c53975fe486e",
substitutionWrappers: ["%", "%"],
substitutions: {
"%shipper_name%": "Test",
traveler_name: shipperResult.name
// and other custom properties here
}
};
console.log("Sending email");
console.log(shipperResult);
return sgMail.send(msg);
});
});

Firebase Functions check if the user id in the database is the current user id

Im working on sending notifications between android devices using Firebase functions. When A-Device sends a message to B-Device, the message will be stored in the firebasedatabase under A-Device Id und B-Device Id like this the problem is the function which i wrote checks always A-Device id therefore it sends the notification always to A-Device. it means when A-Device sends to B-Device the notification will be sent to A-Device
this is my Node.js code. please help me ;(
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
//const mId = firebase.auth().currentUser.getToken();
exports.sendNotification = functions.database.ref('/Messages/{mId}/{uId}/{messageId}').onWrite(event =>{
const mId = event.params.mId; //getting mId
const uId = event.params.uId; //getting uId
const val = event.data.val(); //getting the values from event
const from = val.from; //from value
const type = val.type; //type value
const message = val.message;
console.log("user_name ",user_name);
console.log("user_email ",user_email);
const getDeviceToken = admin.database().ref(`/Users/${uId}/`).once('value');//getting device token function
return getDeviceToken.then(snapshot =>{ //executing the function
const DeviceToken = snapshot.val().DeviceToken;
console.log ("Device Token is ",DeviceToken);
if (from == mId) {
delete DeviceToken;
}
const getName = admin.database().ref(`/Users/${from}/`).once('value');//getting device token function
return getName.then(snapshot =>{ //executing the function
const Name = snapshot.val().Name;
console.log ("Sender is ",Name);
const payload = {
data: {
title: `${Name} sent you a message.`,
body: `${message}`
}
};
return admin.messaging().sendToDevice(DeviceToken,payload).then(response => {
console.log (`Notification has been sent to ${Name}`);
});});
});
});

Express validator ".isEmpty()" not working

When I try to run my application I get an error saying that text boxes that are not empty are empty.
app.js:
https://pastebin.com/5pbVG7kq
index.hbs:
https://pastebin.com/neVV4X78
EDIT:
With express-validator, you need to use the "notEmpty()" function instead of validator's module "isEmpty()", which is not referenced in the readme.md. I tried it out with an empty string and without sending the parametr and it works fine in both cases.
OLD REPLY:
I'm facing the same issue with express-validator. I submitted the issue to the github respository so we have to wait for them to address the problem.
As a workaround in the meantime, you can use the isEmpty() function of the validator package directly.
var validator = require('validator');
validator.isEmpty(string) //returns true or false
Also note that validator only accepts a string value and it doesn't coerce the variable passed to it as opposed to express-validator, so you will need to handle the case when the parameter obtained via req.body.param is not sent.
Here is the link to the reported issue: https://github.com/ctavan/express-validator/issues/336
Hope this helps.
2019 express-validator
6.2.0
Here is what I use for now and it works perfect
app.js
const express = require('express');
const {createPost} = require('../controllers/post');
// Import check only form express-validator
const {check} = require('express-validator');
const router = express.Router();
router.post('/post',[
// Title
check('title').not().isEmpty().withMessage('Title is required.'),
check('title').isLength({
min:4,
max:150
}).withMessage('Title must be between 4 to 150 characters.'),
check('body').not().isEmpty().withMessage('Body is required.'),
check('body').isLength({
min:4,
max:2000
}).withMessage('body must be between 4 to 2000 characters.')
],createPost)
** Folder '../controllers/post'**
post.js
// Import validation result only from expres-validator
const {validationResult } = require('express-validator');
// Post model file with custom implementation.
const Post = require('../models/post');
exports.createPost = (req, res) => {
// Grab your validation errors here before making any CREATE operation to your database.
const errors = validationResult(req);
if (!errors.isEmpty()) {
const firstError = errors.array().map(error => error.msg)[0];
return res.status(400).json({ error: firstError });
}
const post = new Post({
title: req.body.title,
body: req.body.body
});
// Now you can safely save your data after check passes.
post.save()
.then(result => {
res.status(200).json({
post: result
})
});
};

Resources