diff --git a/main.go b/main.go index 98b310f..15ecfe0 100644 --- a/main.go +++ b/main.go @@ -28,33 +28,30 @@ const ( letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits ) -const appVersion = "1.1.0" +const appVersion = "1.2.0" var src = rand.NewSource(time.Now().UnixNano()) var pool = cache.New(240*time.Hour, 1*time.Hour) -var templates *template.Template -var allFiles []string +var t = template.Must(template.ParseFiles("templates/response.html")) -func init() { - files, err := ioutil.ReadDir("templates") - if err != nil { - log.Fatalln(err) - } - for _, file := range files { - filename := file.Name() - if strings.HasSuffix(filename, ".html") { - allFiles = append(allFiles, "templates/"+filename) - } - } - templates, err = template.ParseFiles(allFiles...) - if err != nil { - log.Fatalln(err) - } +type body struct { + FullHeader bool + IsGhost bool + HasForm bool + IsLink bool + H1 string + H3 string + Line1 string + Line2 string } func index(w http.ResponseWriter, r *http.Request) { - t := templates.Lookup("index.html") - t.Execute(w, nil) + b := body{ + HasForm: true, + Line1: "Welcome to Short, the simple URL shortener,", + Line2: "Type an URL below to shorten it", + } + t.Execute(w, b) } // get executes the GET command @@ -77,7 +74,15 @@ func set(key, suffix string) { func redirect(w http.ResponseWriter, r *http.Request, path string) { vals := mux.Vars(r) key := vals["key"] - t := templates.Lookup("404.html") + b := body{ + FullHeader: true, + IsGhost: true, + HasForm: true, + H1: "404", + H3: "page not found", + Line1: "Boo, looks like this ghost stole this page!", + Line2: "But you can type an URL below to shorten it", + } if path != "" { key = strings.Replace(key, path, "", 1) } @@ -86,7 +91,7 @@ func redirect(w http.ResponseWriter, r *http.Request, path string) { key, status := get(key) if !status { w.WriteHeader(http.StatusNotFound) - t.Execute(w, nil) + t.Execute(w, b) return } u, _ := url.Parse(key) @@ -102,11 +107,18 @@ func redirect(w http.ResponseWriter, r *http.Request, path string) { // then if writes the kv pair suffix, url to the database and return the // shortened url to the user func shortner(w http.ResponseWriter, r *http.Request, proto, domain, hostSuf, path string, urlSize int) { - ret := templates.Lookup("returnPage.html") - badR := templates.Lookup("400.html") if !govalidator.IsURL(r.FormValue("url")) { + b := body{ + FullHeader: true, + IsGhost: true, + HasForm: true, + H1: "400", + H3: "bad request", + Line1: "Boo, looks like this ghost stole this page!", + Line2: "But you can type an URL below to shorten it", + } w.WriteHeader(http.StatusBadRequest) - badR.Execute(w, nil) + t.Execute(w, b) return } u, _ := url.Parse(r.FormValue("url")) @@ -121,7 +133,11 @@ func shortner(w http.ResponseWriter, r *http.Request, proto, domain, hostSuf, pa } set(u.String(), suffix) shortend := proto + "://" + domain + hostSuf + path + suffix - ret.Execute(w, shortend) + b := body{ + IsLink: true, + Line1: shortend, + } + t.Execute(w, b) } // randStringBytesMaskImprSrc Generate random string of n size @@ -145,10 +161,18 @@ func randStringBytesMaskImprSrc(n int) string { // internalError receives a http.ResponseWriter, msg and error and // return a internal error page with http code 500 to the user func internalError(w http.ResponseWriter, msg string, err error) { - t := templates.Lookup("500.html") + b := body{ + FullHeader: true, + IsGhost: true, + HasForm: true, + H1: "500", + H3: "internal erver error", + Line1: "Boo, the ghost is broken :(", + Line2: "His last words where: " + err.Error(), + } log.Println(err) w.WriteHeader(http.StatusInternalServerError) - t.Execute(w, msg+err.Error()) + t.Execute(w, b) } // itemsCount returns the number of kv pairs on the in meomry database @@ -177,44 +201,51 @@ func itemsDump(w http.ResponseWriter, r *http.Request) { // itemsFromFile loads kv pairs from the dumpFile json to the in memory database func itemsFromFile(w http.ResponseWriter, r *http.Request, dumpFile string) { - t := templates.Lookup("ok.html") jsonFile, err := ioutil.ReadFile(dumpFile) var dumpObj map[string]cache.Item json.Unmarshal([]byte(jsonFile), &dumpObj) if err != nil { internalError(w, "Cannot open file "+dumpFile+": ", err) - } else { - pool = cache.NewFrom(240*time.Hour, 1*time.Hour, dumpObj) - t.Execute(w, "Imported "+strconv.Itoa(len(dumpObj))+" items to the DB") + return } + pool = cache.NewFrom(240*time.Hour, 1*time.Hour, dumpObj) + b := body{ + Line1: "Imported " + strconv.Itoa(len(dumpObj)) + " items to the DB", + } + t.Execute(w, b) } // itemsFromPost loads kv pairs from a json POST to the in memory database func itemsFromPost(w http.ResponseWriter, r *http.Request) { - t := templates.Lookup("ok.html") decoder := json.NewDecoder(r.Body) var dumpObj map[string]cache.Item err := decoder.Decode(&dumpObj) if err != nil { internalError(w, "Cannot parse JSON: ", err) - } else { - pool = cache.NewFrom(240*time.Hour, 1*time.Hour, dumpObj) - t.Execute(w, "Imported "+strconv.Itoa(len(dumpObj))+" items to the DB") + return } + pool = cache.NewFrom(240*time.Hour, 1*time.Hour, dumpObj) + b := body{ + Line1: "Imported " + strconv.Itoa(len(dumpObj)) + " items to the DB", + } + t.Execute(w, b) } // itemsDumpToFile dumps the kv pairs from the in memory database to the dumpFile func itemsDumpToFile(w http.ResponseWriter, r *http.Request, dumpFile string) { - t := templates.Lookup("ok.html") dumpObj, _ := json.Marshal( pool.Items(), ) err := ioutil.WriteFile(dumpFile, dumpObj, 0644) if err != nil { internalError(w, "Failed to open json file: ", err) - } else { - t.Execute(w, "Dump writen to: "+dumpFile) + return } + b := body{ + Line1: "Imported " + "Dump writen to: " + dumpFile, + } + t.Execute(w, b) + } func main() { diff --git a/templates/400.html b/templates/400.html deleted file mode 100644 index 0184d44..0000000 --- a/templates/400.html +++ /dev/null @@ -1,40 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "header" }} - <body> - <div id="background"></div> - <div class="top"> - <h1>400</h1> - <h3>Bad Request</h3> - </div> - <div class="container"> - <div class="ghost-copy"> - <div class="one"></div> - <div class="two"></div> - <div class="three"></div> - <div class="four"></div> - </div> - <div class="ghost"> - <div class="face"> - <div class="eye"></div> - <div class="eye-right"></div> - <div class="sad_mouth"></div> - </div> - </div> - <div class="shadow"></div> - </div> - <div class="bottom"> - <p>Boo, looks like a ghost didn't like your request! - <br> - But you can try again, type an URL below to shorten it</p> - <form class="search" action="/" method="POST"> - <input type="text" id="url" name="url" class="search-bar" placeholder="http://something :)"> - <button type="submit" value="Submit" name="Submit" class="search-btn"> - <i class="fa fa-search"></i> - </button> - </form> - </div> - - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/404.html b/templates/404.html deleted file mode 100644 index be7cd44..0000000 --- a/templates/404.html +++ /dev/null @@ -1,41 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "header" }} - - <body> - <div id="background"></div> - <div class="top"> - <h1>404</h1> - <h3>page not found</h3> - </div> - <div class="container"> - <div class="ghost-copy"> - <div class="one"></div> - <div class="two"></div> - <div class="three"></div> - <div class="four"></div> - </div> - <div class="ghost"> - <div class="face"> - <div class="eye"></div> - <div class="eye-right"></div> - <div class="mouth"></div> - </div> - </div> - <div class="shadow"></div> - </div> - <div class="bottom"> - <p>Boo, looks like a ghost stole this page! - <br> - But you can type an URL below to shorten it</p> - <form class="search" action="/" method="POST"> - <input type="text" id="url" name="url" class="search-bar" placeholder="http://something :)"> - <button type="submit" value="Submit" name="Submit" class="search-btn"> - <i class="fa fa-search"></i> - </button> - </form> - </div> - - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/500.html b/templates/500.html deleted file mode 100644 index df07b3a..0000000 --- a/templates/500.html +++ /dev/null @@ -1,35 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "header" }} - - <body> - <div id="background"></div> - <div class="top"> - <h1>500</h1> - <h3>Internal server error</h3> - </div> - <div class="container"> - <div class="ghost-copy"> - <div class="one"></div> - <div class="two"></div> - <div class="three"></div> - <div class="four"></div> - </div> - <div class="ghost"> - <div class="face"> - <div class="deadeye"><h3 style="color:black;font-size:1.5em">X</h3></div> - <div class="deadeye-right"><h3 style="color:black;font-size:1.5em">X</h3></div> - <div class="mouth"></div> - </div> - </div> - <div class="shadow"></div> - </div> - <div class="bottom"> - <p>Boo, the ghost is broken :( - <br> - His last words where: {{ . }} </p> - </div> - - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/footer.html b/templates/footer.html deleted file mode 100644 index 9e1b755..0000000 --- a/templates/footer.html +++ /dev/null @@ -1,5 +0,0 @@ -{{ define "footer" }} -<footer> - <p>html theme by <a href="https://codepen.io/juliepark"> julie</a> ♡ -</footer> -{{ end }} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index b4e2f7b..0000000 --- a/templates/index.html +++ /dev/null @@ -1,18 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "slimheader" }} - <body> - <div class="bottom"> - <p>Welcome to Short, the simple URL shortener, - <br> - Type an URL below to shorten it</p> - <form class="search" action="/" method="POST"> - <input type="text" id="url" name="url" class="search-bar" placeholder="http://something :)"> - <button type="submit" value="Submit" name="Submit" class="search-btn"> - <i class="fa fa-search"></i> - </button> - </form> - </div> - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/ok.html b/templates/ok.html deleted file mode 100644 index ef328cc..0000000 --- a/templates/ok.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "slimheader" }} - <body> - <div class="bottom"> - <p>{{ . }}</a></p> - </div> - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/header.html b/templates/response.html similarity index 73% rename from templates/header.html rename to templates/response.html index 6b2bb2a..3f0f8a7 100644 --- a/templates/header.html +++ b/templates/response.html @@ -1,4 +1,5 @@ -{{ define "header" }} +<!DOCTYPE html> +<html lang=en> <head> <title>Short: the simple url shortener</title> <style> @@ -7,7 +8,7 @@ body { background: #D3DEEA; } - + {{ if eq .FullHeader true }} .top { margin-top: 30px; } @@ -189,18 +190,6 @@ margin-top: -20px; font-weight: 900; } - p { - text-align: center; - font-family: 'Lato', sans-serif; - color: #585959; - font-size: .6em; - margin-top: -20px; - text-transform: uppercase; - } - - .search { - text-align: center; - } .buttons { display: flex; @@ -209,39 +198,6 @@ margin-top: 10px; } - /*search style*/ - - .search-bar { - border: 1px solid #BFC0C0; - padding: 5px; - height: 20px; - margin-left: -30px; - width: 200px; - outline: none; - &:focus { - border: 1px solid #D3DEEA; - } - } - - .search-btn { - position: absolute; - width: 30px; - height: 32px; - border: 1px solid #BFC0C0; - background: #BFC0C0; - text-align: center; - color: #EDEDED; - cursor: pointer; - font-size: 1em; - outline: none; - &:hover { - background: #EDEDED; - border: 1px solid #EDEDED; - color: #BFC0C0; - transition: all .2s ease; - } - } - .btn { background: #EDEDED; padding: 15px 20px; @@ -277,6 +233,124 @@ } } } + {{ else }} + form{ + position:fixed; + top:32%; + left:35%; + width:500px; + font-family:georgia,garamond,serif; + font-size:16px; + + } + .bottom { + position:fixed; + top:30%; + left:35%; + width:500px; + } + + {{ end }} + p { + text-align: center; + font-family: 'Lato', sans-serif; + color: #585959; + font-size: .6em; + margin-top: -20px; + text-transform: uppercase; + } + + .search { + text-align: center; + } + + /*search style*/ + + .search-bar { + border: 1px solid #BFC0C0; + padding: 5px; + height: 20px; + margin-left: -30px; + width: 200px; + outline: none; + &:focus { + border: 1px solid #D3DEEA; + } + } + + .search-btn { + position: absolute; + width: 30px; + height: 32px; + border: 1px solid #BFC0C0; + background: #BFC0C0; + text-align: center; + color: #EDEDED; + cursor: pointer; + font-size: 1em; + outline: none; + &:hover { + background: #EDEDED; + border: 1px solid #EDEDED; + color: #BFC0C0; + transition: all .2s ease; + } + } </style> </head> -{{ end }} + <body> + {{ if eq .IsGhost true }} + <div id="background"></div> + <div class="top"> + <h1>{{ .H1 }}</h1> + <h3>{{ .H3 }}</h3> + </div> + <div class="container"> + <div class="ghost-copy"> + <div class="one"></div> + <div class="two"></div> + <div class="three"></div> + <div class="four"></div> + </div> + <div class="ghost"> + <div class="face"> + {{ if or (eq .H1 "404") (eq .H1 "400" ) }} + <div class="eye"></div> + <div class="eye-right"></div> + {{ else if eq .H1 "500" }} + <div class="deadeye"><h3 style="color:black;font-size:1.5em">X</h3></div> + <div class="deadeye-right"><h3 style="color:black;font-size:1.5em">X</h3></div> + {{ end }} + {{ if eq .H1 "404" }} + <div class="mouth"></div> + {{ else if or ( eq .H1 "400") (eq .H1 "500") }} + <div class="sad_mouth"></div> + {{ end }} + </div> + </div> + <div class="shadow"></div> + </div> + {{ end }} + <div class="bottom"> + {{ if eq .IsLink true }} + <p>URL Shortened to <a href="{{ .Line1 }}">{{ .Line1 }}</a></p> + <p></a></p> + {{ else }} + <p>{{ .Line1 }} + <br> + {{ .Line2 }}</p> + {{ end }} + {{ if eq .HasForm true }} + <form class="search" action="/" method="POST"> + <input type="text" id="url" name="url" class="search-bar" placeholder="http://something :)"> + <button type="submit" value="Submit" name="Submit" class="search-btn"> + <i class="fa fa-search"></i> + </button> + </form> + {{ end }} + </div> + <footer> + <p>html theme by <a href="https://codepen.io/juliepark"> julie</a> ♡ + </footer> + </body> +</html> \ No newline at end of file diff --git a/templates/returnPage.html b/templates/returnPage.html deleted file mode 100644 index f1bcfc0..0000000 --- a/templates/returnPage.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang=en> - {{ template "slimheader" }} - <body> - <div class="bottom"> - <p>URL Shortened to <a href="{{ . }}">{{ . }}</a></p> - </div> - {{ template "footer" }} - </body> -</html> \ No newline at end of file diff --git a/templates/slimheader.html b/templates/slimheader.html deleted file mode 100644 index 21e877e..0000000 --- a/templates/slimheader.html +++ /dev/null @@ -1,72 +0,0 @@ -{{ define "slimheader" }} -<head> - <title>Short: the simple url shortener</title> - <style> - @import url('https://fonts.googleapis.com/css?family=Abril+Fatface|Lato'); - - body { - background: #D3DEEA; - } - - form{ - position:fixed; - top:32%; - left:35%; - width:500px; - font-family:georgia,garamond,serif; - font-size:16px; - - } - .bottom { - position:fixed; - top:30%; - left:35%; - width:500px; - } - - p { - text-align: center; - font-family: 'Lato', sans-serif; - color: #585959; - font-size: .6em; - margin-top: -20px; - text-transform: uppercase; - } - - .search { - text-align: center; - } - - .search-bar { - border: 1px solid #BFC0C0; - padding: 5px; - height: 20px; - margin-left: -30px; - width: 200px; - outline: none; - &:focus { - border: 1px solid #D3DEEA; - } - } - - .search-btn { - position: absolute; - width: 30px; - height: 32px; - border: 1px solid #BFC0C0; - background: #BFC0C0; - text-align: center; - color: #EDEDED; - cursor: pointer; - font-size: 1em; - outline: none; - &:hover { - background: #EDEDED; - border: 1px solid #EDEDED; - color: #BFC0C0; - transition: all .2s ease; - } - } - </style> - </head> -{{ end }} \ No newline at end of file