How to build a sports prediction application on the steem blockchain using Node/ExpressJS

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@gotgame·
0.000 HBD
How to build a sports prediction application on the steem blockchain using Node/ExpressJS
#### Repository
https://github.com/nodejs/node

#### What Will I Learn?
 This post marks the beginning of a series of tutorials on how you can build a prediction app that allows users to predict the outcome of sport events and post their predictions on the steem blockchain.

The application we'll be building will have the following features.

- Users will be able to login using their steem account credentials.

- A page for creating prediction tickets

- User dashboard for viewing prediction tickets by the user and other users

- Steem Wallet that allows users to transfer funds

- User Profile Page

By the end end of this tutorial we would have covered the user authentication part of the application.

#### Requirements
In order to be able to follow this tutorial the user has to be able to use the following

- HTML/CSS
- JavaScript/JQuery
- TheSportsDB public api
- AxiosJS
- NodeJS/Express
- SteemJS Api


#### Difficulty
Intermediate

#### Tutorial Content

In this post, we'll be adding the user authentication page

By the end of this post, users will be able to login to the application using their steem account details.

I am not going to cover how to setup an express application as this tutorial is not for that purpose.

However, I used `express-generator` to setup my environment. For a detailed explanation on how you can use `express-generator` to setup your environment check out [ExpressJS's official website](https://expressjs.com/en/starter/generator.html).

After everything is set up and the server is running on the default port `3000` as shown in the console

![steempredict-1.PNG](https://ipfs.busy.org/ipfs/QmPDkZ5EKk1jRTuq7WRNUKrUECA1bGKWG6d6fz8bVAUfbY)

You can navigate to `http://localhost:3000/` in your browser to confirm the server is working correctly, you should see an interface like below

![steempredict-2.PNG](https://ipfs.busy.org/ipfs/QmeZU8VvYLnTJNT8DHEFB8Tn9NZZUXgW7VQ6RJDrS3mpoZ)

We'll be using `jQuery`, HTML` and `CSS` for the front end components.

##### Steem User Authentication

Before a user can create a ticket and post it on the steem blockchain the user has to login first using their steem credentials.

To start with, in your project directory create a sub-directory `client` and in the new folder add another file `login.html`.

In the same folder add the following sub directories `js`, for JavaScript files, and `css` for CSS styles.

In the `js` folder add a file `login.js` and in the `css`directory add a file `login.css`.

In `login.html` and `login.css` add the following code to display the login form

**login.html**

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Login To SteemPredict</title>
    <link rel="stylesheet" href="./css/login.css">
</head>
<body>
    <div class="login-page">
        <div class="form">
          <form class="login-form">
            <input type="text" placeholder="username"  class="username"/>
            <input type="password" placeholder="password"  class="password"/>
            <a class="login-btn" onclick="login()">login</a>
          </form>
        </div>
      </div>

    <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
    <script src="./js/login.js"></script>
</body>
</html>
```

**login.css**

```
@import url(https://fonts.googleapis.com/css?family=Roboto:300);

.login-page {
  width: 360px;
  padding: 8% 0 0;
  margin: auto;
}
.form {
  position: relative;
  z-index: 1;
  background: #FFFFFF;
  max-width: 360px;
  margin: 0 auto 100px;
  padding: 45px;
  text-align: center;
  box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
}
.form input {
  font-family: "Roboto", sans-serif;
  outline: 0;
  background: #f2f2f2;
  width: 100%;
  border: 0;
  margin: 0 0 15px;
  padding: 15px;
  box-sizing: border-box;
  font-size: 14px;
}
.form button {
  font-family: "Roboto", sans-serif;
  text-transform: uppercase;
  outline: 0;
  background: rgb(46, 46, 45);
  width: 100%;
  border: 0;
  padding: 15px;
  color: #FFFFFF;
  font-size: 14px;
  -webkit-transition: all 0.3 ease;
  transition: all 0.3 ease;
  cursor: pointer;
}
.form button:hover,.form button:active,.form button:focus {
  background: rgb(46, 46, 45);
}
.form .message {
  margin: 15px 0 0;
  color: #b3b3b3;
  font-size: 12px;
}
.form .message a {
  color: #4CAF50;
  text-decoration: none;
}
.form .register-form {
  display: none;
}
.container {
  position: relative;
  z-index: 1;
  max-width: 300px;
  margin: 0 auto;
}
.container:before, .container:after {
  content: "";
  display: block;
  clear: both;
}
.container .info {
  margin: 50px auto;
  text-align: center;
}
.container .info h1 {
  margin: 0 0 15px;
  padding: 0;
  font-size: 36px;
  font-weight: 300;
  color: #1a1a1a;
}
.container .info span {
  color: #4d4d4d;
  font-size: 12px;
}
.container .info span a {
  color: #000000;
  text-decoration: none;
}
.container .info span .fa {
  color: #EF3B3A;
}
body {
  background: #76b852; /* fallback for old browsers */
  background: -webkit-linear-gradient(right, rgb(46, 46, 45), rgb(46, 46, 45));
  background: -moz-linear-gradient(right, rgb(46, 46, 45), rgb(46, 46, 45));
  background: -o-linear-gradient(right, rgb(46, 46, 45), rgb(46, 46, 45));
  background: linear-gradient(to left, rgb(46, 46, 45), rgb(46, 46, 45));
  font-family: "Roboto", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;      
}
```

**login.js**

```
$(document).ready(function() {
    $('.message a').click(function(){
        $('form').animate({height: "toggle", opacity: "toggle"}, "slow");
    });
})
```

If you load `login.html` in your browser you should have an interface like below

![steempredict-3.PNG](https://ipfs.busy.org/ipfs/Qma76gEKjmM5NQEReJ9qrS7oyqkxCtqrKUW9pX82gZg7oG)


After designing the interface, we are going to move on to the authentication part of the application.

Before that however, we need to add some modules to our backend.

We'll be adding the following modules to our backend

- SteemJS
- Mongoose

SteemJs will help us handle all api calls to the steem blockchain while Mongoose is a MongoDB helper that will help us create a database driven application.

Open your command line, navigate to your project root directory and run the following code to install both packages.

**SteemJS**

```
npm install steem
```

**Mongoose**

```
npm install mongoose
```

After installing both packages we can now go back to `login.js` so we can grab the form data in `login.html` to be used for logging in our steem account.

In `login.js`, add the following code to grab form data

```
function login() {
    const username = $('.username').val();
    const password = $('.password').val();

    console.log(username, password);
}
```

We need to send the form data to the backend for validation and token creation and to do that we need to add AxiosJs to our project.

AxiosJs is used for sending api requests and retrieving data through the request.

In order to use AxiosJs in our application, we need to bring it in through cdn in a `script`tag.

Add the following code in `login.html`

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>
```

This pulls in axios for use in our application.

After bringing in axios, we will now send a request to the backend to log the user in with their steem account details.

In `login.js` replace the line `console.log(username, password);` with the following 

```
 // send request with axios

    axios.post('http://localhost:3000/login', {
        username,
        password
    }).then(response => {
        console.log(response)
    }).catch(err => {
         console.log(err);
    })
```

Go back to the root directory where the backend files are located and open `app.js`.

In `app.js`, below the line `app.use('/users', usersRouter);` add the following code.

`app.post('/login', loginRouter)`

Beelow the line `var usersRouter = require('./routes/users');` add the code

```
var loginRouter = require('./routes/login');
```

We also need to include `cors` in order to enable `Cross Origin Requests`.

In the root directory console, run the code `npm install cors --save` to install `cors for usage.

In `app.js`, below the line `var logger = require('morgan');` add the following code 

```
var cors = require('cors')
```

On the line after the line `var app = express();`, add the following code 

```
app.use(cors())
```

We need to connect our application to the MongoDB database using mongoose, and to do that add the following code again below the line `var app = express();`.

```
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/steempredict', { promiseLibrary: require('bluebird') })
  .then(() =>  console.log('connection successful'))
  .catch((err) => console.error(err));
```

if you save the file and restart the server and also start up your MongoDB server you should get the following in the server console

![steempredict-6.PNG](https://ipfs.busy.org/ipfs/QmeQBPJAUzcxh85w12CigbeSRByDD4qu4csFuHtXRKyppg)


In the `routes` directory add a new file `login.js`. In the file add the following code 

```
var express = require('express');
var router = express.Router();
var steem = require('steem');

router.post('/login', function(req, res) {
    console.log(req.body)
})


module.exports = router;
```

Save all files, restart the server and reload `login.html`, if you try to log in any user now you should get something like this in your browser console.

![steempredict-4.PNG](https://ipfs.busy.org/ipfs/Qmbyox3BjMq3w7kLekm2M9HK6cJP8fAZAixHxvKAQVjNBT)

In order to log the user in using the steem account, replace `console.log(req.body)` in `login.js` with the following

```
const username = req.body.loginParam.username;
    const password = req.body.loginParam.password;

    steem.api.getAccounts([username], function(err, user){
        // store postinq wif in variable

        const pubWif = user[0].posting.key_auths[0][0];

        // check for the validity of the posting key

        if(steem.auth.isWif(password)){
            // check if the public key tallies with the private key provided

            const Valid = steem.auth.wifIsValid(password, pubWif);

            if(Valid){
                console.log("true"); 
            } else {
                console.log("false");
            }
        }
    });
```

Save all files, restart server and reload `;login.html`, if you try to login with your steem username and posting key, you should get a result like the image in the console below

![steempredict-5.PNG](https://ipfs.busy.org/ipfs/Qmd7YTY3jFwHgYkNB4MDTW6wWJzxJqqYnjZ5nxagh3sbmp)

Getting the value `true` in the console means that the user credentials has been validated successfully.

At this point we have to send a response back to the client and our response will include the following details

- A boolean value `true` indicating successful login

- A signed session token, courtesy of `json web token` which we'll be installing in a bit.

- The user details of the logged in account

In order to install `json web token` run the following command in the project root directory console

```
npm install jsonwebtoken
```

After the line `var steem = require('steem');` add the code `var jwt = require('jsonwebtoken');`

We need a config file that can store our session secret and other configurations.

In the root directory, create a new file `config.js` and add the following code

```
module.exports = {
    'secret': 'ADD YOUR SECRET HERE'
}
```

Bring the file into `login.js` by adding the following code below the line `var jwt = require('jsonwebtoken');`

```
var config = require('../config');
```

In `login.js`, replace the line `console.log(true)` with the following code 

```
// create token and store in token variable

                var token = jwt.sign({ id: user._id }, config.secret, {
                    expiresIn: 86400
                });

                // if user authentication is successful send auth confirmation, token and user data as response

                res.json({
                    auth: true,
                    token: token,
                    user: user
                });
```

If you  save the files, restart the server and try to login you should get an identical response to the image below in your browser console, provided login is successful.

![steempredict-7.PNG](https://ipfs.busy.org/ipfs/QmckK5gSfAwcWRQXqqgExh4qyfH1i2JoySvMD7NZaYKcRf)

The image above signifies successful login. To be continued.

#### Proof of Work Done

https://github.com/olatundeee/steempredict
👍 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,