Mercurial > gemma
view pkg/controllers/shapestretches.go @ 5591:0011f50cf216 surveysperbottleneckid
Removed no longer used alternative api for surveys/ endpoint.
As bottlenecks in the summary for SR imports are now identified by
their id and no longer by the (not guarantied to be unique!) name,
there is no longer the need to request survey data by the name+date
tuple (which isn't reliable anyway). So the workaround was now
reversed.
author | Sascha Wilde <wilde@sha-bang.de> |
---|---|
date | Wed, 06 Apr 2022 13:30:29 +0200 |
parents | 5f47eeea988d |
children | 31973f6f5cca |
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 ( "archive/zip" "database/sql" "fmt" "io" "io/ioutil" "net/http" "os" "path/filepath" "strings" "time" "github.com/gorilla/mux" "github.com/jonas-p/go-shp" "gemma.intevation.de/gemma/pkg/config" "gemma.intevation.de/gemma/pkg/log" "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 users.stretches WHERE staging_done AND name = $1` selectStretchCountriesSQL = ` SELECT country FROM users.stretch_countries WHERE stretch_id = $1 ORDER BY country` ) func flattenPoints(mp wkb.MultiPolygonGeom) []shp.Point { var n int for _, p := range mp { for _, r := range p { n += len(r) } } ps := make([]shp.Point, n) var i int for _, p := range mp { for _, r := range p { for _, v := range r { ps[i].X = v.X ps[i].Y = v.Y i++ } } } return ps } func asShpPolygon(mp wkb.MultiPolygonGeom) *shp.Polygon { points := flattenPoints(mp) var numParts int for _, pl := range mp { numParts += len(pl) } p := &shp.Polygon{} p.NumParts = int32(numParts) p.NumPoints = int32(len(points)) p.Parts = make([]int32, numParts) var marker int32 var i int for _, pl := range mp { for _, r := range pl { p.Parts[i] = marker i++ marker += int32(len(r)) } } p.Points = points p.Box = shp.BBoxFromPoints(points) return p } 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() fields := []shp.Field{ shp.StringField("NAME", 50), shp.StringField("OBJNAM", 50), shp.StringField("NOBJNAM", 50), shp.StringField("LOWER", 25), shp.StringField("UPPER", 25), shp.StringField("SOURCE", 50), shp.StringField("DATEINFO", 25), shp.StringField("COUNTRIES", 50), } writer.SetFields(fields) p := asShpPolygon(geom) writer.Write(p) write := func(field int, v interface{}) { if err == nil { err = writer.WriteAttribute(0, field, v) } } write(0, name) write(1, objnam) if nobjnam.Valid { write(2, nobjnam.String) } write(3, lower) write(4, upper) write(5, source) write(6, dateInfo.Format(time.RFC3339)) if len(countries) > 0 { write(7, strings.Join(countries, ",")) } return err }(); 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.Errorf("cannot write file: %v\n", err) return } } }