diff --git a/python/server/qgsserverprojectutils.sip b/python/server/qgsserverprojectutils.sip index 8fa1ed5e480..7584fbb06d1 100644 --- a/python/server/qgsserverprojectutils.sip +++ b/python/server/qgsserverprojectutils.sip @@ -123,6 +123,30 @@ namespace QgsServerProjectUtils */ QString wfsServiceUrl( const QgsProject& project ); + /** Returns the Layer ids list defined in a QGIS project as published in WFS. + * @param project the QGIS project + * @return the Layer ids list. + */ + QStringList wfsLayerIds( const QgsProject& project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + QStringList wfstUpdateLayerIds( const QgsProject& project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + QStringList wfstInsertLayerIds( const QgsProject& project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + QStringList wfstDeleteLayerIds( const QgsProject& project ); + /** Returns the WCS service url defined in a QGIS project. * @param project the QGIS project * @return url if defined in project, an empty string otherwise. diff --git a/src/server/qgsserverprojectutils.cpp b/src/server/qgsserverprojectutils.cpp index f95b376a75a..d56d25f9084 100644 --- a/src/server/qgsserverprojectutils.cpp +++ b/src/server/qgsserverprojectutils.cpp @@ -97,6 +97,31 @@ QString QgsServerProjectUtils::wfsServiceUrl( const QgsProject &project ) return project.readEntry( QStringLiteral( "WFSUrl" ), QStringLiteral( "/" ), "" ); } +QStringList QgsServerProjectUtils::wfsLayerIds( const QgsProject &project ) +{ + return project.readListEntry( QStringLiteral( "WFSLayers" ), QStringLiteral( "/" ) ); +} + +int QgsServerProjectUtils::wfsLayerPrecision( const QString &layerId, const QgsProject &project ) +{ + return project.readNumEntry( QStringLiteral( "WFSLayersPrecision" ), "/" + layerId, 6 ); +} + +QStringList QgsServerProjectUtils::wfstUpdateLayerIds( const QgsProject &project ) +{ + return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Update" ) ); +} + +QStringList QgsServerProjectUtils::wfstInsertLayerIds( const QgsProject &project ) +{ + return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Insert" ) ); +} + +QStringList QgsServerProjectUtils::wfstDeleteLayerIds( const QgsProject &project ) +{ + return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Delete" ) ); +} + QString QgsServerProjectUtils::wcsServiceUrl( const QgsProject &project ) { return project.readEntry( QStringLiteral( "WCSUrl" ), QStringLiteral( "/" ), "" ); diff --git a/src/server/qgsserverprojectutils.h b/src/server/qgsserverprojectutils.h index 5c1c5a5dfd4..266b97908c1 100644 --- a/src/server/qgsserverprojectutils.h +++ b/src/server/qgsserverprojectutils.h @@ -125,6 +125,32 @@ namespace QgsServerProjectUtils */ SERVER_EXPORT QString wfsServiceUrl( const QgsProject &project ); + /** Returns the Layer ids list defined in a QGIS project as published in WFS. + * @param project the QGIS project + * @return the Layer ids list. + */ + SERVER_EXPORT QStringList wfsLayerIds( const QgsProject &project ); + + SERVER_EXPORT int wfsLayerPrecision( const QString &layerId, const QgsProject &project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + SERVER_EXPORT QStringList wfstUpdateLayerIds( const QgsProject &project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + SERVER_EXPORT QStringList wfstInsertLayerIds( const QgsProject &project ); + + /** Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities. + * @param project the QGIS project + * @return the Layer ids list. + */ + SERVER_EXPORT QStringList wfstDeleteLayerIds( const QgsProject &project ); + /** Returns the WCS service url defined in a QGIS project. * \param project the QGIS project * \returns url if defined in project, an empty string otherwise. diff --git a/src/server/services/wfs/qgswfs.cpp b/src/server/services/wfs/qgswfs.cpp index 9243258f052..0f9265b1d4f 100644 --- a/src/server/services/wfs/qgswfs.cpp +++ b/src/server/services/wfs/qgswfs.cpp @@ -78,7 +78,7 @@ namespace QgsWfs } else if ( QSTR_COMPARE( req, "DescribeFeatureType" ) ) { - writeDescribeFeatureType( mServerIface, versionString, request, response ); + writeDescribeFeatureType( mServerIface, project, versionString, request, response ); } else if ( QSTR_COMPARE( req, "Transaction" ) ) { diff --git a/src/server/services/wfs/qgswfsdescribefeaturetype.cpp b/src/server/services/wfs/qgswfsdescribefeaturetype.cpp index 68e5384d0a0..85eb74b4e80 100644 --- a/src/server/services/wfs/qgswfsdescribefeaturetype.cpp +++ b/src/server/services/wfs/qgswfsdescribefeaturetype.cpp @@ -19,31 +19,42 @@ * * ***************************************************************************/ #include "qgswfsutils.h" +#include "qgsserverprojectutils.h" #include "qgswfsdescribefeaturetype.h" +#include "qgsproject.h" +#include "qgscsexception.h" +#include "qgsvectorlayer.h" +#include "qgsvectordataprovider.h" +#include "qgsmapserviceexception.h" +#include "qgscoordinatereferencesystem.h" + +#include + namespace QgsWfs { - void writeDescribeFeatureType( QgsServerInterface *serverIface, const QString &version, + void writeDescribeFeatureType( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { - QDomDocument doc = createDescribeFeatureTypeDocument( serverIface, version, request ); + QDomDocument doc = createDescribeFeatureTypeDocument( serverIface, project, version, request ); response.setHeader( "Content-Type", "text/xml; charset=utf-8" ); response.write( doc.toByteArray() ); } - QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QString &version, + QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QDomDocument doc; - QgsWfsProjectParser *configParser = getConfigParser( serverIface ); QgsServerRequest::Parameters parameters = request.parameters(); + QgsAccessControl *accessControl = serverIface->accessControls(); + //xsd:schema QDomElement schemaElement = doc.createElement( QStringLiteral( "schema" )/*xsd:schema*/ ); schemaElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) ); @@ -62,9 +73,7 @@ namespace QgsWfs importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ) ); schemaElement.appendChild( importElement ); - //defining typename - QString typeName = QLatin1String( "" ); - + QStringList typeNameList; QDomDocument queryDoc; QString errorMsg; if ( queryDoc.setContent( parameters.value( QStringLiteral( "REQUEST_BODY" ) ), true, &errorMsg ) ) @@ -79,23 +88,208 @@ namespace QgsWfs QDomElement docChildElem = docChildNodes.at( i ).toElement(); if ( docChildElem.tagName() == QLatin1String( "TypeName" ) ) { - if ( typeName == QLatin1String( "" ) ) - typeName = docChildElem.text(); + QString typeName = docChildElem.text().trimmed(); + if ( typeName.contains( QLatin1String( ":" ) ) ) + typeNameList << typeName.section( QStringLiteral( ":" ), 1, 1 ); else - typeName += "," + docChildElem.text(); + typeNameList << typeName; } } } } else { - typeName = request.getParameter( QStringLiteral( "TYPENAME" ) ); + QString typeNames = request.getParameter( QStringLiteral( "TYPENAME" ) ); + if ( !typeNames.isEmpty() ) + { + QStringList typeNameSplit = typeNames.split( QStringLiteral( "," ) ); + for ( int i = 0; i < typeNameSplit.size(); ++i ) + { + QString typeName = typeNameSplit.at( i ).trimmed(); + if ( typeName.contains( QLatin1String( ":" ) ) ) + typeNameList << typeName.section( QStringLiteral( ":" ), 1, 1 ); + else + typeNameList << typeName; + } + } } - configParser->describeFeatureType( typeName, schemaElement, doc ); + QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project ); + for ( int i = 0; i < wfsLayerIds.size(); ++i ) + { + QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) ); + if ( layer->type() != QgsMapLayer::LayerType::VectorLayer ) + { + continue; + } + + QString name = layer->name(); + if ( !layer->shortName().isEmpty() ) + name = layer->shortName(); + name = name.replace( QLatin1String( " " ), QLatin1String( "_" ) ); + + if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) ) + { + continue; + } + + if ( accessControl && !accessControl->layerReadPermission( layer ) ) + { + if ( !typeNameList.isEmpty() ) + { + throw QgsSecurityAccessException( QStringLiteral( "Feature access permission denied" ) ); + } + else + { + continue; + } + } + + QgsVectorLayer *vLayer = qobject_cast( layer ); + QgsVectorDataProvider *provider = vLayer->dataProvider(); + if ( !provider ) + { + continue; + } + setSchemaLayer( schemaElement, doc, const_cast( vLayer ) ); + } return doc; } + void setSchemaLayer( QDomElement &parentElement, QDomDocument &doc, const QgsVectorLayer *layer ) + { + const QgsVectorDataProvider *provider = layer->dataProvider(); + if ( !provider ) + { + return; + } + + QString typeName = layer->name(); + if ( !layer->shortName().isEmpty() ) + typeName = layer->shortName(); + typeName = typeName.replace( QLatin1String( " " ), QLatin1String( "_" ) ); + + //xsd:element + QDomElement elementElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ ); + elementElem.setAttribute( QStringLiteral( "name" ), typeName ); + elementElem.setAttribute( QStringLiteral( "type" ), "qgs:" + typeName + "Type" ); + elementElem.setAttribute( QStringLiteral( "substitutionGroup" ), QStringLiteral( "gml:_Feature" ) ); + parentElement.appendChild( elementElem ); + + //xsd:complexType + QDomElement complexTypeElem = doc.createElement( QStringLiteral( "complexType" )/*xsd:complexType*/ ); + complexTypeElem.setAttribute( QStringLiteral( "name" ), typeName + "Type" ); + parentElement.appendChild( complexTypeElem ); + + //xsd:complexType + QDomElement complexContentElem = doc.createElement( QStringLiteral( "complexContent" )/*xsd:complexContent*/ ); + complexTypeElem.appendChild( complexContentElem ); + + //xsd:extension + QDomElement extensionElem = doc.createElement( QStringLiteral( "extension" )/*xsd:extension*/ ); + extensionElem.setAttribute( QStringLiteral( "base" ), QStringLiteral( "gml:AbstractFeatureType" ) ); + complexContentElem.appendChild( extensionElem ); + + //xsd:sequence + QDomElement sequenceElem = doc.createElement( QStringLiteral( "sequence" )/*xsd:sequence*/ ); + extensionElem.appendChild( sequenceElem ); + + //xsd:element + if ( layer->hasGeometryType() ) + { + QDomElement geomElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ ); + geomElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "geometry" ) ); + if ( provider->name() == QLatin1String( "ogr" ) ) + { + // because some ogr drivers (e.g. ESRI ShapeFile, GML) + // are not able to determine the geometry type of a layer. + // we set to GeometryType + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:GeometryPropertyType" ) ); + } + else + { + QgsWkbTypes::Type wkbType = layer->wkbType(); + switch ( wkbType ) + { + case QgsWkbTypes::Point25D: + case QgsWkbTypes::Point: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:PointPropertyType" ) ); + break; + case QgsWkbTypes::LineString25D: + case QgsWkbTypes::LineString: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:LineStringPropertyType" ) ); + break; + case QgsWkbTypes::Polygon25D: + case QgsWkbTypes::Polygon: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:PolygonPropertyType" ) ); + break; + case QgsWkbTypes::MultiPoint25D: + case QgsWkbTypes::MultiPoint: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiPointPropertyType" ) ); + break; + case QgsWkbTypes::MultiLineString25D: + case QgsWkbTypes::MultiLineString: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiLineStringPropertyType" ) ); + break; + case QgsWkbTypes::MultiPolygon25D: + case QgsWkbTypes::MultiPolygon: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiPolygonPropertyType" ) ); + break; + default: + geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:GeometryPropertyType" ) ); + break; + } + } + geomElem.setAttribute( QStringLiteral( "minOccurs" ), QStringLiteral( "0" ) ); + geomElem.setAttribute( QStringLiteral( "maxOccurs" ), QStringLiteral( "1" ) ); + sequenceElem.appendChild( geomElem ); + + //Attributes + const QgsFields &fields = layer->pendingFields(); + //hidden attributes for this layer + const QSet &layerExcludedAttributes = layer->excludeAttributesWfs(); + for ( int idx = 0; idx < fields.count(); ++idx ) + { + + QString attributeName = fields.at( idx ).name(); + //skip attribute if excluded from WFS publication + if ( layerExcludedAttributes.contains( attributeName ) ) + { + continue; + } + + //xsd:element + QDomElement attElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ ); + attElem.setAttribute( QStringLiteral( "name" ), attributeName ); + QVariant::Type attributeType = fields.at( idx ).type(); + if ( attributeType == QVariant::Int ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) ); + else if ( attributeType == QVariant::LongLong ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "long" ) ); + else if ( attributeType == QVariant::Double ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "double" ) ); + else if ( attributeType == QVariant::Bool ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "boolean" ) ); + else if ( attributeType == QVariant::Date ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) ); + else if ( attributeType == QVariant::Time ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) ); + else if ( attributeType == QVariant::DateTime ) + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) ); + else + attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "string" ) ); + + sequenceElem.appendChild( attElem ); + + QString alias = fields.at( idx ).alias(); + if ( !alias.isEmpty() ) + { + attElem.setAttribute( QStringLiteral( "alias" ), alias ); + } + } + } + } + } // samespace QgsWfs diff --git a/src/server/services/wfs/qgswfsdescribefeaturetype.h b/src/server/services/wfs/qgswfsdescribefeaturetype.h index 535147a487b..dc545278a5c 100644 --- a/src/server/services/wfs/qgswfsdescribefeaturetype.h +++ b/src/server/services/wfs/qgswfsdescribefeaturetype.h @@ -21,21 +21,25 @@ #ifndef QGSWFSDESCRIBEFEATURETYPE_H #define QGSWFSDESCRIBEFEATURETYPE_H +#include "qgsvectorlayer.h" + #include +#include namespace QgsWfs { + void setSchemaLayer( QDomElement& parentElement, QDomDocument& doc, const QgsVectorLayer* layer ); /** * Create get capabilities document */ - QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QString &version, - const QgsServerRequest &request ); + QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface* serverIface, const QgsProject* project, const QString& version, + const QgsServerRequest& request ); /** Output WFS GetCapabilities response */ - void writeDescribeFeatureType( QgsServerInterface *serverIface, const QString &version, - const QgsServerRequest &request, QgsServerResponse &response ); + void writeDescribeFeatureType( QgsServerInterface* serverIface, const QgsProject* project, const QString& version, + const QgsServerRequest& request, QgsServerResponse& response ); } // samespace QgsWfs diff --git a/src/server/services/wfs/qgswfsgetcapabilities.cpp b/src/server/services/wfs/qgswfsgetcapabilities.cpp index e778b181a1e..b0951492d62 100644 --- a/src/server/services/wfs/qgswfsgetcapabilities.cpp +++ b/src/server/services/wfs/qgswfsgetcapabilities.cpp @@ -19,8 +19,18 @@ * * ***************************************************************************/ #include "qgswfsutils.h" +#include "qgsserverprojectutils.h" #include "qgswfsgetcapabilities.h" +#include "qgsproject.h" +#include "qgscsexception.h" +#include "qgsvectorlayer.h" +#include "qgsvectordataprovider.h" +#include "qgsmapserviceexception.h" +#include "qgscoordinatereferencesystem.h" + +#include + namespace QgsWfs { @@ -44,8 +54,6 @@ namespace QgsWfs QDomDocument doc; - QgsWfsProjectParser *configParser = getConfigParser( serverIface ); - //wfs:WFS_Capabilities element QDomElement wfsCapabilitiesElement = doc.createElement( QStringLiteral( "WFS_Capabilities" )/*wms:WFS_Capabilities*/ ); wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE ); @@ -59,7 +67,9 @@ namespace QgsWfs wfsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) ); doc.appendChild( wfsCapabilitiesElement ); - configParser->serviceCapabilities( wfsCapabilitiesElement, doc ); + //configParser->serviceCapabilities( wfsCapabilitiesElement, doc ); + //INSERT Service + wfsCapabilitiesElement.appendChild( getServiceElement( doc, project ) ); //wfs:Capability element QDomElement capabilityElement = doc.createElement( QStringLiteral( "Capability" )/*wfs:Capability*/ ); @@ -125,19 +135,8 @@ namespace QgsWfs transactionDhcTypeElement.firstChild().firstChild().toElement().setTagName( QStringLiteral( "Post" ) ); transactionElement.appendChild( transactionDhcTypeElement ); - //wfs:FeatureTypeList element - QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ ); - wfsCapabilitiesElement.appendChild( featureTypeListElement ); - //wfs:Operations element - QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ ); - featureTypeListElement.appendChild( operationsElement ); - //wfs:Query element - QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ ); - operationsElement.appendChild( queryElement ); - /* - * Adding layer liste in featureTypeListElement - */ - configParser->featureTypeList( featureTypeListElement, doc ); + //wfs:FeatureTypeList + wfsCapabilitiesElement.appendChild( getFeatureTypeListElement( doc, serverIface, project ) ); /* * Adding ogc:Filter_Capabilities in capabilityElement @@ -169,6 +168,224 @@ namespace QgsWfs } + QDomElement getServiceElement( QDomDocument &doc, const QgsProject *project ) + { + //Service element + QDomElement serviceElem = doc.createElement( QStringLiteral( "Service" ) ); + + //Service name + QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) ); + QDomText nameText = doc.createTextNode( "WFS" ); + nameElem.appendChild( nameText ); + serviceElem.appendChild( nameElem ); + + QString title = QgsServerProjectUtils::owsServiceTitle( *project ); + if ( !title.isEmpty() ) + { + QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) ); + QDomText titleText = doc.createTextNode( title ); + titleElem.appendChild( titleText ); + serviceElem.appendChild( titleElem ); + } + + QString abstract = QgsServerProjectUtils::owsServiceAbstract( *project ); + if ( !abstract.isEmpty() ) + { + QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) ); + QDomText abstractText = doc.createCDATASection( abstract ); + abstractElem.appendChild( abstractText ); + serviceElem.appendChild( abstractElem ); + } + + QStringList keywords = QgsServerProjectUtils::owsServiceKeywords( *project ); + if ( !keywords.isEmpty() && !keywords.join( QStringLiteral( ", " ) ).isEmpty() ) + { + QDomElement keywordsElem = doc.createElement( QStringLiteral( "Keywords" ) ); + QDomText keywordsText = doc.createTextNode( keywords.join( QStringLiteral( ", " ) ) ); + keywordsElem.appendChild( keywordsText ); + serviceElem.appendChild( keywordsElem ); + } + + QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "OnlineResource" ) ); + QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project ); + if ( !onlineResource.isEmpty() ) + { + QDomText onlineResourceText = doc.createTextNode( onlineResource ); + onlineResourceElem.appendChild( onlineResourceText ); + } + serviceElem.appendChild( onlineResourceElem ); + + QString fees = QgsServerProjectUtils::owsServiceFees( *project ); + if ( !fees.isEmpty() ) + { + QDomElement feesElem = doc.createElement( QStringLiteral( "Fees" ) ); + QDomText feesText = doc.createTextNode( fees ); + feesElem.appendChild( feesText ); + serviceElem.appendChild( feesElem ); + } + + QString accessConstraints = QgsServerProjectUtils::owsServiceAccessConstraints( *project ); + if ( !accessConstraints.isEmpty() ) + { + QDomElement accessConstraintsElem = doc.createElement( QStringLiteral( "AccessConstraints" ) ); + QDomText accessConstraintsText = doc.createTextNode( accessConstraints ); + accessConstraintsElem.appendChild( accessConstraintsText ); + serviceElem.appendChild( accessConstraintsElem ); + } + + return serviceElem; + + } + + QDomElement getFeatureTypeListElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project ) + { + QgsAccessControl *accessControl = serverIface->accessControls(); + + //wfs:FeatureTypeList element + QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ ); + //wfs:Operations element + QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ ); + featureTypeListElement.appendChild( operationsElement ); + //wfs:Query element + QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ ); + operationsElement.appendChild( queryElement ); + + QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project ); + QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project ); + QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project ); + QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project ); + for ( int i = 0; i < wfsLayerIds.size(); ++i ) + { + QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) ); + if ( layer->type() != QgsMapLayer::LayerType::VectorLayer ) + { + continue; + } + if ( accessControl && !accessControl->layerReadPermission( layer ) ) + { + continue; + } + + QDomElement layerElem = doc.createElement( QStringLiteral( "FeatureType" ) ); + + //create Name + QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) ); + QString typeName = layer->name(); + if ( !layer->shortName().isEmpty() ) + typeName = layer->shortName(); + typeName = typeName.replace( QLatin1String( " " ), QLatin1String( "_" ) ); + QDomText nameText = doc.createTextNode( typeName ); + nameElem.appendChild( nameText ); + layerElem.appendChild( nameElem ); + + //create Title + QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) ); + QString title = layer->title(); + if ( title.isEmpty() ) + { + title = layer->name(); + } + QDomText titleText = doc.createTextNode( title ); + titleElem.appendChild( titleText ); + layerElem.appendChild( titleElem ); + + //create Abstract + QString abstract = layer->abstract(); + if ( !abstract.isEmpty() ) + { + QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) ); + QDomText abstractText = doc.createTextNode( abstract ); + abstractElem.appendChild( abstractText ); + layerElem.appendChild( abstractElem ); + } + + //create keywords + QString keywords = layer->keywordList(); + if ( !keywords.isEmpty() ) + { + QDomElement keywordsElem = doc.createElement( QStringLiteral( "Keywords" ) ); + QDomText keywordsText = doc.createTextNode( keywords ); + keywordsElem.appendChild( keywordsText ); + layerElem.appendChild( keywordsElem ); + } + + //create SRS + QDomElement srsElem = doc.createElement( QStringLiteral( "SRS" ) ); + QDomText srsText = doc.createTextNode( layer->crs().authid() ); + srsElem.appendChild( srsText ); + layerElem.appendChild( srsElem ); + + //create LatLongBoundingBox + QgsRectangle layerExtent = layer->extent(); + QDomElement bBoxElement = doc.createElement( QStringLiteral( "LatLongBoundingBox" ) ); + bBoxElement.setAttribute( QStringLiteral( "minx" ), QString::number( layerExtent.xMinimum() ) ); + bBoxElement.setAttribute( QStringLiteral( "miny" ), QString::number( layerExtent.yMinimum() ) ); + bBoxElement.setAttribute( QStringLiteral( "maxx" ), QString::number( layerExtent.xMaximum() ) ); + bBoxElement.setAttribute( QStringLiteral( "maxy" ), QString::number( layerExtent.yMaximum() ) ); + layerElem.appendChild( bBoxElement ); + + // layer metadata URL + QString metadataUrl = layer->metadataUrl(); + if ( !metadataUrl.isEmpty() ) + { + QDomElement metaUrlElem = doc.createElement( QStringLiteral( "MetadataURL" ) ); + QString metadataUrlType = layer->metadataUrlType(); + metaUrlElem.setAttribute( QStringLiteral( "type" ), metadataUrlType ); + QString metadataUrlFormat = layer->metadataUrlFormat(); + if ( metadataUrlFormat == QLatin1String( "text/xml" ) ) + { + metaUrlElem.setAttribute( QStringLiteral( "format" ), QStringLiteral( "XML" ) ); + } + else + { + metaUrlElem.setAttribute( QStringLiteral( "format" ), QStringLiteral( "TXT" ) ); + } + QDomText metaUrlText = doc.createTextNode( metadataUrl ); + metaUrlElem.appendChild( metaUrlText ); + layerElem.appendChild( metaUrlElem ); + } + + //wfs:Operations element + QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ ); + //wfs:Query element + QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ ); + operationsElement.appendChild( queryElement ); + if ( wfstUpdateLayersId.contains( layer->id() ) || + wfstInsertLayersId.contains( layer->id() ) || + wfstDeleteLayersId.contains( layer->id() ) ) + { + QgsVectorLayer *vlayer = qobject_cast( layer ); + QgsVectorDataProvider *provider = vlayer->dataProvider(); + if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) ) + { + //wfs:Insert element + QDomElement insertElement = doc.createElement( QStringLiteral( "Insert" )/*wfs:Insert*/ ); + operationsElement.appendChild( insertElement ); + } + if ( ( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) && + ( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) && + wfstUpdateLayersId.contains( layer->id() ) ) + { + //wfs:Update element + QDomElement updateElement = doc.createElement( QStringLiteral( "Update" )/*wfs:Update*/ ); + operationsElement.appendChild( updateElement ); + } + if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) ) + { + //wfs:Delete element + QDomElement deleteElement = doc.createElement( QStringLiteral( "Delete" )/*wfs:Delete*/ ); + operationsElement.appendChild( deleteElement ); + } + } + + layerElem.appendChild( operationsElement ); + + featureTypeListElement.appendChild( layerElem ); + } + + return featureTypeListElement; + } + } // samespace QgsWfs diff --git a/src/server/services/wfs/qgswfsgetcapabilities.h b/src/server/services/wfs/qgswfsgetcapabilities.h index 877b574322d..b840bd765f1 100644 --- a/src/server/services/wfs/qgswfsgetcapabilities.h +++ b/src/server/services/wfs/qgswfsgetcapabilities.h @@ -26,6 +26,16 @@ namespace QgsWfs { + /** + * Create FeatureTypeList element for get capabilities document + */ + QDomElement getFeatureTypeListElement( QDomDocument& doc, QgsServerInterface* serverIface, const QgsProject* project ); + + /** + * Create Service element for get capabilities document + */ + QDomElement getServiceElement( QDomDocument& doc, const QgsProject* project ); + /** * Create get capabilities document */ diff --git a/tests/testdata/qgis_server/wfs_getcapabilities.txt b/tests/testdata/qgis_server/wfs_getcapabilities.txt index 420df606b63..5c8c1dea27e 100644 --- a/tests/testdata/qgis_server/wfs_getcapabilities.txt +++ b/tests/testdata/qgis_server/wfs_getcapabilities.txt @@ -6,21 +6,19 @@ Content-Type: text/xml; charset=utf-8 WFS QGIS TestProject Some UTF8 text èòù - - None - None + - + - + @@ -30,12 +28,12 @@ Content-Type: text/xml; charset=utf-8 - + - + @@ -47,19 +45,19 @@ Content-Type: text/xml; charset=utf-8 - + - + - + @@ -74,13 +72,13 @@ Content-Type: text/xml; charset=utf-8 A test vector layer A test vector layer with unicode òà EPSG:4326 + -