aboutsummaryrefslogtreecommitdiff
path: root/cmd/sklad/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/sklad/main.go')
-rw-r--r--cmd/sklad/main.go271
1 files changed, 271 insertions, 0 deletions
diff --git a/cmd/sklad/main.go b/cmd/sklad/main.go
new file mode 100644
index 0000000..32dd68b
--- /dev/null
+++ b/cmd/sklad/main.go
@@ -0,0 +1,271 @@
+package main
+
+import (
+ "errors"
+ "html/template"
+ "io"
+ "log"
+ "math/rand"
+ "net/http"
+ "os"
+ "path/filepath"
+ "time"
+
+ "janouch.name/sklad/imgutil"
+ "janouch.name/sklad/label"
+ "janouch.name/sklad/ql"
+)
+
+var 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 wrap(inner func(http.ResponseWriter, *http.Request)) func(
+ http.ResponseWriter, *http.Request) {
+ return func(w http.ResponseWriter, r *http.Request) {
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if r.Method == http.MethodGet {
+ w.Header().Set("Cache-Control", "no-store")
+ }
+ inner(w, r)
+ }
+}
+
+func handleLogin(w http.ResponseWriter, r *http.Request) {
+ redirect := r.FormValue("redirect")
+ if redirect == "" {
+ redirect = "/"
+ }
+
+ session := sessionGet(w, r)
+ if session.LoggedIn {
+ http.Redirect(w, r, redirect, http.StatusSeeOther)
+ return
+ }
+
+ params := struct {
+ IncorrectPassword bool
+ }{}
+
+ switch r.Method {
+ case http.MethodGet:
+ // We're just going to render the template.
+ 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, &params)
+}
+
+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.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
+ }
+
+ var container *Container
+ children := []*Container{}
+
+ if id := ContainerId(r.FormValue("id")); id == "" {
+ children = indexChildren[""]
+ } else if c, ok := indexContainer[id]; ok {
+ children = c.Children()
+ container = c
+ }
+
+ params := struct {
+ Container *Container
+ Children []*Container
+ AllSeries map[string]string
+ }{
+ Container: container,
+ Children: children,
+ AllSeries: allSeries,
+ }
+
+ executeTemplate("container.tmpl", w, &params)
+}
+
+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, &params)
+}
+
+func handleSearch(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+
+ query := r.FormValue("q")
+ params := struct {
+ Query string
+ Series []*Series
+ Containers []*Container
+ }{
+ Query: query,
+ Series: dbSearchSeries(query),
+ Containers: dbSearchContainers(query),
+ }
+
+ executeTemplate("search.tmpl", w, &params)
+}
+
+func printLabel(id string) error {
+ printer, err := ql.Open()
+ if err != nil {
+ return err
+ }
+ if printer == nil {
+ return errors.New("no suitable printer found")
+ }
+ defer printer.Close()
+
+ /*
+ printer.StatusNotify = func(status *ql.Status) {
+ log.Printf("\x1b[1mreceived status\x1b[m\n%+v\n%s",
+ status[:], status)
+ }
+ */
+
+ if err := printer.Initialize(); err != nil {
+ return err
+ }
+ if err := printer.UpdateStatus(); err != nil {
+ return err
+ }
+
+ mediaInfo := ql.GetMediaInfo(
+ printer.LastStatus.MediaWidthMM(),
+ printer.LastStatus.MediaLengthMM(),
+ )
+ if mediaInfo == nil {
+ return errors.New("unknown media")
+ }
+
+ return printer.Print(&imgutil.LeftRotate{Image: label.GenLabelForHeight(
+ labelFont, id, mediaInfo.PrintAreaPins, db.BDFScale)})
+}
+
+func handleLabel(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+
+ params := struct {
+ Id string
+ UnknownId bool
+ Error error
+ }{
+ Id: r.FormValue("id"),
+ }
+
+ if c := indexContainer[ContainerId(params.Id)]; c == nil {
+ params.UnknownId = true
+ } else {
+ params.Error = printLabel(params.Id)
+ }
+
+ executeTemplate("label.tmpl", w, &params)
+}
+
+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-FILE\n", os.Args[0])
+ }
+
+ var address string
+ address, dbPath = os.Args[1], os.Args[2]
+
+ // Load database.
+ if err := loadDatabase(); err != nil {
+ log.Fatalln(err)
+ }
+
+ // Load HTML templates from the current working directory.
+ m, err := filepath.Glob("*.tmpl")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ for _, name := range m {
+ templates[name] = template.Must(template.ParseFiles("base.tmpl", name))
+ }
+
+ 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))
+}