Skip to content

Commit 35265f4

Browse files
authored
Merge pull request #74 from PDOK/wr/validation
wfs service validation finished
2 parents 1285c6f + 031d06f commit 35265f4

31 files changed

+1701
-1661
lines changed

api/v2beta1/wfs_conversion.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,13 @@ func (src *WFS) ToV3(dst *pdoknlv3.WFS) error {
102102
AccessConstraints: smoothoperatormodel.URL{URL: accessConstraints},
103103
DefaultCrs: src.Spec.Service.DataEPSG,
104104
OtherCrs: []string{
105-
"EPSG::25831",
106-
"EPSG::25832",
107-
"EPSG::3034",
108-
"EPSG::3035",
109-
"EPSG::3857",
110-
"EPSG::4258",
111-
"EPSG::4326",
105+
"EPSG:25831",
106+
"EPSG:25832",
107+
"EPSG:3034",
108+
"EPSG:3035",
109+
"EPSG:3857",
110+
"EPSG:4258",
111+
"EPSG:4326",
112112
},
113113
FeatureTypes: make([]pdoknlv3.FeatureType, 0),
114114
}

api/v3/shared_types.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@ type WMSWFS interface {
4646
Options() Options
4747
HasPostgisData() bool
4848

49-
// URLPath returns the configured service URL
49+
// URL returns the configured service URL
5050
URL() smoothoperatormodel.URL
5151
IngressRouteURLs() smoothoperatormodel.IngressRouteURLs
5252

53+
// DatasetMetadataIds returns list of all configured metadata identifiers configured on Layers or Featuretypes
54+
DatasetMetadataIDs() []string
55+
5356
GeoPackages() []*Gpkg
5457

5558
ReadinessQueryString() (string, string, error)
@@ -115,18 +118,18 @@ type Inspire struct {
115118
ServiceMetadataURL MetadataURL `json:"serviceMetadataUrl"`
116119

117120
// SpatialDatasetIdentifier is the ID uniquely identifying the dataset.
118-
// +kubebuilder:validation:MinLength:=1
121+
// +kubebuilder:validation:Pattern:=`^[0-9a-zA-Z]{8}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{12}$`
119122
SpatialDatasetIdentifier string `json:"spatialDatasetIdentifier"`
120123

121124
// Language of the INSPIRE metadata record
122-
// +kubebuilder:validation:MinLength:=1
125+
// +kubebuilder:validation:Pattern:=`bul|cze|dan|dut|eng|est|fin|fre|ger|gre|hun|gle|ita|lav|lit|mlt|pol|por|rum|slo|slv|spa|swe`
123126
Language string `json:"language"`
124127
}
125128

126-
// +kubebuilder:validation:XValidation:rule="(has(self.csw) || has(self.custom)) && !(has(self.csw) && has(self.custom))", message="metadataUrl should have csw or custom, not both"
129+
// +kubebuilder:validation:XValidation:rule="(has(self.csw) || has(self.custom)) && !(has(self.csw) && has(self.custom))", message="metadataUrl should have exactly 1 of csw or custom"
127130
type MetadataURL struct {
128131
// CSW describes a metadata record via a metadataIdentifier (UUID) as defined in the OwnerInfo.
129-
CSW *Metadata `json:"csw"`
132+
CSW *Metadata `json:"csw,omitempty"`
130133

131134
// Custom allows arbitrary href
132135
Custom *Custom `json:"custom,omitempty"`
@@ -135,16 +138,15 @@ type MetadataURL struct {
135138
// Metadata holds the UUID of a CSW metadata record
136139
type Metadata struct {
137140
// MetadataIdentifier is the record's UUID
138-
// +kubebuilder:validation:MinLength:=1
141+
// +kubebuilder:validation:Pattern:=`^[0-9a-zA-Z]{8}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{4}\-[0-9a-zA-Z]{12}$`
139142
MetadataIdentifier string `json:"metadataIdentifier"`
140143
}
141144

142145
// Custom represents a non-CSW metadata link with a href and MIME type.
143146
// +kubebuilder:validation:Type=object
144147
type Custom struct {
145-
// +kubebuilder:validation:Pattern=`^https?://.*$`
146-
// +kubebuilder:validation:MinLength=1
147-
Href string `json:"href"`
148+
// Href of the custom metadata url
149+
Href smoothoperatormodel.URL `json:"href"`
148150

149151
// MIME type of the custom link
150152
// +kubebuilder:validation:MinLength=1

api/v3/shared_validation.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package v3
22

33
import (
44
"fmt"
5+
"slices"
56

67
sharedValidation "github.com/pdok/smooth-operator/pkg/validation"
78
v1 "k8s.io/api/core/v1"
@@ -82,3 +83,39 @@ func ValidateEphemeralStorage(podSpecPatch v1.PodSpec, allErrs *field.ErrorList)
8283
*allErrs = append(*allErrs, field.Required(path, ""))
8384
}
8485
}
86+
87+
func ValidateInspire[O WMSWFS](obj O, allErrs *field.ErrorList) {
88+
if obj.Inspire() == nil {
89+
return
90+
}
91+
92+
datasetIDs := obj.DatasetMetadataIDs()
93+
spatialID := obj.Inspire().SpatialDatasetIdentifier
94+
95+
if slices.Contains(datasetIDs, spatialID) {
96+
*allErrs = append(*allErrs, field.Invalid(
97+
field.NewPath("spec").Child("service").Child("inspire").Child("spatialDatasetIdentifier"),
98+
spatialID,
99+
"spatialDatasetIdentifier cannot also be used as an datasetMetadataUrl.csw.metadataIdentifier",
100+
))
101+
}
102+
103+
if serviceID := obj.Inspire().ServiceMetadataURL.CSW; serviceID != nil {
104+
if slices.Contains(datasetIDs, serviceID.MetadataIdentifier) {
105+
*allErrs = append(*allErrs, field.Invalid(
106+
field.NewPath("spec").Child("service").Child("inspire").Child("csw").Child("metadataIdentifier"),
107+
serviceID.MetadataIdentifier,
108+
"serviceMetadataUrl.csw.metadataIdentifier cannot also be used as an datasetMetadataUrl.csw.metadataIdentifier",
109+
))
110+
}
111+
112+
if spatialID == serviceID.MetadataIdentifier {
113+
*allErrs = append(*allErrs, field.Invalid(
114+
field.NewPath("spec").Child("service").Child("inspire").Child("csw").Child("metadataIdentifier"),
115+
serviceID.MetadataIdentifier,
116+
"serviceMetadataUrl.csw.metadataIdentifier cannot also be used as the spatialDatasetIdentifier",
117+
))
118+
}
119+
}
120+
121+
}

api/v3/wfs_types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ type WFSSpec struct {
9595
Service WFSService `json:"service"`
9696
}
9797

98+
// +kubebuilder:validation:XValidation:message="otherCrs can't contain the defaultCrs",rule="!has(self.otherCrs) || (has(self.otherCrs) && !(self.defaultCrs in self.otherCrs))",fieldPath=".otherCrs"
9899
type WFSService struct {
99100
// Geonovum subdomein
100101
// +kubebuilder:validation:MinLength:=1
@@ -141,6 +142,7 @@ type WFSService struct {
141142

142143
// Other supported CRS
143144
// +kubebuilder:validation:MinItems:=1
145+
// +kubebuilder:validation:items:Pattern:="^EPSG:(28992|25831|25832|3034|3035|3857|4258|4326)$"
144146
OtherCrs []string `json:"otherCrs,omitempty"`
145147

146148
// Service bounding box
@@ -283,6 +285,20 @@ func (wfs *WFS) URL() smoothoperatormodel.URL {
283285
return wfs.Spec.Service.URL
284286
}
285287

288+
func (wfs *WFS) DatasetMetadataIDs() []string {
289+
ids := []string{}
290+
291+
for _, featureType := range wfs.Spec.Service.FeatureTypes {
292+
if featureType.DatasetMetadataURL != nil && featureType.DatasetMetadataURL.CSW != nil {
293+
if id := featureType.DatasetMetadataURL.CSW.MetadataIdentifier; !slices.Contains(ids, id) {
294+
ids = append(ids, id)
295+
}
296+
}
297+
}
298+
299+
return ids
300+
}
301+
286302
func (wfs *WFS) GeoPackages() []*Gpkg {
287303
gpkgs := make([]*Gpkg, 0)
288304

api/v3/wfs_validation.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ func ValidateWFS(wfs *WFS, warnings *[]string, allErrs *field.ErrorList) {
6161
sharedValidation.AddWarning(warnings, *path.Child("bbox"), "is not used when service.mapfile is configured", wfs.GroupVersionKind(), wfs.GetName())
6262
}
6363

64+
ValidateInspire(wfs, allErrs)
65+
6466
if wfs.Spec.HorizontalPodAutoscalerPatch != nil {
6567
ValidateHorizontalPodAutoscalerPatch(*wfs.Spec.HorizontalPodAutoscalerPatch, allErrs)
6668
}

api/v3/wms_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,20 @@ func (wms *WMS) URL() smoothoperatormodel.URL {
629629
return wms.Spec.Service.URL
630630
}
631631

632+
func (wms *WMS) DatasetMetadataIDs() []string {
633+
ids := []string{}
634+
635+
for _, layer := range wms.Spec.Service.GetAllLayers() {
636+
if layer.DatasetMetadataURL != nil && layer.DatasetMetadataURL.CSW != nil {
637+
if id := layer.DatasetMetadataURL.CSW.MetadataIdentifier; !slices.Contains(ids, id) {
638+
ids = append(ids, id)
639+
}
640+
}
641+
}
642+
643+
return ids
644+
}
645+
632646
func (wms *WMS) GeoPackages() []*Gpkg {
633647
gpkgs := make([]*Gpkg, 0)
634648

api/v3/wms_validation.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ func ValidateWMS(wms *WMS, warnings *[]string, allErrs *field.ErrorList) {
296296
))
297297
}
298298

299+
ValidateInspire(wms, allErrs)
300+
299301
if wms.Spec.HorizontalPodAutoscalerPatch != nil {
300302
ValidateHorizontalPodAutoscalerPatch(*wms.Spec.HorizontalPodAutoscalerPatch, allErrs)
301303
}

api/v3/zz_generated.deepcopy.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)