view pkg/controllers/gauges.go @ 2723:a10022399e24

WFS downloads: Fetch user and password from config.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 19 Mar 2019 12:42:43 +0100
parents 0d7a4fdb9e12
children 87aed4f9b1b8
line wrap: on
line source

// 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
	}
}