product image not showing up when using stripe checkout in my nodejs application - node.js

Below is the code for my checkout route.
Everything works except for one line: images: [`${process.env.SERVER_URL}/public${item.itemData.images[0]}`]
I tried to console log this path and got the correct one: "http://localhost:5000/public/image/test_image_2.webp" Therefore, I am confused as to why this doesnt work. I am pretty sure the images feild takes an array of image paths for each product, and that is what I have given it, but still I am seeing the little cant find image symbole instead of my product image. What do I do?
const router = require("express").Router();
const Product = require("../models/product-schema");
const { default: Stripe } = require("stripe");
const { getUser, authUser, authAdmin, authAdmin404 } = require("../middleware/authentication");
const stripe = require("stripe")(process.env.STRIPE_PRIVATE_KEY);
router.post("/create-checkout-session", authUser, async (req, res) => {
try {
const unresolved = req.body.items.map(async (item, index, arr) => {
const storeItem = await Product.findById(item.id);
return arr[index] = { itemData: storeItem, quantity: item.quantity };
});
const items = await Promise.all(unresolved);
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items: items.map((item) => {
return {
price_data: {
currency: 'eur',
product_data: {
name: item.itemData.product_name,
images: [`${process.env.SERVER_URL}/public${item.itemData.images[0]}`]
},
unit_amount: item.itemData.price_in_cents,
},
quantity: item.quantity,
}
}),
success_url: `${process.env.SERVER_URL}/`,
cancel_url: req.body.url,
});
res.json({ url: session.url });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
module.exports = router;

Stripe will download each image at the URL(s) you provide and cache them locally. When you give a URL that is based on localhost though it has no way to access the data so it just can't cache it and display it later.
You need to make sure that the URL you provide is publicly accessible for them to cache it. It's also possible for your server to be mis-configured (bad TLS certificate for example) causing the attempt to fetch the image to fail and so Stripe will just not render it in that case.

Related

ERROR: Module not found: Can't resolve 'dns'

I am building an application in React. My problem is that if I navigate to the route '/factura/api/invoices/${invoiceId}' and press the edit button, it should send the information to the MongoDB database and return that everything is fine, but when I do it, I get the following error.
./node_modules/mongodb/lib/cmap/auth/gssapi.js:4:0
Module not found: Can't resolve 'dns'
Import trace for requested module:
./node_modules/mongodb/lib/index.js
./pages/facturas/api/edit/[invoiceId]/index.js
https://nextjs.org/docs/messages/module-not-found
I am not sure why I am receiving this error. This is my first part of the code located in the '/facturas/edit/[invoiceId]' folder:
const updateInvoice = async (invoiceId, status) => {
try {
const res = await fetch(`/facturas/api/edit/${invoiceId}`, {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
senderStreet: senderStreet,
senderCity: senderCity,
senderPostalCode: senderPostalCode,
senderCountry: senderCountry,
clientName: clientName,
clientEmail: clientEmail,
clientStreet: clientStreet,
clientCity: clientCity,
clientPostalCode: clientPostalCode,
clientCountry: clientCountry,
description: description,
createdAt: createdAt,
paymentDue: createdAt,
paymentTerms: paymentTerms,
status: status,
items: items,
total: totalAmount
})
})
const data = await res.json()
router.push(`/facturas/invoices/${invoiceId}`)
toast.success(data.message)
} catch (error) {
toast.error("Something is wrong")
console.log(error)
}
}
And this is the second part of the code in the file located in the API folder:
import { MongoClient, ObjectId } from "mongodb";
async function handler(req, res) {
const { invoiceId } = req.query;
const client = await MongoClient.connect('mongodb+srv://test:test#cluster0.uusfifl.mongodb.net/invoices?retryWrites=true&w=majority', { useNewUrlParser: true });
const db = client.db();
const collection = db.collection("allInvoices");
if (req.method === "PUT") {
await collection.updateOne(
{
_id: ObjectId(invoiceId),
},
{
$set: {
senderAddress: {
street: req.body.senderStreet,
city: req.body.senderCity,
postalCode: req.body.senderPostalCode,
country: req.body.senderCountry,
},
clientName: req.body.clientName,
clientEmail: req.body.clientEmail,
clientAddress: {
street: req.body.clientStreet,
city: req.body.clientCity,
postalCode: req.body.clientPostalCode,
country: req.body.clientCountry,
},
createdAt: req.body.createdAt,
paymentDue: req.body.createdAt,
paymentTerms: req.body.paymentTerms,
description: req.body.description,
status: req.body.status,
items: req.body.items,
total: req.body.total,
},
}
);
res.status(200).json({ message: "Invoice updated successfully" });
}
client.close();
}
export default handler;
And here are all the files that I have used, in case you want to see them:
https://github.com/Fukene/tarea_database
Thanks.
I tried to reinstall MongoDB again. I checked that the routes were correct and verified that the MongoDB credentials information were correct. And everything seems to be fine. I still don't know what the problem is.
The confusing thing is that it was working well until I changed the files in folders. I suppose the problem is that the route to some file is wrong, but I haven't found where the problem is.
Edit
I found some posts that say I should move my folders to be directly in the /pages folder, and when I do that my code works perfectly. Why? It's a novice question, but I don't understand how to differentiate what is acting as frontend and what as backend.

Invalid Request Error trying to integrate stripe payments into my website

This is the code from the checkout.js file:
const stripe = require('stripe')(process.env.STRIPE_SECRET_kEY);
const { productList } = require('../products');
exports.checkoutCtrlFunction = async (req, res) => {
try {
const productsFromFrontend = req.body.products;
console.log(productList);
function productsToBuy() {
let products = [];
productList.forEach( singleProductList => {
productsFromFrontend.forEach(singleProductFrontend => {
if(singleProductList.tag === singleProductFrontend.tag) {
products.push({
name: singleProductList.name,
description: singleProductList.description,
images: [singleProductList.image],
amount: singleProductList.price * 100,
currency: 'usd',
quantity: singleProductFrontend.inCart
})
}
})
})
return products
}
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
success_url: `${req.protocol}://${req.get('host')}/checkout/success`,
cancel_url: `${req.protocol}://${req.get('host')}/cart`,
shipping_address_collection: {
allowed_countries: ['US', 'GB']
},
line_items: productsToBuy()
});
res.status(200).json({
status: "success",
session: session
})
} catch (error) {
console.log(error);
}
}
The error is:
You cannot use line_items.amount, line_items.currency, line_items.name, line_items.description, or line_items.images in this API version. Please use line_items.price or line_items.price_data.
Don't understand why I keep getting this error I think i provided the necessary information, I assume something isn't formatted correctly, but im not sure what.
I suspect your Stripe account is on the latest version of the Stripe API (2022-08-01), and this code was used and/or written by someone who was on an earlier version.
The latest version of the Stripe API removed the parameters line_items.amount, line_items.currency, etc. This is listed as one of the breaking changes with version 2022-08-01: https://stripe.com/docs/upgrades#2022-08-01
Here's the API reference for creating Checkout Sessions using line_items.price and line_items.price_data: https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items.
If you'd like to test this code as is, you can specify an older Stripe version with the apiVersion option: https://stripe.com/docs/api/versioning?lang=node

Need help to store variant data in shopify using "Shopify API Node.js"

Hi recently I am working with reactjs & nodejs project and developing a new dashboard module like this.
ERROR SCREEN-SHOT
now i want to add a product to Shopify but i will send data using API for variant but by default, it saves default Shopify data like this.
[enter image description here][2]
And here is my codeĀ 
Main Function On Submit click
const productAddEditSubmit = () => {
var productObject = {
name: fullProductData.name,
description: fullProductData.description,
category_id: fullProductData.category_id,
certification_type_id: fullProductData.certification_type_id,
artwork_origin_id: fullProductData.artwork_origin_id,
price: fullProductData.price,
currency: fullProductData.currency,
quantity: fullProductData.quantity,
sku: fullProductData.sku,
status: fullProductData.status,
purchase_url: fullProductData.purchase_url,
// user_id: user._id,
update_date: new Date(),
}
if (productActionValue.hasOwnProperty('id')) {
// dispatch(updateProduct(fullProductData._id, productObject, tempMediaList))
}
else {
dispatch(addProductData(productObject));
}
}
Action File
export const addProductData = (product) => dispatch => {
axios.post('/api/shopifyProduct', product).then((res) => {
dispatch({
type: ADD_PRODUCT,
payload: res.data
})
})
}
[Final Data Sent to Shopify DB Using shopify-api-node NPM Package][5]
Post Route
router.post('/', (req, res) => {
const getProductDataFromFrontEndPartOne = {
title: req.body.name,
body_html: req.body.description,
product_type: req.body.category_id,
status: "draft"
}
// getProductDataFromFrontEndPartOne this object data store in shopify
shopify.product.create(getProductDataFromFrontEndPartOne)
.then((res) => {
// after res i did not store this object (getProductDataFromFrontEndPartTwo) into shopify.
const getProductDataFromFrontEndPartTwo = {
id: res.id,
price: req.body.price,
sku: req.body.sku,
inventory_quantity: req.body.quantity
}
shopify.productVariant.create(getProductDataFromFrontEndPartTwo)
})
.catch(err => res.status(404).json({ success: false }));
});
Shopify.product.create using this function to save data in Shopify if res is successful after I did send variant data into their particular product using res.id.

Req.body returns undefined : ExpressJs, NodeJs

Please help me I'm having this error for 5 days.
I'm trying to delete data inside of my array on MongoDB
but my req.body returns undefined even though I have my body-parser. I'm using axios.patch for request.
It works well in my postman but once I sent data that's where the problem occurs.
Here's my axios api call.
export const deleteTask = (id,post) => api.patch(`/main/${id}`, post);
Here's my schema.
const todoSchema = mongoose.Schema({
username: {
type: String,
},
password: {
type: String,
},
task: [String],
time: {
type: Date,
default: Date.now,
}
});
const TodoModels = mongoose.model('TodoModels', todoSchema);
here's my query.
export const deleteTask = async (req,res) => {
const { id } = req.params;
console.log(req.body);
if(!mongoose.Types.ObjectId.isValid(id))
return res.status(404).json(`Invalid ID`);
await TodoModels.findByIdAndUpdate(id,{$pull:{ task: req.body.task }},{
new: true });
}
My req.body has no task and I don't know why. Once I send data it returns undefined but the ID from req.params is not undefined.
Also once I sent the data from client to backend/server req.body returns this { data: '' } the data I sent became the element. I believe it was supposed to be { task: 'data' }
If your deleting a record then why are you using findByIdAndUpdate ; it should be findByIdAndDelete. I have put a sample code you to refer. There are 2ways you can delete a record. You can try them out and see.
Way 1:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//check for existing genre
const movieGenre = await Genre.findByIdAndDelete(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
res.send(movieGenre);
})
Way 2:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//second way to delete
let movieGenre = await Genre.findById(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
await movieGenre.deleteOne();
const index = genres.indexOf(movieGenre);
genres.splice(index, 1);
res.send(movieGenre);
})
Hope the answer helps you in any way.

How to fix the issue with Node Js backend only executing the first controller?

In my Book review site in the search option the user can search for books either by author name or the genre. For those I have separate functions in the search.service.ts below. There are separate controllers in the backend too. But while searching, it only executes the first controller, it doesn't execute the second controller even though the route is directing towards it.
Here is search.service.ts functions,
getPostsByAuthor(author: string) {
this.http.get<{message: string, posts: any, maxPosts: number }>(BACKEND_URL + 'api/search/' + author)
.pipe(map((postData) => {
console.log(postData);
return { posts: postData.posts.map((post) => {
return {
title: post.title,
content: post.content,
author: post.author,
genre: post.genre,
id: post._id,
imagePath: post.imagePath,
creator: post.creator
};
}),
maxPosts: postData.maxPosts};
}))
.subscribe(transformedPostsData => {
this.posts = transformedPostsData.posts;
return this.posts;
});
}
getPostsByGenre(genre: string) {
this.http.get<{message: string, posts: any, maxPosts: number }>(BACKEND_URL + 'api/search/' + genre)
.pipe(map((postData) => {
console.log('Genre_');
console.log(postData);
return { posts: postData.posts.map((post) => {
return {
title: post.title,
content: post.content,
author: post.author,
genre: post.genre,
id: post._id,
imagePath: post.imagePath,
creator: post.creator
};
}),
maxPosts: postData.maxPosts};
}))
.subscribe(transformedPostsData => {
this.posts = transformedPostsData.posts;
return this.posts;
});
}
The route in app.js,
app.use('/api/search', searchRoutes);
The search.js in the route folder,
const express = require('express');
const router = express.Router();
const SearchController = require('../controllers/search');
router.get("/:author", SearchController.getPostsByAuthor);
router.get("/:Genre", SearchController.getPostsByGenre);
module.exports = router;
Here are the controllers consecutively given,
const Post = require('../models/post');
const User = require('../models/user');
exports.getPostsByAuthor = (req, res, next) => {
let maxPosts = 10;
Post.find({ author: req.params.author }).then(posts => {
if(posts) {
res.status(200).json({
posts,
message: "Post was successful",
max: maxPosts
});
} else {
res.status(500).alert('Not Found, double check the spelling').json({
message: "Failed to get User Post"
});
}
});
}
exports.getPostsByGenre = (req, res, next) => {
let maxPosts = 10;
Post.find({ genre: req.params.genre }).then(posts => {
if(posts) {
res.status(200).json({
posts,
message: "Post weirdo successful",
max: maxPosts
});
} else {
res.status(500).json({
message: "Failed to get User Post"
});
}
});
}
It always runs the first one that means getPostsByAuthor, it never runs the second one.
I have checked by changing order, when I did put the getPostsByGenre in the first position then that was run and getPostsByAuthor did not run as it was placed second in order.
The controller placed in the first position in order, returns data perfectly, that means the route is reaching the controller file.
I'm not getting what's the issue. Did not find similar questions in SO.
I'm still new to development with MEAN stack, minimum of the clues would mean great help. Thank you.
The way you're trying to achieve routing is wrong.
When client makes a GET requests to route /api/search, express is going to look if a GET route is defined for the path. It will execute the first route it finds, in this case router.get("/:author", SearchController.getPostsByAuthor) (which you've mounted it first).
This is because middlewares are mounted like stack, execute first middleware then next and so forth.
You would need to define two different routes, since they are GET requests to two different resources, something like:
const SearchController = require('../controllers/search');
router.get("/author/:author", SearchController.getPostsByAuthor);
router.get("/genre/:Genre", SearchController.getPostsByGenre);
app.use('/api/search', searchRoutes);
Then you can call like:
api/search/author/someName
api/search/genre/someGenre

Resources