Skip to content

Commit

Permalink
[Server] WFS GetCapapbilities and DescribeFeatureType refactoring
Browse files Browse the repository at this point in the history
Remove QgsWFSProjectParser from GetCapabilities and DescribeFeatureType
  • Loading branch information
rldhont committed Apr 8, 2017
1 parent f450b98 commit 04ed2b4
Show file tree
Hide file tree
Showing 9 changed files with 542 additions and 44 deletions.
24 changes: 24 additions & 0 deletions python/server/qgsserverprojectutils.sip
Expand Up @@ -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.
Expand Down
25 changes: 25 additions & 0 deletions src/server/qgsserverprojectutils.cpp
Expand Up @@ -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( "/" ), "" );
Expand Down
26 changes: 26 additions & 0 deletions src/server/qgsserverprojectutils.h
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/server/services/wfs/qgswfs.cpp
Expand Up @@ -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" ) )
{
Expand Down
218 changes: 206 additions & 12 deletions src/server/services/wfs/qgswfsdescribefeaturetype.cpp
Expand Up @@ -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 <QStringList>

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" ) );
Expand All @@ -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 ) )
Expand All @@ -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<QgsVectorLayer *>( layer );
QgsVectorDataProvider *provider = vLayer->dataProvider();
if ( !provider )
{
continue;
}
setSchemaLayer( schemaElement, doc, const_cast<QgsVectorLayer *>( 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<QString> &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


Expand Down

0 comments on commit 04ed2b4

Please sign in to comment.