diff options
Diffstat (limited to 'sklad/main.go')
-rw-r--r-- | sklad/main.go | 108 |
1 files changed, 96 insertions, 12 deletions
diff --git a/sklad/main.go b/sklad/main.go index c1eaa99..3ceea9f 100644 --- a/sklad/main.go +++ b/sklad/main.go @@ -2,21 +2,100 @@ package main import ( "html/template" + "io" "log" + "math/rand" "net/http" "os" + "path/filepath" + "time" ) var ( - templates *template.Template - - // session storage: UUID -> net.SplitHostPort(http.Server.RemoteAddr)[0] - sessions = map[string]string{} + templates = map[string]*template.Template{} ) +func executeTemplate(name string, w io.Writer, data interface{}) { + if err := templates[name].Execute(w, data); err != nil { + panic(err) + } +} + +func handleLogin(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + redirect := r.FormValue("redirect") + if redirect == "" { + redirect = "/" + } + + session := sessionGet(w, r) + if session.LoggedIn { + http.Redirect(w, r, redirect, http.StatusSeeOther) + return + } + + params := struct { + LoggedIn bool + IncorrectPassword bool + }{} + + switch r.Method { + case http.MethodGet: + w.Header().Set("Cache-Control", "no-store") + case http.MethodPost: + if r.FormValue("password") == db.Password { + session.LoggedIn = true + http.Redirect(w, r, redirect, http.StatusSeeOther) + return + } + params.IncorrectPassword = true + default: + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + executeTemplate("login.tmpl", w, ¶ms) +} + +func handleLogout(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + session := r.Context().Value(sessionContextKey{}).(*Session) + session.LoggedIn = false + http.Redirect(w, r, "/", http.StatusSeeOther) +} + +func handleContainer(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + params := struct { + LoggedIn bool + }{ + LoggedIn: true, + } + + executeTemplate("container.tmpl", w, ¶ms) +} + +// TODO: Consider a wrapper function that automatically calls ParseForm +// and disables client-side caching. + func main() { + // Randomize the RNG for session string generation. + rand.Seed(time.Now().UnixNano()) + if len(os.Args) != 3 { - log.Fatalf("usage: %s ADDRESS DATABASE\n", os.Args[0]) + log.Fatalf("Usage: %s ADDRESS DATABASE-FILE\n", os.Args[0]) } var address string @@ -28,26 +107,31 @@ func main() { } // Load HTML templates from the current working directory. - var err error - templates, err = template.ParseGlob("*.tmpl") + m, err := filepath.Glob("*.tmpl") if err != nil { log.Fatalln(err) } + for _, name := range m { + templates[name] = template.Must(template.ParseFiles("base.tmpl", name)) + } // TODO: Eventually we will need to load a font file for label printing. // - The path might be part of configuration, or implicit by filename. - // TODO: Some routing, don't forget about sessions. - // - https://stackoverflow.com/a/33880971/76313 + // TODO: Some routing and pages. // - // - GET /login // - GET /container?id=UA1 // - GET /series?id=A // - GET /search?q=bottle // - // - POST /login?pass=hue - // - POST /logout + // - https://stackoverflow.com/a/33880971/76313 // - POST /label?id=UA1 + http.HandleFunc("/", sessionWrap(handleContainer)) + http.HandleFunc("/container", sessionWrap(handleContainer)) + + http.HandleFunc("/login", handleLogin) + http.HandleFunc("/logout", sessionWrap(handleLogout)) + log.Fatalln(http.ListenAndServe(address, nil)) } |