Mercurial > gemma
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 + } + } +}