Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions api/v2beta1/wfs_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func convertV2FeatureTypeToV3(src FeatureType) pdoknlv3.FeatureType {
MetadataIdentifier: src.DatasetMetadataIdentifier,
},
},
Data: pdoknlv3.Data{},
Data: pdoknlv3.BaseData{},
}

if src.Extent != nil {
Expand All @@ -186,7 +186,7 @@ func convertV2FeatureTypeToV3(src FeatureType) pdoknlv3.FeatureType {
}
}

featureTypeV3.Data = ConvertV2DataToV3(src.Data)
featureTypeV3.Data = ConvertV2DataToV3(src.Data).BaseData

return featureTypeV3
}
Expand Down Expand Up @@ -260,7 +260,7 @@ func (dst *WFS) ConvertFrom(srcRaw conversion.Hub) error {
Keywords: featureType.Keywords,
DatasetMetadataIdentifier: featureType.DatasetMetadataURL.CSW.MetadataIdentifier,
SourceMetadataIdentifier: "",
Data: ConvertV3DataToV2(featureType.Data),
Data: ConvertV3DataToV2(pdoknlv3.Data{BaseData: featureType.Data}),
}

if src.Spec.Service.Inspire != nil {
Expand Down
17 changes: 11 additions & 6 deletions api/v3/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,19 @@ type Custom struct {
Type string `json:"type"`
}

// Data holds the data source configuration
// +kubebuilder:validation:XValidation:rule="has(self.gpkg) || has(self.tif) || has(self.postgis)", message="Atleast one of the datasource should be provided (postgis, gpkg, tif)"
type Data struct {
// BaseData holds the data source configuration for gpkg and postgis
type BaseData struct {
// Gpkg configures a GeoPackage file source
Gpkg *Gpkg `json:"gpkg,omitempty"`

// Postgis configures a Postgis table source
Postgis *Postgis `json:"postgis,omitempty"`
}

// Data holds the data source configuration
// +kubebuilder:validation:XValidation:rule="has(self.gpkg) || has(self.tif) || has(self.postgis)", message="Atleast one of the datasource should be provided (postgis, gpkg, tif)"
type Data struct {
BaseData `json:",inline"`

// TIF configures a GeoTIF raster source
TIF *TIF `json:"tif,omitempty"`
Expand Down Expand Up @@ -276,7 +281,7 @@ func GetHost(includeProtocol bool) string {
return host
}

func (d *Data) GetColumns() *[]Column {
func (d *BaseData) GetColumns() *[]Column {
switch {
case d.Gpkg != nil:
return &d.Gpkg.Columns
Expand All @@ -287,7 +292,7 @@ func (d *Data) GetColumns() *[]Column {
}
}

func (d *Data) GetTableName() *string {
func (d *BaseData) GetTableName() *string {
switch {
case d.Gpkg != nil:
return &d.Gpkg.TableName
Expand All @@ -298,7 +303,7 @@ func (d *Data) GetTableName() *string {
}
}

func (d *Data) GetGeometryType() *string {
func (d *BaseData) GetGeometryType() *string {
switch {
case d.Gpkg != nil:
return &d.Gpkg.GeometryType
Expand Down
2 changes: 1 addition & 1 deletion api/v3/shared_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func ValidateUpdate[W WMSWFS](c client.Client, newW, oldW W, validate func(W, *[
allErrs := field.ErrorList{}

// Make sure no ingressRouteURLs have been removed
sharedValidation.ValidateIngressRouteURLsNotRemoved(oldW.IngressRouteURLs(true), newW.IngressRouteURLs(true), &allErrs, nil)
sharedValidation.ValidateIngressRouteURLsNotRemoved(oldW.IngressRouteURLs(false), newW.IngressRouteURLs(true), &allErrs, nil)

if len(newW.IngressRouteURLs(false)) == 0 {
// There are no ingressRouteURLs given, spec.service.url is immutable is that case.
Expand Down
3 changes: 2 additions & 1 deletion api/v3/wfs_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ type FeatureType struct {

// FeatureType data connection
// +kubebuilder:validation:Type=object
Data Data `json:"data"`
// +kubebuilder:validation:XValidation:rule="has(self.gpkg) || has(self.postgis)", message="At least one of the datasource should be provided (postgis, gpkg)"
Data BaseData `json:"data"`
}

// FeatureBbox is the optional featureType bounding box, if provided it overrides the default extent
Expand Down
45 changes: 11 additions & 34 deletions api/v3/wfs_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,20 @@ func ValidateWFS(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {
path := field.NewPath("spec").Child("service")

if service.Mapfile == nil && service.DefaultCrs != "EPSG:28992" && service.Bbox == nil {
*allErrs = append(*allErrs, field.Required(path.Child("bbox").Child("defaultCRS"), "when service.defaultCRS is not 'EPSG:28992'"))
*allErrs = append(*allErrs, field.Required(
path.Child("bbox").Child("defaultCRS"),
"when service.defaultCRS is not 'EPSG:28992'",
))
}

if service.Mapfile != nil && service.Bbox != nil {
sharedValidation.AddWarning(warnings, *path.Child("bbox"), "is not used when service.mapfile is configured", wfs.GroupVersionKind(), wfs.GetName())
sharedValidation.AddWarning(
warnings,
*path.Child("bbox"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

ValidateInspire(wfs, allErrs)
Expand Down Expand Up @@ -76,37 +85,5 @@ func ValidateFeatureTypes(wfs *WFS, warnings *[]string, allErrs *field.ErrorList
)
}

if tif := featureType.Data.TIF; tif != nil {
if tif.Resample != "NEAREST" {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("resample"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

if tif.Offsite != nil {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("offsite"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}

if tif.GetFeatureInfoIncludesClass {
sharedValidation.AddWarning(
warnings,
*path.Index(index).Child("data").Child("tif").Child("getFeatureInfoIncludesClass"),
"is not used when service.mapfile is configured",
wfs.GroupVersionKind(),
wfs.GetName(),
)
}
}

}
}
92 changes: 37 additions & 55 deletions api/v3/wms_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ type WMSSpec struct {
Service WMSService `json:"service"`
}

// +kubebuilder:validation:XValidation:message="service requires styling, either through service.mapfile, or stylingAssets.configMapRefs",rule=has(self.mapfile) || (has(self.stylingAssets) && has(self.stylingAssets.configMapRefs))
// +kubebuilder:validation:XValidation:message="when using service.mapfile, don't include stylingAssets.configMapRefs",rule=!has(self.mapfile) || (!has(self.stylingAssets) || !has(self.stylingAssets.configMapRefs))
type WMSService struct {
BaseService `json:",inline"`

Expand Down Expand Up @@ -187,9 +189,9 @@ type ConfigMapRef struct {

// +kubebuilder:validation:XValidation:message="A layer should have exactly one of sublayers or data", rule="(has(self.data) || has(self.layers)) && !(has(self.data) && has(self.layers))"
// +kubebuilder:validation:XValidation:message="A layer with data attribute should have styling", rule="!has(self.data) || has(self.styles)"
// +kubebuilder:validation:XValidation:message="A layer should have keywords when visible", rule="!self.visible || has(self.keywords)"
// +kubebuilder:validation:XValidation:message="A layer should have a title when visible", rule="!self.visible || has(self.title)"
// +kubebuilder:validation:XValidation:message="A layer should have an abstract when visible", rule="!self.visible || has(self.abstract)"
// +kubebuilder:validation:XValidation:message="A layer should have keywords when visible", rule="!self.visible || has(self.keywords)"
type Layer struct {
// Name of the layer, required for layers on the 2nd or 3rd level
// +kubebuilder:validation:MinLength:=1
Expand Down Expand Up @@ -326,7 +328,7 @@ type WMSOptions struct {
func (wmsService *WMSService) GetBoundingBox() WMSBoundingBox {
var boundingBox *WMSBoundingBox

allLayers := wmsService.GetAllLayers()
allLayers := wmsService.GetAnnotatedLayers()
for _, layer := range allLayers {
if len(layer.BoundingBoxes) > 0 {
for _, bbox := range wmsService.Layer.BoundingBoxes {
Expand Down Expand Up @@ -354,6 +356,16 @@ func (wmsService *WMSService) GetBoundingBox() WMSBoundingBox {
}
}

func (stylingAssets *StylingAssets) GetAllConfigMapRefKeys() []string {
keys := []string{}
if stylingAssets != nil {
for _, cmRef := range stylingAssets.ConfigMapRefs {
keys = append(keys, cmRef.Keys...)
}
}
return keys
}

type AnnotatedLayer struct {
// The name of the group that this layer belongs to, nil if it is not a member of a group. Groups can be a member of the toplayer as a group
GroupName *string
Expand All @@ -363,62 +375,43 @@ type AnnotatedLayer struct {
IsGroupLayer bool
// Contains actual data
IsDataLayer bool
Layer Layer
Layer
}

func (wmsService *WMSService) GetAnnotatedLayers() []AnnotatedLayer {
result := make([]AnnotatedLayer, 0)

if wmsService.Layer.Name != nil && len(*wmsService.Layer.Name) > 0 {
firstLayer := AnnotatedLayer{
GroupName: nil,
IsTopLayer: wmsService.Layer.IsTopLayer(),
IsGroupLayer: wmsService.Layer.IsGroupLayer(),
IsDataLayer: wmsService.Layer.IsDataLayer(),
Layer: wmsService.Layer,
}
result = append(result, firstLayer)
}
result = append(result, AnnotatedLayer{
GroupName: nil,
IsTopLayer: true,
IsGroupLayer: true,
IsDataLayer: false,
Layer: wmsService.Layer,
})

for _, subLayer := range wmsService.Layer.Layers {
groupName := wmsService.Layer.Name
isGroupLayer := subLayer.IsGroupLayer()
isDataLayer := !isGroupLayer
for _, middleLayer := range wmsService.Layer.Layers {
result = append(result, AnnotatedLayer{
GroupName: groupName,
GroupName: wmsService.Layer.Name,
IsTopLayer: false,
IsGroupLayer: isGroupLayer,
IsDataLayer: isDataLayer,
Layer: subLayer,
IsGroupLayer: middleLayer.IsGroupLayer(),
IsDataLayer: middleLayer.IsDataLayer(),
Layer: middleLayer,
})

for _, subSubLayer := range subLayer.Layers {
for _, bottomLayer := range middleLayer.Layers {
result = append(result, AnnotatedLayer{
GroupName: subLayer.Name,
GroupName: middleLayer.Name,
IsTopLayer: false,
IsGroupLayer: false,
IsDataLayer: true,
Layer: subSubLayer,
Layer: bottomLayer,
})
}
}

return result
}

func (wmsService *WMSService) GetAllLayers() (layers []Layer) {
return wmsService.Layer.FlattenLayers()
}

// FlattenLayers - flattens the layer and its sublayers into one array
func (layer *Layer) FlattenLayers() []Layer {
layers := []Layer{*layer}
for _, childLayer := range layer.Layers {
layers = append(layers, childLayer.FlattenLayers()...)
}
return layers
}

// GetAllSublayers - get all sublayers of a layer, the result does not include the layer itself
func (layer *Layer) GetAllSublayers() []Layer {
layers := layer.Layers
Expand Down Expand Up @@ -469,17 +462,6 @@ func (layer *Layer) hasTIFData() bool {
return layer.Data.TIF != nil && layer.Data.TIF.BlobKey != ""
}

func (layer *Layer) GetLayerType(service *WMSService) (layerType string) {
switch {
case layer.IsDataLayer():
return DataLayer
case layer.Name == service.Layer.Name:
return TopLayer
default:
return GroupLayer
}
}

func (layer *Layer) IsDataLayer() bool {
return layer.hasData() && len(layer.Layers) == 0
}
Expand Down Expand Up @@ -530,8 +512,8 @@ func (layer *Layer) setInheritedBoundingBoxes() {
layer.Layers = updatedLayers
}

func (wms *WMS) GetAllLayersWithLegend() (layers []Layer) {
for _, layer := range wms.Spec.Service.GetAllLayers() {
func (wms *WMS) GetAllLayersWithLegend() (layers []AnnotatedLayer) {
for _, layer := range wms.Spec.Service.GetAnnotatedLayers() {
if !layer.hasData() || len(layer.Styles) == 0 {
continue
}
Expand All @@ -547,7 +529,7 @@ func (wms *WMS) GetAllLayersWithLegend() (layers []Layer) {

func (wms *WMS) GetUniqueTiffBlobKeys() []string {
blobKeys := map[string]bool{}
for _, layer := range wms.Spec.Service.GetAllLayers() {
for _, layer := range wms.Spec.Service.GetAnnotatedLayers() {
if layer.hasTIFData() {
blobKeys[layer.Data.TIF.BlobKey] = true
}
Expand Down Expand Up @@ -578,7 +560,7 @@ func (wms *WMS) GetAuthority() *Authority {
}

func (wms *WMS) HasPostgisData() bool {
for _, layer := range wms.Spec.Service.GetAllLayers() {
for _, layer := range wms.Spec.Service.GetAnnotatedLayers() {
if layer.Data != nil && layer.Data.Postgis != nil {
return true
}
Expand Down Expand Up @@ -639,7 +621,7 @@ func (wms *WMS) URL() smoothoperatormodel.URL {
func (wms *WMS) DatasetMetadataIDs() []string {
ids := []string{}

for _, layer := range wms.Spec.Service.GetAllLayers() {
for _, layer := range wms.Spec.Service.GetAnnotatedLayers() {
if layer.DatasetMetadataURL != nil && layer.DatasetMetadataURL.CSW != nil {
if id := layer.DatasetMetadataURL.CSW.MetadataIdentifier; !slices.Contains(ids, id) {
ids = append(ids, id)
Expand Down Expand Up @@ -684,8 +666,8 @@ func (wms *WMS) ReadinessQueryString() (string, string, error) {
}

firstDataLayerName := ""
for _, layer := range wms.Spec.Service.GetAllLayers() {
if layer.IsDataLayer() {
for _, layer := range wms.Spec.Service.GetAnnotatedLayers() {
if layer.IsDataLayer {
firstDataLayerName = *layer.Name
break
}
Expand Down
Loading
Loading