diff --git a/012_hands-on/01_hands-on/starting-code/main.go b/012_hands-on/01_hands-on/starting-code/main.go
index ce7d46ef..9b69e11e 100644
--- a/012_hands-on/01_hands-on/starting-code/main.go
+++ b/012_hands-on/01_hands-on/starting-code/main.go
@@ -72,7 +72,7 @@ func main() {
},
}
- err := tpl.Execute(os.Stdout, nil)
+ err := tpl.Execute(os.Stdout, years)
if err != nil {
log.Fatalln(err)
}
diff --git a/012_hands-on/01_hands-on/starting-code/tpl.gohtml b/012_hands-on/01_hands-on/starting-code/tpl.gohtml
index 4d165907..4b7c6201 100644
--- a/012_hands-on/01_hands-on/starting-code/tpl.gohtml
+++ b/012_hands-on/01_hands-on/starting-code/tpl.gohtml
@@ -7,9 +7,16 @@
{{range .}}
+ {{.Fall.Term}} {{.AcaYear}}
+ {{range .Fall.Courses}}
+ {{.Number}} - {{.Name}} - {{.Units}}
+ {{end}}
-
+ {{.Spring.Term}} {{.AcaYear}}
+ {{range .Spring.Courses}}
+ {{.Number}} - {{.Name}} - {{.Units}}
+ {{end}}
{{end}}
diff --git a/012_hands-on/03_hands-on/main.go b/012_hands-on/03_hands-on/main.go
new file mode 100644
index 00000000..02019c9c
--- /dev/null
+++ b/012_hands-on/03_hands-on/main.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+ "log"
+ "os"
+ "text/template"
+)
+
+type hotel struct {
+ Name, Address, City, Zip, Region string
+}
+
+type region struct {
+ Region string
+ Hotels []hotel
+}
+
+type Regions []region
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("tpl.gohtml"))
+}
+
+func main() {
+ h := Regions{
+ region{
+ Region: "Southern",
+ Hotels: []hotel{
+ hotel{
+ Name: "Hotel California",
+ Address: "42 Sunset Boulevard",
+ City: "Los Angeles",
+ Zip: "95612",
+ Region: "southern",
+ },
+ hotel{
+ Name: "H",
+ Address: "4",
+ City: "L",
+ Zip: "95612",
+ Region: "southern",
+ },
+ },
+ },
+ region{
+ Region: "Northern",
+ Hotels: []hotel{
+ hotel{
+ Name: "Hotel California",
+ Address: "42 Sunset Boulevard",
+ City: "Los Angeles",
+ Zip: "95612",
+ Region: "southern",
+ },
+ hotel{
+ Name: "H",
+ Address: "4",
+ City: "L",
+ Zip: "95612",
+ Region: "southern",
+ },
+ },
+ },
+ region{
+ Region: "Central",
+ Hotels: []hotel{
+ hotel{
+ Name: "Hotel California",
+ Address: "42 Sunset Boulevard",
+ City: "Los Angeles",
+ Zip: "95612",
+ Region: "southern",
+ },
+ hotel{
+ Name: "H",
+ Address: "4",
+ City: "L",
+ Zip: "95612",
+ Region: "southern",
+ },
+ },
+ },
+ }
+
+ err := tpl.Execute(os.Stdout, h)
+ if err != nil {
+ log.Fatalln(err)
+ }
+}
diff --git a/012_hands-on/03_hands-on/tpl.gohtml b/012_hands-on/03_hands-on/tpl.gohtml
new file mode 100644
index 00000000..aed14eae
--- /dev/null
+++ b/012_hands-on/03_hands-on/tpl.gohtml
@@ -0,0 +1,18 @@
+
+
+
+
+ Document
+
+
+
+{{range .}}
+ {{.Region}}
+ {{range .Hotels}}
+ {{.Name}}
+ {{.Address}} {{.City}} {{.Zip}}
+ {{end}}
+{{end}}
+
+
+
\ No newline at end of file
diff --git a/012_hands-on/05_hands-on/main.go b/012_hands-on/05_hands-on/main.go
new file mode 100644
index 00000000..bf7f2d83
--- /dev/null
+++ b/012_hands-on/05_hands-on/main.go
@@ -0,0 +1,95 @@
+package main
+
+import (
+ "log"
+ "os"
+ "text/template"
+)
+
+type item struct {
+ Name, Descrip string
+ Price float64
+}
+
+type meal struct {
+ Meal string
+ Item []item
+}
+
+type menu []meal
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("tpl.gohtml"))
+}
+
+func main() {
+ m := menu{
+ meal{
+ Meal: "Breakfast",
+ Item: []item{
+ item{
+ Name: "Oatmeal",
+ Descrip: "yum yum",
+ Price: 4.95,
+ },
+ item{
+ Name: "Cheerios",
+ Descrip: "American eating food traditional now",
+ Price: 3.95,
+ },
+ item{
+ Name: "Juice Orange",
+ Descrip: "Delicious drinking in throat squeezed fresh",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Lunch",
+ Item: []item{
+ item{
+ Name: "Hamburger",
+ Descrip: "Delicous good eating for you",
+ Price: 6.95,
+ },
+ item{
+ Name: "Cheese Melted Sandwich",
+ Descrip: "Make cheese bread melt grease hot",
+ Price: 3.95,
+ },
+ item{
+ Name: "French Fries",
+ Descrip: "French eat potatoe fingers",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Dinner",
+ Item: []item{
+ item{
+ Name: "Pasta Bolognese",
+ Descrip: "From Italy delicious eating",
+ Price: 7.95,
+ },
+ item{
+ Name: "Steak",
+ Descrip: "Dead cow grilled bloody",
+ Price: 13.95,
+ },
+ item{
+ Name: "Bistro Potatoe",
+ Descrip: "Bistro bar wood American bacon",
+ Price: 6.95,
+ },
+ },
+ },
+ }
+
+ err := tpl.Execute(os.Stdout, m)
+ if err != nil {
+ log.Fatalln(err)
+ }
+}
diff --git a/012_hands-on/05_hands-on/tpl.gohtml b/012_hands-on/05_hands-on/tpl.gohtml
new file mode 100644
index 00000000..7f796e64
--- /dev/null
+++ b/012_hands-on/05_hands-on/tpl.gohtml
@@ -0,0 +1,17 @@
+
+
+
+
+ Document
+
+
+
+{{range .}}
+ {{.Meal}}
+ {{range .Item}}
+ {{.Name}} {{.Descrip}} {{.Price}}
+ {{end}}
+{{end}}
+
+
+
\ No newline at end of file
diff --git a/012_hands-on/07_hands-on/main.go b/012_hands-on/07_hands-on/main.go
new file mode 100644
index 00000000..8d7402f7
--- /dev/null
+++ b/012_hands-on/07_hands-on/main.go
@@ -0,0 +1,172 @@
+package main
+
+import (
+ "log"
+ "os"
+ "text/template"
+)
+
+type item struct {
+ Name, Descrip string
+ Price float64
+}
+
+type meal struct {
+ Meal string
+ Item []item
+}
+
+type menu []meal
+
+type restaurant struct {
+ Name string
+ Menu menu
+}
+
+type restaurants []restaurant
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("tpl.gohtml"))
+}
+
+func main() {
+ m := restaurants{
+ restaurant{
+ Name: "Federicos",
+ Menu: menu{
+ meal{
+ Meal: "Breakfast",
+ Item: []item{
+ item{
+ Name: "Oatmeal",
+ Descrip: "yum yum",
+ Price: 4.95,
+ },
+ item{
+ Name: "Cheerios",
+ Descrip: "American eating food traditional now",
+ Price: 3.95,
+ },
+ item{
+ Name: "Juice Orange",
+ Descrip: "Delicious drinking in throat squeezed fresh",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Lunch",
+ Item: []item{
+ item{
+ Name: "Hamburger",
+ Descrip: "Delicous good eating for you",
+ Price: 6.95,
+ },
+ item{
+ Name: "Cheese Melted Sandwich",
+ Descrip: "Make cheese bread melt grease hot",
+ Price: 3.95,
+ },
+ item{
+ Name: "French Fries",
+ Descrip: "French eat potatoe fingers",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Dinner",
+ Item: []item{
+ item{
+ Name: "Pasta Bolognese",
+ Descrip: "From Italy delicious eating",
+ Price: 7.95,
+ },
+ item{
+ Name: "Steak",
+ Descrip: "Dead cow grilled bloody",
+ Price: 13.95,
+ },
+ item{
+ Name: "Bistro Potatoe",
+ Descrip: "Bistro bar wood American bacon",
+ Price: 6.95,
+ },
+ },
+ },
+ },
+ },
+ restaurant{
+ Name: "Domenicos",
+ Menu: menu{
+ meal{
+ Meal: "Breakfast",
+ Item: []item{
+ item{
+ Name: "Oatmeal",
+ Descrip: "yum yum",
+ Price: 4.95,
+ },
+ item{
+ Name: "Cheerios",
+ Descrip: "American eating food traditional now",
+ Price: 3.95,
+ },
+ item{
+ Name: "Juice Orange",
+ Descrip: "Delicious drinking in throat squeezed fresh",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Lunch",
+ Item: []item{
+ item{
+ Name: "Hamburger",
+ Descrip: "Delicous good eating for you",
+ Price: 6.95,
+ },
+ item{
+ Name: "Cheese Melted Sandwich",
+ Descrip: "Make cheese bread melt grease hot",
+ Price: 3.95,
+ },
+ item{
+ Name: "French Fries",
+ Descrip: "French eat potatoe fingers",
+ Price: 2.95,
+ },
+ },
+ },
+ meal{
+ Meal: "Dinner",
+ Item: []item{
+ item{
+ Name: "Pasta Bolognese",
+ Descrip: "From Italy delicious eating",
+ Price: 7.95,
+ },
+ item{
+ Name: "Steak",
+ Descrip: "Dead cow grilled bloody",
+ Price: 13.95,
+ },
+ item{
+ Name: "Bistro Potatoe",
+ Descrip: "Bistro bar wood American bacon",
+ Price: 6.95,
+ },
+ },
+ },
+ },
+ },
+ }
+
+ err := tpl.Execute(os.Stdout, m)
+ if err != nil {
+ log.Fatalln(err)
+ }
+}
diff --git a/012_hands-on/07_hands-on/tpl.gohtml b/012_hands-on/07_hands-on/tpl.gohtml
new file mode 100644
index 00000000..3be72f1b
--- /dev/null
+++ b/012_hands-on/07_hands-on/tpl.gohtml
@@ -0,0 +1,20 @@
+
+
+
+
+ Document
+
+
+
+{{range .}}
+ {{.Name}}
+ {{range .Menu}}
+ {{.Meal}}
+ {{range .Item}}
+ {{.Name}} {{.Descrip}} {{.Price}}
+ {{end}}
+ {{end}}
+{{end}}
+
+
+
\ No newline at end of file
diff --git a/012_hands-on/09_hands-on/hw.gohtml b/012_hands-on/09_hands-on/hw.gohtml
new file mode 100644
index 00000000..ff255ef6
--- /dev/null
+++ b/012_hands-on/09_hands-on/hw.gohtml
@@ -0,0 +1,16 @@
+
+
+
+
+ Document
+
+
+STOCK DATA TEMPLATE
+
+ {{ range . }}
+ - {{ .Date }} - {{ .Open }}
+ {{ end }}
+
+
+
+
\ No newline at end of file
diff --git a/012_hands-on/09_hands-on/main.go b/012_hands-on/09_hands-on/main.go
new file mode 100644
index 00000000..0e4f508d
--- /dev/null
+++ b/012_hands-on/09_hands-on/main.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ "encoding/csv"
+ "html/template"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+ "time"
+)
+
+type Record struct {
+ Date time.Time
+ Open float64
+}
+
+func main() {
+ http.HandleFunc("/", foo)
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(res http.ResponseWriter, req *http.Request) {
+ // parse csv
+ records := prs("table.csv")
+
+ // parse template
+ tpl, err := template.ParseFiles("hw.gohtml")
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ // execute template
+ err = tpl.Execute(res, records)
+ if err != nil {
+ log.Fatalln(err)
+ }
+}
+
+func prs(filePath string) []Record {
+ src, err := os.Open(filePath)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer src.Close()
+
+ rdr := csv.NewReader(src)
+ rows, err := rdr.ReadAll()
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ records := make([]Record, 0, len(rows))
+
+ for i, row := range rows {
+ if i == 0 {
+ continue
+ }
+ date, _ := time.Parse("2006-01-02", row[0])
+ open, _ := strconv.ParseFloat(row[1], 64)
+
+ records = append(records, Record{
+ Date: date,
+ Open: open,
+ })
+ }
+
+ return records
+
+}
diff --git a/016_building-a-tcp-server-for-http/02_hands-on/main.go b/016_building-a-tcp-server-for-http/02_hands-on/main.go
new file mode 100644
index 00000000..33321d54
--- /dev/null
+++ b/016_building-a-tcp-server-for-http/02_hands-on/main.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+ "strings"
+)
+
+func main() {
+ li, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err.Error())
+ }
+ defer li.Close()
+
+ for {
+ conn, err := li.Accept()
+ if err != nil {
+ log.Println(err.Error())
+ continue
+ }
+ go handle(conn)
+ }
+}
+
+func handle(conn net.Conn) {
+ defer conn.Close()
+
+ // read request
+ request(conn)
+
+ // write response
+ respond(conn)
+}
+
+func request(conn net.Conn) {
+ i := 0
+ scanner := bufio.NewScanner(conn)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if i == 0 {
+ // request line
+ m := strings.Fields(ln)[0] // method
+ u := strings.Fields(ln)[1] // uri
+ fmt.Println("***METHOD", m)
+ fmt.Println("***URI", u)
+ }
+ if ln == "" {
+ // headers are done
+ break
+ }
+ i++
+ }
+}
+
+func respond(conn net.Conn) {
+
+ body := `Hello World`
+
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
diff --git a/016_building-a-tcp-server-for-http/04_hands-on/main.go b/016_building-a-tcp-server-for-http/04_hands-on/main.go
new file mode 100644
index 00000000..10921185
--- /dev/null
+++ b/016_building-a-tcp-server-for-http/04_hands-on/main.go
@@ -0,0 +1,158 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+ "strings"
+)
+
+func main() {
+ li, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err.Error())
+ }
+ defer li.Close()
+
+ for {
+ conn, err := li.Accept()
+ if err != nil {
+ log.Println(err.Error())
+ continue
+ }
+ go handle(conn)
+ }
+}
+
+func handle(conn net.Conn) {
+ defer conn.Close()
+ request(conn)
+}
+
+func request(conn net.Conn) {
+ i := 0
+ scanner := bufio.NewScanner(conn)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if i == 0 {
+ mux(conn, ln)
+ }
+ if ln == "" {
+ // headers are done
+ break
+ }
+ i++
+ }
+}
+
+func mux(conn net.Conn, ln string) {
+ // request line
+ m := strings.Fields(ln)[0] // method
+ u := strings.Fields(ln)[1] // uri
+ fmt.Println("***METHOD", m)
+ fmt.Println("***URI", u)
+
+ // multiplexer
+ if m == "GET" && u == "/" {
+ index(conn)
+ }
+ if m == "GET" && u == "/about" {
+ about(conn)
+ }
+ if m == "GET" && u == "/contact" {
+ contact(conn)
+ }
+ if m == "GET" && u == "/apply" {
+ apply(conn)
+ }
+ if m == "POST" && u == "/apply" {
+ applyProcess(conn)
+ }
+}
+
+func index(conn net.Conn) {
+ body := `
+ INDEX
+ index
+ about
+ contact
+ apply
+ `
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
+
+func about(conn net.Conn) {
+ body := `
+ ABOUT
+ index
+ about
+ contact
+ apply
+ `
+
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
+
+func contact(conn net.Conn) {
+
+ body := `
+ CONTACT
+ index
+ about
+ contact
+ apply
+ `
+
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
+
+func apply(conn net.Conn) {
+
+ body := `
+ APPLY
+ index
+ about
+ contact
+ apply
+
+ `
+
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
+
+func applyProcess(conn net.Conn) {
+
+ body := `
+ APPLY PROCESS
+ index
+ about
+ contact
+ apply
+ `
+
+ fmt.Fprint(conn, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(conn, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(conn, "Content-Type: text/html\r\n")
+ fmt.Fprint(conn, "\r\n")
+ fmt.Fprint(conn, body)
+}
diff --git a/022_hands-on/01/01_hands-on/main.go b/022_hands-on/01/01_hands-on/main.go
new file mode 100644
index 00000000..79cfabc3
--- /dev/null
+++ b/022_hands-on/01/01_hands-on/main.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "io"
+ "net/http"
+)
+
+func main() {
+ http.HandleFunc("/", foo)
+ http.HandleFunc("/dog/", bar)
+ http.HandleFunc("/me/", myName)
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "foo ran")
+}
+
+func bar(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "bar ran")
+}
+
+func myName(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "hello mcleod")
+}
diff --git a/022_hands-on/01/03_hands-on/main.go b/022_hands-on/01/03_hands-on/main.go
new file mode 100644
index 00000000..543b3a0c
--- /dev/null
+++ b/022_hands-on/01/03_hands-on/main.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+ "html/template"
+ "io"
+ "log"
+ "net/http"
+)
+
+func main() {
+ http.HandleFunc("/", foo)
+ http.HandleFunc("/dog/", bar)
+ http.HandleFunc("/me/", mcleod)
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "foo ran")
+}
+
+func bar(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "bar ran")
+}
+
+func mcleod(w http.ResponseWriter, req *http.Request) {
+ tpl, err := template.ParseFiles("something.gohtml")
+ if err != nil {
+ log.Fatalln("error parsing template", err)
+ }
+
+ err = tpl.ExecuteTemplate(w, "something.gohtml", "McLeod")
+ if err != nil {
+ log.Fatalln("error executing template", err)
+ }
+}
diff --git a/022_hands-on/01/03_hands-on/something.gohtml b/022_hands-on/01/03_hands-on/something.gohtml
new file mode 100644
index 00000000..f39127c6
--- /dev/null
+++ b/022_hands-on/01/03_hands-on/something.gohtml
@@ -0,0 +1 @@
+Hello, {{.}}
\ No newline at end of file
diff --git a/022_hands-on/01/05_hands-on/main.go b/022_hands-on/01/05_hands-on/main.go
new file mode 100644
index 00000000..cb6eaba3
--- /dev/null
+++ b/022_hands-on/01/05_hands-on/main.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+ "html/template"
+ "io"
+ "log"
+ "net/http"
+)
+
+func main() {
+ http.Handle("/", http.HandlerFunc(foo))
+ http.Handle("/dog/", http.HandlerFunc(bar))
+ http.Handle("/me/", http.HandlerFunc(mcleod))
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "foo ran")
+}
+
+func bar(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "bar ran")
+}
+
+func mcleod(w http.ResponseWriter, req *http.Request) {
+ tpl, err := template.ParseFiles("something.gohtml")
+ if err != nil {
+ log.Fatalln("error parsing template", err)
+ }
+
+ err = tpl.ExecuteTemplate(w, "something.gohtml", "McLeod")
+ if err != nil {
+ log.Fatalln("error executing template", err)
+ }
+}
diff --git a/022_hands-on/01/05_hands-on/something.gohtml b/022_hands-on/01/05_hands-on/something.gohtml
new file mode 100644
index 00000000..f39127c6
--- /dev/null
+++ b/022_hands-on/01/05_hands-on/something.gohtml
@@ -0,0 +1 @@
+Hello, {{.}}
\ No newline at end of file
diff --git a/022_hands-on/02/01_hands-on/main.go b/022_hands-on/02/01_hands-on/main.go
new file mode 100644
index 00000000..65bc9515
--- /dev/null
+++ b/022_hands-on/02/01_hands-on/main.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "io"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+
+ // write to connection
+ io.WriteString(conn, "I see you connected.")
+
+ conn.Close()
+ }
+}
diff --git a/022_hands-on/02/03_hands-on/main.go b/022_hands-on/02/03_hands-on/main.go
new file mode 100644
index 00000000..7740f10b
--- /dev/null
+++ b/022_hands-on/02/03_hands-on/main.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+
+ scanner := bufio.NewScanner(conn)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ }
+ defer conn.Close()
+
+ // we never get here
+ // we have an open stream connection
+ // how does the above reader know when it's done?
+ fmt.Println("Code got here.")
+ io.WriteString(conn, "I see you connected.")
+
+ conn.Close()
+ }
+}
diff --git a/022_hands-on/02/05_hands-on/main.go b/022_hands-on/02/05_hands-on/main.go
new file mode 100644
index 00000000..613ecedf
--- /dev/null
+++ b/022_hands-on/02/05_hands-on/main.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+
+ scanner := bufio.NewScanner(conn)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ }
+
+ fmt.Println("Code got here.")
+ io.WriteString(conn, "I see you connected.")
+
+ conn.Close()
+ }
+}
diff --git a/022_hands-on/02/07_hands-on/main.go b/022_hands-on/02/07_hands-on/main.go
new file mode 100644
index 00000000..2be36e76
--- /dev/null
+++ b/022_hands-on/02/07_hands-on/main.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ go serve(conn)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ scanner := bufio.NewScanner(c)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ }
+}
diff --git a/022_hands-on/02/09_hands-on/main.go b/022_hands-on/02/09_hands-on/main.go
new file mode 100644
index 00000000..9bc12c8c
--- /dev/null
+++ b/022_hands-on/02/09_hands-on/main.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ serve(conn)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ scanner := bufio.NewScanner(c)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ }
+ io.WriteString(c, "Here we WRITE to the response.")
+}
diff --git a/022_hands-on/02/11_hands-on/main.go b/022_hands-on/02/11_hands-on/main.go
new file mode 100644
index 00000000..2c8357e4
--- /dev/null
+++ b/022_hands-on/02/11_hands-on/main.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ serve(conn)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ scanner := bufio.NewScanner(c)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ }
+ body := "CHECK OUT THE RESPONSE BODY PAYLOAD"
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/plain\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
diff --git a/022_hands-on/02/13_hands-on/main.go b/022_hands-on/02/13_hands-on/main.go
new file mode 100644
index 00000000..4c3cbbd6
--- /dev/null
+++ b/022_hands-on/02/13_hands-on/main.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "strings"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ serve(conn)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ scanner := bufio.NewScanner(c)
+ var i int
+ var rMethod, rURI string
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if i == 0 {
+ // we're in REQUEST LINE
+ xs := strings.Fields(ln)
+ rMethod = xs[0]
+ rURI = xs[1]
+ fmt.Println("METHOD:", rMethod)
+ fmt.Println("URI:", rURI)
+ }
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ i++
+ }
+ body := "CHECK OUT THE RESPONSE BODY PAYLOAD"
+ body += "\n"
+ body += rMethod
+ body += "\n"
+ body += rURI
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/plain\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
diff --git a/022_hands-on/02/15_hands-on/main.go b/022_hands-on/02/15_hands-on/main.go
new file mode 100644
index 00000000..d52d48ca
--- /dev/null
+++ b/022_hands-on/02/15_hands-on/main.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "strings"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ conn, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ go serve(conn)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ var i int
+ var rMethod, rURI string
+ scanner := bufio.NewScanner(c)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if i == 0 {
+ // we're in REQUEST LINE
+ xs := strings.Fields(ln)
+ rMethod = xs[0]
+ rURI = xs[1]
+ fmt.Println("METHOD:", rMethod)
+ fmt.Println("URI:", rURI)
+ }
+ if ln == "" {
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ i++
+ }
+
+ body := `
+
+
+
+
+ Code Gangsta
+
+
+ "HOLY COW THIS IS LOW LEVEL"
+
+
+ `
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/html\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
diff --git a/022_hands-on/02/17_hands-on/main.go b/022_hands-on/02/17_hands-on/main.go
new file mode 100644
index 00000000..0ab5686d
--- /dev/null
+++ b/022_hands-on/02/17_hands-on/main.go
@@ -0,0 +1,154 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "strings"
+)
+
+func main() {
+ l, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer l.Close()
+
+ for {
+ c, err := l.Accept()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ // now handles multiple connections
+ go serve(c)
+ }
+}
+
+func serve(c net.Conn) {
+ defer c.Close()
+ var i int
+ var rMethod, rURI string
+ scanner := bufio.NewScanner(c)
+ for scanner.Scan() {
+ ln := scanner.Text()
+ fmt.Println(ln)
+ if i == 0 {
+ // we're in REQUEST LINE
+ xs := strings.Fields(ln)
+ rMethod = xs[0]
+ rURI = xs[1]
+ fmt.Println("METHOD:", rMethod)
+ fmt.Println("URI:", rURI)
+ }
+ if ln == "" {
+ // when ln is empty, header is done
+ fmt.Println("THIS IS THE END OF THE HTTP REQUEST HEADERS")
+ break
+ }
+ i++
+ }
+
+ switch {
+ case rMethod == "GET" && rURI == "/":
+ handleIndex(c)
+ case rMethod == "GET" && rURI == "/apply":
+ handleApply(c)
+ case rMethod == "POST" && rURI == "/apply":
+ handleApplyPost(c)
+ default:
+ handleDefault(c)
+ }
+}
+
+func handleIndex(c net.Conn) {
+ body := `
+
+
+
+
+ GET INDEX
+
+
+ "GET INDEX"
+ index
+ apply
+
+
+ `
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/html\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
+
+func handleApply(c net.Conn) {
+ body := `
+
+
+
+
+ GET DOG
+
+
+ "GET APPLY"
+ index
+ apply
+
+
+
+ `
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/html\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
+
+func handleApplyPost(c net.Conn) {
+ body := `
+
+
+
+
+ POST APPLY
+
+
+ "POST APPLY"
+ index
+ apply
+
+
+ `
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/html\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
+
+func handleDefault(c net.Conn) {
+ body := `
+
+
+
+
+ default
+
+
+ "default"
+
+
+ `
+ io.WriteString(c, "HTTP/1.1 200 OK\r\n")
+ fmt.Fprintf(c, "Content-Length: %d\r\n", len(body))
+ fmt.Fprint(c, "Content-Type: text/html\r\n")
+ io.WriteString(c, "\r\n")
+ io.WriteString(c, body)
+}
diff --git a/024_hands-on/01_hands-on/dog.gohtml b/024_hands-on/01_hands-on/dog.gohtml
new file mode 100644
index 00000000..c74dd4f3
--- /dev/null
+++ b/024_hands-on/01_hands-on/dog.gohtml
@@ -0,0 +1,11 @@
+
+
+
+
+ FIDO
+
+
+ This is from dog
+
+
+
\ No newline at end of file
diff --git a/024_hands-on/05_hands-on/starting-files/public/pics/dog.jpeg b/024_hands-on/01_hands-on/dog.jpg
similarity index 100%
rename from 024_hands-on/05_hands-on/starting-files/public/pics/dog.jpeg
rename to 024_hands-on/01_hands-on/dog.jpg
diff --git a/024_hands-on/01_hands-on/main.go b/024_hands-on/01_hands-on/main.go
new file mode 100644
index 00000000..252a03a3
--- /dev/null
+++ b/024_hands-on/01_hands-on/main.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "html/template"
+ "io"
+ "log"
+ "net/http"
+)
+
+func main() {
+ http.HandleFunc("/", foo)
+ http.HandleFunc("/dog/", dog)
+ http.HandleFunc("/dog.jpg", chien)
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, "foo ran")
+}
+
+func dog(w http.ResponseWriter, req *http.Request) {
+ tpl, err := template.ParseFiles("dog.gohtml")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ tpl.ExecuteTemplate(w, "dog.gohtml", nil)
+}
+
+func chien(w http.ResponseWriter, req *http.Request) {
+ http.ServeFile(w, req, "dog.jpg")
+}
diff --git a/024_hands-on/03_hands-on/starting-files/css/main.css b/024_hands-on/03_hands-on/css/main.css
similarity index 100%
rename from 024_hands-on/03_hands-on/starting-files/css/main.css
rename to 024_hands-on/03_hands-on/css/main.css
diff --git a/024_hands-on/03_hands-on/starting-files/css/reset.css b/024_hands-on/03_hands-on/css/reset.css
similarity index 100%
rename from 024_hands-on/03_hands-on/starting-files/css/reset.css
rename to 024_hands-on/03_hands-on/css/reset.css
diff --git a/024_hands-on/03_hands-on/starting-files/index.html b/024_hands-on/03_hands-on/index.html
similarity index 100%
rename from 024_hands-on/03_hands-on/starting-files/index.html
rename to 024_hands-on/03_hands-on/index.html
diff --git a/024_hands-on/03_hands-on/main.go b/024_hands-on/03_hands-on/main.go
new file mode 100644
index 00000000..d8edd31b
--- /dev/null
+++ b/024_hands-on/03_hands-on/main.go
@@ -0,0 +1,10 @@
+package main
+
+import (
+ "log"
+ "net/http"
+)
+
+func main() {
+ log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("."))))
+}
diff --git a/024_hands-on/03_hands-on/starting-files/pic/surf.jpg b/024_hands-on/03_hands-on/pic/surf.jpg
similarity index 100%
rename from 024_hands-on/03_hands-on/starting-files/pic/surf.jpg
rename to 024_hands-on/03_hands-on/pic/surf.jpg
diff --git a/024_hands-on/05_hands-on/main.go b/024_hands-on/05_hands-on/main.go
new file mode 100644
index 00000000..ca4f64ac
--- /dev/null
+++ b/024_hands-on/05_hands-on/main.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "html/template"
+ "log"
+ "net/http"
+)
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("templates/index.gohtml"))
+}
+
+func main() {
+ fs := http.FileServer(http.Dir("public"))
+ http.Handle("/pics/", fs)
+ http.HandleFunc("/", dogs)
+ http.ListenAndServe(":8080", nil)
+}
+
+func dogs(w http.ResponseWriter, req *http.Request) {
+ err := tpl.Execute(w, nil)
+ if err != nil {
+ log.Fatalln("template didn't execute: ", err)
+ }
+}
diff --git a/024_hands-on/07_hands-on/starting-files/public/pics/dog.jpeg b/024_hands-on/05_hands-on/public/pics/dog.jpeg
similarity index 100%
rename from 024_hands-on/07_hands-on/starting-files/public/pics/dog.jpeg
rename to 024_hands-on/05_hands-on/public/pics/dog.jpeg
diff --git a/024_hands-on/05_hands-on/starting-files/public/pics/dog1.jpeg b/024_hands-on/05_hands-on/public/pics/dog1.jpeg
similarity index 100%
rename from 024_hands-on/05_hands-on/starting-files/public/pics/dog1.jpeg
rename to 024_hands-on/05_hands-on/public/pics/dog1.jpeg
diff --git a/024_hands-on/05_hands-on/starting-files/public/pics/dog2.jpeg b/024_hands-on/05_hands-on/public/pics/dog2.jpeg
similarity index 100%
rename from 024_hands-on/05_hands-on/starting-files/public/pics/dog2.jpeg
rename to 024_hands-on/05_hands-on/public/pics/dog2.jpeg
diff --git a/024_hands-on/05_hands-on/starting-files/templates/index.gohtml b/024_hands-on/05_hands-on/templates/index.gohtml
similarity index 100%
rename from 024_hands-on/05_hands-on/starting-files/templates/index.gohtml
rename to 024_hands-on/05_hands-on/templates/index.gohtml
diff --git a/024_hands-on/07_hands-on/main.go b/024_hands-on/07_hands-on/main.go
new file mode 100644
index 00000000..c8a72a44
--- /dev/null
+++ b/024_hands-on/07_hands-on/main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "html/template"
+ "log"
+ "net/http"
+)
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("templates/index.gohtml"))
+}
+
+func main() {
+ http.HandleFunc("/", dogs)
+ http.Handle("/resources/", http.StripPrefix("/resources", http.FileServer(http.Dir("public"))))
+ http.ListenAndServe(":8080", nil)
+}
+
+func dogs(w http.ResponseWriter, req *http.Request) {
+ err := tpl.Execute(w, nil)
+ if err != nil {
+ log.Fatalln("template didn't execute: ", err)
+ }
+}
diff --git a/024_hands-on/07_hands-on/public/pics/dog.jpeg b/024_hands-on/07_hands-on/public/pics/dog.jpeg
new file mode 100644
index 00000000..0905a7ad
Binary files /dev/null and b/024_hands-on/07_hands-on/public/pics/dog.jpeg differ
diff --git a/024_hands-on/07_hands-on/starting-files/public/pics/dog1.jpeg b/024_hands-on/07_hands-on/public/pics/dog1.jpeg
similarity index 100%
rename from 024_hands-on/07_hands-on/starting-files/public/pics/dog1.jpeg
rename to 024_hands-on/07_hands-on/public/pics/dog1.jpeg
diff --git a/024_hands-on/07_hands-on/starting-files/public/pics/dog2.jpeg b/024_hands-on/07_hands-on/public/pics/dog2.jpeg
similarity index 100%
rename from 024_hands-on/07_hands-on/starting-files/public/pics/dog2.jpeg
rename to 024_hands-on/07_hands-on/public/pics/dog2.jpeg
diff --git a/024_hands-on/07_hands-on/starting-files/templates/index.gohtml b/024_hands-on/07_hands-on/templates/index.gohtml
similarity index 100%
rename from 024_hands-on/07_hands-on/starting-files/templates/index.gohtml
rename to 024_hands-on/07_hands-on/templates/index.gohtml
diff --git a/024_hands-on/09_hands-on/main.go b/024_hands-on/09_hands-on/main.go
new file mode 100644
index 00000000..dd011bdd
--- /dev/null
+++ b/024_hands-on/09_hands-on/main.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "html/template"
+ "net/http"
+)
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseFiles("templates/index.gohtml"))
+}
+
+func main() {
+ http.HandleFunc("/", index)
+ http.Handle("/public/", http.StripPrefix("/public", http.FileServer(http.Dir("public"))))
+ http.ListenAndServe(":8080", nil)
+}
+
+func index(w http.ResponseWriter, _ *http.Request) {
+ tpl.ExecuteTemplate(w, "index.gohtml", nil)
+}
diff --git a/024_hands-on/09_hands-on/starting-files/public/css/main.css b/024_hands-on/09_hands-on/public/css/main.css
similarity index 100%
rename from 024_hands-on/09_hands-on/starting-files/public/css/main.css
rename to 024_hands-on/09_hands-on/public/css/main.css
diff --git a/024_hands-on/09_hands-on/starting-files/public/css/reset.css b/024_hands-on/09_hands-on/public/css/reset.css
similarity index 100%
rename from 024_hands-on/09_hands-on/starting-files/public/css/reset.css
rename to 024_hands-on/09_hands-on/public/css/reset.css
diff --git a/024_hands-on/09_hands-on/starting-files/public/pic/surf.jpg b/024_hands-on/09_hands-on/public/pic/surf.jpg
similarity index 100%
rename from 024_hands-on/09_hands-on/starting-files/public/pic/surf.jpg
rename to 024_hands-on/09_hands-on/public/pic/surf.jpg
diff --git a/024_hands-on/09_hands-on/starting-files/templates/index.gohtml b/024_hands-on/09_hands-on/templates/index.gohtml
similarity index 100%
rename from 024_hands-on/09_hands-on/starting-files/templates/index.gohtml
rename to 024_hands-on/09_hands-on/templates/index.gohtml
diff --git a/024_hands-on/11_hands-on/starting-files/main.go b/024_hands-on/11_hands-on/main.go
similarity index 53%
rename from 024_hands-on/11_hands-on/starting-files/main.go
rename to 024_hands-on/11_hands-on/main.go
index 1b2a851d..8f8bf128 100644
--- a/024_hands-on/11_hands-on/starting-files/main.go
+++ b/024_hands-on/11_hands-on/main.go
@@ -1,37 +1,49 @@
package main
import (
+ "html/template"
"log"
"net/http"
)
-func main() {
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseGlob("templates/*"))
+}
+func main() {
+ http.HandleFunc("/", index)
+ http.HandleFunc("/about", about)
+ http.HandleFunc("/contact", contact)
+ http.HandleFunc("/apply", apply)
http.ListenAndServe(":8080", nil)
}
-func index(w http.ResponseWriter, req *http.Request) {
+func index(w http.ResponseWriter, _ *http.Request) {
err := tpl.ExecuteTemplate(w, "index.gohtml", nil)
HandleError(w, err)
}
-func about(w http.ResponseWriter, req *http.Request) {
+func about(w http.ResponseWriter, _ *http.Request) {
err := tpl.ExecuteTemplate(w, "about.gohtml", nil)
HandleError(w, err)
}
-func contact(w http.ResponseWriter, req *http.Request) {
+func contact(w http.ResponseWriter, _ *http.Request) {
err := tpl.ExecuteTemplate(w, "contact.gohtml", nil)
HandleError(w, err)
}
func apply(w http.ResponseWriter, req *http.Request) {
- err := tpl.ExecuteTemplate(w, "apply.gohtml", nil)
- HandleError(w, err)
-}
-func applyProcess(w http.ResponseWriter, req *http.Request) {
- err := tpl.ExecuteTemplate(w, "applyProcess.gohtml", nil)
+ if req.Method == http.MethodPost {
+ err := tpl.ExecuteTemplate(w, "applyProcess.gohtml", nil)
+ HandleError(w, err)
+ return
+ }
+
+ err := tpl.ExecuteTemplate(w, "apply.gohtml", nil)
HandleError(w, err)
}
diff --git a/024_hands-on/11_hands-on/starting-files/templates/about.gohtml b/024_hands-on/11_hands-on/templates/about.gohtml
similarity index 100%
rename from 024_hands-on/11_hands-on/starting-files/templates/about.gohtml
rename to 024_hands-on/11_hands-on/templates/about.gohtml
diff --git a/024_hands-on/11_hands-on/starting-files/templates/apply.gohtml b/024_hands-on/11_hands-on/templates/apply.gohtml
similarity index 100%
rename from 024_hands-on/11_hands-on/starting-files/templates/apply.gohtml
rename to 024_hands-on/11_hands-on/templates/apply.gohtml
diff --git a/024_hands-on/11_hands-on/starting-files/templates/applyProcess.gohtml b/024_hands-on/11_hands-on/templates/applyProcess.gohtml
similarity index 100%
rename from 024_hands-on/11_hands-on/starting-files/templates/applyProcess.gohtml
rename to 024_hands-on/11_hands-on/templates/applyProcess.gohtml
diff --git a/024_hands-on/11_hands-on/starting-files/templates/contact.gohtml b/024_hands-on/11_hands-on/templates/contact.gohtml
similarity index 100%
rename from 024_hands-on/11_hands-on/starting-files/templates/contact.gohtml
rename to 024_hands-on/11_hands-on/templates/contact.gohtml
diff --git a/024_hands-on/11_hands-on/starting-files/templates/index.gohtml b/024_hands-on/11_hands-on/templates/index.gohtml
similarity index 100%
rename from 024_hands-on/11_hands-on/starting-files/templates/index.gohtml
rename to 024_hands-on/11_hands-on/templates/index.gohtml
diff --git a/029_cookies/03_hands-on/main.go b/029_cookies/03_hands-on/main.go
new file mode 100644
index 00000000..89b03c44
--- /dev/null
+++ b/029_cookies/03_hands-on/main.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "io"
+ "log"
+ "net/http"
+ "strconv"
+)
+
+func main() {
+ http.HandleFunc("/", foo)
+ http.Handle("/favicon.ico", http.NotFoundHandler())
+ http.ListenAndServe(":8080", nil)
+}
+
+func foo(res http.ResponseWriter, req *http.Request) {
+
+ cookie, err := req.Cookie("my-cookie")
+
+ if err == http.ErrNoCookie {
+ cookie = &http.Cookie{
+ Name: "my-cookie",
+ Value: "0",
+ }
+ }
+
+ count, err := strconv.Atoi(cookie.Value)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ count++
+ cookie.Value = strconv.Itoa(count)
+
+ http.SetCookie(res, cookie)
+
+ io.WriteString(res, cookie.Value)
+}
diff --git a/030_sessions/01_uuid/main.go b/030_sessions/01_uuid/main.go
index ad36b1f6..0073ddaf 100644
--- a/030_sessions/01_uuid/main.go
+++ b/030_sessions/01_uuid/main.go
@@ -2,8 +2,9 @@ package main
import (
"fmt"
- "github.com/satori/go.uuid"
"net/http"
+
+ "github.com/satori/go.uuid"
)
// For this code to run, you will need this package:
@@ -18,7 +19,7 @@ func main() {
func index(w http.ResponseWriter, req *http.Request) {
cookie, err := req.Cookie("session")
if err != nil {
- id := uuid.NewV4()
+ id, _ := uuid.NewV4()
cookie = &http.Cookie{
Name: "session",
Value: id.String(),
diff --git a/042_mongodb/10_hands-on/starting-code/main.go b/031_aws/02_hands-on/01_challenge/main.go
similarity index 99%
rename from 042_mongodb/10_hands-on/starting-code/main.go
rename to 031_aws/02_hands-on/01_challenge/main.go
index 690231d9..e6e9a4cb 100644
--- a/042_mongodb/10_hands-on/starting-code/main.go
+++ b/031_aws/02_hands-on/01_challenge/main.go
@@ -40,7 +40,7 @@ func main() {
http.HandleFunc("/login", login)
http.HandleFunc("/logout", logout)
http.Handle("/favicon.ico", http.NotFoundHandler())
- http.ListenAndServe(":8080", nil)
+ http.ListenAndServe(":80", nil)
}
func index(w http.ResponseWriter, req *http.Request) {
diff --git a/042_mongodb/10_hands-on/starting-code/session.go b/031_aws/02_hands-on/01_challenge/session.go
similarity index 100%
rename from 042_mongodb/10_hands-on/starting-code/session.go
rename to 031_aws/02_hands-on/01_challenge/session.go
diff --git a/042_mongodb/10_hands-on/starting-code/templates/bar.gohtml b/031_aws/02_hands-on/01_challenge/templates/bar.gohtml
similarity index 100%
rename from 042_mongodb/10_hands-on/starting-code/templates/bar.gohtml
rename to 031_aws/02_hands-on/01_challenge/templates/bar.gohtml
diff --git a/042_mongodb/10_hands-on/starting-code/templates/index.gohtml b/031_aws/02_hands-on/01_challenge/templates/index.gohtml
similarity index 100%
rename from 042_mongodb/10_hands-on/starting-code/templates/index.gohtml
rename to 031_aws/02_hands-on/01_challenge/templates/index.gohtml
diff --git a/042_mongodb/10_hands-on/starting-code/templates/login.gohtml b/031_aws/02_hands-on/01_challenge/templates/login.gohtml
similarity index 100%
rename from 042_mongodb/10_hands-on/starting-code/templates/login.gohtml
rename to 031_aws/02_hands-on/01_challenge/templates/login.gohtml
diff --git a/042_mongodb/10_hands-on/starting-code/templates/signup.gohtml b/031_aws/02_hands-on/01_challenge/templates/signup.gohtml
similarity index 100%
rename from 042_mongodb/10_hands-on/starting-code/templates/signup.gohtml
rename to 031_aws/02_hands-on/01_challenge/templates/signup.gohtml
diff --git a/040_json/16_hands-on/index.html b/040_json/16_hands-on/index.html
new file mode 100644
index 00000000..e04be3fe
--- /dev/null
+++ b/040_json/16_hands-on/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+ Title
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/040_json/16_hands-on/main.go b/040_json/16_hands-on/main.go
new file mode 100644
index 00000000..43aed967
--- /dev/null
+++ b/040_json/16_hands-on/main.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+)
+
+type code struct {
+ Code int
+ Descrip string
+}
+
+func main() {
+ var data []code
+
+ rcvd := `[{"Code":200,"Descrip":"StatusOK"},{"Code":301,"Descrip":"StatusMovedPermanently"},{"Code":302,"Descrip":"StatusFound"},{"Code":303,"Descrip":"StatusSeeOther"},{"Code":307,"Descrip":"StatusTemporaryRedirect"},{"Code":400,"Descrip":"StatusBadRequest"},{"Code":401,"Descrip":"StatusUnauthorized"},{"Code":402,"Descrip":"StatusPaymentRequired"},{"Code":403,"Descrip":"StatusForbidden"},{"Code":404,"Descrip":"StatusNotFound"},{"Code":405,"Descrip":"StatusMethodNotAllowed"},{"Code":418,"Descrip":"StatusTeapot"},{"Code":500,"Descrip":"StatusInternalServerError"}]`
+
+ err := json.Unmarshal([]byte(rcvd), &data)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ for _, v := range data {
+ fmt.Println(v.Code, "-", v.Descrip)
+ }
+}
diff --git a/042_mongodb/06_hands-on/controllers/user.go b/042_mongodb/06_hands-on/controllers/user.go
new file mode 100644
index 00000000..79f65b4a
--- /dev/null
+++ b/042_mongodb/06_hands-on/controllers/user.go
@@ -0,0 +1,65 @@
+package controllers
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/07_solution/models"
+ "github.com/julienschmidt/httprouter"
+ "github.com/satori/go.uuid"
+ "net/http"
+)
+
+type UserController struct {
+ session map[string]models.User
+}
+
+func NewUserController(m map[string]models.User) *UserController {
+ return &UserController{m}
+}
+
+func (uc UserController) GetUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
+ // Grab id
+ id := p.ByName("id")
+
+ // Retrieve user
+ u := uc.session[id]
+
+ uj, err := json.Marshal(u)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK) // 200
+ fmt.Fprintf(w, "%s\n", uj)
+}
+
+func (uc UserController) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+ u := models.User{}
+
+ json.NewDecoder(r.Body).Decode(&u)
+
+ // create ID
+ u.Id = uuid.NewV4().String()
+
+ // store the user
+ uc.session[u.Id] = u
+
+ uj, err := json.Marshal(u)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated) // 201
+ fmt.Fprintf(w, "%s\n", uj)
+}
+
+func (uc UserController) DeleteUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
+ id := p.ByName("id")
+
+ delete(uc.session, id)
+
+ w.WriteHeader(http.StatusOK) // 200
+ fmt.Fprint(w, "Deleted user", id, "\n")
+}
diff --git a/042_mongodb/06_hands-on/starting-code/main.go b/042_mongodb/06_hands-on/main.go
similarity index 52%
rename from 042_mongodb/06_hands-on/starting-code/main.go
rename to 042_mongodb/06_hands-on/main.go
index e47ade07..95e80c79 100644
--- a/042_mongodb/06_hands-on/starting-code/main.go
+++ b/042_mongodb/06_hands-on/main.go
@@ -1,9 +1,9 @@
package main
import (
- "github.com/GoesToEleven/golang-web-dev/040_mongodb/06_hands-on/starting-code/controllers"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/07_solution/controllers"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/07_solution/models"
"github.com/julienschmidt/httprouter"
- "gopkg.in/mgo.v2"
"net/http"
)
@@ -17,13 +17,6 @@ func main() {
http.ListenAndServe("localhost:8080", r)
}
-func getSession() *mgo.Session {
- // Connect to our local mongo
- s, err := mgo.Dial("mongodb://localhost")
-
- // Check if connection error, is mongo running?
- if err != nil {
- panic(err)
- }
- return s
+func getSession() map[string]models.User {
+ return make(map[string]models.User)
}
diff --git a/042_mongodb/06_hands-on/models/user.go b/042_mongodb/06_hands-on/models/user.go
new file mode 100644
index 00000000..9e4c179d
--- /dev/null
+++ b/042_mongodb/06_hands-on/models/user.go
@@ -0,0 +1,9 @@
+package models
+
+// changed Id type to string
+type User struct {
+ Id string `json:"id"`
+ Name string `json:"name" `
+ Gender string `json:"gender"`
+ Age int `json:"age"`
+}
diff --git a/042_mongodb/06_hands-on/starting-code/controllers/user.go b/042_mongodb/06_hands-on/starting-code/controllers/user.go
deleted file mode 100644
index 345fd95e..00000000
--- a/042_mongodb/06_hands-on/starting-code/controllers/user.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package controllers
-
-import (
- "encoding/json"
- "fmt"
- "github.com/GoesToEleven/golang-web-dev/040_mongodb/06_hands-on/starting-code/models"
- "github.com/julienschmidt/httprouter"
- "gopkg.in/mgo.v2"
- "gopkg.in/mgo.v2/bson"
- "net/http"
-)
-
-type UserController struct {
- session *mgo.Session
-}
-
-func NewUserController(s *mgo.Session) *UserController {
- return &UserController{s}
-}
-
-func (uc UserController) GetUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
- // Grab id
- id := p.ByName("id")
-
- // Verify id is ObjectId hex representation, otherwise return status not found
- if !bson.IsObjectIdHex(id) {
- w.WriteHeader(http.StatusNotFound) // 404
- return
- }
-
- // ObjectIdHex returns an ObjectId from the provided hex representation.
- oid := bson.ObjectIdHex(id)
-
- // composite literal
- u := models.User{}
-
- // Fetch user
- if err := uc.session.DB("go-web-dev-db").C("users").FindId(oid).One(&u); err != nil {
- w.WriteHeader(404)
- return
- }
-
- // Marshal provided interface into JSON structure
- uj, _ := json.Marshal(u)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK) // 200
- fmt.Fprintf(w, "%s\n", uj)
-}
-
-func (uc UserController) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
- u := models.User{}
-
- json.NewDecoder(r.Body).Decode(&u)
-
- // create bson ID
- u.Id = bson.NewObjectId()
-
- // store the user in mongodb
- uc.session.DB("go-web-dev-db").C("users").Insert(u)
-
- uj, _ := json.Marshal(u)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated) // 201
- fmt.Fprintf(w, "%s\n", uj)
-}
-
-func (uc UserController) DeleteUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
- id := p.ByName("id")
-
- if !bson.IsObjectIdHex(id) {
- w.WriteHeader(404)
- return
- }
-
- oid := bson.ObjectIdHex(id)
-
- // Delete user
- if err := uc.session.DB("go-web-dev-db").C("users").RemoveId(oid); err != nil {
- w.WriteHeader(404)
- return
- }
-
- w.WriteHeader(http.StatusOK) // 200
- fmt.Fprint(w, "Deleted user", oid, "\n")
-}
diff --git a/042_mongodb/06_hands-on/starting-code/models/user.go b/042_mongodb/06_hands-on/starting-code/models/user.go
deleted file mode 100644
index 94e05c63..00000000
--- a/042_mongodb/06_hands-on/starting-code/models/user.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package models
-
-import "gopkg.in/mgo.v2/bson"
-
-type User struct {
- Id bson.ObjectId `json:"id" bson:"_id"`
- Name string `json:"name" bson:"name"`
- Gender string `json:"gender" bson:"gender"`
- Age int `json:"age" bson:"age"`
-}
-
-// Id was of type string before
diff --git a/042_mongodb/08_hands-on/controllers/user.go b/042_mongodb/08_hands-on/controllers/user.go
new file mode 100644
index 00000000..8d13d344
--- /dev/null
+++ b/042_mongodb/08_hands-on/controllers/user.go
@@ -0,0 +1,68 @@
+package controllers
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/09_solution/models"
+ "github.com/julienschmidt/httprouter"
+ "github.com/satori/go.uuid"
+ "net/http"
+)
+
+type UserController struct {
+ session map[string]models.User
+}
+
+func NewUserController(m map[string]models.User) *UserController {
+ return &UserController{m}
+}
+
+func (uc UserController) GetUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
+ // Grab id
+ id := p.ByName("id")
+
+ // Retrieve user
+ u := uc.session[id]
+
+ uj, err := json.Marshal(u)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK) // 200
+ fmt.Fprintf(w, "%s\n", uj)
+}
+
+func (uc UserController) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+ u := models.User{}
+
+ json.NewDecoder(r.Body).Decode(&u)
+
+ // create ID
+ u.Id = uuid.NewV4().String()
+
+ // store the user
+ uc.session[u.Id] = u
+ models.StoreUsers(uc.session)
+
+ uj, err := json.Marshal(u)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated) // 201
+ fmt.Fprintf(w, "%s\n", uj)
+}
+
+func (uc UserController) DeleteUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
+ id := p.ByName("id")
+
+ delete(uc.session, id)
+
+ models.StoreUsers(uc.session)
+
+ w.WriteHeader(http.StatusOK) // 200
+ fmt.Fprint(w, "Deleted user ", id, "\n")
+}
diff --git a/042_mongodb/08_hands-on/data b/042_mongodb/08_hands-on/data
new file mode 100644
index 00000000..d60141ea
--- /dev/null
+++ b/042_mongodb/08_hands-on/data
@@ -0,0 +1 @@
+{"ff69705b-0c6d-479d-ae12-71acf86587cf":{"id":"ff69705b-0c6d-479d-ae12-71acf86587cf","name":"Miss Moneypenny","gender":"female","age":27}}
diff --git a/042_mongodb/08_hands-on/main.go b/042_mongodb/08_hands-on/main.go
new file mode 100644
index 00000000..0b712be6
--- /dev/null
+++ b/042_mongodb/08_hands-on/main.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/09_solution/controllers"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/09_solution/models"
+ "github.com/julienschmidt/httprouter"
+ "net/http"
+)
+
+func main() {
+ r := httprouter.New()
+ // Get a UserController instance
+ uc := controllers.NewUserController(getSession())
+ r.GET("/user/:id", uc.GetUser)
+ r.POST("/user", uc.CreateUser)
+ r.DELETE("/user/:id", uc.DeleteUser)
+ http.ListenAndServe("localhost:8080", r)
+}
+
+func getSession() map[string]models.User {
+ return models.LoadUsers()
+}
diff --git a/042_mongodb/08_hands-on/models/user.go b/042_mongodb/08_hands-on/models/user.go
new file mode 100644
index 00000000..8f8ac512
--- /dev/null
+++ b/042_mongodb/08_hands-on/models/user.go
@@ -0,0 +1,42 @@
+package models
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+)
+
+// changed Id type to string
+type User struct {
+ Id string `json:"id"`
+ Name string `json:"name" `
+ Gender string `json:"gender"`
+ Age int `json:"age"`
+}
+
+func StoreUsers(m map[string]User) {
+ f, err := os.Create("data")
+ if err != nil {
+ fmt.Println(err)
+ }
+ defer f.Close()
+
+ json.NewEncoder(f).Encode(m)
+}
+
+func LoadUsers() map[string]User {
+ m := make(map[string]User)
+
+ f, err := os.Open("data")
+ if err != nil {
+ fmt.Println(err)
+ return m
+ }
+ defer f.Close()
+
+ err = json.NewDecoder(f).Decode(&m)
+ if err != nil {
+ fmt.Println(err)
+ }
+ return m
+}
diff --git a/042_mongodb/10_hands-on/controllers/general.go b/042_mongodb/10_hands-on/controllers/general.go
new file mode 100644
index 00000000..b9236ab5
--- /dev/null
+++ b/042_mongodb/10_hands-on/controllers/general.go
@@ -0,0 +1,35 @@
+package controllers
+
+import (
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/11_solution/session"
+ "html/template"
+ "net/http"
+)
+
+type Controller struct {
+ tpl *template.Template
+}
+
+func NewController(t *template.Template) *Controller {
+ return &Controller{t}
+}
+
+func (c Controller) Index(w http.ResponseWriter, req *http.Request) {
+ u := session.GetUser(w, req)
+ session.Show() // for demonstration purposes
+ c.tpl.ExecuteTemplate(w, "index.gohtml", u)
+}
+
+func (c Controller) Bar(w http.ResponseWriter, req *http.Request) {
+ u := session.GetUser(w, req)
+ if !session.AlreadyLoggedIn(w, req) {
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ if u.Role != "007" {
+ http.Error(w, "You must be 007 to enter the bar", http.StatusForbidden)
+ return
+ }
+ session.Show() // for demonstration purposes
+ c.tpl.ExecuteTemplate(w, "bar.gohtml", u)
+}
diff --git a/042_mongodb/10_hands-on/controllers/user.go b/042_mongodb/10_hands-on/controllers/user.go
new file mode 100644
index 00000000..82f6dd6b
--- /dev/null
+++ b/042_mongodb/10_hands-on/controllers/user.go
@@ -0,0 +1,116 @@
+package controllers
+
+import (
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/11_solution/models"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/11_solution/session"
+ "github.com/satori/go.uuid"
+ "golang.org/x/crypto/bcrypt"
+ "net/http"
+ "time"
+)
+
+func (c Controller) SignUp(w http.ResponseWriter, req *http.Request) {
+ if session.AlreadyLoggedIn(w, req) {
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ var u models.User
+ // process form submission
+ if req.Method == http.MethodPost {
+ // get form values
+ un := req.FormValue("username")
+ p := req.FormValue("password")
+ f := req.FormValue("firstname")
+ l := req.FormValue("lastname")
+ r := req.FormValue("role")
+ // username taken?
+ if _, ok := session.Users[un]; ok {
+ http.Error(w, "Username already taken", http.StatusForbidden)
+ return
+ }
+ // create session
+ sID, _ := uuid.NewV4()
+ ck := &http.Cookie{
+ Name: "session",
+ Value: sID.String(),
+ }
+ ck.MaxAge = session.Length
+ http.SetCookie(w, ck)
+ session.Sessions[ck.Value] = models.Session{un, time.Now()}
+ // store user in session.Users
+ bs, err := bcrypt.GenerateFromPassword([]byte(p), bcrypt.MinCost)
+ if err != nil {
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+ u = models.User{un, bs, f, l, r}
+ session.Users[un] = u
+ // redirect
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ session.Show() // for demonstration purposes
+ c.tpl.ExecuteTemplate(w, "signup.gohtml", u)
+}
+
+func (c Controller) Login(w http.ResponseWriter, req *http.Request) {
+ if session.AlreadyLoggedIn(w, req) {
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ var u models.User
+ // process form submission
+ if req.Method == http.MethodPost {
+ un := req.FormValue("username")
+ p := req.FormValue("password")
+ // is there a username?
+ u, ok := session.Users[un]
+ if !ok {
+ http.Error(w, "Username and/or password do not match", http.StatusForbidden)
+ return
+ }
+ // does the entered password match the stored password?
+ err := bcrypt.CompareHashAndPassword(u.Password, []byte(p))
+ if err != nil {
+ http.Error(w, "Username and/or password do not match", http.StatusForbidden)
+ return
+ }
+ // create session
+ sID, _ := uuid.NewV4()
+ ck := &http.Cookie{
+ Name: "session",
+ Value: sID.String(),
+ }
+ ck.MaxAge = session.Length
+ http.SetCookie(w, ck)
+ session.Sessions[ck.Value] = models.Session{un, time.Now()}
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ session.Show() // for demonstration purposes
+ c.tpl.ExecuteTemplate(w, "login.gohtml", u)
+}
+
+func (c Controller) Logout(w http.ResponseWriter, req *http.Request) {
+ if !session.AlreadyLoggedIn(w, req) {
+ http.Redirect(w, req, "/", http.StatusSeeOther)
+ return
+ }
+ ck, _ := req.Cookie("session")
+ // delete the session
+ delete(session.Sessions, ck.Value)
+ // remove the cookie
+ ck = &http.Cookie{
+ Name: "session",
+ Value: "",
+ MaxAge: -1,
+ }
+ http.SetCookie(w, ck)
+
+ // clean up session.Sessions
+ if time.Now().Sub(session.LastCleaned) > (time.Second * 30) {
+ go session.Clean()
+ }
+
+ http.Redirect(w, req, "/login", http.StatusSeeOther)
+}
diff --git a/042_mongodb/10_hands-on/main.go b/042_mongodb/10_hands-on/main.go
new file mode 100644
index 00000000..798b0bbd
--- /dev/null
+++ b/042_mongodb/10_hands-on/main.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/11_solution/controllers"
+ "html/template"
+ "net/http"
+)
+
+var tpl *template.Template
+
+func init() {
+ tpl = template.Must(template.ParseGlob("templates/*"))
+}
+
+func main() {
+ c := controllers.NewController(tpl)
+ http.HandleFunc("/", c.Index)
+ http.HandleFunc("/bar", c.Bar)
+ http.HandleFunc("/signup", c.SignUp)
+ http.HandleFunc("/login", c.Login)
+ http.HandleFunc("/logout", c.Logout)
+ http.Handle("/favicon.ico", http.NotFoundHandler())
+ http.ListenAndServe(":8080", nil)
+}
diff --git a/042_mongodb/10_hands-on/models/user.go b/042_mongodb/10_hands-on/models/user.go
new file mode 100644
index 00000000..cc6214a6
--- /dev/null
+++ b/042_mongodb/10_hands-on/models/user.go
@@ -0,0 +1,18 @@
+package models
+
+import "time"
+
+// capitalize to export from package
+type User struct {
+ UserName string
+ Password []byte
+ First string
+ Last string
+ Role string
+}
+
+// capitalize to export from package
+type Session struct {
+ UserName string
+ LastActivity time.Time
+}
diff --git a/042_mongodb/10_hands-on/session/session.go b/042_mongodb/10_hands-on/session/session.go
new file mode 100644
index 00000000..f7cae192
--- /dev/null
+++ b/042_mongodb/10_hands-on/session/session.go
@@ -0,0 +1,78 @@
+package session
+
+import (
+ "fmt"
+ "github.com/GoesToEleven/golang-web-dev/042_mongodb/11_solution/models"
+ "github.com/satori/go.uuid"
+ "net/http"
+ "time"
+)
+
+const Length int = 30
+
+var Users = map[string]models.User{} // user ID, user
+var Sessions = map[string]models.Session{} // session ID, session
+var LastCleaned time.Time = time.Now()
+
+func GetUser(w http.ResponseWriter, req *http.Request) models.User {
+ // get cookie
+ ck, err := req.Cookie("session")
+ if err != nil {
+ sID, _ := uuid.NewV4()
+ ck = &http.Cookie{
+ Name: "session",
+ Value: sID.String(),
+ }
+
+ }
+ ck.MaxAge = Length
+ http.SetCookie(w, ck)
+
+ // if the user exists already, get user
+ var u models.User
+ if s, ok := Sessions[ck.Value]; ok {
+ s.LastActivity = time.Now()
+ Sessions[ck.Value] = s
+ u = Users[s.UserName]
+ }
+ return u
+}
+
+func AlreadyLoggedIn(w http.ResponseWriter, req *http.Request) bool {
+ ck, err := req.Cookie("session")
+ if err != nil {
+ return false
+ }
+ s, ok := Sessions[ck.Value]
+ if ok {
+ s.LastActivity = time.Now()
+ Sessions[ck.Value] = s
+ }
+ _, ok = Users[s.UserName]
+ // refresh session
+ ck.MaxAge = Length
+ http.SetCookie(w, ck)
+ return ok
+}
+
+func Clean() {
+ fmt.Println("BEFORE CLEAN") // for demonstration purposes
+ Show() // for demonstration purposes
+ for k, v := range Sessions {
+ if time.Now().Sub(v.LastActivity) > (time.Second * 30) {
+ delete(Sessions, k)
+ }
+ }
+ LastCleaned = time.Now()
+ fmt.Println("AFTER CLEAN") // for demonstration purposes
+ Show() // for demonstration purposes
+}
+
+// for demonstration purposes
+func Show() {
+ fmt.Println("********")
+ for k, v := range Sessions {
+ fmt.Println(k, v.UserName)
+ }
+ fmt.Println("")
+}
diff --git a/042_mongodb/10_hands-on/templates/bar.gohtml b/042_mongodb/10_hands-on/templates/bar.gohtml
new file mode 100644
index 00000000..ddd56835
--- /dev/null
+++ b/042_mongodb/10_hands-on/templates/bar.gohtml
@@ -0,0 +1,20 @@
+
+
+
+
+ BAR
+
+
+
+Welcome to the bar. What can I get you to drink?
+
+{{if .First}}
+USER NAME {{.UserName}}
+PASSWORD {{.Password}}
+FIRST {{.First}}
+LAST {{.Last}}
+
+{{end}}
+
+
+
\ No newline at end of file
diff --git a/042_mongodb/10_hands-on/templates/index.gohtml b/042_mongodb/10_hands-on/templates/index.gohtml
new file mode 100644
index 00000000..3bc10844
--- /dev/null
+++ b/042_mongodb/10_hands-on/templates/index.gohtml
@@ -0,0 +1,24 @@
+
+
+
+
+ Document
+
+
+
+{{if .First}}
+USER NAME {{.UserName}}
+PASSWORD {{.Password}}
+FIRST {{.First}}
+LAST {{.Last}}
+
+{{else}}
+
+
+{{end}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/042_mongodb/10_hands-on/templates/login.gohtml b/042_mongodb/10_hands-on/templates/login.gohtml
new file mode 100644
index 00000000..eb155256
--- /dev/null
+++ b/042_mongodb/10_hands-on/templates/login.gohtml
@@ -0,0 +1,18 @@
+
+
+
+
+ Document
+
+
+
+LOGIN
+
+
+
+
+
\ No newline at end of file
diff --git a/042_mongodb/10_hands-on/templates/signup.gohtml b/042_mongodb/10_hands-on/templates/signup.gohtml
new file mode 100644
index 00000000..e9188a11
--- /dev/null
+++ b/042_mongodb/10_hands-on/templates/signup.gohtml
@@ -0,0 +1,26 @@
+
+
+
+
+ Document
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/042_mongodb/10_hands-on/wildwest b/042_mongodb/10_hands-on/wildwest
new file mode 100644
index 00000000..35d0d136
Binary files /dev/null and b/042_mongodb/10_hands-on/wildwest differ
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..c028ab16
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# golang-web-dev
+Learn golang for web development. Web Development w/ Google’s Go (golang) Programming.
+
+Web Development w/ Google’s Go (golang) Programming
+https://www.udemy.com/go-programming-language
+
+Course Resource
+* [ Course Documents](https://drive.google.com/drive/folders/0B22KXlqHz6ZNUnZ3Umw2YkFFVms)
+
+Skills
+1. golang
+2. docker
+3. aws
+4. postgreSQL
+5. mongoDB
+
+```
+ > 030_sessions
+ > 045-code-organization
+ > 046_mongodb/15_postgres
+ > 046_mongodb/16_go-mongo
+```
\ No newline at end of file