├── 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 |
15 | {{.Caption}} 16 |
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 |
12 |
13 | 14 |
15 | 16 | {{.Errors.captionError}} 17 |
18 | 19 |
20 | 21 | {{.Errors.messageBodyError}} 22 |
23 | 24 |
25 | 26 | 31 |
32 | 33 | 34 | 35 |
36 |
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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 |
12 |
13 | 14 |
15 | 16 | {{.Errors.captionError}} 17 |
18 | 19 |
20 | 21 | {{.Errors.messageBodyError}} 22 |
23 | 24 |
25 | 26 | 31 |
32 | 33 | 34 | 35 |
36 |
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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 |
12 |
13 | 14 |
15 | 16 | {{.Errors.captionError}} 17 |
18 | 19 |
20 | 21 | {{.Errors.messageBodyError}} 22 |
23 | 24 |
25 | 26 | 31 |
32 | 33 | 34 | 35 |
36 |
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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 |
12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 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 | 2 | 3 | -------------------------------------------------------------------------------- /section6/gopherfaceauth/templates/friends.html: -------------------------------------------------------------------------------- 1 | {{template "gatedheader.html" .}} 2 | 3 |

{{.PageTitle}}

4 | 5 |

List of friends goes here.

6 | 7 | {{template "footer.html" .}} 8 | -------------------------------------------------------------------------------- /section6/gopherfaceauth/templates/gatedheader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | GopherFace - {{.PageTitle}} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |