Mercurial > gemma
changeset 1338:5bb1e3c1f364
merges
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Mon, 26 Nov 2018 09:01:21 +0100 |
parents | 53057ab27ff2 (current diff) 813342f2e927 (diff) |
children | 1d1fc92fc3ea 3fee649d3d5d |
files | pkg/controllers/search.go pkg/imports/sr.go schema/gemma.sql schema/install-db.sh schema/manage_users.sql schema/std_login_roles.sql |
diffstat | 41 files changed, 341 insertions(+), 218 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/map/Main.vue Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/components/map/Main.vue Mon Nov 26 09:01:21 2018 +0100 @@ -1,10 +1,8 @@ <template> <div class="main d-flex flex-column"> - <Maplayer :split="showSplitscreen" :lat="6155376" :long="1819178" :zoom="11"></Maplayer> + <Maplayer :split="showSplitscreen"></Maplayer> <FairwayProfile :additionalSurveys="additionalSurveys" - :height="height" - :width="width" :xScale="xAxis" :yScaleLeft="yAxisLeft" :yScaleRight="yAxisRight" @@ -32,7 +30,6 @@ import Maplayer from "./Maplayer"; import FairwayProfile from "./fairway/Fairwayprofile"; import { mapState } from "vuex"; -import debounce from "debounce"; export default { name: "mainview", @@ -97,30 +94,6 @@ y: this.totalLength }; } - }, - created() { - window.addEventListener("resize", debounce(this.scaleFairwayProfile), 100); - window.addEventListener("onbeforeprint", this.test); - }, - updated() { - this.scaleFairwayProfile(); - }, - destroyed() { - window.removeEventListener("resize", debounce(this.scaleFairwayProfile)); - }, - methods: { - test(evt) { - console.log("test: ", evt); - }, - scaleFairwayProfile() { - if (!document.querySelector(".fairwayprofile")) return; - const clientHeight = document.querySelector(".fairwayprofile") - .clientHeight; - const clientWidth = document.querySelector(".fairwayprofile").clientWidth; - if (!clientHeight || !clientWidth) return; - this.height = clientHeight; - this.width = clientWidth; - } } }; </script>
--- a/client/src/components/map/Maplayer.vue Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/components/map/Maplayer.vue Mon Nov 26 09:01:21 2018 +0100 @@ -50,7 +50,7 @@ /* eslint-disable no-console */ export default { name: "maplayer", - props: ["lat", "long", "zoom", "split"], + props: ["split"], data() { return { projection: "EPSG:3857" @@ -59,6 +59,7 @@ computed: { ...mapGetters("map", ["getLayerByName"]), ...mapState("map", [ + "extent", "layers", "openLayersMap", "lineTool", @@ -261,11 +262,19 @@ target: "map", controls: [], view: new View({ - center: [this.long, this.lat], - zoom: this.zoom, + center: [this.extent.lon, this.extent.lat], + zoom: this.extent.zoom, projection: this.projection }) }); + map.on("moveend", event => { + const center = event.map.getView().getCenter(); + this.$store.commit("map/extent", { + lat: center[1], + lon: center[0], + zoom: event.map.getView().getZoom() + }); + }); this.$store.dispatch("map/openLayersMap", map); // TODO make display of layers more dynamic, e.g. from a list
--- a/client/src/components/map/contextbox/ImportSoundingresults.vue Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/components/map/contextbox/ImportSoundingresults.vue Mon Nov 26 09:01:21 2018 +0100 @@ -1,8 +1,7 @@ <template> <div> <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> - <font-awesome-icon icon="upload" class="mr-2"></font-awesome-icon> - Import Soundingresults + <font-awesome-icon icon="upload" class="mr-2"></font-awesome-icon>Import Soundingresults </h6> <div v-if="editState" class="ml-auto mr-auto mt-4 w-95"> <div class="d-flex flex-row input-group mb-4"> @@ -195,9 +194,12 @@ confirm() { let formData = new FormData(); formData.append("token", this.token); - ["bottleneck", "importDate", "depthReference"].forEach(x => { - if (this[x]) formData.append(x, this[x]); - }); + if (this.bottleneck) formData.append("bottleneck", this.bottleneck); + if (this.importDate) + formData.append("date", this.importDate.split("T")[0]); + if (this.depthReference) + formData.append("depth-reference", this.depthReference); + HTTP.post("/imports/soundingresult", formData, { headers: { "X-Gemma-Auth": localStorage.getItem("token"),
--- a/client/src/components/map/contextbox/Staging.vue Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/components/map/contextbox/Staging.vue Mon Nov 26 09:01:21 2018 +0100 @@ -1,8 +1,7 @@ <template> <div class="w-90"> <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> - <font-awesome-icon icon="clipboard-check" class="mr-2"></font-awesome-icon> - Staging Area + <font-awesome-icon icon="clipboard-check" class="mr-2"></font-awesome-icon>Staging Area </h6> <table class="table mb-0"> <thead> @@ -48,7 +47,7 @@ </tbody> </table> <div class="p-3" v-if="filteredData.length"> - <button class="btn btn-info">Confirm</button> + <button @click="confirmReview" class="btn btn-info">Confirm</button> </div> </div> </template> @@ -69,6 +68,8 @@ */ import { mapState } from "vuex"; +import { displayError, displayInfo } from "../../../lib/errors.js"; + export default { STATES: { NEEDSAPPROVAL: "NEEDSAPPROVAL", @@ -117,6 +118,15 @@ ] }; }, + mounted() { + this.$store.dispatch("imports/getStaging").catch(error => { + const { status, data } = error.response; + displayError({ + title: "Backend Error", + message: `${status}: ${data.message || data}` + }); + }); + }, computed: { ...mapState("application", ["searchQuery"]), filteredData() { @@ -155,6 +165,17 @@ } }, methods: { + confirmReview() { + const message = this.demodata + .map(x => { + return x.name + ": " + x.status; + }) + .join("\n"); + displayInfo({ + title: "Staging Area", + message: message + }); + }, needsApproval(item) { return item.status === this.$options.STATES.NEEDSAPPROVAL; },
--- a/client/src/components/map/fairway/Fairwayprofile.vue Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/components/map/fairway/Fairwayprofile.vue Mon Nov 26 09:01:21 2018 +0100 @@ -155,27 +155,22 @@ import { displayError, displayInfo } from "../../../lib/errors.js"; import Feature from "ol/Feature"; import LineString from "ol/geom/LineString"; +import debounce from "debounce"; const GROUND_COLOR = "#4A2F06"; export default { name: "fairwayprofile", - props: [ - "width", - "height", - "xScale", - "yScaleLeft", - "yScaleRight", - "margin", - "additionalSurveys" - ], + props: ["xScale", "yScaleLeft", "yScaleRight", "margin", "additionalSurveys"], data() { return { wait: false, coordinatesInput: "", coordinatesSelect: null, cutLabel: "", - showLabelInput: false + showLabelInput: false, + width: null, + height: null }; }, computed: { @@ -304,6 +299,7 @@ this.coordinatesSelect = null; const chartDiv = document.querySelector(".fairwayprofile"); d3.select(".fairwayprofile svg").remove(); + this.scaleFairwayProfile(); let svg = d3.select(chartDiv).append("svg"); svg.attr("width", this.width); svg.attr("height", this.height); @@ -514,6 +510,15 @@ .attr("d", profileLine); } }, + scaleFairwayProfile() { + if (!document.querySelector(".fairwayprofile")) return; + const clientHeight = document.querySelector(".fairwayprofile") + .clientHeight; + const clientWidth = document.querySelector(".fairwayprofile").clientWidth; + if (!clientHeight || !clientWidth) return; + this.height = clientHeight; + this.width = clientWidth; + }, onCopyCoordinates() { displayInfo({ title: "Success", @@ -580,8 +585,17 @@ }); } }, + created() { + window.addEventListener("resize", debounce(this.drawDiagram), 100); + }, mounted() { this.drawDiagram(); + }, + updated() { + this.scaleFairwayProfile(); + }, + destroyed() { + window.removeEventListener("resize", debounce(this.drawDiagram)); } }; </script>
--- a/client/src/store/imports.js Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/store/imports.js Mon Nov 26 09:01:21 2018 +0100 @@ -15,10 +15,19 @@ import { HTTP } from "../lib/http"; +/* eslint-disable no-unused-vars */ +/* eslint-disable no-unreachable */ +const STATES = { + NEEDSAPPROVAL: "NEEDSAPPROVAL", + APPROVED: "APPROVED", + REJECTED: "REJECTED" +}; + // initial state const init = () => { return { - imports: {} + imports: [], + staging: [] }; }; @@ -29,6 +38,22 @@ mutations: { setImports: (state, imports) => { state.imports = imports; + }, + setStaging: (state, staging) => { + state.staging = staging; + }, + + toggleApproval: (state, change) => { + throw "Not implemented!"; + const { id, newState } = change; + const stagedResult = this.state.staging.find(e => { + return e.id === id; + }); + if (stagedResult.status === newState) { + stagedResult.status = this.$options.STATES.NEEDSAPPROVAL; + } else { + stagedResult.status = newState; + } } }, actions: { @@ -45,6 +70,35 @@ reject(error); }); }); + }, + getStaging({ commit }) { + return new Promise((resolve, reject) => { + HTTP.get("/imports?states=pending", { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + commit("setStaging", response.data.imports); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + }, + setStaging({ commit }, results) { + return new Promise((resolve, reject) => { + throw "Not implemented!"; + HTTP.get("/imports?states=pending", { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + commit("setStaging", response.data.imports); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); } } };
--- a/client/src/store/map.js Fri Nov 23 15:46:07 2018 +0100 +++ b/client/src/store/map.js Mon Nov 26 09:01:21 2018 +0100 @@ -31,6 +31,11 @@ const init = () => { return { openLayersMap: null, + extent: { + lat: 6155376, + lon: 1819178, + zoom: 11 + }, identifiedFeatures: [], // map features identified by clicking on the map currentMeasurement: null, // distance or area from line-/polygon-/cutTool lineTool: null, // open layers interaction object (Draw) @@ -347,6 +352,9 @@ } }, mutations: { + extent: (state, extent) => { + state.extent = extent; + }, toggleVisibility: (state, layer) => { state.layers[layer].isVisible = !state.layers[layer].isVisible; state.layers[layer].data.setVisible(state.layers[layer].isVisible);
--- a/pkg/auth/middleware.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/auth/middleware.go Mon Nov 26 09:01:21 2018 +0100 @@ -65,8 +65,7 @@ func SessionChecker(next http.Handler, check func(*Session) bool) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - claims, ok := GetSession(req) - if !ok || !check(claims) { + if claims, ok := GetSession(req); !ok || !check(claims) { http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return }
--- a/pkg/auth/opendb.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/auth/opendb.go Mon Nov 26 09:01:21 2018 +0100 @@ -126,7 +126,7 @@ return roles, rows.Err() } -func RunAs(role string, ctx context.Context, fn func(*sql.Conn) error) error { +func RunAs(ctx context.Context, role string, fn func(*sql.Conn) error) error { conn, err := MetamorphConn(ctx, role) if err != nil { return err @@ -144,5 +144,5 @@ if session == nil { return ErrNotLoggedIn } - return RunAs(session.User, req.Context(), fn) + return RunAs(req.Context(), session.User, fn) }
--- a/pkg/auth/session.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/auth/session.go Mon Nov 26 09:01:21 2018 +0100 @@ -76,7 +76,7 @@ return err } - wr := misc.BinWriter{w, nil} + wr := misc.BinWriter{Writer: w, Err: nil} wr.WriteBin(s.ExpiresAt) wr.WriteString(s.User) wr.WriteBin(uint32(len(s.Roles))) @@ -90,17 +90,15 @@ func (s *Session) deserialize(r io.Reader) error { - var session Session - var n uint32 - rd := misc.BinReader{r, nil} - rd.ReadBin(&session.ExpiresAt) - rd.ReadString(&session.User) + rd := misc.BinReader{Reader: r, Err: nil} + rd.ReadBin(&s.ExpiresAt) + rd.ReadString(&s.User) rd.ReadBin(&n) - session.Roles = make(Roles, n) + s.Roles = make(Roles, n) for i := uint32(0); n > 0 && i < n; i++ { - rd.ReadString(&session.Roles[i]) + rd.ReadString(&s.Roles[i]) } if rd.Err != nil { @@ -121,23 +119,21 @@ return err } - session.access = t - - *s = session + s.access = t return nil } -func (c *Session) touch() { - c.mu.Lock() - c.access = time.Now() - c.mu.Unlock() +func (s *Session) touch() { + s.mu.Lock() + s.access = time.Now() + s.mu.Unlock() } -func (c *Session) last() time.Time { - c.mu.Lock() - access := c.access - c.mu.Unlock() +func (s *Session) last() time.Time { + s.mu.Lock() + access := s.access + s.mu.Unlock() return access }
--- a/pkg/common/random.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/common/random.go Mon Nov 26 09:01:21 2018 +0100 @@ -51,7 +51,7 @@ out[i] = alphabet[v.Int64()] } // Ensure at least one special char. - if bytes.IndexAny(out, special) >= 0 { + if bytes.ContainsAny(out, special) { return string(out) } }
--- a/pkg/config/config.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/config/config.go Mon Nov 26 09:01:21 2018 +0100 @@ -10,6 +10,7 @@ // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> +// * Bernhard E. Reiter <bernhard.reiter@intevation.de> package config @@ -29,8 +30,6 @@ // This is not part of the persistent config. var configFile string -func ConfigFile() string { return configFile } - func DBHost() string { return viper.GetString("db-host") } func DBPort() uint { return uint(viper.GetInt32("db-port")) } func DBName() string { return viper.GetString("db-name") }
--- a/pkg/controllers/cross.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/cross.go Mon Nov 26 09:01:21 2018 +0100 @@ -28,16 +28,17 @@ const WGS84 = 4326 func reproject( + ctx context.Context, rp *models.Reprojector, src models.GeoJSONLineCoordinates, - ctx context.Context, ) (models.GeoJSONLineCoordinates, error) { dst := make(models.GeoJSONLineCoordinates, len(src)) for i, s := range src { var err error if dst[i].Lat, dst[i].Lon, err = rp.Reproject( - s.Lat, s.Lon, ctx, + ctx, + s.Lat, s.Lon, ); err != nil { return nil, err } @@ -50,10 +51,10 @@ ST_Transform(ST_GeomFromWKB($2, $1::integer), 4326))` func projectBack( + ctx context.Context, line octree.MultiLineStringZ, epsg uint32, conn *sql.Conn, - ctx context.Context, ) (models.GeoJSONMultiLineCoordinatesZ, error) { var mls models.GeoJSONMultiLineCoordinatesZ @@ -74,10 +75,11 @@ csi := input.(*models.CrossSectionInput) start := time.Now() + ctx := req.Context() - tree, err := octree.Cache.Get( - csi.Properties.Bottleneck, csi.Properties.Date.Time, - conn, req.Context()) + tree, err := octree.FromCache( + ctx, conn, + csi.Properties.Bottleneck, csi.Properties.Date.Time) log.Printf("loading octree took: %s\n", time.Since(start)) if err != nil { @@ -102,14 +104,14 @@ var rp *models.Reprojector if rp, err = models.NewReprojector( - conn, req.Context(), + ctx, conn, WGS84, tree.EPSG, ); err != nil { return } defer rp.Close() - coords, err := reproject(rp, csi.Geometry.Coordinates, req.Context()) + coords, err := reproject(ctx, rp, csi.Geometry.Coordinates) log.Printf("transforming input coords took: %s\n", time.Since(start)) if err != nil { @@ -149,8 +151,9 @@ var joined models.GeoJSONMultiLineCoordinatesZ joined, err = projectBack( + ctx, segments, tree.EPSG, - conn, req.Context(), + conn, ) log.Printf("projecting back took: %s\n", time.Since(start))
--- a/pkg/controllers/importqueue.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/importqueue.go Mon Nov 26 09:01:21 2018 +0100 @@ -14,7 +14,6 @@ package controllers import ( - "context" "database/sql" "fmt" "log" @@ -91,8 +90,7 @@ func queryImportListStmt( conn *sql.Conn, - ctx context.Context, - vars map[string]string, + req *http.Request, ) (*sql.Rows, error) { var ( @@ -102,11 +100,16 @@ kinds *pgtype.TextArray ) - if st, found := vars["states"]; found { + arg := func(format string, v interface{}) { + fmt.Fprintf(&stmt, format, len(args)+1) + args = append(args, v) + } + + if st := req.FormValue("states"); st != "" { states = toTextArray(st, imports.ImportStateNames) } - if ks, found := vars["kinds"]; found { + if ks := req.FormValue("kinds"); ks != "" { kinds = toTextArray(ks, imports.ImportKindNames) } @@ -116,8 +119,7 @@ } if states != nil { - fmt.Fprintf(&stmt, " states = ANY($%d) ", len(args)+1) - args = append(args, states) + arg(" state = ANY($%d) ", states) } if states != nil && kinds != nil { @@ -125,25 +127,28 @@ } if kinds != nil { - fmt.Fprintf(&stmt, " kind = ANY($%d) ", len(args)+1) - args = append(args, kinds) + arg(" kind = ANY($%d) ", kinds) } stmt.WriteString(" ORDER BY enqueued DESC ") - if lim, found := vars["limit"]; found { - fmt.Fprintf(&stmt, " LIMIT $%d ", len(args)+1) - limit, _ := strconv.ParseInt(lim, 10, 64) - args = append(args, limit) + if lim := req.FormValue("limit"); lim != "" { + limit, err := strconv.ParseInt(lim, 10, 64) + if err != nil { + return nil, err + } + arg(" LIMIT $%d ", limit) } - if ofs, found := vars["offset"]; found { - fmt.Fprintf(&stmt, " OFFSET $%d ", len(args)+1) - offset, _ := strconv.ParseInt(ofs, 10, 64) - args = append(args, offset) + if ofs := req.FormValue("offset"); ofs != "" { + offset, err := strconv.ParseInt(ofs, 10, 64) + if err != nil { + return nil, err + } + arg(" OFFSET $%d ", offset) } - return conn.QueryContext(ctx, stmt.String(), args...) + return conn.QueryContext(req.Context(), stmt.String(), args...) } func listImports( @@ -153,7 +158,7 @@ ) (jr JSONResult, err error) { var rows *sql.Rows - rows, err = queryImportListStmt(conn, req.Context(), mux.Vars(req)) + rows, err = queryImportListStmt(conn, req) if err != nil { return } @@ -357,7 +362,7 @@ if state == "accepted" { if jc := imports.FindJobCreator(imports.JobKind(kind)); jc != nil { - if err = jc.StageDone(tx, ctx, id); err != nil { + if err = jc.StageDone(ctx, tx, id); err != nil { return } }
--- a/pkg/controllers/json.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/json.go Mon Nov 26 09:01:21 2018 +0100 @@ -63,7 +63,7 @@ if token, ok := auth.GetToken(req); ok && !j.NoConn { if session := auth.Sessions.Session(token); session != nil { - err = auth.RunAs(session.User, req.Context(), func(conn *sql.Conn) error { + err = auth.RunAs(req.Context(), session.User, func(conn *sql.Conn) error { jr, err = j.Handle(input, req, conn) return err })
--- a/pkg/controllers/proxy.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/proxy.go Mon Nov 26 09:01:21 2018 +0100 @@ -203,6 +203,7 @@ "text/xml", "application/gml+xml", "application/vnd.ogc.wms_xml", + "application/vnd.ogc.se_xml", } func isXML(h http.Header) bool {
--- a/pkg/controllers/pwreset.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/pwreset.go Mon Nov 26 09:01:21 2018 +0100 @@ -11,6 +11,7 @@ // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> // * Bernhard E. Reiter <bernhard.reiter@intevation.de> +// * Tom Gottfried <tom.gottfried.intevation.de> package controllers @@ -121,12 +122,13 @@ config.WaitReady() for { time.Sleep(cleanupPause) + ctx := context.Background() err := auth.RunAs( - pwResetRole, context.Background(), + ctx, pwResetRole, func(conn *sql.Conn) error { good := time.Now().Add(-passwordResetValid) _, err := conn.ExecContext( - context.Background(), cleanupRequestsSQL, good) + ctx, cleanupRequestsSQL, good) return err }) if err != nil { @@ -207,7 +209,7 @@ ctx := context.Background() if err := auth.RunAs( - pwResetRole, ctx, + ctx, pwResetRole, func(conn *sql.Conn) error { var count int64 @@ -303,7 +305,7 @@ ctx := req.Context() if err = auth.RunAs( - pwResetRole, ctx, func(conn *sql.Conn) error { + ctx, pwResetRole, func(conn *sql.Conn) error { err := conn.QueryRowContext(ctx, findRequestSQL, hash).Scan(&email, &user) switch { case err == sql.ErrNoRows:
--- a/pkg/controllers/routes.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/routes.go Mon Nov 26 09:01:21 2018 +0100 @@ -176,14 +176,7 @@ }) api.Handle("/imports", lsImports). - Methods(http.MethodGet). - Queries( - "offset", "{offset:[0-9]+}", - "limit", "{limit:[0-9]+}", - "states", "", - "kinds", "") - - api.Handle("/imports", lsImports).Methods(http.MethodGet) + Methods(http.MethodGet) api.Handle("/imports/{id:[0-9]+}", waterwayAdmin(&JSONHandler{ Handle: importLogs,
--- a/pkg/controllers/srimports.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/srimports.go Mon Nov 26 09:01:21 2018 +0100 @@ -120,7 +120,7 @@ if err != nil { return err } - sr.Date = &models.SoundingResultDate{date} + sr.Date = &models.SoundingResultDate{Time: date} } if v := req.FormValue("depth-reference"); v != "" { @@ -229,7 +229,7 @@ messages = append(messages, fmt.Sprintf("'meta.json' found but invalid: %v", err)) } else { - errs := meta.Validate(conn, req.Context()) + errs := meta.Validate(req.Context(), conn) for _, err := range errs { messages = append(messages, fmt.Sprintf("invalid 'meta.json': %v", err))
--- a/pkg/controllers/surveys.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/surveys.go Mon Nov 26 09:01:21 2018 +0100 @@ -10,6 +10,7 @@ // // Author(s): // * Sascha Wilde <sascha.wilde@intevation.de> +// * Sascha L. Teichmann <sascha.teichmann@intevation.de> package controllers @@ -49,7 +50,7 @@ for rows.Next() { var survey models.Survey if err = rows.Scan( - &survey.BottleneckId, + &survey.BottleneckID, &survey.DateInfo, ); err != nil { return
--- a/pkg/controllers/user.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/controllers/user.go Mon Nov 26 09:01:21 2018 +0100 @@ -11,6 +11,7 @@ // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> // * Tom Gottfried <tom.gottfried@intevation.de> +// * Sascha Wilde <sascha.wilde@intevation.de> package controllers
--- a/pkg/geoserver/boot.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/geoserver/boot.go Mon Nov 26 09:01:21 2018 +0100 @@ -371,9 +371,8 @@ defer resp.Body.Close() // Fetch all styles - if err := json.NewDecoder(resp.Body).Decode(s); err != nil { - // XXX: Same quirk as with featuretypes. - } + // XXX: Avoid error checking due to quirks with featuretypes. + json.NewDecoder(resp.Body).Decode(s) return nil }
--- a/pkg/imports/queue.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/imports/queue.go Mon Nov 26 09:01:21 2018 +0100 @@ -36,7 +36,7 @@ } Job interface { - Do(int64, context.Context, *sql.Conn, Feedback) error + Do(context.Context, int64, *sql.Conn, Feedback) error CleanUp() error } @@ -45,7 +45,7 @@ JobCreator interface { Create(kind JobKind, data string) (Job, error) Depends() []string - StageDone(*sql.Tx, context.Context, int64) error + StageDone(context.Context, *sql.Tx, int64) error } idJob struct { @@ -160,7 +160,7 @@ func (q *importQueue) addJob(kind JobKind, user, data string) (int64, error) { ctx := context.Background() var id int64 - err := auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + err := auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { return conn.QueryRowContext(ctx, insertJobSQL, string(kind), user, data).Scan(&id) }) if err == nil { @@ -180,7 +180,7 @@ func (lf logFeedback) log(kind, format string, args ...interface{}) { ctx := context.Background() - err := auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + err := auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { _, err := conn.ExecContext( ctx, logMessageSQL, int64(lf), kind, fmt.Sprintf(format, args...)) return err @@ -215,7 +215,7 @@ func reEnqueueRunning() error { ctx := context.Background() - return auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + return auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { _, err := conn.ExecContext(ctx, reEnqueueRunningSQL) return err }) @@ -248,7 +248,7 @@ var ji idJob ctx := context.Background() - err := auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + err := auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { tx, err := conn.BeginTx(ctx, nil) if err != nil { return err @@ -275,7 +275,7 @@ func updateState(id int64, state string) error { ctx := context.Background() - return auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + return auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { _, err := conn.ExecContext(ctx, updateStateSQL, state, id) return err }) @@ -283,7 +283,7 @@ func errorAndFail(id int64, format string, args ...interface{}) error { ctx := context.Background() - err := auth.RunAs(queueUser, ctx, func(conn *sql.Conn) error { + err := auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error { tx, err := conn.BeginTx(ctx, nil) if err != nil { return err @@ -372,9 +372,9 @@ errDo := survive(func() error { ctx := context.Background() - return auth.RunAs(idj.user, ctx, + return auth.RunAs(ctx, idj.user, func(conn *sql.Conn) error { - return job.Do(idj.id, ctx, conn, feedback) + return job.Do(ctx, idj.id, conn, feedback) }) })() if errDo != nil {
--- a/pkg/imports/sr.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/imports/sr.go Mon Nov 26 09:01:21 2018 +0100 @@ -80,8 +80,8 @@ } func (srJobCreator) StageDone( + ctx context.Context, tx *sql.Tx, - ctx context.Context, id int64, ) error { _, err := tx.ExecContext(ctx, srStageDoneSQL, id) @@ -165,8 +165,8 @@ } func (sr *SoundingResult) Do( + ctx context.Context, importID int64, - ctx context.Context, conn *sql.Conn, feedback Feedback, ) error { @@ -188,7 +188,7 @@ return err } - if err := m.Validate(conn, ctx); err != nil { + if err := m.Validate(ctx, conn); err != nil { return common.ToError(err) } @@ -204,7 +204,7 @@ } if len(xyz) == 0 { - return errors.New("XYZ does not contain any vertices.") + return errors.New("XYZ does not contain any vertices") } // Is there a boundary shapefile in the ZIP archive? @@ -241,7 +241,7 @@ feedback.Info("Triangulate...") start = time.Now() - tin, err := octree.GenerateTinByID(conn, ctx, id, epsg) + tin, err := octree.GenerateTinByID(ctx, conn, id, epsg) feedback.Info("triangulation took %s", time.Since(start)) if err != nil { return err @@ -285,7 +285,7 @@ } // Store for potential later removal. - if err = track(tx, ctx, importID, "waterway.sounding_results", id); err != nil { + if err = track(ctx, tx, importID, "waterway.sounding_results", id); err != nil { return err }
--- a/pkg/imports/track.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/imports/track.go Mon Nov 26 09:01:21 2018 +0100 @@ -24,7 +24,7 @@ VALUES ($1, $2::regclass, $3)` ) -func track(tx *sql.Tx, ctx context.Context, importID int64, relation string, key int64) error { +func track(ctx context.Context, tx *sql.Tx, importID int64, relation string, key int64) error { _, err := tx.ExecContext(ctx, trackImportSQL, importID, relation, key) return err }
--- a/pkg/models/cross.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/cross.go Mon Nov 26 09:01:21 2018 +0100 @@ -246,14 +246,6 @@ math.Abs(cz.Z-other.Z) < zEps } -func (cz GeoJSONCoordinateZ) mid(other GeoJSONCoordinateZ) GeoJSONCoordinateZ { - return GeoJSONCoordinateZ{ - Lon: (cz.Lon + other.Lon) * 0.5, - Lat: (cz.Lat + other.Lat) * 0.5, - Z: (cz.Z + other.Z) * 0.5, - } -} - func deg2rad(d float64) float64 { return d * math.Pi / 180.0 } func (cz GeoJSONCoordinateZ) Distance(other GeoJSONCoordinateZ) float64 {
--- a/pkg/models/extservices.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/extservices.go Mon Nov 26 09:01:21 2018 +0100 @@ -61,7 +61,7 @@ func (es *ExtServices) load() error { // make empty slice to prevent retry if slice is empty. es.entries = []ExtEntry{} - return auth.RunAs("sys_admin", context.Background(), + return auth.RunAs(context.Background(), "sys_admin", func(conn *sql.Conn) error { rows, err := conn.QueryContext( context.Background(), selectExternalServices)
--- a/pkg/models/intservices.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/intservices.go Mon Nov 26 09:01:21 2018 +0100 @@ -59,10 +59,11 @@ func (e *IntEntry) LoadStyle() (string, error) { var style string - err := auth.RunAs("sys_admin", context.Background(), + ctx := context.Background() + err := auth.RunAs(ctx, "sys_admin", func(conn *sql.Conn) error { return conn.QueryRowContext( - context.Background(), + ctx, selectStyleSQL, e.Name).Scan(&style) }) @@ -119,10 +120,11 @@ func (ps *IntServices) load() error { // make empty slice to prevent retry if slice is empty. ps.entries = []IntEntry{} - return auth.RunAs("sys_admin", context.Background(), + ctx := context.Background() + return auth.RunAs(ctx, "sys_admin", func(conn *sql.Conn) error { rows, err := conn.QueryContext( - context.Background(), selectServicesSQL) + ctx, selectServicesSQL) if err != nil { return err }
--- a/pkg/models/reproject.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/reproject.go Mon Nov 26 09:01:21 2018 +0100 @@ -29,8 +29,8 @@ } func NewReprojector( + ctx context.Context, conn *sql.Conn, - ctx context.Context, fromEPSG, toEPSG uint32, ) (*Reprojector, error) { stmt, err := conn.PrepareContext(ctx, reprojectSQL) @@ -53,8 +53,8 @@ } func (r *Reprojector) Reproject( + ctx context.Context, x, y float64, - ctx context.Context, ) (v, w float64, err error) { err = r.stmt.QueryRowContext(ctx, x, y, r.FromEPSG, r.ToEPSG).Scan(&v, &w) return
--- a/pkg/models/sr.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/sr.go Mon Nov 26 09:01:21 2018 +0100 @@ -73,7 +73,7 @@ return err } -func (m *SoundingResultMeta) Validate(conn *sql.Conn, ctx context.Context) []error { +func (m *SoundingResultMeta) Validate(ctx context.Context, conn *sql.Conn) []error { var errs []error @@ -83,11 +83,11 @@ m.DepthReference).Scan(&b) switch { case err == sql.ErrNoRows: - errs = append(errs, fmt.Errorf("Unknown depth reference '%s'\n", m.DepthReference)) + errs = append(errs, fmt.Errorf("unknown depth reference '%s'", m.DepthReference)) case err != nil: errs = append(errs, err) case !b: - errs = append(errs, errors.New("Unexpected depth reference")) + errs = append(errs, errors.New("unexpected depth reference")) } err = conn.QueryRowContext(ctx, @@ -95,11 +95,11 @@ m.Bottleneck).Scan(&b) switch { case err == sql.ErrNoRows: - errs = append(errs, fmt.Errorf("Unknown bottleneck '%s'\n", m.Bottleneck)) + errs = append(errs, fmt.Errorf("unknown bottleneck '%s'", m.Bottleneck)) case err != nil: errs = append(errs, err) case !b: - errs = append(errs, errors.New("Unexpected bottleneck")) + errs = append(errs, errors.New("unexpected bottleneck")) } err = conn.QueryRowContext(ctx, @@ -111,7 +111,7 @@ errs = append(errs, err) case b: errs = append(errs, - errors.New("Sounding result for this date already exists.")) + errors.New("sounding result for this date already exists")) } return errs
--- a/pkg/models/surveys.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/models/surveys.go Mon Nov 26 09:01:21 2018 +0100 @@ -15,7 +15,7 @@ type ( Survey struct { - BottleneckId string `json:"bottleneck_id"` + BottleneckID string `json:"bottleneck_id"` DateInfo string `json:"date_info"` } )
--- a/pkg/octree/builder.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/octree/builder.go Mon Nov 26 09:01:21 2018 +0100 @@ -173,7 +173,7 @@ return nil } -func (tb *Builder) WriteTo(w io.Writer) error { +func (tb *Builder) writeTo(w io.Writer) error { out := snappy.NewBufferedWriter(w) if err := tb.t.Serialize(out); err != nil { return err @@ -186,7 +186,7 @@ func (tb *Builder) Bytes() ([]byte, error) { var buf bytes.Buffer - if err := tb.WriteTo(&buf); err != nil { + if err := tb.writeTo(&buf); err != nil { return nil, err } return buf.Bytes(), nil
--- a/pkg/octree/cache.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/octree/cache.go Mon Nov 26 09:01:21 2018 +0100 @@ -31,7 +31,7 @@ tree *Tree access time.Time } - OctreeCache struct { + Cache struct { sync.Mutex entries map[cacheKey]*cacheEntry } @@ -61,41 +61,50 @@ ` ) -var Cache = OctreeCache{ +var cache = Cache{ entries: map[cacheKey]*cacheEntry{}, } func init() { - go Cache.background() + go cache.background() } -func (oc *OctreeCache) background() { +func (c *Cache) background() { for { time.Sleep(cleanupCacheSleep) - oc.cleanup() + c.cleanup() } } -func (oc *OctreeCache) cleanup() { - oc.Lock() - defer oc.Unlock() +func (c *Cache) cleanup() { + c.Lock() + defer c.Unlock() good := time.Now().Add(-maxCacheAge) - for k, v := range oc.entries { + for k, v := range c.entries { if v.access.Before(good) { - delete(oc.entries, k) + delete(c.entries, k) } } } -func (oc *OctreeCache) Get( +func FromCache( + ctx context.Context, + conn *sql.Conn, bottleneck string, date time.Time, - conn *sql.Conn, ctx context.Context, ) (*Tree, error) { - oc.Lock() - defer oc.Unlock() + return cache.get(ctx, conn, bottleneck, date) +} + +func (c *Cache) get( + ctx context.Context, + conn *sql.Conn, + bottleneck string, date time.Time, +) (*Tree, error) { + c.Lock() + defer c.Unlock() key := cacheKey{date, bottleneck} - entry := oc.entries[key] + entry := c.entries[key] var data []byte var checksum string @@ -139,21 +148,21 @@ return tree, nil } - for len(oc.entries) >= maxCacheEntries { + for len(c.entries) >= maxCacheEntries { // Evict the entry that is accessed the longest time ago. var oldestKey cacheKey oldest := now - for k, v := range oc.entries { + for k, v := range c.entries { if v.access.Before(oldest) { oldest = v.access oldestKey = k } } - delete(oc.entries, oldestKey) + delete(c.entries, oldestKey) } - oc.entries[key] = &cacheEntry{ + c.entries[key] = &cacheEntry{ checksum: checksum, tree: tree, access: now,
--- a/pkg/octree/contours.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/octree/contours.go Mon Nov 26 09:01:21 2018 +0100 @@ -10,6 +10,7 @@ // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> +// * Tom Gottfried <tom.gottfried@intevation.de> package octree
--- a/pkg/octree/tin.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/octree/tin.go Mon Nov 26 09:01:21 2018 +0100 @@ -23,7 +23,6 @@ "io" "log" "math" - "time" ) var ( @@ -199,32 +198,12 @@ SELECT ST_AsBinary(ST_Collect(triangles.geom)) FROM triangles, trans WHERE ST_Covers(trans.area, triangles.poly)` - loadTinSQL = tinSQLPrefix + `WHERE bottleneck_id = $2 AND date_info = $3` + tinSQLSuffix loadTinByIDSQL = tinSQLPrefix + `WHERE id = $2` + tinSQLSuffix ) -func GenerateTin( - conn *sql.Conn, +func GenerateTinByID( ctx context.Context, - bottleneck string, - date time.Time, - epsg uint32, -) (*Tin, error) { - var tin Tin - err := conn.QueryRowContext(ctx, loadTinSQL, epsg, bottleneck, date).Scan(&tin) - switch { - case err == sql.ErrNoRows: - return nil, nil - case err != nil: - return nil, err - } - tin.EPSG = epsg - return &tin, nil -} - -func GenerateTinByID( conn *sql.Conn, - ctx context.Context, id int64, epsg uint32, ) (*Tin, error) {
--- a/pkg/octree/vertex.go Fri Nov 23 15:46:07 2018 +0100 +++ b/pkg/octree/vertex.go Mon Nov 26 09:01:21 2018 +0100 @@ -110,8 +110,8 @@ } } -func (a Vertex) Less(b Vertex) bool { - return a.X < b.X || a.Y < b.Y || a.Z < b.Z +func (v Vertex) Less(w Vertex) bool { + return v.X < w.X || v.Y < w.Y || v.Z < w.Z } func NewLine(p1, p2 Vertex) Line { @@ -537,26 +537,26 @@ return false } -func (a Vertex) Cross(b Vertex) Vertex { +func (v Vertex) Cross(w Vertex) Vertex { return Vertex{ - a.Y*b.Z - a.Z*b.Y, - a.Z*b.X - a.X*b.Z, - a.X*b.Y - a.Y*b.X, + v.Y*w.Z - v.Z*w.Y, + v.Z*w.X - v.X*w.Z, + v.X*w.Y - v.Y*w.X, } } -func (p1 Plane2D) Intersection(p2 Plane2D) (float64, float64, bool) { +func (p Plane2D) Intersection(o Plane2D) (float64, float64, bool) { - u1 := Vertex{p1.A, p1.B, p1.C} - u2 := Vertex{p2.A, p2.B, p2.C} + u1 := Vertex{p.A, p.B, p.C} + u2 := Vertex{o.A, o.B, o.C} - p := u1.Cross(u2) + plane := u1.Cross(u2) - if p.Z == 0 { + if plane.Z == 0 { return 0, 0, false } - return p.X / p.Z, p.Y / p.Z, true + return plane.X / plane.Z, plane.Y / plane.Z, true } type VerticalLine struct {
--- a/schema/auth.sql Fri Nov 23 15:46:07 2018 +0100 +++ b/schema/auth.sql Mon Nov 26 09:01:21 2018 +0100 @@ -10,6 +10,8 @@ -- Author(s): -- * Tom Gottried <tom@intevation.de> +-- * Sascha Wilde <sascha.wilde@intevation.de> +-- * Sascha L. Teichmann <sascha.teichmann@intevation.de> BEGIN;
--- a/schema/demo-data/published_services.sql Fri Nov 23 15:46:07 2018 +0100 +++ b/schema/demo-data/published_services.sql Mon Nov 26 09:01:21 2018 +0100 @@ -1,3 +1,16 @@ +-- 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) 2018 by via donau +-- – Österreichische Wasserstraßen-Gesellschaft mbH +-- Software engineering by Intevation GmbH + +-- Author(s): +-- * Tom Gottfried <tom@intevation.de> + INSERT INTO sys_admin.published_services (name) VALUES ('waterway.fairway_dimensions'), ('waterway.distance_marks_geoserver'),
--- a/schema/demo-data/responsibility_areas.sql Fri Nov 23 15:46:07 2018 +0100 +++ b/schema/demo-data/responsibility_areas.sql Mon Nov 26 09:01:21 2018 +0100 @@ -1,3 +1,18 @@ +-- 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) 2018 by via donau +-- – Österreichische Wasserstraßen-Gesellschaft mbH +-- Software engineering by Intevation GmbH + +-- Author(s): +-- * Sascha Wilde <sascha.wilde@intevation.de> +-- * Tom Gottfried <tom@intevation.de> + + -- Setup Country Codes COPY countries (country_code) FROM stdin; RO
--- a/schema/demo-data/roles.sql Fri Nov 23 15:46:07 2018 +0100 +++ b/schema/demo-data/roles.sql Mon Nov 26 09:01:21 2018 +0100 @@ -1,3 +1,17 @@ +-- 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) 2018 by via donau +-- – Österreichische Wasserstraßen-Gesellschaft mbH +-- Software engineering by Intevation GmbH + +-- Author(s): +-- * Christine Tschuprine <christine.tschuprine@intevation.de> +-- * Tom Gottfried <tom@intevation.de> + -- System Administrator CREATE ROLE sophie IN ROLE sys_admin ROLE metamorph LOGIN PASSWORD 'so2Phie4';
--- a/schema/demo-data/users.sql Fri Nov 23 15:46:07 2018 +0100 +++ b/schema/demo-data/users.sql Mon Nov 26 09:01:21 2018 +0100 @@ -1,3 +1,19 @@ +-- 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) 2018 by via donau +-- – Österreichische Wasserstraßen-Gesellschaft mbH +-- Software engineering by Intevation GmbH + +-- Author(s): +-- * Sascha Wilde <sascha.wilde@intevation.de> +-- * Christine Tschuprine <christine.tschuprine@intevation.de> +-- * Thomas Junk <thomas.junk@intevation.de> +-- * Tom Gottfried <tom@intevation.de> + BEGIN; -- PREREQUISITES: