SendGrid template transactional v3 functions Firebase - firebase

I am using a function in Firebase to send an email every time there is a new record in Firestore, this worked fine, but it seems that SendGrid has been updated to a new version of transactional templates.
What I had before in the body of my SendGrid transaction template was:
nombre: {{nombre}}
email: {{email}}
celular: {{celular}}
valorPropiedad: {{valorPropiedad}}
This worked correctly, that is, it sent the mail (every time there was a new record in Firestore) with the data of the new record, but now it only sends the mail but arrives without any data. I think something has changed in SendGrid? or is it a theme of my function?
Before I used Angular 5 I am now using version 6.
Here the code of my function index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.firestoreEmail2 = functions.firestore
.document('domiciliarios/{domiciliarioId}')
.onCreate((snap, context) => {
const domiciliarioId = context.params.domiciliarioId;
const db = admin.firestore()
return db.collection('domiciliarios').doc(domiciliarioId)
.get()
.then(doc => {
const domiciliario = doc.data();
const msg = {
from: 'mail1#mail.com',
to: 'mail2#mail.com',
subject: 'mySubject',
templateId: 'myTemplateId',
substitutionWrappers: ['{{', '}}'],
substitutions: {
nombre: domiciliario.nombre,
email: domiciliario.email,
celular: domiciliario.celular,
valorPropiedad: `US$ ${domiciliario.valorPropiedad}`,
}
};
return sgMail.send(msg)
})
.then(() => console.log('email sent!'))
.catch(err => console.log(err))
});

After some brute force testing this combination worked.
exports.firestoreEmail = functions.firestore
.document( 'members/{memberId}' )
.onCreate( ( snap, context ) => {
const member = snap.data();
mail.setApiKey( SENDGRID_API_KEY );
const msg = {
to: member.email,
from: "hello#angularfirebase.com",
subject: "Welcome",
templateId: "xxx",
substitutions: {
name: member.name,
email: member.email,
membershipId: member.memberId
},
dynamic_template_data:
{
name: member.name,
email: member.email,
membershipId: member.memberId
}
};
return mail.send( msg ).then( () => console.log( 'email sent to receiver2!' ) )
.catch( err => console.log( err ) );
} );

Related

Firebase realtime database Cannot record touch move without a touch start. Touch Mov

enter code herein my Expo app I am using googleSignin as login method, so afterlogin I want to collect Name, email, photo, and post it to the database
import database from '#react-native-firebase/database';
const [initializing, setInitializing] = useState(true);
const [user, setUser] = useState();
GoogleSignin.configure({
webClientId: 'My_ID',
});
function onAuthStateChanged(user) {
setUser(user);
if (initializing) setInitializing(false);
}
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
return subscriber;
}, []);
async function onGoogleButtonPress() {
await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
const { idToken } = await GoogleSignin.signIn();
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
const user_sign_in = auth().signInWithCredential(googleCredential);
user_sign_in.then((user)=>{
console.log(user);
})
.catch((error) => {
console.log(error)
})
const userRef = database.ref(`/user_id/${user.uid}`);
userRef.set({
email: signInResult.user.email,
name: signInResult.user.displayName,
photoURL: signInResult.user.photoURL,
});
}
but I am getting this Error
WARN Warning: Cannot record touch move without a touch start.
Touch Move: {"identifier":0,"pageX":311.22845458984375,"pageY":496.953125,"timestamp":754177246}
Touch Bank: []
WARN Warning: Cannot record touch end without a touch start.
Touch End: {"identifier":0,"pageX":304.1109619140625,"pageY":495.1422119140625,"timestamp":754177252}
Touch Bank: []
I think there is mistake in code, You should wait till the promise resolved by signInWithCredential method.
Have a try using below changes in code of onGoogleButtonPress function:
async function onGoogleButtonPress() {
await GoogleSignin.hasPlayServices({showPlayServicesUpdateDialog: true});
const {idToken} = await GoogleSignin.signIn();
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
const user_sign_in = auth().signInWithCredential(googleCredential);
user_sign_in
.then(user => {
console.log(user);
const userRef = database().ref(`/user_id/${user.uid}`);
userRef.set({
email: user.email,
name: user.displayName,
photoURL: user.photoURL,
});
})
.catch(error => {
console.log(error);
});
}

Uncaught (in promise) TypeError: (0 , _firebase__WEBPACK_IMPORTED_MODULE_5__.db) is not a function

I am trying to use the Stripe Extension on Firebase to handle payments for my project. But when I try to go to stripe's checkout I get this error Uncaught (in promise) TypeError: (0 , firebase__WEBPACK_IMPORTED_MODULE_5_.db) is not a function.
This is the error
This is my Plans.js
const loadCheckout = async (priceId) => {
const docRef = doc(db("customers", `${user?.uid}`));
const docSnap = await getDoc(docRef);
const addedRef = await addDoc(
docSnap(collection(db, "checkout_sessions"), {
price: priceId,
success_url: window.location.origin,
cancel_url: window.location.origin,
})
);
const unsub = onSnapshot(addedRef, async (snap) => {
const { error, sessionId } = snap.data();
if (error) {
// Show an error to your customer and
// inspect your Cloud Function logs in the Firebase console
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
// We have a session, let's redirect to Checkout
// Init Stripe
const stripe = await loadStripe(
"PRIVATE_STRIPE_KEY"
);
stripe.redirectToCheckout({ sessionId });
}
});
};
return (
<div className="plans">
{Object.entries(products).map(([productId, productData]) => {
// Add some logic to check if the user's subscriptio is active
return (
<div className="plans-subscription">
<div className="plans-info">
<h5>{productData?.name}</h5>
<h6>{productData?.description}</h6>
</div>
<button onClick={() => loadCheckout(productData?.prices?.priceId)}>
Subscribe
</button>
</div>
);
})}
</div>
);
I am trying to do the same thing as a video but they're using Firebase v8.
This is what they did
const loadCheckout = async (priceld) => {
const docRef = await db
.collection("custoners")
.doc(user.uid)
.collection("checkout_sessions")
.add({
price: priceld,
success_url: window. location.origin,
cancel_url: window. location. origin,
}):
docRef.onSnapshot(async (snap) => {
const { error, sessionId } = snap.data():
if (error) (
// Show an error to your custoner and
// Inspect your Cloud Function logs in the Firebase console
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
// We have a session, let's redirect to Checkout
// Init Stripe
const stripe = await loadStripe(
"PRIVATE_STRIPE_KEY"
);
stripe.redirectToCheckout({ sessionId });
}
});
};
Perhaps I did not correctly did the conversion to v9 ? Thank you for your help you all
The db is not a function but you are trying to call it. Also, docSnap isn't one either. Try refactoring the code as shown below:
const docRef = doc(db, "customers", `${user?.uid}`);
const docSnap = await getDoc(docRef);
const addedRef = await addDoc(collection(docRef, "checkout_sessions"), {
price: priceId,
success_url: window.location.origin,
cancel_url: window.location.origin,
})
);

Firebase - getting error when importing "Service account object must contain a string "project_id" property."

It's my first time using Firebase, and I'd appreciate any help!
I had my code in one file, everything was working fine. I was trying to organize everything in separate files and folders and with the first import it breaks, giving me an "⚠ Error: Service account object must contain a string "project_id" property." The moment I bring back everything it's fine. (see below with redacted info)
So I can't bring anything out, and just import it, I tried it with several little pieces of it.
Below if you see const {signUp} = require('./handlers/users'), that causes it to break, if i comment it out (leaving the original code in) it's fine. I tried exporting just serviceAccount, and the same thing happens.
Thanks in advance!
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const app = require('express')()
const serviceAccount = require("./admin.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "----------------------"
});
const firebaseConfig = {
apiKey: "-------------------",
authDomain: "-----------------",
databaseURL: "-------------------",
projectId: "----------------",
storageBucket: "-------------------",
messagingSenderId: "-----------",
appId: "----------------------------",
measurementId: "----------------"
}
const db = admin.firestore()
const firebase = require('firebase')
firebase.initializeApp(firebaseConfig)
const {signUp} = require('./handlers/users')
//middleware to protect the code
const routeProtect = (req, res, next) => {
let idToken
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
idToken = req.headers.authorization.split('Bearer ')[1]
} else {
console.error('There is no token')
return res.status(403).json({error: 'Unauthorized'})
}
admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken
console.log(decodedToken)
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get()
})
.then(data => {
req.user.handle = data.docs[0].data().handle
return next()
})
.catch(err => {
console.error('There was an error with the token', err)
return res.status(403).json(err)
})
}
app.get('/posts', (req, res) => {
db
.collection('posts')
.orderBy('createdAt', 'desc')
.get()
.then(data => {
let posts = []
data.forEach(doc => {
posts.push({
postId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt
})
})
return res.json(posts)
})
.catch(err => console.error(err))
})
app.post('/post', routeProtect, (req, res) => {
if(req.body.body.trim() === '') {
return res.status(400).json({body: 'Boddy cannot be empty'})
}
const newPost = {
body: req.body.body,
userHandle: req.user.handle,
createdAt: new Date().toISOString()
}
db
.collection('posts')
.add(newPost)
.then(doc => {
res.json({message: `document ${doc.id} created successfully`})
})
.catch(err => {
res.status(500).json({error: 'something went wrong'})
console.error(err)
})
})
//email address validation helper functions
const isEmail = (email) => {
const emailRegEx = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
//match() matches a string against a regular expression
if (email.match(emailRegEx)) return true
else return false
}
const isEmpty = (string) => {
if (string.trim() === '') return true
else return false
}
//signup route
app.post('/signup', (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
}
let errors = {}
//validating the email address
if(isEmpty(newUser.email)) {
errors.email = 'This field cannot be empty'
} else if (!isEmail(newUser.email)) {
errors.email = 'You must enter a valid email address'
}
if(isEmpty(newUser.password)) errors.password = 'This field cannot be empty'
if(newUser.password !== newUser.confirmPassword) errors.confirmPassword = "Passwords must be the same"
if(isEmpty(newUser.handle)) errors.handle = 'This field cannot be empty'
//need to make sure the errors object is empthy
if(Object.keys(errors).length > 0) return res.status(400).json(errors)
//TODO validate data
let token, userId
db.doc(`/users/${newUser.handle}`).get()
.then(doc => {
if (doc.exists) {
return res.status(400).json({handle: 'this handle is already taken'})
}else {
return firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
}
})
.then(data => {
userId = data.user.uid
return data.user.getIdToken()
})
.then(idToken => {
token = idToken
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new Date().toISOString(),
userId
}
return db.doc(`/users/${newUser.handle}`).set(userCredentials)
})
.then(() => {
return res.status(201).json({token})
})
.catch(err => {
console.error(err)
if(err.code ==='auth/email-already-in-use') {
return res.status(400).json({email: 'Email is already in use'})
} else {
return res.status(500).json({error: err.code})
}
})
}
)
//login route
app.post('/login', (req, res) => {
const user = {
email: req.body.email,
password: req.body.password
}
let errors = {}
if(isEmpty(user.email)) errors.email = 'Cannot be empty'
if(isEmpty(user.password)) errors.password = 'Cannot be empty'
if(Object.keys(errors).length > 0) return res.status(400).json(errors)
//logging in the user
firebase.auth().signInWithEmailAndPassword(user.email, user.password)
.then(data => data.user.getIdToken())
.then(token => res.json({token}))
.catch(err => {
console.error(err)
if(err.code === 'auth/wrong-password') return res.status(403).json({general: 'Wrong credentials, try again'})
else return res.status(500).json({error: err.code})
})
})
exports.api = functions.https.onRequest(app)
my admin.js contains
const admin = require("firebase-admin");
const serviceAccount = require("./admin.js");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "-------------"
});
const db = admin.firestore()
module.exports = {admin, db}
go to project setting on firebase console for app, and looking for service account tab, than at bottom clik "generate new private key", and will download new file "name-service-admin-account.json"
admin.initializeApp({
credential: admin.credential.cert('path/to/service-account-that-has-download-before.json'),
databaseURL: "-------------"
});

Firebase Functions ReferenceError with SendGrid function

I'm trying to get started with SendGrid and a Firestore database, using Firebase functions. I've gone through tutorials and set up according to the latest notation, (snap, context) instead of (event). I can't figure out what's wrong with this script:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
//admin.initializeApp(functions.config().firebase);
const SENDGRID_API_KEY = my-api-key-is-here;
const sendgridemail = require('#sendgrid/mail');
sendgridemail.setApiKey(SENDGRID_API_KEY);
exports.confEmail = functions.firestore
.document('clients/{clientId}/projects/{projectId}/form-data/{docId}') //any write to this node will trigger email
.onCreate((snap, context) => {
const clientId = context.params.clientId;
const projectId = context.params.projectId;
const docId = context.params.docId;
const fsdb = admin.firestore();
return fsdb.collection('clients/'+clientId+'/projects/'+projectId+'/form-data').doc(docId)
.get()
.then(doc => {
const docData = doc.data()
const msgbody = {
to: docData.EMAIL,
from: 'xxxxx#gmail.com',
subject: 'Form Submission Confirmation',
templateId: 'd-07bf6a2b89084951a30ceddcd9c8915f',
substitutionWrappers: ['{{', '}}'],
substitutions: {
formdata: "Message Body\n<br>"+docData.CONF_MSG
}
};
return confEmail.send(msgbody)
})
.then(() => console.log('confimration mail sent success') )
.catch(err => console.log(err) )
});
The error message generated in the Firebase console is mysterious, and I'm not even sure how to interpret it.
ReferenceError: confEmail is not defined
at fsdb.collection.doc.get.then.doc (/user_code/index.js:48:13)
at process._tickDomainCallback (internal/process/next_tick.js:135:7
)
My best guess just that my 'confEmail' function is not defined because there's an error in it, but I can't figure out what. Or does it mean something else?
It looks like most of the tutorial scripts are over-complicating things. and a simpler script like this seems to work.
const sendgrid = require('#sendgrid/mail');
sendgrid.setApiKey(SENDGRID_API_KEY);
exports.confEmail = functions.firestore
.document('clients/{clientId}/projects/{projectId}/form-data/{docId}') //any write to this node will trigger email
.onCreate((snap, context) => {
const docData = snap.data();
const msgbody = {
to: docData.EMAIL,
from: 'xxxxxxx#gmail.com',
subject: 'Form Submission Confirmation',
templateId: 'd-07bf6a2b89084951a30ceddcd9c8915f',
substitutionWrappers: ['{{', '}}'],
substitutions: {
formdata: docData.CONF_MSG
}
};
return sendgrid.send(msgbody)
});

I am receiving this error while getting notifications from firebase

'use strict'
const functions = require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification=functions.database.ref('/notifications/{user_id}/{notification_id }').onWrite((change,context) =>{
const user_id=context.params.user_id;
const notification_id=context.params.notification_id;
console.log('The user ID is :',user_id);
if(!change.after.val()){
return console.log('A notification has been deleted from database:',notification_id);
}
const fromUser=admin.database().ref(`/notifications/${user_id}/${notification_id}`).once('value');
return fromUser.then(fromUserResult=>{
const from_user_id=fromUserResult.val().from;
console.log('You have new notification from: : ', from_user_id);
const userQuery=admin.database().ref(`users/${from_user_id}/name`).once('value');
return userQuery.then(userResult=>{
const userName=userResult.val();
const deviceToken=admin.database().ref(`/users/${user_id}/device_token`).once('value');
return deviceToken.then(result =>{
const token_id=result.val();
const payload={
notification:{
title:"Friend Request",
body:`${userName} has sent you request`,
icon:"default"
}
};
return admin.messaging().sendToDevice(token_id, payload);
});
});
});
});
TypeError: Cannot read property 'from' of null
at fromUser.then.fromUserResult (/user_code/index.js:22:47)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
The only line of code where you're accessing a property called from is here:
const from_user_id=fromUserResult.val().from;
Therefore, fromUserResult.val() must be returning null.
fromUserResult is a DataSnapshot type object. According to the API documentation for the val() method, it can return null if there is no data at the location of the query. So, you will have to check for that case in your code.
I have achieved sending a notification with sender's name using this code:
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Notifications/{receiver_user_id}/{notification_id}')
.onWrite((data, context) =>
{
const receiver_user_id = context.params.receiver_user_id;
const notification_id = context.params.notification_id;
if(!data.after.val())
{
console.log('A notification has been deleted :' , notification_id);
return null;
}
const sender_user_id = admin.database().ref(`/Notifications/${receiver_user_id}/${notification_id}`).once('value');
return sender_user_id.then(fromUserResult =>
{
const from_sender_user_id = fromUserResult.val().from;
const userQuery = admin.database().ref(`/Users/${from_sender_user_id}/name`).once('value');
return userQuery.then(userResult =>
{
const senderUserName = userResult.val();
console.log('You have notification from :' , senderUserName);
const DeviceToken = admin.database().ref(`/Users/${receiver_user_id}/device_token`).once('value');
console.log('Checkpoint2');
return DeviceToken.then(result =>
{
const token_id = result.val();
const payload =
{
notification:
{
//from_sender_user_id : from_sender_user_id,
title: "New Chat Request",
body: `${senderUserName} wants to connect with you`,
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response =>
{
console.log('This was the notification Feature');
return null;
}).catch(error => {
console.error(error);
res.error(500);
});
});
});
});
});

Resources