Design rationale - EmileKost/Discover Wiki

Debriefing

Opdrachtomschrijving

De aanleiding van deze opdracht is dat veel mensen na het afronden van hun opleiding niet een duidelijk beeld hebben van een baan die zij zoeken en wat zij zelf willen. De doelstelling van dit project is dat de gebruikers een beter beeld van hun persoonlijkheid krijgen. Aan de hand van de persoonlijkheidstest krijgt de gebruiker een overzichtelijke lijst van passende vacatures (disc model). Eventueel waar nodig worden vervolgstappen aangeboden zoals omscholingsopties. Ook is nog een doel dat bedrijven kunnen zoeken naar relevante kandidaten. Wij werken samen met de CMD Agency, zij hebben al vooronderzoek gedaan en aan de hand daar van gaan zij uiteindelijk een ontwerp aan ons presenteren. Wij gaan dan kijken in hoeverre dat haalbaar is met betrekking tot de technische functionaliteiten. Aan ons is nu de taak om te experimenteren met de technische functionaliteiten. Wij gaan prototypes maken en op basis van iteraties dit uiteindelijk toepassen op de website. De eindgebruikers zijn werkzoekenden die niet goed weten wat voor baan zij zoeken, en werkgevers die op zoek zijn naar nieuwe werknemers.  

Randvoorwaarden

  • Aantrekkelijke website ontwerpen
  • Data ophalen van vacatures en bedrijven
  • Persoonlijkheidstest
  • Persoonlijke vacatures aan de hand van persoonlijkheidstest

Samenvatting uiteindelijke werking van de website

Functionaliteiten

Profiel aanmaken

Gebruikers worden bij hun eerste bezoek van de website meteen doorverwezen naar de login pagina. Het is niet mogelijk om de website te gebruiken zonder account. Hier kan een gebruiker een profiel aanmaken voor een persoonlijke ervaring op de website. Het profiel is ook noodzakelijk om andere data van de website op te slaan, voor volgende bezoeken van de gebruiker.

Inloggen

Als een gebruiker de website al eerder heeft bezocht kan hij inloggen met zijn account. Wanneer je niet uitlogt blijf je automatisch op je eigen account de website gebruiken bij latere bezoeken.

Vacatures bekijken

Op de homepagina van de website kan de gebruiker uitgelichte vacatures bekijken. Hier staan een aantal vacatures onder elkaar. Ook zit er bij elke vacature een detailpagina met extra informatie, en een button om te solliciteren, en op te slaan in favorieten.

Vacatures zoeken

Boven in de header staat een zoekfunctie waarmee de gebruiker kan zoeken naar vacatures. Dit is erg handig voor gebruikers die al weten waaar ze naar opzoek zijn.

Vacatures toevoegen aan favorieten

Als een gebruiker een vacature wilt opslaan om later te bekijken/onthouden kan hij deze toevoegen aan favorieten. Dit wordt dan verstuurt naar de database zodat het opgeslagen staat.

DISC persoonlijkheidstest

Voor gebruiker die nog niet zo goed weten waar ze naar opzoek zijn is de DISC test. Na het doen van deze test krijgt de gebruiker een uitslag van karaktereigenschappen.

Vacatures adhv DISC test (prototype)

Na het doen van de DISC test krijgt de gebruiker resultaten met overeenkomsten van verschillende DISC categorieën. Aan de hand deze resultaten krijgt hij dan relevante vacatures te zien.

Code bij functionaliteiten

Profiel aanmaken

De eerste functionaliteit is de registreer functie. De gebruiker kan bij het registeren zijn naam, email en een zelf bedacht wachtwoord invullen. Deze informatie wordt gekoppeld aan een uniek gebruikers ID. Deze data wordt opgeslagen in een Mongodb collection genaamd Blogs. Doormiddel van Bcrypt en Passport kon de registreer functionaliteit worden ontwikkeld.

app.post('/register', checkNotAuthenticated, async (req, res) => {
  try {
    const hashedPassword = await bcrypt.hash(req.body.password, 10)

    //This is the required data that has to be stored in mongodb
    const blog = new Blog({
      name: req.body.name,
      email: req.body.email,
      password: hashedPassword,
    })
    
    //Saves user account data in mongodb, password is still secure and encrypted
    blog.save()
      .then((result) => {
        console.log(result)
      })
      .catch((err) => {
        console.log(error)
      })

    res.redirect('/login')
  } catch {
    res.redirect('/register')
  }
})

Bij de app.post van de /register route wordt het registreer formulier gesubmit. Wij hebben hier een try statement gebruikt zodat tijdens het uitvoeren van de code, er tegelijkertijd wordt gezocht naar errors. Als er geen errors worden gevonden worder allereerst een variabele aangemaakt voor hashedPassword. Dit is door middel van Bcrypt een encrypted wachtwoord geworden. In de functie wordt er een nieuwe blog aangemaakt. Blog is in dit geval het datamodel van de collectie blogs. De blogs collectie is voor het maken van een account. Omdat er een nieuwe gebruiker wordt aangemaakt hebben we gebruik gemaakt van new Blog zodat Mongoose weet dat er een nieuw dataobject zal worden toegevoegd. Door middel van body parser kunnen wij heel gemakkelijk de waardes ophalen door middel van req.body.name. Als de data aan het model is toegevoegd wordt door middel van de .save() methode de data opgeslagen en toegevoegd aan de database. De gebruiker wordt doorverwezen naar de inlogpagina.

Inloggen

Als de gebruiker eenmaal een account heeft, komt deze op de inlog pagina terecht. Hier kan die zijn email en wachtwoord invullen om zo toegang te krijgen tot de vacaturebank.

app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
  successRedirect: '/',
  failureRedirect: '/login',
  failureFlash: true
}))

In de app.post wordt de functie checkNotAuthenticated en passport.authenticate meegegeven. Als uit deze functie blijkt dat de gegevens kloppen, dan is er sprake van een succesRedirect. De gebruiker zal dan doorverwezen worden naar de index pagina.

Passport-config.js Deze functie hoort nog bij het inloggen, en is eigenlijk de functie die controleert of de juiste gegevens zijn ingevuld. Waar nodig zal deze functie de juiste foutmelding geven om de gebruiker te begeleiden.


const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const Blog = require('./models/blog.js');

module.exports = function(passport) {
    passport.use(
        new LocalStrategy({usernameField : 'email'},(email,password,done)=> {
                //match user
                Blog.findOne({email : email})
                .then((user)=>{
                 if(!user) {
                     return done(null,false,{message : 'that email is not registered'});
                 }
                 //match pass
                 bcrypt.compare(password,user.password,(err,isMatch)=>{
                     if(err) throw err;

                     if(isMatch) {
                         return done(null,user);
                     } else {
                         return done(null,false,{message : 'pass incorrect'});
                     }
                 })
                })
                .catch((err)=> {console.log(err)})
        })
        
    )
    passport.serializeUser(function(user, done) {
        done(null, user.id);
      });
      
      passport.deserializeUser(function(id, done) {
        Blog.findById(id, function(err, user) {
          done(err, user);
        });
      }); 
}; 

Allereerst wordt het email gecontroleerd. Als dit voltooid is, dan zal het wachtwoord worden vergeleken door middel van bcrypt. Als deze functie voltooid is, dan zal in de app.post de gebruiker worden doorverwezen naar de juiste pagina. Bij succes de indexpagina.

Renderen van vacatures op de index pagina

De eerste functionaliteit die er is na he succesvol inloggen is dat alle vacatures uit de database worden opgehaald. Deze worden allemaal op de index pagina gerenderd door middel van ejs.

Vacatures bekijken

const Offers = require('./models/joboffers.js');

app.get('/', checkAuthenticated, async (req, res, next) => {

    Offers.find((err, docs) => {
      if(!err) {
        res.render('index', {
          data: docs,
          name: req.user.name
        })
      } else {
        console.log('Failed to retrieve data')
      }
    })
})

In de app.get van de index route wordt er een async functie uitgevoerd omdat we hier werken met data. Offers is de collectie waar alle vacatures in zijn te vinden. Omdat we alle vacatures willen renderen hebben we gebruik gemaakt van .find((err,docs) zodat alle documenten en eventuele errors worden opgehaald. Het if statement zorgt er voor dat als er geen error uitkomt dat dan de index pagina moet worden gerenderd. Bij het renderen geven wij een object mee die de vacatures meegeeft aan data, en de gebruikersnaam aan name. De checkAuthenticated functie zorgt ervoor dat je de naam van de gebruiker kan ophalen.

Vacatures zoeken

Naast het renderen van de vacatures moet de gebruiker ook de mogelijkheid krijgen om te zoeken naar vacatures. In de app.post wordt de value van de zoekbalk opgehaald door middel van body parser. Na het ophalen van de zoekopdracht wordt er door middel van Regex gezocht in de Offers collectie naar een vergelijkende tekst. Regex maakt het mogelijk om eenvoudig een woord of een deel daarvan stap voor stap te vergelijken met data. Omdat dit een promise is wordt in de .then de response meegegeven. Na het voltooien van de zoekopdracht wordt de indexpagina opnieuw gerenderd waarbij een object wordt meegegeven met de resultaten van de zoekopdracht en de gebruikersnaam.

app.post('/', checkAuthenticated, async (req, res) => {
  const input = req.body.search;
  console.log(input);
  let search = await Offers.find({title: {$regex: new RegExp('^' + input + '.*', 'i')}}).exec()
   .then(response => {
     console.log(response)
     res.render('index', {data: response, name: req.user.name})
   })
})

Vacatures toevoegen aan favorieten

Het moet voor de gebruiker mogelijk zijn om vacatures op te slaan, zodat deze later terug kunnen worden bekeken. Wij hebben dit gerealiseerd door een veld in het user data model toe te voegen die een array opslaat. In deze array kunnen de objectId's van de opgeslagen vacatures worden gepusht zodat deze later weer kunnen worden gerenderd.

app.post('/:id', checkAuthenticated, (req, res) => {
  const user = req.user.id;
  const offerId = req.params.id;
  
  Blog.findOneAndUpdate({
    _id: user
  }, {
    $push: {
      favorites: offerId
    }
  })
  .then((result) => {
    console.log(result)
    res.redirect('profile')
  })
})

In de app.post van de detailpagina speciaal voor de juiste vacature wordt allereerst weer het user id opgevraagd. Daarna wordt het objectId van de vacature opgevraagd door middel van req.params.id. Dit zorgt ervoor dat het id in de url wordt gepakt, wat weer gelijk staat aan het objectId van de vacature. Omdat we zoeken naar bestaande data hebben wij findOneAndUpdate gebruikt om zo data toe te voegen. Het is is gelijk gezet aan user en door middel van $push wordt het offerId aan het juiste user model toegevoegd. De gebruiker wordt doorverwezen naar de profiel pagina omdat daar de favoriete vacatures zichbaar zullen zijn.

DISC persoonlijkheidstest

Ik heb elk antwoord één of meerdere classes toegewezen, voor de bijbehorende categorie van het DISC model. Vervolgens kan je dan met JS alle input radio selecteren met een class van Dominant Interactief Stabiel of Consciëntieus. Ik had online wat onderzoek gedaan naar hoe ik de persoonlijkheidstest met radio buttons kon maken. Daaruit kwam het .checked element. Hiermee kan je nalopen of een checkbox of radiobutton geselecteerd is door de gebruiker. Door een forEach te gebruiken met .checked kon ik alle radiobuttons nalopen. Vervolgens heb ik een if statement gemaakt voor wanneer de radio button gechecked is, om de counter +1 te geven aan de bijbehorende variabele.

Vacatures adhv DISC test

Eindproduct

Gebruikers van vacaturebanken kijken vaak even snel op een mobiel, of grondiger op een desktop of tablet. Vandaar dat het belangrijk is dat de hele website responsive is, en op elk formaat scherm goed te gebruiken.

Log in pagina

Register pagina

Home pagina

Detail pagina vacatures

DISC test pagina

Profiel pagina