changeset 4935:c64dba002726 fairway-marks-import

Load and prepare data models for layer groups. TODO: Feed config to GeoServer.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 16 Feb 2020 15:16:22 +0100
parents c6af373b0832
children 21a48e2d2260
files pkg/auth/opendb.go pkg/controllers/publish.go pkg/geoserver/boot.go pkg/models/intservices.go
diffstat 4 files changed, 145 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/auth/opendb.go	Sat Feb 15 21:29:38 2020 +0100
+++ b/pkg/auth/opendb.go	Sun Feb 16 15:16:22 2020 +0100
@@ -145,6 +145,24 @@
 	return fn(conn)
 }
 
+// RunAllAs runs the given functions fns with a database connection impersonated
+// as the given role.
+// To make this work a metamorphic user has to be configured in
+// the system configuration.
+func RunAllAs(ctx context.Context, role string, fns ...func(*sql.Conn) error) error {
+	conn, err := metamorphConn(ctx, role)
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+	for _, fn := range fns {
+		if err := fn(conn); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // RunAsSessionUser is a convinience wrapper araound which extracts
 // the logged in user from a session and calls RunAs with it.
 func RunAsSessionUser(req *http.Request, fn func(*sql.Conn) error) error {
--- a/pkg/controllers/publish.go	Sat Feb 15 21:29:38 2020 +0100
+++ b/pkg/controllers/publish.go	Sun Feb 16 15:16:22 2020 +0100
@@ -24,11 +24,13 @@
 func published(req *http.Request) (mw.JSONResult, error) {
 	return mw.JSONResult{
 		Result: struct {
-			Internal []models.IntEntry `json:"internal"`
-			External []models.ExtEntry `json:"external"`
+			Internal    []models.IntEntry   `json:"internal"`
+			LayerGroups []models.LayerGroup `json:"layer-groups"`
+			External    []models.ExtEntry   `json:"external"`
 		}{
-			Internal: models.InternalServices.Filter(models.InternalAll),
-			External: models.ExternalServices.Filter(models.ExternalAll),
+			Internal:    models.InternalServices.Filter(models.InternalAll),
+			LayerGroups: models.InternalServices.LayerGroups(),
+			External:    models.ExternalServices.Filter(models.ExternalAll),
 		},
 	}, nil
 }
--- a/pkg/geoserver/boot.go	Sat Feb 15 21:29:38 2020 +0100
+++ b/pkg/geoserver/boot.go	Sun Feb 16 15:16:22 2020 +0100
@@ -385,6 +385,29 @@
 	return nil
 }
 
+func ensureLayerGroups() error {
+
+	groups := models.InternalServices.LayerGroups()
+	if len(groups) == 0 {
+		log.Println("info: no groups layers to publish")
+		return nil
+	}
+
+	log.Printf("info: number of layer groups to publish %d\n", len(groups))
+	// TODO: Implement me!
+
+	/*
+		for i := range groups {
+			log.Printf("info: layer group #%d: %s\n", i+1, groups[i].Name)
+			for _, layer := range groups[i].Layers {
+				log.Printf("info: layer: %s\n", layer)
+			}
+		}
+	*/
+
+	return nil
+}
+
 func deleteWorkspace() error {
 
 	// Should we delete our workspace first?
@@ -689,6 +712,7 @@
 		ensureWorkspace,
 		ensureDataStore,
 		ensureFeatures,
+		ensureLayerGroups,
 		ensureStyles,
 	} {
 		if err := ensure(); err != nil {
--- a/pkg/models/intservices.go	Sat Feb 15 21:29:38 2020 +0100
+++ b/pkg/models/intservices.go	Sun Feb 16 15:16:22 2020 +0100
@@ -27,21 +27,29 @@
 
 const DatabaseScheme = "waterway"
 
-type IntEntry struct {
-	Schema    string  `json:"schema"`
-	Name      string  `json:"name"`
-	SQL       *string `json:"sql"`
-	KeyColumn *string `json:"keycolumn"`
-	SRS       *string `json:"srs"`
-	Style     bool    `json:"style"`
-	WMS       bool    `json:"wms"`
-	WFS       bool    `json:"wfs"`
-}
+type (
+	IntEntry struct {
+		Schema    string  `json:"schema"`
+		Name      string  `json:"name"`
+		SQL       *string `json:"sql"`
+		KeyColumn *string `json:"keycolumn"`
+		SRS       *string `json:"srs"`
+		Style     bool    `json:"style"`
+		WMS       bool    `json:"wms"`
+		WFS       bool    `json:"wfs"`
+	}
 
-type IntServices struct {
-	entries []IntEntry
-	mu      sync.Mutex
-}
+	LayerGroup struct {
+		Name   string   `json:"name"`
+		Layers []string `json:"layers"`
+	}
+
+	IntServices struct {
+		mu          sync.Mutex
+		entries     []IntEntry
+		layerGroups []LayerGroup
+	}
+)
 
 const (
 	selectServicesSQL = `
@@ -53,6 +61,11 @@
 WHERE schema = $1
 ORDER by name`
 
+	selectGroupedLayersSQL = `
+SELECT group_name, name
+FROM sys_admin.grouped_layers
+ORDER BY group_name, ord`
+
 	selectStyleSQL = `
 SELECT style
 FROM sys_admin.published_services
@@ -91,6 +104,28 @@
 	})
 }
 
+func (ps *IntServices) LayerGroups() []LayerGroup {
+	ps.mu.Lock()
+	defer ps.mu.Unlock()
+
+	if ps.entries == nil {
+		if err := ps.load(); err != nil {
+			log.Printf("error: %v\n", err)
+			return nil
+		}
+	}
+
+	// To avoid races we simple make a deep copy.
+	// As we don't have such many of them it light weight enough for now.
+	groups := make([]LayerGroup, len(ps.layerGroups))
+	for i := range groups {
+		layers := make([]string, len(ps.layerGroups[i].Layers))
+		copy(layers, ps.layerGroups[i].Layers)
+		groups[i] = LayerGroup{Name: ps.layerGroups[i].Name, Layers: layers}
+	}
+	return groups
+}
+
 func (ps *IntServices) Find(name string) (string, bool) {
 	ps.mu.Lock()
 	defer ps.mu.Unlock()
@@ -129,33 +164,63 @@
 func (ps *IntServices) load() error {
 	// make empty slice to prevent retry if slice is empty.
 	ps.entries = []IntEntry{}
+	ps.layerGroups = []LayerGroup{}
 	ctx := context.Background()
-	return auth.RunAs(ctx, "sys_admin",
-		func(conn *sql.Conn) error {
-			rows, err := conn.QueryContext(
-				ctx, selectServicesSQL, DatabaseScheme)
-			if err != nil {
+
+	// Load the internal layers.
+	entries := func(conn *sql.Conn) error {
+		rows, err := conn.QueryContext(
+			ctx, selectServicesSQL, DatabaseScheme)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+		for rows.Next() {
+			var entry IntEntry
+			if err := rows.Scan(
+				&entry.Schema, &entry.Name,
+				&entry.SQL, &entry.KeyColumn, &entry.SRS, &entry.Style,
+				&entry.WMS, &entry.WFS,
+			); err != nil {
 				return err
 			}
-			defer rows.Close()
-			for rows.Next() {
-				var entry IntEntry
-				if err := rows.Scan(
-					&entry.Schema, &entry.Name,
-					&entry.SQL, &entry.KeyColumn, &entry.SRS, &entry.Style,
-					&entry.WMS, &entry.WFS,
-				); err != nil {
-					return err
-				}
-				ps.entries = append(ps.entries, entry)
+			ps.entries = append(ps.entries, entry)
+		}
+		return rows.Err()
+	}
+
+	// Load the layer groups.
+	groups := func(conn *sql.Conn) error {
+		rows, err := conn.QueryContext(ctx, selectGroupedLayersSQL)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			var group, layer string
+			if err := rows.Scan(&group, &layer); err != nil {
+				return err
 			}
-			return rows.Err()
-		})
+			if n := len(ps.layerGroups); n > 0 && ps.layerGroups[n-1].Name == group {
+				ps.layerGroups[n-1].Layers = append(ps.layerGroups[n-1].Layers, layer)
+			} else {
+				ps.layerGroups = append(ps.layerGroups, LayerGroup{
+					Name:   group,
+					Layers: []string{layer},
+				})
+			}
+		}
+		return rows.Err()
+	}
+
+	return auth.RunAllAs(ctx, "sys_admin", entries, groups)
 }
 
 func (ps *IntServices) Invalidate() {
 	ps.mu.Lock()
 	ps.entries = nil
+	ps.layerGroups = nil
 	ps.mu.Unlock()
 }