I'm sending push notifications in Actions on Google (ref this official documentation).
So once I send the notification I'm sending title in it. So it looks like this, where A Very Happy Birthday, Jay Patel is the title that I've sent.
So once I click on the notification, it opens Google Assistant and invokes the intent (configured in this step), but it doesn't specify any contexts or other data regarding that notification so I'm not getting a person name that I've specified in title or any other data.
I want to know, is there anyway so that I can pass some data(title or any other data of notification) to the invocation intent when a
person taps on the notification?
I'm getting this json response in my webhook when a person taps on the notification
{
"responseId":"e2de9045-b415-kr45-be96-1a35779abcde",
"queryResult":{
"queryText":"intent:send_push",
"parameters":{
},
"allRequiredParamsPresent":true,
"fulfillmentText":"Latest update is here!",
"fulfillmentMessages":[
{
"text":{
"text":[
"Latest update is here!"
]
}
}
],
"intent":{
"name":"projects/happierwork-bot/agent/intents/d1f4c032-28cf-4906-a393-6f2a612c0496",
"displayName":"send_push"
},
"intentDetectionConfidence":1.0,
"languageCode":"en-in"
},
"originalDetectIntentRequest":{
"source":"google",
"version":"2",
"payload":{
"user":{
"userId":"my_id",
"accessToken":"my_token",
"permissions":[
"UPDATE"
],
"locale":"en-IN",
"lastSeen":"2018-10-09T05:57:18Z"
},
"conversation":{
"conversationId":"ABwppHE7XKXDdjfjSRPF_OCVttGKMavfasdffngesQEI2Jy11Q8fp8lNXgpgGtFe7KCxK3WWey-1ColL7",
"type":"NEW"
},
"inputs":[
{
"intent":"send_push",
"rawInputs":[
{
"inputType":"URL",
"url":"bot_url?intent=send_push"
}
],
"arguments":[
{
"name":"UPDATES",
"boolValue":true
}
]
}
],
"surface":{
"capabilities":[
{
"name":"actions.capability.WEB_BROWSER"
},
{
"name":"actions.capability.AUDIO_OUTPUT"
},
{
"name":"actions.capability.SCREEN_OUTPUT"
},
{
"name":"actions.capability.MEDIA_RESPONSE_AUDIO"
}
]
},
"isInSandbox":true,
"availableSurfaces":[
{
"capabilities":[
{
"name":"actions.capability.WEB_BROWSER"
},
{
"name":"actions.capability.AUDIO_OUTPUT"
},
{
"name":"actions.capability.SCREEN_OUTPUT"
}
]
}
]
}
},
"session":"projects/myproject-bot/agent/sessions/ABwppHE7XKXDdjfjSRPF_OCVtasdffagbKiGKA9sCsQEI2Jy11Q8fp8lNXgpgGtFe7KCxK3WWey-1ColL7"
}
You can supply argument data using the argument field of the push message target.
Please view the reference for more detail:
https://actions-on-google.github.io/actions-on-google-nodejs/2.12.0/interfaces/_service_actionssdk_api_v2_.googleactionsv2custompushmessagetarget.html
Related
I am new to Meteor and integrating Paypal(Which i never had done).
from Client side in meteor -
I am calling method on button click.
<MDBBtn onClick={(e) => callPaypal(e)} color="primary" type="submit">
Add and Continue to PayPal
</MDBBtn>
And this callpaypal() method ->
import { Link as ReactRouterLink } from 'react-router-dom'
const callPaypal = (e) => {
e.preventDefault();
Meteor.call('createPayalPayment', (err, res) => {
console.log(res[1].href) **FIRST CONSOLE**
if (res) {
let link = res[1];
if (link.href) {
return <ReactRouterLink to={`${link.href}`} />
}
}
})
}
Calling createPayalPayment method from server ->
import { Config } from "./paypal_config";
createPayalPayment() {
var data = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
// "return_url": `${Meteor.absoluteUrl('/execute'), { "replaceLocalhost": "true" }}`,
"return_url": "http://127.0.0.1:3000/execute",
"cancel_url": "http://172.20.10.5:3000/cancel"
},
"transactions": [{
"amount": {
"currency": "USD",
"total": "1.00"
},
"description": "This is the payment description."
}]
};
paypal.configure(Config);
var ppCreate = Meteor.wrapAsync(paypal.payment.create.bind(paypal.payment));
var ppExecute = Meteor.wrapAsync(paypal.payment.execute.bind(paypal.payment));
var response = ppCreate(data);
if (response.state !== 'created') {
console.log('not created!!!!!!!!!!!!!!!!')
}
else {
console.log(response); **SECOND CONSOLE**
return response.links;
}
}
And here is my Paypal config ->
export const Config = {
'mode': 'sandbox',
'client_id': 'client_Id',
'client_secret': 'secret'
};
FIRST CONSOLE --> 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-1HR12649X9688931M'
SECOND CONSOLE -->>
{ id: 'PAYID-L2IJO4I8GE24787GF168351L',
intent: 'sale',
state: 'created',
payer: { payment_method: 'paypal' },
transactions:
[ { amount: [Object],
description: 'This is the payment description.',
related_resources: [] } ],
create_time: '2020-04-10T15:57:37Z',
links:
[ { href: 'https://api.sandbox.paypal.com/v1/payments/payment/PAYID-L2IJO4I8GE24787GF168351L',
rel: 'self',
method: 'GET' },
{ href: 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-1HR12649X9688931M',
rel: 'approval_url',
method: 'REDIRECT' },
{ href: 'https://api.sandbox.paypal.com/v1/payments/payment/PAYID-L2IJO4I8GE24787GF168351L/execute',
rel: 'execute',
method: 'POST' } ],
httpStatusCode: 201
}
As the links[2].href is the URL, where the paypal should be redirect here and user can login to the account. But It is not redirecting. So I am manually redirecting to this link in callPaypal() method just below the First console.
But Still the router is unable to redirect to the link maybe Outer Domain Issue or whatever even it's not showing error.
Please Is there any way that the paypal redirect itself to paypal login? I have already wasted my 2 days on this and still have nothing.
Thanks.
I added the Redirect URL in my paypal developer account for this project.
It looks like you're using an old, redirect-based PayPal integration, so my recommendation is trying the new in-context experience: https://developer.paypal.com/demo/checkout/#/pattern/server
Notice the two fetch calls to '/demo/..' placeholders, which would need to be replaced with actual routes on your server. The first should return a PayID (or newer v2/orders ID), and the second should execute/capture that ID.
This integration is superior because your site stays loaded in the background, and the buyer is able to checkout and pay without 'leaving' it.
On the server side, it looks like you may be using the old deprecated v1 PayPal-node-SDK, which there is no reason to do for a new integration. Instead, use the v2 Checkout-NodeJS-SDK
I am trying to implement push notification in KaiOS app. I simply follow below links.
W3C Push API
Push API introduction
Service Worker Cookbook - Web Push Payload
After follow all links the push is working in browser but not in KaiOS app.
If anybody have any sample code or documents please share.
Any help will be appriciated.
1) First, add this permission in manifest.webapp
"permissions": {
"serviceWorker":{
"description": "required for handle push."
},
"push":{
"description": "New update push."
},
"desktop-notification": {
"description": "New content update notification for the user."
}
}
2) service worker file sw.js code
self.addEventListener('push', function(event) {
event.waitUntil(
self.registration.showNotification('My Push', {
body: 'Push Activated',
})
);
});
self.addEventListener('activate', e => {
self.clients.claim();
});
3) Add service worker on app start
registerSW : function() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').then(function(reg) {
console.log('Service Worker Registered!', reg);
reg.pushManager.getSubscription().then(function(sub) {
if (sub === null) {
} else {
console.log('Subscription object: ', sub);
}
});
}).catch(function(e) {
console.log('SW reg failed');
});
}
}
4) Call service worker by any dom element like button
registerServiceWorker: function() {
Notification.requestPermission().then(function(permission) {
if (permission === 'granted') {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(function(reg) {
reg.pushManager.subscribe({
userVisibleOnly: true
}).then(function(sub) {
console.log('Endpoint URL: ', sub.endpoint);
}).catch(function(e) {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Unable to subscribe to push', e);
}
});
})
}
}
});
}
That's it.
I had same problem as this, but I followed this simple web push notification method,
https://medium.com/#seladir/how-to-implement-web-push-notifications-in-your-node-react-app-9bed79b53f34
as well as I fixed that issue and now It work properly. please don't forget to add permissions like below into the manifest.webapp file.
"permissions": {
"serviceworker": {
"description": "Needed for assocating service worker"
},
"desktop-notification": {
"description": "Needed for creating system notifications."
},
"notifications": {},
"push": {
"description": "Required for being updated with new goals in soccer matches"
},
"geolocation": {
"description": "Marking out user location"
},
"alarms": {
"description": "Scheduling alarms"
}
},
and as well as please refer this kaios documention for run the applicaion on kaios device.
https://developer.kaiostech.com/getting-started/build-your-first-hosted-app/pwa-to-hosted-app
I'm following the facebook messenger develop QuickStart to create a Node.js project, and I improved it to work in quick reply. Then when I tried the Generic Template and List Template, but it didn't work.
As the following source code, when I input the work "generic" or "list", the messenger should reply me with the template messege. But there was nothing happened.
} else if (received_message.text === 'generic') {
console.log('generic in');
response = {
"attachment":{
"type":"template",
"payload":{
"template_type":"generic",
"elements":[
{
"title":"Welcome!",
"image_url":"http://webapplication120181023051009.azurewebsites.net/colorcar1.jpg",
"subtitle":"We have the right hat for everyone.",
"default_action": {
"type": "web_url",
"url": "https://www.taobao.com/",
"messenger_extensions": false,
"webview_height_ratio": "tall",
"fallback_url": "https://www.taobao.com/"
},
"buttons":[
{
"type":"web_url",
"url":"https://www.taobao.com/",
"title":"View Website"
},{
"type":"postback",
"title":"Start Chatting",
"payload":"DEVELOPER_DEFINED_PAYLOAD"
}
]
}
]
}
}
}
// Sends the response message
callSendAPI(sender_psid, response);
// Sends response messages via the Send API
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
console.log('PAGE_ACCESS_TOKEN:');
console.log(PAGE_ACCESS_TOKEN);
console.log('request body:');
console.log(request_body);
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v2.6/me/messages?access_token=" + PAGE_ACCESS_TOKEN,
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
} else {
console.error("Unable to send message:" + err);
}
});
}
Sorry, I forgot to add the url into whiltelist.
I am having issues understanding how to display images on the Echo Show inside the audioPlayer 'Now Playing' screen.
I am currently playing an audio file and want to display an image on the 'Now Playing' screen. The closest I have been able to get is the following code which displays the image and title just before the audio starts, but then disappears immediately and the Echo Show goes to the 'Now Playing' screen with no background image and no metadata. I feel I'm close, but just cannot understand how to update the 'Now Playing' screen, rather than the screen that comes immediately before it.
This is part of the code (which works as per above):
var handlers = {
'LaunchRequest': function() {
this.emit('PlayStream');
},
'PlayStream': function() {
let builder = new Alexa.templateBuilders.BodyTemplate1Builder();
let template = builder.setTitle('Test Title')
.setBackgroundImage(makeImage('https://link_to_my_image.png'))
.setTextContent(makePlainText('Test Text'))
.build();
this.response.speak('OK.').
audioPlayerPlay(
'REPLACE_ALL',
stream.url,
stream.url,
null,
0)
.renderTemplate(template);
this.emit(':responseReady');
}
I have been looking at this page https://developer.amazon.com/docs/custom-skills/audioplayer-interface-reference.html but cannot understand how to convert the structure of what is on that page into my code. I assume that, from the code on the page :
{
"type": "AudioPlayer.Play",
"playBehavior": "valid playBehavior value such as ENQUEUE",
"audioItem": {
"stream": {
"url": "https://url-of-the-stream-to-play",
"token": "opaque token representing this stream",
"expectedPreviousToken": "opaque token representing the previous stream",
"offsetInMilliseconds": 0
},
"metadata": {
"title": "title of the track to display",
"subtitle": "subtitle of the track to display",
"art": {
"sources": [
{
"url": "https://url-of-the-album-art-image.png"
}
]
},
"backgroundImage": {
"sources": [
{
"url": "https://url-of-the-background-image.png"
}
]
}
}
}
}
I somehow need to get this part :
"metadata": {
"title": "title of the track to display",
"subtitle": "subtitle of the track to display",
"art": {
"sources": [
{
"url": "https://url-of-the-album-art-image.png"
}
]
},
Into this block of my code :
audioPlayerPlay(
'REPLACE_ALL',
streamInfo.url,
streamInfo.url,
null,
0)
.renderTemplate(template);
(and could probably lose the .renderTemplate(template); part as it only flashes up briefly before the 'Now Playing' screen loads anyway.
Any ideas on how to achieve this?
Thanks!
Update :
I have added the following to index.js:
var metadata = {
title: "title of the track to display",
subtitle: "subtitle of the track to display",
art: {
sources: {
url: "https://url-of-the-album-art-image.png"
}
}
};
And modified the audioPlayer as follows :
audioPlayerPlay(
'REPLACE_ALL',
stream.url,
stream.url,
null,
0,
metadata)
.renderTemplate(template);
And modified the responseBuilder.js as indicated:
audioPlayerPlay(behavior, url, token, expectedPreviousToken, offsetInMilliseconds, metadata) {
const audioPlayerDirective = {
type : DIRECTIVE_TYPES.AUDIOPLAYER.PLAY,
playBehavior: behavior,
audioItem: {
stream: {
url: url,
token: token,
expectedPreviousToken: expectedPreviousToken,
offsetInMilliseconds: offsetInMilliseconds,
metadata : metadata
}
}
};
this._addDirective(audioPlayerDirective);
return this;
}
But I'm still not getting anything displayed on the 'Now Playing' screen.
For some reason the Echo Show is not updating in realtime and needs to be rebooted before it will show whatever is passed in the metadata variable, which is why I wasn't seeing any results.
Simply passing a variable as such works fine. I just need to find out why the content gets stuck on the 'Now Playing' screen and requires a reboot to work.
var "metadata": {
"title": "title of the track to display",
"subtitle": "subtitle of the track to display",
"art": {
"sources": [
{
"url": "https://url-of-the-album-art-image.png"
}
]
},
Just define your metadata as below. And pass it as a 6th argument to audioPlayerPlay;
"metadata": {
"title": "title of the track to display",
"subtitle": "subtitle of the track to display",
"art": {
"sources": [
{
"url": "https://url-of-the-album-art-image.png"
}
]
},
audioPlayerPlay(
'REPLACE_ALL',
streamInfo.url,
streamInfo.url,
null,
0,metadata)
P.S. For this to work properly, You have to modify your node modules which you ll be zipping and uploading to lambda.
steps -
Go to your node_modules\alexa-sdk\lib and open responseBuilder file in it. And modify the code as follows-
audioPlayerPlay(behavior, url, token, expectedPreviousToken, offsetInMilliseconds, **metadata**) {
const audioPlayerDirective = {
type : DIRECTIVE_TYPES.AUDIOPLAYER.PLAY,
playBehavior: behavior,
audioItem: {
stream: {
url: url,
token: token,
expectedPreviousToken: expectedPreviousToken,
offsetInMilliseconds: offsetInMilliseconds
},
**metadata : metadata**
}
};
this._addDirective(audioPlayerDirective);
return this;
}
P.S. - The node module modifications required only if you are using alexa-sdk version 1.
I know it's been years since this question was originally posted, but for those like me who stumble upon this now, make sure you use a unique token in the play directive because metadata is cached using that token.
See the yellow Important note in the following section https://developer.amazon.com/en-US/docs/alexa/custom-skills/audioplayer-interface-reference.html#images
Important: The metadata for a given audio stream is identified by the
audioItem.stream.token included in the Play directive. Note that the
metadata associated with a particular audioItem.stream.token may be
cached in the Alexa service for up to five days, so changes to the
metadata (such as a different image, or a change to the title text)
may not be reflected immediately on the device. For instance, you may
notice this when testing if you experiment with different images or
title text for the same audio stream. You can send a new Play
directive with a different audioItem.stream.token to clear the cache.
And an example payload with a token:
{
"type": "AudioPlayer.Play",
"playBehavior": "valid playBehavior value such as ENQUEUE",
"audioItem": {
"stream": {
"url": "https://cdn.example.com/url-of-the-stream-to-play",
"token": "opaque token representing this stream",
"expectedPreviousToken": "opaque token representing the previous stream",
"offsetInMilliseconds": 0,
"captionData":{
"content": "WEBVTT\n\n00:00.000 --> 00:02.107\n<00:00.006>My <00:00.0192>Audio <00:01.232>Captions.\n",
"type": "WEBVTT"
}
},
"metadata": {
"title": "title of the track to display",
"subtitle": "subtitle of the track to display",
"art": {
"sources": [
{
"url": "https://cdn.example.com/url-of-the-album-art-image.png"
}
]
},
"backgroundImage": {
"sources": [
{
"url": "https://cdn.example.com/url-of-the-background-image.png"
}
]
}
}
}
}
I'm working on setting up validaton rules for a Firebase data structure, created using the Bolt compiler.
I'm currently having the Bolt statement below:
path /sharedEvents/{share} is Boolean[] {
read() { isMailOfCurrentUser( share ) }
create() { isOwnerOfEvent( ...) } //NOT YET CORRECT!
delete() { isOwnerOfEvent( prior(...) } //NOT YET CORRECT!
}
With this, I'm trying to achieve that:
Only users having a mail corresponding to the key of 'share' are allowed to read the data (they use this date to retrieve the key of events shared with them.
Only the owner of an event is able to add/remove the key for his event to the list of shared events.
This second point is where I'm running into trouble -I'm not able to create the create/delete rules- since I have no idea how to reference the keys of the boolean values in the validation rule...
Example data in Firebase for the above bolt statement:
sharedEvents
ZW5kc3dhc0BldmVyeW1hMWwuYml6
-BDKBEvy-hssDhKqVF5w: true
-FDKBEvy-hsDsgsdsf5w: true
-ADBEvy-hfsdsdKqVF5w: true
aXQnc251bWJlcnNAbWExbDJ1LnVz
-KBEvy-hsDhH6OKqVF5w: true
To clarify the needs on this example:
Only user with mail 'ZW5kc3dhc0BldmVyeW1hMWwuYml6' is able to read the three nested childs.
Only the owner of event '-BDKBEvy-hssDhKqVF5w' should be able to create/delete this value. (the same for the other event key/boolean pairs).
My question: is this setup going to work (and how to setup the create/delete rules)? Or is this not going to work and should I rethink/structure the data?
Any help is appreciated!
-----------------OUTPUT JSON FILE------------------------------------------
The question above has been answered, this section is showing the resulting json
"sharedEvents": {
"$share": {
".read": "<removed for readability>",
"$event": {
".validate": "newData.isBoolean()",
".write": "<removed for readability>"
}
}
},
Thanks again for your quick support!
You'll need a nested path statement to handle the restriction on the events (the nodes under /sharedEvents/$mail/$eventid). I quickly prototyped with this JSON structure:
{
"events": {
"-ADBEvy-hfsdsdKqVF5w": {
"name": "Event 1",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-BDKBEvy-hssDhKqVF5w": {
"name": "Event 2",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-FDKBEvy-hsDsgsdsf5w": {
"name": "Event 3",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-KBEvy-hsDhH6OKqVF5w": {
"name": "Event 3",
"ownerMail": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
},
"sharedEvents": {
"ZW5kc3dhc0BldmVyeW1hMWwuYml6": {
"-ADBEvy-hfsdsdKqVF5w": true,
"-BDKBEvy-hssDhKqVF5w": true,
"-FDKBEvy-hsDsgsdsf5w": true
},
"aXQnc251bWJlcnNAbWExbDJ1LnVz": {
"-KBEvy-hsDhH6OKqVF5w": true
}
},
"userMails": {
"peter": "aXQnc251bWJlcnNAbWExbDJ1LnVz",
"puf": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
}
And came up with these rules:
path /sharedEvents/{share} {
read() { isMailOfCurrentUser(share) }
}
path /sharedEvents/{share}/{event} is Boolean {
create() { isOwnerOfEvent(event) }
delete() { isOwnerOfEvent(prior(event)) }
}
isMailOfCurrentUser(share) { true }
getMailOfCurrentUser(uid) { root.ownerMails.uid }
getEventOwnerMail(event) { root.events.event.ownerMail }
isOwnerOfEvent(event) { getMailOfCurrentUser(auth.uid) == getEventOwnerMail(event) }
Ignoring any mistakes on my end, this should be the basics of the authorization structure you're looking for.