I am working through the full stack certification on devchallenges.io and I'm doing the authentication app challenge. So far I have been able to create the login and register functionality and have been able to set up the functionality to get the logged in user and display their information and also the functionality for the user to update their profile however, when registering or logging in a user, the profile information of the same one user is displayed regardless of which user is logged in. I have attached a link to a loom video to demonstrate the issue. Furthermore,. I have attached the github source code link.
https://www.loom.com/share/c464f456751a45068110e699f796e11d
https://github.com/gbopola/Auth-App
Profile.js
import React, { useEffect, useState } from 'react';
import { Navbar } from './Navbar';
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { loadUser } from '../redux/actions/auth';
import { Link } from 'react-router-dom';
import { store } from '../store';
export const Profile = () => {
const [hover, setHover] = useState(false);
const dispatch = useDispatch();
useEffect(() => {
dispatch(loadUser());
}, []);
const state = useSelector((state) => state.auth);
let styles = {
width: '72px',
height: '72px',
borderRadius: '8px',
background: `url(${
state && state.user && state.user.avatar
}) center center/cover`,
};
return (
<div className="Profile">
<Navbar />
<div className="profile-personal-info">
<h1>Personal Info</h1>
<p className="personal-info-text">
Basic info, like your name and photo
</p>
</div>
<div className="profile-wrapper">
<div className="profile-heading">
<div>
<h2>Profile</h2>
<p className="personal-info-grey">
Some info may be visible to other people
</p>
</div>
<Link to={`/profile/edit/${state && state.user && state.user._id}`}>
<button className="edit-btn">Edit</button>
</Link>
</div>
<div className="divider"></div>
<div className="profile-photo">
<p className="personal-info-grey">PHOTO</p>
<div className="profile-img" style={styles}></div>
</div>
<div className="divider"></div>
<div className="name">
<p className="personal-info-grey">NAME</p>
<p className="name-text">{state && state.user && state.user.name}</p>
</div>
<div className="divider"></div>
<div className="bio">
<p className="personal-info-grey">BIO</p>
<p className="bio-text">{state && state.user && state.user.bio}</p>
</div>
<div className="divider"></div>
<div className="phone">
<p className="personal-info-grey">PHONE</p>
<p className="phone-text">
{state && state.user && state.user.phone}
</p>
</div>
<div className="divider"></div>
<div className="email">
<p className="personal-info-grey">EMAIL</p>
<p className="email-text">
{state && state.user && state.user.email}
</p>
</div>
<div className="divider"></div>
<div className="password">
<p className="personal-info-grey">PASSWORD</p>
<p className="password-text">***********</p>
</div>
</div>
</div>
);
};
Server.js
const express = require('express');
const connectDB = require('./config/db');
const app = express();
const { check, validationResult } = require('express-validator');
const User = require('./models/User');
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const auth = require('./middleware/auth');
const cloudinary = require('./utils/cloudinary');
const upload = require('./utils/multer');
// Connect database
connectDB();
// Init Middleware
app.use(express.json({ extended: false }));
// @route POST /register
// @desc Register user
// @access Public
app.post(
'/register',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Please enter a password').notEmpty(),
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
// See if user exists
let user = await AuthUser.findOne({ email });
if (user) {
return res
.status(400)
.json({ errors: [{ msg: 'User already exists' }] });
}
// Get users gravatar
const avatar = gravatar.url(email, {
s: '200',
r: 'pg',
d: 'mm',
});
user = new AuthUser({
email,
avatar,
password,
});
// Encrypt password
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
// Return jsonwebtoken
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: '5 days' },
(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (error) {
console.error(error.message);
res.status(500).send('Server error');
}
}
);
// @route POST /login
// @desc Authenticate user & get token
// @access Public
app.post(
'/login',
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists(),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
});
}
const { email, password } = req.body;
try {
// See if user exists
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid credentials' }] });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid credentials' }] });
}
// Return jsonwebtoken
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: '5 days' },
(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
}
);
// @route GET /profile
// @desc Get full user profile
// @access Private
app.get('/profile', auth, async (req, res) => {
try {
let user = await User.findOne({ user: req.user.id }).select('-password');
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
// @route POST /profile/edit/:id
// @desc edit profile
// @access Private
app.put('/profile/edit/:id', upload.single('image'), auth, async (req, res) => {
const { name, bio, email, phone, password } = req.body;
try {
let user = await AuthUser.findById(req.params.id);
// Delete image from cloudinary
if (user.cloudinary_id !== '')
await cloudinary.uploader.destroy(user.cloudinary_id);
// Upload image to cloudinary
let result;
if (req.file) {
result = await cloudinary.uploader.upload(req.file.path);
}
const data = {
name: name || user.name,
avatar: (result && result.secure_url) || user.avatar,
bio: bio || user.bio,
email: email || user.email,
phone: phone || user.phone,
password: password || user.password,
cloudinary_id: (result && result.public_id) || user.cloudinary_id,
};
if (password !== '') {
// Encrypt password
const salt = await bcrypt.genSalt(10);
data.password = await bcrypt.hash(password, salt);
}
// Update
user = await User.findByIdAndUpdate(req.params.id, data, { new: true });
return res.json(data);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
CodePudding user response:
On the /profile route, what is
await User.findOne({ user: req.user.id }).select('-password');
returning?
It looks to me as if your are trying to find a user whose "user" property is the id, but your User model has no such property. So try replacing that with
await User.findById(req.user.id);
I'm assuming mongoose creates ObjectIDs for your documents.