Pushpad is not able to send notifcation from node.js app - web-push

I have written the code shown below to send the push notification:
const pushpad = require('pushpad');
require('dotenv').config();
const axios = require('axios');
const project = new pushpad.Pushpad({
authToken: process.env.PUSH_PAD_AUTH_TOKEN,
projectId: process.env.PUSH_PAD_PROJECT_ID
});
console.log('called pushpad');
let notification = new pushpad.Notification({
project: project,
body: 'Hello world!',
title: 'Website Name',
targetUrl: 'http://example.com',
iconUrl: 'http://example.com/assets/icon.png',
imageUrl: 'http://example.com/assets/image.png',
ttl: 604800,
requireInteraction: true,
customData: '123',
actions: [
{
title: 'My Button 1',
targetUrl: 'http://example.com/button-link',
icon: 'http://example.com/assets/button-icon.png',
action: 'myActionName'
}
],
starred: true,
sendAt: new Date(Date.UTC(2016, 7 - 1, 25, 10, 9)),
customMetrics: ['examples', 'another_metric']
});
// deliver to everyone
notification.broadcast(function (err, result) {
console.log("error is " + err);
});
module.exports = notification;
but somehow, as soon as I run this code, it gives me error Unprocessable Entity . So how to solve this error ?

Probably you have entered some wrong parameters. For example customMetrics must be defined in your project settings before using them.
Try the same code with a simple notification:
let notification = new pushpad.Notification({
project: project,
body: 'Hello world!'
});

Related

Why I can't I add an API using swagger?

Im a beginner at swagger. What im trying to do is creating an API and the problem is when test it on Postman, the Postman can't find the API.
This is my router:
router
/**
* #swagger
* /orders/{id}/status:
* put:
* summary: accept the order
* tags: [Order]
* description: this action can accessd by driver or admin
* responses:
* 200:
* description: The order was updated
*
* 404:
* description: you are not authorized to access this route
* 500:
* description: Some error happened
*/
.route("/:id/status")
.put(protect, authorize("user", "admin"), requestOrder);
This is my controller:
//#route put/api/v1/orders/:id
//#access private for admin & user who create the order
exports.requestOrder = asyncHandler(async (req, res, next) => {
const updatedOrder = await Order.findByIdAndUpdate(
{ _id: req.params.id },
{ status: req.body.status },
{
new: true,
}
);
if (!updatedOrder) {
return next(
new ErrorResponse(`error ${req.params.id}`, 404)
);
}
res.status(200).json({
success: true,
msg: ` order with id ${req.params.id} is updated`,
data: updatedOrder,
});
});
I'm wondering if it is any mistake in the swagger code since i'm a beginner, and not sure if I can notice any mistake in it.
In the postman I get error 404 (Cannot PUT)
Also im using MongoDb as a database.
Did you create a Swagger config file and added your servers?
Example:
//./configs/openapi.js
module.exports = {
openapi: '3.0.0',
info: {
title: 'Your API Titel',
description: '',
termsOfService: '',
contact: {
name: 'Your contact Details',
url: 'https://example.com',
},
license: {},
},
servers: [
{
url: 'http://localhost:2000/api',
description: 'Local development server',
}
]
};
And then you need to import the config file in app.js
const express = require('express')
const app = express()
const swaggerJSDoc = require('swagger-jsdoc');
swaggerDefinition = require('./config/openapi.js')
const options = {
swaggerDefinition,
// Paths to files containing OpenAPI definitions
apis: ['src/routes/*js']
};
const swaggerSpec = swaggerJSDoc(options);
api.listen(config.api.port, () => {
console.log('Server running at port 2000')
})

Action button push-notification not working | Node | sw-push

I've created a web app using MEAN stack and integrated push message notification for certain events. But how do I add link/s in the notification so the user can click and gets redirected to site on browser
here's a specimen I send
const notificationPayload = JSON.stringify({
notification: {
title: "Hello",
body: "World,
icon: <icon link>,
vibrate: [100, 50],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [{
action: "explore",
title: "Checkout",
icon: <icon link>,
click_action: "https://www.google.com", // not working
url: "https://www.google.com" // not working
}]
}
});
Resultant is good, and checkout button is clickable... but no reaction
Okay, firstly, NotificationAction object is only allowed to have 3 keys:
action
title
icon
So Naturally, click_action & url will just be ignored.
Coming to your question on how to handle actions, you need to write handlers for each action in the array based on the NotificationAction.action key in your service worker. A detailed guide can de found here.
example:
self.registration.showNotification("New mail from Alice", {
actions: [
{
action: 'archive',
title: 'Archive'
}
]
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
if (event.action === 'archive') {
// Archive action was clicked
archiveEmail();
} else {
// Main body of notification was clicked
clients.openWindow('/inbox');
}
}, false);
References:
NotificationAction
NotificationEvent.action
Notification API
Displaying a notification - Web Fundamentals
Notification behaviour
I'll setup the precise answer, that resolved my case with ngsw-worker:
this was the notification that I was sending, with it, you can send data in the data attribute:
notification: {
title: "hello world,
body: "you have a notification",
icon: <user dp url>,
vibrate: [100, 50],
data: {
dateOfArrival: Date.now(),
primaryKey: 1,
url: <user's profile URL> // data to be used
},
actions: [{
action: "explore",
title: "Checkout",
icon: '... some address ... jolly-roger.png',
},
{
action: 'close',
title: 'Close'
}
]
}
Now, open ngsw-worker.js. It's usually in root folder of dist (for production ready rip), or in node_modules\#angular\service-worker\ngsw-worker.js
here, goto line that handles clicks on notification (:1932: in my case)
this.scope.addEventListener('notificationclick', (event) =>
and you can add your code here regarding the ULR to open. example:
this.scope.addEventListener('notificationclick', (event) => {
try {
clients.openWindow("http://localhost:3000/#/"+event.data.url);
} catch (e) {
clients.openWindow("http://localhost:3000/#/");
}
this.onClick(event)
});
alternatively, if you are handling it within angular itself, you can use redefine the function after injecting swPush in constructor:
this._swPush.notificationClicks.subscribe( event => {
console.log("event = ", event);
});
Rest related articles are present in Salvio's answer below.

How to configure Node email-template to use SendGrid as Transport

What I want to achieve
I want to send an email using email-templates and configuring the transport to use sendgrid in My
Node/Express backend
However when I send my email, I get no errors in the console but I do not receive any emails on my email client. and I have made extra sure all my information with API Keys and Email addresses are correct.
Code
const express = require('express');
const nodemailer = require("nodemailer")
const sendgridTransport = require("nodemailer-sendgrid-transport")
const router = express.Router();
let transporter = nodemailer.createTransport(
sendgridTransport({
auth: {
api_key:
process.env.SENDGRID_API_KEY
}
})
);
const Email = require('email-templates');
const path = require('path')
router.post('/email', (req,res) => {
const email = new Email({
message: {
from: 'info#4loop.online'
},
transport: {
jsonTransport: transporter
}
});
email
.send({
template: path.join(__dirname, "../templates", "contact"),
message: {
to: 'info#4loop.online'
},
locals: {
name: 'Elon'
}
})
.then(console.log)
.catch(console.error);
})
module.exports = router
link to email-template docs
https://www.npmjs.com/package/email-templates
Response
{
envelope: { from: 'info#4loop.online', to: [ 'info#4loop.online' ] },
messageId: '<1082af04-68ec-2337-1fa0-926aca91b9ce#4loop.online>',
message: '{"to":[{"address":"info#4loop.online","name":""}],"from":{"address":"info#4loop.online","name":""},"attachments":[],"subject":"Hi Elon, welcome to Mars","html":"\\n<p>Hi Elon,</p>\\n<p>Welcome to Mars, the red planet.</p>","text":"<hey>There.</hey>","headers":{},"messageId":"<1082af04-68ec-2337-1fa0-926aca91b9ce#4loop.online>"}',
originalMessage: {
to: 'info#4loop.online',
from: 'info#4loop.online',
attachments: [],
subject: 'Hi Elon, welcome to Mars',
html: '\n<p>Hi Elon,</p>\n<p>Welcome to Mars, the red planet.</p>',
text: '<hey>There.</hey>'
}
}
{
envelope: { from: 'info#4loop.online', to: [ 'info#4loop.online' ] },
messageId: '<0e80bb1f-01ae-d994-ea06-549e34a0eed0#4loop.online>',
message: '{"to":[{"address":"info#4loop.online","name":""}],"from":{"address":"info#4loop.online","name":""},"attachments":[],"subject":"Hi Elon, welcome to Mars","html":"\\n<p>Hi Elon,</p>\\n<p>Welcome to Mars, the red planet.</p>","text":"<hey>There.</hey>","headers":{},"messageId":"<0e80bb1f-01ae-d994-ea06-549e34a0eed0#4loop.online>"}',
Answer
The answer was really simple. all you need to do is replace the transport configuration with this.
const email = new Email({
message: {
from: 'info#4loop.online'
},
send: true,
transport:transporter
});

Invalid registration token provided. Make sure it matches the registration token the client app receives from registering with FCM

I got this code from my client iOS app on XCode console
Firebase registration token: diWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7h
diWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7h
NodeJS
console.log("START");
var FCM = require('fcm-node');
var serverKey = require('/Users/bheng/Desktop/Apps/APNS/node/mhn-app-firebase-adminsdk-bs45c-5ac3770488.json')
var fcm = new FCM(serverKey)
var collapseKey = 'new_message';
var message = {
to: 'diWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7hdiWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7h',
data: {
cpeMac: '000000000000',
type: 'malware'
},
notification: {
title: 'Hello baby',
body: 'Nice body',
tag: collapseKey,
icon: 'ic_notification',
color: '#18d821',
sound: 'default',
},
};
fcm.send(message, function(err, response){
if (err) {
console.log("Something has gone wrong!")
console.log(JSON.stringify(err));
} else {
console.log("Successfully sent with response: ", JSON.stringify(response))
}
})
console.log("END");
Result
When I run it
node app.js
I kept getting
START
END
Successfully sent with response: {"results":[{"error":{"code":"messaging/invalid-registration-token","message":"Invalid registration token provided. Make sure it matches the registration token the client app receives from registering with FCM."}}],"canonicalRegistrationTokenCount":0,"failureCount":1,"successCount":0,"multicastId":7577724855311354000}
How would one go about debugging this further?
your token has some additional random string such as
to: 'diWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7hdiWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7h',
just remove : diWY78iar8s: from your token string
console.log("START");
var FCM = require('fcm-node');
var serverKey = require('/Users/bheng/Desktop/Apps/APNS/node/mhn-app-firebase-adminsdk-bs45c-5ac3770488.json')
var fcm = new FCM(serverKey)
var collapseKey = 'new_message';
var message = {
to: 'APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7hdiWY78iar8s:APA91bHJAzXe384OEYvfk4bKsyS1NQvteph7DwG7JRIMm_HuXg8EeNllVrsSi0v9W_Gh95ezbOStp3ZWuWl0AzFKxMaCOjN81yiz7A5qhkONrd7lP2CTkUbFErw28r3ONTLvo8c8sO7h',
data: {
cpeMac: '000000000000',
type: 'malware'
},
notification: {
title: 'Hello baby',
body: 'Nice body',
tag: collapseKey,
icon: 'ic_notification',
color: '#18d821',
sound: 'default',
},
};
fcm.send(message, function(err, response){
if (err) {
console.log("Something has gone wrong!")
console.log(JSON.stringify(err));
} else {
console.log("Successfully sent with response: ", JSON.stringify(response))
}
})
console.log("END");
Response from FCM :
Successfully sent with response: { results: [ { messageId: '0:1543448946734425%479ec0e2479ec0e2' } ],
canonicalRegistrationTokenCount: 0,
failureCount: 0,
successCount: 1,
multicastId: 6133765431734591000 }
One of the interesting reasons for invalid registration is: that device have a different token. Maybe you are trying to use a past token.
In my case what happened was I was getting the FCMRegistrationToken from my colleague via Discord and the Ctrl+C Ctrl+V was modifying the token. On obtaining the token via email solved the issue.

Send data from bot to client in DirectLine WebChat - NodeJS Botframework

I added bot to an HTML page on our intranet using the following code:
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet" />
<style>
#bot{
height: 600px;
}
</style>
<div>
<div id="bot" />
</div>
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<script>
var user = {
id: 'user-id',
name: 'user name'
};
var botConnection = new BotChat.DirectLine({
token: '[token]',
user: user
});
BotChat.App({
user: user,
botConnection: botConnection,
bot: { id: 'test', name: 'test' }
}, document.getElementById("bot"));
botConnection
.postActivity({
from: user,
name: 'WelcomeDialog',
type: 'event',
value: ''
})
.subscribe(function (id) {
console.log('"trigger requestWelcomeDialog" sent');
});
</script>
Now, I need to send data back to this client, to be executed on that HTML page, since the page exists within the context of our intranet (internal servers), so I want to have the intent return from LUIS and directed to specific dialog, then send the required entity value from this dialog to the client to be executed there, then send the result back to the server so I can display a formatted message to the user.
So basically, I would need to have 2-way communication between the client (added to my intranet) and the bot itself (the nodejs app hosted in azure)
Update:
I implemented the backchannel in my bot, so now the code looks like this:
jQuery(function () {
//get user name from the system
var userid = _spPageContextInfo.userId;
var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")";
var requestHeaders = { "accept": "application/json;odata=verbose" };
$.ajax({
url: requestUri,
contentType: "application/json;odata=verbose",
headers: requestHeaders,
success: onSuccess,
error: onError
});
function onSuccess(data, request) {
var loginName = data.d.Title;
var user = {
id: userid,
name: loginName
};
var botConnection = new BotChat.DirectLine({
token: '[token]',
user: user
});
let FindPerson = function (personName) {
let msg = `You asked for ${personName}`
botConnection
.postActivity({ type: "event", value: msg, from: { id: "me" }, name: "FindPersonResultFound" })
.subscribe(id => console.log("success"));
}
BotChat.App({
user: user,
botConnection: botConnection,
bot: { id: 'TestBot', name: 'test bot' }
}, document.getElementById("bot"));
botConnection
.postActivity({
from: user,
name: 'WelcomeDialog',
type: 'event',
value: ''
})
.subscribe(function (id) {
console.log('"trigger requestWelcomeDialog" sent');
});
botConnection.activity$
.filter(activity => activity.type === "event" && activity.name === "FindPerson")
.subscribe(activity => FindPerson(activity.value))
}
function onError(error) {
alert("error");
}
})
My server side code looks like this:
bot.on('event', function (message) {
if (message.name == 'WelcomeDialog') {
bot.beginDialog(message.address, message.name);
}
if (message.name === "FindPersonResultFound") {
bot.beginDialog(message.address, message.name, message.value)
}
});
However, if I send a message that's related to any dialog, it gets repeated as if the sender is me:
According to your output, I assumpt that your bot application would contain a default root dialog / which will return any thing you input.
If so, you can try to change beginDialog to replaceDialog in your bot event register functions, to clear the previous dialog stack.
Also, you could provide more code about your bot application, so that we can have a deeper looking over.

Resources