Skip to content

Commit

Permalink
Merge pull request #3999 from elpaso/wfst-fixes-15597-16043
Browse files Browse the repository at this point in the history
[bugfix] WFS-T Fixes #15597 #16043
  • Loading branch information
elpaso authored Jan 16, 2017
2 parents bf22cbf + 9324bda commit 39a5f6a
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 10 deletions.
34 changes: 25 additions & 9 deletions src/providers/wfs/qgswfscapabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,31 @@ void QgsWfsCapabilities::capabilitiesReplyFinished()
}

// Parse operations supported for all feature types
bool insertCap, updateCap, deleteCap;
parseSupportedOperations( featureTypeListElem.firstChildElement( QStringLiteral( "Operations" ) ),
insertCap,
updateCap,
deleteCap );
bool insertCap = false;
bool updateCap = false;
bool deleteCap = false;
// WFS < 2
if ( mCaps.version.startsWith( QLatin1String( "1" ) ) )
{
parseSupportedOperations( featureTypeListElem.firstChildElement( QStringLiteral( "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( QStringLiteral( "FeatureType" ) );
Expand Down Expand Up @@ -474,10 +494,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( QLatin1String( "1.0" ) ) )
return;

if ( operationsElem.isNull() )
{
return;
Expand Down
15 changes: 14 additions & 1 deletion src/providers/wfs/qgswfsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,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*/
Q_FOREACH ( const QString &v, idList )
{
if ( v.startsWith( QStringLiteral( "new" ) ) )
{
reloadData();
return true;
}
}
QStringList::const_iterator idIt = idList.constBegin();
featureIt = flist.begin();

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

Expand Down
1 change: 1 addition & 0 deletions src/providers/wfs/qgswfstransactionrequest.cpp
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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, vl.dataProvider().NoCapabilities)
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, vl.dataProvider().NoCapabilities)
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)

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

0 comments on commit 39a5f6a

Please sign in to comment.