Mercurial > gemma
diff pkg/controllers/gauges.go @ 2694:0d7a4fdb9e12
Added GET /api/data/waterlevels/{gauge isrs}?from={time_a}&to={time_b} to fetch waterlevels of gauge.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 15 Mar 2019 18:34:13 +0100 |
parents | |
children | 87aed4f9b1b8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/controllers/gauges.go Fri Mar 15 18:34:13 2019 +0100 @@ -0,0 +1,142 @@ +// This is Free Software under GNU Affero General Public License v >= 3.0 +// without warranty, see README.md and license for details. +// +// SPDX-License-Identifier: AGPL-3.0-or-later +// License-Filename: LICENSES/AGPL-3.0.txt +// +// Copyright (C) 2019 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Sascha L. Teichmann <sascha.teichmann@intevation.de> + +package controllers + +import ( + "encoding/csv" + "fmt" + "log" + "net/http" + "strconv" + "time" + + "github.com/gorilla/mux" + + "gemma.intevation.de/gemma/pkg/middleware" + "gemma.intevation.de/gemma/pkg/models" +) + +const ( + selectWaterlevelsSQL = ` +SELECT + measure_date, + water_level, + predicted +FROM waterway.gauge_measurements +WHERE +` +) + +func waterlevels(rw http.ResponseWriter, req *http.Request) { + gauge := mux.Vars(req)["gauge"] + + isrs, err := models.IsrsFromString(gauge) + if err != nil { + http.Error( + rw, fmt.Sprintf("error: Invalid ISRS code: %v", err), + http.StatusBadRequest) + return + } + + var fb filterBuilder + fb.stmt.WriteString(selectWaterlevelsSQL) + + fb.cond( + " fk_gauge_id = ($%d::char(2), $%d::char(3), $%d::char(5), $%d::char(5), $%d::int) ", + isrs.CountryCode, + isrs.LoCode, + isrs.FairwaySection, + isrs.Orc, + isrs.Hectometre, + ) + + if from := req.FormValue("from"); from != "" { + fromTime, err := time.Parse(models.ImportTimeFormat, from) + if err != nil { + http.Error( + rw, fmt.Sprintf("error: Invalid from time: %v", err), + http.StatusBadRequest) + return + } + fb.cond("measure_date >= $%d", fromTime) + } + + if to := req.FormValue("to"); to != "" { + toTime, err := time.Parse(models.ImportTimeFormat, to) + if err != nil { + http.Error( + rw, fmt.Sprintf("error: Invalid from time: %v", err), + http.StatusBadRequest) + return + } + fb.cond("measure_date <= $%d", toTime) + } + + conn := middleware.GetDBConn(req) + + ctx := req.Context() + + rows, err := conn.QueryContext(ctx, fb.stmt.String(), fb.args...) + if err != nil { + http.Error( + rw, fmt.Sprintf("error: %v", err), + http.StatusInternalServerError) + return + } + defer rows.Close() + + rw.Header().Add("Content-Type", "text/csv") + + out := csv.NewWriter(rw) + + record := make([]string, 3) + + for rows.Next() { + var ( + measureDate time.Time + waterlevel float64 + predicted bool + ) + if err := rows.Scan(&measureDate, &waterlevel, &predicted); err != nil { + log.Printf("error: %v\n", err) + // Too late for an HTTP error code. + return + } + record[0] = measureDate.Format(models.ImportTimeFormat) + record[1] = strconv.FormatFloat(waterlevel, 'f', -1, 64) + if predicted { + record[2] = "t" + } else { + record[2] = "f" + } + if err := out.Write(record); err != nil { + log.Printf("error: %v", err) + // Too late for an HTTP error code. + return + } + } + + if err := rows.Err(); err != nil { + log.Printf("error: %v", err) + // Too late for an HTTP error code. + return + } + + out.Flush() + if err := out.Error(); err != nil { + log.Printf("error: %v", err) + // Too late for an HTTP error code. + return + } +}