changeset 4232:8aff98c84a5a

Example how to style distance_marks WMS layer with templating.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 21 Aug 2019 11:47:18 +0200
parents 6f31a99cd92d
children 63b160379e06
files pkg/controllers/system.go pkg/geoserver/templates.go schema/default_sysconfig.sql schema/updates/1109/01.distance_marks.sql
diffstat 4 files changed, 109 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/controllers/system.go	Wed Aug 21 11:13:12 2019 +0200
+++ b/pkg/controllers/system.go	Wed Aug 21 11:47:18 2019 +0200
@@ -21,6 +21,7 @@
 	"io/ioutil"
 	"log"
 	"net/http"
+	"regexp"
 	"strings"
 	"sync"
 	"time"
@@ -174,6 +175,24 @@
 	return reconfigureFuncs[key]
 }
 
+var validColorRe = regexp.MustCompile(`#[[:xdigit:]]{6}`)
+
+func reconfigureWMSLayer(
+	old sql.NullString, curr,
+	which string,
+) (func(*http.Request), error) {
+
+	if !validColorRe.MatchString(curr) {
+		return nil, fmt.Errorf("'%v' is not a valid color", curr)
+	}
+
+	if !old.Valid || old.String != strings.ToLower(curr) {
+		return func(*http.Request) { geoserver.ReconfigureStyle(which) }, nil
+	}
+
+	return nil, nil
+}
+
 func reconfigureClassBreaks(
 	old sql.NullString, curr,
 	which string,
@@ -245,6 +264,14 @@
 				"sounding_differences",
 				func(*http.Request) { go deleteSoundingDiffs() })
 		})
+
+	dm := func(old sql.NullString, curr string) (func(*http.Request), error) {
+		return reconfigureWMSLayer(old, curr, "distance_marks_geoserver")
+	}
+	registerReconfigureFunc("distance_marks_fill", dm)
+	registerReconfigureFunc("distance_marks_stroke", dm)
+
+	// TODO: Add more layers.
 }
 
 func triggerSoundingResultsContoursRecalc(who, breaks string) {
--- a/pkg/geoserver/templates.go	Wed Aug 21 11:13:12 2019 +0200
+++ b/pkg/geoserver/templates.go	Wed Aug 21 11:47:18 2019 +0200
@@ -17,6 +17,7 @@
 import (
 	"context"
 	"database/sql"
+	"regexp"
 	"strings"
 	"text/template"
 
@@ -25,7 +26,7 @@
 )
 
 const (
-	selectClassBreaksSQL = `
+	selectConfigValSQL = `
 SELECT config_val FROM sys_admin.system_config
 WHERE config_key = $1`
 )
@@ -37,6 +38,80 @@
 	RegisterStylePreprocessor(
 		"sounding_differences",
 		templateContourLinesFunc("morphology_classbreaks_compare"))
+	RegisterStylePreprocessor(
+		"distance_marks_geoserver",
+		templateConfigValues)
+	// TODO: Add more layers.
+}
+
+func templateConfigValues(tmplTxt string) (string, error) {
+	tmpl, err := template.New("template").Parse(tmplTxt)
+	if err != nil {
+		return "", err
+	}
+
+	// Try to extract the needed keys from the template.
+	keys := extractKeysFromTemplate(tmplTxt)
+	kv, err := loadConfigValues(keys)
+	if err != nil {
+		return "", err
+	}
+
+	var buf strings.Builder
+	if err = tmpl.Execute(&buf, kv); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+
+}
+
+// TODO: Use the parse tree of the template to extract keys.
+var findKeysRe = regexp.MustCompile(`{{[-]?\s*\.([^-.\s]+)\s*[-]?}}`)
+
+func extractKeysFromTemplate(tmpl string) []string {
+	parts := findKeysRe.FindAllStringSubmatch(tmpl, -1)
+	keys := make(map[string]struct{})
+	for _, part := range parts {
+		keys[part[1]] = struct{}{}
+	}
+	out := make([]string, len(keys))
+	var i int
+	for key := range keys {
+		out[i] = key
+		i++
+	}
+	return out
+}
+
+func loadConfigValues(keys []string) (map[string]string, error) {
+	kv := make(map[string]string, len(keys))
+	if len(keys) == 0 {
+		return kv, nil
+	}
+	ctx := context.Background()
+	if err := auth.RunAs(
+		ctx,
+		"sys_admin",
+		func(conn *sql.Conn) error {
+			stmt, err := conn.PrepareContext(ctx, selectConfigValSQL)
+			if err != nil {
+				return err
+			}
+			defer stmt.Close()
+			for _, key := range keys {
+				var val string
+				if err := stmt.QueryRowContext(ctx, key).Scan(&val); err != nil {
+					return err
+				}
+				kv[key] = val
+			}
+			return nil
+		},
+	); err != nil {
+		return nil, err
+	}
+
+	return kv, nil
 }
 
 func templateContourLinesFunc(configKey string) func(string) (string, error) {
@@ -74,7 +149,7 @@
 		func(conn *sql.Conn) error {
 			return conn.QueryRowContext(
 				ctx,
-				selectClassBreaksSQL,
+				selectConfigValSQL,
 				configKey,
 			).Scan(&config)
 		},
--- a/schema/default_sysconfig.sql	Wed Aug 21 11:13:12 2019 +0200
+++ b/schema/default_sysconfig.sql	Wed Aug 21 11:47:18 2019 +0200
@@ -51,4 +51,7 @@
 INSERT INTO sys_admin.system_config VALUES ('fairwaydimensionslos3_fill','#ffffff66');
 INSERT INTO sys_admin.system_config VALUES ('waterwayprofiles_stroke','#0000ff80');
 
+INSERT INTO sys_admin.system_config VALUES ('distance_marks_fill', '#ff9999');
+INSERT INTO sys_admin.system_config VALUES ('distance_marks_stroke', '#6666ff');
+
 COMMIT;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/schema/updates/1109/01.distance_marks.sql	Wed Aug 21 11:47:18 2019 +0200
@@ -0,0 +1,2 @@
+INSERT INTO sys_admin.system_config VALUES ('distance_marks_fill', '#ff9999') ON CONFLICT (config_key) DO NOTHING;
+INSERT INTO sys_admin.system_config VALUES ('distance_marks_stroke', '#6666ff') ON CONFLICT (config_key) DO NOTHING;