back end - GiiovanniK/blok-tech GitHub Wiki
Belangrijke variabelen, zoals de DB uri worden opgeslagen in een .env
bestand. Dit bestand wordt niet mee gecommit naar GitHub, want deze staat in de .gitignore
. Dit zorgt er voor dat deze variabelen altijd secret blijven. Vervolgens exporteer ik de functie connectDB om te kunnen requiren in andere bestanden.
require('dotenv').config();
const uri = process.env.ATLAS_URI;
const connectDB = async (mongoose) => {
try {
await mongoose.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
});
console.log('Connection to DB successful');
} catch (err) {
console.log('Connection to DB failed');
}
};
module.exports = connectDB;
Mongoose DB modellen. Ik heb twee schema's aangemaakt voor twee verschillende functies. Login en user uploads. De modellen zijn opgesteld met mongoose en deze geven aan hoe de structuur van een collectie er uit moet zien.
const mongoose = require('mongoose');
require('../connect.js')
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
const User = mongoose.model('users', UserSchema);
module.exports = User;
const mongoose = require('mongoose');
require('../connect.js')
const userUploadSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
gender: {
type: String,
required: true
},
skill: {
type: [String],
required: true
},
genre: {
type: [String],
required: true
},
createdAt: {
type: Date,
default: Date.now,
required: true
}
});
const userUpload = mongoose.model('useruploads', userUploadSchema);
module.exports = userUpload;
Alle routes in de app, waar de gebruiker naar toe kan navigeren. De routes zijn. Home(/), About, Login, Register, Dashboard, changePassword en userUpload. De title
option wordt gebruikt om een pagina <title>
in de browser te tonen.
app.get('/', (req, res) => {
res.render('index', {
title: 'Home'
});
});
app.get('/about', (req, res) => {
res.render('about', {
title: 'About'
});
});
app.get('/login', checkNoAuth.checkNotAuthenticated, (req, res) => {
res.render('login', {
title: 'Login'
})
});
app.get('/register', checkNoAuth.checkNotAuthenticated, (req, res) => {
res.render('register', {
title: 'Register'
})
});
app.get('/dashboard', checkAuth.checkAuthenticated, async (req, res) => {
const userupload = await userUpload.find().select('username gender skill genre');
res.render('dashboard', {
username: req.user.username,
title: 'Dashboard',
data: userupload
});
});
app.get('/changePassword', checkNoAuth.checkAuthenticated, (req, res) => {
res.render('changePassword', {
title: 'Change Password'
})
});
app.get('/userUpload', checkNoAuth.checkAuthenticated, (req, res) => {
res.render('userUpload', {
title: 'Create Listing'
})
});
Als een route niet bestaat krijgt de gebruiker een HTTP 404 status, oftewel, de pagina bestaat niet.
app.get('*', (req, res) => {
res.status(404).send('This page does not exist!');
});
Ik heb gebruik gemaakt van session d.m.v. de package passport
. Deze session zorgt ervoor dat er gecheckt kan worden of er een gebruiker is ingelogd of uitgelogd, waardoor er bepaalde content alleen beschikbaar kan worden gesteld voor een ingelogde of uitgelogde gebruiker.
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const User = require('../models/User.js');
module.exports = (passport) => {
passport.use(
new LocalStrategy({
usernameField: 'email'
}, (email, password, done) => {
User.findOne({
email: email
})
.then(user => {
if (!user)
return done(null, false, {
message: 'Invalid email'
});
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, {
message: 'Invalid password'
})
}
});
}).catch(err => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
}
In de auth.js
maak ik functies aan die bepaalde routes kunnen blokkeren voor een ingelogde of uitgelogde gebruiker. De checkAuthenticated
checkt of een gebruiker is ingelogd, mocht dit niet zo zijn wordt de gebruiker terug gestuurd naar de /login
route om in te kunnen loggen. de checkNotAuthenticated
checkt of een gebruiker nog steeds is ingelogd. Mocht dit het geval zijn dan kan de gebruiker niet navigeren naar de routes /login
en /register
. De gebruiker wordt terug gestuurd naar de homepage van een ingelogde gebruiker, namelijk /dashboard
.
const checkAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
// req.flash('error_msg', 'Please log in to view this page.');
res.redirect('login');
}
const checkNotAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
res.redirect('dashboard');
} else
return next();
}
module.exports = {
checkAuthenticated,
checkNotAuthenticated
};
Bij het wachtwoord veranderen wordt de User in de DB vergeleken met de user die ingelogd d.m.v. het checken van de user in de huidige session.
app.post('/changePassword', async (req, res) => {
try {
const salt = await bcrypt.genSalt()
const hashedPassword = await bcrypt.hash(req.body.password, salt)
const user = await User.findOne({
username: req.user.username
});
await User.updateOne(user, {
password: hashedPassword
});
await user.save()
res.redirect('login')
} catch {
res.status(500).send();
}
});
Voor het ophalen van de geuploade user data moet er uit de database velden geselecteerd worden die ik wil renderen. In dit geval zijn dat de velden: username, gender, skill en genre.
app.get('/dashboard', checkAuth.checkAuthenticated, async (req, res) => {
const userupload = await userUpload.find().select('username gender skill genre');
res.render('dashboard', {
username: req.user.username,
title: 'Dashboard',
data: userupload
});
});
Een wachtwoord kan veranderd worden. Dit wachtwoord wordt geupdate in de DB. Deze wordt ook opnieuw gehashed, zodat het wachtwoord veilig blijft.
app.post('/changePassword', async (req, res) => {
try {
const salt = await bcrypt.genSalt()
const hashedPassword = await bcrypt.hash(req.body.password, salt)
const user = await User.findOne({
username: req.user.username
});
await User.updateOne(user, {
password: hashedPassword
});
await user.save()
res.redirect('login')
} catch {
res.status(500).send();
}
});
Video's bekeken over NPM packages. Hierna wat rondgekeken op NPM library website waarbij ik even heb gekeken naar alle verschillende packages. Vervolgens Vue.js modal (https://www.npmjs.com/package/vue-js-modal) en nodemon (als dev dependency) (https://www.npmjs.com/package/nodemon) geïnstalleerd. Ook een start runscript gemaakt "start": "node index.js". Hierna nog een algemene node .gitignore file gepushed naar GitHub met gebruik van de terminal.
Met ExpressJS de server opgezet. Routes aangemaakt, voor nu root (index), about en login. Vervolgens ingelezen over Handlebars om deze toe te gaan passen als templating engine, moest hiervoor nog een viewengine package installeren. index.hbs, about.hbs en login.hbs files aangemaakt. Hier is ook naar toe te navigeren. Header en footer files aangemaakt om deze op een later punt te kunnen includen op de dynamische pagina's.
POST request oefeningen en ook connectie met DB gemaakt en getest door met een script data te importeren.
Inlog/registreer systeem, waarbij input wordt gestored in de DB en ook weer opgehaald. Change Password functie waarbij wachtwoord geupdate wordt in de DB (met ook weer de benodigde hashing).
github/gitignore. GitHub. https://github.com/github/gitignore/blob/master/Node.gitignore
Documentation. Node.Js. https://nodejs.org/en/docs/
Handlebars. (n.d.). Handlebars. https://handlebarsjs.com/
Get Started with Atlas — MongoDB Atlas. (n.d.). MongoDB Atlas. https://docs.atlas.mongodb.com/getting-started/
Quick Start — Node.js. (n.d.). Quick Start - Node.Js. https://docs.mongodb.com/drivers/node/quick-start/
Mongoose ODM v5.11.19. (n.d.). Mongoose Documentation. https://mongoosejs.com/
MongoDB CRUD Operations — MongoDB Manual. (n.d.). MongoDB CRUD Operations. https://docs.mongodb.com/manual/crud/
npm: bcrypt. (2021, February 26). Npm - Bcrypt. https://www.npmjs.com/package/bcrypt
npm: express-handlebars. (2021, February 16). Npm. https://www.npmjs.com/package/express-handlebars