How to get the time zone or local time of Alexa device - node.js

I want to get the "time zone" set in the settings or local date time of the Alexa device. Is there any API available for it? Or is there any option to get the date-time of the user using his postal code?
Any help will be highly appreciable?

It is now possible to get a user's timezone and other related data using the Alexa Settings API. Also see the related blogpost for more information on this API release.
The endpoint you'll be interested in is the following:
GET /v2/devices/{deviceId}/settings/System.timeZone
You simply need to provide the user's device ID, which is part of the received intent. The response will contain a timezone name, for instance "Europe/London".

Yes, there is a native Alexa API that you can use. Here is a perfect solution for what you're looking for. What you will need is a device ID and an API access token. Also, few tools like axios ( npm i axios) and zip-to-country-code (npm i zipcode-to-timezone) more info here Enhance Your Skill With Address Information Also, before you implement this code make sure to go to Alexa dev portal and turn on permissions See image below. Cheers!
const apiAccessToken = this.event.context.System.apiAccessToken;
const deviceId = this.event.context.System.device.deviceId;
let countryCode = '';
let postalCode = '';
axios.get(`https://api.amazonalexa.com/v1/devices/${deviceId}/settings/address/countryAndPostalCode`, {
headers: { 'Authorization': `Bearer ${apiAccessToken}` }
})
.then((response) => {
countryCode = response.data.countryCode;
postalCode = response.data.postalCode;
const tz = ziptz.lookup( postalCode );
const currDate = new moment();
const userDatetime = currDate.tz(tz).format('YYYY-MM-DD HH:mm');
console.log('Local Timezone Date/Time::::::: ', userDatetime);
})

If you are using ASK sdk v2. There's a better way to get the timezone.
const getCurrentDate = async (handlerInput) => {
const serviceClientFactory = handlerInput.serviceClientFactory;
const deviceId = handlerInput.requestEnvelope.context.System.device.deviceId;
try {
const upsServiceClient = serviceClientFactory.getUpsServiceClient();
return userTimeZone = await upsServiceClient.getSystemTimeZone(deviceId);
} catch (error) {
if (error.name !== 'ServiceError') {
return handlerInput.responseBuilder.speak("There was a problem connecting to the service.").getResponse();
}
console.log('error', error.message);
}
}

Related

Listing Business Accounts under Google My Business API

I have authenticated against a Google Account and trying to fetch the Businesses on that account using the Google My Business API.
I can't seem to find any samples on how to do that using the Google NodeJS Client Libraries.
Here is what I tried:
async fetchGoogleMyBusinessAccounts() {
console.log(`Fetching GMB Accounts`);
let authCredentials= ...
const oauth2Client = initOAuth2Client(platform, authCredentials);
google.options({ auth: oauth2Client });
let gmbAccountManagement = google.mybusinessaccountmanagement(); //There seems to be an issue on this line
try {
let myBusinessAccounts = await gmbAccountManagement.accounts.list();
console.log(`Connected Accounts = ${JSON.stringify(myBusinessAccounts, null, 2)}`);
} catch (e) {
console.log(`Error Listing GMB Accounts`);
}
}
But the error I keep getting is:
Argument error: Accepts only string or object
I can't seem to figure out how what might be wrong and how best to get about this.
Any insights would be really appreciated.
I think you may be missing the API version:
const mybusinessaccountmanagement = google.mybusinessaccountmanagement('v1');

Access Error while accessing Azure API from NodeJS

I am trying to use Azure News Search in my NodeJS App. The code for the router is here:
const CognitiveServicesCredentials = require('ms-rest-azure').CognitiveServicesCredentials;
let credentials = new CognitiveServicesCredentials('apikey');
let search_term = 'Winter Olympics'
const NewsSearchAPIClient = require('azure-cognitiveservices-newssearch');
let client = new NewsSearchAPIClient(credentials);
client.newsOperations.search(search_term).then((result) => {
console.log(result.value);
}).catch((err) => {
throw err;
});
I get an error:
Access denied due to invalid subscription key or wrong API endpoint. Make sure to provide a valid key for an active subscription and use a correct regional API endpoint for your resource.
I made sure my API key is correct. The code sample is straight from Azure's Quickstart quide. There is no mention of the endpoint there. I feel like I am missing something but can't figure out what.
Thanks in advance for any guidance.
Try this to specify your endpoint :
const CognitiveServicesCredentials = require('ms-rest-azure').CognitiveServicesCredentials;
let credentials = new CognitiveServicesCredentials('<api key>');
let search_term = 'Winter Olympics'
const NewsSearchAPIClient = require('azure-cognitiveservices-newssearch');
let client = new NewsSearchAPIClient(credentials,{"endpoint":"<endpoint url>"});
client.newsOperations.search(search_term,{"count":1}).then((result) => {
console.log(result.value);
}).catch((err) => {
console.log(err);
throw err;
});
Result :
Hope it helps .

Stripe error: You cannot use a PaymentMethod as a source for Customers

I am new to NodeJS, and I am trying to integrate Stripe payments, using Firebase Cloud functions. I Followed these steps:
I got the token from client-side, stored it in Firestore, the token looks like this: pm_1FFhvNDcXKDMgaqV...
I've created a Customer on Stripe
exports.createNewStripeCustomer =
functions.auth.user().onCreate(
async (user) => {
const customer = await stripe.customers.create({email:
user.email}) ;
return admin.firestore()
.collection('customers')
.doc(user.uid)
.set({customer_id: customer.id});
}
);
The above code works.
Now I've tried to add a payment source using the token as specified in tutorials and docs and I keep getting the following error:
Error: You cannot use a payment method as a source for Customers. Instead, use the payment methods API to Attach a Customer to a payment method. See https://stripe.com/docs/api/payment_methods/attach
Here's the code that causes the error:
exports.newPaymentSource = functions.firestore.document('customers/{userId}/tokens/{tokenId}').onWrite(async (change, context) => {
//Get token that strike sdk gave to the client...
const data = change.after.data();
if (data ===null) { return null }
const token = data.tokenId;
const snapshot = await firestore.collection('customers').doc(context.params.userId).get();
const customer = snapshot.data().customer_id;
//calling stripe api...
console.log(customer + ":" + token + ":" + context.params.userId);
const respFromStripe = await stripe.customers.createSource(customer, { source: token });
// console.log(respFromStripe);
return firestore.collection('users').doc(context.params.userId)
.collection('sources').doc(respFromStripe.card.fingerprint).set(respFromStripe, { merge: true });
});
PaymentMethod objects (which represent your user's cards) need to be attached to a Customer with /v1/payment_methods/pm_123/attach endpoint or in Stripe-Node:
pm = await stripe.paymentMethods.attach('pm_678', {customer: 'cus_123'});
https://stripe.com/docs/api/payment_methods/attach?lang=node
The way you're using it (customer.createSource()) works for older Tokens (tok_123) and Source (src_123) objects, not PaymentMethods.

Access Facebook Messenger User Profile API in DialogFlow

I'm building a cross-platform chatbot in Google's DialogFlow. I'd like to access the Facebook User Profile API to learn the user's first name.
I'm struggling to find advice on how (or if) I can make this happen.
https://developers.facebook.com/docs/messenger-platform/identity/user-profile/
Has anybody here achieved this?
I did that for one of my bots yesterday, you need 2 things, first the Page Token and second is the psid which is Page scope user ID.
On dialogflow, you will receive the request block with psid as sender id. You can find it at:
agent.originalRequest.payload.data.sender.id
This psid needs to be passed to api get request at
/$psid?fields=first_name with your page Token as accessToken to get the first name in response.
You need to make a call to Facebook Graph API in order to get user's profile.
Facebook offers some SDKs for this, but their official JavaScript SDK is more intended to be on a web client, not on a server. They mention some 3rd party Node.js libraries on that link. I'm particularly using fbgraph (at the time of writing, it's the only one that seems to be "kind of" maintained).
So, you need a Page Token to make the calls. While developing, you can get one from here:
https://developers.facebook.com/apps/<your app id>/messenger/settings/
Here's some example code:
const { promisify } = require('util');
let graph = require('fbgraph'); // facebook graph library
const fbGraph = {
get: promisify(graph.get)
}
graph.setAccessToken(FACEBOOK_PAGE_TOKEN); // <--- your facebook page token
graph.setVersion("3.2");
// gets profile from facebook
// user must have initiated contact for sender id to be available
// returns: facebook profile object, if any
async function getFacebookProfile(agent) {
let ctx = agent.context.get('generic');
let fbSenderID = ctx ? ctx.parameters.facebook_sender_id : undefined;
let payload;
console.log('FACEBOOK SENDER ID: ' + fbSenderID);
if ( fbSenderID ) {
try { payload = await fbGraph.get(fbSenderID) }
catch (err) { console.warn( err ) }
}
return payload;
}
Notice you don't always have access to the sender id, and in case you do, you don't always have access to the profile. For some fields like email, you need to request special permissions. Regular fields like name and profile picture are usually available if the user is the one who initiates the conversation. More info here.
Hope it helps.
Edit
Promise instead of async:
function getFacebookProfile(agent) {
return new Promise( (resolve, reject) => {
let ctx = agent.context.get('generic');
let fbSenderID = ctx ? ctx.parameters.facebook_sender_id : undefined;
console.log('FACEBOOK SENDER ID: ' + fbSenderID);
fbGraph.get( fbSenderID )
.then( payload => {
console.log('all fine: ' + payload);
resolve( payload );
})
.catch( err => {
console.warn( err );
reject( err );
});
});
}

How to properly get Twitter screenName from firebase auth?

Following these links https://firebase.google.com/docs/auth/web/manage-users#update_a_users_profile and https://firebase.google.com/docs/auth/web/manage-users#get_a_users_provider-specific_profile_information
I was able to authenticate user and log in with their twitter account. However, I want to get the screenName of an user. How will I do that?
I've checked some network request and I see the screenName attribute. I've checked onAuthStateChanged and it returns user attribute but without the screenName.
I needed to do this from Node, however, Google/Firebase Auth does not store a user's Twitter handle (at least it's not accessible through firebase-admin).
However, they do make the Twitter uid accessible as the question points out. With that, you can subsequently call Twitter's API to get a user by their uid and the result will return the handle a.k.a username:
import { TwitterApi } from 'twitter-api-v2';
import { auth } from 'firebase-admin';
const BEARER = process.env['TWITTER_BEARER_TOKEN'] as string;
const logTwitterHandleFromUid = async (googleUid: string): Promise<void> => {
// get Google Auth information associated with the target user
const { providerData } = await auth().getUser(googleUid);
// pull out the Twitter information
const twitter = providerData.find((p) => p.providerId.includes('twitter'));
if (!twitter) {
console.error('User does not have a linked Twitter account')
process.exit(1)
}
const details = await new TwitterApi(BEARER).v2.user(twitter.uid);
// pull out the Twitter handle
const twitter_handle = details.data.username;
return console.log(twitter_handle);
};
See Get a user's profile documentation. The .displayName property should have it.
var user = firebase.auth().currentUser;
var name, email, photoUrl, uid, emailVerified;
if (user != null) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid; // The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
}

Resources