changeset 3625:a688a478e35f configuration

implemented configuration backend and frontend
author Markus Kottlaender <markus@intevation.de>
date Fri, 07 Jun 2019 12:53:41 +0200
parents 3012d0b3badc
children 73fd4dd9e569
files client/src/components/systemconfiguration/DataAccuracy.vue client/src/components/systemconfiguration/MapLayers.vue client/src/components/systemconfiguration/MorphologyClassbreaks.vue client/src/components/systemconfiguration/Systemconfiguration.vue client/src/store/application.js pkg/controllers/routes.go pkg/controllers/system.go schema/default_sysconfig.sql
diffstat 8 files changed, 165 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/systemconfiguration/DataAccuracy.vue	Wed Jun 05 18:50:54 2019 +0200
+++ b/client/src/components/systemconfiguration/DataAccuracy.vue	Fri Jun 07 12:53:41 2019 +0200
@@ -330,7 +330,17 @@
   },
   methods: {
     submit() {
-      this.$store.commit("application/config", this.config);
+      this.$store.dispatch("application/saveConfig", {
+        bn_revtime_multiplier: this.config.bn_revtime_multiplier,
+        gm_latest_hours: this.config.gm_latest_hours,
+        gm_min_values_14d: this.config.gm_min_values_14d,
+        gm_forecast_offset_24h: this.config.gm_forecast_offset_24h,
+        gm_forecast_offset_72h: this.config.gm_forecast_offset_72h,
+        gm_forecast_vs_reality_nsc_24h: this.config
+          .gm_forecast_vs_reality_nsc_24h,
+        gm_forecast_vs_reality_nsc_72h: this.config
+          .gm_forecast_vs_reality_nsc_72h
+      });
     }
   }
 };
--- a/client/src/components/systemconfiguration/MapLayers.vue	Wed Jun 05 18:50:54 2019 +0200
+++ b/client/src/components/systemconfiguration/MapLayers.vue	Fri Jun 07 12:53:41 2019 +0200
@@ -46,7 +46,9 @@
   },
   methods: {
     submit() {
-      this.$store.commit("application/config", this.config);
+      this.$store.dispatch("application/saveConfig", {
+        ecdis_url: this.config.ecdis_url
+      });
     }
   }
 };
--- a/client/src/components/systemconfiguration/MorphologyClassbreaks.vue	Wed Jun 05 18:50:54 2019 +0200
+++ b/client/src/components/systemconfiguration/MorphologyClassbreaks.vue	Fri Jun 07 12:53:41 2019 +0200
@@ -8,11 +8,11 @@
       <div class="d-flex flex-wrap">
         <div
           class="input-group mb-3 mr-2 classbreak"
-          v-for="(value, i) in config.morphology_classbreaks"
+          v-for="(value, i) in morphologyClassbreaks"
           :key="i"
         >
           <input
-            v-model="config.morphology_classbreaks[i]"
+            v-model="morphologyClassbreaks[i]"
             type="number"
             min="0"
             step="0.1"
@@ -22,7 +22,7 @@
             <button
               class="btn btn-sm btn-outline-secondary"
               type="button"
-              @click="config.morphology_classbreaks.splice(i, 1)"
+              @click="morphologyClassbreaks.splice(i, 1)"
             >
               <font-awesome-icon icon="times" />
             </button>
@@ -31,11 +31,9 @@
         <button
           class="btn btn-sm btn-success mb-3"
           @click="
-            config.morphology_classbreaks.push(
-              config.morphology_classbreaks.length
-                ? config.morphology_classbreaks[
-                    config.morphology_classbreaks.length - 1
-                  ]
+            morphologyClassbreaks.push(
+              morphologyClassbreaks.length
+                ? morphologyClassbreaks[morphologyClassbreaks.length - 1]
                 : 1
             )
           "
@@ -51,11 +49,11 @@
       <div class="d-flex flex-wrap">
         <div
           class="input-group mb-3 mr-2 classbreak"
-          v-for="(value, i) in config.morphology_classbreaks_compare"
+          v-for="(value, i) in morphologyClassbreaksCompare"
           :key="i"
         >
           <input
-            v-model="config.morphology_classbreaks_compare[i]"
+            v-model="morphologyClassbreaksCompare[i]"
             type="number"
             step="0.1"
             class="form-control form-control-sm"
@@ -64,7 +62,7 @@
             <button
               class="btn btn-sm btn-outline-secondary"
               type="button"
-              @click="config.morphology_classbreaks_compare.splice(i, 1)"
+              @click="morphologyClassbreaksCompare.splice(i, 1)"
             >
               <font-awesome-icon icon="times" />
             </button>
@@ -73,10 +71,10 @@
         <button
           class="btn btn-sm btn-success mb-3"
           @click="
-            config.morphology_classbreaks_compare.push(
-              config.morphology_classbreaks_compare.length
-                ? config.morphology_classbreaks_compare[
-                    config.morphology_classbreaks_compare.length - 1
+            morphologyClassbreaksCompare.push(
+              morphologyClassbreaksCompare.length
+                ? morphologyClassbreaksCompare[
+                    morphologyClassbreaksCompare.length - 1
                   ]
                 : 1
             )
@@ -122,13 +120,32 @@
 import { mapState } from "vuex";
 
 export default {
+  data() {
+    return {
+      morphologyClassbreaks: [],
+      morphologyClassbreaksCompare: []
+    };
+  },
   computed: {
     ...mapState("application", ["config"])
   },
   methods: {
     submit() {
-      this.$store.commit("application/config", this.config);
+      this.$store.dispatch("application/saveConfig", {
+        morphology_classbreaks: this.morphologyClassbreaks.join(","),
+        morphology_classbreaks_compare: this.morphologyClassbreaksCompare.join(
+          ","
+        )
+      });
     }
+  },
+  mounted() {
+    this.morphologyClassbreaks = this.config.morphology_classbreaks
+      .split(",")
+      .map(n => Number(n));
+    this.morphologyClassbreaksCompare = this.config.morphology_classbreaks_compare
+      .split(",")
+      .map(n => Number(n));
   }
 };
 </script>
--- a/client/src/components/systemconfiguration/Systemconfiguration.vue	Wed Jun 05 18:50:54 2019 +0200
+++ b/client/src/components/systemconfiguration/Systemconfiguration.vue	Fri Jun 07 12:53:41 2019 +0200
@@ -6,6 +6,9 @@
       <div class="text-left flex-fill" style="overflow: auto">
         <PDFTemplates />
         <ColorSettings v-if="isSysAdmin" />
+        <MapLayers v-if="isSysAdmin" />
+        <DataAccuracy v-if="isSysAdmin" />
+        <MorphologyClassbreaks v-if="isSysAdmin" />
       </div>
       <!-- card-body -->
     </div>
@@ -35,7 +38,10 @@
   components: {
     Spacer: () => import("../Spacer"),
     PDFTemplates: () => import("./PDFTemplates"),
-    ColorSettings: () => import("./ColorSettings")
+    ColorSettings: () => import("./ColorSettings"),
+    MapLayers: () => import("./MapLayers"),
+    DataAccuracy: () => import("./DataAccuracy"),
+    MorphologyClassbreaks: () => import("./MorphologyClassbreaks")
   },
   computed: {
     ...mapGetters("user", ["isSysAdmin"]),
--- a/client/src/store/application.js	Wed Jun 05 18:50:54 2019 +0200
+++ b/client/src/store/application.js	Fri Jun 07 12:53:41 2019 +0200
@@ -14,6 +14,8 @@
  *   Bernhard E. Reiter <bernhard.reiter@intevation.de>
  */
 
+import { HTTP } from "@/lib/http";
+import { displayError } from "@/lib/errors";
 import { version } from "../../package.json";
 
 // initial state
@@ -140,85 +142,26 @@
     }
   },
   actions: {
-    loadConfig({ commit, state }) {
-      if (!Object.keys(state.config).length) {
-        setTimeout(() => {
-          commit("config", {
-            ecdis_url: "https://service.d4d-portal.info/wms/",
-            bn_revtime_multiplier: 1.5,
-            gm_min_values_14d: 1124,
-            gm_latest_hours: 24,
-            gm_forecast_offset_24h: 15,
-            gm_forecast_offset_72h: 15,
-            gm_forecast_vs_reality_nsc_24h: -12.5,
-            gm_forecast_vs_reality_nsc_72h: -12.5,
-            morphology_classbreaks: [
-              1,
-              1.5,
-              1.7,
-              1.9,
-              2.1,
-              2.3,
-              2.5,
-              2.7,
-              2.9,
-              3.1,
-              3.3,
-              3.5,
-              4.0,
-              4.5,
-              5,
-              5.5,
-              6,
-              6.5,
-              7
-            ],
-            morphology_classbreaks_compare: [
-              -2,
-              -1.9,
-              -1.8,
-              -1.7,
-              -1.6,
-              -1.5,
-              -1.4,
-              -1.3,
-              -1.2,
-              -1.1,
-              -1,
-              -0.9,
-              -0.8,
-              -0.7,
-              -0.6,
-              -0.5,
-              -0.4,
-              -0.3,
-              -0.2,
-              -0.1,
-              0,
-              0.1,
-              0.2,
-              0.3,
-              0.4,
-              0.5,
-              0.6,
-              0.7,
-              0.8,
-              0.9,
-              1,
-              1.1,
-              1.2,
-              1.3,
-              1.4,
-              1.5,
-              1.6,
-              1.7,
-              1.8,
-              1.9,
-              2
-            ]
-          });
-        }, 1000);
-      }
+    loadConfig({ commit }) {
+      HTTP.get("/system/settings", {
+        headers: { "X-Gemma-Auth": localStorage.getItem("token") }
+      }).then(response => {
+        commit("config", response.data);
+      });
+    },
+    saveConfig(context, config) {
+      HTTP.put("/system/settings", config, {
+        headers: {
+          "X-Gemma-Auth": localStorage.getItem("token"),
+          "Content-type": "application/json"
+        }
+      }).catch(error => {
+        const { status, data } = error.response;
+        displayError({
+          title: "Backend Error",
+          message: `${status}: ${data.message || data}`
+        });
+      });
     }
   }
 };
--- a/pkg/controllers/routes.go	Wed Jun 05 18:50:54 2019 +0200
+++ b/pkg/controllers/routes.go	Fri Jun 07 12:53:41 2019 +0200
@@ -79,6 +79,15 @@
 		NoConn: true,
 	})).Methods(http.MethodGet)
 
+	api.Handle("/system/settings", any(&JSONHandler{
+		Handle: getSystemSettings,
+	})).Methods(http.MethodGet)
+
+	api.Handle("/system/settings", any(&JSONHandler{
+		Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
+		Handle: setSystemSettings,
+	})).Methods(http.MethodPut)
+
 	api.Handle("/system/style/{feature}/{attr}", any(&JSONHandler{
 		Handle: getFeatureStyle,
 	})).Methods(http.MethodGet)
--- a/pkg/controllers/system.go	Wed Jun 05 18:50:54 2019 +0200
+++ b/pkg/controllers/system.go	Fri Jun 07 12:53:41 2019 +0200
@@ -17,6 +17,7 @@
 	"bytes"
 	"database/sql"
 	"fmt"
+	"encoding/json"
 	"io/ioutil"
 	"net/http"
 	"strings"
@@ -35,6 +36,14 @@
 WHERE feature_name = $1 AND style_attr = $2`
 )
 
+const (
+	getSettingsSQL = `SELECT config_key, config_val
+FROM sys_admin.system_config`
+	updateSettingSQL = `UPDATE sys_admin.system_config
+SET config_val = $2
+WHERE config_key = $1`
+)
+
 // System status end points
 
 func showSystemLog(
@@ -100,6 +109,63 @@
 	return
 }
 
+func getSystemSettings(
+	_ interface{},
+	req *http.Request,
+	conn *sql.Conn,
+) (jr JSONResult, err error) {
+
+	var rows *sql.Rows
+	if rows, err = conn.QueryContext(req.Context(), getSettingsSQL); err != nil {
+		return
+	}
+	defer rows.Close()
+
+	var settings = map[string]string{}
+
+	for rows.Next() {
+		var key string
+		var val string
+		err = rows.Scan(&key, &val)
+		if err == nil {
+			settings[key] = val
+		}
+	}
+
+	jr = JSONResult{Result: settings}
+	return
+}
+
+func setSystemSettings(
+	input interface{},
+	req *http.Request,
+	conn *sql.Conn,
+) (jr JSONResult, err error) {
+
+	var settings map[string]interface{}
+	raw := input.(*json.RawMessage)
+	json.Unmarshal(*raw, &settings)
+
+	for key, value := range settings {
+		_, err = conn.ExecContext(
+			req.Context(),
+			updateSettingSQL,
+			key, value)
+
+		if err != nil {
+			return
+		}
+  }
+
+	jr = JSONResult{
+		Code: http.StatusCreated,
+		Result: struct {
+			Result string `json:"result"`
+		}{"success"},
+	}
+	return
+}
+
 // Map/Feature style end points
 
 func getFeatureStyle(
--- a/schema/default_sysconfig.sql	Wed Jun 05 18:50:54 2019 +0200
+++ b/schema/default_sysconfig.sql	Fri Jun 07 12:53:41 2019 +0200
@@ -23,4 +23,18 @@
 INSERT INTO systemconf.feature_colours VALUES ('Bottlenecks', 'stroke', 250, 40, 255, 1);
 INSERT INTO systemconf.feature_colours VALUES ('Bottlenecks', 'fill', 255, 37, 196, 0.14);
 
+--
+-- Settings
+--
+INSERT INTO sys_admin.system_config VALUES ('ecdis_url', 'https://service.d4d-portal.info/wms/');
+INSERT INTO sys_admin.system_config VALUES ('bn_revtime_multiplier', 1.5);
+INSERT INTO sys_admin.system_config VALUES ('gm_min_values_14d', 1224);
+INSERT INTO sys_admin.system_config VALUES ('gm_latest_hours', 24);
+INSERT INTO sys_admin.system_config VALUES ('gm_forecast_offset_24h', 15);
+INSERT INTO sys_admin.system_config VALUES ('gm_forecast_offset_72h', 15);
+INSERT INTO sys_admin.system_config VALUES ('gm_forecast_vs_reality_nsc_24h', -12.5);
+INSERT INTO sys_admin.system_config VALUES ('gm_forecast_vs_reality_nsc_72h', -12.5);
+INSERT INTO sys_admin.system_config VALUES ('morphology_classbreaks', '1,1.5,1.7,1.9,2.1,2.3,2.5,2.7,2.9,3.1,3.3,3.5,4.0,4.5,5,5.5,6,6.5,7');
+INSERT INTO sys_admin.system_config VALUES ('morphology_classbreaks_compare', '-2,-1.9,-1.8,-1.7,-1.6,-1.5,-1.4,-1.3,-1.2,-1.1,-1,-0.9,-0.8,-0.7,-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2');
+
 COMMIT;