Coding Journal

Jordan Vidrine

Daily Coding Journal

An experienced business owner + musician with a demonstrated history of management in the Energy sector and an insatiable appetite for learning new and complex skills. Transitioning from an ownership role & seeking employment in Web Development as a Jr Full Stack Developer.

July 14th & 15th 2019

I spent yesterday and this morning getting deeper with working with MongoDB. I really enjoy using mongoose.js to interface with the mongo database as well. I spent time implementing my own CRUD operations, sending get and post requests to my own express app on the backend.

This morning, after realizing that git version control wasnt working with my database folder for the app I am working on, I migrated my database over to MongoDB Atlas. This is a cloud database that offers a couple free tier options. I like the UI for the site as well as the ability to access the database from any computer I will be working from.

The implementation was extremely simple as well.

I am now going to go through a couple more videos from the NodeJS course. At this time I am 61% complete and I feel like I have learned a pretty large amount of tools.

I am looking forward to learning:

  1. How to authenticate users, and render certain pages depending on their user admin level.
  2. Having users be able to add information to a database and tagging that info with the user data.
  3. Getting deeper with express and mongoose middleware.

Advanced postman use

We’ve been using Postman a lot in this course. I have also begun to use it often in my own projects when learning to create an API or send requests to the back-end and getting data. We will cover some advanced topics related to getting more use out of Postman in this section.

Postman Env and Env Variables With these we can setup environments with different variables, configuring how Postman runs. This will allow us to change the variables we are going to use as URLs for post and get calls rather than having to change each request we have created in Postman.

Creating and using environments and variables in Postman is super simple and easy. Just follow the onscreen UI prompts and setup your environment with its own variables.

Ex. We can use the variable URL to point to localhost:3000 while we are developing. If the port were to change, or we want to start testing it in production, we can just change the value of URL to the new link.

Old POST method: http://localhost:3000/users

New POST method: /users

This makes things a lot more simple!

Working with Authorization Headers

We can also setup authorization that will populate to all necessary request methods in the Authorization tab. From the type dropdown (for our use) we select the inherit auth from parent option. It allows us to set the auth scheme once, and all others follow that.

We do this by editing the Authorization tab of the parent collection menu. Any request that you do not want to use can have its auth section set to No Auth. We will use a variable as an auth token so in the bearer option, we can set the token to

Setting up automation

Right now, we have multiple steps in our testing of this api. We create a user, get its auth token, then use that token to ‘login’. We can have Postman automatically do these steps for us by writing some custom javascript.

We can write scripts to perform actions before or after the request takes place. We can use this to create environment variables to be used in other requests.

The following script added to the TEST tab of a request will set an environment variable of authToken to the correct user token anytime we send a request to login.

if (pm.response.code === 200) {
    pm.environment.set('authToken', pm.response.json().token)
}

Now when we test logging in or creating a user, a token is automatically stored in the and used in the header. This saves a good bit of back and forth so I am glad the course developer added this in.

Rest of the day

I spent the rest of my coding time implementing what I’ve learned in the node course into my own app and API. I am workin on creating the ability to log in as an admin and edit data that other users will be able to submit.

I want to store the auth token as a cookie to test if the user is currently logged in. If the user is not logged in, it will log in and create a new token to save to a cookie.

Implementing Login/Admin functionality

Albeit the method of signing in as an admin is a bit haphazard at the moment, I did get my app to function in the correct way. I can now sign in on a page, navigate to localhost:3000/admin-panel, and I am authenticated using the jwt token stored as a cookie in my browser as long as I am user with admin privileges. Here is how some of that code looks.

note! - In order to use cookies in express you need to install cookie-parser with npm, and set app.use(cookie-parser)

First up, the authorization middleware:

var jwt = require('jsonwebtoken')
var User = require('../models/user')
let adminAuth = async (req,res,next) => {
  try {
    // getting the cookie from the browser, or header
    let token = req.cookies.drawingToken;
    // decoding the cookie
    let decoded = jwt.verify(token, 'secret token goes here')
    // using token to find a user with the id stored in the token, and verfying the user has been issued that token
    let user = await User.findOne({ _id: decoded._id, admin: true, 'tokens.token': token })

    if (!user) {
      throw new Error
    }

    req.user = user;
    req.token = token;

    next();
  } catch (e) {
    res.status(401).send('Could not authenticate')
  }
}
module.exports = adminAuth;

This compares the cookie stored in the browser and decodes it. If this cookie has an id stored to it that matches a user, and that users tokens array in the database includes the token, AND that user is also specified as an admin, the auth function completes, saving the user and token to the req object for later access, and moves onto the next() function in sequence.

Next up is the route method:

router.get('/admin-panel', adminAuth, async (req,res) => {
  res.render('admin-panel', {
    title: 'Drawing Prompt Admin Panel'
  });
})

Since this only runs if the adminAuth was successful, the route will render the admin-panel page to the user. On this page the admin will be able to modify all entered data that is currently stored in the database.

In order to approve and disapprove data entered by Users I want and admin to be able to look at all of the data users have entered. The following function will run on the admin page and render only un-approved data for an admin to look at.

let list = document.getElementById('prompt-list');

let promptsHtml;

let getPrompts = () => {
  let prompts = [];
  fetch('http://localhost:3000/prompts').then( async (response) => {
    let data = await response.json();
    data.forEach(prompt => prompts.push({description: prompt.description, approved: prompt.approved}))
    debugger;
    let filteredPrompts = prompts.filter(prompt => prompt.approved !== true)
    promptsHtml = filteredPrompts.reduce((acc,current) => {
      acc = acc + `<li>${current.description}<input type="checkbox"></li>`
      return acc;
    },'')
    list.innerHTML = promptsHtml;
  })
}
getPrompts();

Thats it for today! Heading to the beach this week. I will still work a bit on coding while there, hopefully from the balcony overlooking the gulf!

Back to blog...