DialogFlow conv.user.id Deprecated - any implications? - node.js

Similar to DialogFlow V2 user id? I am using the user ID from conv.user.id (dialogflow v2) to (anonymously) determine the user in my Dialogflow app. However, I get the log message:
conv.user.id is *DEPRECATED*: Use conv.user.storage to store data instead
Does this mean I will (soon) no longer have access to the user id? I understand I can store data in conv.user.storage, yet I need the id - not the storage.
Anyone thoughts on how to fail-safe this?
// Code snippet:
app.intent('Default Welcome Intent', conv => {
var userID = conv.user.id;
// do something
});

The anonymous user identity has been deprecated and will be officially removed starting 1 June 2019 (a year from now). So your code snippet will start failing then.
The fix depends on exactly how and why you're using the id, but for the most basic needs, you can do something like this:
Check to see if you've stored an id in the userStore. If you have - use this id.
If you haven't, generate an id (generating a UUID is a good method to do this), use this as your id, and store it in the userStore for future reference.
Code to do this might look something like this:
if ('userId' in conv.user.storage) {
userId = conv.user.storage.userId;
} else {
// generateUUID is your function to generate ids.
userId = generateUUID();
conv.user.storage.userId = userId
}
Alternately, you may wish to just plan to use Google Sign-In for the Assistant which will get you the Google UserID.
EDIT:
userId in condition should be quoted.

Related

How to back to start wait new input-text in Dialogflow by using fulfillment?

Hi all,
I have question about control flow in Dialogflow. Is it possible to control Dialogflow in fullfillment?
Below are my Dialogflow Process.
I created 'Intent1' -> wait for user input about 'Document Type' such as 'Document No.1' or 'Document No.2', etc ...
I created 'Intent2' -> It is follow-up intent of 'Intent1'. It get user input (Training Phrases) such as 'Document No.1' or 'Document No.2' or etc. This 'Intent2' has created parameters for get 'Document Type' such as 'No.1' or 'No.2' from user input.
I created fulfillment 'Inline' for 'Intent2' too. After user input 'No.1' or 'No.2' or etc. I check the parameter value with my Firebase Realtime Database. And then return result message to user for waiting next user input by using ...
agent.add("...some phrase...");
I want to know, is it possible to control Dialogflow in fullfillment?
Such as, if I check 'No.3' does not in by Database, may I send message
"It is not in database" and force process back to 'Intent1'.
But if 'No.1' is in my Database, may I send message "Please input time
to get it?" to user and wait user input at 'Intent3' (follow-up intent
of 'Intent2').
I try to search guide for solving but not found.
Thank in advance
Using Firebase to retrieve data
When using firebase to retrieve data for your dialogflow agent, try not to have any ' business logic' in your databases. Instead, query the database, get the results in your application code (for this example Inline fulfillment), and have your logic there (i.e. did the results come back null or non-null, depending on if it exists in the database). Now, let's get back to your problem at stake.
Implementing a solution
First, you should have code that looks like this to set up the connection between Dialogflow and Firebase.
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'ws://project_name.firebaseio.com/'
});
If you have issues with respect to using firebase-admin, you will need greater permission and check out this out.
Next, when your user says a Document Type to the agent, you query the database based on what you extracted from the user. This extraction is stored in a variable you named when you created parameters in the console. You can name this variable anything; I am going to call this extracted parameter userType. The inline fulfillment code is as follows:
function getDoc(agent){
// userType is what the user responded to you
const response = agent.parameters.userType;
return admin.database().ref('data').once('value').then((snapshot) => {
const type = snapshot.child(response).val();// response is variable so no quotes
if(type!== null){
agent.add(`You chose Document type ${type}`);
}
else{
// type == null indicating the type doesn't exist in the database
agent.add('You gave an invalid type');
}
});
}
If the Document Type the user said to agent exists in your database, then the variable above I called type will be some value (not null). If it is null, then what the user asked for is not in the database, and you can prompt a message to user as a follow up such as, "Your input is invalid."
In your example, if the user asked for No. 3 then response would refer to No. 3 and the type would be null. indicative of the fact No. 3 is not is your database.
Resources:
Video by Axle Web Technologies about the workflow and syntax of connecting Dialogflow to Firebase (highly recommended)
Accessing parameters from inside a fulfillment, by GCP Quickstart
Get data using Firebase, from the Firebase Documentation

Stripe: Getting Credit Card's Last 4 Digits

I have upgraded the Stripe.net to the latest version which is 20.3.0 and now I don't seem to find the .Last4 for the credit card. I had the following method:
public void CreateLocalCustomer(Stripe.Customer stipeCustomer)
{
var newCustomer = new Data.Models.Customer
{
Email = stipeCustomer.Email,
StripeCustomerId = stipeCustomer.Id,
CardLast4 = stipeCustomer.Sources.Data[0].Card.Last4
};
_dbService.Add(newCustomer);
_dbService.Save();
}
But now the stipeCustomer.Sources.Data[0].Card.Last4 says 'IPaymentSource' does not contain a definition for 'Card'. Does anyone know how I can get the card details now? The flow is that I create the customer by passing the Stripe token to Stripe, then I get the above stripeCustomer. So I expect it to be somewhere in that object. But I can't find it. The release notes can be found here.
Thank you.
In the old world of Stripe, there only used to be one type of payment method you could attach to a Customer; specifically, Card-objects. You would create a Card-object by using Stripe.js/v2 or the Create Token API Endpoint to first create a Token-object and then attach that token to a Customer-object with the Create Card API Endpoint.
Once Stripe expanded to support a number of other payment methods though, Stripe built support for a new object type that encapsulated a number of payment methods (including credit cards) called Source-objects. A Source-object is created either by using Stripe.js/v3 or the Create Source API Endpoint. It can also be attached to a Customer-object in much the same way as the Card-objects mentioned above, except they retain their object type. They're still a Source. You use the Attach Source API Endpoint to do this (that is notably identical to the Create Card API Endpoint mentioned above).
What I'm getting at here, is there are now two different object types (or more) that you can expect to see returned in the sources-array (or Sources in .NET). All of these methods though inherit from the IPaymentSource-interface. So if you know you have a Card-object getting returned, you can simply cast the returned object to the Card-class.
Something like this should get you going:
CardLast4 = ((Card) stipeCustomer.Sources.Data[0]).Last4
You can see what I mean by inheritance by looking at this line in the Card-class file:
https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Cards/Card.cs#L7
Good luck!
As of Stripe.net.21.4.1, this is what works:
var chargeService = new ChargeService();
var charge = chargeService.Get(id);
CardLast4 = ((Card)charge.Source).Last4;
It's getting hard not to panic when code breaks because of all the micro-changes Stripe makes.
So after debugging, it looks like the Data[0] needs to be cast as Card to get the card.
So it will be CardLast4 = ((Card)stipeCustomer.Sources.Data[0]).Last4.

Srapi - retrieve 1-n property from the Lifecycle call back model parameter

i am using Strapi for a prototype and i am meeting the following issue. I have created a new content type "Checklist" and i added in it a relation property 1 to many with the User model provided by the users-permissions plugin.
Then i wanted to add some custom logic on the lifecycle call back, in beforeSave and in beforeUpdate from which i would like to access the user assigned to the Checklist.
The code looks like that:
{
var self = module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
generateLabel : (model) => {
var label = "";
var day = _moment(model.date,_moment.ISO_8601).year();
var month = _moment(model.date,_moment.ISO_8601).day();
var year = _moment(model.date,_moment.ISO_8601).month();
console.log(model);
if (model.user) {
label = `${model.user}-${year}-${month}-${day}`;
}else{
label = `unassigned-${year}-${month}-${day}`;
}
return label;
I call the method generateLabel from the callback. It works, but my model.user always returned undefined. It is a 1-n property. I can access model.date property (one of the field i have created) without any issue, so i guess the pbs is related to something i have to do to populate the user relation, but i am not sure on how to proceed.
When i log the model object, the console display what i guess is a complete mongoose object but i am not sure where to go from there as if i try to access the property that i see in the console, i will always reach an undefined.
Thanks in advance for your time, i use the following
strapi: 3.0.0-alpha.13.0.1
nodejs: v9.10.1
mongodb: 3.6.3
macos high sierra
Also running into the similar / same issue, I think this has to do with the user permissions plugin, and having to use that to access the User model. Or I thought about trying to find the User that’s associated with the id of the newly created record. I’m trying to use AfterCreate. Anyone that could shed some light on this would be great!
It's because relational attributes are not send in create fonction (See your checklist service add function).
Relations are handled in an other function updateRelations.
The thing you can do is to send values in Checklit.create()

Using the Spotify iOS SDK, how can I tell what market the user is connected to?

Is it possible to tell the country associated with the current user's account with the iOS Spotify SDK? How? I have not been able to find anything in the docs.
(I'd like to get the ISO 3166-1 alpha-2 country code so that another (unauthenticated) user can do searches with the web api and only find tracks that we will ultimately be able to play using the authenticated user that is using the SDK.)
Found it. It is available from the territory field of the SPTUser object. Here is how you might get it after having logged in and received a session object, example code in Swift:
SPTUser.requestCurrentUserWithAccessToken(session.accessToken) { error, object in
guard let user = object as? SPTUser,
territory = user.territory else {
print("Could not get territory, error: \(error)"
return
}
print(territory)
}
However, you will get nil values for the territory unless you have included SPTAuthUserReadPrivateScope in requestedScopes when setting up your SPTAuth object.

How to protect properties for different roles using loopback

I was just wondering how you would restrict property access to the $owner role only. For instance in my case I have a Joke which has an Author. The Author has User as base. I would like other "Authers" / Users to see who created the Joke, but they should not be able to see the Authers email, only if the Author is the $owner of the Joke itself it should be OK to show their email, just for the sake of this case.
Looking at the built-in User model you can see that they use the hidden feature to hide the password, but using that for their email will also hide their email for the $owner, which is not what I wanted
Let me know if something is not clear.
Thanks in advance
Register beforeRemote hook and check if current user is the $owner.
Joke.boforeRemote('findById', function(context, joke, next) {
// 1. find current user by id, using context.req.accessToken.userId
// 2. check if he is owner or not, by Role.isOwner
// 3. remove email from returned joke instance if user is not $owner
})
Note: it can be a bit complicated to cover all endpoints that return Jokes. But is there another way to do it?
To modify the output/results, you can use the afterRemote hook, as per the docs. The output/results are stored in ctx.result.
'findById' hooks into your GET requests when the call is like GET http://myModel/id. Use 'find' if you are not including the id in your request e.g. GET http://myModel. Just notice that in case of 'find', the returned instance(s) (joke(s)) is usually not just one so it is in an array of objects.
Joke.afterRemote('findById', function(ctx, joke, next) {
//your code
});
Get the id of current logged-in user: var currentUser = context.req.accessToken.userId
Compare the user id of the current logged-in user with that of the joke owner. If both are not the same (i.e. if (!(currentUser == joke.userId))), then:
before calling next(), remove the email attribute from returned joke instance. Because sometimes some ways don't work, here are a few:
delete ctx.result.email;
ctx.result.email = '';
loop through the attributes and transferring them to a new var, except the email, then save that new var the result: ctx.result = newVar;
You can create your own role resolver. See https://github.com/strongloop/loopback-example-access-control/blob/master/server/boot/role-resolver.js for an example. Just add your own logic once you determine the user.

Resources