comparison 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
comparison
equal deleted inserted replaced
4304:fee5794f3b7a 4305:0f467a839fe2
1 // This is Free Software under GNU Affero General Public License v >= 3.0
2 // without warranty, see README.md and license for details.
3 //
4 // SPDX-License-Identifier: AGPL-3.0-or-later
5 // License-Filename: LICENSES/AGPL-3.0.txt
6 //
7 // Copyright (C) 2019 by via donau
8 // – Österreichische Wasserstraßen-Gesellschaft mbH
9 // Software engineering by Intevation GmbH
10 //
11 // Author(s):
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de>
13
14 package controllers
15
16 import (
17 "archive/zip"
18 "database/sql"
19 "fmt"
20 "io"
21 "io/ioutil"
22 "log"
23 "net/http"
24 "os"
25 "path/filepath"
26 "time"
27
28 "github.com/gorilla/mux"
29 "github.com/jonas-p/go-shp"
30
31 "gemma.intevation.de/gemma/pkg/config"
32 "gemma.intevation.de/gemma/pkg/middleware"
33 "gemma.intevation.de/gemma/pkg/wkb"
34 )
35
36 const (
37 selectStretchSQL = `
38 SELECT
39 id,
40 isrs_asText(lower(stretch)),
41 isrs_asText(upper(stretch)),
42 ST_AsBinary(area::geometry),
43 objnam,
44 nobjnam,
45 date_info,
46 source_organization
47 FROM waterway.stretches WHERE
48 staging_done AND
49 name = $1`
50
51 selectStretchCountriesSQL = `
52 SELECT country_code FROM waterway.stretch_countries
53 WHERE stretches_id = $1
54 ORDER BY country_code`
55 )
56
57 func stretchShapeDownload(rw http.ResponseWriter, req *http.Request) {
58 vars := mux.Vars(req)
59 name := vars["name"]
60
61 conn := middleware.GetDBConn(req)
62 ctx := req.Context()
63
64 tx, err := conn.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
65 if err != nil {
66 http.Error(
67 rw, fmt.Sprintf("DB error: %v.", err),
68 http.StatusInternalServerError)
69 return
70 }
71 defer tx.Rollback()
72
73 var (
74 id int64
75 lower, upper string
76 data []byte
77 objnam string
78 nobjnam sql.NullString
79 dateInfo time.Time
80 source string
81 )
82
83 switch err := tx.QueryRowContext(ctx, selectStretchSQL, name).Scan(
84 &id,
85 &lower, &upper,
86 &data,
87 &objnam, &nobjnam,
88 &dateInfo,
89 &source,
90 ); {
91 case err == sql.ErrNoRows:
92 http.NotFound(rw, req)
93 return
94 case err != nil:
95 http.Error(
96 rw, fmt.Sprintf("DB error: %v.", err),
97 http.StatusInternalServerError)
98 return
99 }
100
101 var countries []string
102
103 if err := func() error {
104 rows, err := tx.Query(selectStretchCountriesSQL, id)
105 if err != nil {
106 return err
107 }
108 defer rows.Close()
109
110 for rows.Next() {
111 var country string
112 if err := rows.Scan(&country); err != nil {
113 return err
114 }
115 countries = append(countries, country)
116 }
117
118 return rows.Err()
119 }(); err != nil {
120 http.Error(
121 rw, fmt.Sprintf("DB error: %v.", err),
122 http.StatusInternalServerError)
123 return
124 }
125
126 var geom wkb.MultiPolygonGeom
127
128 if err := geom.FromWKB(data); err != nil {
129 http.Error(
130 rw, fmt.Sprintf("Decoding WKB error: %v.", err),
131 http.StatusInternalServerError)
132 return
133 }
134
135 tmp := config.TmpDir()
136
137 dir, err := ioutil.TempDir(tmp, "stretch-download")
138 if err != nil {
139 http.Error(
140 rw, fmt.Sprintf("Cannot create temp dir: %v.", err),
141 http.StatusInternalServerError)
142 return
143 }
144 defer os.RemoveAll(dir)
145
146 shpDir := filepath.Join(dir, "stretch")
147
148 if err := os.Mkdir(shpDir, os.ModePerm); err != nil {
149 http.Error(
150 rw, fmt.Sprintf("Cannot create temp dir: %v.", err),
151 http.StatusInternalServerError)
152 return
153 }
154
155 filename := filepath.Join(shpDir, "stretch")
156
157 if err := func() error {
158 writer, err := shp.Create(filename, shp.POLYGON)
159 if err != nil {
160 return err
161 }
162 defer writer.Close()
163
164 // TODO: Write geometry
165
166 return nil
167 }(); err != nil {
168 http.Error(
169 rw, fmt.Sprintf("creating shapefile failed: %v.", err),
170 http.StatusInternalServerError)
171 return
172 }
173
174 entries, err := func() ([]os.FileInfo, error) {
175 f, err := os.Open(shpDir)
176 if err != nil {
177 return nil, err
178 }
179 defer f.Close()
180 return f.Readdir(-1)
181 }()
182 if err != nil {
183 http.Error(
184 rw, fmt.Sprintf("cannot read directory: %v.", err),
185 http.StatusInternalServerError)
186 return
187 }
188
189 rw.Header().Set("Content-Type", "application/zip")
190 rw.Header().Set("Content-Disposition", `attachment; filename="stretch.zip"`)
191
192 zipfile := zip.NewWriter(rw)
193 defer zipfile.Close()
194
195 now := time.Now()
196
197 base := filepath.Base(shpDir)
198 for _, info := range entries {
199 if !info.Mode().IsRegular() {
200 continue
201 }
202 if err := func() error {
203 srcFile, err := os.Open(filepath.Join(shpDir, info.Name()))
204 if err != nil {
205 return err
206 }
207 defer srcFile.Close()
208 header := &zip.FileHeader{
209 Name: base + "/" + info.Name(),
210 Method: zip.Deflate,
211 Modified: now,
212 }
213 out, err := zipfile.CreateHeader(header)
214 if err != nil {
215 return err
216 }
217 _, err = io.Copy(out, srcFile)
218 return err
219 }(); err != nil {
220 log.Printf("error: cannot write file: %v\n", err)
221 return
222 }
223 }
224 }