I have been struggling with this for a few days and i'm new to reactjs and javascript. I have a form that submit successfully to database then it redirect me to an other page where there is a Quiz to do. When you answer all the questions and click on "Apply", you submit the Quiz score by updating the database and add the score value. How to update database at button click?
Quiz.js:
function EndScreen() {
const { score } = useContext(QuizContext);
return (
<div className='EndScreen'>
<h1>Test finished</h1>
<br></br>
<h3> You scored:</h3>
<h1 style={{ fontSize: '70px' }}>{score}/{Questions.length}</h1>
<br></br>
<br></br>
<button>Apply</button> //Clicking on this button should submit score to database
</div>
)
}
formServices.js:
export const FormService = {
store: (data) => {
console.log('data===>>>', data);
const { title, fname, lname, email, phoneNumber, cv, coverLetter } = data;
const formData = new FormData();
formData.append('fname', fname);
formData.append('lname', lname);
formData.append('email', email);
formData.append('phoneNumber', phoneNumber);
formData.append('coverLetter', coverLetter);
formData.append('title', title);
formData.append('cv', cv);
Axios.post(requests.formApi.store, formData)
.then((res) => {
return res;
})
.catch((err) => {
return err;
});
}
};
FormController.js:
const form = require('../models/FormModel')
module.exports = {
store: (req, res, next) => {
let candidate = new form({
title: req.body.title,
fname: req.body.fname,
lname: req.body.lname,
email: req.body.email,
phoneNumber: req.body.phoneNumber,
coverLetter: req.body.coverLetter,
cv: req.body.cv,
score: req.body.score
})
if (req.file) {
candidate.cv = req.file.path
}
candidate.save()
.then(response => {
res.json({
success: true,
message: 'Candidate added successfully!',
data: candidate,
})
})
.catch(error => {
res.json({
success: false,
message: 'An error occured!',
error: error,
})
})
}
}
Related
I am developing a MERN app with axios and trying to populate a field(songList) in a model (User) that is referencing the Schema.Types.ObjectId of another schema (Song).
The _id populates when I create a new Song appropriately.
I can see the entire referenced field is populated in the terminal server side with a console.log but the I cannot get the field to populate on the client side.
My Model; I am trying to populate songList.
const { Schema, model } = require('mongoose')
const bcrypt = require('bcrypt');
const userSchema = new Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
songList: [
{
type: Schema.Types.ObjectId,
ref: 'Song'
}
],
});
userSchema.pre('save', async function (next) {
if (this.isNew || this.isModified('password')) {
const saltRounds = 10;
this.password = await bcrypt.hash(this.password, saltRounds);
}
next();
});
userSchema.methods.isCorrectPassword = async function (password) {
return bcrypt.compare(password, this.password);
};
const User = model("User", userSchema);
module.exports = User;
My server side query, console.log(userSongs) and console.log(user.songList) shows the array of songs appropriately in the terminal:
//login
router.post('/login', async (req, res) => {
const username = req.body.username;
const password = req.body.password;
User.findOne({ username: username })
.populate({path: "songList"})
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
res.status(404).json({ message: 'User Not Found' });
}
const passwordIsValid = bcrypt.compareSync(
password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password" });
}
let userSongs = [];
for (let i = 0; i < user.songList.length; i++) {
userSongs.push(user.songList[i])
}
const accessToken = sign(
{ username: user.username, _id: user._id },
"importantsecret");
// res.json({
// token: accessToken,
// username: username,
// _id: user._id,
// songList: user.songList
// });
res.status(200).send({
token: accessToken,
username: username,
_id: user._id,
userSongs: userSongs
});
console.log(userSongs)
});
});
The client side request for the user information where I am hoping to see a populated songList with console.log(singleUser):
const [singleUser, setSingleUser] = useState({})
const [userSongs, setUserSongs] = useState([])
useEffect(() => {
Axios.get(`http://localhost:3001/api/user/${id}`).then((response) => {
setSingleUser(response.data)
})
}, [authState])
Client side login request.
const login = () => {
const data = { username: username, password: password };
Axios
.post("http://localhost:3001/api/user/login", data)
.then((response) => {
if (response.data.error) {
console.log(response.data.error)
} else {
localStorage.setItem('accessToken', response.data.token)
setAuthState({
username: response.data.username,
_id: response.data._id,
status: true
});
window.location.replace('/')
}
})
}
Here is where I create a new Song and add it to the user that is logged in.
router.post('/insert', (req, res) => {
const id = req.body.id;
const songTitle = req.body.songTitle;
const artist = req.body.artist;
const album = req.body.album;
Song.create({ songTitle: songTitle, artist: artist, album: album })
.then((song) => {
return User.findOneAndUpdate(
{ _id: id },
{ $addToSet: { songList: song._id } },
{ new: true }
)
})
.then((user) =>
!user
? res.status(404).json({
message: 'Song created, but found no user with that ID',
})
: res.json('Created the song')
)
.catch((err) => {
console.log(err);
res.status(500).json(err)
})
});
Any suggests on how I can get songList to populate using the populate() mongoose function is much appreciated.
Thank you,
Brandon
I've read articles on stack overflow, 'Mongoose 'populate' not populating",
"Mongoose .populate() not working correctly". Medium articles, and the mongoose documentation.
I've tried sending the user songs in the response back as res.json() and res.send(). The field shows up but is not populated.
I've tried being more specific with songList.songTitle and {path: "songList")
All of these show the field populated in the terminal but not on the front side.
I've been struggling with this issue for a day now and can't seem to figure out a way to resolve it. This is the code I'm running
Client side:
const nameInput = document.querySelector("#nameInput");
const urlInput = document.querySelector("#urlInput");
const rowAlert = document.querySelector(".alertAppend");
const divAlert = document.createElement("div");
const nameUpdate = async (e) => {
e.preventDefault();
fetch("/auth/updateName", {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
},
body: JSON.stringify({
name: nameInput,
url: urlInput,
})
})
.then(function (data) {
console.log('Request success: ', data);
})
.catch(function (error) {
console.log('Request failure: ', error);
});
};
submitName.addEventListener("click", nameUpdate);
API:
router.get("/updateName", auth, async (req, res) =>{
try {
const { name, url } = req.body;
const ime = name;
const uid = req.session.passport.user;
db.User.find({ where: { id: uid } })
.on('success', function (user) {
if (user) {
user.update({
name: ime,
webhook: url
})
.success(function () {})
}
})
res.json({ message: url});
} catch (err) {
if (err) res.status(500).json({ message: "Internal Error"})
}
});
For some reason it just runs the select query and never proceeds to update the user.
Chrome console output
Debug console output
Sequelize model in case it helps:
module.exports = function (sequelize, DataTypes) {
var User = sequelize.define("User", {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: DataTypes.STRING,
allowNull: false
},
name: {
type: DataTypes.STRING
}
})
return User;
}
The issue was in the API, it's supposed to be router.post
router.post("/updateName", auth, async (req, res) =>{
const { ime, url } = req.body;
const uid = req.session.passport.user;
console.log(ime);
db.User.findOne({where: {id: uid}})
.then(record => {
let values = {
name: ime,
webhook: url
}
record.update(values).then( updatedRecord => {
console.log(`updated record ${JSON.stringify(updatedRecord,null,2)}`)
res.status(200).json({ message: "success"});
})
}
})
.catch((error) => {
// do seomthing with the error
throw new Error(error)
})
});
You can try the following code
await db.User.update({
name: ime,
webhook: url
}, { where: { id: uid } });
When defining your model I don't see the webhook field
I have a repository where I connect directly to my model to insert some data, it creates the data successfully but when I connect my controller to this repository, I get a nulled response, if I log it in the repository itself I get Promise . Please checkout my code below:-
Repository.js
exports.register = (request) => {
const data = UserModel.findOne({email: request.email})
.then(user => {
if(user)
{
return {status: 400, message: 'Email Already exist'}
} else {
return bcrypt.genSalt(10, (err, salt) => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
return bcrypt.hash(newUser.password, salt, async (err, hash) => {
if(err) throw err;
newUser.password = hash;
return newUser.save()
.then(user => {
const token = jwt.sign({id: user._id}, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return {status: 200, message: 'Successfully Registered', auth: true, token: token, user: user}
})
.catch(err => {
return {status: 400, message: err}
})
})
})
}
})
console.log(data) // This part is return Promise <pending>
return data;
};
Controller.js
exports.SeedRegisteration = async (req, res, next) => {
try {
let element = await userRepo.register({username: "Testin", email: "Testin#test.com", "password":
"joe" });
return await res.status(200).json({ status: 200, data: element })
} catch (e) {
return res.status(400).json({ status: 400, message: e.message });
}
};
Works fine but does not return data
Here's the register function using the Promise version of bcrypt (if you don't supply a callback, the bcrypt functions return a Promise
exports.register = (request) =>
UserModel.findOne({
email: request.email
})
.then(user => {
if (user) {
throw 'Email Already exist'
}
})
.then(() => bcrypt.genSalt(10))
.then(salt => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
return bcrypt.hash(newUser.password, salt)
.then((hash) => {
newUser.password = hash;
return newUser.save();
})
}).then(user => {
const token = jwt.sign({
id: user._id
}, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return {
status: 200,
message: 'Successfully Registered',
auth: true,
token: token,
user: user
}
}).catch(err => {
return {
status: 400,
message: err
}
});
Note: there is ONE nested .then - this code could be perfectly flat if you used async/await in register - however I was not prepared to perform such a big rewrite for the answer. Now that the code is in a nice almost flat promise chain, it's relatively simple to convert the whole thing into async/await style
There are too many return statements which return promise. Please update your code in to the following:
exports.register = (request) => {
return new Promise((resolve, reject) => {
try {
UserModel.findOne({ email: request.email })
.then(user => {
if (user) {
return reject({ status: 400, message: 'Email Already exist' })
} else {
bcrypt.genSalt(10, (err, salt) => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
bcrypt.hash(newUser.password, salt, async (err, hash) => {
if (err) return reject(err);
newUser.password = hash;
newUser.save()
.then(user => {
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return resolve({ status: 200, message: 'Successfully Registered', auth: true, token: token, user: user })
})
.catch(err => {
return reject({ status: 400, message: err })
})
})
})
}
}).catch(err => {
return reject(err)
})
} catch (error) {
return reject(error)
}
});
};
I'm building a website where users can register, but when registration is complete nothing happens, its supposed to enter the site.
I have tested it with console.log and found out that my user.id is undefined.
this is my register on the server side:
const handleRegister = (req, res, db, bcrypt) => {
const { email, name, password } = req.body;
if (!email || !name || !password) {
return res.status(400).json('incorrect form submission');
}
const hash = bcrypt.hashSync(password);
db.transaction(trx => {
trx.insert({
hash: hash,
email: email
})
.into('login')
.returning('email')
.then(loginEmail => {
console.log(email)
return trx('users')
.returning('*')
.insert({
email: email,
name: name,
joined: new Date()
})
.then(user => {
res.json(user[0]);
})
})
.then(trx.commit)
.catch(trx.rollback)
})
.catch(err => res.status(400).json('unable to register ' + err))
}module.exports = {
handleRegister: handleRegister
};
and this is my register on the frontend:
import React from 'react';
class Register extends React.Component {
constructor(props){
super(props);
this.state = {
name: '',
email: '',
password: ''
}
}
onNameChange = (event) => {
this.setState({name: event.target.value})
}
onEmailChange = (event) => {
this.setState({email: event.target.value})
}
onPasswordChange = (event) => {
this.setState({password: event.target.value})
}
onSubmitSignIn = () => {
fetch('http://localhost:3000/register', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: this.state.name,
email: this.state.email,
password: this.state.password
})
})
.then(response => response.json())
.then(user => {
console.log(user.id);
if (user.id) {
console.log(user, user.id);
this.props.loadUser(user)
this.props.onRouteChange('home');
}console.log(user.id);
})
}
It is on the frontend I have set the console.log and it never enters the if statement.
How do I fix this?
If you are using mongodb the id field is defined as _id
I have the following module,
module.exports.registerUser = (userData) => {
return new Promise((resolve, reject) => {
if (userData.password !== userData.password2) {
reject("Passwords do not match!");
}
console.log(userData); //prints correctly
let newUser = new iUser(userData);
console.log(newUser); //prints correctly
newUser.save((err) => {
console.log("REACHED"); //DOES NOT ENTER
if (err) {
reject(err.code === 11000 ? 'Username already taken!' :
`Error creating User: ${err}`);
} else {
console.log(newUser);
resolve(newUser);
}
process.exit();
});
})
};
For some reason, the .save() is never invoked and line 10 is never reached... any thoughts?
Edit:
With the registerUser() module, my data-service-auth.js source file so far is:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var userSchema = new Schema({
"userName": {
type: String,
unique: true
},
"email": String,
"password": String,
"loginHistory": {
"userAgent": String,
"dateTime": Date
}
});
let iUser;
module.exports.initialize = () => {
return new Promise(function (resolve, reject) {
let db = mongoose.createConnection("mongodb://user:pass#ds237409.mlab.com:37409/web322_a6");
db.on('error', function (err) {
console.log("error!");
reject(err);
});
db.once('open', function() {
console.log("enteringgggggggggggg");
iUser = mongoose.model("iUser", userSchema);
resolve();
});
resolve();
});
};
module.exports.registerUser = (userData) => {
return new Promise((resolve, reject) => {
if (userData.password !== userData.password2) {
reject("Passwords do not match!");
}
console.log(userData);
let newUser = new iUser(userData);
newUser.save((err) => {
console.log("REACHED"); //DOES NOT ENTER
if (err) {
reject(err.code === 11000 ? 'Username already taken!' :
`Error creating User: ${err}`);
} else {
console.log(newUser);
resolve(newUser);
}
process.exit();
});
})
};
My register form POSTs to my server.js file, which has a route,
app.post("/register", (req, res) => {
dataServiceAuth.registerUser(req.body).then((data) => {
res.render('register', {successMessage: "User Created"});
}).catch((err) => {
console.log("Error: " + err);
res.render('register', {errorMessage: err, userName: req.body.userName});
})
});
And my register.hbs view is, (apologies if formatting is terrible, new coder here):
<h2>Register</h2>
<hr />
<form method="post" action="/register">
{{!-- form --}}
</form>
{{#if errorMessage }}
<div class="alert">
<strong>Error:</strong> {{errorMessage}}</div>
{{else if successMessage}}
<div class="success">
<strong>Success:</strong> {{successMessage}}
</div><a class="btn-right"
href="/login">Proceed to Log in</a>
<br />
<br />
<br />
{{/if}}
I assume it has to be the .save() function, because console.log("REACHED"); is never reached and executed, however calls to console.log(userData) or console.log(newUser); after that instance is created yield expected results.