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