Stripe - storing multiple sources on a user - stripe-payments

I am trying to store multiple sources (cards) on a single user object.
Lets say I have a customer that already has one source stored.
With a new source token I then do the following
stripe.customers.update(customer, {source:call.request.source}, function(err, updatedCustomer){
if(err){
return console.log(err);
}
console.log(updatedCustomer.sources.data);
})
When I do this, the customers existing source is lost and the new one is stored.
How can I store multiple sources on the same customer??

Using createSource rather than update done the trick.
stripe.customers.createSource(customer, {source:call.request.source}, function(err, updatedCustomer){
if(err){
return console.log(err);
}
console.log(updatedCustomer.sources.data);
})

This will work for you.
customer = Stripe::Customer.retrieve(stripe_customer_id)
customer.sources.create(stripeToken)
Stripe token is generated using stripe.js.

Related

How to get Auth0 user.sub in Node.js/Express backend?

I have a simple ToDo app using React frontend, Nodejs/Express API backend, and MySQL DB. My tasks DB has a userId column which pulls the user.sub value on the frontend before sending the task to the backend and creating the DB entry.
Next, I want users to be able to see only their own tasks as identified by the userId column - to do this, I want to pull the user.sub value of the current logged-in user and dynamically insert it into my backend SQL query.
Example:
Task.getAll = (userId, result) => {
let query = `SELECT * FROM tasks WHERE userId LIKE '${userId}'`;
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err);
result(null, err);
return;
}
console.log("tasks: ", res);
result(null, res);
});
};
If I hardcode an existing auth0 user ID (“auth0|123456789…”) into the statement above, it successfully filters tasks based on ID - so the logic seems sound. I just need to be able to pull the user.sub value, which I have not been able to figure out in the backend. I have been following this quickstart document - https://auth0.com/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs:
Determine the User Identity The express-jwt middleware which is used to validate the JWT, also sets the req.user with the information
contained in the JWT. If you want to use the sub claim to identify the
user uniquely, you can simply use req.user.sub.
…This sounds like what I want to achieve, but I can’t figure out how to actually do this in practice. How exactly can I pull the user.sub value from the checkJwt middleware?

Mongoose adding incorrect value in UpdateOne

I'm trying to update a User's discord ID based on their key to link the two. Here is my code:
console.log(user.discordID);
User.updateOne({key: user.key},{discordID: user.discordID}, (err, result) => {
if(err){
console.log(err);
return err;
}
console.log("Updated missing User discord ID");
console.log(result);
console.log(user.discordID);
});
I pass in the user object to the function and have verified the values are correct. The console.logs show the correct value, 660955020694650891, both before and after the update. But in the DB itself after the update the value is 660955020694650900. For the life of me I can't figure out why this is happening and it is derailing other functionality. Any help would be greatly appreciated.
Its probably because the number of the discordID is bigger then the 'Number.MAX_SAFE_INTEGER', which means that javascript can not represent the exact number.
See more information here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
You can solve the problem by using BigInt.
See details here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

passing multiple collections to the same express route

app.get('/dbpage', function(req, res){
Chapters.find({}, function(err, allChapters){
if(err){
console.log(err);
}else{
res.render('dbpage', {chapters: allChapters});
}
});
});
The code above is a small portion of my project, and it's working fine. Chapters is the collection's name which is part of my books database. But I have another collection (from the same database) that I'm trying to pass through the same route /dbpage. How would add this other collection to the code above? So I can access the information stored in this other collection in the /dbpage route.
I've seen some other answers that are more or less suited for what I'm trying to do, but they all seen overkill for such a simple thing. Any suggestions? Thanks!!
You can't invoke the same route name. If you use duplicate route definitions, the one "listed first" will take precedence. The only time the same route definition is allowed is if you utilize a different HTTP verb... such as POST, PUT, PATCH, etc.
Thus, if you truly want to use the same route, you need to pass query params and then push conditional logic in the route, such as:
app.get('/dbpage', function(req, res){
let {someQueryParam} = req.query;
if(someQueryParam === 'someSpecialValue'){
//... do something different...
} else {
Chapters.find({}, function(err, allChapters){
if(err){
console.log(err);
}else{
res.render('dbpage', {chapters: allChapters});
}
}
});
});
And, you'd invoke it with some endpoint such as:
yourDomain.com:3000/dbPage?someQueryParam="someSpecialValue"
Honestly though I'd advise against introducing conditional logic when at all possible. If possible, just set up another endpoint.

Bot Framework Node.js ad hoc message TO A SPECIFIC USER

I have been staring at this for hours and can't find a solution and that is even though by all suggestions it SHOULD be quite easy - https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-proactive-messages.
I have created a simple code which will "register" the user and save their data in my cosmosDatabse on Azure. That works perfectly.
//ON "register" SAVE USER DATA AND SAY REGISTERED MESSAGE
bot.dialog('adhocDialog', function(session, args) {
var savedAddress = session.message.address;
session.userData.savedAddress = savedAddress;
//REGISTERED MESSAGE
session.endDialog("*Congratulations! You are now registered in our network! (goldmedal)*");
})
.triggerAction({
matches: /^register$/i
})
But how can I then access that specific user and send him a message if, say, a condition is met? (in fact on HTTP request)
I am fairly certain we have to write the conversation ID or user ID somewhere. The question is where?
function startProactiveDialog(address) {
bot.beginDialog(address, "A notification!");
}
This is how simple I think it should be. But where do you specify the user then?
You've saved the address of the user inside of your database by saving it to session.userData.savedAddress. When the event triggers, perform a query to your database that checks for the users that meet two criteria.
They're registered to listen for the event
Their address has been saved inside of the database.
In your case, you can save a property to the session.userData object, a property that lists which events they're listening for. If you just need to send a message to the user, then you can simply use bot.loadSession(savedAddress) to ping the user.
Edit:
So instead of looking specifically by user ID, you should send a query to your CosmosDB that looks for entries that have a "listen-to" Boolean-type flag corresponding to the event.
You're not worrying about the user ID at first, you're just retrieving all entries with a query that would (broadly speaking) look like this:
SELECT * FROM BotState WHERE data LIKE 'listenForEvent=1.
So to setup your session.userData so that the above theoretical query would work, you would need to modify that snippet of code in your question to something like the following:
bot.dialog('adhocDialog', function(session, args) {
var savedAddress = session.message.address;
session.userData.savedAddress = savedAddress;
session.userData.listenForEvent = 1 // Our property we're going to look for.
session.endDialog("*Congratulations! You are now registered in our network! (goldmedal)*");
})
.triggerAction({
matches: /^register$/i
})
Actually, the savedAddress should be an instance of IAddress, and also, the function loadSession(address: IAddress, callback: (err: Error, session: Session) => void): void; and address(adr: IAddress): Message; under Message class all require IAddress as the parameter.
So first of all, you should save the entire address json object in cosmosDB for later using.
As botbuilder for Node.js is built on Restify or Express, you can build an addition route for your user to trigger and send proactive messages. The work flow could be following:
Guide user to register & Save the user's address object with the account mapping in your DB
Create a Route in Restify or Expressjs for trigger the proactive message:
server.get('/api/CustomWebApi', (req, res, next) => {
//find the user's address in your DB as `savedAddress`
var msg = new builder.Message().address(savedAddress);
msg.text('Hello, this is a notification');
bot.send(msg);
res.send('triggered');
next();
}
);
or if you want to leverage loadSession
server.get('/api/CustomWebApi', function (req, res, next) {
bot.loadSession(savedAddress, (err, session) => {
if (!err) {
session.send('Hello, this is a notification')
session.endConversation();
}
})
res.send('triggered');
next();
});
I created a users.json file, to which I save all the users. It works the way I need it to. I guess database would be better, but I don't really have a clue where to begin with that. Database is a whole new chapter I have not encountered yet, so it doesn't make sense to work on it when the project needs are resolved.

Storing some small (under 1MB) files with MongoDB in NodeJS WITHOUT GridFS

I run a website that runs on a backend of nodeJS + mongoDB. Right now, I'm implementing a system to store some icons (small image files) that will need to be in the database.
From my understanding, it makes more sense NOT to use GridFS, since that seems to be tailored for either large files or large numbers of files. Since every file that I need to save will be well under the BSON maximum file size, I should be able to save them directly into a regular document.
I have 2 questions:
1) Is my reasoning correct? Is it ok to save image files within a regular mongo collection, as opposed to with GridFS? Is there anything I'm not considering here that I should be?
2) If my thought process is sound, how do I go about doing this? Could I do something like the following:
//assume 'things' is a mongoDB collection created properly using node-mongodb-driver
fs.readFile(pathToIconImage, function(err,image){
things.insert({'image':image}, function(err,doc){
if(err) console.log('you have an error! ' + err);
});
});
I'm guessing that there's probably a better way to do this, since mongoDB uses BSON and here I'm trying to save a file in JSON before I send it off to the database. I also don't know if this code will work (haven't tried it).
UPDATE - New Question
If I have a document within a collection that has three pieces of information saved: 1) a name, 2) a date, and 3) an image file (the above icon), and I want to send this document to a client in order to display all three, would this be possible? If not, I guess I'd need to use GridFS and save the fileID in place of the image itself. Thoughts/suggestions?
Best, and thanks for any responses,Sami
If your images truly are small enough to not be a problem with document size and you don't mind a little amount of extra processing, then it's probably fine to just store it directly in your collection. To do that you'll want to base64 encode the image, then store it using mongo's BinData type. As I understand it, that will then save it as a BSON bit array, not actually store the base64 string, so the size won't grow larger than your original binary image.
It will display in json queries as a base64 string, which you can use to get the binary image back.
I have been looking for the same thing.
I know this post is old , but perhaps i can help someone out there.
var fs = require('fs');
var mongo = require('mongodb').MongoClient;
var Binary = require('mongodb').Binary;
var archivobin = fs.readFileSync("vc.exe");
// print it out so you can check that the file is loaded correctly
console.log("Loading file");
console.log(archivobin);
var invoice = {};
invoice.bin = Binary(archivobin);
console.log("largo de invoice.bin= "+ invoice.bin.length());
// set an ID for the document for easy retrieval
invoice._id = 12345;
mongo.connect('mongodb://localhost:27017/nogrid', function(err, db) {
if(err) console.log(err);
db.collection('invoices').insert(invoice, function(err, doc){
if(err) console.log(err);
// check the inserted document
console.log("Inserting file");
console.log(doc);
db.collection('invoices').findOne({_id : 12345}, function(err, doc){
if (err) {
console.error(err);
}
fs.writeFile('vcout.exe', doc.bin.buffer, function(err){
if (err) throw err;
console.log('Sucessfully saved!');
});
});
});
});

Resources