How to set a DialogFlow session's timezone? - dialogflow-es

When I use a 'date' entity in a Sialogflow intent, I want it to interpret today's date according to a specific timezone.
That time zone might vary between sessions, as my web-client is aware of the user's specific timezone, and can convey this in the request, or when first initiating the session.
Right now, Dialogflow just uses UTC, so if the user is in California, UTC-7 and it is January 1st, 9pm in California, it is 4am on January 2nd in UTC, and so the user saying today is interpreted as January 2nd instead of the desired January 1st.

According to the docs, there's a timezone parameter when sending a query:
POST /query sample
HTTPCURL
curl \
https://api.dialogflow.com/v1/query?v=20150910 \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_CLIENT_ACCESS_TOKEN' \
-d '{
"contexts": [
"shop"
],
"lang": "en",
"query": "I need apples",
"sessionId": "12345",
"timezone": "America/New_York"
}'
So if you know the user's timezone, you only need to send it on every request.
API V2
For an API V2 agent, the timezone can be send in queryParams.timeZone
const sessionClient = new dialogflow.SessionsClient({
keyFilename: '/path/to/google.json'
});
const sessionPath = sessionClient.sessionPath('[PROJECT_ID]', '[SESSION_ID]');
const request = {
session: sessionPath,
queryInput: {
text: {
text: 'query',
languageCode: 'en'
}
},
queryParams: {
timeZone: 'America/New_York'
}
};
sessionClient.detectIntent(request)
.then(res => console.log(res))
.catch(err => console.error(err))

Related

Send message with Google Business Messages using access token

Currently I can send a message with Google Business Messages API from an agent to a user from NodeJS code.
const bmApi = new businessmessages.businessmessages_v1.Businessmessages({});
This requires an auth client for a given service account key/secret.
const auth = new GoogleAuth({
keyFilename: '/home/my-keyfile.json',
scopes: 'https://www.googleapis.com/auth/businessmessages',
});
const authClient = await auth.getClient();
// and logic to send message
However the key/secret is hard-coded at the moment.
But at this point in the flow I have the access token.
And want to use that instead of the .json file.
But it will not accept the access token.
Another approach is to directly call the REST interface.
https://developers.google.com/business-communications/business-messages/guides/how-to/message/send
curl -X POST https://businessmessages.googleapis.com/v1/conversations/__CONVERSATION_ID__/messages \
-H "Content-Type: application/json" \
-H "User-Agent: curl/business-messages" \
-H "$(oauth2l header --json ./service_account_key.json businessmessages)" \
-d "{
'messageId': '$(uuidgen)',
'text': 'Hello world!',
'representative': {
'avatarImage': 'https://developers.google.com/identity/images/g-logo.png',
'displayName': 'Chatbot',
'representativeType': 'BOT'
}
}"
Added a header with token.
access_token: <access-token>
But again no joy.
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
I know this should work as we do it for calls to Google Play Store:
try {
let response = await this.httpClient.post({
url: `${process.env.PLAYSTORE_URL}/${packageName}/reviews/${reviewId}:reply`,
body : {
"replyText" : replyText
},
query: {
access_token: access_token <----
}
});
Any help would be much appreciated.
i think you need to use the variable that match the current CONVERSATION_ID in the url path, with the currently one of each agent message received.
Example:
curl -X POST https://businessmessages.googleapis.com/v1/conversations/$(uuidgen)/messages \
-H "Content-Type: application/json" \
-H "User-Agent: curl/business-messages" \
-H "$(oauth2l header --json ./service_account_key.json businessmessages)" \
-d "{
'messageId': '$(uuidgen)',
'text': 'Hello world!',
'representative': {
'avatarImage': 'https://developers.google.com/identity/images/g-logo.png',
'displayName': 'Chatbot',
'representativeType': 'BOT'
}
}"

I would like to know how to get the email address associated with the linked calendar

The application I'm developing is a google calender api, which does google calendar integration.
I would like to get the email address associated with the linked calendar, but I can't figure out how to do that by looking at the following url.
https://developers.google.com/calendar/api/v3/reference/calendars
Calendars dont have email addresses. They have calendar id's this for example would be a calendar id
v205qep4g260mm7fgq8vtgp18#group.calendar.google.com
It may look like an email address but it is not. You cant send it an email there for it is not an email address.
If you do a calendar.get on the primary calendar
curl \ 'https://www.googleapis.com/calendar/v3/calendars/pramary?key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--compressed
The calendar id of that calendar is actually the email address of the currently authenticated user
{
"kind": "calendar#calendar",
"etag": "\"j32ipQvsbvz0_YlxYi3Ml2Fd7A\"",
"id": "xxxxx#gmail.com",
"summary": "Linda Lawton ",
"description": "test",
"timeZone": "Europe/Copenhagen",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet"
]
}
}
This will however not work with other calendars the one above is my house hold cleaning calendar.
If what you are actually trying to do id get the email address of the owner of the calendar then you should be using acl.list this method will return to you all the rules for the calendar
curl \
'https://www.googleapis.com/calendar/v3/calendars/p4g260mm7fgq8vtgp18%40group.calendar.google.com/acl?key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--compressed
One of those rules is the owners email
{
"kind": "calendar#aclRule",
"etag": "\"00001501683456631000\"",
"id": "user:XXXXX#gmail.com",
"scope": {
"type": "user",
"value": "XXXXX#gmail.com"
},
"role": "owner"
},
I altered the node quickstart a little to show how to use this method
/**
* Lists the next 10 events on the user's primary calendar.
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function listEvents(auth) {
const calendar = google.calendar({version: 'v3', auth});
calendar.acl.list({
calendarId: 'primary',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const rules = res.data.items;
if (rules .length) {
rules .map((rule, i) => {
console.log(`User ${rule.id} with the role ${rule.role}`)
});
} else {
console.log('No upcoming rules found.');
}
});
}
As #DalmTo said Google Calendar is associated with an id not corresponding to an email address, except in the case of your primary calendar.
As an implementation in NodeJS of what #DalmTo has provided on ACL:
async function getCalendarACL(auth) {
// call the service
const calendar = google.calendar({ version: 'v3', auth });
console.log(Object.keys(calendar))
// get all the calendars in the current user
let res = await calendar.calendarList.list({})
let calendars = await res.data.items
for (let calendar_i of calendars) {
let calendar_acl = await calendar.acl.list({ calendarId: calendar_i.id })
let acl_rules = await calendar_acl.data.items
console.log(`Calendar ${calendar_i.id}`)
for (rule of acl_rules) {
console.log(`User ${rule.id} with the role ${rule.role}`)
}
}
}
If you get a group in the scope.typefield you need to use the Directory API, in order to get the emails of the users having access.
const directory = google.admin({version: 'directory_v1', auth});
const usersInGroup = await directory.members.list({groupKey:groupID})
Documentation
Members Resource
Calendar API Reference
NodeJS Calendar API Reference

Paypal "PAYEE_NOT_CONSENTED" Only for REST API?

I am trying to integrating Paypal on my application. This application will allow people to sell tokens between them. So the money doesn't go to me, but to the payees.
I first used smart button directly on my front-end (https://developer.paypal.com/docs/checkout/integrate/). I just had to add a payee field and it worked perfectly fine. 0 bug, no issue.
But now, I want to make the integration on a NodejS back-end, because it is more secure for me.
And despite I am doing exactly the same thing (create order -> capturing order), I am getting this error :
{"name":"NOT_AUTHORIZED","details": [{
"issue":"PAYEE_NOT_CONSENTED","description":"Payee does not have appropriate consent to
allow the API caller to process this type of transaction on their behalf. Your current
setup requires the 'payee' to provide a consent before this transaction can be
processed successfully."
}],
"message": "Authorization failed due to insufficient permissions.",
"debug_id":"300756d694c77","links": [{
"href":"https://developer.paypal.com/docs/api/orders/v2/#error-PAYEE_NOT_CONSENTED",
"rel":"information_link","method":"GET"
}]
}
Why ? Why it has no issue doing this kind of operation with smart button, but I can't do it with the checkout sdk on nodejs and need the payee consent ?
Whats the difference ?
Needing the consent or any kind of operation from the payee is really annoying for me, because I need payee to sell their tokens with the minimal of action to do it.
And I don't see whats the difference between doing it with smart button, or with a back-end.
Btw here is my code :
const paypal = require('#paypal/checkout-server-sdk')
if (process.env.NODE_ENV === "prod") {
APP_SETTINGS = require('src/PRIVATE_APP_SETTINGS.json').prod;
var environment = new paypal.core.LiveEnvironment(APP_SETTINGS.paypal.paypal_client_id, APP_SETTINGS.paypal.paypal_secret);
} else {
APP_SETTINGS = require('src/PRIVATE_APP_SETTINGS.json').dev;
var environment = new paypal.core.SandboxEnvironment(APP_SETTINGS.paypal.paypal_client_id, APP_SETTINGS.paypal.paypal_secret);
}
var client = new paypal.core.PayPalHttpClient(environment);
function createPayment(info)
{
const body = {
intent: 'CAPTURE',
purchase_units: [{
amount:
{
value: info.usdAmount,
currency_code: 'USD'
},
payee: {
email_address: info.paypalEmail
}
}],
}
let request = new paypal.orders.OrdersCreateRequest()
request.requestBody(body)
return client.execute(request).then(res => {
return {res: true, id: res.result.id}
}).catch(err => {
if (err) {
console.error(err.message);
}
return {res: false}
})
}
function executePayment(info)
{
console.log(info)
const request = new paypal.orders.OrdersCaptureRequest(info.orderId)
request.requestBody({})
return client.execute(request).then((result) => {
console.log("Payment suceed")
return {res: true}
}).catch(err => {
if (err) {
console.error(err);
}
return {res: false}
})
}
Oddly, you don't seem to be doing anything wrong. I tested the exact same thing except using a simple curl integration rather than node, and everything worked as expected. Here are the curl requests so you can validate whether it works for you...
#!/bin/bash
access_token=$(curl -s https://api-m.sandbox.paypal.com/v1/oauth2/token \
-H "Accept: application/json" \
-H "Accept-Language: en_US" \
-u "clientid:secret" \
-d "grant_type=client_credentials" | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
echo $access_token
#!/bin/bash
access_token=$(./curl_rest_gettoken);
curl $# -s https://api-m.sandbox.paypal.com/v2/checkout/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $access_token" \
-d '{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "5"
},
"payee": {
"email_address": "......#business.example.com"
}
}
],
"application_context": {
"return_url": "https://www.yahoo.com"
}
}' | python -mjson.tool
#!/bin/bash
access_token=$(./curl_rest_gettoken);
curl -v -s -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/$1/capture \
-H "Content-Type:application/json" \
-H "Authorization: Bearer $access_token" | python -mjson.tool

Discord.js send a webhook

Hi I have been experimenting with webhooks and I'm wondering how do you send a normal message(not embeded) through a webhook with a custom avatar and name
const user = message.mentions.users.first() || client.users.cache.get(args[0]);
let announcement = args.slice(1).join(" ");
if(!announcement) return message.channel.send(`lol say something`)
const wc = new WebhookClient('id', 'token')
const embed = new MessageEmbed()
.setTitle("").setColor('GREEN').setTimestamp().setDescription(announcement)
wc.send({
username : user.username,
avatarURL : user.displayAvatarURL({ dynamic : true }),
embeds : [embed]
})
}
```
If you wish to send Discord webhooks you need to make a POST API request to the webhook url.
For that you can basically use any module you want however in this example I'll use node-fetch. Simply install it in your console
npm install node-fetch
and then require it where you need to use it
const fetch = require('node-fetch');
Now that we have what we need to make it work lets create the API request.
For that we start with the params variable. Here you set all the things that make the webhook look like you want it to look. Note: I also included how to send embeds just in case. If you want to see all options check here.
var params = {
username: "Your name",
avatar_url: "",
content: "Some message you want to send",
embeds: [
{
"title": "Some title",
"color": 15258703,
"thumbnail": {
"url": "",
},
"fields": [
{
"name": "Your fields here",
"value": "Whatever you wish to send",
"inline": true
}
]
}
]
}
Now that we have the params we can create the actual POST request. For that you simply call the fetch function and provide the webhook url.
First you specify the method you want to use. By default the method is GET. Next make sure to set the headers to 'Content-type': 'application/json', otherwise you'll get an error. Lastly include the params from earlier in the body. We use JSON.stringify() here to make it work.
fetch('URL', {
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => {
console.log(res);
})
At the end you have the option to catch any errors you might receive.

Axios Basic Auth with API key Example in Node

There is a curl request like this:
curl -X GET --header 'Accept: application/json' --header 'Authorization: Basic [==APIKEYHERE==]' 'https://apipath.com/path?verbose=true'
I removed the APIKEY and the API path for privacy.
The curl request is working fine, I can't figure out how to convert this into an Axios request since it only needs an API key and not a username and password.
Here is the example I found:
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(function(response) {
console.log(response.data, 'api response');
})
I'm not sure how to get this to work for my case?
The short answer to adding an X-Api-Key to an http request with axios can be summed up with the following example:
const url =
"https://someweirdawssubdomain.execute-api.us-east-9.amazonaws.com/prod/custom-endpoint";
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Add Your Key Here!!!
axios.defaults.headers.common = {
"X-API-Key": "******this_is_a_secret_api_key**********",
};
const smsD = await axios({
method: "post",
url: url,
data: {
message: "Some message to a lonely_server",
},
config,
});
I was stuck for 8 hours trying to figure this out as the errors lined up in the queue, adding the key to the default headers was the only way I could get this to work.
Given the cURL command including --header 'Authorization: Basic [==APIKEYHERE==]', you know that the server wants a header sent using the Basic authentication scheme. That means that your API key is both the username and password joined by a : and encoded with Base64. So, you can decode what the username and password should be by decoding your API key with Base64 and seeing the values joined by the colon.
Consider the spec detailed on MDN: Authorization Header
So if your API key is Ym9iOnBhc3N3b3JkMQ==, and you decode it with Buffer.from("API_KEY", "base64").toString(), you would get the value bob:password1 meaning your username is bob and your password is password1 making your request:
const [username, password] = Buffer.from("YOUR_API_KEY", "base64").toString().split(":");
axios.get('https://apipath.com/path?verbose=true', {}, {
auth: {
username,
password
}
})
.then(function(response) {
console.log(response.data, 'api response');
})
You can define a function like this, then you can pass the token to header after login success.
import axios from "axios";
const setAuthToken = token => {
if (token) {
// Apply to every request
axios.defaults.headers.common["Authorization"] = token;
} else {
// Delete auth header
delete axios.defaults.headers.common["Authorization"];
}
};
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(() => setAuthToken(response.token));

Resources