diff pkg/controllers/shapestretches.go @ 4305:0f467a839fe2

Moved stretches as shape file download to separate file.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 02 Sep 2019 18:01:45 +0200
parents
children e5a831ecd557
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/controllers/shapestretches.go	Mon Sep 02 18:01:45 2019 +0200
@@ -0,0 +1,224 @@
+// 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 (
+	"archive/zip"
+	"database/sql"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"time"
+
+	"github.com/gorilla/mux"
+	"github.com/jonas-p/go-shp"
+
+	"gemma.intevation.de/gemma/pkg/config"
+	"gemma.intevation.de/gemma/pkg/middleware"
+	"gemma.intevation.de/gemma/pkg/wkb"
+)
+
+const (
+	selectStretchSQL = `
+SELECT
+  id,
+  isrs_asText(lower(stretch)),
+  isrs_asText(upper(stretch)),
+  ST_AsBinary(area::geometry),
+  objnam,
+  nobjnam,
+  date_info,
+  source_organization
+FROM waterway.stretches WHERE
+  staging_done AND
+  name = $1`
+
+	selectStretchCountriesSQL = `
+SELECT country_code FROM waterway.stretch_countries
+WHERE stretches_id = $1
+ORDER BY country_code`
+)
+
+func stretchShapeDownload(rw http.ResponseWriter, req *http.Request) {
+	vars := mux.Vars(req)
+	name := vars["name"]
+
+	conn := middleware.GetDBConn(req)
+	ctx := req.Context()
+
+	tx, err := conn.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
+	if err != nil {
+		http.Error(
+			rw, fmt.Sprintf("DB error: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+	defer tx.Rollback()
+
+	var (
+		id           int64
+		lower, upper string
+		data         []byte
+		objnam       string
+		nobjnam      sql.NullString
+		dateInfo     time.Time
+		source       string
+	)
+
+	switch err := tx.QueryRowContext(ctx, selectStretchSQL, name).Scan(
+		&id,
+		&lower, &upper,
+		&data,
+		&objnam, &nobjnam,
+		&dateInfo,
+		&source,
+	); {
+	case err == sql.ErrNoRows:
+		http.NotFound(rw, req)
+		return
+	case err != nil:
+		http.Error(
+			rw, fmt.Sprintf("DB error: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	var countries []string
+
+	if err := func() error {
+		rows, err := tx.Query(selectStretchCountriesSQL, id)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			var country string
+			if err := rows.Scan(&country); err != nil {
+				return err
+			}
+			countries = append(countries, country)
+		}
+
+		return rows.Err()
+	}(); err != nil {
+		http.Error(
+			rw, fmt.Sprintf("DB error: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	var geom wkb.MultiPolygonGeom
+
+	if err := geom.FromWKB(data); err != nil {
+		http.Error(
+			rw, fmt.Sprintf("Decoding WKB error: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	tmp := config.TmpDir()
+
+	dir, err := ioutil.TempDir(tmp, "stretch-download")
+	if err != nil {
+		http.Error(
+			rw, fmt.Sprintf("Cannot create temp dir: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+	defer os.RemoveAll(dir)
+
+	shpDir := filepath.Join(dir, "stretch")
+
+	if err := os.Mkdir(shpDir, os.ModePerm); err != nil {
+		http.Error(
+			rw, fmt.Sprintf("Cannot create temp dir: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	filename := filepath.Join(shpDir, "stretch")
+
+	if err := func() error {
+		writer, err := shp.Create(filename, shp.POLYGON)
+		if err != nil {
+			return err
+		}
+		defer writer.Close()
+
+		// TODO: Write geometry
+
+		return nil
+	}(); err != nil {
+		http.Error(
+			rw, fmt.Sprintf("creating shapefile failed: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	entries, err := func() ([]os.FileInfo, error) {
+		f, err := os.Open(shpDir)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+		return f.Readdir(-1)
+	}()
+	if err != nil {
+		http.Error(
+			rw, fmt.Sprintf("cannot read directory: %v.", err),
+			http.StatusInternalServerError)
+		return
+	}
+
+	rw.Header().Set("Content-Type", "application/zip")
+	rw.Header().Set("Content-Disposition", `attachment; filename="stretch.zip"`)
+
+	zipfile := zip.NewWriter(rw)
+	defer zipfile.Close()
+
+	now := time.Now()
+
+	base := filepath.Base(shpDir)
+	for _, info := range entries {
+		if !info.Mode().IsRegular() {
+			continue
+		}
+		if err := func() error {
+			srcFile, err := os.Open(filepath.Join(shpDir, info.Name()))
+			if err != nil {
+				return err
+			}
+			defer srcFile.Close()
+			header := &zip.FileHeader{
+				Name:     base + "/" + info.Name(),
+				Method:   zip.Deflate,
+				Modified: now,
+			}
+			out, err := zipfile.CreateHeader(header)
+			if err != nil {
+				return err
+			}
+			_, err = io.Copy(out, srcFile)
+			return err
+		}(); err != nil {
+			log.Printf("error: cannot write file: %v\n", err)
+			return
+		}
+	}
+}