Back end - lottekoblens/matching-application GitHub Wiki
De applicatie stelt de gebruiker in staat om andere mensen te liken of disliken op basis van een leuke/gekke foto met het favoriete product van de McDonalds. De applicatie haalt data op uit de database (MongoDB) en zal deze data updaten.
Het doel van de gebruiker is om te liken of te disliken en om personen die geliked zijn te verwijderen uit de lijst met mensen die geliked zijn.
Om de app op te zetten heb ik eerst express gedownload en gezorgd dat er een pagina getoond ging worden op de port die ik heb ingesteld, port 3000. En ik heb ejs geïnstalleerd. Voor ejs is de juiste mappenstructuur nodig. De static files moeten in de public map. En in de public map heb ik een views map geplaatst, deze views map bevat de dynamische files, de ejs files.
const express = require('express');
const app = express();
const port = 3000;
const path = require('path');
app
.use('/static', express.static(path.join(__dirname, 'public')))
.set('view engine', 'ejs')
.set('views', path.join(__dirname, '/views'))
Met het main.ejs file zet je de basis neer voor de pagina’s, deze file wordt dan ook geïnclude in de andere files.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/static/css/<%= style %>" rel="stylesheet" type="text/css">
<title>McDuo's</title>
</head>
<body>
</body>
</html>
Daarna ben ik de routes gaan opzetten.
app
.get('/', async (req, res) => {
try {
const allUsers = await findAllPeopleNotVisited();
const firstUser = allUsers[0];
const userID = allUsers[0].id;
res.render('home', {
style: 'home.css',
firstUser,
userID,
});
} catch (error) {
console.log(error);
res.redirect('/nomorepeople');
}
.get('/like', async (req, res) => {
try {
const likedPeople = await findAllPeopleLiked();
if (likedPeople.length === 0) {
throw new Error('Required');
}
res.render('like', {
style: 'like.css',
likedPeople,
});
} catch (error) {
console.log(error);
res.redirect('/nobodyliked');
}
})
.get('/nobodyliked', async (req, res) => {
res.render('nobodyliked', {
style: 'like.css',
});
})
.get('/nomorepeople', async (req, res) => {
res.render('nomorepeople', {
style: 'home.css',
});
})
Voor de homepagina wordt er een async function gebruikt die await op de functie findAllPeopleNotVisited().
async function findAllPeopleNotVisited() {
const data = await testingModel.find({ visited: false }).lean();
return data;
}
Met deze functie worden de users opgehaald waarvan visited gelijk is aan false. Om dit voor elkaar te krijgen heb ik gebruik gemaakt van mongoose en dotenv. En heb ik een database aangemaakt met MongoDB.
const mongoose = require('mongoose');
const testingModel = require('./models/test.model');
require('dotenv').config();
const dbUrl = `mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@${process.env.DB_HOST}`;
mongoose.connect(dbUrl, {
useUnifiedTopology: true,
useNewUrlParser: true,
useFindAndModify: false,
});
In de .env file staan de db_user, DB_PASS, DB_HOST. Deze file moet overigens niet meegestuurd worden naar GitHub, dus zet je hem in de .gitignore file. Als je deze wel mee zou sturen naar GitHub zou iedereen in je database kunnen en dat wil je niet.
Met mongoose moet je gebruik maken van models. Een model bevat een Schema waarin je de onderdelen van wat je de user meegeeft in de database in het schema zet.
const mongoose = require('mongoose');
const schema = mongoose.Schema;
mongoose.set('useCreateIndex', true);
const clusterSchema = new schema({
id: {
type: String,
required: [true, 'Id is required'],
unique: [true, 'There can only be one record with this id'],
},
name: {
type: String,
required: [true, 'Name is required'],
},
age: {
type: String,
required: [true, 'Age is required'],
},
img: {
type: String,
required: [true, 'Image is required'],
},
residence: {
type: String,
required: [true, 'Residence is required'],
},
product: {
type: String,
required: [true, 'Product is required'],
},
liked: {
type: Boolean,
required: [true, 'Liked is required'],
},
visited: {
type: Boolean,
default: false,
},
});
module.exports = mongoose.model('users', clusterSchema);
De data die wordt opgehaald wordt opgeslagen in de const allUsers. Daarna wordt de firstUser gedefinieerd door allUser[0] te doen. En daarna wordt de userID gedefinieerd. Dit is dan allUsers[0].id. Oftewel het unieke id dat de user heeft gekregen in de database.
Op de homepagina wordt dan de informatie van de firstUser die er op dat moment is getoond.
<%- include('./layouts/main.ejs'); %>
<%- include('partials/header.ejs'); %>
<img class="profilepicture" src="<%- firstUser.img %>" alt="Girl eating McDonalds">
<h3><%= firstUser.name %></h3>
<p class="info"> <%- firstUser.age %>, <%- firstUser.residence %></p>
<div class="formulier">
<%- include('partials/form.ejs'); %>
<div class="popuptext" id="LikedPopup">Yeah, likeee!</div>
</div>
<script src="../static/js/script.js"></script>
Wanneer er geen users meer zijn om te tonen dan stuur ik de gebruiker naar de pagina ‘nomorepeople’. Ik maak hierbij gebruik van de try, catch-methode. Dit houdt eigenlijk in: probeer eerst de code die in de try staat en wanneer dit een error geeft, voer dan de catch uit.
Bij de like pagina gaat het redelijk hetzelfde als bij de homepagina. Ik maak wederom gebruik van een try, catch-methode. Waarmee ik, wanneer er een error plaatsvindt, de gebruiker naar de ‘nobodyliked’ stuur. Voor de like pagina heb ik de const likedPeople. Deze const wacht op de data die er wordt verkregen met de functie findAllPeopleLiked().
async function findAllPeopleLiked() {
const data = await testingModel.find({ liked: true }).lean();
return data;
}
Hierbij worden de users gezocht waarvan liked true is. Deze data wordt dan gereturnt en opgeslagen in de const likedPeople. Op de like pagina wordt dan een lijst getoond met daarin elke user waarvan liked dus true is.
<%- include('./layouts/main.ejs'); %>
<%- include('partials/header.ejs'); %>
<h3>These are the people you liked</h3>
<p>If you don't like someone anymore, you can delete them.</p>
<ul>
<% likedPeople.forEach(function(likedPeople) { %>
<li>
<img src="<%= likedPeople.img %>">
<div>
<h4><%= likedPeople.name %></h4>
<p><%= likedPeople.age %>, <%= likedPeople.residence %></p>
<p>Favorite product: <%= likedPeople.product %></p>
</div>
<%- include('./partials/dislike-form.ejs', { userID: likedPeople.id})%>
</li>
<% }); %>
</ul>
Op de homepagina kan de gebruiker dus liken of disliken. Hierbij maak ik gebruik van twee formulieren. Een formulier voor het disliken en een formulier voor het liken.
<form id="dislike" method="POST" action="/">
<input name="liked" type="hidden" value="false">
<input name="id" type="hidden" value="<%= userID %>">
<button id="like-button" type="submit">Like</button>
</form>
<form id="like" method="POST" action= "/">
<input name="liked" type="hidden" value="true">
<input name="id" type="hidden" value="<%= userID %>">
<button id="dislike-button" type="submit">Dislike</button>
</form>
<script src="../static/js/script.js"></script>
Met het dislike form, wordt er een voor like een value van false meegegeven en er wordt bij beide formulieren het userID meegestuurd van de user die op dat moment wordt getoond. Bij het like formulier wordt er dan juist voor like een value van true meegegeven, oftewel de user wordt geliked.
Ik gebruik bij de formulier een post method. Hierbij heb ik body-parser als middleware gebruikt.
const bodyParser = require('body-parser');
app.use(bodyParser.json())
.use(urlencodedParser)
app.post('/', (req, res) => {
likedAndVisitedToTrue(req.body.id, req.body.liked);
res.redirect('/');
})
Met de post method wordt dan de functie likedAndVisitedToTrue aangeroepen en worden de id en liked values meegestuurd naar de database. Met de functie likedAndVisitedToTrue, wordt er gebruik gemaakt van de methode .findOneAndUpdate waarmee het id wordt gevonden met de values van liked en visited en de values van liked en visited worden naar true gezet.
function likedAndVisitedToTrue(id, liked) {
testingModel
.findOneAndUpdate({ id }, { $set: { liked, visited: true } })
.lean()
.then((data) => {
console.log(data);
});
}
Op de like pagina kan de gebruiker dus ook een user weer verwijderen uit de lijst, oftewel de user unliken. Hierbij maak ik weer gebruik van een formulier.
<form id="unlike" action="/like" method="POST">
<input name="liked" type="hidden" value="false">
<input name="id" type="hidden" value="<%= userID %>">
<button id="delete" type="submit">Delete</button>
</form>
Dit formulier maakt ook weer gebruik van een post method. Het formulier stuurt weer twee dingen mee, de userID en de value false van liked.
app.post('/like', (req, res) => {
unlike(req.body.id);
res.redirect('like');
})
In het formulier wordt de functie unlike aangeroepen.
function unlike(userID) {
testingModel
.findOneAndUpdate({ id: userID }, { $set: { liked: false } })
.lean()
.then((data) => {
console.log(data);
});
}
In deze functie wordt er weer gebruik gemaakt van de methode .findOneAndUpdate waarmee het id wordt gevonden met de value van liked en de value van liked wordt verandert naar false. Oftewel, de user wordt uit de lijst met users die geliked waren gehaald.
De doelen die de gebruiker had, worden dus bereikt. De gebruiker kan users liken of disliken. En de gebruiker kan users weer verwijderen uit de lijst met users die geliked zijn.