Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3989 from elpaso/wfst-200-fix-15597
[bugfix] WFS-T fixes #15597 #16043 geoserver compatibility
  • Loading branch information
elpaso committed Jan 14, 2017
2 parents 77b8c3d + 502a8da commit 93770b1
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 11 deletions.
34 changes: 25 additions & 9 deletions src/providers/wfs/qgswfscapabilities.cpp
Expand Up @@ -247,11 +247,31 @@ void QgsWFSCapabilities::capabilitiesReplyFinished()
}

// Parse operations supported for all feature types
bool insertCap, updateCap, deleteCap;
parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
insertCap,
updateCap,
deleteCap );
bool insertCap = false;
bool updateCap = false;
bool deleteCap = false;
// WFS < 2
if ( mCaps.version.startsWith( "1" ) )
{
parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
insertCap,
updateCap,
deleteCap );
}
else // WFS 2.0.0 tested on GeoServer
{
QDomNodeList operationNodes = doc.elementsByTagName( "Operation" );
for ( int i = 0; i < operationNodes.count(); i++ )
{
QDomElement operationElement = operationNodes.at( i ).toElement( );
if ( operationElement.isElement( ) && "Transaction" == operationElement.attribute( "name" ) )
{
insertCap = true;
updateCap = true;
deleteCap = true;
}
}
}

// get the <FeatureType> elements
QDomNodeList featureTypeList = featureTypeListElem.elementsByTagName( "FeatureType" );
Expand Down Expand Up @@ -475,10 +495,6 @@ void QgsWFSCapabilities::parseSupportedOperations( const QDomElement& operations
updateCap = false;
deleteCap = false;

// TODO: remove me when WFS-T 1.1 or 2.0 is done
if ( !mCaps.version.startsWith( "1.0" ) )
return;

if ( operationsElem.isNull() )
{
return;
Expand Down
17 changes: 15 additions & 2 deletions src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -849,6 +849,16 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
{
//transaction successful. Add the features to the cache
QStringList idList = insertedFeatureIds( serverResponse );
/* Fix issue with GeoServer and shapefile feature stores when no real
feature id are returned but new0 returned instead of the featureId*/
for ( const QString &v : idList )
{
if ( v.startsWith( "new" ) )
{
reloadData();
return true;
}
}
QStringList::const_iterator idIt = idList.constBegin();
featureIt = flist.begin();

Expand Down Expand Up @@ -1344,7 +1354,10 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument& doc, QDomDocum
QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const
{
QDomElement transactionElem = doc.createElementNS( QgsWFSConstants::WFS_NAMESPACE, "Transaction" );
transactionElem.setAttribute( "version", "1.0.0" );
// QString WfsVersion = mShared->mWFSVersion;
// For now: hardcoded to 1.0.0
QString WfsVersion = "1.0.0";
transactionElem.setAttribute( "version", WfsVersion );
transactionElem.setAttribute( "service", "WFS" );
transactionElem.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );

Expand All @@ -1353,7 +1366,7 @@ QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const
if ( mShared->mURI.baseURL().toString().contains( "fake_qgis_http_endpoint" ) )
describeFeatureTypeURL = QUrl( "http://fake_qgis_http_endpoint" );
describeFeatureTypeURL.addQueryItem( "REQUEST", "DescribeFeatureType" );
describeFeatureTypeURL.addQueryItem( "VERSION", "1.0.0" );
describeFeatureTypeURL.addQueryItem( "VERSION", WfsVersion );
describeFeatureTypeURL.addQueryItem( "TYPENAME", mShared->mURI.typeName() );

transactionElem.setAttribute( "xsi:schemaLocation", mApplicationNamespace + ' '
Expand Down
1 change: 1 addition & 0 deletions src/providers/wfs/qgswfstransactionrequest.cpp
Expand Up @@ -36,6 +36,7 @@ bool QgsWFSTransactionRequest::send( const QDomDocument& doc, QDomDocument& serv
QgsDebugMsg( errorMsg );
return false;
}
QgsDebugMsg( mResponse );
return true;
}
return false;
Expand Down
136 changes: 136 additions & 0 deletions tests/src/python/test_provider_wfs.py
Expand Up @@ -2225,6 +2225,142 @@ def testDescribeFeatureTypeWithInlineType(self):
got = got_f[0].geometry().geometry()
self.assertEqual((got.x(), got.y()), (2.0, 49.0))

def testWFS20TransactionsDisabled(self):
"""Test WFS 2.0 Transaction disabled"""

endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'

with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
f.write("""
<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
<ows:OperationsMetadata>
<ows:Operation name="GetFeature">
<ows:Constraint name="CountDefault">
<ows:NoValues/>
<ows:DefaultValue>1</ows:DefaultValue>
</ows:Constraint>
</ows:Operation>
<ows:Constraint name="ImplementsTransactionalWFS">
<ows:NoValues/>
<ows:DefaultValue>TRUE</ows:DefaultValue>
</ows:Constraint>
</ows:OperationsMetadata>
<FeatureTypeList>
<FeatureType>
<Name>my:typename</Name>
<Title>Title</Title>
<Abstract>Abstract</Abstract>
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
<ows:WGS84BoundingBox>
<ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
<ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
</ows:WGS84BoundingBox>
</FeatureType>
</FeatureTypeList>
</wfs:WFS_Capabilities>""".encode('UTF-8'))

with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
f.write("""
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
<xsd:complexType name="typenameType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
</xsd:schema>
""".encode('UTF-8'))

# Create test layer
vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
assert vl.isValid()
self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)

def testWFS20TransactionsEnabled(self):
"""Test WFS 2.0 Transaction enabled"""

endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'

with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
f.write("""
<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
<ows:OperationsMetadata>
<ows:Operation name="GetFeature">
<ows:Constraint name="CountDefault">
<ows:NoValues/>
<ows:DefaultValue>1</ows:DefaultValue>
</ows:Constraint>
</ows:Operation>
<ows:Constraint name="ImplementsTransactionalWFS">
<ows:NoValues/>
<ows:DefaultValue>TRUE</ows:DefaultValue>
</ows:Constraint>
<ows:Operation name="Transaction">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:href="http://{endpoint}"/>
<ows:Post xlink:href="{endpoint}"/>
</ows:HTTP>
</ows:DCP>
<ows:Parameter name="inputFormat">
<ows:AllowedValues>
<ows:Value>text/xml; subtype=gml/3.2</ows:Value>
</ows:AllowedValues>
</ows:Parameter>
<ows:Parameter name="releaseAction">
<ows:AllowedValues>
<ows:Value>ALL</ows:Value>
<ows:Value>SOME</ows:Value>
</ows:AllowedValues>
</ows:Parameter>
</ows:Operation>
</ows:OperationsMetadata>
<FeatureTypeList>
<FeatureType>
<Name>my:typename</Name>
<Title>Title</Title>
<Abstract>Abstract</Abstract>
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
<ows:WGS84BoundingBox>
<ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
<ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
</ows:WGS84BoundingBox>
</FeatureType>
</FeatureTypeList>
</wfs:WFS_Capabilities>""".format(endpoint=endpoint).encode('UTF-8'))

with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
f.write("""
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
<xsd:complexType name="typenameType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="intfield" nillable="true" type="xsd:int"/>
<xsd:element maxOccurs="1" minOccurs="0" name="longfield" nillable="true" type="xsd:long"/>
<xsd:element maxOccurs="1" minOccurs="0" name="stringfield" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="datetimefield" nillable="true" type="xsd:dateTime"/>
<xsd:element maxOccurs="1" minOccurs="0" name="geomfield" nillable="true" type="gml:PointPropertyType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
</xsd:schema>
""".encode('UTF-8'))

# Create test layer
vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
assert vl.isValid()
self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)

if __name__ == '__main__':
unittest.main()

0 comments on commit 93770b1

Please sign in to comment.