package main import ( "context" "database/sql" "errors" "html/template" "net/http" "strconv" "sync" "github.com/go-kit/kit/log/level" "git.c3pb.de/gbe/invinoveritas/auth" "git.c3pb.de/gbe/invinoveritas/log" "git.c3pb.de/gbe/invinoveritas/storage" "git.c3pb.de/gbe/invinoveritas/storage/query" ) func (h Handler) index() http.Handler { var ( once sync.Once tpl *template.Template ) type templateData struct { Wines []query.ListWinesRow User auth.User } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { once.Do(func() { tpl = template.Must(template.ParseFS(templateFS, "templates/base.tpl", "templates/index.tpl")) }) level.Debug(log.Get(r)).Log("user", auth.Get(r)) if r.Method == "GET" { wines, err := h.Q.ListWines(r.Context()) if err != nil { httpError(w, r, "can't list wines", err, http.StatusInternalServerError) return } w.Header().Add("content-type", "text/html") data := templateData{ Wines: wines, User: auth.Get(r), } err = tpl.ExecuteTemplate(w, "index.tpl", data) if err != nil { level.Error(log.Get(r)). Log("error", err, "msg", "can't execute index template") } return } if r.Method != "POST" { httpError(w, r, "invalid method", errors.New(r.Method), http.StatusMethodNotAllowed) return } name := r.FormValue("name") if len(name) > 80 || len(name) == 0 { httpError(w, r, "bad name", errors.New("name must be between 1 and 80 chars"), http.StatusBadRequest) return } ratingVal := r.FormValue("rating") var ( id int64 rating int err error ) if ratingVal != "" { rating, err = strconv.Atoi(ratingVal) if err != nil { httpError(w, r, "can't convert rating", err, http.StatusBadRequest) return } } err = r.ParseMultipartForm(16 * 1024 * 1024) if err != nil { level.Warn(log.Get(r)).Log("error", err, "msg", "can't parse multipart form data") } err = h.Q.RunTx(r.Context(), func(ctx context.Context, q *query.Queries) error { params := query.InsertWineParams{ Name: name, } if ratingVal != "" { params.Rating = sql.NullInt32{ Int32: int32(rating), Valid: true, } } res, err := q.InsertWine(ctx, params) if err != nil { httpError(w, r, "can't store wine", err, http.StatusInternalServerError) return err } id, err = res.LastInsertId() if err != nil { httpError(w, r, "can't store wine", err, http.StatusInternalServerError) return err } level.Debug(log.Get(r)).Log("msg", "inserted new wine", "id", id) // See if there's an image file uploaded and persist it if that's the case. if r.MultipartForm == nil || len(r.MultipartForm.File["picture"]) == 0 { return nil } picFile, picHdr, err := r.FormFile("picture") if err != nil { httpError(w, r, "can't open picture file", err, http.StatusInternalServerError) return err } defer picFile.Close() err = storage.AddPicture(ctx, q, int(id), picFile, picHdr.Header.Get("Content-Type")) if err != nil { httpError(w, r, "can't load picture", err, http.StatusBadRequest) return err } return nil }) if err != nil { return } http.Redirect(w, r, "/details?id="+strconv.Itoa(int(id)), http.StatusSeeOther) // TODO: Is this the correct status? }) }