Facebook Messenger Bot Generic Template redirects to 'Watch' section - facebook

Recently I have noticed that the facebook video links that I pass on a generic template aka "cards" are redirecting the users to "watch" section of facebook.
-I know for sure that this is not an issue with the code but it must be something on facebook end?!
Is anyone experiencing this ?
To satisfy the "need to see some code" requests:
I'm using BootBot and this is my specific implementation:
const showLatestVideos = (payload, chat) => {
chat.say({
cards: [
{ title: '😅😅', image_url: 'https://scontent.fprn1-1.fna.fbcdn.net/v/t15.13418-10/p370x247/52063931_808166469575942_2311605833122709504_n.jpg?_nc_cat=106&_nc_ht=scontent.fprn1-1.fna&oh=fa00211a8bdf83959a23bac5971a19f8&oe=5CEE1050', default_action: {
type: "web_url",
url: "https://web.facebook.com/SwedenViral/videos/795477234150322/",
webview_height_ratio: "tall"
},
buttons:[
{
type:"web_url",
url:"https://web.facebook.com/SwedenViral/videos/795477234150322/",
title:"Tagga någon",
webview_height_ratio: "tall"
}
]
},
{ title: '😂🤣', image_url: 'https://scontent.fprn1-1.fna.fbcdn.net/v/t15.13418-10/p370x247/52171349_1186996514800023_9059384507546730496_n.jpg?_nc_cat=1&_nc_ht=scontent.fprn1-1.fna&oh=b9ca303276cbbeb131d5c659b2812e54&oe=5CE89DDB', default_action: {
type: "web_url",
url: "https://web.facebook.com/SwedenViral/videos/241869170093762/",
webview_height_ratio: "tall"
},
buttons:[
{
type:"web_url",
url:"https://web.facebook.com/SwedenViral/videos/241869170093762/",
title:"Berätta",
webview_height_ratio: "tall"
}
]
},
{ title: 'The most interesting and satisfying video you\'ll ever watch...', image_url: 'https://scontent.fprx1-1.fna.fbcdn.net/v/t15.5256-10/48349980_984643338399874_7749589283798777856_n.jpg?_nc_cat=102&_nc_ht=scontent.fprx1-1.fna&oh=d4b8f45f9115d561f66e519ec3cad053&oe=5D1DA1BB', default_action: {
type: "web_url",
url: "https://web.facebook.com/SwedenViral/videos/1021393401391534/",
webview_height_ratio: "tall"
},
buttons:[
{
type:"web_url",
url:"https://web.facebook.com/SwedenViral/videos/1021393401391534/",
title:"Kommentar",
webview_height_ratio: "tall"
}
]
},
{ title: 'Hur jag lämnande jobbet idga...🤣😂', image_url: 'https://scontent.fprn1-1.fna.fbcdn.net/v/t15.13418-10/p235x350/52142869_152469279005397_1516129000290779136_n.jpg?_nc_cat=1&_nc_ht=scontent.fprn1-1.fna&oh=0aed9824d288ce94f4ed426421c2d910&oe=5D282FFA', default_action: {
type: "web_url",
url: "https://web.facebook.com/SwedenViral/videos/816827101985067/",
webview_height_ratio: "tall"
},
buttons:[
{
type:"web_url",
url:"https://web.facebook.com/SwedenViral/videos/816827101985067/",
title:"Tagga någon",
webview_height_ratio: "tall"
}
]
}
]
});
};
And this is how the above content/message is sent:
bot.hear(['latest', 'videos', 'rate', 'senaste', 'videon'], showLatestVideos);

Answering this question/issue...
It turned out to be a Facebook bug which is fixed now! Hooray

Related

AWS Api Gateway VTL Merge Json Object

Trying to merge the principalId from Lambda Authorizer into the payload that will be sent to Event Bridge.
So far I've gotten close by transforming to map and re-creating the Json object. The problem is that this Json object is printed out as a key:value pair with no quotes, So there's an error thrown.
According to the docs, there's non $util.toJson($map) available, this seems to be only available for AppSync.
const eventsAPI = new RestApi(this, 'eventsAPI', apigwOps);
const LambdaAuth0Authorizer = new LambdaAuth0Authorizer(this, 'LambdaAuth0Authorizer', {
env: {
auth0Audience: '',
auth0Domain: '',
},
});
const eventTypeResource = eventsAPI.root.addResource('event');
const options: IntegrationOptions = {
credentialsRole: apigwRole,
passthroughBehavior: PassthroughBehavior.NEVER,
requestParameters: {
'integration.request.header.X-Amz-Target': "'AWSEvents.PutEvents'",
'integration.request.header.Content-Type': "'application/x-amz-json-1.1'",
},
requestTemplates: {
'application/json': `
#set ( $map = $util.parseJson($input.body) )
#set ( $j = {
"eventType": "$map['eventType']",
"action": "$map['action']",
"subject": "$map['subject']",
"eventTime": $map['eventTime'],
"actor": "$context.authorizer.principalId"
}
)
{"Entries":
[
{
"Source": "com.xyz",
"Detail": "$util.escapeJavascript($j)",
"Resources": [],
"DetailType": "event",
"EventBusName": "${eventBus.eventBusName}"
}
]
}
`,
},
integrationResponses: [
{
statusCode: '200',
responseTemplates: {
'application/json': '',
},
},
],
};
eventTypeResource.addMethod('POST', new Integration({
type: IntegrationType.AWS,
uri: `arn:aws:apigateway:${env.region}:events:path//`,
integrationHttpMethod: 'POST',
options: options,
}), {
authorizer: LambdaAuth0Authorizer.authorizer,
methodResponses: [{ statusCode: '200' }],
requestModels: { 'application/json': getEventModel(this, eventsAPI) },
requestValidator: new RequestValidator(this, 'eventValidator', {
restApi: eventsAPI,
validateRequestBody: true,
}),
});
This generates:
{"Entries":
[
{
"Source": "com.uproarapi",
"Detail": "{eventType=FOLLOW, action=CREATE, subject=USER_777POIUY, eventTime=51644444444, actor=}",
"Resources": [],
"DetailType": "UpRoarEvent",
"EventBusName": "UpRoarEventBus"
}
]
}
With an error:
{"Entries":[{"ErrorCode":"MalformedDetail","ErrorMessage":"Detail is malformed."}],"FailedEntryCount":1}

503 The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later. nuxt js

My site was running fine and then I updated nuxt.config.js. Then after that, the site starts to show Service Unavailable.
I am using pm2 to start / deploy the app. Its vps server with apache in it.
Its showing:
Service Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
But, if I run npm run dev the site loads fine without any issue. Also, I checked the status with pm2 list, it showing the app is online.
My package.json
{
"name": "nuxtjs",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt --hostname domain.link --port 49000",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"deploy": "pm2 start npm --name nuxtjs -- start"
},
"dependencies": {
"#nuxtjs/axios": "^5.13.6",
"#yeger/vue-masonry-wall": "^3.0.16",
"core-js": "^3.19.3",
"nuxt": "^2.15.8",
"pm2": "^5.1.2",
"vue": "^2.6.14",
"vue-server-renderer": "^2.6.14",
"vue-template-compiler": "^2.6.14",
"webpack": "^4.46.0"
},
"devDependencies": {},
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "49000"
}
}
}
My nuxt.config:
import { join } from "path";
export default {
target: "static",
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
title: "Project Title",
htmlAttrs: {
lang: "en",
},
meta: [
{ charset: "utf-8" },
{ name: "viewport", content: "width=device-width, initial-scale=1" },
{ hid: "description", name: "description", content: "" },
{ name: "format-detection", content: "telephone=no" },
{ property: "og:title", content: "Project Title" },
{
property: "og:image",
content: "https://lovealabradoodle.com/images/two.jpg",
},
{
property: "og:description",
content:
"Content here",
},
],
link: [
{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Roboto:400,600,700%7CMontserrat:400,500,600,700",
},
{
rel: "stylesheet",
href: "https://use.fontawesome.com/releases/v5.15.4/css/all.css",
},
{
rel: "stylesheet",
href: join("/", `fonts/flaticon/flaticon.css`),
},
{
rel: "stylesheet",
href: join("/", `css/bootstrap.min.css`),
},
{
rel: "stylesheet",
href: join("/", `css/plugins.css`),
},
{
rel: "stylesheet",
href: join("/", `css/magnific-popup.css`),
},
{
rel: "stylesheet",
href: join("/", `css/aos.css`),
},
{
rel: "stylesheet",
href: join("/", `css/style.css`),
},
{
rel: "stylesheet",
href: join("/", `css/styles/maincolors.css`),
},
],
script: [
// {
// src: "js/jquery.min.js",
// body: true,
// },
{
src: join("/", `js/bootstrap.bundle.min.js`),
body: true,
},
{
src: join("/", `js/imagesloaded.pkgd.min.js`),
body: true,
},
{
src: join("/", `js/isotope.pkgd.min.js`),
body: true,
},
{
src: join("/", `js/jquery.magnific-popup.min.js`),
body: true,
},
{
src: join("/", `js/easing.min.js`),
body: true,
},
{
src: join("/", `js/aos.js`),
body: true,
},
{
src: join("/", `js/custom-nuxt.js`),
body: true,
},
],
bodyAttrs: {
id: "top",
},
},
// Global CSS: https://go.nuxtjs.dev/config-css
css: [
// "~/static/css/bootstrap.min.css",
// "~/static/css/plugins.css",
// "~/static/css/magnific-popup.css",
// "~/static/css/aos.css",
// "~/static/css/style.css",
// "~/static/css/styles/maincolors.css",
],
//Global JS
// script: [
// "~assets/js/custom.js"
// ],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [],
// Auto import components: https://go.nuxtjs.dev/config-components
components: {
path: "~/components", // will get any components nested in let's say /components/test too
pathPrefix: false,
},
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
"#nuxtjs/axios",
],
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
// Workaround to avoid enforcing hard-coded localhost:3000: https://github.com/nuxt-community/axios-module/issues/308
baseURL: "http://api.domain.link/api",
retry: { retries: 3 },
},
publicRuntimeConfig: {
axios: {
baseURL: "http://api.domain.link/api",
},
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
extractCSS: true,
},
};
I ran yarn/npm install and it worked for me

Adding lambda integration to HttpApi routes with SAM

I am currently attempting to have a AWS::Serverless::HttpApi integrate with a group of AWS::Serverless::Function's. The goal is to define these resources within a SAM template, and define the actual API using a swagger file.
I have my SAM template defined as so:
Resources:
apiPing:
Type: AWS::Serverless::Function
Properties:
Description: 'Ping'
CodeUri: ../bin/cmd-api-ping.zip
Handler: cmd-api-ping
Runtime: go1.x
Role:
Fn::GetAtt: apiLambdaRole.Arn
Events:
PingEvent:
Type: HttpApi
Properties:
ApiId: !Ref api
Path: /ping
Method: post
api:
Type: AWS::Serverless::HttpApi
Properties:
StageName: prod
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: swagger.yaml
AccessLogSettings:
DestinationArn: !GetAtt accessLogs.Arn
Format: $context.requestId
And my swagger file:
openapi: 3.0.1
info:
title: 'API'
version: 2019-10-13
paths:
/ping:
post:
summary: 'invoke ping'
operationId: 'apiPing'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PingRequest'
required: true
responses:
'200':
description: 'Successful'
content:
application/json:
schema:
$ref: '#/components/schemas/PongResponse'
x-amazon-apigateway-integration:
httpMethod: "POST"
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${apiPing.Arn}/invocations
responses:
default:
statusCode: "200"
contentHandling: "CONVERT_TO_TEXT"
passthroughBehavior: "when_no_match"
components:
schemas:
PingRequest:
description: 'a ping request'
type: object
properties:
ping:
description: 'some text'
type: string
PongResponse:
description: 'a pong response'
type: object
properties:
pong:
description: 'some text'
type: string
This template deploys without any errors, however there is no integration attached to the /ping POST route.
The transformed template in CloudFormation does show a loaded swagger file:
"api": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Body": {
"info": {
"version": 1570924800000,
"title": "API"
},
"paths": {
"/ping": {
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PingRequest"
}
}
},
"required": true
},
"x-amazon-apigateway-integration": {
"contentHandling": "CONVERT_TO_TEXT",
"responses": {
"default": {
"statusCode": "200"
}
},
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${apiPing.Arn}/invocations"
},
"httpMethod": "POST",
"passthroughBehavior": "when_no_match",
"type": "aws_proxy"
},
"summary": "invoke ping",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PongResponse"
}
}
},
"description": "Successful"
}
},
"operationId": "apiPing"
}
}
},
"openapi": "3.0.1",
"components": {
"schemas": {
"PingRequest": {
"type": "object",
"description": "a ping request",
"properties": {
"ping": {
"type": "string",
"description": "some text"
}
}
},
"PongResponse": {
"type": "object",
"description": "a pong response",
"properties": {
"pong": {
"type": "string",
"description": "some text"
}
}
}
}
},
"tags": [
{
"name": "httpapi:createdBy",
"x-amazon-apigateway-tag-value": "SAM"
}
]
}
}
}
I'm trying to understand what I may need to change or add to add the integration to the http api. I can't find any clear explanation in the aws documentation.
I have managed to resolve this. aws::serverless::httpapi creates a AWS::ApiGatewayV2::Api resource. This requires a different integration than the previous versioned ApiGateway.
x-amazon-apigateway-integration has a key defined, payloadFormatVersion. Despite documentation suggesting both 1.0 and 2.0 are supported, it seems 2.0 must be used. As such, my x-amazon-apigateway-integration has become the following (I did clean it up a bit):
x-amazon-apigateway-integration:
payloadFormatVersion: "2.0"
httpMethod: "POST"
type: "aws_proxy"
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${apiPing.Arn}/invocations
responses:
default:
statusCode: "200"
connectionType: "INTERNET"
And with this, integration is applied upon deployment.

"How to get username by userID in google assistant action?"

I was connected my chatbot to google assistant action. They give only the userID, how to get username by using this userID?
You can get username without knowing userid, by the permissions document here. You can take a look at this sample code.
Or you can use account linking feature.
Tip! for userID, you can check out this doc
For Python:
There is no official library for developing google action using Python but,
You can add permission intent in possibleIntent array. So your Action SDK JSON will be,
{
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "PLACEHOLDER"
}
}
]
}
},
"possibleIntents": [
{
"intent": "actions.intent.PERMISSION",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"optContext": "To address you by name and know your location",
"permissions": [
"NAME",
"DEVICE_PRECISE_LOCATION"
]
}
}
]
}
],
"conversationToken": "{\"data\":{}}",
"userStorage": "{\"data\":{}}"
}
{`"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "welcome"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns":["talk to Mr Bot"]
}
}
},
{
"description": "Rasa Intent",
"name": "TEXT",
"fulfillment": {
"conversationName": "rasa_intent"
},
"intent": {
"name": "actions.intent.TEXT",
"trigger": {
"queryPatterns":[]
}
}
}],
"conversations": {
"welcome": {
"name": "welcome",
"url": "https://ac752bb0.ngrok.io/webhooks/google_home/webhook",
"fulfillmentApiVersion": 2
},
"rasa_intent": {
"name": "rasa_intent",
"url": "https://ac752bb0.ngrok.io/webhooks/google_home/webhook",
"fulfillmentApiVersion": 2
}
} }
this is my action.json,
class GoogleConnector(InputChannel):
#classmethod
def name(cls):
return "google_home"
#def __init__(self):
# self.out_channel = CustomOutput(url, access_token)
def blueprint(self, on_new_message):
google_webhook = Blueprint('google_webhook', __name__)
#google_webhook.route("/", methods=['GET'])
def health():
return jsonify({"status": "ok"})
#google_webhook.route("/webhook", methods=['POST'])
def receive():
payload = json.loads(request.data)
sender_id = payload['user']['userId']
intent = payload['inputs'][0]['intent']
text = payload['inputs'][0]['rawInputs'][0]['query']
if intent == 'actions.intent.MAIN':
message = "<speak>Hello! <break time=\"1\"/> Welcome to the Rasa-powered Google Assistant skill. You can start by saying hi."
else:
out = CollectingOutputChannel()
on_new_message(UserMessage(text, out, sender_id))
responses = [m["text"] for m in out.messages]
message = responses[0]
r = json.dumps(
{
"conversationToken": "{\"state\":null,\"data\":{}}",
"expectUserResponse": 'true',
"expectedInputs": [
{
"inputPrompt": {
"initialPrompts": [
{
"ssml": message
}
]
},
"possibleIntents": [
{
"intent": "actions.intent.TEXT"
}
]
}
]
})
return r
return google_webhook
this my google connector python code,
how to modified this for account signin

Is it possible to play audio file or stream?

Is it possible to play audio file or stream using actions-on-google-nodejs library?
Using SSML you can return an audio clip up to 120s.
<speak>
<audio src="https://actions.google.com/sounds/v1/animals/cat_purr_close.ogg">
<desc>a cat purring</desc>
PURR (sound didn't load)
</audio>
</speak>
Edit
If you want to play audio the mp3 file (over 120s), you need to use Media Responses
if (!conv.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO')) {
conv.ask('Sorry, this device does not support audio playback.');
return;
}
conv.ask(new MediaObject({
name: 'Jazz in Paris',
url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3',
description: 'A funky Jazz tune',
icon: new Image({
url: 'https://storage.googleapis.com/automotive-media/album_art.jpg',
alt: 'Ocean view',
}),
}));
To add one more point to Nick's answer, you can also build a Media Response which will allow you to play a long audio file (I'm currently playing 50 mins album in my app).
You can find it on Google's doc here.
A short example in Node.js could be:
const richResponse = app.buildRichResponse()
.addSimpleResponse("Here's song one.")
.addMediaResponse(app.buildMediaResponse()
.addMediaObjects([
app.buildMediaObject("Song One", "https://....mp3")
.setDescription("Song One with description and large image.") // Optional
.setImage("https://....jpg", app.Media.ImageType.LARGE)
// Optional. Use app.Media.ImageType.ICON if displaying icon.
])
)
.addSuggestions(["other songs"]);
And then you can just do
app.ask(richResponse)
UPDATE:
As per a comment request, here is the JSON response sent by my app for a mediaResponse:
{
"conversationToken": "[\"_actions_on_google\"]",
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Here is my favorite album."
}
},
{
"mediaResponse": {
"mediaType": "AUDIO",
"mediaObjects": [
{
"name": my_name,
"description": my_descr,
"largeImage": {
"url": my_url
},
"contentUrl": my_contentURL
}
]
}
}
],
"suggestions": [
{
"title": my_suggestion
}
]
}
},
"possibleIntents": [
{
"intent": "assistant.intent.action.TEXT"
}
]
}
],
"responseMetadata": {
"status": {
"message": "Success (200)"
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "0a3c14f8-87ca-47e7-a211-4e0a8968e3c5",
"parameterNames": [
my_param_name
]
}
},
"userStorage": "{\"data\":{}}"
}