Firebase Admin SDK sendMulticast - node.js

This code with a smaller list of tokens works correctly, but I don't know why it fails to send the notification to all the tokens when individually the token is valid.
I am doing something wrong? when the token list contains fewer tokens, all notifications are sent. There is a maximum of 30 tokens.
let notificationData = {
Id: messageInfo.ChatId,
Type: notificationType.ChatMessage,
Data: chatRoom
};
var payload = {
notification: {
title: title,
body: body,
},
data: {
NotificationData: JSON.stringify(notificationData),
},
apns: {
payload: {
aps: {
sound: "default",
},
},
},
};
payload.tokens = chatRoom.FCMTokens;
return admin.messaging().sendMulticast(payload).then(response => {
if (response.failureCount > 0) {
const failedTokens = [];
response.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(payload.tokens[idx]);
}
});
console.log('List of tokens that caused failures: ' + JSON.stringify(response));
console.log('List of tokens that caused failures: ' + failedTokens);
}
else {
console.log("Successsfully MulticastMessage");
}
return null;
}).catch(error => {
console.log("Error sending notification", error);
return null;
});
more info:

The problem was that being many users in the payload exceeded 4kb
Notification messages can contain an optional data payload. Maximum payload for both message types is 4KB, except when sending messages from the Firebase console, which enforces a 1024 character limit.

Related

Once I completed Stripe payment and then create-payment-intent can't fetch

I have a payment system with stripe payment intents and I want to create a succesfull paymnent . but once i payment then show this eorror in server side
C:\Project_Programing_hero\assainment-list\assainment-12\best-tech-server\node_modules\stripe\lib\Error.js:40
return new StripeInvalidRequestError(rawStripeError);
^
StripeInvalidRequestError: This value must be greater than or equal to 1.
on client side in checkoutFrom.js
useEffect(() => {
console.log(typeof (totalPrice));
fetch('http://localhost:5000/create-payment-intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ price: parseInt(totalPrice) }),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
const dataClientSecret = data?.clientSecret;
if (dataClientSecret) {
setClientSecret(dataClientSecret)
}
})
}, [totalPrice])
const handleSubmit = async (event) => {
event.preventDefault()
if (!stripe || !elements) {
return;
}
const card = elements.getElement(CardElement);
if (card == null) {
return;
}
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card,
});
if (error) {
console.log('[error]', error);
setCardError(error.message)
} else {
console.log('[PaymentMethod]', paymentMethod);
setCardError('')
}
// confirm card payment
setCardSuccess('')
setProcessing(true)
const { paymentIntent, error: intentError } = await stripe.confirmCardPayment(
`${clientSecret}`,
{
payment_method: {
card: card,
billing_details: {
name: customerName,
email: email
},
},
},
);
if (intentError) {
setCardError(intentError?.message)
setProcessing(false)
} else {
setCardError('')
setTransitionId(paymentIntent.id)
console.log(paymentIntent);
setCardSuccess('Congrats,Your payment is compiled')
// store payment to database
const payment = {
order: _id,
transitionId: paymentIntent.id
}
axios.patch(`http://localhost:5000/order/${_id}`, payment)
.then(res => {
setProcessing(false)
console.log(res.data);
})
}
}
“This value must be greater than or equal to 1” error shows that the amount [0] param set in the payment intent creation request is smaller than 1. In the endpoint /create-payment-intent at your server, you will need to ensure request.price is greater than or equal to 1, and correctly assign into amount param. For example,
const paymentIntent = await stripe.paymentIntents.create({
amount: request.price,
currency: 'usd',
automatic_payment_methods: {enabled: true},
});
Apart from the server side, you should also make sure that the totalPrice at frontend is greater than or equal to 1 before passing to server.
body: JSON.stringify({ price: parseInt(totalPrice) }),
[0] https://stripe.com/docs/api/payment_intents/create#create_payment_intent-amount

Microsoft Graph API outlook send attachments

How do you send attachments with the Microsoft graph outlook API? I understand everything for sending attachments up until the content bytes. The files that I need to send are a word document a pdf and a jpeg Is it asking me to turn the file into bytes, if so how would I do that? I am using node.js and I have the following code:
exports.send_mail = async function(req, res, next) {
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
//read test.html
//so you have to wait for the file to read then send it
message = fs.readFileSync('views/test.html', 'utf8');
console.log(rawImage.data.toString('utf8'))
try {
mailMess ={
message:{
subject: 'This is a test',
body:{
ContentType: 'HTML',
Content: message
},
ToRecipients:[
{
EmailAddress:{
Address: 'name#email.com'
}
}
],
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "attachment.jpeg",
"contentBytes": "not sure what to put here"
}
]
}
}
//sendmail
const result = await client
.api('/me/sendmail')
.version('v1.0')
.post(mailMess);
res.status('202')
parms.messages = result.value;
res.redirect('/');
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
}
I found out that param takes the file encoded as base64

Push notification returns ECONNRESET in Google Cloud Functions

I am having a function in Firebase Cloud Functions that is retrieves the user's device group id in order to send a push notification, and after sends a push notification. This works well if the function gets called only once, but if I have an array of users I want to send a push notification too, the sendPushNotification function returns error : FAILED err= { RequestError: Error: read ECONNRESET
at new RequestError (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/errors.js:14:15) for every try to send push
From what i understand ECONNRESET means that the connection gets closed at one end before finishing the operation, can some help/explain me why this is:
here is my code:
function sendFollowNotification(snapshot) {
const notificationMsg = getFollowNotificationMsg() //returns a string
snapshot.forEach(function(singleUser, index) {
const userId = singleUser.key;
const userObject = singleUser.val();
console.log("will get device group")
if (index + 1 == snapshot.numChildren()) {
return getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", true);
} else {
getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", false);
}
}
function getDeviceGroupNotificationKey(groupId, notificationTitle, notificationBody, notificationSubject, shouldReturn) {
const pathToDeviceGroup = admin.database().ref('deviceGroups').child(groupId);
pathToDeviceGroup.once("value").then( function(snapshot) {
const deviceGroupObj = snapshot.val();
const notification_key = deviceGroupObj.notification_key;
console.log("got notification key")
console.log(notification_key)
if (notification_key !== undefined) {
return sendPushToDeviceGroupOld(notification_key, notificationTitle, notificationBody, "notificationKeyOld2", notificationSubject, shouldReturn);
} else {
return
}
}).catch(reason => {
console.log("user device group not there")
return
})
}
function sendPushToDeviceGroupOld(notification_key, title, body, subject, message, shouldReturn) {
console.log('sending push to ' + notification_key)
const serverKey = '-';
const senderId = '-';
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
'project_id': senderId
},
body: {
to: notification_key,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
sound: "default",
},
priority : 'high',
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
return
})
.catch((err) => {
console.log('FAILED', err);
return
});
}

Facebook Messenger Bot wait to respond after many request and resume

When I write the alphabet on my facebook bot, my bot wait to respond.
I write for example : I write "a"... bot respond "a", I write "b"... bot respond "b", etc...
But, for example on the letter "l", the bot waits to respond, and resume after about some minutes :
after about some minutes, the bot responds :
I use the official code, from https://developers.facebook.com/docs/messenger-platform/guides/quick-start/
app.js
app.get('/webhook', function(req, res) {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === CONFIGURATION.webhook_token) {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Failed validation. Make sure the validation tokens match.");
res.sendStatus(403);
}
});
app.post('/webhook', function (req, res) {
let data = req.body;
// Make sure this is a page subscription
if (data.object === 'page') {
// Iterate over each entry - there may be multiple if batched
data.entry.forEach(function(entry) {
let pageID = entry.id;
let timeOfEvent = entry.time;
// Iterate over each messaging event
entry.messaging.forEach(function(event) {
if (event.message) {
receivedMessage(event);
} else {
console.log("Webhook received unknown event: ", event);
}
});
});
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know
// you've successfully received the callback. Otherwise, the request
// will time out and we will keep trying to resend.
res.sendStatus(200);
}
});
function receivedMessage(event) {
let senderID = event.sender.id;
let recipientID = event.recipient.id;
let timeOfMessage = event.timestamp;
let message = event.message;
console.log("Received message for user %d and page %d at %d with message:",
senderID, recipientID, timeOfMessage);
console.log(JSON.stringify(message));
let messageId = message.mid;
let messageText = message.text;
let messageAttachments = message.attachments;
if (messageText) {
// If we receive a text message, check to see if it matches a keyword
// and send back the example. Otherwise, just echo the text we received.
switch (messageText) {
case 'generic':
sendGenericMessage(senderID);
break;
default:
sendTextMessage(senderID, messageText);
}
} else if (messageAttachments) {
sendTextMessage(senderID, "Message with attachment received");
}
}
function sendGenericMessage(recipientId) {
let messageData = {
recipient: {
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: [{
title: "rift",
subtitle: "Next-generation virtual reality",
item_url: "https://www.oculus.com/en-us/rift/",
image_url: "http://messengerdemo.parseapp.com/img/rift.png",
buttons: [{
type: "web_url",
url: "https://www.oculus.com/en-us/rift/",
title: "Open Web URL"
}, {
type: "postback",
title: "Call Postback",
payload: "Payload for first bubble",
}],
}, {
title: "touch",
subtitle: "Your Hands, Now in VR",
item_url: "https://www.oculus.com/en-us/touch/",
image_url: "http://messengerdemo.parseapp.com/img/touch.png",
buttons: [{
type: "web_url",
url: "https://www.oculus.com/en-us/touch/",
title: "Open Web URL"
}, {
type: "postback",
title: "Call Postback",
payload: "Payload for second bubble",
}]
}]
}
}
}
};
callSendAPI(messageData);
}
function sendTextMessage(recipientId, messageText) {
let messageData = {
recipient: {
id: recipientId
},
message: {
text: messageText
}
};
callSendAPI(messageData);
}
function callSendAPI(messageData) {
request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: { access_token: CONFIGURATION.access_token },
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
let recipientId = body.recipient_id;
let messageId = body.message_id;
console.log("Successfully sent generic message with id %s to recipient %s",
messageId, recipientId);
} else {
console.error("Unable to send message.");
console.error(response);
console.error(error);
}
});
}
let server = app.listen(port, function () {
InterfaceLogin.process();
console.log('App listening on port 8080!');
});
server.timeout = 1000;
In my console, During the last respond I see :
Received message for user xxx and page xxx at xxx with message:
{"mid":"mid.$xxx","seq":xxxx,"text":"k"}
Successfully sent generic message with id mid.$xxx to recipient xxxxx
the bot don't respond, and after some minutes I see :
Received message for user xxx and page xxx at xxx with message:
{"mid":"mid.$xxx","seq":xxxx,"text":"l"}
Successfully sent generic message with id mid.$xxx to recipient xxxx
Webhook received unknown event: { sender: { id: 'xxx' },
recipient: { id: 'xxx' },
timestamp: xxx,
delivery:
{ mids: [ 'mid.$xxx' ],
watermark: xxx,
seq: 0 } }
the bots responds
My last respond is :
Received message for user xxx and page xxx at xxx with message:
{"mid":"mid.$xxx","seq":xx,"text":"k"}
Successfully sent generic message with id mid.$xxx to recipient xxx
Received message for user xxx and page xxx at xxx with message:
{"mid":"mid.$xxx","seq":xx,"text":"l"}
Successfully sent generic message with id mid.$xxx to recipient xxxx
Webhook received unknown event: { sender: { id: 'xxx' },
recipient: { id: 'xxx' },
timestamp: xxx,
delivery:
{ mids: [ 'mid.$xxx' ],
watermark: xxx,
seq: 0 } }
The messenger bot platform has rate limit, if you exceed it the requests will queue up and execute later.
https://developers.facebook.com/docs/messenger-platform/reference/send-api/

Adding 'typing_on' sender action bubble before each response from Wit.ai chatbot

I've built a flow-base chat bot using FB messenger, Wit.ai and node.js. It's working well, but in order to make the interaction seem more natural I want my bot to pause for a short while and appear to be typing each of its responses.
I want the 'typing' bubble to be displayed briefly before each response my bot sends, ideally being able to define the time the bubble is visible for before the response is sent. At the moment there are sections of my conversation where the bot sends consecutive messages and they are all sent too quickly at once.
The FB Messenger Send API says that either the 'message' or 'sender_action' property must be set. I've tried setting both like so:
const fbMessage = (id, text) => {
if(fruits.apples.indexOf(text) >= 0 || fruits.oranges.indexOf(text) >= 0) {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});
} else {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
But I get the following error:
I'm not sure what I need to do - I'm assuming I've got to set up some sort of 'sender_action' bot response that's triggered before each conversational response but I don't know how I'd do this.
To display the typing bubble you simply send a sender action of typing_on. This displays the typing indicator for up to 20 seconds, during which time you will send the actual message you want to send.
The JSON for this would be:
{
"recipient":{
"id":"USER_ID"
},
"sender_action":"typing_on"
}
The call is documented here
Got it working, can't work out how to control bubble timing but it's fine for now. The code below will make the typing bubble display briefly before each of my bot's responses without mucking up the flow of my conversation.
FB Messenger code:
const typingBubble = (id, text) => {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on"
});
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
const fbMessage = (id, text) => {
if(scenarioCombos.trends.indexOf(text) >= 0 || scenarioCombos.disruptions.indexOf(text) >= 0) {
var body = JSON.stringify({
recipient: { id },
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});
} else {
var body = JSON.stringify({
recipient: { id },
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
Wit.ai send action code (within 'actions'):
send({sessionId}, {text}) {
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
return typingBubble(recipientId, text), fbMessage(recipientId, text)
.then(() => null)
.catch((err) => {
console.error(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err.stack || err
);
});
} else {
console.error('Oops! Couldn\'t find user for session:', sessionId);
return Promise.resolve()
}
},

Resources