changeset 719:d1b60ad2f50d octree

Merged default into octree branch.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 21 Sep 2018 16:29:38 +0200
parents c0bba602b60e (current diff) bb0788567609 (diff)
children aeaa2adf5a8b
files
diffstat 17 files changed, 307 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/client/package.json	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/package.json	Fri Sep 21 16:29:38 2018 +0200
@@ -25,6 +25,7 @@
     "purgecss-webpack-plugin": "^1.2.1",
     "v-tooltip": "^2.0.0-rc.33",
     "vue": "^2.5.16",
+    "vue-highlightjs": "^1.3.3",
     "vue-router": "^3.0.1",
     "vuex": "^3.0.1"
   },
--- a/client/src/App.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/App.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -17,7 +17,7 @@
             </div>
             <div class="bottomcontainer d-flex flex-row align-items-end">
                 <Userbar></Userbar>
-                <Linetool v-if="routeName != 'usermanagement'"></Linetool>
+                <Linetool v-if="routeName == 'mainview'"></Linetool>
             </div>
         </div>
         <div class="d-flex flex-column">
--- a/client/src/application/Main.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/application/Main.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -71,6 +71,9 @@
   },
   updated() {
     if (!document.querySelector(".profile")) return;
+    const clientHeight = document.querySelector(".profile").clientHeight;
+    const clientWidth = document.querySelector(".profile").clientWidth;
+    if (!clientHeight || !clientWidth) return;
     this.height = document.querySelector(".profile").clientHeight - 25;
     this.width = document.querySelector(".profile").clientWidth - 100;
   },
--- a/client/src/application/Sidebar.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/application/Sidebar.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -10,6 +10,9 @@
                     <router-link class="text-body d-flex flex-row nav-link" to="usermanagement">
                         <i class="fa fa-address-card-o align-self-center navicon"></i>Users
                     </router-link>
+                    <router-link class="text-body d-flex flex-row nav-link" to="logs">
+                        <i class="fa  fa-book align-self-center navicon"></i>Systeminformation
+                    </router-link>
                 </div>
             </div>
         </div>
--- a/client/src/application/Topbar.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/application/Topbar.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -3,7 +3,7 @@
         <div @click="toggleSidebar">
             <i class="ui-element menubutton fa fa-bars"></i>
         </div>
-        <div v-if="routeName != 'usermanagement'" :class="searchbarContainerStyle">
+        <div v-if="routeName == 'mainview'" :class="searchbarContainerStyle">
             <div class="input-group-prepend shadow">
                 <span @click="toggleSearchbar" class="ui-element input-group-text searchlabel" for="search">
                     <i class="fa fa-search"></i>
@@ -11,11 +11,11 @@
             </div>
             <input v-if="!searchbarCollapsed" id="search" type="text" class="form-control ui-element search searchbar">
         </div>
-        <div v-if="routeName != 'usermanagement'" class="splitbutton">
+        <div v-if="routeName == 'mainview'" class="splitbutton">
             <i @click="splitScreen" class="ui-element splitscreen fa fa-window-restore shadow"></i>
         </div>
         <div class="">
-            <Layers v-if="routeName != 'usermanagement'"></Layers>
+            <Layers v-if="routeName == 'mainview'"></Layers>
         </div>
     </div>
 </template>
@@ -92,7 +92,7 @@
   },
   data() {
     return {
-      searchbarCollapsed: false
+      searchbarCollapsed: true
     };
   },
   computed: {
--- a/client/src/application/assets/application.scss	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/application/assets/application.scss	Fri Sep 21 16:29:38 2018 +0200
@@ -1,23 +1,23 @@
-$offset: 1rem;
-$small-offset: 0.5rem;
-$x-small-offset: 0.25rem;
+$basic-shadow-light: 1px 1px 12px 1px rgba(235, 235, 235, 0.75);
+$basic-shadow: 1px 3px 8px 2px rgba(220, 220, 220, 0.75);
+$border-radius: 5px;
+$icon-height: 2rem;
+$icon-width: 2rem;
 $large-offset: 2rem;
-$x-large-offset: 3rem;
-$basic-shadow: 1px 3px 8px 2px rgba(220, 220, 220, 0.75);
-$basic-shadow-light: 1px 1px 12px 1px rgba(235, 235, 235, 0.75);
-$transition: 0.5s;
+$layerselect-height: 20rem;
+$layerselect-width: 20rem;
+$offset: 1rem;
+$searchbar-width: 50vw;
+$sidebar-height: 16rem;
+$sidebar-width: 15rem;
+$slight-transparent: 0.96;
+$small-offset: 0.5rem;
+$smaller: 0.9rem;
 $transition-fast: 0.3s;
 $transition-slow: 3s;
-$smaller: 0.9rem;
-$border-radius: 5px;
-$sidebar-width: 15rem;
-$sidebar-height: 13rem;
-$icon-height: 2rem;
-$icon-width: 2rem;
-$layerselect-height: 20rem;
-$layerselect-width: 20rem;
-$slight-transparent: 0.96;
-$searchbar-width: 50vw;
+$transition: 0.5s;
+$x-large-offset: 3rem;
+$x-small-offset: 0.25rem;
 
 .debug {
   border: 1px solid red;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/logs/logs.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -0,0 +1,186 @@
+<template>
+    <div class="main d-flex flex-column">
+        <div class="d-flex flex-row">
+            <div :class="spacer"></div>
+            <div class="logoutput shadow">
+                <pre v-highlightjs="logs"><code class="javascript"></code></pre>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style scoped lang="scss">
+.logoutput {
+  width: 95%;
+  height: 85vh;
+  margin-top: $offset;
+  margin-right: $offset;
+  margin-left: $offset;
+  text-align: left;
+  background-color: white;
+  overflow: scroll;
+  transition: $transition-fast;
+}
+
+.spacer {
+  margin-left: $offset;
+  height: 90vh;
+}
+
+.spacer-collapsed {
+  min-width: $icon-width + $offset;
+  transition: $transition-fast;
+}
+
+.spacer-expanded {
+  min-width: $sidebar-width + $offset;
+}
+</style>
+
+<script>
+import { mapGetters } from "vuex";
+
+export default {
+  name: "logs",
+  data() {
+    return {
+      logs: `gemma ❯ ./run-app.sh
+2018/09/21 11:13:37 Configure GeoServer...
+2018/09/21 11:13:37 listen on localhost:8000
+2018/09/21 11:13:37 info: creating workspace gemma
+2018/09/21 11:13:38 info: creating datastore gemma
+2018/09/21 11:13:38 info: number of tables to publish 2
+2018/09/21 11:13:38 info: creating featuretype distance_marks_geoserver.
+2018/09/21 11:13:39 warn: configure GeoServer failed: Status code 'Internal Server Error' (500)
+2018/09/21 11:48:22 Injecting user sophie
+2018/09/21 11:48:22 proxyDirector: /api/internal/wfs
+2018/09/21 11:48:22 proxyDirector: /api/external/d4d
+2018/09/21 11:48:22 proxyDirector: /api/external/d4d
+2018/09/21 11:48:22 Injecting user sophie
+2018/09/21 11:48:22 proxyDirector: /api/internal/wfs
+2018/09/21 11:48:25 gzip compression
+2018/09/21 11:48:25 rewrite successful
+2018/09/21 11:48:25 rewrite took 25.603973ms
+2018/09/21 11:48:27 gzip compression
+2018/09/21 11:48:27 rewrite successful
+2018/09/21 11:48:27 rewrite took 1.039415ms
+2018/09/21 11:48:52 Injecting user sophie
+2018/09/21 11:48:52 proxyDirector: /api/internal/wfs
+2018/09/21 11:48:52 proxyDirector: /api/external/d4d
+2018/09/21 11:48:53 gzip compression
+2018/09/21 11:48:53 rewrite successful
+2018/09/21 11:48:53 rewrite took 1.039695ms
+2018/09/21 11:48:53 proxyDirector: /api/external/d4d
+2018/09/21 11:48:53 Injecting user sophie
+2018/09/21 11:48:53 proxyDirector: /api/internal/wfs
+2018/09/21 11:48:53 gzip compression
+2018/09/21 11:48:53 rewrite successful
+2018/09/21 11:48:53 rewrite took 16.220881ms
+2018/09/21 11:49:05 Injecting user sophie
+2018/09/21 11:49:05 proxyDirector: /api/internal/wfs
+2018/09/21 11:49:05 proxyDirector: /api/external/d4d
+2018/09/21 11:49:05 gzip compression
+2018/09/21 11:49:05 rewrite successful
+2018/09/21 11:49:05 rewrite took 973.896µs
+2018/09/21 11:49:05 Injecting user sophie
+2018/09/21 11:49:05 proxyDirector: /api/internal/wfs
+2018/09/21 11:49:05 gzip compression
+2018/09/21 11:49:05 rewrite successful
+2018/09/21 11:49:05 rewrite took 1.396081ms
+2018/09/21 11:49:38 Injecting user sophie
+2018/09/21 11:49:38 proxyDirector: /api/internal/wfs
+2018/09/21 11:49:38 proxyDirector: /api/external/d4d
+2018/09/21 11:49:38 gzip compression
+2018/09/21 11:49:38 rewrite successful
+2018/09/21 11:49:38 rewrite took 853.268µs
+2018/09/21 11:49:38 proxyDirector: /api/external/d4d
+2018/09/21 11:49:38 Injecting user sophie
+2018/09/21 11:49:38 proxyDirector: /api/internal/wfs
+2018/09/21 11:49:38 gzip compression
+2018/09/21 11:49:38 rewrite successful
+2018/09/21 11:49:38 rewrite took 5.146315ms
+2018/09/21 11:50:38 Injecting user sophie
+2018/09/21 11:50:38 proxyDirector: /api/internal/wfs
+2018/09/21 11:50:38 proxyDirector: /api/external/d4d
+2018/09/21 11:50:38 gzip compression
+2018/09/21 11:50:38 rewrite successful
+2018/09/21 11:50:38 rewrite took 1.221311ms
+2018/09/21 11:50:38 Injecting user sophie
+2018/09/21 11:50:38 proxyDirector: /api/internal/wfs
+2018/09/21 11:50:38 proxyDirector: /api/external/d4d
+2018/09/21 11:50:38 gzip compression
+2018/09/21 11:50:38 rewrite successful
+2018/09/21 11:50:38 rewrite took 1.427937ms
+2018/09/21 11:51:06 proxyDirector: /api/external/d4d
+2018/09/21 11:51:06 Injecting user sophie
+2018/09/21 11:51:06 proxyDirector: /api/internal/wfs
+2018/09/21 11:51:06 gzip compression
+2018/09/21 11:51:06 rewrite successful
+2018/09/21 11:51:06 rewrite took 8.170505ms
+2018/09/21 11:51:17 Injecting user sophie
+2018/09/21 11:51:17 proxyDirector: /api/internal/wfs
+2018/09/21 11:51:17 proxyDirector: /api/external/d4d
+2018/09/21 11:51:17 gzip compression
+2018/09/21 11:51:17 rewrite successful
+2018/09/21 11:51:17 rewrite took 1.222553ms
+2018/09/21 11:51:17 Injecting user sophie
+2018/09/21 11:51:17 proxyDirector: /api/internal/wfs
+2018/09/21 11:51:17 gzip compression
+2018/09/21 11:51:17 rewrite successful
+2018/09/21 11:51:17 rewrite took 2.78996ms
+2018/09/21 11:51:34 proxyDirector: /api/external/d4d
+2018/09/21 11:51:34 Injecting user sophie
+2018/09/21 11:51:34 proxyDirector: /api/internal/wfs
+2018/09/21 11:51:34 gzip compression
+2018/09/21 11:51:34 rewrite successful
+2018/09/21 11:51:34 rewrite took 1.33321ms
+2018/09/21 11:51:34 proxyDirector: /api/external/d4d
+2018/09/21 11:51:34 Injecting user sophie
+2018/09/21 11:51:34 proxyDirector: /api/internal/wfs
+2018/09/21 11:51:34 gzip compression
+2018/09/21 11:51:34 rewrite successful
+2018/09/21 11:51:34 rewrite took 3.687839ms
+2018/09/21 11:52:08 Injecting user sophie
+2018/09/21 11:52:08 proxyDirector: /api/internal/wfs
+2018/09/21 11:52:08 proxyDirector: /api/external/d4d
+2018/09/21 11:52:08 gzip compression
+2018/09/21 11:52:08 rewrite successful
+2018/09/21 11:52:08 rewrite took 1.26564ms
+2018/09/21 11:52:08 proxyDirector: /api/external/d4d
+2018/09/21 11:52:08 Injecting user sophie
+2018/09/21 11:52:08 proxyDirector: /api/internal/wfs
+2018/09/21 11:52:08 gzip compression
+2018/09/21 11:52:08 rewrite successful
+2018/09/21 11:52:08 rewrite took 1.024643ms
+2018/09/21 11:54:23 Injecting user sophie
+2018/09/21 11:54:23 proxyDirector: /api/internal/wfs
+2018/09/21 11:54:23 proxyDirector: /api/external/d4d
+2018/09/21 11:54:23 gzip compression
+2018/09/21 11:54:23 rewrite successful
+2018/09/21 11:54:23 rewrite took 1.162201ms
+2018/09/21 11:54:23 proxyDirector: /api/external/d4d
+2018/09/21 11:54:23 Injecting user sophie
+2018/09/21 11:54:23 proxyDirector: /api/internal/wfs
+2018/09/21 11:54:23 gzip compression
+2018/09/21 11:54:23 rewrite successful
+2018/09/21 11:54:23 rewrite took 990.32µs
+`
+    };
+  },
+  methods: {
+    disallow(e) {
+      e.target.blur();
+    }
+  },
+  computed: {
+    ...mapGetters("application", ["sidebarCollapsed", "isUsermenuCollapsed"]),
+    spacer() {
+      return {
+        spacer: true,
+        "spacer-expanded": !this.sidebarCollapsed,
+        "spacer-collapsed": this.sidebarCollapsed
+      };
+    }
+  }
+};
+</script>
--- a/client/src/main.js	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/main.js	Fri Sep 21 16:29:38 2018 +0200
@@ -11,7 +11,10 @@
 import "../node_modules/animate.css/animate.min.css";
 import "../node_modules/ol/ol.css";
 import "../node_modules/cxlt-vue2-toastr/dist/css/cxlt-vue2-toastr.css";
+import "../node_modules/highlight.js/styles/paraiso-dark.css";
 import VTooltip from "v-tooltip";
+import VueHighlightJS from "vue-highlightjs";
+Vue.use(VueHighlightJS);
 
 Vue.use(VTooltip);
 
--- a/client/src/map/Maplayer.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/map/Maplayer.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -14,14 +14,18 @@
 
 <script>
 import { HTTP } from "../application/lib/http";
+import { mapGetters } from "vuex";
 import "ol/ol.css";
+// openlayers imports, sorted by module name
 import { Map, View } from "ol";
-import { bbox as bboxFilter } from "ol/format/filter.js";
+import Feature from "ol/Feature";
+// import { bbox as bboxFilter } from "ol/format/filter.js";
 import { WFS, GeoJSON } from "ol/format.js";
-import { mapGetters } from "vuex";
+import GeometryType from "ol/geom/GeometryType.js";
+import LineString from "ol/geom/LineString.js";
 import Draw from "ol/interaction/Draw.js";
+import { Vector as VectorLayer } from "ol/layer.js";
 import { Vector as VectorSource } from "ol/source.js";
-import { Vector as VectorLayer } from "ol/layer.js";
 
 export default {
   name: "maplayer",
@@ -65,20 +69,45 @@
     },
     createInteraction() {
       var that = this;
-      this.vectorSource.clear();  // start empty
+      this.vectorSource.clear(); // start empty
       var draw = new Draw({
         source: this.vectorSource,
         type: this.drawMode
       });
       draw.on("drawstart", function(event) {
         console.log(event);
-        that.vectorSource.clear();  // remove old features when draw starts
+        that.vectorSource.clear(); // remove old features when draw starts
       });
       draw.on("drawend", this.drawEnd);
       return draw;
     },
     drawEnd(event) {
       console.log(event);
+      var inputLineString = event.feature.getGeometry().clone();
+      if (inputLineString.getType() == GeometryType.LINE_STRING) {
+        // prepare to send the first line seqment to the server as GeoJSON
+        inputLineString.transform("EPSG:3857", "EPSG:4326");
+        var coords = inputLineString.getCoordinates();
+        if (coords.length >= 2) {
+          var feature = new Feature({
+            geometry: new LineString([coords[0], coords[1]]),
+            // FIXME: hardcoded bottleneck and survey date
+            bottleneck: "AT_Bottleneck_44",
+            date: "2017-11-20"
+          });
+          var gStr = new GeoJSON({ geometryName: "geometry" }).writeFeature(
+            feature
+          );
+          console.log("Ready to start profile view with: ", feature, gStr);
+
+          // FIXME: assuming that we have the fairway dimensions loaded
+          var vectorSource = this.getLayerByName(
+            "Fairway Dimensions"
+          ).data.getSource();
+          console.log(vectorSource);
+          // vectorSource.forEachFeatureIntersectingExtent()
+        }
+      }
     },
     activateInteraction() {
       const interaction = this.createInteraction(this.drawMode);
@@ -121,11 +150,19 @@
             );
             // DEBUG console.log("loaded ", features, "for", vectorSource);
             // eslint-disable-next-line
-        }).catch(error => {
+          })
+          .catch(() => {
             vectorSource.removeLoadedExtent(extent);
           });
       };
       return loader;
+    },
+    getLayerByName(name) {
+      for (let layer of this.layers) {
+        if (layer.name === name) {
+          return layer;
+        }
+      }
     }
   },
   watch: {
@@ -226,9 +263,9 @@
     var featureRequestOptions5 = {
       featurePrefix: "ws-wamos",
       featureTypes: ["ienc_dismar"],
-      geometryName: "geom",
+      geometryName: "geom" //,
       /* restrict loading approximately to extend of danube in Austria */
-      filter: bboxFilter("geom", [13.3, 48.0, 17.1, 48.6], "EPSG:4326")
+      // filter: bboxFilter("geom", [13.3, 48.0, 17.1, 48.6], "EPSG:4326")
     };
 
     this.layers[5].data
--- a/client/src/map/store.js	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/map/store.js	Fri Sep 21 16:29:38 2018 +0200
@@ -30,7 +30,7 @@
         isVisible: true
       },
       {
-        name: "Fairways Dimensions",
+        name: "Fairway Dimensions",
         data: new VectorLayer({
           source: new VectorSource(),
           style: function(feature) {
--- a/client/src/router.js	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/router.js	Fri Sep 21 16:29:38 2018 +0200
@@ -10,6 +10,7 @@
 const Login = () => import("./login/Login.vue");
 const Main = () => import("./application/Main.vue");
 const Usermanagement = () => import("./usermanagement/Usermanagement.vue");
+const Logs = () => import("./logs/logs.vue");
 
 Vue.use(Router);
 
@@ -37,6 +38,22 @@
       }
     },
     {
+      path: "/logs",
+      name: "logs",
+      component: Logs,
+      meta: {
+        requiresAuth: true
+      },
+      beforeEnter: (to, from, next) => {
+        const isSysadmin = store.getters["user/isSysAdmin"];
+        if (!isSysadmin) {
+          next("/");
+        } else {
+          next();
+        }
+      }
+    },
+    {
       path: "/",
       name: "mainview",
       component: Main,
--- a/client/src/usermanagement/Usermanagement.vue	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/src/usermanagement/Usermanagement.vue	Fri Sep 21 16:29:38 2018 +0200
@@ -70,7 +70,7 @@
     </div>
 </template>
 
-<style lang="scss">
+<style scoped lang="scss">
 @import "../application/assets/tooltip.scss";
 
 .spacer {
@@ -80,6 +80,7 @@
 
 .spacer-collapsed {
   min-width: $icon-width + $offset;
+  transition: $transition-fast;
 }
 
 @media screen and (min-width: 600px) {
--- a/client/yarn.lock	Fri Sep 21 14:47:44 2018 +0200
+++ b/client/yarn.lock	Fri Sep 21 16:29:38 2018 +0200
@@ -4387,6 +4387,10 @@
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
 
+highlight.js@*:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
+
 hmac-drbg@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -9213,6 +9217,12 @@
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/vue-gettext/-/vue-gettext-2.1.0.tgz#e4932037a8601412dd9f7d7d7a5d60c4bdb341d1"
 
+vue-highlightjs@^1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/vue-highlightjs/-/vue-highlightjs-1.3.3.tgz#29a0d57132fc1ce15cfa61e896918f5b718c5d52"
+  dependencies:
+    highlight.js "*"
+
 vue-hot-reload-api@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926"
--- a/docker/Dockerfile.spa	Fri Sep 21 14:47:44 2018 +0200
+++ b/docker/Dockerfile.spa	Fri Sep 21 16:29:38 2018 +0200
@@ -4,7 +4,7 @@
 RUN sed -i 's/\(deb.*\)$/\1 universe/' /etc/apt/sources.list
 
 RUN apt-get update &&\
-    apt-get -y install --no-install-recommends curl nodejs make
+    apt-get -y install --no-install-recommends curl gnupg nodejs make
 
 # Install yarn
 RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - &&\
--- a/docker/README.md	Fri Sep 21 14:47:44 2018 +0200
+++ b/docker/README.md	Fri Sep 21 16:29:38 2018 +0200
@@ -6,6 +6,13 @@
 Other example commands, too, assume they are run from the root of your
 checkout.
 
+## Network setup
+
+- Create a network to connect containers:
+  ```
+  docker network create gemma
+  ```
+
 ## Database setup
 
 - Build Dockerfile with e.g.:
@@ -16,8 +23,9 @@
 - Get a running instance with e.g.:
   ```
   docker run --name gemma_db -d -p 54321:5432 -v $PWD/schema:/opt/gemma \
-         gemma_db
+          --network gemma gemma_db
   ```
+  Use `--network-alias gemma_db` if your container has a different name
 
 - Run tests for RLS policies:
   ```
@@ -39,19 +47,6 @@
 Omit the `-s` option to get a diagram with all tables or use any other
 schema name to see other parts of the whole picture.
 
-## Network setup
-
-- Create a network to connect containers:
-  ```
-  docker network create gemma
-  ```
-
-- Connect database to new network
-  ```
-  docker network connect gemma gemma_db
-  ```
-  Use `--alias gemma_db` if your container has a different name
-
 ## GeoServer setup
 
 - Build Dockerfile with e.g.:
--- a/pkg/controllers/cross.go	Fri Sep 21 14:47:44 2018 +0200
+++ b/pkg/controllers/cross.go	Fri Sep 21 16:29:38 2018 +0200
@@ -11,13 +11,13 @@
 
 const crossSQL = `
 WITH line AS (
-SELECT ST_3DIntersection(
+SELECT ST_LineMerge(ST_Union(ST_3DIntersection(
   ST_Translate(
     ST_Extrude(
       ST_GeomFromWKB($1, 4326),
     0, 0, 1000),
    0, 0, -500),
-   geom) AS geom
+   geom))) AS geom
 FROM waterway.meshes m JOIN waterway.sounding_results sr ON m.sounding_result_id = sr.id
 WHERE ST_Intersects(geom, ST_GeomFromWKB($1, 4326)) AND
   sr.bottleneck_id = $2 AND sr.date_info = $3
--- a/pkg/controllers/routes.go	Fri Sep 21 14:47:44 2018 +0200
+++ b/pkg/controllers/routes.go	Fri Sep 21 16:29:38 2018 +0200
@@ -47,10 +47,12 @@
 	api.Handle("/users/passwordreset", &JSONHandler{
 		Input:  func() interface{} { return new(models.PWResetUser) },
 		Handle: passwordResetRequest,
+		NoConn: true,
 	}).Methods(http.MethodPost)
 
 	api.Handle("/users/passwordreset/{hash}", &JSONHandler{
 		Handle: passwordReset,
+		NoConn: true,
 	}).Methods(http.MethodGet)
 
 	// External proxies.