diff options
Diffstat (limited to 'csci4131/hw6')
-rw-r--r-- | csci4131/hw6/strap012_hw6/README.txt | 2 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/api/utilities.js | 48 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/create_accounts_table.js | 41 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/create_contacts_table.js | 44 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/dbio.js | 74 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/index.js | 109 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/insert_into_accounts_table.js | 45 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/login.html | 48 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/package.json | 18 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/public/addContact.html | 106 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/public/stock.html | 124 | ||||
-rw-r--r-- | csci4131/hw6/strap012_hw6/public/welcome.html | 53 |
12 files changed, 712 insertions, 0 deletions
diff --git a/csci4131/hw6/strap012_hw6/README.txt b/csci4131/hw6/strap012_hw6/README.txt new file mode 100644 index 0000000..e056441 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/README.txt @@ -0,0 +1,2 @@ +username: charlie +password: tango
\ No newline at end of file diff --git a/csci4131/hw6/strap012_hw6/api/utilities.js b/csci4131/hw6/strap012_hw6/api/utilities.js new file mode 100644 index 0000000..65a087f --- /dev/null +++ b/csci4131/hw6/strap012_hw6/api/utilities.js @@ -0,0 +1,48 @@ +const express = require('express')
+const db = require ('../dbio')
+const router = express.Router()
+router.use(express.urlencoded({ extended: true }))
+
+router.get('/contacts', function (req, res) {
+ db.getContacts().then(function(table) {
+ res.send(table)
+ });
+});
+
+router.post('/login', async function(req, res) {
+ var loginInfo = req.body;
+ var login = loginInfo.login;
+ var pwd = loginInfo.password;
+ let rows = [];
+
+ // Query the database tbl_login with login and hashed password
+ db.query(login, pwd).then(function(rows) {
+ // Provided there is no error, and the results set is assigned to a variable named rows:
+ if (rows.length >= 1) {// the length should be 0 or 1, but this will work for now
+ //success, set the session, return success
+ req.session.user = login;
+ res.json({ status: 'success' });
+ } else {
+ res.json({ status: 'fail' });
+ }
+ });
+
+});
+
+router.get('/logout', function(req, res) {
+ if(!req.session.user) {
+ res.send('Session not started, can not logout!');
+ } else {
+ req.session.destroy();
+ res.redirect('/login');
+ }
+});
+
+router.post('/addContact', function(req, res) {
+ var contact = req.body;
+ db.addContact(contact).then(function() {
+ res.redirect('/contacts');
+ });
+});
+
+module.exports = router;
diff --git a/csci4131/hw6/strap012_hw6/create_accounts_table.js b/csci4131/hw6/strap012_hw6/create_accounts_table.js new file mode 100644 index 0000000..61b2602 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/create_accounts_table.js @@ -0,0 +1,41 @@ +/* +TO DO: +----- +READ ALL COMMENTS AND REPLACE VALUES ACCORDINGLY +*/ + +const mysql = require("mysql"); + +const dbCon = mysql.createConnection({ + host: "cse-mysql-classes-01.cse.umn.edu", + user: "C4131S21U83", // replace with the database user provided to you + password: "6919", // replace with the database password provided to you + database: "C4131S21U83", // replace with the database user provided to you + port: 3306 +}); + +console.log("Attempting database connection"); +dbCon.connect(function (err) { + if (err) { + throw err; + } + console.log("Connected to database!"); + + const sql = `CREATE TABLE tbl_accounts ( + acc_id INT NOT NULL AUTO_INCREMENT, + acc_name VARCHAR(20), + acc_login VARCHAR(20), + acc_password VARCHAR(200), + PRIMARY KEY (acc_id) + )`; + + console.log("Attempting to create table: tbl_accounts"); + dbCon.query(sql, function (err, result) { + if (err) { + throw err; + } + console.log("Table tbl_accounts created"); + }); + + dbCon.end(); +}); diff --git a/csci4131/hw6/strap012_hw6/create_contacts_table.js b/csci4131/hw6/strap012_hw6/create_contacts_table.js new file mode 100644 index 0000000..bcad389 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/create_contacts_table.js @@ -0,0 +1,44 @@ +/* +TO DO: +----- +READ ALL COMMENTS AND REPLACE VALUES ACCORDINGLY +*/ + +const mysql = require("mysql"); + +const dbCon = mysql.createConnection({ + host: "cse-mysql-classes-01.cse.umn.edu", + user: "C4131S21U83", // replace with the database user provided to you + password: "6919", // replace with the database password provided to you + database: "C4131S21U83", // replace with the database user provided to you + port: 3306 +}); + +console.log("Attempting database connection"); +dbCon.connect(function (err) { + if (err) { + throw err; + } + console.log("Connected to database!"); + + const sql = `CREATE TABLE tbl_contacts ( + contact_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(30), + category VARCHAR(40), + location VARCHAR(300), + contact_info VARCHAR(200), + email VARCHAR(30), + website VARCHAR(300), + website_url VARCHAR(300) + )`; + + console.log("Attempting to create table: tbl_contacts"); + dbCon.query(sql, function (err, result) { + if (err) { + throw err; + } + console.log("Table tbl_accounts created"); + }); + + dbCon.end(); +}); diff --git a/csci4131/hw6/strap012_hw6/dbio.js b/csci4131/hw6/strap012_hw6/dbio.js new file mode 100644 index 0000000..302334b --- /dev/null +++ b/csci4131/hw6/strap012_hw6/dbio.js @@ -0,0 +1,74 @@ +var mysql = require("mysql"); +var bcrypt = require("bcrypt"); + +var connection = mysql.createConnection({ + host: "cse-mysql-classes-01.cse.umn.edu", + user: "C4131S21U83", + password: "6919", + database: "C4131S21U83", + port: 3306 +}); + +connection.connect(function(err) { + if (err) { + throw err; + }; + console.log("Connected to MYSQL database!"); +}); + +function passcheck(user,pass) { + return new Promise(function(resolve, reject) { + connection.query('SELECT * FROM tbl_accounts', function(err, rows, fields) { + let ret = []; + if (err) { + return reject(err); + } + for (var i = 0; i < rows.length; i++) { + if (rows[i].acc_login.localeCompare(user) === 0) { + if (bcrypt.compareSync(pass, rows[i].acc_password)) { + ret += rows[i]; + } + } + } + resolve(ret); + }); + }); +} + +function getContacts() { + return new Promise (function(resolve, reject) { + let conTab = [] + connection.query('SELECT * FROM tbl_contacts', function (err, rows, fields) { + if (err) { + return reject(err); + } + resolve(rows); + }); + }); +} + +function addContacts(contact) { + let newCon = { + name: contact.name, + category: contact.category, + location: contact.location, + contact_info: contact.contact, + email: contact.email, + website_url: contact.website_name, + } + return new Promise(function(resolve, reject) { + connection.query('INSERT tbl_contacts SET ?', newCon, function (err, result) { //Parameterized insert + if (err) throw err; + console.log("Values inserted"); + resolve(); + }); + }); + +} + + + + +exports.addContact = addContacts; +exports.query = passcheck; +exports.getContacts = getContacts; diff --git a/csci4131/hw6/strap012_hw6/index.js b/csci4131/hw6/strap012_hw6/index.js new file mode 100644 index 0000000..851b096 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/index.js @@ -0,0 +1,109 @@ +// YOU CAN USE THIS FILE AS REFERENCE FOR SERVER DEVELOPMENT +const createError = require('http-errors'); + +// Include the express module +const express = require('express'); + +// helps in extracting the body portion of an incoming request stream +var bodyparser = require('body-parser'); + +// Path module - provides utilities for working with file and directory paths. +const path = require('path'); + +// Helps in managing user sessions +const session = require('express-session'); + +// include the mysql module +var mysql = require('mysql'); + +// Bcrypt library for comparing password hashes +const bcrypt = require('bcrypt'); + +// Include the express router. +const utilities = require('./api/utilities'); + +const port = 9001; + +// create an express application +const app = express(); + +// Use express-session +// In-memory session is sufficient for this assignment +app.use(session({ + secret: "csci4131secretkey", + saveUninitialized: true, + resave: false + } +)); + +// middle ware to serve static files +app.use(express.static(path.join(__dirname, 'public'))); + +// server listens on port for incoming connections +app.listen(port, () => console.log('Listening on port', port)); + +app.get('/', function (req, res) { + res.sendFile(path.join(__dirname, 'public/welcome.html')); +}); + +// GET method route for the contacts page. +// It serves contact.html present in public folder +app.get('/contacts', function(req, res) { + if(!req.session.user) { + res.redirect('/login'); + } else { + res.sendFile(path.join(__dirname, 'public/contacts.html')); + } +}); + +app.get('/stocks', function(req, res) { + res.redirect('/stock'); +}) + +app.get('/stock', function (req, res) { + if (!req.session.user) { + res.redirect('/login'); + } else { + res.sendFile(path.join(__dirname, 'public/stock.html')); + } +}); + +app.get('/addContact', function (req, res) { + if (!req.session.user) { + res.redirect('/login'); + } else { + res.sendFile(path.join(__dirname, 'public/addContact.html')); + } +}); + +app.get('/login', function (req, res) { + if (req.session.user) { + res.redirect('/contacts'); + } else { + res.sendFile(path.join(__dirname, 'login.html')); + } +}); + +app.get('/logout', function(req, res) { + res.redirect('/api/logout') +}); + +// Makes Express use a router called utilities +app.use('/api', utilities); + +// function to return the 404 message and error to client +app.use(function (req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function (err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + // res.render('error'); + res.send(); +}); diff --git a/csci4131/hw6/strap012_hw6/insert_into_accounts_table.js b/csci4131/hw6/strap012_hw6/insert_into_accounts_table.js new file mode 100644 index 0000000..3157ce3 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/insert_into_accounts_table.js @@ -0,0 +1,45 @@ +/* +TO DO: +----- +READ ALL COMMENTS AND REPLACE VALUES ACCORDINGLY +*/ + +const mysql = require("mysql"); +const bcrypt = require('bcrypt'); + +const dbCon = mysql.createConnection({ + host: "cse-mysql-classes-01.cse.umn.edu", + user: "C4131S21U83", // replace with the database user provided to you + password: "6919", // replace with the database password provided to you + database: "C4131S21U83", // replace with the database user provided to you + port: 3306 +}); + +console.log("Attempting database connection"); +dbCon.connect(function (err) { + if (err) { + throw err; + } + + console.log("Connected to database!"); + + const saltRounds = 10; + const myPlaintextPassword = 'tango'; // replace with password chosen by you OR retain the same value + const passwordHash = bcrypt.hashSync(myPlaintextPassword, saltRounds); + + const rowToBeInserted = { + acc_name: 'charlie', // replace with acc_name chosen by you OR retain the same value + acc_login: 'charlie', // replace with acc_login chosen by you OR retain the same value + acc_password: passwordHash + }; + + console.log("Attempting to insert record into tbl_accounts"); + dbCon.query('INSERT tbl_accounts SET ?', rowToBeInserted, function (err, result) { + if (err) { + throw err; + } + console.log("Table record inserted!"); + }); + + dbCon.end(); +}); diff --git a/csci4131/hw6/strap012_hw6/login.html b/csci4131/hw6/strap012_hw6/login.html new file mode 100644 index 0000000..9bb80cc --- /dev/null +++ b/csci4131/hw6/strap012_hw6/login.html @@ -0,0 +1,48 @@ +<html> + +<head> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <script src="https://code.jquery.com/jquery-2.2.4.min.js"integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> +</head> + +<body> + <div class="jumbotron" style="background: DarkSeaGreen !important"> + <h1>Login Page</h1> + <div id="error"></div> + <br><br> + <form id="myForm" name="myForm" style="list-style-type:none"> + <div> + <label for="login">login:</label> + <input type="text" id="login" name="login" required> + </div> + <div> + <label for="password">password:</label> + <input id="password" name="password" type="password" required> + </div> + <input type="submit"value="Submit!"> + </form> + </div> + <script> + //jQuery below. Tread with caution as sneezing near here may rupture the fabric of reality. + $(document).ready(function () { + $('#myForm').submit(function (event) { + event.preventDefault();//collect the form data using Id Selector for whatever data you need to send to server + let login=$('#login').val(); + let password=$('#password').val(); + $.post('api/login', + {"login": login,"password": password}, + (data) => { + if(data.status === 'success'){ + //pseudo code + //Make sure error message is not displayed + //Re-direct to contacts page, + window.location.href='contacts';} + else{ + //Display error message + $('#error').html("<b>Login failed. Please try again.</b>") + }}); + }); + });</script> + +</html> diff --git a/csci4131/hw6/strap012_hw6/package.json b/csci4131/hw6/strap012_hw6/package.json new file mode 100644 index 0000000..db9cf8f --- /dev/null +++ b/csci4131/hw6/strap012_hw6/package.json @@ -0,0 +1,18 @@ +{ + "name": "strap012_hw6", + "version": "1.0.0", + "description": "Assignment 6", + "main": "index.js", + "scripts": { + "test": "node index.js" + }, + "author": "strap012", + "license": "ISC", + "dependencies": { + "bcrypt": "^5.0.1", + "body-parser": "^1.19.0", + "express": "^4.17.1", + "express-session": "^1.17.1", + "mysql": "^2.18.1" + } +} diff --git a/csci4131/hw6/strap012_hw6/public/addContact.html b/csci4131/hw6/strap012_hw6/public/addContact.html new file mode 100644 index 0000000..629f9b2 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/public/addContact.html @@ -0,0 +1,106 @@ +<!doctype html>
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+ </head>
+
+ <body>
+ <nav class="navbar navbar-default">
+ <div class="container-fluid">
+ <ul class="nav navbar-nav">
+ <li><a href="/"><b>Home</b></a></li>
+ <li><a href="contacts"><b>Contacts</b></a></li>
+ <li><a href="addContact"><b>Add Contact</b></a></li>
+ <li><a href="stock"><b>Stock Page</b></a></li>
+ <li><a href="logout"><b>Logout</b></a></li>
+ </ul>
+ </div>
+ </nav>
+ <br><br>
+
+ <div class="container">
+ <div class="row">
+ <p><br /></p>
+ </div>
+
+ <div class="row">
+ <div class="col-md-4"></div>
+ <div class="col-md-4">
+ <div class="panel panel-default">
+ <form name="addContact" method="post" action="/api/addContact">
+ <p></p>
+ <table class="table table-bordered table-hover">
+ <tbody>
+ <tr>
+ <td class="col-md-6">Name</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <input type="text" class="form-control" name="name" required>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6">Category</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <select class="form-control" name="category">
+ <option>Personal</option>
+ <option>Academic</option>
+ <option>Industry</option>
+ </select>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6">Location</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <input type="text" class="form-control" name="location" required>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6">Contact Information</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <input type="text" class="form-control" name="contact" required>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6">Email</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <input type="email" class="form-control" name="email" required>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6">Website Name</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <input type="url" class="form-control" name="website_name" required maxlength="100">
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td class="col-md-6"></td>
+ <td class="col-md-6">
+ <input type="submit" value="Submit">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </form>
+ </div>
+ </div>
+ <div class="col-md-4"></div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/csci4131/hw6/strap012_hw6/public/stock.html b/csci4131/hw6/strap012_hw6/public/stock.html new file mode 100644 index 0000000..d63b233 --- /dev/null +++ b/csci4131/hw6/strap012_hw6/public/stock.html @@ -0,0 +1,124 @@ +<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+ <style>
+ pre {
+ max-height: 12em;
+ }
+ textarea {
+ width: 100%;
+ min-height: 30rem;
+ background-color: black;
+ font-family: "Lucida Console", Monaco, monospace;
+ font-size: 0.75 rem;
+ line-height: 1.2;
+ color: #fff;
+ }
+ </style>
+</head>
+
+<body>
+ <nav class="navbar navbar-default">
+ <div class="container-fluid">
+ <ul class="nav navbar-nav">
+ <li><a href="/"><b>Home</b></a></li>
+ <li><a href="contacts"><b>Contacts</b></a></li>
+ <li><a href="addContact"><b>Add Contact</b></a></li>
+ <li><a href="stock"><b>Stock Page</b></a></li>
+ <li><a href="logout"><b>Logout</b></a></li>
+ </ul>
+ </div>
+ </nav>
+ <br><br>
+
+ <div class="container">
+ <div class="panel panel-default">
+ <div class="panel-body"><center>Welcome to Stock Page</center></div>
+ </div>
+ </div>
+
+ <div class="container">
+ <div class="row">
+ <div class="col">
+ <table class="table table-bordered table-hover">
+ <tbody>
+ <tr>
+ <td class="col-md-6">Company</td>
+ <td class="col-md-6">
+ <div class="form-group">
+ <select id="Company" name="Company">
+ <option value="GME">Gamestop</option>
+ <option value="MSFT">Microsoft</option>
+ <option value="BA">Boeing Company</option>
+ <option value="AAPL">Apple Inc</option>
+ <option value="AMZN">Amazon</option>
+ <option value="NVDA">NVIDIA Corporation</option>
+ </select>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <button type="button" onclick="Click()">Get Data</button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <div id="chartContainer"></div>
+ </div>
+
+ <div class="container">
+ <table class="table" id="StockData">
+ <thead>
+ <tr>
+ <th scope="col" id="meta">Company-MetaData</th>
+ <th scope="col" id="Time">Stock-Info</th>
+ </tr>
+ </thead>
+ <pre>
+ <tbody></tbody>
+ </pre>
+ </table>
+ </div>
+
+ <script>
+ function Click() {
+ var comp = document.getElementById("Company").value;
+ var xmlhttp = new XMLHttpRequest();
+ var url = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=" + comp + "&apikey=8MWSNPDWKH0BTBH2";
+ xmlhttp.onreadystatechange = function () {
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
+ var parse = JSON.parse(xmlhttp.responseText);
+ var table = document.getElementById("StockData").getElementsByTagName("tbody")[0];
+ var row = table.insertRow();
+ for (var i in parse) {
+ var cell = row.insertCell();
+ cell.innerHTML = "<pre>" + JSON.stringify(parse[i], undefined, 2) + "</pre>";
+ }
+ }
+ }
+ xmlhttp.open("GET", url, true);
+ xmlhttp.send();
+
+ }
+ /* TODO:
+ / Bonus 1. Request the TIME_SERIES_DAILY endpoint of alphavantage API
+ / for the company selected in the dropdown. Display the JSON
+ / in the result according to the write up.
+ / Bonus 2. Take the JSON from the alphavantage API and chart it to a
+ / line chart using Chart.js to the chartContainer div. Ensure
+ / the chart meets all requirements from the HW writeup.
+ /*/
+ </script>
+</body>
+</html>
diff --git a/csci4131/hw6/strap012_hw6/public/welcome.html b/csci4131/hw6/strap012_hw6/public/welcome.html new file mode 100644 index 0000000..095023e --- /dev/null +++ b/csci4131/hw6/strap012_hw6/public/welcome.html @@ -0,0 +1,53 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <title>Welcome to Node.js</title> + <style type="text/css"> + .jumbotron { + text-align: center; + } + </style> +</head> + +<body> +<div class="jumbotron" style="background: DarkSeaGreen !important"> + <h1>Welcome to Express (Node.js)</h1> + <p>The objective of this assignment is to develop a basic website with:</p> + <p><b>Express</b> which is a Node.js web application framework.</p> + <br/> + <p>Following are some useful resources:</p> + + <ul style="list-style-type:none"> + <li><a href="https://expressjs.com/">Express website</a></li> + <li><a href="https://expressjs.com/en/starter/installing.html">Express installation</a></li> + <li><a href="https://expressjs.com/en/starter/hello-world.html">Hello world example</a></li> + <li><a href="https://expressjs.com/en/starter/basic-routing.html">Basic routing</a></li> + <li><a href="https://expressjs.com/en/starter/static-files.html">Serving static files in Express</a></li> + <li><a href="https://expressjs.com/en/starter/faq.html">FAQ</a></li> + <li><a href="https://expressjs.com/en/guide/routing.html">Routing</a></li> + <li><a href="https://expressjs.com/en/4x/api.html">API Reference</a></li> + <li><a href="https://expressjs.com/en/resources/books-blogs.html">Books and blogs</a></li> + <li><a href="https://docs.npmjs.com/getting-started/what-is-npm">NPM introduction</a></li> + </ul> + + <br/> + <br/> + +</div> + +<div class="row"> + <div class="col-md-1"></div> + <div class="col-md-10"> + <button id="myButton" type="button" class="btn btn-primary btn-block" onclick="location.href ='/login'"> + Navigate to website + </button> + </div> + <div class="col-md-1"></div> +</div> +</body> +</html> |