Delete an image of a post stored in a backend folder when i delete a user of a social network application - mysql

I have a problem on my application, it is a social network. The user can create a post with a message and an image, stored in a backend images folder thanks to Multer. I use sequelize and MySql. When I delete a post, the image is indeed deleted in the images folder since I use multer in my post deletion function so everything goes well but when I delete the author, since I go through a relationship between tables so that when I delete a user, their posts are deleted. This works but in this case the images are not deleted from the folder they are stored in, since Multer is not in the loop. How do I get the images to be deleted from the images folder too in this specific case? Thank you for your help !
`
// Template for the Post table
const User = require("../models/User");
const Sequelize = require("sequelize");
const database = require("../config/database");
const Post = database.define("post", {
content: { type: Sequelize.STRING, allowNull: false },
image: { type: Sequelize.STRING, allowNull: true },
likes: { type: Sequelize.INTEGER, allowNull: false, default: 0 },
});
module.exports = Post;
// Relationship with the User table
User.hasMany(Post, { onDelete: "CASCADE", foreignKey: "userId" });
Post.belongsTo(User, { onDelete: "CASCADE" });
`
`
// deletePost function
exports.deleteOnePost = (req, res, next) => {
Post.findOne({ where: { id: req.params.id } })
.then((post) => {
if (!post) {
return res.status(404).json({
error: new Error("Post non trouvé !"),
});
}
if (post.userId === req.auth.userId || req.auth.userAdmin) {
if (post.image) {
const filename = post.image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
Post.destroy({ where: { id: req.params.id } })
.then(() => res.status(200).json({ message: "Post sans supprimé" }))
.catch((error) => res.status(400).json({ error }));
} else {
return res.status(403).json({
error: new Error("Requête non autorisée !"),
});
}
})
.catch((error) => res.status(500).json({ error }));
};
`

#Anatoly Thank you very much for your help, I'm sorry, I'm a beginner, I tried to adapt what you sent me to the method I use. I don't use the async/await method much and don't know much about it. Do you think I'm getting closer to the solution with what i made ? thanks again !
`
exports.deleteUser = (req, res, next) => {
const userId = req.params.id;
User.findOne({ where: { id: userId } }).then((user) => {
if (!user) {
return res.status(404).json({
error: new Error("User not found!"),
});
}
});
const userPosts = User.getAllPosts();
const postImages = posts.map((x) => x.image).filter((x) => x);
User.destroy({ where: { id: userId } })
.then((post) => {
Post.findOne({ where: { userId } })
.then((post) => {
Post.destroy({ where: { userId } }).then((res) =>
res.status(200).json({
message: "User is deleted",
})
);
for (const image of postImages) {
const filename = image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
})
.catch((error) =>
res.status(400).json({
error,
})
);
})
.catch((error) => res.status(500).json({ error }));
};
`

I don't see how Multer is related to a file deletion. It only helps you to store them. Any way you just need to get all posts of a certain user and delete them and a user in a transaction and then delete their images in a cycle:
// I did not use try/catch for simplicity
exports.deleteUser = async (req, res, next) => {
// get the user id somehow (req.params or the request context, for instance)
const userId = ...
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({
error: new Error("User not found!"),
});
}
const userPosts = await user.getPosts();
const postImages = poists.map(x => x.image).filter(x => x);
// here 'sequelize' is the Sequelize instance, you used to register models
await sequelize,transaction(async transaction => {
await Post.destroy({ where: { userId } })
await User.destroy({ where: { id: userId } })
});
for (const image of postImages) {
const filename = image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
res.status(200).json({ message: "User is deleted" }))
}

I come back to put the fonction that works with my method, i often use ".then()" ".catch()", many thanks to Anatoly for helping me to find the solution, here is the result of my work :
exports.deleteUser = (req, res, next) => {
User.findOne({ where: { id: req.params.id } })
.then((user) => {
if (!user) {
return res.status(404).json({
error: new Error("user not found !"),
});
}
// I get all the posts of the author
Post.findAll({ where: { userId: req.params.id } })
.then((posts) => {
// I start a loop in the posts of the author to find the posts with an image
posts.forEach((post) => {
if (post.image) {
// I erase the files in the images backend directory
const filename = post.image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
// Now i can erase the author
User.destroy({ where: { id: req.params.id } })
.then(() =>
res.status(200).json({
message: "User erased !",
})
)
.catch((error) =>
res.status(400).json({
error,
})
);
});
})
.catch((error) =>
res.status(400).json({
error,
})
);
})
.catch((error) => res.status(500).json({ error }));
};

Related

Node.js - CRUD API multi delete ID's from SQL

I have small project with ReactJS + NodeJS + mySQL.
I can't create-receive correct request for multi delete by IDs.
This how I sent request from React to Node ==>
const deleteProductsByIds = () => {
let ids = [];
stateProducts.forEach((d) => {
if (d.select) {
ids.push(d.id);
}
});
axios
.delete(`http://localhost:5000/products/${ids}`)
.then((data) => {
console.log(data);
getProducts();
})
.catch((err) => alert(err));
};
this how I receive request in Node(sequelize)
router.delete('/:ids', deleteProducts);
export const deleteProducts = async (req, res) => {
try {
await Product.destroy({
where: {
id: []
}
});
res.json({
"message": "ProductS Deleted"
});
} catch (error) {
res.json({ message: error.message });
}
in logs I have this data and by message everything fine, but products(301,302,303,304) not deleted.
config: {url: 'http://localhost:5000/products/301,302,303,304',
method: 'delete', headers: {…},
transformRequest: Array(1), transformResponse: Array(1), …}
data: {message: 'ProductS Deleted'}
I try
where: {
id: req.params.ids
}
but ids value undefind
also I try:
const ids = req.params
try {
await Product.destroy({
where: {
id: ids
}
});
message: "Invalid value { ids: '301,302,303,304' }"}
but receive error message.
usual delete request by ID working without any problem.
For example:
export const deleteProduct = async (req, res) => {
try {
await Product.destroy({
where: {
id: req.params.id
}
});
res.json({
"message": "Product Deleted"
});
} catch (error) {
res.json({ message: error.message });
}
}
Please help me, because I can't find so much information about multi delete request with React-Node-mySQL.

Check if a user is present in the database for a parameter other than ID

I created 3 functions: findOne, create and update. Respectively the methods are GET, POST, PUT.
I changed my API path, it used to be /api/users/:id, now it's /api/users/:sub.
routes.js:
module.exports = app => {
const users = require("../controllers/user.controller.js");
const router = require("express").Router();
// Create a new User
router.post("/", users.create);
// Retrieve a single User with sub
router.get("/:sub", users.findOne);
// Update a User with sub
router.put("/:sub", users.update);
// Delete a User with sub
router.delete("/:sub", users.delete);
app.use('/api/users', router);
};
controller.js:
// Save User in the database
User.create(user)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while creating the Users."
});
});
};
// Find a single User with an id and sub
exports.findOne = (req, res) => {
const sub = req.params.sub;
User.findOne({sub})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message: "Error retrieving User with id=" +sub
});
});
};
// Update a User by the sub in the request
exports.update = (req, res) => {
const sub = req.params.sub;
User.update(req.body, {
where: { sub }
})
.then(num => {
if (sub) {
res.send({
message: "User was updated successfully."
});
} else {
res.send({
message: `Cannot update User with sub=. Maybe User was not found or req.body is empty!`
});
}
})
.catch(err => {
res.status(500).send({
message: "Error updating User with sub="
});
});
};
What I wanted to do was: check if the user_id provided by the authentication provider was present in my database.
If yes, update user data with that user_id.
If not, create a new user record
This is the front-end part involved:
//INFO SAVE AND UPDATE CONDITION
const userExist = InfoDataService.get(data.sub)
.then((response) => {
console.log('find', response.data);
return true;
});
if ( userExist ) {
InfoDataService.create(data)
.then((response) => {
console.log('create', response.data);
setInfo({
id: response.data.id,
sub: response.data.sub,
email: response.data.email,
firstname: response.data.firstname,
lastname: response.data.lastname,
});
})
} else {
InfoDataService.update(sub, data)
.then((response) => {
console.log(response.data);
})
.catch((e) => {
console.error(e);
});
}
};
I thought userInDatabase could only give true or false, so I used it as an argument in the if statement. It does not work and just updates.
If you need any other information, please ask, I have just started and I hope I have given the necessary info.
EDIT
Through findOne I can find the entire object in my database, but I thought that putting the function as an if condition could give me true if it found the object with its sub; false if he found nothing.
This is not the case, in fact in the code I just updated, although findOne works correctly, it continues to execute always and only create.

Asynch problem when fetching MySQL and EXPRESS

I'm trying to simple add a new property in an object. The array of objs is being fetched from my database and then I try to add a property which is also fetched from my database. Although when I try to manipulate it I'm receiving "undefined".
Is it indeed an asynch problem?
Am I doing any silly mistakes?
Those are questions that surrounds my head at the moment.
Code:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRows = rows.map(el => {
Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows, fieldData]) => {
console.log(rows);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows.name
};
}).catch(err => console.log(err));
// return{
// ...el,
// userOfReport: 'Joao'
// };
});
res.render('user/index', { reports: rows, pageTitle: 'Social Reporter', path: '/' });
}).catch(err => console.log(err));
};
Obs This works if comment this out and comment Report.fetchUserNameOfReport function->
// return{
// ...el,
// userOfReport: 'Joao'
// };
Expected result:
{
idComplaint: 83059,
title: '4444',
description: '4444',
image: '4444',
location: '4444',
UserInfo_idPessoa: 80068,
userOfReport: 'Joao'
}
Actual result:
undefined
Thank you in advance!
You never return anything in your .map, so all of the values of modifiedRows will be undefined. You can map them all to promises to get all the values, and then access the modified rows once you wait for all of the promises to resolve. Also, you're shadowing your variable by declaring rows and fieldData multiple times:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRowPromises = rows.map(el => {
return Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows2, fieldData2]) => {
console.log(rows2);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
});
Promise.all(modifiedRowPromises).then(modifiedRows => {
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' });
}).catch(console.log);
}).catch(err => console.log(err));
};
Alternatively, if you use async/await syntax, this can be achieved much more cleanly:
exports.getIndex = async (req, res, next) => {
try {
const [rows, fieldData] = Report.fetchAll();
const modifiedRowPromises = rows.map(async el => {
const [rows2, fieldData2] = await Report.fetchUserNameOfReport(el.UserInfo_idPessoa);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
const modifiedRows = await Promise.all(modifiedRowPromises);
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' };
} catch (err) {
console.log(err);
}
};

Incorrect response after iteration inside for-loop for findById()

I had created 2 tables named: groupusermaps and groups. From groupusermaps i am fetching all the groupId and these groupId I am passing in findById() method to fetch all the details related to that groupId inside the for loop.
here is my method in service:
getAllGroupsByUserId(userId, callback) {
var arr = [];
return sequelize.transaction().then(function(t) {
return groupUserMapModel.GroupUserMap.findAll({
where: {
userId: userId
},
transaction: t
}).then((allGroupsByUserId) => {//from findAll i am getting 2, 1, 4
groupId
for (var p in allGroupsByUserId) {
return
groupModel.Group.findById(allGroupsByUserId[p].groupId, { transaction: t
}).then((group) => {
arr.push(
JSON.stringify(group)
);
});
}
}).then(() => {
callback(arr);
});
});
}
my controller code:
router.get('/controllers/getGroups/user/:userId/groups', (req, res) => {
groupService.getAllGroupsByUserId((req.params.userId), (result) => {
log.info('Group list: ' + JSON.stringify(result));
});
res.send('Fetched all group list');
});
But I am getting an empty array as response from the controller on the console. Is there any way to fix this issue?
groupUserMapModel.GroupUserMap.findAll({
where: {
userId: userId
},
include:[{
model:groupModel
}]
})
.then((results) => {
console.log(results);
})
.catch(err=>{
console.log(err);
})
// provided that groupUserMapModel associated to groupModel
groupUserMapModel.associate = models => {
groupUserMapModel.belongsTo(models.groupModel, {foreignKey: groupId})
}
for more info read about sequelize association

TypeError: Cannot read property 'splice' of undefined

I've created a fixture file to handle my JSON datas used to write tests.
Before each test, I want my data to be filled with seed data.
After each test, I want my data to be empty
Courses.json :
[
{
"id": 1,
"title": "Ma course"
}
]
CoursesFixture.js :
const { courseList } = require('./courses')
mockData = [
{
"id": 1,
"title": "Ma course"
}
]
module.exports = {
up: () => {
courseList.splice(0)
courseList.push.apply(courseList, mockData)
},
down: () => {
courseList.splice(0)
}
}
CoursesTest.js :
const request = require("supertest")
require('chai').should()
const bodyParser = require("body-parser")
const app = require('./../../app')
app.use(bodyParser.json())
const listeDeCourses = require("../fixtures/courses")
const listeDeCoursesFixture = require("../fixtures/coursesFixture")
describe('Courses', () =>{
beforeEach(() => { listeDeCoursesFixture.up() })
afterEach(() => { listeDeCoursesFixture.down() })
describe('Delete course list', ()=>{
it("Should delete a list of course", ()=>{
return request(app).get('/course')
.then((res) => {
res.body.should.have.lengthOf(1)
request(app).delete('/course').send({"id":"1"})
.then((res) => {
res.body.should.have.lengthOf(0)
})
}).catch((err) =>{
throw new Error(err);
})
})
})
describe('Create course list', () =>{
it("Should create a list of courses", () =>{
return request(app).post('/course').send({"id":3,"title":"Première course"}).then((res) => {
res.status.should.be.eq(200)
const listCourses = res.body
const lastCourse = res.body[1]
listCourses.should.be.a('array')
lastCourse.id.should.be.eq(3)
lastCourse.title.should.be.eq("Première course")
listCourses[listCourses.length - 1].should.be.eq(lastCourse)
}).catch((err) => {
throw new Error(err)
})
})
})
describe('Get course list', ()=>{
it("Should get a list of all courses", ()=>{
return request(app).get('/course')
.then((res) => {
res.body.should.have.lengthOf(1)
}).catch((err) =>{
console.log(err)
throw new Error(err);
})
})
})
})
My problem is that when I launch my test I have an error :
TypeError: Cannot read property 'splice' of undefined
I think the problem is in CoursesFixture.js and surely a syntax error somewhere but I can't find where it is.
const { courseList } = require('./courses') should be const courseList = require('./courses')?