Mercurial > gemma
changeset 3439:d7ddb21f7017 fairway-avail-csv
Prepared to write the fairway availibilty as CSV, too. WIP.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 24 May 2019 11:20:15 +0200 |
parents | df6c2973f791 |
children | e07b18f2482e |
files | pkg/controllers/bottlenecks.go pkg/controllers/routes.go pkg/controllers/stretches.go |
diffstat | 3 files changed, 164 insertions(+), 201 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/bottlenecks.go Fri May 24 11:15:58 2019 +0200 +++ b/pkg/controllers/bottlenecks.go Fri May 24 11:20:15 2019 +0200 @@ -256,29 +256,46 @@ return percents } -func parseTime(s, what string) (time.Time, error) { - var t time.Time - var err error - if t, err = time.Parse(common.TimeFormat, s); err != nil { - return time.Time{}, JSONError{ - Code: http.StatusBadRequest, - Message: fmt.Sprintf( - "Invalid time format for '%s' field: %v", what, err), - } +func parseFormTime( + rw http.ResponseWriter, + req *http.Request, + field string, + def time.Time, +) (time.Time, bool) { + f := req.FormValue(field) + if f == "" { + return def.UTC(), true } - return t.UTC(), nil + v, err := time.Parse(common.TimeFormat, f) + if err != nil { + http.Error( + rw, fmt.Sprintf("Invalid format for '%s': %v.", field, err), + http.StatusBadRequest, + ) + return time.Time{}, false + } + return v.UTC(), true } -func parseInt(s, what string) (int, error) { - i, err := strconv.Atoi(s) +func parseFormInt( + rw http.ResponseWriter, + req *http.Request, + field string, + def int, +) (int, bool) { + f := req.FormValue(field) + if f == "" { + return def, true + } + v, err := strconv.Atoi(f) if err != nil { - return 0, JSONError{ - Code: http.StatusBadRequest, - Message: fmt.Sprintf( - "Invalid value for field '%s': %v", what, err), - } + http.Error( + rw, fmt.Sprintf("Invalid format for '%s': %v.", field, err), + http.StatusBadRequest, + ) + return 0, false } - return i, nil + return v, true } func loadDepthValues( @@ -360,71 +377,60 @@ return values } -func bottleneckAvailabilty( - _ interface{}, - req *http.Request, - conn *sql.Conn, -) (jr JSONResult, err error) { +func bottleneckAvailabilty(rw http.ResponseWriter, req *http.Request) { + mode := intervalMode(req.FormValue("mode")) bn := mux.Vars(req)["objnam"] - var from, to time.Time - var los int var breaks []float64 var ldcRefs []float64 if bn == "" { - err = JSONError{ - Code: http.StatusBadRequest, - Message: "Missing objnam of bottleneck", - } + http.Error( + rw, + "Missing objnam of bottleneck", + http.StatusBadRequest, + ) return } - if f := req.FormValue("from"); f != "" { - if from, err = parseTime(f, "from"); err != nil { - return - } - } else { - from = time.Now().AddDate(-1, 0, 0).UTC() + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) + if !ok { + return } - if t := req.FormValue("to"); t != "" { - if to, err = parseTime(t, "to"); err != nil { - return - } - } else { - to = from.AddDate(1, 0, 0).UTC() + to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) + if !ok { + return } if to.Before(from) { to, from = from, to } - if l := req.FormValue("los"); l != "" { - if los, err = parseInt(l, "los"); err != nil { - return - } - } else { - los = 1 + los, ok := parseFormInt(rw, req, "los", 1) + if !ok { + return } - if b := req.FormValue("breaks"); b != "" { - breaks = breaksToReferenceValue(b) - } else { - breaks = afdRefs - } - + conn := middleware.GetDBConn(req) ctx := req.Context() - if ldcRefs, err = loadLDCReferenceValue(ctx, conn, bn); err != nil { + ldcRefs, err := loadLDCReferenceValue(ctx, conn, bn) + if err != nil { + http.Error( + rw, + fmt.Sprintf("Internal server error: %v", err), + http.StatusInternalServerError, + ) return } if len(ldcRefs) == 0 { - err = JSONError{ - Code: http.StatusNotFound, - Message: "No gauge reference values found for bottleneck", - } + http.Error( + rw, + "No gauge reference values found for bottleneck", + http.StatusNotFound, + ) return } @@ -436,28 +442,38 @@ } if len(ms) == 0 { - err = JSONError{ - Code: http.StatusNotFound, - Message: "No available fairway depth values found", - } + http.Error( + rw, + "No available fairway depth values found", + http.StatusNotFound, + ) return } - lnwl := ms.classify( - from, to, - ldcRefs, - (*availMeasurement).getValue, - ) + interval := intervals[mode](from, to) + + for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { + lnwl := ms.classify( + pfrom, pto, + ldcRefs, + (*availMeasurement).getValue, + ) - afd := ms.classify( - from, to, - breaks, - (*availMeasurement).getDepth, - ) + afd := ms.classify( + from, to, + breaks, + (*availMeasurement).getDepth, + ) - duration := to.Sub(from) - lnwlPercents := durationsToPercentage(duration, lnwl) - afdPercents := durationsToPercentage(duration, afd) + duration := pto.Sub(pfrom) + lnwlPercents := durationsToPercentage(duration, lnwl) + afdPercents := durationsToPercentage(duration, afd) + + _ = lnwlPercents + _ = afdPercents + } + + /* // TODO: Rewrite this type ldcOutput struct { Value float64 `json:"value"` @@ -502,17 +518,10 @@ } jr = JSONResult{Result: &out} + */ return } -/* - -{ "type": "below", "value": 230, "percent": 0 }, -{ "below": 250, "value": 9 } -{ "above": 250, "value": 8.1 - -*/ - func intervalMode(mode string) int { switch strings.ToLower(mode) { case "monthly": @@ -529,8 +538,6 @@ func bottleneckAvailableFairwayDepth(rw http.ResponseWriter, req *http.Request) { mode := intervalMode(req.FormValue("mode")) - var from, to time.Time - var los int bn := mux.Vars(req)["objnam"] if bn == "" { @@ -540,46 +547,23 @@ return } - if f := req.FormValue("from"); f != "" { - var err error - if from, err = time.Parse(common.TimeFormat, f); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'from': %v.", err), - http.StatusBadRequest) - return - } - } else { - from = time.Now().AddDate(-1, 0, 0) + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) + if !ok { + return } - from = from.UTC() - if t := req.FormValue("to"); t != "" { - var err error - if to, err = time.Parse(common.TimeFormat, t); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'to': %v.", err), - http.StatusBadRequest) - return - } - } else { - to = from.AddDate(1, 0, 0) + to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) + if !ok { + return } - to = to.UTC() if to.Before(from) { to, from = from, to } - if l := req.FormValue("los"); l != "" { - var err error - if los, err = strconv.Atoi(l); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'los': %v.", err), - http.StatusBadRequest) - return - } - } else { - los = 1 + los, ok := parseFormInt(rw, req, "los", 1) + if !ok { + return } conn := middleware.GetDBConn(req)
--- a/pkg/controllers/routes.go Fri May 24 11:15:58 2019 +0200 +++ b/pkg/controllers/routes.go Fri May 24 11:20:15 2019 +0200 @@ -310,13 +310,9 @@ })).Methods(http.MethodPut) // Handler to serve data to the client. - api.Handle("/data/bottleneck/availability/{objnam}", any(&JSONHandler{ - Handle: bottleneckAvailabilty, - })).Methods(http.MethodGet) - api.Handle("/data/{kind:stretch|section}/availability/{name}", any(&JSONHandler{ - Handle: stretchAvailabilty, - })).Methods(http.MethodGet) + api.Handle("/data/{kind:stretch|section}/availability/{name}", any( + middleware.DBConn(http.HandlerFunc(stretchAvailabilty)))).Methods(http.MethodGet) api.Handle("/data/{kind:stretch|section}/fairway-depth/{name}", any( middleware.DBConn(http.HandlerFunc(stretchAvailableFairwayDepth)))).Methods(http.MethodGet) @@ -324,6 +320,9 @@ api.Handle("/data/bottleneck/fairway-depth/{objnam}", any( middleware.DBConn(http.HandlerFunc(bottleneckAvailableFairwayDepth)))).Methods(http.MethodGet) + api.Handle("/data/bottleneck/availability/{objnam}", any( + middleware.DBConn(http.HandlerFunc(bottleneckAvailabilty)))).Methods(http.MethodGet) + api.Handle("/data/waterlevels/{gauge}", any( middleware.DBConn(http.HandlerFunc(waterlevels)))).Methods(http.MethodGet)
--- a/pkg/controllers/stretches.go Fri May 24 11:15:58 2019 +0200 +++ b/pkg/controllers/stretches.go Fri May 24 11:20:15 2019 +0200 @@ -21,12 +21,10 @@ "log" "net/http" "runtime" - "strconv" "strings" "sync" "time" - "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/middleware" "github.com/gorilla/mux" ) @@ -163,51 +161,26 @@ name := vars["name"] mode := intervalMode(req.FormValue("mode")) - var from, to time.Time - var los int depthbreaks, widthbreaks := afdRefs, afdRefs - if f := req.FormValue("from"); f != "" { - var err error - if from, err = time.Parse(common.TimeFormat, f); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'from': %v.", err), - http.StatusBadRequest) - return - } - } else { - from = time.Now().AddDate(-1, 0, 0) + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) + if !ok { + return } - from = from.UTC() - if t := req.FormValue("to"); t != "" { - var err error - if to, err = time.Parse(common.TimeFormat, t); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'to': %v.", err), - http.StatusBadRequest) - return - } - } else { - to = from.AddDate(1, 0, 0) + to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) + if !ok { + return } - to = to.UTC() if to.Before(from) { to, from = from, to } - if l := req.FormValue("los"); l != "" { - var err error - if los, err = strconv.Atoi(l); err != nil { - http.Error( - rw, fmt.Sprintf("Invalid format for 'los': %v.", err), - http.StatusBadRequest) - return - } - } else { - los = 1 + los, ok := parseFormInt(rw, req, "los", 1) + if !ok { + return } conn := middleware.GetDBConn(req) @@ -220,6 +193,7 @@ http.StatusInternalServerError) return } + if len(bns) == 0 { http.Error(rw, "No bottlenecks found.", http.StatusNotFound) return @@ -441,49 +415,42 @@ return b.String() } -func stretchAvailabilty( - _ interface{}, - req *http.Request, - conn *sql.Conn, -) (jr JSONResult, err error) { +func stretchAvailabilty(rw http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) stretch := vars["kind"] == "stretch" name := vars["name"] - var from, to time.Time - var los int - - depthbreaks, widthbreaks := afdRefs, afdRefs - - if f := req.FormValue("from"); f != "" { - if from, err = parseTime(f, "from"); err != nil { - return - } - } else { - from = time.Now().AddDate(-1, 0, 0).UTC() + if name == "" { + http.Error( + rw, + fmt.Sprintf("Missing %s name", vars["kind"]), + http.StatusBadRequest, + ) + return } - if t := req.FormValue("to"); t != "" { - if to, err = parseTime(t, "to"); err != nil { - return - } - } else { - to = from.AddDate(1, 0, 0).UTC() + from, ok := parseFormTime(rw, req, "form", time.Now().AddDate(-1, 0, 0)) + if !ok { + return + } + + to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) + if !ok { + return } if to.Before(from) { to, from = from, to } - if l := req.FormValue("los"); l != "" { - if los, err = parseInt(l, "los"); err != nil { - return - } - } else { - los = 1 + los, ok := parseFormInt(rw, req, "los", 1) + if !ok { + return } + depthbreaks, widthbreaks := afdRefs, afdRefs + if b := req.FormValue("depthbreaks"); b != "" { depthbreaks = breaksToReferenceValue(b) } @@ -492,29 +459,35 @@ widthbreaks = breaksToReferenceValue(b) } + conn := middleware.GetDBConn(req) ctx := req.Context() - var bns stretchBottlenecks - if bns, err = loadStretchBottlenecks(ctx, conn, stretch, name); err != nil { + bns, err := loadStretchBottlenecks(ctx, conn, stretch, name) + if err != nil { + http.Error( + rw, fmt.Sprintf("DB error: %v.", err), + http.StatusInternalServerError) return } if len(bns) == 0 { - err = JSONError{ - Code: http.StatusNotFound, - Message: "No bottlenecks found.", - } + http.Error( + rw, + "No bottlenecks found.", + http.StatusNotFound, + ) return } useDepth, useWidth := bns.contains("depth"), bns.contains("width") if useDepth && useWidth && len(widthbreaks) != len(depthbreaks) { - err = JSONError{ - Code: http.StatusBadRequest, - Message: fmt.Sprintf("class breaks lengths differ: %d != %d", + http.Error( + rw, + fmt.Sprintf("class breaks lengths differ: %d != %d", len(widthbreaks), len(depthbreaks)), - } + http.StatusBadRequest, + ) return } @@ -541,10 +514,11 @@ } if len(loaded) == 0 { - err = JSONError{ - Code: http.StatusInternalServerError, - Message: fmt.Sprintf("No bottleneck loaded: %v", joinErrors(errors)), - } + http.Error( + rw, + fmt.Sprintf("No bottleneck loaded: %v", joinErrors(errors)), + http.StatusInternalServerError, + ) return } @@ -620,6 +594,11 @@ lnwlPercents := durationsToPercentage(duration, ldc) afdPercents := durationsToPercentage(duration, afd) + _ = lnwlPercents + _ = afdPercents + + /* // TODO: Rewrite this + type ldcOutput struct { Value float64 `json:"value"` Below float64 `json:"below"` @@ -666,4 +645,5 @@ jr = JSONResult{Result: &out} return + */ }