Skip to content
Permalink
Browse files

[bugfix] WFS-T Fixes #15597 #16043

This commit fixes a few bugs on WFS-T with
servers that support WFS-T > 1.0.0 when user
configure version != 1.0.0 ("auto" is the default).

It also fixes WFS-T multiple operations on GeoServer
when an insert operation is among them and the feature
store does not return generated feature ids for the
inserted features (i.e. shapefiles).

Tested on GeoServer and QGIS Server

 (cherry-picked from 502a8da)
  • Loading branch information
elpaso committed Jan 16, 2017
1 parent 6d23b04 commit 9324bdac1f90058ba77ac01002a5379cfb79c545
@@ -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" ) );
@@ -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;
@@ -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();

@@ -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" ) );

@@ -36,6 +36,7 @@ bool QgsWFSTransactionRequest::send( const QDomDocument& doc, QDomDocument& serv
QgsDebugMsg( errorMsg );
return false;
}
QgsDebugMsg( mResponse );
return true;
}
return false;
@@ -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 9324bda

Please sign in to comment.
You can’t perform that action at this time.