From e003427f9f86b0b3898cca67b39a96e391fd1b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sun, 14 Apr 2019 03:59:53 +0200 Subject: sklad: preliminary web interface Only exposing most read operations thus far. --- sklad/base.tmpl | 44 +++++++++++++++++---- sklad/container.tmpl | 86 +++++++++++++++++++++++++++++++++++----- sklad/db.go | 11 +++--- sklad/login.tmpl | 5 ++- sklad/main.go | 110 +++++++++++++++++++++++++++++++++++++++++---------- sklad/series.tmpl | 43 ++++++++++++++++++++ 6 files changed, 253 insertions(+), 46 deletions(-) create mode 100644 sklad/series.tmpl diff --git a/sklad/base.tmpl b/sklad/base.tmpl index b8487ee..542d019 100644 --- a/sklad/base.tmpl +++ b/sklad/base.tmpl @@ -1,19 +1,46 @@ - {{ template "Title" }} - sklad + {{ template "Title" . }} - sklad + @@ -21,7 +48,7 @@

sklad

-{{ if .LoggedIn }} +{{ block "HeaderControls" . }} Obaly Řady @@ -33,6 +60,7 @@ {{ end }} +
{{ template "Content" . }} diff --git a/sklad/container.tmpl b/sklad/container.tmpl index b261496..cbc8ea4 100644 --- a/sklad/container.tmpl +++ b/sklad/container.tmpl @@ -1,25 +1,91 @@ -{{ define "Title" }}Přehled{{ end }} +{{ define "Title" }}{{ or .Id "Obaly" }}{{ end }} {{ define "Content" }} {{ if .Id }} -

{{ .Id }}

+ +
+
+

{{ .Id }}

+
+ +
+
+ +
+
+ +
+ +
+
+ + +
+
+ + +
+ +
+
+
+ +

Podobaly

+ {{ else }} -

Obaly nejvyšší úrovně

+
+
+

Nový obal

+
+
+ +
+
+ + +
+
+ + +
+ +
+
+
-{{ if .Description }} -

{{ .Description }} +

Obaly nejvyšší úrovně

{{ end }} -{{ if .Children }} {{ range .Children }} -
-

{{ .Id }}

+
+
+

{{ .Id }}

+
+ +
+
+ +
+
{{ if .Description }}

{{ .Description }} {{ end }} -

-{{ end }} + {{ else }}

Obal je prázdný. {{ end }} diff --git a/sklad/db.go b/sklad/db.go index 8710fb5..3420c23 100644 --- a/sklad/db.go +++ b/sklad/db.go @@ -123,12 +123,11 @@ func loadDatabase() error { // Construct an index that goes from parent containers to their children. for _, pv := range db.Containers { - if pv.Parent == "" { - continue - } - if _, ok := indexContainer[pv.Parent]; !ok { - return fmt.Errorf("container %s has a nonexistent parent %s", - pv.Id(), pv.Parent) + if pv.Parent != "" { + if _, ok := indexContainer[pv.Parent]; !ok { + return fmt.Errorf("container %s has a nonexistent parent %s", + pv.Id(), pv.Parent) + } } indexChildren[pv.Parent] = append(indexChildren[pv.Parent], pv) } diff --git a/sklad/login.tmpl b/sklad/login.tmpl index 8dbca84..dab1172 100644 --- a/sklad/login.tmpl +++ b/sklad/login.tmpl @@ -1,12 +1,13 @@ {{ define "Title" }}Přihlášení{{ end }} +{{ define "HeaderControls" }}{{ end }} {{ define "Content" }}

Přihlášení

- - +
{{ if .IncorrectPassword }} diff --git a/sklad/main.go b/sklad/main.go index dee8723..a2a7143 100644 --- a/sklad/main.go +++ b/sklad/main.go @@ -13,8 +13,6 @@ import ( var templates = map[string]*template.Template{} -// TODO: Consider wrapping the data object in something that always contains -// a LoggedIn member, so that we don't need to duplicate it. func executeTemplate(name string, w io.Writer, data interface{}) { if err := templates[name].Execute(w, data); err != nil { panic(err) @@ -48,7 +46,6 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { } params := struct { - LoggedIn bool IncorrectPassword bool }{} @@ -82,39 +79,119 @@ func handleLogout(w http.ResponseWriter, r *http.Request) { } func handleContainer(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + // TODO + } if r.Method != http.MethodGet { w.WriteHeader(http.StatusMethodNotAllowed) return } + allSeries := map[string]string{} + for _, s := range indexSeries { + allSeries[s.Prefix] = s.Description + } + children := []*Container{} id := ContainerId(r.FormValue("id")) description := "" + series := "" + parent := ContainerId("") if id == "" { - children = db.Containers + children = indexChildren[id] } else if container, ok := indexContainer[id]; ok { children = indexChildren[id] description = container.Description + series = container.Series + parent = container.Parent } params := struct { - LoggedIn bool Id ContainerId Description string Children []*Container + Series string + Parent ContainerId + AllSeries map[string]string }{ - LoggedIn: true, Id: id, Description: description, Children: children, + Series: series, + Parent: parent, + AllSeries: allSeries, } executeTemplate("container.tmpl", w, ¶ms) } -// TODO: Consider a wrapper function that automatically calls ParseForm -// and disables client-side caching. +func handleSeries(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + // TODO + } + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + allSeries := map[string]string{} + for _, s := range indexSeries { + allSeries[s.Prefix] = s.Description + } + + prefix := r.FormValue("prefix") + description := "" + + if prefix == "" { + } else if series, ok := indexSeries[prefix]; ok { + description = series.Description + } + + params := struct { + Prefix string + Description string + AllSeries map[string]string + }{ + Prefix: prefix, + Description: description, + AllSeries: allSeries, + } + + executeTemplate("series.tmpl", w, ¶ms) +} + +func handleSearch(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + query := r.FormValue("q") + _ = query + + // TODO: Query the database for exact matches and fulltext. + + params := struct{}{} + + executeTemplate("search.tmpl", w, ¶ms) +} + +func handleLabel(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + id := r.FormValue("id") + _ = id + + // TODO: See if such a container exists, print a label on the printer. + + params := struct{}{} + + executeTemplate("label.tmpl", w, ¶ms) +} func main() { // Randomize the RNG for session string generation. @@ -144,20 +221,13 @@ func main() { // 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 and pages. - // - // - GET /container?id=UA1 - // - GET /series?id=A - // - GET /search?q=bottle - // - // - https://stackoverflow.com/a/33880971/76313 - // - POST /label?id=UA1 - - http.HandleFunc("/", sessionWrap(wrap(handleContainer))) - http.HandleFunc("/container", sessionWrap(wrap(handleContainer))) - http.HandleFunc("/login", wrap(handleLogin)) http.HandleFunc("/logout", sessionWrap(wrap(handleLogout))) + http.HandleFunc("/", sessionWrap(wrap(handleContainer))) + http.HandleFunc("/series", sessionWrap(wrap(handleSeries))) + http.HandleFunc("/search", sessionWrap(wrap(handleSearch))) + http.HandleFunc("/label", sessionWrap(wrap(handleLabel))) + log.Fatalln(http.ListenAndServe(address, nil)) } diff --git a/sklad/series.tmpl b/sklad/series.tmpl new file mode 100644 index 0000000..4956e3a --- /dev/null +++ b/sklad/series.tmpl @@ -0,0 +1,43 @@ +{{ define "Title" }}{{ or .Prefix "Řady" }}{{ end }} +{{ define "Content" }} + +{{ if .Prefix }} +

{{ .Prefix }}

+ +{{ if .Description }} +

{{ .Description }} +{{ end }} +{{ else }} + +

+
+
+

Nová řada

+ + + +
+ +
+ +{{ range $prefix, $desc := .AllSeries }} +
+
+

{{ $prefix }}

+
+ +
+
+ +
+
+
+{{ else }} +

Nejsou žádné řady. +{{ end }} + +{{ end }} + +{{ end }} -- cgit v1.2.3