view pkg/models/intservices.go @ 598:4854a1e85870

Ensure published service is based on existing table Using the OID of the table (via the regclass type) establishes a reference to the system catalogs, which will also allow to distinguish between tables in different schemas if such tables have to be published via different datastores in GeoServer.
author Tom Gottfried <tom@intevation.de>
date Fri, 07 Sep 2018 17:27:01 +0200
parents c10c76c92797
children ac325d191009
line wrap: on
line source

package models

import (
	"context"
	"database/sql"
	"log"
	"sync"

	"gemma.intevation.de/gemma/pkg/auth"
	"gemma.intevation.de/gemma/pkg/config"
)

type IntEntry struct {
	Name  string         `json:"name"`
	Style sql.NullString `json:"-"` // This should be done separately.
	WMS   bool           `json:"wms"`
	WFS   bool           `json:"wfs"`
}

type IntServices struct {
	entries []IntEntry
	mu      sync.Mutex
}

const selectPublishedServices = `SELECT relname, style, as_wms, as_wfs
FROM sys_admin.published_services JOIN pg_class ON name = oid ORDER by relname`

var InternalServices = &IntServices{}

func (ps *IntServices) Find(name string) (string, bool) {
	ps.mu.Lock()
	defer ps.mu.Unlock()

	if ps.entries == nil {
		if err := ps.load(); err != nil {
			log.Printf("error: %v\n", err)
			return "", false
		}
	}

	if ps.has(name) {
		return config.GeoServerURL() + "/" + name, true
	}
	return "", false
}

func (ps *IntServices) has(service string) bool {
	var check func(*IntEntry) bool
	switch service {
	case "wms":
		check = func(e *IntEntry) bool { return e.WMS }
	case "wfs":
		check = func(e *IntEntry) bool { return e.WFS }
	default:
		return false
	}
	for i := range ps.entries {
		if check(&ps.entries[i]) {
			return true
		}
	}
	return false
}

func (ps *IntServices) load() error {
	// make empty slice to prevent retry if slice is empty.
	ps.entries = []IntEntry{}
	return auth.RunAs("sys_admin", context.Background(),
		func(conn *sql.Conn) error {
			rows, err := conn.QueryContext(
				context.Background(), selectPublishedServices)
			if err != nil {
				return err
			}
			defer rows.Close()
			for rows.Next() {
				var entry IntEntry
				if err := rows.Scan(
					&entry.Name, &entry.Style,
					&entry.WFS, &entry.WFS,
				); err != nil {
					return err
				}
				ps.entries = append(ps.entries, entry)
			}
			return rows.Err()
		})
	return nil
}

func (ps *IntServices) Invalidate() {
	ps.mu.Lock()
	ps.entries = nil
	ps.mu.Unlock()
}

func InternalAll(IntEntry) bool  { return true }
func IntWMS(entry IntEntry) bool { return entry.WMS }
func IntWFS(entry IntEntry) bool { return entry.WFS }

func (ps *IntServices) Filter(accept func(IntEntry) bool) []IntEntry {
	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
		}
	}
	pe := make([]IntEntry, 0, len(ps.entries))
	for _, e := range ps.entries {
		if accept(e) {
			pe = append(pe, e)
		}
	}

	return pe
}