changeset 4304:fee5794f3b7a

Return stretch as a ZIPed ESRI shape file from end point. TODO: Write the actual geometries to the shape file.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 02 Sep 2019 17:57:44 +0200
parents 3e0755af1177
children 0f467a839fe2
files pkg/controllers/routes.go pkg/controllers/stretches.go pkg/wkb/data.go
diffstat 3 files changed, 98 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/controllers/routes.go	Mon Sep 02 17:45:18 2019 +0200
+++ b/pkg/controllers/routes.go	Mon Sep 02 17:57:44 2019 +0200
@@ -309,7 +309,7 @@
 
 	// Handler to serve data to the client.
 
-	api.Handle("/data/{kind:stretch|section}/shape/{name}", any(
+	api.Handle("/data/stretch/shape/{name}", any(
 		mw.DBConn(http.HandlerFunc(stretchShapeDownload)))).Methods(http.MethodGet)
 
 	api.Handle("/data/{kind:stretch|section}/availability/{name}", any(
--- a/pkg/controllers/stretches.go	Mon Sep 02 17:45:18 2019 +0200
+++ b/pkg/controllers/stretches.go	Mon Sep 02 17:57:44 2019 +0200
@@ -14,20 +14,28 @@
 package controllers
 
 import (
+	"archive/zip"
 	"context"
 	"database/sql"
 	"encoding/csv"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"log"
 	"net/http"
+	"os"
+	"path/filepath"
 	"runtime"
 	"strings"
 	"sync"
 	"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"
-	"github.com/gorilla/mux"
 )
 
 const (
@@ -681,17 +689,8 @@
 
 func stretchShapeDownload(rw http.ResponseWriter, req *http.Request) {
 	vars := mux.Vars(req)
-	stretch := vars["kind"] == "stretch"
 	name := vars["name"]
 
-	// TODO: Implement me!
-	if !stretch {
-		http.Error(
-			rw, "Not implemented, yet!",
-			http.StatusBadRequest)
-		return
-	}
-
 	conn := middleware.GetDBConn(req)
 	ctx := req.Context()
 
@@ -766,6 +765,93 @@
 		return
 	}
 
-	// TODO: Serialize as ESRI shapefile.
+	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
+		}
+	}
 }
--- a/pkg/wkb/data.go	Mon Sep 02 17:45:18 2019 +0200
+++ b/pkg/wkb/data.go	Mon Sep 02 17:57:44 2019 +0200
@@ -64,8 +64,6 @@
 
 	polygons := make([]PolygonGeom, numPolygons)
 
-	// TODO: Parse the polygons.
-
 	for i := range polygons {
 		switch endian, err := r.ReadByte(); {
 		case err != nil: