Cloud Function not executed Flutter - firebase

I have this cloud function in my index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
const db = admin.firestore();
const fcm = admin.messaging();
console.log("osakosak");
export const sendToDevice = functions.firestore
.document('orders/{orderId}')
.onCreate(async snapshot => {
console.log("osakosak2");
const order = snapshot.data();
const querySnapshot = await db
.collection('users')
.doc(order.ustaID)
.collection('tokens')
.get();
const tokens = querySnapshot.docs.map(snap => snap.id);
const payload: admin.messaging.MessagingPayload = {
notification: {
title: 'New Order!',
body: `you sold a ${order.day} for ${order.time}`,
click_action: 'FLUTTER_NOTIFICATION_CLICK'
}
};
return fcm.sendToDevice(tokens, payload);
});
However, when the document gets added a notification isn't sent. Nor is anything printed. I have deployed the function.

You need to check your function error logs in your firebase functions. Go to your function named sendToDevice and click show daily logs. Also be sure that collection and document names are correct. I had the same issue and I solved them by checking logs and correcting the collection/document names in function.

Related

Read from firebase storage and write to firestore using firebase functions

I had tried this typescript code 👇
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import serviceAccount from "/Users/300041370/Downloads/serviceKey.json";
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
const buckObj = functions.storage.bucket("myBucket").object();
export const onWikiWrite = buckObj.onFinalize(async (object) => {
const filePath = object.name ?? "test.json";
const bucket = admin.storage().bucket("myBucket");
bucket.file(filePath).download().then((data) => {
const contents = data[0];
data = {"key": "value"};
const doc = admin.firestore().collection("myCollection").doc();
doc.set(data);
});
});
but this gave me following error
"status":{"code":7,"message":"Insufficient permissions to (re)configure a trigger (permission denied for bucket myBucket). Please, give owner permissions to the editor role of the bucket and try again.
I had asked this question here but it got closed as duplicate of this question. It basically said, storage.bucket("myBucket") feature is not supported and that I'll have to instead use match for limiting this operation to files in this specific bucket/folder. Hence, I tried this 👇
const buckObj = functions.storage.object();
export const onWikiWrite = buckObj.onFinalize(async (object) => {
if (object.name.match(/myBucket\//)) {
const fileBucket = object.bucket;
const filePath = object.name;
const bucket = admin.storage().bucket(fileBucket);
bucket.file(filePath).download().then((data) => {
const contents = data[0];
const doc = admin.firestore().collection("myCollection").doc();
const data = {content: contents}
doc.set(data);
});
}
});
I am still facing the same issue. I'll repeat that here:
"status":{"code":7,"message":"Insufficient permissions to (re)configure a trigger (permission denied for bucket myBucket). Please, give owner permissions to the editor role of the bucket and try again.
Since version 1.0 of the Firebase SDK for Cloud Functions, firebase-admin shall be initialized without any parameters within the Cloud Functions runtime.
The following should work (I've removed the check on filePath):
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
export const onWikiWrite = functions.storage
.object()
.onFinalize(async (object) => {
const fileBucket = object.bucket;
const filePath = object.name;
const bucket = admin.storage().bucket(fileBucket);
return bucket
.file(filePath)
.download()
.then((data) => {
const contents = data[0];
return admin
.firestore()
.collection('myCollection')
.add({ content: contents });
});
});
Note that we return the chain of promises returned by the asynchronous Firebase methods. It is key, in a Cloud Function which performs asynchronous processing (also known as "background functions") to return a JavaScript promise when all the asynchronous processing is complete.
We also use the add() method instead of doing doc().set().
Finally, when checking the value of the filePath, be aware of the fact that there is actually no concept of folder or subdirectory in Cloud Storage (See this answer).

Firebase Cloud Function not executing Flutter

I have the following function in my index.ts file:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
const fcm = admin.messaging();
export const sendToDevice = functions.firestore
.document('orders/{orderId}')
.onCreate(async snapshot => {
print("aa")
console.log("osakosak");
const order = snapshot.data();
const querySnapshot = await db
.collection('users')
.doc(order.ustaID)
.collection('tokens')
.get();
const tokens = querySnapshot.docs.map(snap => snap.id);
const payload: admin.messaging.MessagingPayload = {
notification: {
title: 'New Order!',
body: `you sold a ${order.day} for ${order.time}`,
click_action: 'FLUTTER_NOTIFICATION_CLICK'
}
};
return fcm.sendToDevice(tokens, payload);
});
However, when the new document gets added into the order collection, this doesn't get triggered. Even the print and console.log don't work. I tried putting print and console log before export, and it still didn't fire.
Based on your comments ("It depends on cloud_firestore in pubspec.yaml"), it seems that you didn't deploy your Cloud Function correctly.
As a matter of fact, Cloud Functions are totally independent from your Flutter app (your front-end). It is a back-end service. You should deploy it with the Firebase CLI, see the doc. Note that the code shall be in the Firebase Project, not in your Flutter project.

Connecting Dialogflow to Firebase question

I have been reading around but cannot find the answer
I tried my firebase and it's not storing any data.
Here's the related inline editor
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
function angerEmotionCapture(agent) {
let angryTo = agent.parameters.angryDirectedTo;
agent.add(`love your ${angryTo},dude`);
return db.collection('directedTo').add({directedTo: angryTo});
}
Here's my firebase database
Any help will be greatly appreciated, thanks!
Please have a look into the following sample code showing how to connect Firebase's Firestore database to Dialogflow fulfillment hosting on Firebase functions:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('WriteToFirestore', writeToDb);
agent.handleRequest(intentMap);
});
Have a look into the Dialogflow's Firestore GitHub example

FIREBASE FATAL ERROR: Database initialized multiple times

I have multiple database instances in my firebase app. I am trying to write into three database instances in firebase cloud functions. My understanding by following this document is no need to initialize multiple apps for each database instance. We can initialize one and pass in the database url. As a side note, I have another function with similar kind of functionality where I have trigger event in one database and write data to other database instance and it works fine.
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
const app = admin.app();
export const onStart =
functions.database.instance('my-db-1')
.ref('path')
.onCreate(async (snapshot, context) => {
return await onCreate('my-db-1',snapshot,context);
});
export const onStartDb01 = functions.database.instance('my-db-2')
.ref('path')
.onCreate(async (snapshot, context) => {
return await onCreate('my-db-2', snapshot, context);
});
async function onCreate(dbInstance: string, snapshot:
functions.database.DataSnapshot, context: functions.EventContext):
Promise<any> {
const defaultDb = app.database(defaultDbUrl);
const actvDb = app.database(actvDbUrl);
await defaultDb.ref('path')
.once("value")
.then(snap => {
const val = snap.val();
---do something and write back---
});
await actvDb.ref('path')
.once("value")
.then(snap => {
const val = snap.val();
---do something and write back---
});
return true;
}
But when a db event is fired, it logs the error as below
Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.
You'll need to initialize a separate app() for each database instance.
Based on Doug's answer here that should be something like this:
const app1 = admin.initializeApp(functions.config().firebase)
const app2 = admin.initializeApp(functions.config().firebase)
And then:
const defaultDb = app1.database(defaultDbUrl);
const actvDb = app2.database(actvDbUrl);

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

Resources