├── LICENSE
├── README.md
├── section1
├── smptemplate
│ ├── smptemplate.go
│ ├── static
│ │ ├── css
│ │ │ └── gopherface.css
│ │ └── images
│ │ │ └── gogopher.png
│ └── templates
│ │ └── socialmediapost.html
└── templatedemo
│ ├── templatedemo.go
│ └── templates
│ └── greeting.html
├── section2
└── gopherface
│ ├── endpoints
│ ├── createpost.go
│ ├── deletepost.go
│ ├── fetchposts.go
│ └── updatepost.go
│ ├── gopherface.go
│ ├── handlers
│ ├── feed.go
│ ├── find.go
│ ├── foo.go
│ ├── friends.go
│ ├── home.go
│ ├── login.go
│ ├── logout.go
│ ├── myprofile.go
│ ├── panic.go
│ ├── profile.go
│ └── register.go
│ ├── middleware
│ ├── contextexample.go
│ └── panicrecovery.go
│ ├── models
│ └── socialmedia
│ │ ├── moodstate_string.go
│ │ └── socialmedia.go
│ └── templates
│ └── index.html
├── section3
└── gopherfaceform
│ ├── endpoints
│ ├── createpost.go
│ ├── deletepost.go
│ ├── fetchposts.go
│ └── updatepost.go
│ ├── gopherface.go
│ ├── handlers
│ ├── feed.go
│ ├── find.go
│ ├── foo.go
│ ├── friends.go
│ ├── home.go
│ ├── login.go
│ ├── logout.go
│ ├── myprofile.go
│ ├── panic.go
│ ├── postpreview.go
│ ├── profile.go
│ ├── register.go
│ ├── signup.go
│ ├── uploadimage.go
│ ├── uploadvideo.go
│ └── utility.go
│ ├── middleware
│ ├── contextexample.go
│ └── panicrecovery.go
│ ├── models
│ └── socialmedia
│ │ ├── moodstate_string.go
│ │ └── socialmedia.go
│ ├── static
│ ├── css
│ │ ├── gopherface.css
│ │ └── pure.css
│ ├── imageset
│ │ ├── 0083d2f4a81588ed85c06679e68d9855754b498d.png
│ │ ├── 142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
│ │ ├── 21ea6a171c98374b61ffceea7146da1ecaef14d9.png
│ │ ├── 68e3075133cf704244c2b2a61d78fa9adabdf678.png
│ │ ├── 85a586dc6db1483f6014819972e6d709a03e7801.png
│ │ ├── 8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
│ │ ├── a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
│ │ ├── c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
│ │ └── c923378f14eba979d8e81db2fa8259f211af4870.png
│ ├── uploads
│ │ ├── images
│ │ │ └── readme.txt
│ │ └── videos
│ │ │ └── readme.txt
│ └── videoset
│ │ └── 3DGopher.mp4
│ ├── templates
│ ├── imagepreview.html
│ ├── index.html
│ ├── postform.html
│ ├── signupconfirmation.html
│ ├── signupform.html
│ ├── socialmediapost.html
│ ├── uploadimageform.html
│ ├── uploadvideoform.html
│ └── videopreview.html
│ └── validationkit
│ ├── checkusername_test.go
│ └── validationkit.go
├── section4
└── gopherfaceform
│ ├── endpoints
│ ├── createpost.go
│ ├── deletepost.go
│ ├── fetchposts.go
│ └── updatepost.go
│ ├── gopherface.go
│ ├── handlers
│ ├── feed.go
│ ├── find.go
│ ├── foo.go
│ ├── friends.go
│ ├── home.go
│ ├── login.go
│ ├── logout.go
│ ├── myprofile.go
│ ├── panic.go
│ ├── postpreview.go
│ ├── profile.go
│ ├── register.go
│ ├── signup.go
│ ├── uploadimage.go
│ ├── uploadvideo.go
│ └── utility.go
│ ├── middleware
│ ├── contextexample.go
│ └── panicrecovery.go
│ ├── models
│ └── socialmedia
│ │ ├── moodstate_string.go
│ │ └── socialmedia.go
│ ├── static
│ ├── css
│ │ ├── gopherface.css
│ │ └── pure.css
│ ├── imageset
│ │ ├── 0083d2f4a81588ed85c06679e68d9855754b498d.png
│ │ ├── 142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
│ │ ├── 21ea6a171c98374b61ffceea7146da1ecaef14d9.png
│ │ ├── 68e3075133cf704244c2b2a61d78fa9adabdf678.png
│ │ ├── 85a586dc6db1483f6014819972e6d709a03e7801.png
│ │ ├── 8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
│ │ ├── a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
│ │ ├── c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
│ │ └── c923378f14eba979d8e81db2fa8259f211af4870.png
│ ├── uploads
│ │ ├── images
│ │ │ └── readme.txt
│ │ └── videos
│ │ │ └── readme.txt
│ └── videoset
│ │ └── 3DGopher.mp4
│ ├── templates
│ ├── imagepreview.html
│ ├── index.html
│ ├── postform.html
│ ├── signupconfirmation.html
│ ├── signupform.html
│ ├── socialmediapost.html
│ ├── uploadimageform.html
│ ├── uploadvideoform.html
│ └── videopreview.html
│ └── validationkit
│ ├── checkusername_test.go
│ └── validationkit.go
├── section5
└── gopherfacedb
│ ├── common
│ ├── common.go
│ ├── datastore
│ │ ├── datastore.go
│ │ ├── mongodb.go
│ │ ├── mysql.go
│ │ └── redis.go
│ └── utility
│ │ ├── sha256.go
│ │ └── uuid.go
│ ├── config
│ └── gopherfacedb.sql
│ ├── endpoints
│ ├── createpost.go
│ ├── deletepost.go
│ ├── fetchposts.go
│ └── updatepost.go
│ ├── gopherface.go
│ ├── handlers
│ ├── feed.go
│ ├── find.go
│ ├── foo.go
│ ├── friends.go
│ ├── home.go
│ ├── login.go
│ ├── logout.go
│ ├── myprofile.go
│ ├── panic.go
│ ├── postpreview.go
│ ├── profile.go
│ ├── register.go
│ ├── signup.go
│ ├── uploadimage.go
│ ├── uploadvideo.go
│ └── utility.go
│ ├── middleware
│ ├── contextexample.go
│ └── panicrecovery.go
│ ├── models
│ ├── socialmedia
│ │ ├── moodstate_string.go
│ │ └── socialmedia.go
│ └── user.go
│ ├── static
│ ├── css
│ │ ├── gopherface.css
│ │ └── pure.css
│ ├── imageset
│ │ ├── 0083d2f4a81588ed85c06679e68d9855754b498d.png
│ │ ├── 142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
│ │ ├── 21ea6a171c98374b61ffceea7146da1ecaef14d9.png
│ │ ├── 68e3075133cf704244c2b2a61d78fa9adabdf678.png
│ │ ├── 85a586dc6db1483f6014819972e6d709a03e7801.png
│ │ ├── 8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
│ │ ├── a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
│ │ ├── c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
│ │ └── c923378f14eba979d8e81db2fa8259f211af4870.png
│ ├── uploads
│ │ ├── images
│ │ │ └── readme.txt
│ │ └── videos
│ │ │ └── readme.txt
│ └── videoset
│ │ └── 3DGopher.mp4
│ ├── templates
│ ├── imagepreview.html
│ ├── index.html
│ ├── postform.html
│ ├── signupconfirmation.html
│ ├── signupform.html
│ ├── socialmediapost.html
│ ├── uploadimageform.html
│ ├── uploadvideoform.html
│ └── videopreview.html
│ └── validationkit
│ ├── checkusername_test.go
│ └── validationkit.go
├── section6
└── gopherfaceauth
│ ├── certs
│ ├── gopherfacecert.pem
│ └── gopherfacekey.pem
│ ├── common
│ ├── asyncq
│ │ ├── asyncq.go
│ │ └── task.go
│ ├── authenticate
│ │ ├── authenticate.go
│ │ ├── cookie.go
│ │ └── session.go
│ ├── common.go
│ ├── datastore
│ │ ├── datastore.go
│ │ ├── mongodb.go
│ │ ├── mysql.go
│ │ └── redis.go
│ └── utility
│ │ ├── sha256.go
│ │ └── uuid.go
│ ├── config
│ └── gopherfacedb.sql
│ ├── endpoints
│ ├── createpost.go
│ ├── deletepost.go
│ ├── fetchposts.go
│ └── updatepost.go
│ ├── gopherface.go
│ ├── handlers
│ ├── feed.go
│ ├── find.go
│ ├── foo.go
│ ├── friends.go
│ ├── home.go
│ ├── login.go
│ ├── logout.go
│ ├── myprofile.go
│ ├── panic.go
│ ├── postpreview.go
│ ├── profile.go
│ ├── register.go
│ ├── signup.go
│ ├── uploadimage.go
│ ├── uploadvideo.go
│ └── utility.go
│ ├── middleware
│ ├── contextexample.go
│ ├── gated.go
│ └── panicrecovery.go
│ ├── models
│ ├── socialmedia
│ │ ├── moodstate_string.go
│ │ └── socialmedia.go
│ └── user.go
│ ├── static
│ ├── css
│ │ ├── gopherface.css
│ │ └── pure.css
│ ├── imageset
│ │ ├── 0083d2f4a81588ed85c06679e68d9855754b498d.png
│ │ ├── 142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
│ │ ├── 21ea6a171c98374b61ffceea7146da1ecaef14d9.png
│ │ ├── 68e3075133cf704244c2b2a61d78fa9adabdf678.png
│ │ ├── 85a586dc6db1483f6014819972e6d709a03e7801.png
│ │ ├── 8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
│ │ ├── a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
│ │ ├── c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
│ │ └── c923378f14eba979d8e81db2fa8259f211af4870.png
│ ├── uploads
│ │ ├── images
│ │ │ └── readme.txt
│ │ └── videos
│ │ │ └── readme.txt
│ └── videoset
│ │ └── 3DGopher.mp4
│ ├── tasks
│ └── imagetask.go
│ ├── templates
│ ├── feed.html
│ ├── footer.html
│ ├── friends.html
│ ├── gatedheader.html
│ ├── header.html
│ ├── imagepreview.html
│ ├── index.html
│ ├── loginform.html
│ ├── postform.html
│ ├── profile.html
│ ├── signupconfirmation.html
│ ├── signupform.html
│ ├── socialmediapost.html
│ ├── uploadimageform.html
│ ├── uploadvideoform.html
│ └── videopreview.html
│ └── validationkit
│ ├── checkusername_test.go
│ └── validationkit.go
└── section7
└── gopherfaceq
├── certs
├── gopherfacecert.pem
└── gopherfacekey.pem
├── common
├── asyncq
│ ├── asyncq.go
│ └── task.go
├── authenticate
│ ├── authenticate.go
│ ├── cookie.go
│ └── session.go
├── common.go
├── datastore
│ ├── datastore.go
│ ├── mongodb.go
│ ├── mysql.go
│ └── redis.go
└── utility
│ ├── sha256.go
│ └── uuid.go
├── config
└── gopherfacedb.sql
├── endpoints
├── createpost.go
├── deletepost.go
├── fetchposts.go
└── updatepost.go
├── gopherface.go
├── handlers
├── feed.go
├── find.go
├── foo.go
├── friends.go
├── home.go
├── login.go
├── logout.go
├── myprofile.go
├── panic.go
├── postpreview.go
├── profile.go
├── register.go
├── signup.go
├── uploadimage.go
├── uploadvideo.go
└── utility.go
├── middleware
├── contextexample.go
├── gated.go
└── panicrecovery.go
├── models
├── socialmedia
│ ├── moodstate_string.go
│ └── socialmedia.go
└── user.go
├── static
├── css
│ ├── gopherface.css
│ └── pure.css
├── imageset
│ ├── 0083d2f4a81588ed85c06679e68d9855754b498d.png
│ ├── 142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
│ ├── 21ea6a171c98374b61ffceea7146da1ecaef14d9.png
│ ├── 68e3075133cf704244c2b2a61d78fa9adabdf678.png
│ ├── 85a586dc6db1483f6014819972e6d709a03e7801.png
│ ├── 8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
│ ├── a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
│ ├── c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
│ └── c923378f14eba979d8e81db2fa8259f211af4870.png
├── uploads
│ ├── images
│ │ └── readme.txt
│ └── videos
│ │ └── readme.txt
└── videoset
│ └── 3DGopher.mp4
├── tasks
└── imagetask.go
├── templates
├── feed.html
├── footer.html
├── friends.html
├── gatedheader.html
├── header.html
├── imagepreview.html
├── index.html
├── loginform.html
├── postform.html
├── profile.html
├── signupconfirmation.html
├── signupform.html
├── socialmediapost.html
├── uploadimageform.html
├── uploadvideoform.html
└── videopreview.html
└── validationkit
├── checkusername_test.go
└── validationkit.go
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/section1/smptemplate/smptemplate.go:
--------------------------------------------------------------------------------
1 | // Simple example of creating and using a template in Go
2 | package main
3 |
4 | import (
5 | "fmt"
6 | "html/template"
7 | "log"
8 | "net/http"
9 |
10 | "github.com/EngineerKamesh/gofullstack/volume1/section5/socialmedia"
11 | )
12 |
13 | // Handler for displaying a social media post
14 | func displaySocialMediaPostHandler(w http.ResponseWriter, r *http.Request) {
15 |
16 | myPost := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
17 | fmt.Printf("myPost: %+v\n", myPost)
18 | renderTemplate(w, "./templates/socialmediapost.html", myPost)
19 | }
20 |
21 | // Template rendering function
22 | func renderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
23 |
24 | t, err := template.ParseFiles(templateFile)
25 | if err != nil {
26 | log.Fatal("Error encountered while parsing the template: ", err)
27 | }
28 | t.Execute(w, templateData)
29 | }
30 |
31 | func main() {
32 |
33 | http.HandleFunc("/display-social-media-post", displaySocialMediaPostHandler)
34 | http.Handle("/", http.FileServer(http.Dir("./static")))
35 | http.ListenAndServe(":8080", nil)
36 | }
37 |
--------------------------------------------------------------------------------
/section1/smptemplate/static/css/gopherface.css:
--------------------------------------------------------------------------------
1 | body {
2 |
3 | font-family: arial, helvetica;
4 | font-size: 12pt;
5 |
6 | }
7 |
8 | .smpostContainer {
9 |
10 | border: 1px solid #CCC;
11 | width: 504px;
12 | min-height: 108px;
13 | margin: auto;
14 | padding: 18px;
15 | box-shadow: 1px 1px 3px #888;
16 | }
17 |
18 | .author {
19 |
20 |
21 | }
22 |
23 | .caption {
24 |
25 | font-weight: bold;
26 | font-size: 18pt;
27 | }
28 |
29 | .caption a {
30 | text-decoration: none;
31 | }
32 |
33 | .creationtime {
34 |
35 | }
36 |
37 | .createdby {
38 | color: blue;
39 | }
40 |
41 | .imagePreview {
42 | text-align: center;
43 | margin-top: 18px;
44 | }
45 |
46 | .msgBody {
47 | margin-top: 27px;
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/section1/smptemplate/static/images/gogopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section1/smptemplate/static/images/gogopher.png
--------------------------------------------------------------------------------
/section1/smptemplate/templates/socialmediapost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Social Media Post Example
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 | {{.CreatedBy}}
21 | {{.TimeCreated}}
22 |
23 |
24 |
25 |

26 |
27 |
28 |
29 | {{.MessageBody}}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/section1/templatedemo/templatedemo.go:
--------------------------------------------------------------------------------
1 | // Simple example of creating and using a template in Go
2 | package main
3 |
4 | import (
5 | "html/template"
6 | "log"
7 | "net/http"
8 | )
9 |
10 | // Type representing a gopher
11 | type Gopher struct {
12 | Name string
13 | }
14 |
15 | // Handler for the hello-gopher route
16 | func helloGopherHandler(w http.ResponseWriter, r *http.Request) {
17 |
18 | var gophername string
19 | gophername = r.URL.Query().Get("gophername")
20 | if gophername == "" {
21 | gophername = "Gopher"
22 | }
23 | gopher := Gopher{Name: gophername}
24 | renderTemplate(w, "./templates/greeting.html", gopher)
25 |
26 | }
27 |
28 | // Template rendering function
29 | func renderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
30 | t, err := template.ParseFiles(templateFile)
31 | if err != nil {
32 | log.Fatal("Error encountered while parsing the template: ", err)
33 | }
34 | t.Execute(w, templateData)
35 | }
36 |
37 | func main() {
38 | http.HandleFunc("/hello-gopher", helloGopherHandler)
39 | http.ListenAndServe(":8080", nil)
40 | }
41 |
--------------------------------------------------------------------------------
/section1/templatedemo/templates/greeting.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello {{.Name}}!
5 |
6 |
7 |
--------------------------------------------------------------------------------
/section2/gopherface/endpoints/createpost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func CreatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the create post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section2/gopherface/endpoints/deletepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func DeletePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the delete post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section2/gopherface/endpoints/fetchposts.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section2/gopherface/models/socialmedia"
10 | )
11 |
12 | func FetchPostsEndpoint(w http.ResponseWriter, r *http.Request) {
13 |
14 | // TODO: Implement fetching posts for a given user
15 |
16 | // We are going to create some mock data and send it out in JSON
17 | // format.
18 |
19 | // We will actually implement this endpoint, when we cover database
20 | // persistence later in the course.
21 |
22 | v := mux.Vars(r)
23 |
24 | if v["username"] == "EngineerKamesh" {
25 |
26 | mockPosts := make([]socialmedia.Post, 3)
27 |
28 | post1 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
29 | post2 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["happy"], "Tour of Go", "Check out the Tour of Go!", "https://tour.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
30 | post3 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["hopeful"], "Go Playground", "Check out the Go Playground!", "https://playground.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
31 |
32 | mockPosts = append(mockPosts, *post1)
33 | mockPosts = append(mockPosts, *post2)
34 | mockPosts = append(mockPosts, *post3)
35 | json.NewEncoder(w).Encode(mockPosts)
36 |
37 | } else {
38 | json.NewEncoder(w).Encode(nil)
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/section2/gopherface/endpoints/updatepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func UpdatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the update post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section2/gopherface/gopherface.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "os"
6 |
7 | "github.com/EngineerKamesh/gofullstack/volume2/section2/gopherface/endpoints"
8 | "github.com/EngineerKamesh/gofullstack/volume2/section2/gopherface/handlers"
9 | "github.com/EngineerKamesh/gofullstack/volume2/section2/gopherface/middleware"
10 | ghandlers "github.com/gorilla/handlers"
11 | "github.com/gorilla/mux"
12 | )
13 |
14 | const (
15 | WEBSERVERPORT = ":8080"
16 | )
17 |
18 | func main() {
19 |
20 | r := mux.NewRouter()
21 | r.HandleFunc("/", handlers.HomeHandler)
22 | r.HandleFunc("/register", handlers.RegisterHandler).Methods("GET,POST")
23 | r.HandleFunc("/login", handlers.LoginHandler).Methods("POST")
24 | r.HandleFunc("/logout", handlers.LogoutHandler).Methods("POST")
25 | r.HandleFunc("/feed", handlers.FeedHandler).Methods("GET")
26 | r.HandleFunc("/friends", handlers.FriendsHandler).Methods("GET")
27 | r.HandleFunc("/find", handlers.FindHandler).Methods("GET,POST")
28 | r.HandleFunc("/profile", handlers.MyProfileHandler).Methods("GET")
29 | r.HandleFunc("/profile/{username}", handlers.ProfileHandler).Methods("GET")
30 | r.HandleFunc("/triggerpanic", handlers.TriggerPanicHandler).Methods("GET")
31 | r.HandleFunc("/foo", handlers.FooHandler).Methods("GET")
32 |
33 | r.HandleFunc("/restapi/socialmediapost/{username}", endpoints.FetchPostsEndpoint).Methods("GET")
34 | r.HandleFunc("/restapi/socialmediapost/{postid}", endpoints.CreatePostEndpoint).Methods("POST")
35 | r.HandleFunc("/restapi/socialmediapost/{postid}", endpoints.UpdatePostEndpoint).Methods("PUT")
36 | r.HandleFunc("/restapi/socialmediapost/{postid}", endpoints.DeletePostEndpoint).Methods("DELETE")
37 |
38 | //http.Handle("/", r)
39 | //http.Handle("/", ghandlers.LoggingHandler(os.Stdout, r))
40 | //http.Handle("/", middleware.PanicRecoveryHandler(ghandlers.LoggingHandler(os.Stdout, r)))
41 | http.Handle("/", middleware.ContextExampleHandler(middleware.PanicRecoveryHandler(ghandlers.LoggingHandler(os.Stdout, r))))
42 |
43 | http.ListenAndServe(WEBSERVERPORT, nil)
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/feed.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FeedHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/find.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FindHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/foo.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func FooHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | fooID := r.Context().Value("fooID").(string)
10 | w.Write([]byte(fooID))
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/friends.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FriendsHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/home.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func HomeHandler(w http.ResponseWriter, r *http.Request) {
9 |
10 | fmt.Println("test")
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/login.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LoginHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/logout.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LogoutHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/myprofile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func MyProfileHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | w.Write([]byte("profile"))
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/panic.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func TriggerPanicHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | panic("Triggering a Panic!")
10 | }
11 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/profile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/mux"
7 | )
8 |
9 | func ProfileHandler(w http.ResponseWriter, r *http.Request) {
10 |
11 | vars := mux.Vars(r)
12 | username := vars["username"]
13 | w.Write([]byte(username))
14 | }
15 |
--------------------------------------------------------------------------------
/section2/gopherface/handlers/register.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func RegisterHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section2/gopherface/middleware/contextexample.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | )
7 |
8 | func newExampleContext(ctx context.Context, r *http.Request) context.Context {
9 |
10 | fooID := r.Header.Get("X-Foo-ID")
11 | if fooID == "" {
12 | fooID = "bar"
13 | }
14 |
15 | return context.WithValue(ctx, "fooID", fooID)
16 |
17 | }
18 |
19 | func ContextExampleHandler(next http.Handler) http.Handler {
20 |
21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 |
23 | defer func() {
24 |
25 | ctx := newExampleContext(r.Context(), r)
26 | next.ServeHTTP(w, r.WithContext(ctx))
27 |
28 | }()
29 |
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/section2/gopherface/middleware/panicrecovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func PanicRecoveryHandler(next http.Handler) http.Handler {
9 |
10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 |
12 | defer func() {
13 |
14 | if err := recover(); err != nil {
15 | log.Printf("Encountered panic: %+v", err)
16 | http.Error(w, http.StatusText(500), 500)
17 | }
18 |
19 | }()
20 |
21 | next.ServeHTTP(w, r)
22 |
23 | })
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/section2/gopherface/models/socialmedia/moodstate_string.go:
--------------------------------------------------------------------------------
1 | // Code generated by "stringer -type=MoodState"; DO NOT EDIT
2 |
3 | package socialmedia
4 |
5 | import "fmt"
6 |
7 | const _MoodState_name = "MoodStateNeutralMoodStateHappyMoodStateSadMoodStateAngryMoodStateHopefulMoodStateThrilledMoodStateBoredMoodStateShyMoodStateComicalMoodStateOnCloudNine"
8 |
9 | var _MoodState_index = [...]uint8{0, 16, 30, 42, 56, 72, 89, 103, 115, 131, 151}
10 |
11 | func (i MoodState) String() string {
12 | if i < 0 || i >= MoodState(len(_MoodState_index)-1) {
13 | return fmt.Sprintf("MoodState(%d)", i)
14 | }
15 | return _MoodState_name[_MoodState_index[i]:_MoodState_index[i+1]]
16 | }
17 |
--------------------------------------------------------------------------------
/section2/gopherface/templates/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section2/gopherface/templates/index.html
--------------------------------------------------------------------------------
/section3/gopherfaceform/endpoints/createpost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func CreatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the create post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/endpoints/deletepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func DeletePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the delete post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/endpoints/fetchposts.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section3/gopherfaceform/models/socialmedia"
10 | )
11 |
12 | func FetchPostsEndpoint(w http.ResponseWriter, r *http.Request) {
13 |
14 | // TODO: Implement fetching posts for a given user
15 |
16 | // We are going to create some mock data and send it out in JSON
17 | // format.
18 |
19 | // We will actually implement this endpoint, when we cover database
20 | // persistence later in the course.
21 |
22 | v := mux.Vars(r)
23 |
24 | if v["username"] == "EngineerKamesh" {
25 |
26 | mockPosts := make([]socialmedia.Post, 3)
27 |
28 | post1 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
29 | post2 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["happy"], "Tour of Go", "Check out the Tour of Go!", "https://tour.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
30 | post3 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["hopeful"], "Go Playground", "Check out the Go Playground!", "https://playground.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
31 |
32 | mockPosts = append(mockPosts, *post1)
33 | mockPosts = append(mockPosts, *post2)
34 | mockPosts = append(mockPosts, *post3)
35 | json.NewEncoder(w).Encode(mockPosts)
36 |
37 | } else {
38 | json.NewEncoder(w).Encode(nil)
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/endpoints/updatepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func UpdatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the update post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/gopherface.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/EngineerKamesh/gofullstack/volume2/section3/gopherfaceform/handlers"
5 | "github.com/EngineerKamesh/gofullstack/volume2/section3/gopherfaceform/middleware"
6 |
7 | "net/http"
8 | "os"
9 |
10 | ghandlers "github.com/gorilla/handlers"
11 | "github.com/gorilla/mux"
12 | )
13 |
14 | const (
15 | WEBSERVERPORT = ":8080"
16 | )
17 |
18 | func main() {
19 |
20 | r := mux.NewRouter()
21 | r.HandleFunc("/", handlers.HomeHandler)
22 | r.HandleFunc("/register", handlers.RegisterHandler).Methods("GET,POST")
23 | r.HandleFunc("/login", handlers.LoginHandler).Methods("POST")
24 | r.HandleFunc("/logout", handlers.LogoutHandler).Methods("POST")
25 | r.HandleFunc("/feed", handlers.FeedHandler).Methods("GET")
26 | r.HandleFunc("/friends", handlers.FriendsHandler).Methods("GET")
27 | r.HandleFunc("/find", handlers.FindHandler).Methods("GET,POST")
28 | r.HandleFunc("/profile", handlers.MyProfileHandler).Methods("GET")
29 | r.HandleFunc("/profile/{username}", handlers.ProfileHandler)
30 | r.HandleFunc("/triggerpanic", handlers.TriggerPanicHandler)
31 | r.HandleFunc("/foo", handlers.FooHandler)
32 | r.HandleFunc("/signup", handlers.SignUpHandler).Methods("GET", "POST")
33 | r.HandleFunc("/postpreview", handlers.PostPreviewHandler).Methods("GET", "POST")
34 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
35 | http.Handle("/", middleware.PanicRecoveryHandler(ghandlers.LoggingHandler(os.Stdout, r)))
36 | http.ListenAndServe(WEBSERVERPORT, nil)
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/feed.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FeedHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/find.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FindHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/foo.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func FooHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | fooID := r.Context().Value("fooID").(string)
10 | w.Write([]byte(fooID))
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/friends.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FriendsHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/home.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func HomeHandler(w http.ResponseWriter, r *http.Request) {
9 |
10 | fmt.Println("home page handler reached")
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/login.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LoginHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/logout.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LogoutHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/myprofile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func MyProfileHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | w.Write([]byte("profile"))
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/panic.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func TriggerPanicHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | panic("Triggering a Panic!")
10 | }
11 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/profile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/mux"
7 | )
8 |
9 | func ProfileHandler(w http.ResponseWriter, r *http.Request) {
10 |
11 | vars := mux.Vars(r)
12 | username := vars["username"]
13 | w.Write([]byte(username))
14 | }
15 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/register.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func RegisterHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/handlers/utility.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 | "os"
9 | ttemplate "text/template"
10 | )
11 |
12 | // Template rendering function
13 | func RenderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
14 | t, err := template.ParseFiles(templateFile)
15 | if err != nil {
16 | log.Printf("Error encountered while parsing the template: ", err)
17 | }
18 | t.Execute(w, templateData)
19 | }
20 |
21 | func RenderUnsafeTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
22 | t, err := ttemplate.ParseFiles(templateFile)
23 | if err != nil {
24 | log.Printf("Error encountered while parsing the template: ", err)
25 | }
26 | w.Header().Set("X-XSS-Protection", "0")
27 | t.Execute(w, templateData)
28 | }
29 |
30 | func GenerateUUID() string {
31 | f, err := os.Open("/dev/urandom")
32 | if err != nil {
33 | log.Println("Encountered the following error when attempting to generate an UUID: ", err)
34 | return ""
35 | }
36 | b := make([]byte, 16)
37 | f.Read(b)
38 | f.Close()
39 | uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
40 | return uuid
41 | }
42 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/middleware/contextexample.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | )
7 |
8 | func newExampleContext(ctx context.Context, r *http.Request) context.Context {
9 |
10 | fooID := r.Header.Get("X-Foo-ID")
11 | if fooID == "" {
12 | fooID = "bar"
13 | }
14 |
15 | return context.WithValue(ctx, "fooID", fooID)
16 |
17 | }
18 |
19 | func ContextExampleHandler(next http.Handler) http.Handler {
20 |
21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 |
23 | defer func() {
24 |
25 | ctx := newExampleContext(r.Context(), r)
26 | next.ServeHTTP(w, r.WithContext(ctx))
27 |
28 | }()
29 |
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/middleware/panicrecovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func PanicRecoveryHandler(next http.Handler) http.Handler {
9 |
10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 |
12 | defer func() {
13 |
14 | if err := recover(); err != nil {
15 | log.Printf("Encountered panic: %+v", err)
16 | http.Error(w, http.StatusText(500), 500)
17 | }
18 |
19 | }()
20 |
21 | next.ServeHTTP(w, r)
22 |
23 | })
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/models/socialmedia/moodstate_string.go:
--------------------------------------------------------------------------------
1 | // Code generated by "stringer -type=MoodState"; DO NOT EDIT
2 |
3 | package socialmedia
4 |
5 | import "fmt"
6 |
7 | const _MoodState_name = "MoodStateNeutralMoodStateHappyMoodStateSadMoodStateAngryMoodStateHopefulMoodStateThrilledMoodStateBoredMoodStateShyMoodStateComicalMoodStateOnCloudNine"
8 |
9 | var _MoodState_index = [...]uint8{0, 16, 30, 42, 56, 72, 89, 103, 115, 131, 151}
10 |
11 | func (i MoodState) String() string {
12 | if i < 0 || i >= MoodState(len(_MoodState_index)-1) {
13 | return fmt.Sprintf("MoodState(%d)", i)
14 | }
15 | return _MoodState_name[_MoodState_index[i]:_MoodState_index[i+1]]
16 | }
17 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/css/gopherface.css:
--------------------------------------------------------------------------------
1 | body {
2 |
3 | font-family: arial, helvetica;
4 | font-size: 12pt;
5 | margin-left: 18px;
6 |
7 | }
8 |
9 | .smpostContainer {
10 |
11 | border: 1px solid #CCC;
12 | width: 540px;
13 | min-height: 108px;
14 | padding: 18px;
15 | box-shadow: 1px 1px 3px #888;
16 | }
17 |
18 | .smpostFormContainer {
19 | width: 720px;
20 | }
21 |
22 | .uploadFormContainer {
23 | width: 720px;
24 | }
25 |
26 | #messageBody {
27 | min-height: 207px;
28 | }
29 |
30 | .author {
31 |
32 |
33 | }
34 |
35 | .caption {
36 |
37 | font-weight: bold;
38 | font-size: 18pt;
39 | }
40 |
41 | .caption a {
42 | text-decoration: none;
43 | }
44 |
45 | .creationtime {
46 |
47 | }
48 |
49 | .createdby {
50 | color: blue;
51 | }
52 |
53 | .imagePreview {
54 | text-align: center;
55 | margin-top: 18px;
56 | }
57 |
58 | .msgBody {
59 | margin-top: 27px;
60 |
61 | }
62 |
63 | /* pure overrides */
64 | .pure-form-message-inline {
65 | color: red !important;
66 | }
67 |
68 | .pure-control-group label, label{
69 | color: gray;
70 | font-weight: bold;
71 | font-size: 0.93em;
72 | }
73 |
74 | .imageContainer {
75 |
76 | display: inline;
77 | margin-right: 27px;
78 | }
79 |
80 | .videoContainer {
81 | display: inline;
82 | }
83 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/uploads/images/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded image files.
2 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/uploads/videos/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded video files.
2 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/static/videoset/3DGopher.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/static/videoset/3DGopher.mp4
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/imagepreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Gopherface - Image Preview
5 |
6 |
7 |
8 | GopherFace - Image Preview
9 |
10 |
11 |
12 |
13 |

14 |
15 |
16 |
17 |
18 |

19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section3/gopherfaceform/templates/index.html
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/postform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - New Post
4 |
5 |
6 |
7 |
8 | GopherFace - New Post
9 |
10 |
11 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/signupconfirmation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - Sign Up Confirmation
4 |
5 |
6 |
7 | GopherFace - Sign Up Confirmation
8 |
9 |
10 | Thank you {{.Fields.firstName}}!
11 | We have received your form submission!
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/socialmediapost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Social Media Post Example
8 |
9 |
10 |
11 |
12 | {{.Caption}}
13 |
14 |
15 |
16 |
17 | {{.CreatedBy}} {{.AuthorMoodEmoji}}
18 | {{.TimeCreated}}
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 | {{.MessageBody}}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/uploadimageform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Image
4 |
5 |
6 |
7 |
8 | Gopherface - Upload Image
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/uploadvideoform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Video
4 |
5 |
6 |
7 |
8 | GopherFace - Upload Video
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/templates/videopreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | GopherFace - Video Preview
8 |
9 |
10 |
11 |
12 |

13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/validationkit/checkusername_test.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // Test for minimum number of characters
8 | func TestCheckUsernameSyntaxMinimumCharacterLength(t *testing.T) {
9 |
10 | result := CheckUsernameSyntax("")
11 |
12 | if result != false {
13 | t.Errorf("Failed the minimum character check.")
14 |
15 | }
16 |
17 | }
18 |
19 | // Test for maximum number of characters
20 | func TestCheckUsernameSyntaxMaximumCharacterLength(t *testing.T) {
21 |
22 | result := CheckUsernameSyntax("aaaaaaaaaaaaaaaa")
23 |
24 | if result != false {
25 | t.Errorf("Failed the maximum character check.")
26 |
27 | }
28 |
29 | }
30 |
31 | func TestCheckUsernameSyntaxSymbols(t *testing.T) {
32 |
33 | result := CheckUsernameSyntax("g-@p!h#r")
34 | if result != false {
35 | t.Errorf("Failed the special character check.")
36 |
37 | }
38 |
39 | }
40 |
41 | func TestCheckUsernameSyntaxUnderscore(t *testing.T) {
42 |
43 | // Underscores are permissible
44 | result := CheckUsernameSyntax("the_gopher")
45 | if result != true {
46 | t.Errorf("Failed the check to allow underscore characters.")
47 |
48 | }
49 |
50 | }
51 |
52 | func TestCheckUsernameSyntaxAtSignInsideUsername(t *testing.T) {
53 |
54 | // The @ sign can only be placed at the start of the username string and is invalid anyhwere else
55 | result := CheckUsernameSyntax("the@gopher")
56 | if result != false {
57 | t.Errorf("Failed the @ sign check. The @ sign was found in another place besides the start of the string.")
58 | }
59 | }
60 |
61 | func TestCheckUsernameSyntaxRandomUsernames(t *testing.T) {
62 |
63 | for i := 0; i < 10008; i++ {
64 |
65 | username := GenerateRandomUsername()
66 | //fmt.Println("username: ", username)
67 | result := CheckUsernameSyntax(username)
68 | if result != true {
69 | t.Errorf("The random username, ", username, ", failed to pass the username check.")
70 | t.Fatal("Quitting!")
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/section3/gopherfaceform/validationkit/validationkit.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "log"
5 | "math/rand"
6 | "regexp"
7 | "time"
8 | )
9 |
10 | const UsernameRegex string = `^@?(\w){1,15}$`
11 | const EmailRegex = `(?i)^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})+$`
12 |
13 | func CheckUsernameSyntax(username string) bool {
14 |
15 | validationResult := false
16 | r, err := regexp.Compile(UsernameRegex)
17 | if err != nil {
18 | log.Fatal(err)
19 | }
20 | validationResult = r.MatchString(username)
21 | return validationResult
22 | }
23 |
24 | func CheckEmailSyntax(email string) bool {
25 | validationResult := false
26 | r, err := regexp.Compile(EmailRegex)
27 | if err != nil {
28 | log.Fatal(err)
29 | }
30 | validationResult = r.MatchString(email)
31 | return validationResult
32 | }
33 |
34 | func GenerateRandomUsername() string {
35 |
36 | rand.Seed(time.Now().UnixNano())
37 |
38 | usernameLength := rand.Intn(15) + 1
39 |
40 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
41 | b := make([]rune, usernameLength)
42 | for i := range b {
43 | b[i] = letterRunes[rand.Intn(len(letterRunes))]
44 | }
45 | randomUsername := string(b)
46 |
47 | zeroOrOne := rand.Intn(2)
48 | if zeroOrOne == 1 {
49 | randomUsername = "@" + randomUsername
50 | }
51 | return randomUsername
52 | }
53 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/endpoints/createpost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func CreatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the create post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/endpoints/deletepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func DeletePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the delete post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/endpoints/fetchposts.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section4/gopherfaceform/models/socialmedia"
10 | )
11 |
12 | func FetchPostsEndpoint(w http.ResponseWriter, r *http.Request) {
13 |
14 | // TODO: Implement fetching posts for a given user
15 |
16 | // We are going to create some mock data and send it out in JSON
17 | // format.
18 |
19 | // We will actually implement this endpoint, when we cover database
20 | // persistence later in the course.
21 |
22 | v := mux.Vars(r)
23 |
24 | if v["username"] == "EngineerKamesh" {
25 |
26 | mockPosts := make([]socialmedia.Post, 3)
27 |
28 | post1 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
29 | post2 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["happy"], "Tour of Go", "Check out the Tour of Go!", "https://tour.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
30 | post3 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["hopeful"], "Go Playground", "Check out the Go Playground!", "https://playground.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
31 |
32 | mockPosts = append(mockPosts, *post1)
33 | mockPosts = append(mockPosts, *post2)
34 | mockPosts = append(mockPosts, *post3)
35 | json.NewEncoder(w).Encode(mockPosts)
36 |
37 | } else {
38 | json.NewEncoder(w).Encode(nil)
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/endpoints/updatepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func UpdatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the update post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/gopherface.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/EngineerKamesh/gofullstack/volume2/section4/gopherfaceform/handlers"
5 | "github.com/EngineerKamesh/gofullstack/volume2/section4/gopherfaceform/middleware"
6 |
7 | "net/http"
8 | "os"
9 |
10 | ghandlers "github.com/gorilla/handlers"
11 | "github.com/gorilla/mux"
12 | )
13 |
14 | const (
15 | WEBSERVERPORT = ":8080"
16 | )
17 |
18 | func main() {
19 |
20 | r := mux.NewRouter()
21 | r.HandleFunc("/", handlers.HomeHandler)
22 | r.HandleFunc("/register", handlers.RegisterHandler).Methods("GET,POST")
23 | r.HandleFunc("/login", handlers.LoginHandler).Methods("POST")
24 | r.HandleFunc("/logout", handlers.LogoutHandler).Methods("POST")
25 | r.HandleFunc("/feed", handlers.FeedHandler).Methods("GET")
26 | r.HandleFunc("/friends", handlers.FriendsHandler).Methods("GET")
27 | r.HandleFunc("/find", handlers.FindHandler).Methods("GET,POST")
28 | r.HandleFunc("/profile", handlers.MyProfileHandler).Methods("GET")
29 | r.HandleFunc("/profile/{username}", handlers.ProfileHandler)
30 | r.HandleFunc("/triggerpanic", handlers.TriggerPanicHandler)
31 | r.HandleFunc("/foo", handlers.FooHandler)
32 | r.HandleFunc("/signup", handlers.SignUpHandler).Methods("GET", "POST")
33 | r.HandleFunc("/postpreview", handlers.PostPreviewHandler).Methods("GET", "POST")
34 | r.HandleFunc("/upload-image", handlers.UploadImageHandler).Methods("GET", "POST")
35 | r.HandleFunc("/upload-video", handlers.UploadVideoHandler).Methods("GET", "POST")
36 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
37 | http.Handle("/", middleware.PanicRecoveryHandler(ghandlers.LoggingHandler(os.Stdout, r)))
38 | http.ListenAndServe(WEBSERVERPORT, nil)
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/feed.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FeedHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/find.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FindHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/foo.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func FooHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | fooID := r.Context().Value("fooID").(string)
10 | w.Write([]byte(fooID))
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/friends.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FriendsHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/home.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func HomeHandler(w http.ResponseWriter, r *http.Request) {
9 |
10 | fmt.Println("home page handler reached")
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/login.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LoginHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/logout.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LogoutHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/myprofile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func MyProfileHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | w.Write([]byte("profile"))
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/panic.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func TriggerPanicHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | panic("Triggering a Panic!")
10 | }
11 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/profile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/mux"
7 | )
8 |
9 | func ProfileHandler(w http.ResponseWriter, r *http.Request) {
10 |
11 | vars := mux.Vars(r)
12 | username := vars["username"]
13 | w.Write([]byte(username))
14 | }
15 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/register.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func RegisterHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/handlers/utility.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 | "os"
9 | ttemplate "text/template"
10 | )
11 |
12 | // Template rendering function
13 | func RenderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
14 | t, err := template.ParseFiles(templateFile)
15 | if err != nil {
16 | log.Printf("Error encountered while parsing the template: ", err)
17 | }
18 | t.Execute(w, templateData)
19 | }
20 |
21 | func RenderUnsafeTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
22 | t, err := ttemplate.ParseFiles(templateFile)
23 | if err != nil {
24 | log.Printf("Error encountered while parsing the template: ", err)
25 | }
26 | w.Header().Set("X-XSS-Protection", "0")
27 | t.Execute(w, templateData)
28 | }
29 |
30 | func GenerateUUID() string {
31 | f, err := os.Open("/dev/urandom")
32 | if err != nil {
33 | log.Println("Encountered the following error when attempting to generate an UUID: ", err)
34 | return ""
35 | }
36 | b := make([]byte, 16)
37 | f.Read(b)
38 | f.Close()
39 | uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
40 | return uuid
41 | }
42 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/middleware/contextexample.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | )
7 |
8 | func newExampleContext(ctx context.Context, r *http.Request) context.Context {
9 |
10 | fooID := r.Header.Get("X-Foo-ID")
11 | if fooID == "" {
12 | fooID = "bar"
13 | }
14 |
15 | return context.WithValue(ctx, "fooID", fooID)
16 |
17 | }
18 |
19 | func ContextExampleHandler(next http.Handler) http.Handler {
20 |
21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 |
23 | defer func() {
24 |
25 | ctx := newExampleContext(r.Context(), r)
26 | next.ServeHTTP(w, r.WithContext(ctx))
27 |
28 | }()
29 |
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/middleware/panicrecovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func PanicRecoveryHandler(next http.Handler) http.Handler {
9 |
10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 |
12 | defer func() {
13 |
14 | if err := recover(); err != nil {
15 | log.Printf("Encountered panic: %+v", err)
16 | http.Error(w, http.StatusText(500), 500)
17 | }
18 |
19 | }()
20 |
21 | next.ServeHTTP(w, r)
22 |
23 | })
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/models/socialmedia/moodstate_string.go:
--------------------------------------------------------------------------------
1 | // Code generated by "stringer -type=MoodState"; DO NOT EDIT
2 |
3 | package socialmedia
4 |
5 | import "fmt"
6 |
7 | const _MoodState_name = "MoodStateNeutralMoodStateHappyMoodStateSadMoodStateAngryMoodStateHopefulMoodStateThrilledMoodStateBoredMoodStateShyMoodStateComicalMoodStateOnCloudNine"
8 |
9 | var _MoodState_index = [...]uint8{0, 16, 30, 42, 56, 72, 89, 103, 115, 131, 151}
10 |
11 | func (i MoodState) String() string {
12 | if i < 0 || i >= MoodState(len(_MoodState_index)-1) {
13 | return fmt.Sprintf("MoodState(%d)", i)
14 | }
15 | return _MoodState_name[_MoodState_index[i]:_MoodState_index[i+1]]
16 | }
17 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/css/gopherface.css:
--------------------------------------------------------------------------------
1 | body {
2 |
3 | font-family: arial, helvetica;
4 | font-size: 12pt;
5 | margin-left: 18px;
6 |
7 | }
8 |
9 | .smpostContainer {
10 |
11 | border: 1px solid #CCC;
12 | width: 540px;
13 | min-height: 108px;
14 | padding: 18px;
15 | box-shadow: 1px 1px 3px #888;
16 | }
17 |
18 | .smpostFormContainer {
19 | width: 720px;
20 | }
21 |
22 | .uploadFormContainer {
23 | width: 720px;
24 | }
25 |
26 | #messageBody {
27 | min-height: 207px;
28 | }
29 |
30 | .author {
31 |
32 |
33 | }
34 |
35 | .caption {
36 |
37 | font-weight: bold;
38 | font-size: 18pt;
39 | }
40 |
41 | .caption a {
42 | text-decoration: none;
43 | }
44 |
45 | .creationtime {
46 |
47 | }
48 |
49 | .createdby {
50 | color: blue;
51 | }
52 |
53 | .imagePreview {
54 | text-align: center;
55 | margin-top: 18px;
56 | }
57 |
58 | .msgBody {
59 | margin-top: 27px;
60 |
61 | }
62 |
63 | /* pure overrides */
64 | .pure-form-message-inline {
65 | color: red !important;
66 | }
67 |
68 | .pure-control-group label, label{
69 | color: gray;
70 | font-weight: bold;
71 | font-size: 0.93em;
72 | }
73 |
74 | .imageContainer {
75 |
76 | display: inline;
77 | margin-right: 27px;
78 | }
79 |
80 | .videoContainer {
81 | display: inline;
82 | }
83 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/uploads/images/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded image files.
2 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/uploads/videos/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded video files.
2 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/static/videoset/3DGopher.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/static/videoset/3DGopher.mp4
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/imagepreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Gopherface - Image Preview
5 |
6 |
7 |
8 | GopherFace - Image Preview
9 |
10 |
11 |
12 |
13 |

14 |
15 |
16 |
17 |
18 |

19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section4/gopherfaceform/templates/index.html
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/postform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - New Post
4 |
5 |
6 |
7 |
8 | GopherFace - New Post
9 |
10 |
11 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/signupconfirmation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - Sign Up Confirmation
4 |
5 |
6 |
7 | GopherFace - Sign Up Confirmation
8 |
9 |
10 | Thank you {{.Fields.firstName}}!
11 | We have received your form submission!
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/socialmediapost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Social Media Post Example
8 |
9 |
10 |
11 |
12 | {{.Caption}}
13 |
14 |
15 |
16 |
17 | {{.CreatedBy}} {{.AuthorMoodEmoji}}
18 | {{.TimeCreated}}
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 | {{.MessageBody}}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/uploadimageform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Image
4 |
5 |
6 |
7 |
8 | Gopherface - Upload Image
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/uploadvideoform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Video
4 |
5 |
6 |
7 |
8 | GopherFace - Upload Video
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/templates/videopreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | GopherFace - Video Preview
8 |
9 |
10 |
11 |
12 |

13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/validationkit/checkusername_test.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // Test for minimum number of characters
8 | func TestCheckUsernameSyntaxMinimumCharacterLength(t *testing.T) {
9 |
10 | result := CheckUsernameSyntax("")
11 |
12 | if result != false {
13 | t.Errorf("Failed the minimum character check.")
14 |
15 | }
16 |
17 | }
18 |
19 | // Test for maximum number of characters
20 | func TestCheckUsernameSyntaxMaximumCharacterLength(t *testing.T) {
21 |
22 | result := CheckUsernameSyntax("aaaaaaaaaaaaaaaa")
23 |
24 | if result != false {
25 | t.Errorf("Failed the maximum character check.")
26 |
27 | }
28 |
29 | }
30 |
31 | func TestCheckUsernameSyntaxSymbols(t *testing.T) {
32 |
33 | result := CheckUsernameSyntax("g-@p!h#r")
34 | if result != false {
35 | t.Errorf("Failed the special character check.")
36 |
37 | }
38 |
39 | }
40 |
41 | func TestCheckUsernameSyntaxUnderscore(t *testing.T) {
42 |
43 | // Underscores are permissible
44 | result := CheckUsernameSyntax("the_gopher")
45 | if result != true {
46 | t.Errorf("Failed the check to allow underscore characters.")
47 |
48 | }
49 |
50 | }
51 |
52 | func TestCheckUsernameSyntaxAtSignInsideUsername(t *testing.T) {
53 |
54 | // The @ sign can only be placed at the start of the username string and is invalid anyhwere else
55 | result := CheckUsernameSyntax("the@gopher")
56 | if result != false {
57 | t.Errorf("Failed the @ sign check. The @ sign was found in another place besides the start of the string.")
58 | }
59 | }
60 |
61 | func TestCheckUsernameSyntaxRandomUsernames(t *testing.T) {
62 |
63 | for i := 0; i < 10008; i++ {
64 |
65 | username := GenerateRandomUsername()
66 | //fmt.Println("username: ", username)
67 | result := CheckUsernameSyntax(username)
68 | if result != true {
69 | t.Errorf("The random username, ", username, ", failed to pass the username check.")
70 | t.Fatal("Quitting!")
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/section4/gopherfaceform/validationkit/validationkit.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "log"
5 | "math/rand"
6 | "regexp"
7 | "time"
8 | )
9 |
10 | const UsernameRegex string = `^@?(\w){1,15}$`
11 | const EmailRegex = `(?i)^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})+$`
12 |
13 | func CheckUsernameSyntax(username string) bool {
14 |
15 | validationResult := false
16 | r, err := regexp.Compile(UsernameRegex)
17 | if err != nil {
18 | log.Fatal(err)
19 | }
20 | validationResult = r.MatchString(username)
21 | return validationResult
22 | }
23 |
24 | func CheckEmailSyntax(email string) bool {
25 | validationResult := false
26 | r, err := regexp.Compile(EmailRegex)
27 | if err != nil {
28 | log.Fatal(err)
29 | }
30 | validationResult = r.MatchString(email)
31 | return validationResult
32 | }
33 |
34 | func GenerateRandomUsername() string {
35 |
36 | rand.Seed(time.Now().UnixNano())
37 |
38 | usernameLength := rand.Intn(15) + 1
39 |
40 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
41 | b := make([]rune, usernameLength)
42 | for i := range b {
43 | b[i] = letterRunes[rand.Intn(len(letterRunes))]
44 | }
45 | randomUsername := string(b)
46 |
47 | zeroOrOne := rand.Intn(2)
48 | if zeroOrOne == 1 {
49 | randomUsername = "@" + randomUsername
50 | }
51 | return randomUsername
52 | }
53 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/common/datastore"
4 |
5 | type Env struct {
6 | DB datastore.Datastore
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/datastore/datastore.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/models"
7 | )
8 |
9 | type Datastore interface {
10 | CreateUser(user *models.User) error
11 | GetUser(username string) (*models.User, error)
12 | Close()
13 | }
14 |
15 | const (
16 | MYSQL = iota
17 | MONGODB
18 | REDIS
19 | )
20 |
21 | func NewDatastore(datastoreType int, dbConnectionString string) (Datastore, error) {
22 |
23 | switch datastoreType {
24 | case MYSQL:
25 | return NewMySQLDatastore(dbConnectionString)
26 | case MONGODB:
27 | return NewMongoDBDatastore(dbConnectionString)
28 | case REDIS:
29 | return NewRedisDatastore(dbConnectionString)
30 | default:
31 | return nil, errors.New("The datastore you specified does not exist!")
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/datastore/mongodb.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/models"
5 |
6 | mgo "gopkg.in/mgo.v2"
7 | "gopkg.in/mgo.v2/bson"
8 | )
9 |
10 | type MongoDBDatastore struct {
11 | *mgo.Session
12 | }
13 |
14 | func NewMongoDBDatastore(url string) (*MongoDBDatastore, error) {
15 | session, err := mgo.Dial(url)
16 | if err != nil {
17 | return nil, err
18 | }
19 | return &MongoDBDatastore{
20 | Session: session,
21 | }, nil
22 | }
23 |
24 | func (m *MongoDBDatastore) CreateUser(user *models.User) error {
25 |
26 | session := m.Copy()
27 |
28 | defer session.Close()
29 | userCollection := session.DB("gopherface").C("User")
30 | err := userCollection.Insert(user)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | return nil
36 | }
37 |
38 | func (m *MongoDBDatastore) GetUser(username string) (*models.User, error) {
39 |
40 | session := m.Copy()
41 | defer session.Close()
42 | userCollection := session.DB("gopherface").C("User")
43 | u := models.User{}
44 | err := userCollection.Find(bson.M{"username": username}).One(&u)
45 | if err != nil {
46 | return nil, err
47 | }
48 | return &u, nil
49 |
50 | }
51 |
52 | func (m *MongoDBDatastore) Close() {
53 | m.Close()
54 | }
55 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/datastore/mysql.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "database/sql"
5 | "log"
6 |
7 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/models"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | )
11 |
12 | type MySQLDatastore struct {
13 | *sql.DB
14 | }
15 |
16 | func NewMySQLDatastore(dataSourceName string) (*MySQLDatastore, error) {
17 |
18 | connection, err := sql.Open("mysql", dataSourceName)
19 |
20 | if err != nil {
21 | log.Fatal(err)
22 | return nil, err
23 | }
24 |
25 | return &MySQLDatastore{
26 | DB: connection}, nil
27 | }
28 |
29 | func (m *MySQLDatastore) CreateUser(user *models.User) error {
30 |
31 | tx, err := m.Begin()
32 | if err != nil {
33 | log.Print(err)
34 | }
35 |
36 | defer tx.Rollback()
37 |
38 | stmt, err := tx.Prepare("INSERT INTO user(uuid, username, first_name, last_name, email, password_hash) VALUES (?,?,?,?,?,?)")
39 | if err != nil {
40 | return err
41 | }
42 |
43 | defer stmt.Close()
44 |
45 | _, err = stmt.Exec(user.UUID, user.Username, user.FirstName, user.LastName, user.Email, user.PasswordHash)
46 | if err != nil {
47 | return err
48 | }
49 |
50 | err = tx.Commit()
51 | if err != nil {
52 | return err
53 | }
54 |
55 | return nil
56 | }
57 |
58 | func (m *MySQLDatastore) GetUser(username string) (*models.User, error) {
59 |
60 | stmt, err := m.Prepare("SELECT uuid, username, first_name, last_name, email, password_hash, UNIX_TIMESTAMP(created_ts), UNIX_TIMESTAMP(updated_ts) FROM user WHERE username = ?")
61 | if err != nil {
62 | log.Print(err)
63 | return nil, err
64 | }
65 |
66 | defer stmt.Close()
67 |
68 | row := stmt.QueryRow(username)
69 | u := models.User{}
70 | err = row.Scan(&u.UUID, &u.Username, &u.FirstName, &u.LastName, &u.Email, &u.PasswordHash, &u.TimestampCreated, &u.TimestampModified)
71 | if err != nil {
72 | log.Print(err)
73 | return nil, err
74 | }
75 |
76 | return &u, err
77 | }
78 |
79 | func (m *MySQLDatastore) Close() {
80 | m.Close()
81 | }
82 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/datastore/redis.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "log"
7 |
8 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/models"
9 |
10 | "github.com/mediocregopher/radix.v2/pool"
11 | )
12 |
13 | type RedisDatastore struct {
14 | *pool.Pool
15 | }
16 |
17 | func NewRedisDatastore(address string) (*RedisDatastore, error) {
18 |
19 | connectionPool, err := pool.New("tcp", address, 10)
20 | if err != nil {
21 | return nil, err
22 | }
23 | return &RedisDatastore{
24 | Pool: connectionPool,
25 | }, nil
26 | }
27 |
28 | func (r *RedisDatastore) CreateUser(user *models.User) error {
29 |
30 | userJSON, err := json.Marshal(*user)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | if r.Cmd("SET", "user:"+user.Username, string(userJSON)).Err != nil {
36 | return errors.New("Failed to execute Redis SET command")
37 | }
38 |
39 | return nil
40 | }
41 |
42 | func (r *RedisDatastore) GetUser(username string) (*models.User, error) {
43 |
44 | exists, err := r.Cmd("EXISTS", "user:"+username).Int()
45 |
46 | if err != nil {
47 | return nil, err
48 | } else if exists == 0 {
49 | return nil, nil
50 | }
51 |
52 | var u models.User
53 |
54 | userJSON, err := r.Cmd("GET", "user:"+username).Str()
55 |
56 | if err != nil {
57 | log.Print(err)
58 |
59 | return nil, err
60 | }
61 |
62 | if err := json.Unmarshal([]byte(userJSON), &u); err != nil {
63 | log.Print(err)
64 | return nil, err
65 | }
66 |
67 | return &u, nil
68 | }
69 |
70 | func (r *RedisDatastore) Close() {
71 |
72 | r.Empty()
73 | }
74 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/utility/sha256.go:
--------------------------------------------------------------------------------
1 | package utility
2 |
3 | import (
4 | "crypto/sha256"
5 | "fmt"
6 | )
7 |
8 | func SHA256OfString(input string) string {
9 |
10 | sum := sha256.Sum256([]byte(input))
11 | return fmt.Sprintf("%x", sum)
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/common/utility/uuid.go:
--------------------------------------------------------------------------------
1 | package utility
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "os"
7 | )
8 |
9 | func GenerateUUID() string {
10 | f, err := os.Open("/dev/urandom")
11 | if err != nil {
12 | log.Println("Encountered the following error when attempting to generate an UUID: ", err)
13 | return ""
14 | }
15 | b := make([]byte, 16)
16 | f.Read(b)
17 | f.Close()
18 | uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
19 | return uuid
20 | }
21 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/config/gopherfacedb.sql:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | // Setup preferences
3 | // ****************************************************************************/
4 | SET NAMES utf8 COLLATE 'utf8_unicode_ci';
5 | SET time_zone = '-07:00';
6 | SET CHARACTER SET utf8;
7 |
8 | /* *****************************************************************************
9 | // Remove database (if it already exists)
10 | // ****************************************************************************/
11 | DROP DATABASE IF EXISTS gopherfacedb;
12 |
13 | /* *****************************************************************************
14 | // Create new database
15 | // ****************************************************************************/
16 | CREATE DATABASE gopherfacedb DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci;
17 | USE gopherfacedb;
18 |
19 | /* *****************************************************************************
20 | // Create the table(s)
21 | // ****************************************************************************/
22 | CREATE TABLE user (
23 | id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT,
24 | username VARCHAR(18) NOT NULL,
25 | uuid VARCHAR(64) NOT NULL,
26 | first_name VARCHAR(64) NOT NULL,
27 | last_name VARCHAR(64) NOT NULL,
28 | password_hash CHAR(64) NOT NULL,
29 | email VARCHAR(255) NOT NULL,
30 | created_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
31 | updated_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
32 | UNIQUE (username),
33 | PRIMARY KEY (id)
34 | );
35 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/endpoints/createpost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func CreatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the create post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/endpoints/deletepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func DeletePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the delete post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/endpoints/fetchposts.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/models/socialmedia"
10 | )
11 |
12 | func FetchPostsEndpoint(w http.ResponseWriter, r *http.Request) {
13 |
14 | // TODO: Implement fetching posts for a given user
15 |
16 | // We are going to create some mock data and send it out in JSON
17 | // format.
18 |
19 | // We will actually implement this endpoint, when we cover database
20 | // persistence later in the course.
21 |
22 | v := mux.Vars(r)
23 |
24 | if v["username"] == "EngineerKamesh" {
25 |
26 | mockPosts := make([]socialmedia.Post, 3)
27 |
28 | post1 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
29 | post2 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["happy"], "Tour of Go", "Check out the Tour of Go!", "https://tour.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
30 | post3 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["hopeful"], "Go Playground", "Check out the Go Playground!", "https://playground.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
31 |
32 | mockPosts = append(mockPosts, *post1)
33 | mockPosts = append(mockPosts, *post2)
34 | mockPosts = append(mockPosts, *post3)
35 | json.NewEncoder(w).Encode(mockPosts)
36 |
37 | } else {
38 | json.NewEncoder(w).Encode(nil)
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/endpoints/updatepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func UpdatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the update post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/gopherface.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/common"
7 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/common/datastore"
8 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/handlers"
9 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/middleware"
10 |
11 | "net/http"
12 | "os"
13 |
14 | ghandlers "github.com/gorilla/handlers"
15 | "github.com/gorilla/mux"
16 | )
17 |
18 | const (
19 | WEBSERVERPORT = ":8080"
20 | )
21 |
22 | func main() {
23 |
24 | db, err := datastore.NewDatastore(datastore.MYSQL, "gopherface:gopherface@/gopherfacedb")
25 | //db, err := datastore.NewDatastore(datastore.MONGODB, "localhost:27017")
26 | //db, err := datastore.NewDatastore(datastore.REDIS, "localhost:6379")
27 |
28 | if err != nil {
29 | log.Print(err)
30 | }
31 |
32 | defer db.Close()
33 |
34 | env := common.Env{DB: db}
35 |
36 | r := mux.NewRouter()
37 | r.HandleFunc("/", handlers.HomeHandler)
38 | r.HandleFunc("/register", handlers.RegisterHandler).Methods("GET,POST")
39 | r.HandleFunc("/login", handlers.LoginHandler).Methods("POST")
40 | r.HandleFunc("/logout", handlers.LogoutHandler).Methods("POST")
41 | r.HandleFunc("/feed", handlers.FeedHandler).Methods("GET")
42 | r.HandleFunc("/friends", handlers.FriendsHandler).Methods("GET")
43 | r.HandleFunc("/find", handlers.FindHandler).Methods("GET,POST")
44 | r.HandleFunc("/profile", handlers.MyProfileHandler).Methods("GET")
45 | r.HandleFunc("/profile/{username}", handlers.ProfileHandler)
46 | r.HandleFunc("/triggerpanic", handlers.TriggerPanicHandler)
47 | r.HandleFunc("/foo", handlers.FooHandler)
48 | r.Handle("/signup", handlers.SignUpHandler(&env)).Methods("GET", "POST")
49 | r.HandleFunc("/postpreview", handlers.PostPreviewHandler).Methods("GET", "POST")
50 | r.HandleFunc("/upload-image", handlers.UploadImageHandler).Methods("GET", "POST")
51 | r.HandleFunc("/upload-video", handlers.UploadVideoHandler).Methods("GET", "POST")
52 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
53 | http.Handle("/", middleware.PanicRecoveryHandler(ghandlers.LoggingHandler(os.Stdout, r)))
54 | http.ListenAndServe(WEBSERVERPORT, nil)
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/feed.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FeedHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/find.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FindHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/foo.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func FooHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | fooID := r.Context().Value("fooID").(string)
10 | w.Write([]byte(fooID))
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/friends.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FriendsHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/home.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func HomeHandler(w http.ResponseWriter, r *http.Request) {
9 |
10 | fmt.Println("home page handler reached")
11 | }
12 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/login.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LoginHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/logout.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func LogoutHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/myprofile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func MyProfileHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | w.Write([]byte("profile"))
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/panic.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func TriggerPanicHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | panic("Triggering a Panic!")
10 | }
11 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/profile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/mux"
7 | )
8 |
9 | func ProfileHandler(w http.ResponseWriter, r *http.Request) {
10 |
11 | vars := mux.Vars(r)
12 | username := vars["username"]
13 | w.Write([]byte(username))
14 | }
15 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/register.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func RegisterHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/handlers/utility.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 | ttemplate "text/template"
8 | )
9 |
10 | // Template rendering function
11 | func RenderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
12 | t, err := template.ParseFiles(templateFile)
13 | if err != nil {
14 | log.Printf("Error encountered while parsing the template: ", err)
15 | }
16 | t.Execute(w, templateData)
17 | }
18 |
19 | func RenderUnsafeTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
20 | t, err := ttemplate.ParseFiles(templateFile)
21 | if err != nil {
22 | log.Printf("Error encountered while parsing the template: ", err)
23 | }
24 | w.Header().Set("X-XSS-Protection", "0")
25 | t.Execute(w, templateData)
26 | }
27 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/middleware/contextexample.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | )
7 |
8 | func newExampleContext(ctx context.Context, r *http.Request) context.Context {
9 |
10 | fooID := r.Header.Get("X-Foo-ID")
11 | if fooID == "" {
12 | fooID = "bar"
13 | }
14 |
15 | return context.WithValue(ctx, "fooID", fooID)
16 |
17 | }
18 |
19 | func ContextExampleHandler(next http.Handler) http.Handler {
20 |
21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 |
23 | defer func() {
24 |
25 | ctx := newExampleContext(r.Context(), r)
26 | next.ServeHTTP(w, r.WithContext(ctx))
27 |
28 | }()
29 |
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/middleware/panicrecovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func PanicRecoveryHandler(next http.Handler) http.Handler {
9 |
10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 |
12 | defer func() {
13 |
14 | if err := recover(); err != nil {
15 | log.Printf("Encountered panic: %+v", err)
16 | http.Error(w, http.StatusText(500), 500)
17 | }
18 |
19 | }()
20 |
21 | next.ServeHTTP(w, r)
22 |
23 | })
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/models/socialmedia/moodstate_string.go:
--------------------------------------------------------------------------------
1 | // Code generated by "stringer -type=MoodState"; DO NOT EDIT
2 |
3 | package socialmedia
4 |
5 | import "fmt"
6 |
7 | const _MoodState_name = "MoodStateNeutralMoodStateHappyMoodStateSadMoodStateAngryMoodStateHopefulMoodStateThrilledMoodStateBoredMoodStateShyMoodStateComicalMoodStateOnCloudNine"
8 |
9 | var _MoodState_index = [...]uint8{0, 16, 30, 42, 56, 72, 89, 103, 115, 131, 151}
10 |
11 | func (i MoodState) String() string {
12 | if i < 0 || i >= MoodState(len(_MoodState_index)-1) {
13 | return fmt.Sprintf("MoodState(%d)", i)
14 | }
15 | return _MoodState_name[_MoodState_index[i]:_MoodState_index[i+1]]
16 | }
17 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section5/gopherfacedb/common/utility"
7 | )
8 |
9 | type User struct {
10 | UUID string `json:"uuid" bson:"uuid"`
11 | Username string `json:"username" bson:"username"`
12 | FirstName string `json:"firstName" bson:"firstName"`
13 | LastName string `json:"lastName" bson:"lastName"`
14 | Email string `json:"email" bson:"email"`
15 | PasswordHash string `json:"passwordHash" bson:"passwordHash"`
16 | TimestampCreated int64 `json:"timestampCreated" bson:"timestampCreated"`
17 | TimestampModified int64 `json:"timestampModified" bson:"timestampModified"`
18 | }
19 |
20 | func NewUser(username string, firstName string, lastName string, email string, password string) *User {
21 |
22 | passwordHash := utility.SHA256OfString(password)
23 | now := time.Now()
24 | unixTimestamp := now.Unix()
25 | u := User{UUID: utility.GenerateUUID(), Username: username, FirstName: firstName, LastName: lastName, Email: email, PasswordHash: passwordHash, TimestampCreated: unixTimestamp}
26 | return &u
27 | }
28 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/css/gopherface.css:
--------------------------------------------------------------------------------
1 | body {
2 |
3 | font-family: arial, helvetica;
4 | font-size: 12pt;
5 | margin-left: 18px;
6 |
7 | }
8 |
9 | .smpostContainer {
10 |
11 | border: 1px solid #CCC;
12 | width: 540px;
13 | min-height: 108px;
14 | padding: 18px;
15 | box-shadow: 1px 1px 3px #888;
16 | }
17 |
18 | .smpostFormContainer {
19 | width: 720px;
20 | }
21 |
22 | .uploadFormContainer {
23 | width: 720px;
24 | }
25 |
26 | #messageBody {
27 | min-height: 207px;
28 | }
29 |
30 | .author {
31 |
32 |
33 | }
34 |
35 | .caption {
36 |
37 | font-weight: bold;
38 | font-size: 18pt;
39 | }
40 |
41 | .caption a {
42 | text-decoration: none;
43 | }
44 |
45 | .creationtime {
46 |
47 | }
48 |
49 | .createdby {
50 | color: blue;
51 | }
52 |
53 | .imagePreview {
54 | text-align: center;
55 | margin-top: 18px;
56 | }
57 |
58 | .msgBody {
59 | margin-top: 27px;
60 |
61 | }
62 |
63 | /* pure overrides */
64 | .pure-form-message-inline {
65 | color: red !important;
66 | }
67 |
68 | .pure-control-group label, label{
69 | color: gray;
70 | font-weight: bold;
71 | font-size: 0.93em;
72 | }
73 |
74 | .imageContainer {
75 |
76 | display: inline;
77 | margin-right: 27px;
78 | }
79 |
80 | .videoContainer {
81 | display: inline;
82 | }
83 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/uploads/images/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded image files.
2 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/uploads/videos/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded video files.
2 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/static/videoset/3DGopher.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/static/videoset/3DGopher.mp4
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/imagepreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Gopherface - Image Preview
5 |
6 |
7 |
8 | GopherFace - Image Preview
9 |
10 |
11 |
12 |
13 |

14 |
15 |
16 |
17 |
18 |

19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section5/gopherfacedb/templates/index.html
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/postform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - New Post
4 |
5 |
6 |
7 |
8 | GopherFace - New Post
9 |
10 |
11 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/signupconfirmation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | GopherFace - Sign Up Confirmation
4 |
5 |
6 |
7 | GopherFace - Sign Up Confirmation
8 |
9 |
10 | Thank you {{.Fields.firstName}}!
11 | We have received your form submission!
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/socialmediapost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Social Media Post Example
8 |
9 |
10 |
11 |
12 | {{.Caption}}
13 |
14 |
15 |
16 |
17 | {{.CreatedBy}} {{.AuthorMoodEmoji}}
18 | {{.TimeCreated}}
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 | {{.MessageBody}}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/uploadimageform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Image
4 |
5 |
6 |
7 |
8 | Gopherface - Upload Image
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/uploadvideoform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Upload Video
4 |
5 |
6 |
7 |
8 | GopherFace - Upload Video
9 |
10 |
11 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/templates/videopreview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | GopherFace - Video Preview
8 |
9 |
10 |
11 |
12 |

13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/validationkit/checkusername_test.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // Test for minimum number of characters
8 | func TestCheckUsernameSyntaxMinimumCharacterLength(t *testing.T) {
9 |
10 | result := CheckUsernameSyntax("")
11 |
12 | if result != false {
13 | t.Errorf("Failed the minimum character check.")
14 |
15 | }
16 |
17 | }
18 |
19 | // Test for maximum number of characters
20 | func TestCheckUsernameSyntaxMaximumCharacterLength(t *testing.T) {
21 |
22 | result := CheckUsernameSyntax("aaaaaaaaaaaaaaaa")
23 |
24 | if result != false {
25 | t.Errorf("Failed the maximum character check.")
26 |
27 | }
28 |
29 | }
30 |
31 | func TestCheckUsernameSyntaxSymbols(t *testing.T) {
32 |
33 | result := CheckUsernameSyntax("g-@p!h#r")
34 | if result != false {
35 | t.Errorf("Failed the special character check.")
36 |
37 | }
38 |
39 | }
40 |
41 | func TestCheckUsernameSyntaxUnderscore(t *testing.T) {
42 |
43 | // Underscores are permissible
44 | result := CheckUsernameSyntax("the_gopher")
45 | if result != true {
46 | t.Errorf("Failed the check to allow underscore characters.")
47 |
48 | }
49 |
50 | }
51 |
52 | func TestCheckUsernameSyntaxAtSignInsideUsername(t *testing.T) {
53 |
54 | // The @ sign can only be placed at the start of the username string and is invalid anyhwere else
55 | result := CheckUsernameSyntax("the@gopher")
56 | if result != false {
57 | t.Errorf("Failed the @ sign check. The @ sign was found in another place besides the start of the string.")
58 | }
59 | }
60 |
61 | func TestCheckUsernameSyntaxRandomUsernames(t *testing.T) {
62 |
63 | for i := 0; i < 10008; i++ {
64 |
65 | username := GenerateRandomUsername()
66 | //fmt.Println("username: ", username)
67 | result := CheckUsernameSyntax(username)
68 | if result != true {
69 | t.Errorf("The random username, ", username, ", failed to pass the username check.")
70 | t.Fatal("Quitting!")
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/section5/gopherfacedb/validationkit/validationkit.go:
--------------------------------------------------------------------------------
1 | package validationkit
2 |
3 | import (
4 | "log"
5 | "math/rand"
6 | "regexp"
7 | "time"
8 | )
9 |
10 | const UsernameRegex string = `^@?(\w){1,15}$`
11 | const EmailRegex = `(?i)^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})+$`
12 |
13 | func CheckUsernameSyntax(username string) bool {
14 |
15 | validationResult := false
16 | r, err := regexp.Compile(UsernameRegex)
17 | if err != nil {
18 | log.Fatal(err)
19 | }
20 | validationResult = r.MatchString(username)
21 | return validationResult
22 | }
23 |
24 | func CheckEmailSyntax(email string) bool {
25 | validationResult := false
26 | r, err := regexp.Compile(EmailRegex)
27 | if err != nil {
28 | log.Fatal(err)
29 | }
30 | validationResult = r.MatchString(email)
31 | return validationResult
32 | }
33 |
34 | func GenerateRandomUsername() string {
35 |
36 | rand.Seed(time.Now().UnixNano())
37 |
38 | usernameLength := rand.Intn(15) + 1
39 |
40 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
41 | b := make([]rune, usernameLength)
42 | for i := range b {
43 | b[i] = letterRunes[rand.Intn(len(letterRunes))]
44 | }
45 | randomUsername := string(b)
46 |
47 | zeroOrOne := rand.Intn(2)
48 | if zeroOrOne == 1 {
49 | randomUsername = "@" + randomUsername
50 | }
51 | return randomUsername
52 | }
53 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/certs/gopherfacecert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIC2DCCAcCgAwIBAgIJAJeZ756CwpghMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
3 | BAMTEGdvcGhlcmZhY2UubG9jYWwwHhcNMTcwNjE1MDAzMjU1WhcNNDcwMTA5MDAz
4 | MjU1WjAbMRkwFwYDVQQDExBnb3BoZXJmYWNlLmxvY2FsMIIBIjANBgkqhkiG9w0B
5 | AQEFAAOCAQ8AMIIBCgKCAQEAur++pQkyO/JmCMM+0fXiNIWFKExLqcPqBEdox1Mi
6 | XUxT0oN42PDOkDKF+HOF3LsSTiSQzsX1QgwFTTEWdLlWCBHTTFGA2aCEBV4vnbzn
7 | ohk1mW3BapQLRPej/CjGYadi2eWp52kO9L3oKxlYIQEd4HGeZ15nKGuLotB6KOPZ
8 | +f2ingsbUcfXOFPDjWJ2BCJ6qfx+Kt0jkKNILV6Spu/Lf/yA8wStu06hHKm0W2Xm
9 | MW0RnMzsgr7D34JdqPVfhpMKan8RtPJFRtQJQin+qBolLADl8qx+eqABD0QJpD28
10 | ghM+LB3gOdv65+ZLElI/5z/Y6AmjY4ZZvYBzN2eZ8yUIBwIDAQABox8wHTAbBgNV
11 | HREEFDASghBnb3BoZXJmYWNlLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQA726bN
12 | htcYqvY9fcpg+WeX1HFk24+a4h3ta3dGxK7YgF5csx+P+EGn3enlVM4GkGg5f/qc
13 | Vqisie/mFdnpw/Bb+i9tbCUHcUfnyo7tfnz3KrtqfXFArgmzFb2rDXtHkMe3d8es
14 | wQ9krRqZwFUMs+gWnFbKaeUCqYAoSb92pyNmcqmCZvvbcBCs3PjyQJuA1/V6E9Ed
15 | iho/wXEGs3vytckO06zW8Nbixq5uE7uXhF+It9xXHmZCdNbet5Tv6PZxBuXfFTBx
16 | reRFs+85LGyHExfKmHeaojohOd7w4v5pfax4KzNJSWEXFwlqEBZVivybRKCQ3ctT
17 | R4huoi3kp8YrhVwr
18 | -----END CERTIFICATE-----
19 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/certs/gopherfacekey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6v76lCTI78mYI
3 | wz7R9eI0hYUoTEupw+oER2jHUyJdTFPSg3jY8M6QMoX4c4XcuxJOJJDOxfVCDAVN
4 | MRZ0uVYIEdNMUYDZoIQFXi+dvOeiGTWZbcFqlAtE96P8KMZhp2LZ5annaQ70vegr
5 | GVghAR3gcZ5nXmcoa4ui0Hoo49n5/aKeCxtRx9c4U8ONYnYEInqp/H4q3SOQo0gt
6 | XpKm78t//IDzBK27TqEcqbRbZeYxbRGczOyCvsPfgl2o9V+GkwpqfxG08kVG1AlC
7 | Kf6oGiUsAOXyrH56oAEPRAmkPbyCEz4sHeA52/rn5ksSUj/nP9joCaNjhlm9gHM3
8 | Z5nzJQgHAgMBAAECggEAYqCp2xeEREy8vpv/LXwiv4JU1PeWbk5d5WyhVcP+Pi/1
9 | hRSSWmCzd0x3nMPGStEx1btSDyJVaVBX7HCkX3kSiqh/Y6sX1dgEYaFgnHoMC3ws
10 | 5p8kq1kMqpvvK1mNjD2O42170g+WKoOxfjGgba3dTZA0DHu7F4nU8WQRYE8V7AS1
11 | SesclqNpwudqtypgEdDHbWcr5tssWVXFSXv4PM7Ado6IApb2sdJO8pf2iSASgtP4
12 | 0RPlGbNiJpwEfm4BCdRb5/wfd3tDteHcYUxELJHSKGn53BlMigScP9nA518UfFF7
13 | KC1u+4jn8PYglIfdGxaGQJ1r+MAmGcWwi7x6++RLYQKBgQDdCBHkGv1nAuNKGQhl
14 | dgtXIT8su1y6MaBNBvx6jqBr6eBBni9Vjld7Z0fTZS+ZhVCWHU0tdQLeNwCEFIkL
15 | SZDWQw+HsntivlnXXRb06E14CqHvaumdCsBaj+XRDLr+97bWolMlg5/i21nWLJ4G
16 | DlsMt1pqZN6jJaLluXjjFsw1kwKBgQDYSzV92a+4UfNgaAlNjuIGOo5yFSA8fJxU
17 | taeTqo6HOIKugQL0hvS3M5InP3mjTj+4jdAc6li6mN7IjNxIdvScf4o6mymdUzZm
18 | D0IJtqSZDhwsLq/LIoeWm17Oo6QGUwWxwUoKUXf6ZBNiCCrZpOpZhk5i3wcaqluR
19 | ch7UQ/0sPQKBgQCWiXd97u/lJ69beP8h8yq4FdmsApOd8EyoCXkNk3Qo6ymkJzM/
20 | xulID8h4bnLj0UtYYe59ZjMk2zsLudy4hksR0qySE/o6/z+7ERighlK0zjEKGbuw
21 | DHGDfHveTBhTrKynM/kDFMlhPVnLJ6ocn8xdNcdrrPWBEhIG+bIeoBlG5wKBgEmu
22 | 5VwoKnqKQHTZPEIVqN4iWKB4nfC9KqyY7auacM+T6sDz5kPTLc6zXNjOAOwnHgIL
23 | HZicJPn8VfjQM8Lj81TVBgwNC9IypNeD3yVb+RrC+cn7ZZu3+aTO7S9MA/a7lbcG
24 | d+in9E1yhj/hNGfMjKFO5ak8/TiSTHtx+xqoxripAoGBAIHMgLlbSnjlPqd5FXIN
25 | snvogXNFX8CHPWkEbaSjIHA8SQXP3k40SxoJblM1UzwFdO4v45zYYVgjpRGjiVuF
26 | kYS1+xMRVXq5muJfjSG1fj3e0l/y2q2+fqoi6x6toz38WQGVsok1CnWvCzdpZTlF
27 | 7Pt1xP4y9bWGNFpGejwaTBd5
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/asyncq/asyncq.go:
--------------------------------------------------------------------------------
1 | package asyncq
2 |
3 | import (
4 | "log"
5 | )
6 |
7 | var TaskQueue chan Task
8 | var TaskWorkerQueue chan chan Task
9 |
10 | type TaskWorker struct {
11 | ID int
12 | TaskChannel chan Task
13 | TaskWorkerQueue chan chan Task
14 | }
15 |
16 | func NewTaskWorker(id int, taskWorkerQueue chan chan Task) TaskWorker {
17 | taskWorker := TaskWorker{
18 | ID: id,
19 | TaskChannel: make(chan Task),
20 | TaskWorkerQueue: taskWorkerQueue,
21 | }
22 |
23 | return taskWorker
24 | }
25 |
26 | func (t *TaskWorker) Start() {
27 | go func() {
28 | for {
29 | t.TaskWorkerQueue <- t.TaskChannel
30 |
31 | select {
32 | case task := <-t.TaskChannel:
33 | log.Printf("Asynchronous task worker #%d is performing a task.\n", t.ID)
34 | task.Perform()
35 |
36 | }
37 | }
38 | }()
39 | }
40 |
41 | func StartTaskDispatcher(taskWorkerSize int) {
42 |
43 | TaskWorkerQueue = make(chan chan Task, taskWorkerSize)
44 |
45 | for i := 0; i < taskWorkerSize; i++ {
46 | log.Print("Starting asynchronous task worker #", i+1)
47 | taskWorker := NewTaskWorker(i+1, TaskWorkerQueue)
48 | taskWorker.Start()
49 | }
50 |
51 | go func() {
52 | for {
53 | select {
54 | case task := <-TaskQueue:
55 | go func() {
56 | taskChannel := <-TaskWorkerQueue
57 | taskChannel <- task
58 | }()
59 | }
60 | }
61 | }()
62 | }
63 |
64 | func init() {
65 |
66 | TaskQueue = make(chan Task, 108)
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/asyncq/task.go:
--------------------------------------------------------------------------------
1 | package asyncq
2 |
3 | type Task interface {
4 | Perform()
5 | }
6 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/authenticate/authenticate.go:
--------------------------------------------------------------------------------
1 | package authenticate
2 |
3 | import (
4 | "log"
5 | "strings"
6 |
7 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common"
8 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common/utility"
9 | )
10 |
11 | func VerifyCredentials(e *common.Env, username string, password string) bool {
12 |
13 | u, err := e.DB.GetUser(username)
14 | if u == nil {
15 | return false
16 | }
17 |
18 | if err != nil {
19 | log.Print(err)
20 | }
21 |
22 | if strings.ToLower(username) == strings.ToLower(u.Username) && utility.SHA256OfString(password) == u.PasswordHash {
23 | log.Println("Successful login attempt from user: ", u.Username)
24 | return true
25 | } else {
26 | log.Println("Unsuccessful login attempt from user: ", u.Username)
27 | return false
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/authenticate/cookie.go:
--------------------------------------------------------------------------------
1 | package authenticate
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "os"
7 | "time"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
10 |
11 | "github.com/gorilla/securecookie"
12 | )
13 |
14 | var hashKey []byte
15 | var blockKey []byte
16 | var s *securecookie.SecureCookie
17 |
18 | func CreateSecureCookie(u *models.User, sessionID string, w http.ResponseWriter, r *http.Request) error {
19 |
20 | value := map[string]string{
21 | "username": u.Username,
22 | "sid": sessionID,
23 | }
24 |
25 | if encoded, err := s.Encode("session", value); err == nil {
26 | cookie := &http.Cookie{
27 | Name: "session",
28 | Value: encoded,
29 | Path: "/",
30 | Secure: true,
31 | HttpOnly: true,
32 | }
33 |
34 | http.SetCookie(w, cookie)
35 | } else {
36 | log.Print(err)
37 | return err
38 | }
39 |
40 | return nil
41 |
42 | }
43 |
44 | func ReadSecureCookieValues(w http.ResponseWriter, r *http.Request) (map[string]string, error) {
45 | if cookie, err := r.Cookie("session"); err == nil {
46 | value := make(map[string]string)
47 | if err = s.Decode("session", cookie.Value, &value); err == nil {
48 | return value, nil
49 | } else {
50 | return nil, err
51 | }
52 | } else {
53 | return nil, nil
54 | }
55 | }
56 |
57 | func ExpireSecureCookie(w http.ResponseWriter, r *http.Request) {
58 |
59 | cookie := &http.Cookie{
60 | Name: "session",
61 | Value: "",
62 | Path: "/",
63 | MaxAge: -1,
64 | }
65 | w.Header().Set("Cache-Control", "no-cache, private, max-age=0")
66 | w.Header().Set("Expires", time.Unix(0, 0).Format(http.TimeFormat))
67 | w.Header().Set("Pragma", "no-cache")
68 | w.Header().Set("X-Accel-Expires", "0")
69 |
70 | http.SetCookie(w, cookie)
71 | http.Redirect(w, r, "/login", 301)
72 | }
73 |
74 | func init() {
75 |
76 | hashKey = []byte(os.Getenv("GOPHERFACE_HASH_KEY"))
77 | blockKey = []byte(os.Getenv("GOPHERFACE_BLOCK_KEY"))
78 |
79 | s = securecookie.New(hashKey, blockKey)
80 | }
81 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/authenticate/session.go:
--------------------------------------------------------------------------------
1 | package authenticate
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "os"
7 |
8 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
9 |
10 | "github.com/gorilla/sessions"
11 | )
12 |
13 | var SessionStore *sessions.FilesystemStore
14 |
15 | func CreateUserSession(u *models.User, sessionID string, w http.ResponseWriter, r *http.Request) error {
16 |
17 | gfSession, err := SessionStore.Get(r, "gopherface-session")
18 |
19 | if err != nil {
20 | log.Print(err)
21 | }
22 |
23 | gfSession.Values["sessionID"] = sessionID
24 | gfSession.Values["username"] = u.Username
25 | gfSession.Values["firstName"] = u.FirstName
26 | gfSession.Values["lastName"] = u.LastName
27 | gfSession.Values["email"] = u.Email
28 |
29 | err = gfSession.Save(r, w)
30 | if err != nil {
31 | log.Print(err)
32 | return err
33 | }
34 |
35 | return nil
36 | }
37 |
38 | func ExpireUserSession(w http.ResponseWriter, r *http.Request) {
39 | gfSession, err := SessionStore.Get(r, "gopherface-session")
40 |
41 | if err != nil {
42 | log.Print(err)
43 | }
44 |
45 | gfSession.Options.MaxAge = -1
46 | gfSession.Save(r, w)
47 | }
48 |
49 | func init() {
50 |
51 | SessionStore = sessions.NewFilesystemStore("/tmp/gopherface-sessions", []byte(os.Getenv("GOPHERFACE_HASH_KEY")))
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common/datastore"
4 |
5 | type Env struct {
6 | DB datastore.Datastore
7 | }
8 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/datastore/datastore.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
4 |
5 | type Datastore interface {
6 | CreateUser(user *models.User) error
7 | GetUser(username string) (*models.User, error)
8 | Close()
9 | }
10 |
11 | const (
12 | MYSQL = iota
13 | MONGODB
14 | REDIS
15 | )
16 |
17 | func NewDatastore(datastoreType int, dbConnectionString string) (Datastore, error) {
18 |
19 | switch datastoreType {
20 | case MYSQL:
21 | return NewMySQLDatastore(dbConnectionString)
22 | case MONGODB:
23 | return NewMongoDBDatastore(dbConnectionString)
24 | case REDIS:
25 | return NewRedisDatastore(dbConnectionString)
26 |
27 | }
28 |
29 | return nil, nil
30 | }
31 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/datastore/mongodb.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
7 |
8 | mgo "gopkg.in/mgo.v2"
9 | "gopkg.in/mgo.v2/bson"
10 | )
11 |
12 | type MongoDBDatastore struct {
13 | *mgo.Session
14 | }
15 |
16 | func NewMongoDBDatastore(url string) (*MongoDBDatastore, error) {
17 | session, err := mgo.Dial(url)
18 | if err != nil {
19 | return nil, err
20 | }
21 | return &MongoDBDatastore{
22 | Session: session,
23 | }, nil
24 | }
25 |
26 | func (m *MongoDBDatastore) CreateUser(user *models.User) error {
27 |
28 | session := m.Copy()
29 |
30 | defer session.Close()
31 | userCollection := session.DB("gopherface").C("User")
32 | err := userCollection.Insert(user)
33 | if err != nil {
34 | return err
35 | }
36 |
37 | return nil
38 | }
39 |
40 | func (m *MongoDBDatastore) GetUser(username string) (*models.User, error) {
41 |
42 | session := m.Copy()
43 | defer session.Close()
44 | userCollection := session.DB("gopherface").C("User")
45 | u := models.User{}
46 | err := userCollection.Find(bson.M{"username": username}).One(&u)
47 | if err != nil {
48 | return nil, err
49 | }
50 | fmt.Println("created")
51 | return &u, nil
52 |
53 | }
54 |
55 | func (m *MongoDBDatastore) Close() {
56 | m.Close()
57 | }
58 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/datastore/mysql.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "database/sql"
5 | "log"
6 |
7 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | )
11 |
12 | type MySQLDatastore struct {
13 | *sql.DB
14 | }
15 |
16 | func NewMySQLDatastore(dataSourceName string) (*MySQLDatastore, error) {
17 |
18 | connection, err := sql.Open("mysql", dataSourceName)
19 |
20 | if err != nil {
21 | return nil, err
22 | }
23 |
24 | return &MySQLDatastore{
25 | DB: connection}, nil
26 | }
27 |
28 | func (m *MySQLDatastore) CreateUser(user *models.User) error {
29 |
30 | tx, err := m.Begin()
31 | if err != nil {
32 | log.Print(err)
33 | }
34 |
35 | defer tx.Rollback()
36 |
37 | stmt, err := tx.Prepare("INSERT INTO user(uuid, username, first_name, last_name, email, password_hash) VALUES (?,?,?,?,?,?)")
38 | if err != nil {
39 | return err
40 | }
41 |
42 | defer stmt.Close()
43 |
44 | _, err = stmt.Exec(user.UUID, user.Username, user.FirstName, user.LastName, user.Email, user.PasswordHash)
45 | if err != nil {
46 | return err
47 | }
48 |
49 | err = tx.Commit()
50 | if err != nil {
51 | return err
52 | }
53 |
54 | return nil
55 | }
56 |
57 | func (m *MySQLDatastore) GetUser(username string) (*models.User, error) {
58 |
59 | stmt, err := m.Prepare("SELECT uuid, username, first_name, last_name, email, password_hash, UNIX_TIMESTAMP(created_ts), UNIX_TIMESTAMP(updated_ts) FROM user WHERE username = ?")
60 | if err != nil {
61 | log.Print(err)
62 | return nil, err
63 | }
64 |
65 | defer stmt.Close()
66 |
67 | row := stmt.QueryRow(username)
68 | u := models.User{}
69 | err = row.Scan(&u.UUID, &u.Username, &u.FirstName, &u.LastName, &u.Email, &u.PasswordHash, &u.TimestampCreated, &u.TimestampModified)
70 | return &u, err
71 | }
72 |
73 | func (m *MySQLDatastore) Close() {
74 | m.Close()
75 | }
76 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/datastore/redis.go:
--------------------------------------------------------------------------------
1 | package datastore
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "log"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models"
10 |
11 | "github.com/mediocregopher/radix.v2/pool"
12 | )
13 |
14 | type RedisDatastore struct {
15 | *pool.Pool
16 | }
17 |
18 | func NewRedisDatastore(address string) (*RedisDatastore, error) {
19 |
20 | connectionPool, err := pool.New("tcp", address, 10)
21 | if err != nil {
22 | return nil, err
23 | }
24 | return &RedisDatastore{
25 | Pool: connectionPool,
26 | }, nil
27 | }
28 |
29 | func (r *RedisDatastore) CreateUser(user *models.User) error {
30 |
31 | userJSON, err := json.Marshal(*user)
32 | if err != nil {
33 | return err
34 | }
35 |
36 | if r.Cmd("SET", "user:"+user.Username, string(userJSON)).Err != nil {
37 | return errors.New("Failed to execute Redis SET command")
38 | }
39 |
40 | return nil
41 | }
42 |
43 | func (r *RedisDatastore) GetUser(username string) (*models.User, error) {
44 |
45 | exists, err := r.Cmd("EXISTS", "user:"+username).Int()
46 |
47 | if err != nil {
48 | return nil, err
49 | } else if exists == 0 {
50 | return nil, nil
51 | }
52 |
53 | var u models.User
54 |
55 | userJSON, err := r.Cmd("GET", "user:"+username).Str()
56 |
57 | fmt.Println("userJSON: ", userJSON)
58 |
59 | if err != nil {
60 | log.Print(err)
61 |
62 | return nil, err
63 | }
64 |
65 | if err := json.Unmarshal([]byte(userJSON), &u); err != nil {
66 | log.Print(err)
67 | return nil, err
68 | }
69 |
70 | return &u, nil
71 | }
72 |
73 | func (r *RedisDatastore) Close() {
74 |
75 | r.Close()
76 | }
77 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/utility/sha256.go:
--------------------------------------------------------------------------------
1 | package utility
2 |
3 | import (
4 | "crypto/sha256"
5 | "fmt"
6 | )
7 |
8 | func SHA256OfString(input string) string {
9 |
10 | sum := sha256.Sum256([]byte(input))
11 | return fmt.Sprintf("%x", sum)
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/common/utility/uuid.go:
--------------------------------------------------------------------------------
1 | package utility
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "os"
7 | )
8 |
9 | func GenerateUUID() string {
10 | f, err := os.Open("/dev/urandom")
11 | if err != nil {
12 | log.Println("Encountered the following error when attempting to generate an UUID: ", err)
13 | return ""
14 | }
15 | b := make([]byte, 16)
16 | f.Read(b)
17 | f.Close()
18 | uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
19 | return uuid
20 | }
21 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/config/gopherfacedb.sql:
--------------------------------------------------------------------------------
1 | /* *****************************************************************************
2 | // Setup preferences
3 | // ****************************************************************************/
4 | SET NAMES utf8 COLLATE 'utf8_unicode_ci';
5 | SET time_zone = '-07:00';
6 | SET CHARACTER SET utf8;
7 |
8 | /* *****************************************************************************
9 | // Remove database (if it already exists)
10 | // ****************************************************************************/
11 | DROP DATABASE IF EXISTS gopherfacedb;
12 |
13 | /* *****************************************************************************
14 | // Create new database
15 | // ****************************************************************************/
16 | CREATE DATABASE gopherfacedb DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci;
17 | USE gopherfacedb;
18 |
19 | /* *****************************************************************************
20 | // Create the table(s)
21 | // ****************************************************************************/
22 | CREATE TABLE user (
23 | id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT,
24 | username VARCHAR(18) NOT NULL,
25 | uuid VARCHAR(64) NOT NULL,
26 | first_name VARCHAR(64) NOT NULL,
27 | last_name VARCHAR(64) NOT NULL,
28 | password_hash CHAR(64) NOT NULL,
29 | email VARCHAR(255) NOT NULL,
30 | created_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
31 | updated_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
32 | UNIQUE (username),
33 | PRIMARY KEY (id)
34 | );
35 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/endpoints/createpost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func CreatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the create post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/endpoints/deletepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func DeletePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the delete post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/endpoints/fetchposts.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/models/socialmedia"
10 | )
11 |
12 | func FetchPostsEndpoint(w http.ResponseWriter, r *http.Request) {
13 |
14 | // TODO: Implement fetching posts for a given user
15 |
16 | // We are going to create some mock data and send it out in JSON
17 | // format.
18 |
19 | // We will actually implement this endpoint, when we cover database
20 | // persistence later in the course.
21 |
22 | v := mux.Vars(r)
23 |
24 | if v["username"] == "EngineerKamesh" {
25 |
26 | mockPosts := make([]socialmedia.Post, 3)
27 |
28 | post1 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["thrilled"], "Go is awesome!", "Check out the Go web site!", "https://golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
29 | post2 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["happy"], "Tour of Go", "Check out the Tour of Go!", "https://tour.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
30 | post3 := socialmedia.NewPost("EngineerKamesh", socialmedia.Moods["hopeful"], "Go Playground", "Check out the Go Playground!", "https://playground.golang.org", "/images/gogopher.png", "", []string{"go", "golang", "programming language"})
31 |
32 | mockPosts = append(mockPosts, *post1)
33 | mockPosts = append(mockPosts, *post2)
34 | mockPosts = append(mockPosts, *post3)
35 | json.NewEncoder(w).Encode(mockPosts)
36 |
37 | } else {
38 | json.NewEncoder(w).Encode(nil)
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/endpoints/updatepost.go:
--------------------------------------------------------------------------------
1 | package endpoints
2 |
3 | import "net/http"
4 |
5 | func UpdatePostEndpoint(w http.ResponseWriter, r *http.Request) {
6 |
7 | // TODO: Implement the update post endpoint
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/feed.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FeedHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | m := make(map[string]string)
8 | m["PageTitle"] = "Feed"
9 | RenderGatedTemplate(w, "./templates/feed.html", m)
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/find.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FindHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/foo.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func FooHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | fooID := r.Context().Value("fooID").(string)
10 | w.Write([]byte(fooID))
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/friends.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func FriendsHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | m := make(map[string]string)
8 | m["PageTitle"] = "Friends"
9 | RenderGatedTemplate(w, "./templates/friends.html", m)
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/home.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func HomeHandler(w http.ResponseWriter, r *http.Request) {
9 |
10 | fmt.Println("home page handler reached")
11 | }
12 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/logout.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common/authenticate"
7 | )
8 |
9 | func LogoutHandler(w http.ResponseWriter, r *http.Request) {
10 |
11 | authenticate.ExpireUserSession(w, r)
12 | authenticate.ExpireSecureCookie(w, r)
13 | }
14 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/myprofile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func MyProfileHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | m := make(map[string]string)
10 | m["PageTitle"] = "My Profile"
11 | RenderGatedTemplate(w, "./templates/profile.html", m)
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/panic.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func TriggerPanicHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | panic("Triggering a Panic!")
10 | }
11 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/profile.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "net/http"
5 | )
6 |
7 | func ProfileHandler(w http.ResponseWriter, r *http.Request) {
8 |
9 | w.Write([]byte("profile"))
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/register.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import "net/http"
4 |
5 | func RegisterHandler(w http.ResponseWriter, r *http.Request) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/handlers/utility.go:
--------------------------------------------------------------------------------
1 | package handlers
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | // Template rendering function
10 | func RenderTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
11 | t, err := template.ParseFiles(templateFile, "./templates/header.html", "./templates/footer.html")
12 | if err != nil {
13 | log.Printf("Error encountered while parsing the template: ", err)
14 | }
15 | t.Execute(w, templateData)
16 | }
17 |
18 | func RenderGatedTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
19 | t, err := template.ParseFiles(templateFile, "./templates/gatedheader.html", "./templates/footer.html")
20 | if err != nil {
21 | log.Printf("Error encountered while parsing the template: ", err)
22 | }
23 | t.Execute(w, templateData)
24 | }
25 |
26 | /*
27 | func RenderUnsafeTemplate(w http.ResponseWriter, templateFile string, templateData interface{}) {
28 | t, err := ttemplate.ParseFiles(templateFile)
29 | if err != nil {
30 | log.Printf("Error encountered while parsing the template: ", err)
31 | }
32 | w.Header().Set("X-XSS-Protection", "0")
33 | t.Execute(w, templateData)
34 | }
35 | */
36 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/middleware/contextexample.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | )
7 |
8 | func newExampleContext(ctx context.Context, r *http.Request) context.Context {
9 |
10 | fooID := r.Header.Get("X-Foo-ID")
11 | if fooID == "" {
12 | fooID = "bar"
13 | }
14 |
15 | return context.WithValue(ctx, "fooID", fooID)
16 |
17 | }
18 |
19 | func ContextExampleHandler(next http.Handler) http.Handler {
20 |
21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 |
23 | defer func() {
24 |
25 | ctx := newExampleContext(r.Context(), r)
26 | next.ServeHTTP(w, r.WithContext(ctx))
27 |
28 | }()
29 |
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/middleware/gated.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common/authenticate"
9 | )
10 |
11 | func GatedContentHandler(next http.HandlerFunc) http.Handler {
12 |
13 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14 |
15 | shouldRedirectToLogin := false
16 |
17 | secureCookieMap, err := authenticate.ReadSecureCookieValues(w, r)
18 | if err != nil {
19 | log.Print(err)
20 | }
21 |
22 | //fmt.Printf("secure cookie contents: %+v\n", secureCookieMap)
23 |
24 | // Check if the sid key which is used to store the session id value
25 | // has been populated in the map using the comma ok idiom
26 | if _, ok := secureCookieMap["sid"]; ok == true {
27 |
28 | gfSession, err := authenticate.SessionStore.Get(r, "gopherface-session")
29 |
30 | fmt.Printf("gopherface session values: %+v\n", gfSession.Values)
31 | if err != nil {
32 | log.Print(err)
33 | return
34 | }
35 |
36 | // Check if the session id stored in the secure cookie matches
37 | // the id and username on the server-side session
38 | if gfSession.Values["sessionID"] == secureCookieMap["sid"] && gfSession.Values["username"] == secureCookieMap["username"] {
39 | next(w, r)
40 | } else {
41 | shouldRedirectToLogin = true
42 | }
43 |
44 | } else {
45 | shouldRedirectToLogin = true
46 |
47 | }
48 |
49 | if shouldRedirectToLogin == true {
50 | http.Redirect(w, r, "/login", 302)
51 | }
52 |
53 | })
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/middleware/panicrecovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func PanicRecoveryHandler(next http.Handler) http.Handler {
9 |
10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 |
12 | defer func() {
13 |
14 | if err := recover(); err != nil {
15 | log.Printf("Encountered panic: %+v", err)
16 | http.Error(w, http.StatusText(500), 500)
17 | }
18 |
19 | }()
20 |
21 | next.ServeHTTP(w, r)
22 |
23 | })
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/models/socialmedia/moodstate_string.go:
--------------------------------------------------------------------------------
1 | // Code generated by "stringer -type=MoodState"; DO NOT EDIT
2 |
3 | package socialmedia
4 |
5 | import "fmt"
6 |
7 | const _MoodState_name = "MoodStateNeutralMoodStateHappyMoodStateSadMoodStateAngryMoodStateHopefulMoodStateThrilledMoodStateBoredMoodStateShyMoodStateComicalMoodStateOnCloudNine"
8 |
9 | var _MoodState_index = [...]uint8{0, 16, 30, 42, 56, 72, 89, 103, 115, 131, 151}
10 |
11 | func (i MoodState) String() string {
12 | if i < 0 || i >= MoodState(len(_MoodState_index)-1) {
13 | return fmt.Sprintf("MoodState(%d)", i)
14 | }
15 | return _MoodState_name[_MoodState_index[i]:_MoodState_index[i+1]]
16 | }
17 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/EngineerKamesh/gofullstack/volume2/section6/gopherfaceauth/common/utility"
7 | )
8 |
9 | type User struct {
10 | UUID string `json:"uuid" bson:"uuid"`
11 | Username string `json:"username" bson:"username"`
12 | FirstName string `json:"firstName" bson:"firstName"`
13 | LastName string `json:"lastName" bson:"lastName"`
14 | Email string `json:"email" bson:"email"`
15 | PasswordHash string `json:"passwordHash" bson:"passwordHash"`
16 | TimestampCreated int64 `json:"timestampCreated" bson:"timestampCreated"`
17 | TimestampModified int64 `json:"timestampModified" bson:"timestampModified"`
18 | }
19 |
20 | func NewUser(username string, firstName string, lastName string, email string, password string) *User {
21 |
22 | passwordHash := utility.SHA256OfString(password)
23 | now := time.Now()
24 | unixTimestamp := now.Unix()
25 | u := User{UUID: utility.GenerateUUID(), Username: username, FirstName: firstName, LastName: lastName, Email: email, PasswordHash: passwordHash, TimestampCreated: unixTimestamp}
26 | return &u
27 | }
28 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/css/gopherface.css:
--------------------------------------------------------------------------------
1 | body {
2 |
3 | font-family: arial, helvetica;
4 | margin-left: 18px;
5 |
6 | }
7 |
8 | body p {
9 | font-size: 16pt;
10 | }
11 |
12 | h1 {
13 | font-size: 1.8em;
14 | }
15 | .smpostContainer {
16 |
17 | border: 1px solid #CCC;
18 | width: 540px;
19 | min-height: 108px;
20 | padding: 18px;
21 | box-shadow: 1px 1px 3px #888;
22 | }
23 |
24 | .smpostFormContainer {
25 | width: 720px;
26 | }
27 |
28 | .uploadFormContainer {
29 | width: 720px;
30 | }
31 |
32 | #messageBody {
33 | min-height: 207px;
34 | }
35 |
36 | .author {
37 |
38 |
39 | }
40 |
41 | .caption {
42 |
43 | font-weight: bold;
44 | font-size: 18pt;
45 | }
46 |
47 | .caption a {
48 | text-decoration: none;
49 | }
50 |
51 | .creationtime {
52 |
53 | }
54 |
55 | .createdby {
56 | color: blue;
57 | }
58 |
59 | .imagePreview {
60 | text-align: center;
61 | margin-top: 18px;
62 | }
63 |
64 | .msgBody {
65 | margin-top: 27px;
66 |
67 | }
68 |
69 | /* pure overrides */
70 | .pure-form-message-inline {
71 | color: red !important;
72 | }
73 |
74 | .pure-control-group label, label{
75 | color: gray;
76 | font-weight: bold;
77 | font-size: 0.93em;
78 | }
79 |
80 | .imageContainer {
81 |
82 | display: inline;
83 | margin-right: 27px;
84 | }
85 |
86 | .videoContainer {
87 | display: inline;
88 | }
89 |
90 |
91 |
92 |
93 | ul {
94 | list-style-type: none;
95 | margin: 0;
96 | padding: 0;
97 | overflow: hidden;
98 | background-color: rgb(0,117,183);
99 | margin-left: -18px;
100 | }
101 |
102 | li {
103 | float: left;
104 | border-right:1px solid #bbb;
105 | }
106 |
107 | li:last-child {
108 | float: right;
109 | }
110 |
111 | li a {
112 | font-size: 1.2em;
113 | display: block;
114 | color: white;
115 | text-align: center;
116 | padding: 14px 16px;
117 | text-decoration: none;
118 | }
119 |
120 | li a:hover:not(.active) {
121 | background-color: rgb(0,76,142)
122 |
123 | }
124 |
125 | .active {
126 | background-color: #4CAF50;
127 | }
128 |
129 | #sitelogo {
130 | font-size: 3.6em;
131 | font-family: 'Lobster', serif;
132 | color: rgb(4,147,227);
133 | margin-bottom: 18px;
134 | /*
135 | text-shadow: 0px 1px 0px #999, 0px 2px 0px #888, 0px 3px 0px #777, 0px 4px 0px #666, 0px 5px 0px #555, 0px 6px 0px #444, 0px 7px 0px #333, 0px 8px 7px #001135;
136 | */
137 | }
138 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/0083d2f4a81588ed85c06679e68d9855754b498d.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/142cb526f8d5602ec97b674804768d4eb9c1d8b3.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/21ea6a171c98374b61ffceea7146da1ecaef14d9.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/68e3075133cf704244c2b2a61d78fa9adabdf678.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/85a586dc6db1483f6014819972e6d709a03e7801.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/8f8a8c9921ed370dbf405d3c3d7d6e73b82a8ac5.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/a3d046688ad17ab84d6c6fe79d2167aceba49f7f.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/c1e4861d325e29731efd9e9abc760eacf3d9be8b.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/imageset/c923378f14eba979d8e81db2fa8259f211af4870.png
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/uploads/images/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded image files.
2 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/uploads/videos/readme.txt:
--------------------------------------------------------------------------------
1 | This directory will store uploaded video files.
2 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/static/videoset/3DGopher.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Back-End-Web-Development-using-Go/d7c4ef71b4f23a3685b8da417a16eacc4f71686e/section6/gopherfaceauth/static/videoset/3DGopher.mp4
--------------------------------------------------------------------------------
/section6/gopherfaceauth/tasks/imagetask.go:
--------------------------------------------------------------------------------
1 | package tasks
2 |
3 | import (
4 | "fmt"
5 | "image/png"
6 | "log"
7 | "os"
8 |
9 | "github.com/nfnt/resize"
10 | )
11 |
12 | type ImageResizeTask struct {
13 | BaseImageName string
14 | ImageFileExtension string
15 | }
16 |
17 | func NewImageResizeTask(baseImageName string, imageFileExtension string) *ImageResizeTask {
18 | return &ImageResizeTask{BaseImageName: baseImageName, ImageFileExtension: imageFileExtension}
19 | }
20 |
21 | func (t *ImageResizeTask) Perform() {
22 |
23 | thumbImageFilePath := t.BaseImageName + "_thumb.png"
24 | fmt.Println("Creating new thumbnail at ", thumbImageFilePath)
25 |
26 | originalimagefile, err := os.Open(t.BaseImageName + t.ImageFileExtension)
27 |
28 | if err != nil {
29 | log.Println(err)
30 | return
31 | }
32 |
33 | img, err := png.Decode(originalimagefile)
34 |
35 | if err != nil {
36 | log.Println("Encountered Error while decoding image file: ", err)
37 | }
38 |
39 | thumbImage := resize.Resize(270, 0, img, resize.Lanczos3)
40 | thumbImageFile, err := os.Create(thumbImageFilePath)
41 |
42 | if err != nil {
43 | log.Println("Encountered error while resizing image:", err)
44 | }
45 |
46 | png.Encode(thumbImageFile, thumbImage)
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/templates/feed.html:
--------------------------------------------------------------------------------
1 | {{template "gatedheader.html" .}}
2 |
3 | {{.PageTitle}}
4 |
5 | Social media feed goes here.
6 |
7 | {{template "footer.html" .}}
8 |
--------------------------------------------------------------------------------
/section6/gopherfaceauth/templates/footer.html:
--------------------------------------------------------------------------------
1 |