Amazon product advertising API always returning undefined as result - amazon-product-api

I am trying to use amazon product advertising API lookup product details for products in my DB. However, the response is always undefined. Am I doing anything wrong ?
var amazon = require('amazon-product-api');
var client = amazon.createClient({
awsId: "my aws id",
awsSecret: "my secret key",
awsTag: "my aws tag"
});
client.itemLookup({
responseGroup: 'Images,ItemAttributes,Offers,EditorialReview',
IdType: 'ASIN',
ItemId: "B00UTKTX36"
}).then(function (results){
console.log("results", results);
}).catch(function(err){
console.log(err.Error[0].Message);
});

Two things -
1. B00UTKTX36 is not a valid ASIN anymore (atleast as of now) http://www.amazon.com/dp/B00UTKTX36
2. ItemLookup operation on ASINs should not contain SearchIndex parameter. So comment this line https://github.com/t3chnoboy/amazon-product-api/blob/master/lib/utils.js#L57 in your node_modules/amazon-product-api/lib/utils.js and you are good to go.

Related

How can I get UserPool details by IdentityPool/UserPool id (sub)

Is there a way to get user details (profile attributes etc) if I have IdentityPool or UserPool ID (sub) of a user with AWS SDK?
The use case is that I'm saving some information submitted by a user in a DB with a key equal to user ID (sub). So, when I'm reading it from the DB, I want to restore back some user info from my pool for my app UI.
I found a similar question (Getting cognito user pool username from cognito identity pool identityId), but it seems, the answer given is focused around serverless deployment, and still has some gaps.
Thanks in advance
Since you have the user's sub, you can use AdminGetUser. It returns the UserAttributes in the pool.
I think I found a solution, it was on the surface actually.
Having user pool id one can use ListUsers call with filter sub = \"${userId}\". The client to be used is CognitoIdentityProviderClient, if JS is used.
const client = new CognitoIdentityProviderClient({
region: REGION,
credentials: fromCognitoIdentityPool({
client: new CognitoIdentityClient({ region: REGION }),
logins: {
[PROVIDER_ID]: token
},
identityPoolId: ID_POOL_ID
})
});
const filter = `sub = \"${userPoolId}\"`;
const resp = await client.send(new ListUsersCommand({
UserPoolId: USER_POOL_ID,
Filter: filter,
Limit: 1
}));
Of course AdminGetUser can be used as well, as Ulas Keles mentioned above, if it's applicable

Using Identity Server 4 with OIDC External Provider is not mapping the claims

I'm using Identity Server 4. I have an external identity provider that I want to get the claims from the id token. In the documentation, http://docs.identityserver.io/en/latest/topics/signin_external_providers.html, it says that all the claims will be available. When I sign in only a few claims are shown in the Home/secure page. If I goto the Diagnostics page and look at the Id Token, they are there. I would like to include some of the claims in the id token and access token that the service is returning. I have created a Profile service thinking that I could add them there, but the same claims that show in the home/secure page are the only ones available:
Here is my external config in start up:
services.AddAuthentication()
.AddOpenIdConnect("external", "external", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.Authority = "https://external idp address.com";
options.ClientId = "secret";
options.Scope.Clear();
options.Scope.Add("openid profile");
options.SaveTokens = true;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
};
options.ClaimActions.MapAll();
});

Sailsjs MVC map params from external API to multiple models

I need to create a database of shopify orders so I can run advanced queries and sales reports that you can't do in the shopify admin area. I'm building in Sails .12 and mysql. Shopify lets you register a webhook so that every time an order is placed, it creates a POST to the specified URL with the order data in the body as JSON. The products ordered are an array of JSON objects as one of the values in the POST:
{
"id": 123456,
"email": "jon#doe.ca",
"created_at": "2017-01-10T14:26:25-05:00",
...//many more entires
"line_items": [
{
"id": 24361829895,
"variant_id": 12345,
"title": "T-Shirt",
"quantity": 1,
"price": "140.00",
},
{
"id": 44361829895,
"variant_id": 42345,
"title": "Hat",
"quantity": 1,
"price": "40.00",
},
]
}
I need to save the order into an Orders table, and the products ordered into a line_items table that is a one to many relation; one order can have many line_items (products ordered). There are over 100 key-value pairs sent by the webhook, and I'm saving all of it. I've created my two models where I define the data type, so now i have very long Order.js and Line_item.js files, and I'm using the
line_items: {
collection: 'line_item',
via: 'order_id'
},
in my Order.js, and
order_id: {
model: 'order'
},
in my Line_item.js models to relate them. Is this the correct way to denfine my two tables? Also, where would I put the code that maps the JSON to the model parameters? If I put that code in the controllers, would I have to type another 100+ lines of code to map each json value to its correct parameter. The how would I save to the two different models/tables? Eg:
var newOrder = {};
newOrder.id =req.param('id');
newOrder.email = req.param('email');
newOrder.name = req.param('name');
...//over 100 lines more, then Order.create(newOrder, ...)
var newLine_items = req.params('line_items'); //an array
_.forEach(newLine_items, function(line_item){
var newLine_item = {};
newLine_item.id = line_item.id;
newLine_item.order_id = newOrder.id;
newLine_item.title = line_item.title;
//etc for over 20 more lines, then Line_item.create(newLine_item, ...)
});
I need to save the order into an Orders table, and the products ordered into a line_items table that is a one to many relation; one order can have many line_items (products ordered).
That sounds completely reasonable, well, besides the use of the Oxford comma :)
There are over 100 key-value pairs sent by the webhook
I'm not sure that I understand exactly what this is or what it is used for within this process.
That being said, it might help to have a single attribute in your model for this which has a JSON value, then retrieve and work with it as JSON instead of trying to manually account for each attribute if that is what you're doing over there?
It really depends on your use case and how you'll use the data though but I figure if the format changes you might have a problem, not so if it's just being stored and parsed as a JSON object?
Also, where would I put the code that maps the JSON to the model parameters
In v0.12.x take a look at Services.
In v1, Services will still work but moving this logic into Helpers might be a good option but then, it seems that a custom model method would be a better one.
Here is a shorter version of your code:
var newOrder = req.allParams();
newLine_items = {};
_.forEach(newOrder.line_items, function(line_item) {
newLine_items.push(line_item);
});
Here is what your logic might look like:
var newOrder = req.allParams();
// Store the order
Order
.create(newOrders)
.exec(function (err, result) {
if (err) // handle the error
var newLine_items = {};
_.forEach(newOrder.line_items, function(line_item) {
// Add the order id for association
line_item.order_id = result.id;
// Add the new line item with the orders id
newLine_items.push(line_item);
});
// Store the orders line items
LineItems
.create(newLine_items)
.exec(function (err, result) {
if (err) // handle the error
// Handle success
});
});
And the lifecycle callback in the Order model:
beforeCreate: function (values, cb) {
delete(values.line_items);
cb();
}
But you really should look into bluebird promises as the model methods in version one of sails have opt in support for them and it helps to negate the pyramid of doom that is starting in my example and is also something that you want to avoid :P

Retrieve MySQL insert id in Meteor method

I am relatively new to Node and Meteor and am trying to retrieve the insert ID of a MySQL query using the numtal:mysql package. The trouble I run into is the query function running on the server and not returning to the client. I need the ID to return to the client so I can route the client to the newly created entry.
Client:
Template.new.events({
'click .button.submit' : function(){
Meteor.call('demoFunc', function(error, result){
console.log(result);
});
},
});
Server:
Meteor.methods({
demoFunc:function(){
//construct deal object
var newDeal = {
dealer_id : 1,
client_id : 1
};
//deal query
liveDb.db.query('INSERT INTO deal SET ?', newDeal, function(err, result){
return result.returnId;
});
}
});
If I could get the result.returnId in the demoFunc method to return to the client then I would be golden. If anyone's run into anything like this or worked around this, any help would be greatly appreciated.
The best place to ask that is at https://github.com/numtel/meteor-mysql/issues
This is a community packages and I highly recommend not to use it in production, only for learning/fun. You can also contribute to this repo by adding that feature that you want.
It is expect that Meteor will support MySQL soon. Meteor bought Fatomdb: http://techcrunch.com/2014/10/07/meteor-acquires-yc-alum-fathomdb-for-its-web-development-platform/
I've had the same issue and solved the problem with this package usefulio:sync-methods. You can see how the package works in Github.
This package automatically adds a callback function to every syncMethod defined in server side. So, you can just call this callback function from inside the server method, after the async results have been processed.
So, the steps are:
1) Install the package: meteor add usefulio:sync-methods
2) Declare your method as a syncMethod like this:
Meteor.syncMethods({
demoFunc:function(callback){
//construct deal object
var newDeal = { dealer_id : 1, client_id : 1 };
//deal query
liveDb.db.query('INSERT INTO deal SET ?', newDeal, function(err, result){
callback(undefined, result.returnId);
});
}
});
3) On the client side, you just call the method in the Meteor way:
Meteor.call('demoFunc', function(err, result){
...
});

Update user with Admin SDK

I am trying to update some user data via the admin SDK. I thought this would work
function directoryUpdate(userId, userDept, userLocation, userPhone, userTitle) {
var update = {
organizations:
{
name: "Next Step Living",
title: userTitle,
primary: true,
type: "work",
department: userDept,
location: userLocation
},
phones:
{
value: userPhone,
type: "work",
primary: true,
}
};
update = AdminDirectory.Users.update(update, userId);
Logger.log('User %s updated with result %s.', userId, update)
return true;
}
but it is not updating the organization or phone data on the record. It also does not throw any kind of error.
three questions, what is the proper syntax to do this update, I assume this works like the API update and behaves like an upsert, is that true, and what is the best practice for capturing any errors during the update. I would like to return a false when the update fails and capture that info. Thanks in advance for your help.
Thanks for your question!
This "inspired" me to work out how the update API worked, as I had got as far as retrieving a User object, updating the properties but had not worked out how to persist the data back to Google.
So, here's my prototype code, which appears to work (the objective being to reset the user's password based on entries in a spreadsheet).
It doesn't seem the most elegant code to me, being that there are two round-trips to the Admin API, and we have to post the email address twice, but I guess that is a side-effect of the JSON API.
var emailAddress = userListSheet.getRange(row, 1).getValue();
var password = userListSheet.getRange(row, 2).getValue();
Logger.log('Email: %s, Password: %s', emailAddress, password);
// Reset user's password
var user = AdminDirectory.Users.get(emailAddress);
user.password = password;
if (changePasswordAtNextLogin == 'Yes') {
user.changePasswordAtNextLogin = true;
}
AdminDirectory.Users.update(user, emailAddress);
Figured out the syntax issue. You do need a set of [] around the name value pairs under organization and phones. organizations:[{....}], phones:[{...}]}; and no, at the end of primary: true under phones. Also changed it from an update to a patch but not sure if that was really required;
update = AdminDirectory.Users.patch(update, userId);
And Yes, it did behave like an upsert and modified existing data and added new data just like the API.
Still need to figure out the best way to capture any errors though so if you have any suggestions please post them.
Looks like supplying an invalid email address is a fatal error that can not be caught and dealt with in code. What I did was get all the primary emails out of Google, store them in an array, and validate that the email I was using was in that list prior to running the update. Since everything else is just a string or logical replacement it should not throw any errors so I am confident that the script will not fail. Now all I have to worry about is the time limit.