Upload and set default controller functions are working perfectly. However, we are trying to implement delete image from Cloudinary as well. How can it be done?
In the documentation it was confusing. Here is the code:
const cloudinary = require('cloudinary');
const HttpStatus = require('http-status-codes');
const User = require('../models/userModels');
cloudinary.config({
cloud_name: 'name',
api_key: 'key',
api_secret: 'secret'
});
module.exports = {
UploadImage(req, res) {
cloudinary.uploader.upload(req.body.image, async result => {
await User.update(
{
_id: req.user._id
},
{
$push: {
images: {
imgId: result.public_id,
imgVersion: result.version
}
}
}
)
.then(() =>
res
.status(HttpStatus.OK)
.json({ message: 'Image uploaded successfully' })
)
.catch(err =>
res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error uploading image' })
);
});
},
DeleteImage(req, res) {
cloudinary.uploader.destroy(req.params.image, async result => {
await User.update(
{
_id: req.user._id
},
{
$pull: {
images: {
imgId: result.public_id,
imgVersion: result.version
}
}
}
)
.then(() =>
res
.status(HttpStatus.OK)
.json({ message: 'Image deleted successfully' })
)
.catch(err =>
res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error deleting image' })
);
});
},
async SetDefaultImage(req, res) {
const { imgId, imgVersion } = req.params;
await User.update(
{
_id: req.user._id
},
{
picId: imgId,
picVersion: imgVersion
}
)
.then(() =>
res.status(HttpStatus.OK).json({ message: 'Default image set' })
)
.catch(err =>
res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error occured' })
);
}
};
We are using Node.js Express with Mongoose. How can we include extra function here that will remove images?
There are two options to delete an image from cloudinary:
By using the admin API. For example in Node:
cloudinary.v2.api.delete_resources(['image1', 'image2'],
function(error, result){console.log(result);});
Using our upload API:
cloudinary.v2.uploader.destroy('sample', function(error,result) {
console.log(result, error) });
Please note that using our admin API is rate limited and you might want to use the second option.
it just because your req.params.image is like https:https://res.cloudinary.com/your/image/upload/v1663358932/Asset_2_bdxdsl.png
instead write your delete request like so :
cloudinary.v2.uploader.destroy('Asset_2_bdxdsl', function(error,result) {
console.log(result, error) })
ps: Asset_2_bdxdsl is your image name without prefix .png !!
Related
I have a controller to create new Course but i wanna know how to can i use async and await in order to replace then and catch
Here is my code:
// create new course
export function createCourse (req, res) {
const course = new Course({
_id: mongoose.Types.ObjectId(),
title: req.body.title,
description: req.body.description,
});
return course
.save()
.then((newCourse) => {
return res.status(201).json({
success: true,
message: 'New cause created successfully',
Course: newCourse,
});
})
.catch((error) => {
console.log(error);
res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: error.message,
});
});
}
I hope anyone can show me and help me how to use async and await
export async function createCourse(req, res) {
try {
const course = new Course({
title: req.body.title,
description: req.body.description,
});
await course.save();
res.status(201).json({
success: true,
message: "New cause created successfully",
Course: newCourse,
});
} catch (error) {
console.log(error);
res.status(500).json({
success: false,
message: "Server error. Please try again.",
error: error.message,
});
}
}
// Make sure to add the async keyword
export async function createCourse (req, res) {
// ...
try {
const newCourse = await course.save();
// Do something with the created course, works like the .then function
} catch (err) {
// Do something with the error, works like the .catch function
}
}
If you want to replace cache, then with async, await you will have to use promises. This is example how i would structure code above.
function createCourse(req, res) {
const course = new Course({
_id: mongoose.Types.ObjectId(),
title: req.body.title,
description: req.body.description,
});
try {
const newCourse = await create(course);
return res.status(201).json({
success: true,
message: 'New cause created successfully',
Course: newCourse,
})
} catch (error) {
return res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: error.message,
})
}
}
function create(course) {
return Promise((resolve, reject) => {
return course
.save()
.then((newCourse) => {
return resolve(newCourse);
})
.catch((error) => {
return reject(error);
});
})
}
I'm a beginner in the MERN stack, but I'm trying to create a social network application with the help of various tutorials on YouTube when I get stuck. I need a little more experienced thinking on how best to upload an image to the cloudinary. When I study, I want to learn in the right direction how people work in companies and how they work in the real world.
I found two types of code on youtube that works the same (uploads an image to cloudinary). I wonder which is better. A new API is created in one tutorial, something like this:
cloudinary.config({
cloud_name: '',
api_key: '',
api_secret: '',
});
router.post('/upload', authenticateUser, (req, res) => {
try {
if (!req.files || Object.keys(req.files).length === 0)
return res.status(400).json({ msg: 'No files were uploaded.' });
const file = req.files.file;
if (file.size > 1024 * 1024) {
removeTmp(file.tempFilePath);
return res.status(400).json({ msg: 'Size too large' });
}
if (file.mimetype !== 'image/jpeg' && file.mimetype !== 'image/png') {
removeTmp(file.tempFilePath);
return res.status(400).json({ msg: 'File format is incorrect.' });
}
cloudinary.v2.uploader.upload(
file.tempFilePath,
{ folder: 'test' },
async (err, result) => {
if (err) throw err;
removeTmp(file.tempFilePath);
res.json({ public_id: result.public_id, url: result.secure_url });
}
);
} catch (err) {
return res.status(500).json({ msg: err.message });
}
});
router.post('/destroy', authenticateUser, (req, res) => {
try {
const { public_id } = req.body;
if (!public_id) return res.status(400).json({ msg: 'No images Selected' });
cloudinary.v2.uploader.destroy(public_id, async (err, result) => {
if (err) throw err;
res.json({ msg: 'Deleted Image' });
});
} catch (err) {
return res.status(500).json({ msg: err.message });
}
});
const removeTmp = path => {
fs.unlink(path, err => {
if (err) throw err;
});
};
export default router;
And the other shot does it all the same from the controller. For example if I want to make a new post my controller looks like this:
export const createPost = async (req, res) => {
const myCloud = await cloudinary.v2.uploader.upload(req.body.image, {
folder: 'posts',
});
const { description, image } = req.body;
if (!image) {
throw new BadRequestError('Image is required');
}
const user = await User.findById(req.user.userId);
const newPost = new Post({
description,
image: {
public_id: myCloud.public_id,
url: myCloud.secure_url,
},
username: user.username,
avatar: user.avatar,
user: req.user.userId,
});
const post = await newPost.save();
res.status(StatusCodes.CREATED).json({ post });
};
I create an image in the controller and upload it when I submit the form in react. They both work the same, I tried, but I'm interested in whether it's necessary to make a new endpoint or it's enough to upload an image from the controller, delete an image from the controller, etc.
You can use multer module for uploading content in the directory and if you want to upload in S3 bucket then you have to use module accordingly.
For multer -> https://www.npmjs.com/package/multer
For multer-S3 -> https://www.npmjs.com/package/multer-s3
In my social media application, when a user comments on a post, it throws a 500 Internal Server Error.
The console states POST https://shielded-journey-88539.herokuapp.com/https://us-central1-myapp-1d191.cloudfunctions.net/api/post/3Y7OcHJXXXa0ilBeq35u/comment 500 (Internal Server Error)
When I check the commentOnPost route on Postman, the response returns a Status 200, but the body returns Invalid Host Header.
// Comment on a Post API
exports.commentOnPost = (req, res) => {
if (req.body.body.trim() === '') {
return res.status(400).json({ comment: 'Cannot be empty' });
}
const newComment = {
body: req.body.body,
createdAt: new Date().toISOString(),
postId: req.params.postId,
userHandle: req.user.handle,
profileImage: req.user.profileImage
};
db.doc(`/posts/${req.params.postId}`)
.get()
.then(doc => {
if (!doc.exists) {
return res.status(404).json({ error: 'Post does not exist.' });
}
// after gaining access to document, use prefix reference to update comment count
return doc.ref.update({ commentCount: doc.data().commentCount + 1 })
})
.then(() => { // add newComment to comments collection
return db.collection('comments').add(newComment);
})
.then(() => {
res.json(newComment);
})
.catch(err => {
console.log(err);
res.status(500).json({ error: 'Something went wrong' });
});
};
When I console.log(commentData) inside of dataSlice/submitComment, it returns just the req.body.body and not the rest of the newComment object, from the commentOnPost route.
// submitComment of dataSlice
export const submitComment = (postId, commentData) => dispatch => {
console.log(commentData)
return axios
.post(`/post/${postId}/comment`, commentData)
.then(res => {
dispatch(submitTheComment(res.data))
dispatch(clearErrors());
})
.catch(err => dispatch(setErrors(err.response)))
};
I'm using my own Heroku proxy server.
// App.jsx
axios.defaults.baseURL =
'https://shielded-journey-88539.herokuapp.com/https://us-central1-myapp-1d191.cloudfunctions.net/api';
// package.json
"proxy": "https://shielded-journey-88539.herokuapp.com/https://us-central1-myapp-1d191.cloudfunctions.net/api"
What am I doing wrong?
Can you try this code, and console.log(commentData), and where is commentData?
exports.commentOnPost = (req, res) => {
if (req.body.body.trim() === '') {
return res.status(400).json({ comment: 'Cannot be empty' });
}
const newComment = {
body: req.body.body,
createdAt: new Date().toISOString(),
postId: req.params.postId,
userHandle: req.user.handle,
profileImage: req.user.profileImage
};
console.log("newComment: ", newComment)
db.doc(`/posts/${req.params.postId}`).get()
.then(doc => {
if (!doc.exists) {
return res.status(404).json({ error: 'Post does not exist.' });
}
// after gaining access to document, use prefix reference to update comment count
return doc.ref.update({ commentCount: doc.data().commentCount + 1 });
}).then(() => {
// add newComment to comments collection
db.collection('comments').add(newComment);
res.status(200).json(newComment);
}).catch(err => {
console.log("Error in Catch commentOnPost: ", err);
res.status(500).json({ error: 'Something went wrong' });
});
};
I want to delete a doc with id in mongoose. It executes the method but doesn't delete that doc in MongoDB Altas.
Note:Everthing is correct and also Passing id correctly in PostMan.
here is my controller :
const Post = require("../models/Post");
const mongoose = require("mongoose");
exports.postPost = async (req, res) => {
try {
const post = await new Post({
_id: new mongoose.Types.ObjectId(),
title: req.body.title,
desc: req.body.desc,
}).save();
console.log("Saved in db!");
return res.status(201).json({
success: true,
data: post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: "Server Error",
});
}
};
exports.deletePost = async (req, res) => {
let postID = req.params.id;
await Post.deleteOne({ _id: postID }, (err, data) => {
if (err) {
res.status(500).json({
message: "Something went wrong, please try again later.",
});
} else {
res.status(200).json({
message: "Post Deleted",
data: data,
});
}
});
};
here is my posts route:
const express = require("express");
const router = express.Router();
const {
postPost,
deletePost,
} = require("../controllers/posts_controller");
router.route("/:id").delete(deletePost);
router.route("/").post(postPost);
module.exports = router;
here is my postman :
here is my mongodb altas:
use the findOneAndDelete({_id:postId}) instead of deleteOne in posts controller
Or
use findByIdAndDelete(postId) instead of deleteOne in posts controller
exports.deletePost = async (req, res) => {
let postID = req.params.id;
await Post.findByIdAndDelete(postID, (err, data) => {
if (err) {
res.status(500).json({
message: "Something went wrong, please try again later.",
});
} else {
res.status(200).json({
message: "Post Deleted",
data: data,
});
}
});
};
I'm a bit stumped and was wondering if anyone could help. Whenever I call an axios post, the network tab shows that the request is pending and ultimately fails. When I try the same call through Robo 3T, it updates succesfully.
Can anyone give me some insight? Thank you!
Here's the route I'm using:
router.post('/upvote/reply/id/:id',
// passport.authenticate('jwt', { session: false }),
async (req, res) => {
await Posts.findOneAndUpdate(
{ "comments._id": mongoose.Types.ObjectId(req.params.id) },
{
$inc: { "comments.$.points": 1 },
$push: { "comments.$.upvotedBy": req.user._id },
$pull: { "comments.$.downvotedBy": req.user._id },
},
(err, result) => {
if (err) {
return res.status(404).json({
success: false,
error: err,
message: 'Post not upvoted!',
})
}
else {
return res.status(200).json({
success: true,
data: result
})
}
})
.catch(err => console.log(err))
})
Here's how I'm calling my API route:
handleReplyUpvote = (id) => {
this.setState(prevState => {
const updatedReplies = prevState.replies.map(item => {
if (item._id === id) {
try {
axios
.post(`http://localhost:5000/api/posts/upvote/reply/id/${id}`)
.then(res => {
// console.log(res.data.data[0].comments[0])
console.log(res)
// ...item,
// const {posts} = this.state
// posts.push(res.data)
// this.setState({posts})
})
}
catch (err) {
console.log(err)
}
return {
...item,
// voted: true,
points: item.points + 1
}
}
return item
})
return {
replies: updatedReplies
}
})
// console.log('boops')
}
A little more context code which might help:
const replies = this.state.replies.slice().map((item, i) =>
<div
key={i}
className='replyItem'
>
<Reply
// key={i}
reply={item.reply}
id={item._id}
user_id={item.user_id}
createdAt={item.createdAt}
points={item.points}
handleDelete={() => this.handleDelete(item._id)}
user={this.props.auth}
handleReplyUpvote={() => this.handleReplyUpvote(item._id)}
// handleDownvote={() => this.handleReplyDownvote(item._id.points)}
/>
</div>
)
You are mixing async/await, promises and callbacks. Use either promises or asyns/await, not all. I have fixed few things and it should work. (I didn't test it though)
router.post("/upvote/reply/id/:id", async (req, res) => {
try {
const result = await Posts.findOneAndUpdate(
{ "comments._id": mongoose.Types.ObjectId(req.params.id) },
{
$inc: { "comments.$.points": 1 },
$push: { "comments.$.upvotedBy": req.user._id },
$pull: { "comments.$.downvotedBy": req.user._id },
}
);
return res.status(200).json({
success: true,
data: result,
});
} catch (error) {
return res.status(404).json({
success: false,
error: error.message,
message: "Post not upvoted!",
});
}
});
handleReplyUpvote = async(id) => {
const updatedReplies = [];
for(const item of this.state.replies){
if(item._id === id){
try{
const response = await axios
.post(`http://localhost:5000/api/posts/upvote/reply/id/${id}`)
console.log(response.data);
}catch(error){
console.log(error.message);
}
updatedReplies.push({
...item,
points: item.points + 1;
})
continue;
}
updatedReplies.push(item);
}
this.setState({
replies: updatedReplies
})
}