I have a problem for my image (I use multer), when in my user edit form.
Is it possible to put conditions on my image if the field is null, it still sends my request to the server.
I did the necessary on the front-end to send the firstname and lastname data but for the image impossible, that's why I want to go through the back end.
exports.updateUser = (req, res, next) => {
try {
if (res.locals.userId === parseInt(req.params.id)) {
const user = [
[req.body.user_lastName],
[req.body.user_firstName],
[`${req.protocol}://${req.get('host')}/images/${req.file.filename}`],
[req.params.id]
]
const sql = "UPDATE users SET user_lastName=?, user_firstName=?,user_avatar=? WHERE user_id=?";
db.query(sql, user, function (error, results) {
if (!error) {
res.status(200).json({ message: 'modification profil executé' });
} else {
console.log(error)
res.status(401).json({ error: 'Erreur utilisateur table users' });
}
});
} else {
res.status(401).json({ error: 'erreur d\'authentification, vous n\'avez pas les droits pour modifier ce profil' })
}
} catch (error) {
res.status(500).json({ error });
console.log(error)
}
}
Use an if statement to set a variable conditional on whether the field was provided.
exports.updateUser = (req, res, next) => {
try {
let image = null;
if (req.?file.?filename) {
image = `${req.protocol}://${req.get('host')}/images/${req.file.filename}`;
}
if (res.locals.userId === parseInt(req.params.id)) {
const user = [
req.body.user_lastName,
req.body.user_firstName,
image,
req.params.id
]
const sql = "UPDATE users SET user_lastName=?, user_firstName=?,user_avatar=? WHERE user_id=?";
db.query(sql, user, function(error, results) {
if (!error) {
res.status(200).json({
message: 'modification profil executé'
});
} else {
console.log(error)
res.status(401).json({
error: 'Erreur utilisateur table users'
});
}
});
} else {
res.status(401).json({
error: 'erreur d\'authentification, vous n\'avez pas les droits pour modifier ce profil'
})
}
} catch (error) {
res.status(500).json({
error
});
console.log(error)
}
}
Related
I'm learning how to work with databases and I ran into the following problem that I can't solve:
I'm trying to change the data in the table, but I get an error every time
That's my Node.Js code:
app.post('/db/:userId', async (req, res)=> {
const { userId } = req.params
try {
const conn = mysql.createConnection({
host: 'localhost',
user: 'root',
database: 'testdb',
password: ''
})
conn.connect( err=> {
if (err) {
console.log(err)
return err
} else {
console.log('DATABASE ----- CONNECTED SUCCESSFULLY')
}
})
const { name, scnmb, login, password, isLogged } = req.body;
let create = `UPDATE user_info SET name = '${name}', scnmb = '${scnmb}', login = '${login}', password = ${password}, is_logged = '${isLogged}' WHERE user_info.id = ${userId};`
conn.query(create, async (err, result) => {
if (err) {
console.log(err);
res.status(500).send("Error creating user");
} else {
res.json(result);
}
});
conn.end(err=> {
if (err) {
console.log(err)
return err
} else {
console.log('DATABASE ----- DISCONNECTED SUCCESSFULLY')
}
})
} catch (e) {
console.log(e)
res.statusCode = 500
res.json({ errcode: 500, errmsg: 'DataBase error', ...e})
}
})
That's my request body(Im using Postman):
{
"name": "Nikita",
"scnmb": 5,
"login": "+888",
"password": 0,
"isLogged": 1
}
And that's an error I get:
TypeError: Cannot destructure property 'name' of 'req.body' as it is undefined
I'm sure this problem is simple, but I just don't have any experience to solve it.
Can you help me?
I am having an issue with the session variable not setting. I am assuming the problem has something to do with the functions being asynchronous(async/await).
How do I make sure that session is set before jwt.sign and committing (how should I use async await or promises here)?
connection.getConnection(function(err, conn) {
try {
conn.beginTransaction(function(err) {
if (err) {
throw err
}
conn.query(`INSERT INTO USER SET username = ?, email = ?; SELECT LAST_INSERT_ID() AS id;`, [username, hashedEmail], (error, results) => {
if(error){
throw error;
} else {
// this doesn't set
req.session.verify = results[0].id;
jwt.sign(
{},
process.env.gmail_secret,
{
expiresIn: '1d',
},
(err, emailToken) => {
//...
}
)
await conn.commit(async function(error) {
if (error) {
throw err;
}
await conn.destroy();
req.flash("flash", "You have successfully created an account. The last step is to confirm your email so we know you are legit =].");
return res.redirect('/register');
});
}
})
})
} catch {
return conn.rollback(function() {
conn.destroy();
req.flash("flash", 'A server error has occurred.');
res.redirect('/register');
});
}
});
No matter what I change the user login will keep redirecting to failure instead of success. I don't know if I'm missing something or if I did something wrong. I tried to read the documentation for passport but, I found it pretty confusing. Here is my github link if you need to see the rest of the code. The node files are in app.js and passport-config.js.The sign up part of the website is working. https://github.com/gego144/to-do-list-website/tree/main
const customFields = {
usernameField: 'email',
passwordField: 'password'
}
const verifyCallback = (username, password, done) => {
user_exists = userName_Checker(username), function (err, user) {
if (err) { return done(err); }
if (userName_Checker(username) == false) {
console.log('wrong user');
return done(null, false, { message: 'Incorrect username.' });
}
if (password_finder(username, password)) {
console.log('wrong pass');
return done(null, false, { message: 'Incorrect password.' });
}
console.log('wtf');
return done(null, user);
};
;
}
const strategy = new LocalStrategy(customFields, verifyCallback);
passport.use(strategy);
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// function that checks to see if the users email is in the database
function userName_Checker(email_name){
var sql = "select * from info where email = ?";
var user_email = [[email_name]];
db.query(sql, [user_email],function (err,result){
if (err) throw err;
var not_unique = result.length;
if(not_unique == 0){
return false;
}
else{
return true;
}
}
)}
// function that checks to see if the password in the database matches with the email
function password_finder(email_name, pass){
var sql = "SELECT password FROM info WHERE email = ?";
var user_email = [[email_name]];
db.query(sql, [user_email],function (err,result){
if (err) throw err;
bcrypt.compare(result, pass, function(err, res){
if(err){ throw err};
if(res){
return true;
}
else{
return false;
}
})
}
)}
My post method in my other file.
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect:'/index.html',
failureFlash: true
}))
Edit 1.
I just want to mention that the console.logs you see in verify Callback all don't log anything for some reason too.
The problem might be in the serialization logic.
In passport.serializeUser, you are passing in the whole user object, but when deserializing you are passing the id
Though I am not using SQL, the logic should be similar.
So the code should be something like this:
// Session
// Pass in user id => keep the session data small
passport.serializeUser((id, done) => {
done(null, id);
});
// Deserialize when needed by querying the DB for full user details
passport.deserializeUser(async (id, done) => {
try {
const user = await User_DB.findById(id);
done(null, user);
} catch (err) {
console.error(`Error Deserializing User: ${id}: ${err}`);
}
});
// Export the passport module
module.exports = (passport) => {
passport.use(new LocalStrategy({ usernameField: 'email', }, async (email, password, done) => {
try {
// Lookup the user
const userData = await User_DB.findOne({ email: email, }, {
password: 1, }); // Return the password hash only instead of the whole user object
// If the user does not exist
if (!userData) {
return done(null, false);
}
// Hash the password and compare it to the hash in the database
const passMatch = await bcrypt.compare(password, userData.password);
// If the password hash does not match
if (!passMatch) {
return done(null, false);
}
// Otherwise return the user id
return done(null, userData.id);
} catch (err) {
passLog.error(`Login Error: ${err}`);
}
}));
};
These options for passport seems to malfunction a lot or exhibit weird behaviors, so I suggest you handle the redirection logic like in my controller.
{ successRedirect: '/good',
failureRedirect: '/bad' }
Login controller logic:
(I am omitting the code here for session storage and made some modifications, but this code should work for what you need)
const login = (req, res, next) => {
//Using passport-local
passport.authenticate('local', async (err, user) => {
//If user object does not exist => login failed
if (!user) { return res.redirect('/unauthorized'); }
//If all good, log the dude in
req.logIn(user, (err) => {
if (err) { return res.status(401).json({ msg: 'Login Error', }); }
// Send response to the frontend
return res.redirect('/good');
});
});
})(req, res, next);
};
The actual route:
// Import the controller
const {login} = require('../controllers/auth');
// Use it in the route
router.post('/auth/login', login);
I would like to explain my problem of the day.
currently i am logging in,
I am in my profile, and here I would like to display my name.
the following code works correctly, only it shows me all the use registered in my database.
and I would only like to be able to display the correct name which corresponds to the UID in my database
How can I fix this issue?
that is my get and return
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
data:[]
};
}
getRandom = async () => {
const res = await axios.get(
"https://joke.fr/api/profil"
);
this.setState({ data: res.data })
}
componentDidMount() {
this.getRandom()
}
render() {
return (
<div>
{this.state.data.map(data => <p>{data.name}</p>)}
</div>
)
}
}
export default Profile;
that is my route is bdd
app.get('/api/profil', (req, res) => {
connection.query('SELECT * from profil' , (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
console.log(results);
return res.json(results);
}
});
});
and last one is my BDD schéma.
{
"id": 62,
"name": "neff",
"uid": "dycjibu96zgmzc0KpGAqxKiUsMu2"
}
You would need another parameter in your app.get. I suppose when user logged in to your app, you store their UID. If that's the case, you can use:
app.get('api/profil/:id', (req, res) => {
const userId = req.params.id
connection.query(`SELECT * from profil WHERE id = ${userId}` , (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
console.log(results);
return res.json(results);
}
});
})
But I would recommend something like body-parser to sanitise your SQL request though.
Since you are logged in then probably you have the UUID or name in the browser saved in the local storage (this is the simplest approach). This means on your backend you should send a GET request to get 1 profile based on the UUID.
Server Side Code
app.get('/api/profil/:name', (req, res) => {
const { name } = req.params;
connection.query(`SELECT * from profil where name=${name}`, (err, results) => {
if (err) {
console.log(err);
return res.status(500).send('Erreur lors de la récupération des employés');
} else {
// This should be an object
console.log(results); // This should be an object like {"id": 62, "name": "authUser"}
return res.json(results);
}
});
});
Client Side Code
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
userProfile: null
};
}
getUserProfile = async (userName) => {
// Get the profile by passing the id to the URL.
// Side note, you should handle errors here but for simplicity lets skip it.
const res = await axios.get(
`https://joke.fr/api/profil/${userName}`
);
// res.data should be an object like {"id": 62, "name": "authUser"}
this.setState({ userProfile: res.data });
}
componentDidMount() {
// You should have the id of the user after login
// Let me assume you stored it in localstorage
const user = localStorage.getItem("user");
if (user) {
const { id, name } = JSON.parse(user);
// You can skip the localstorage part if you store the user's details in a different way and jump here by passing the ID/name to this function
this.getUserProfile(name);
}
}
render() {
const { userProfile } = this.state;
return (
<div>
{userProfile ? userProfile.name : "No user name"}
</div>
)
}
}
export default Profile;
I am registering a new user by checking it is already available. But for every user it shows "user is already available"
signup: function (req, res) {
var username = req.param("username");
var password = req.param("password");
var status = false;
console.log("user : " + username + " : " + password);
Signup.find({username: username}).exec(function(err, usr){
if (err) {
var response = {status:status, error:"db error"};
res.send(500, response);
} else {
if (usr) {
status = true;
res.send(400, {error: "Username already Taken"});
}
else {
signup.create({username: username, password: password}).exec(function(error, user) {
if (error) {
res.send(500, {error: "DB Error"});
} else {
req.session.user = user;
res.send(user);
}
});
}}
});
},
I assume that in your model it clear that the username must be unique. So use findOne() function. It's return only one record( object ).
signup: function(req, res) {
var username = req.param("username");
var password = req.param("password");
var status = false;
Signup.findOne({ username: username })
.exec(function(err, usr) {
if (err) {
var response = { status: status, error: "db error" };
return res.send(500, response);
}
if (usr) {
//status = true; --> in this case you don't use 'status' so this assignment is unnecessary
return res.send(400, { error: "Username already Taken" });
} else {
Signup.create({ username: username, password: password })
.exec(function(err, user) {
if (err) {
res.send(500, { error: "DB Error" });
} else {
req.session.user = user;
res.send(user.username);
}
});
}
});
}
Signup.find({username: username}).exec(function(err, usr){
// usr is an array
});
the result of find is a list with objects matching your query. The list either has items or no items. In both cases
if (usr) {}
will be true, because you basically just check whether usr is defined which it always is. So change it to
if (usr.length === 0) {
// already exists
}
Or you change find to findOne.