I'm trying to get the input value to mongoDB while my password is being hashed.
But my password in my scheme is inside an object (localProvider). (This is only for educational only, this is what my teacher coded)
{
username: {
type: String,
required: false,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
match: /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
},
localProvider: {
password: {
type: String,
required: false,
},
},
facebookProvider: {
id: { type: String, required: false },
token: { type: String, required: false },
},
published_at: { type: Date, required: false },
deleted_at: { type: Date, required: false },
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
{
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
},
);
UserSchema.methods.slugify = function () {
this.slug = slug(this.email);
};
UserSchema.pre('validate', function (next) {
if (!this.slug) {
this.slugify();
}
return next();
});
UserSchema.pre('save', function (next) {
const user = this;
if (!user.isModified('localProvider.password')) return next();// only hash the password if it has been modified (or is new)
try {
return bcrypt.genSalt(config.auth.bcrypt.SALT_WORK_FACTOR, (errSalt, salt) => {
if (errSalt) throw errSalt;
return bcrypt.hash(user.localProvider.password, salt, (errHash, hash) => {
if (errHash) throw errHash;
user.localProvider.password = hash;
return next();
});
});
} catch (error) {
return next(error);
}
});
UserSchema.methods.comparePassword = function (candidatePassword, cb) {
const user = this;
bcrypt.compare(candidatePassword, user.localProvider.password, (err, isMatch) => {
if (err) return cb(err, null);
return cb(null, isMatch);
});
};
UserSchema.virtual('id').get(function () { return this._id; });
UserSchema.plugin(mongoosePaginate);
export default mongoose.model('User', UserSchema);
I've tried in the register.js passing my input values with onChange
[event.target.name]: event.target.value
Only this line of code works only for the single values not inside an object.
As you've seen in the scheme there's no way, so far I know, to pass value to a single state value and to a nested state value.
So is there a solution to fix the code so I'm able to push also the username & email to the state and push the password to localProvider in 1 handleChange?
code from my register.js
class Signup extends Component {
constructor() {
super()
this.state = {
username: '',
email: '',
redirectTo: null,
localProvider:{
password: ''
}
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleInputChange(event, value){
this.setState({
[event.target.name]: event.target.value
})
}
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let statusCopy = Object.assign({}, this.state);
statusCopy.localProvider[inputName].value = inputValue;
this.setState(statusCopy);
}
handleSubmit(event) {
console.log('sign-up handleSubmit, username: ')
console.log(this.state.username)
event.preventDefault()
//request to server to add a new username/password
axios.post('/api/v1/users/', {
...this.state
})
.then(response => {
console.log(response)
if (!response.data.errmsg) {
console.log('successful signup')
this.props.history.push("/");
} else {
console.log('username already taken')
}
}).catch(error => {
console.log('signup error: ')
console.log(error)
})
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form}>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="name">Name</InputLabel>
<Input name="username" type="text" id="username" autoComplete="username" onChange={this.handleInputChange} />
</FormControl>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="email">Email Address</InputLabel>
<Input id="email" name="email" autoComplete="email" onChange={this.handleInputChange} />
</FormControl>
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="password">Password</InputLabel>
<Input type="password" id="password" autoComplete="current-password" onChange={this.handleChange} name="password"/>
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
>
Sign in
</Button>
</form>
</Paper>
</React.Fragment>
)
}
}
export default withStyles(styles)(Signup);```