Error: Stripe: Argument "intent" must be a string, but got: undefined - javascript

I'm trying to integrate the stripe payment gateway to my event application. I'm currently only implementing the server side, and the code below is the attend to the event functionality in the userController.js script, which should, upon clicking on the register to the event button, redirect the user to the checkout page, where the user enters his/her card details. Once the payment is completed, the user should be added to the attendees list and so on. However, I encounter an error that I'm unable to solve. I'm just trying to learn node by learning by doing, so any help would be really appreciated!
Code:
// #desc Register to an event
// #route POST /api/events/attend
// #access Private
const attendToEvent = asyncHandler(async (req, res) => {
const {eventID} = req.body
const paymentSuccessful = false
// Check for event
validEventID = mongoose.Types.ObjectId.isValid({eventID});
const event = await Event.findOne({_id:eventID})
const user = req.user
if (event == null) {
res.status(400)
throw new Error('Invalid Event id.')
}
registered = await User.findOne({attendsTo: event._id})
console.log(`user registered: ${registered}`)
if (registered != null) {
res.status(400)
throw new Error('You are already registered to this event.')
}
var customer = await stripe.customers.create({
name: user.username,
email: user.email,
source: req.body.stripeToken
})
const paymentMethods = await stripe.paymentMethods.list({
customer: customer.id,
type: 'card',
});
//Get create customer on stripe and get the payment
stripe.paymentIntents.create({
amount:1000,
currency: 'usd',
customer: customer.id,
payment_method: paymentMethods.id
}).then(function(confirm) {
return stripe.paymentIntents.confirm(
paymentMethods.id,
{payment_method: 'pm_card_visa'}
)
}).then(function(result) {
if (result.error) {
return console.log('Payment unsuccessful')
} else {
paymentSuccessful = true
return paymentSuccessful
}
})
if (!registered && paymentSuccessful) {
User.findOneAndUpdate(
{ _id: user._id },
{ $push: { attendsTo: event._id } },
function (error, success) {
if (error) {
console.log(error);
} else {
console.log(success);
}
});
Event.findOneAndUpdate(
{_id: event._id},
{$push: {attendees: user._id}},
function (error, success) {
if (error) {
console.log(error);
}
else {
console.log(success);
}
}
);
//res.render("../completed.html")
res.status(201).send(`Successfully registered to event: ${event.eventname}`)
}
})
Error:
Error: Stripe: Argument "intent" must be a string, but got: undefined (on API request to `POST /payment_intents/{intent}/confirm`)

In your PaymentIntent confirmation call, you are incorrectly passing in a PaymentMethod Id instead of a PaymentIntent Id
}).then(function(confirm) {
return stripe.paymentIntents.confirm(
paymentMethods.id, // <--- Here
{payment_method: 'pm_card_visa'}
)
})
Look at Stripe's Doc, you will see the Id should be in format of pi_xxx, which is a Payment Intent Id format. In this case it should be confirm.id.

Related

How to make a post request by SERVER not by user

Node.js CODE
exports.user = async (req, res) => {
try {
const { wallet } = req.body;
if (!wallet) {
res.status(400).json({ error: "Not logged in" });
return;
} else {
user = User.findone(wallet);
// if user is not found then create a new user and mark as loggged In
if (!user) {
User.create({
user: wallet,
});
}
// if user found then create a session token and mark as logged
in
res.send({
user: wallet,
});
}
} catch (error) {
console.log(`ERROR::`, error);
}
};
REACTJs CODE
// post call/update
const axiosCall = async () => {
// core login will give a unique username by fulling a transcation
// core.login i dont have any control
const userAccount = await core.login();
try {
const res = await Axios.post(`${API}/user`, userAccount, dataToken);
setData({
...data,
error: "",
success: res.data.message,
});
} catch (error) {
setData({
...data,
error: error.response.data.error,
});
}
};
Now here the problem occurs when some one could modify userAccount in the front-end or someone could send a body with wallet: anything to my route localhost:3000/api/user
There is no option for me to check if some actually used core.login(); to get the wallet address.
So is there any solution?
I was thinking to allow only my server IP or localhost to hit the route localhost:3000/api/user and is that even possible?
Also there is another issue anyone could modify userAccount in front-end.

Issue with Stripe Payment Sheet using firebase, cloud functions and stripe. "Unexpected Character (at line 2, character 1) <html><head>

As the title suggests, I am trying to implement Stripe into my flutter app using the stripe extension for Firebase and using Javascript Firebase Cloud Functions for the server side. I believe the issue is on the server side when I try to create a customer and create a payment intent.
The server side code is here:
const functions = require("firebase-functions");
const stripe = require("stripe")("my test secret key"); // this works fine for the other stripe functions I am calling
exports.stripePaymentIntentRequest = functions.https.onRequest(
async (req, res) => {
const {email, amount} = req.body;
try {
let customerId;
// Gets the customer who's email id matches the one sent by the client
const customerList = await stripe.customers.list({
email: email,
limit: 1,
});
// Checks the if the customer exists, if not creates a new customer
if (customerList.data.length !== 0) {
customerId = customerList.data[0].id;
} else {
const customer = await stripe.customers.create({
email: email,
});
customerId = customer.data.id;
}
// Creates a temporary secret key linked with the customer
const ephemeralKey = await stripe.ephemeralKeys.create(
{customer: customerId},
{apiVersion: "2022-11-15"},
);
// Creates a new payment intent with amount passed in from the client
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(amount),
currency: "gbp",
customer: customerId,
});
res.status(200).send({
paymentIntent: paymentIntent.client_secret,
ephemeralKey: ephemeralKey.secret,
customer: customerId,
success: true,
});
} catch (error) {
res.status(404).send({success: false, error: error.message});
}
},
);
Then my client-side code is:
try {
// 1. create payment intent on the server
final response = await http.post(
Uri.parse(
'https://us-central1-clublink-1.cloudfunctions.net/stripePaymentIntentRequest'),
headers: {"Content-Type": "application/json"},
body: json.encode({
'email': email,
'amount': amount.toString(),
}),
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['error'] != null) {
throw Exception(jsonResponse['error']);
}
log(jsonResponse.toString());
//2. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonResponse['paymentIntent'],
merchantDisplayName: 'Clublink UK',
customerId: jsonResponse['customer'],
customerEphemeralKeySecret: jsonResponse['ephemeralKey'],
style: ThemeMode.dark,
),
);
await Stripe.instance.presentPaymentSheet();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment completed!')),
);
} catch (e) {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage}'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
}
I basically copied the flutter_stripe documentation to create the payment sheet with the necessary changes. Any help would be greatly appreciated!
Ok so I found what worked! I was being given a 403 status error with reason "forbidden". This meant I had to go to the google cloud console and update the permissions in the cloud functions tab.

Update a record in database after delete with Sequelize Model and NodeJS

i created a controller that can delete but it is difference because it is not only delete records according ID, it also update the record after the API of delete is call.
Let me demonstrate my code below:
// delete user
exports.delete = (req, res) => {
const user_id = req.params.user_id;
// Find record by it is id to DELETE
User.findByPk(user_id).then((num) => {
if (num == 1) {
res.status(200).send({
message: "User was deleted successfully!",
data: null,
});
} else {
res.status(500).send({
message: `Cannot delete User with id=${user_id}. Maybe User was not found!`,
data: null,
});
}
});
//After delete must update the is_active field
User.update(
{
is_active: 0,
},
{
where: { is_active: null },
}
);
};
Now i have problem that i do not know how to make my API to work. So, i hope someone can help me to deal with this problem that how to update is_active MUST BE 0 after DELETE. I am appreciate it.
You just need to use async/await instead of then to wait for then result of findByPk before calling update:
exports.delete = async (req, res) => {
const user_id = req.params.user_id;
// Find record by it is id to DELETE
const user = await User.findByPk(user_id)
if (user) {
//After delete must update the is_active field
await User.update(
{
is_active: 0,
},
{
where: { is_active: null },
}
);
res.status(200).send({
message: "User was deleted successfully!",
data: null,
});
} else {
res.status(500).send({
message: `Cannot delete User with id=${user_id}. Maybe User was not found!`,
data: null,
});
}
};
This way you have a straight forward code like you usually write when it's synchronous.

Why am I not getting the appropriate error messages displayed upon (network) request?

I'm trying to work out how to receive helpful error messages on the client side, but keep getting generic error messages. For example, trying to sign up with an email that is not available should result in the email#email.com is already in use error message. I, however, get the generic Request failed with status code 409 message, which is obviously unhelpful to the user. The network response is as expected as seen in the screenshot below. What gives? Why am I not getting the same error message as my (Redux) payload?
Below are the relevant code snippets.
Sign up controller
export default {
signup: async (req, res, next) => {
try {
const { fullname, username, email, password } = req.body;
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return res.status(409).send({ error: `${email} is already in use` });
}
const newUser = await User.create({
fullname,
username,
email,
password,
});
// Assign token to succesfully registered user
const token = authToken(newUser);
return res.status(200).send({ token, user: newUser });
} catch (error) {
next(error);
}
},
};
Sign up action
export const createAccount = ({
fullname,
username,
email,
password,
history
}) => async dispatch => {
dispatch({
type: actionTypes.CREATE_ACCOUNT_REQUEST,
});
try {
const {
data: {
newUser: { token, user },
},
} = await request.post('/auth/signup', {
fullname,
username,
email,
password,
});
localStorage.setItem('auth-token', token);
dispatch({
type: actionTypes.CREATE_ACCOUNT_SUCCESS,
payload: user
});
// Redirect to home
history.push('/home');
} catch (error) {
dispatch({
type: actionTypes.CREATE_ACCOUNT_FAILURE,
payload: error.message
});
}
};
Sign up network response
Redux sign up error payload
Try 'error.response.data.error' instead of 'error.message'

How To Use Variables Down A Promise Chain

I am using nodejs with express framework and mongodb/mongoose to store my data.
I have a register function which does 4 things. Creates a user, creates a token, assigns the token to the user and finally sends an email.
I initially did this using callbacks which worked fine. Im trying to use promises now i have required bluebird to do this. However when one promise is complete i need to use that returned variable in the next promise.
Register Function
module.exports.register = function(req, res) {
var input = req.body;
var newUser = new User ({
username: input.username,
email: input.email,
password: input.password,
active: false
});
var promise = newUser.save();
promise.then(function(user) {
return createToken('new', null, user._id);
}).then(function(token) {
user.tokens.push(token._id);
return user.save();
}).then(function(user) {
//Do Email Stuff
}).catch(function(err) {
return res.json("Could Not Register");
});
}
Create Token Function
var createToken = function(type, expiry, userid) {
var token = uuid.v4();
return new Promise(function(resolve, reject) {
var newToken = Token({
type:type,
token: token,
expiry: expiry,
user: userid
});
var promise = newToken.save();
promise.then(function(token) {
resolve(token);
}).catch(function(err) {
reject(err);
});
});
};
So where im doing "user.tokens.push" it can't find the user. ive read in bluebird that i can use somethign called binding? and then use "this". Could anyone show me how to do this properly.
Also if there is an an error in each promise i'd like the catch method to be dynamic. Instead of just "Could not register" it would be "Could Not Save User" or "Could Not Save Token" depending on which promise failed.
And if theres a way to make this even cleaner let me know.
there's no shame in using a var in the scope of the register function to store the value of user for later use
module.exports.register = function(req, res) {
var input = req.body;
var newUser = new User ({
username: input.username,
email: input.email,
password: input.password,
active: false
});
var sUser; // store user in this var
newUser.save()
.then(function(user) {
sUser = user; // save value user to use later on
return createToken('new', null, user._id);
}).then(function(token) {
sUser.tokens.push(token._id); // sUser is user, huzzah
return sUser.save();
}).then(function(user) {
//Do Email Stuff
}).catch(function(err) {
// use the content of err to return a meaningful error
return res.json("something more meaningful based on the content of err");
});
}
You should also avoid the new Promise antipattern in createToken
var createToken = function(type, expiry, userid) {
var token = uuid.v4();
var newToken = Token({
type:type,
token: token,
expiry: expiry,
user: userid
});
return newToken.save();
};
That produces an identical result to your code
another way would be to send user to the createToken function and rewrite your code like this
module.exports.register = function(req, res) {
var input = req.body;
var newUser = new User ({
username: input.username,
email: input.email,
password: input.password,
active: false
});
newUser.save()
.then(function(user) {
return createToken('new', null, user);
}, function(err) { // optionally change errors to meaningful error messages
throw "newUser.save failed";
}).then(function(user) {
//Do Email Stuff
// you could throw "email failed" if there's an error
}).catch(function(err) {
// err could be "newUser.save failed", "newToken.save failed", "email failed"
// use the content of err to return a meaningful error
return res.json("something more meaningful based on the content of err");
});
}
var createToken = function(type, expiry, user) {
var token = uuid.v4();
var newToken = Token({
type:type,
token: token,
expiry: expiry,
user: user._id
});
return newToken.save()
.then(function(token) {
user.tokens.push(token._id);
return user.save();
}) // you could add the following to make the errors suited to you
.catch(function(err) {
throw "newToken.save failed";
});
};

Categories