Rundown of all of the code within our website (First version..Different to final version) - Alna132/GO-Group-Web-App GitHub Wiki

Finally deciding on the layout of our HTML Page called Test.Html:

  1. We backtracked from using Macaron as we were having issues with getting the CSS to show up. We instead used Angular JS by placing 'ng-app' within the HTML tag to allow HTML to become the route element for AngularJS. All AngularJS applications must have a root element. Only one instance allowed, if there are more than one instances included then the first one will be used.
<html ng-app>
  1. To use a template from Bootstrap you include a link to it within the head tags in your HTML page:
<head>
	<title>WorkTracker</title>
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head> 
  1. After a few attempts on getting the layout right we decided to display a header and a welcome message first:
<body>
	<!-- Main jumbotron for a primary marketing message or call to action -->
    <div class="jumbotron">
      <!--Changed the top header here to include a name being entered and shown back to the user with a friendly hello-->
      <div class="container">
        <h2><input type="text" placeholder="Your Name here" ng-model="yes"></h2>
		      <h3><p>Hello <span ng-bind="yes"></span></p></h3>
        <p>This is a place where you can record all of your daily duties in one place, ready to show the boss. </p>
      </div>
    </div>
  1. As you can see we use a placeholder which includes a hint for the user on what to write into the textbox. We use Angular here to bind to the page what the user writes into the textbox using ng-model and ng-bind.

  2. We then add a navbar, fixed to the top of the page. We include the title of the webapp (WorkTracker) using navbar-brand and then we use the navbar form controls to include a Username and Password textbox with a Login button. The Login button is of type "btn-success" to give it it's green colour.

<nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Work Tracker</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <form class="navbar-form navbar-right">
            <div class="form-group">
              <input type="text" placeholder="Email" class="form-control">
            </div>
            <div class="form-group">
              <input type="password" placeholder="Password" class="form-control">
            </div>
            <button type="submit" class="btn btn-success">Sign in</button>
          </form>
        </div><!--/.navbar-collapse -->
      </div>
    </nav>
  1. We then include a dropdown list to display our different Tradesmen's jobs:
<div class="row">
        <div class="col-md-4">
          <h2>Job Title</h2>
          <!-- Dropdown list with Tradesperson's job titles
  adapted from https://www.socketloop.com/tutorials/golang-populate-dropdown-with-html-template-example -->
          <select>
    <option value="Beautician">Beautician</option>
    <option value="Builder">Builder</option>
    <option value="Carpenter">Carpenter</option>
    <option value="Cleaner">Cleaner</option>
    <option value="Delivery">Delivery</option>
    <option value="Electrician">Electrician</option>
    <option value="Farmer">Farmer</option>
    <option value="Gardener">Gardener</option>
    <option value="Hair and Beauty">Hair and Beauty</option>
    <option value="Hairdresser">Hairdresser</option>
    <option value="Mechanic">Mechanic</option>
    <option value="Painter">Painter</option>
    <option value="Plumber">Plumber</option>
    <option value="Technician">Technician</option>
    <option value="Tiler">Tiler</option>
    <option value="Transport">Transport</option>
    <option value="Other">Other</option>
 
  </select>
  1. And an "Hours Worked" dropdown list:
<!-- Code adapted from http://www.w3schools.com/html/html_form_elements.asp -->
        <div class="col-md-4">
          <h2>Hours Worked This Week</h2>
          <select name="HoursWorked">
  <option value="Less than 10 hours">Less than 10 Hours</option>
  <option value="10-15">10-15 Hours</option>
  <option value="15-20">15-20 Hours</option>
  <option value="25-30">25-30 Hours</option>
  <option value="30-40">30-40 Hours</option>
  <option value="40+">40+ Hours</option>

</select>
  1. We included our "Additional Information" textbox and added a function to send the form:
<div class="col-md-4">
          <h2>Additonal Information</h2>
          <!--Adapted from http://www.w3schools.com/tags/tag_input.asp-->
          <form action="demo_form.asp">
              <input type="text" name="AddInfo" value=""><br>
              <!--<input type="submit" value="Submit"> -->
              <button onclick="sendFunction()">Send Form</button>
    
<script>
function sendFunction() 
{
    alert("Thank you for sending us your details!");   
}
</script>    
    
<button onclick="clearFunction()">Clear</button>   
  1. Lastly, we thought it fitting to include a logo for our 'company' as a footer:
<footer>
        <p>&copy; 2016 WorkTracker, Inc.</p>
      </footer>
  1. At the bottom of our html page we include a reference to the angularjs library to be able to use it within our website:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>

The Go Code inside the class main.go in 12 steps:

  1. Inside the package main we first had to import a number of packages into our app:
package main

import (
	//"flag"
	"fmt"
	//"log" // It defines a type, Logger, with methods for formatting output. 
	"net/http"
	"github.com/gorilla/mux"
	"github.com/gorilla/securecookie"
       )
  1. We straight away use our gorilla package to handle cookies for the website:
var cookieHandler = securecookie.New(
	securecookie.GenerateRandomKey(64),
	securecookie.GenerateRandomKey(32))
  1. We then handle getting the username using these cookies for the login:
func getUserName(request *http.Request) (userName string) {
	if cookie, err := request.Cookie("session"); err == nil {
		cookieValue := make(map[string]string)
		if err = cookieHandler.Decode("session", cookie.Value, &cookieValue); err == nil {
			userName = cookieValue["name"]
		}
	}
	return userName
}
  1. We then save this username by using the http ResponseWriter to map the username string and encodes the value to store in a cookie:
func setSession(userName string, response http.ResponseWriter) {
	value := map[string]string{
		"name": userName,
	}
	if encoded, err := cookieHandler.Encode("session", value); err == nil {
		cookie := &http.Cookie{
			Name:  "session",
			Value: encoded,
			Path:  "/",
		}
		http.SetCookie(response, cookie)
	}
}
  1. Now we create a function called clearSession which we will call later to allow the user to logout of the webpage:
//Returns to indexPage and clears cookies
func clearSession(response http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   "session",
		Value:  "",
		Path:   "/",
		MaxAge: -1,
	}
	http.SetCookie(response, cookie)
}

We set the MaxAge property (the length of time the cookie has before expiring) to -1 in order to allow the page not to be cached, forcing the user to have to log back in.

  1. In order to understand how we only allow logged in users to see the content the website has to offer I need to digress: We set the non-logged in path to be "/" above. Now we specify an "Internal" page so that only the logged in user has access, We make a httpRequest for the name and password of the user and redirect them to the internal page after checking their credentials:
func loginHandler(response http.ResponseWriter, request *http.Request) {
	name := request.FormValue("name")
	pass := request.FormValue("password")
	redirectTarget := "/"
	if name != "" && pass != "" {
		// .. check credentials ..
		setSession(name, response)
		redirectTarget = "/internal"
	}
	http.Redirect(response, request, redirectTarget, 302)
}
  1. Now we use the clearSession function to handle the user logging out of the website and back to the "/" path so that the user will not have access to or see the Internal page functionality anymore:
// logout handler logs the current user out

func logoutHandler(response http.ResponseWriter, request *http.Request) {
	clearSession(response)
	http.Redirect(response, request, "/", 302)
}
  1. This is our Index page or as I said above the "/" path the non-logged-in user will see:
const indexPage = `
<!-- Incorporating some HTML -->
<h1>Login</h1>
<head>
<!-- Nav bar -->
<form class="navbar-form navbar-left">
	<title>WorkTracker</title>
	</form>
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<div class="container">
		
	</div>
	<nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Work Tracker</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
        <small>User: jjj</small>
        <form method="post" action="/login">
    <input type="text" placeholder="Name" id="name" name="name">
    <input type="password" placeholder="Password" id="password" name="password">
    <button type="submit" class="btn btn-success">Login</button>
</form>    
</div><!--/.navbar-collapse -->
</div>
</nav>
`
  1. We need to handle our Index Html code now in this next function:
func indexPageHandler(response http.ResponseWriter, request *http.Request) {
	fmt.Fprintf(response, indexPage)
}
  1. We then specify what the user will see within the internal page:
const internalPage = `
<h1>Internal</h1>
<hr>
<small>User: %s</small>
<html ng-app> <!-- 'ng-app'' placed within a tag (in this case, the HTML tag)
				allows HTML to become the route element for AngularJS.
				All AngularJS applications must have a root element. Only one instance allowed. --> 
<head>
	<title>WorkTracker</title>
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
	<!-- Main jumbotron for a primary marketing message or call to action -->
    <div class="jumbotron">
      <!--Changed the top header here to include a name being entered and shown back to the user with a friendly hello-->
      <div class="container">
        <h2><input type="text" placeholder="Your Name here" ng-model="yes"></h2>
		      <h3><p>Hello <span ng-bind="yes"></span></p></h3>
        <p>This is a place where you can record all of your daily duties in one place, ready to show the boss. </p>
      </div>
    </div>
	<div class="container">
		
	</div>
	<nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
                     <form method="post" action="/logout">
    <button type="submit" class="btn btn-success">Logout</button>
          </button>
          <a class="navbar-brand" href="#">Work Tracker</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <form class="navbar-form navbar-right">
  
</form>
          </form>
        </div><!--/.navbar-collapse -->
      </div>
    </nav>
	<div class="container">
      <!-- Example row of columns -->
      <div class="row">
        <div class="col-md-4">
          <h2>Job Title</h2>
          <!-- Dropdown list with Tradesperson's job titles
  adapted from https://www.socketloop.com/tutorials/golang-populate-dropdown-with-html-template-example -->
          <select>
    <option value="Beautician">Beautician</option>
    <option value="Builder">Builder</option>
    <option value="Carpenter">Carpenter</option>
    <option value="Cleaner">Cleaner</option>
    <option value="Delivery">Delivery</option>
    <option value="Electrician">Electrician</option>
    <option value="Farmer">Farmer</option>
    <option value="Gardener">Gardener</option>
    <option value="Hair and Beauty">Hair and Beauty</option>
    <option value="Hairdresser">Hairdresser</option>
    <option value="Mechanic">Mechanic</option>
    <option value="Painter">Painter</option>
    <option value="Plumber">Plumber</option>
    <option value="Technician">Technician</option>
    <option value="Tiler">Tiler</option>
    <option value="Transport">Transport</option>
    <option value="Other">Other</option>
 
  </select>
          <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>
<!-- Code adapted from http://www.w3schools.com/html/html_form_elements.asp -->
        <div class="col-md-4">
          <h2>Hours Worked This Week</h2>
          <select name="HoursWorker">
  <option value=">10 hours">>10 Hours</option>
  <option value="10-15">10-15 Hours</option>
  <option value="15-20">15-20 Hours</option>
  <option value="25-30">25-30 Hours</option>
  <option value="30-40">30-40 Hours</option>
  <option value="40+">40+ Hours</option>
</select>
          <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
       </div>
       
        <div class="col-md-4">
          <h2>Additonal Information</h2>
          <!--Adapted from http://www.w3schools.com/tags/tag_input.asp-->
          <form action="demo_form.asp">
              <input type="text" name="AddInfo" value=""><br>
              <input type="submit" value="Submit">
</form><p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p>
        </div>
      </div>
	  <hr>
      <footer>
        <p>&copy; 2016 WorkTracker, Inc.</p>
      </footer>
    </div> <!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
</body>
</html>
  1. We then handle moving to internal page and bringing along the userName:
func internalPageHandler(response http.ResponseWriter, request *http.Request) {
	userName := getUserName(request)
	if userName != "" {
		fmt.Fprintf(response, internalPage, userName)
	} else {
		http.Redirect(response, request, "/", 302)
	}
}
  1. Finally, we need to serve up our code to port 8000 and handle all requests within the main function:
var router = mux.NewRouter()
func main() {
	
	
	router.HandleFunc("/", indexPageHandler)
	router.HandleFunc("/internal", internalPageHandler)

	router.HandleFunc("/login", loginHandler).Methods("POST")
	router.HandleFunc("/logout", logoutHandler).Methods("POST")

	http.Handle("/", router)
	http.ListenAndServe(":8000", nil)
}
⚠️ **GitHub.com Fallback** ⚠️