diff pkg/controllers/geostyling.go @ 871:f0b6852c14d1 geo-style

More on uploading styles to gemma.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 30 Sep 2018 11:49:23 +0200
parents 29c11f4bf9db
children ad9272460ef3
line wrap: on
line diff
--- a/pkg/controllers/geostyling.go	Sat Sep 29 23:33:14 2018 +0200
+++ b/pkg/controllers/geostyling.go	Sun Sep 30 11:49:23 2018 +0200
@@ -2,9 +2,16 @@
 
 import (
 	"bytes"
+	"database/sql"
+	"fmt"
 	"io"
 	"log"
 	"net/http"
+	"strings"
+
+	"gemma.intevation.de/gemma/pkg/auth"
+	"gemma.intevation.de/gemma/pkg/models"
+	"github.com/gorilla/mux"
 )
 
 const (
@@ -12,6 +19,65 @@
 	styleName    = "style"
 )
 
+const (
+	replaceNameXSLT = `<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:sld="http://www.opengis.net/sld"
+  xmlns:se="http://www.opengis.net/se">
+
+  <xsl:param name="name"/>
+
+  <xsl:template
+    match="/sld:StyledLayerDescriptor/sld:NamedLayer/sld:Name/text()">
+	<xsl:value-of select="$name"/>
+  </xsl:template>
+
+  <xsl:template
+    match="/sld:StyledLayerDescriptor/sld:NamedLayer/se:Name/text()">
+	<xsl:value-of select="$name"/>
+  </xsl:template>
+
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+</xsl:stylesheet>`
+
+	xsltSQL = `SELECT xslt_process($1, $2, $3)`
+)
+
+func runXSLT(
+	req *http.Request,
+	document, stylesheet string,
+	params ...string,
+) (string, error) {
+	var result string
+
+	var args strings.Builder
+
+	for len(params) > 1 {
+		if args.Len() > 0 {
+			args.WriteByte(',')
+		}
+		fmt.Fprintf(&args, "%s='%s'",
+			strings.Replace(params[0], ",", "", -1),
+			strings.Replace(params[1], ",", "", -1))
+		params = params[2:]
+	}
+
+	log.Printf("params: %s\n", args.String())
+
+	err := auth.RunAsSessionUser(req, func(conn *sql.Conn) error {
+		return conn.QueryRowContext(
+			req.Context(), xsltSQL,
+			document, stylesheet, args.String()).Scan(&result)
+	})
+
+	return result, err
+}
+
 func extractStyle(req *http.Request) ([]byte, error) {
 
 	f, _, err := req.FormFile(styleName)
@@ -28,15 +94,46 @@
 	return buf.Bytes(), nil
 }
 
+func supportedWMSFeature(name string) bool {
+	return len(models.InternalServices.Filter(
+		models.IntAnd(models.IntWMS, models.IntByName(name)))) > 0
+}
+
 func uploadStyle(rw http.ResponseWriter, req *http.Request) {
 
-	data, err := extractStyle(req)
+	feature := mux.Vars(req)["feature"]
+
+	// only allow internal WMS features
+	if !supportedWMSFeature(feature) {
+		http.Error(rw,
+			fmt.Sprintf("WMS feature %s is not found.", feature),
+			http.StatusNotFound)
+		return
+	}
+
+	style, err := extractStyle(req)
 	if err != nil {
 		log.Printf("error: %v\n", err)
 		http.Error(rw, "error: "+err.Error(), http.StatusBadRequest)
 		return
 	}
 
-	log.Printf("uploaded file length: %d\n", len(data))
-	// TODO: Implement me!
+	log.Printf("uploaded file length: %d\n", len(style))
+
+	result, err := runXSLT(
+		req, string(style), replaceNameXSLT, "name", feature)
+
+	if err != nil {
+		log.Printf("error: %v\n", err)
+		http.Error(rw, "error: "+err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	if err := models.UpdateInternalStyle(feature, result); err != nil {
+		log.Printf("error: %v\n", err)
+		http.Error(rw, "error: "+err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	// TODO: Configure GeoServer
 }