Skip to content

Commit 502a8da

Browse files
committed
[bugfix] WFS-T Fixes #15597 #16043
Tested on GeoServer and QGIS Server Needs forward port to master
1 parent 77b8c3d commit 502a8da

4 files changed

Lines changed: 177 additions & 11 deletions

File tree

‎src/providers/wfs/qgswfscapabilities.cpp‎

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,31 @@ void QgsWFSCapabilities::capabilitiesReplyFinished()
247247
}
248248

249249
// Parse operations supported for all feature types
250-
bool insertCap, updateCap, deleteCap;
251-
parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
252-
insertCap,
253-
updateCap,
254-
deleteCap );
250+
bool insertCap = false;
251+
bool updateCap = false;
252+
bool deleteCap = false;
253+
// WFS < 2
254+
if ( mCaps.version.startsWith( "1" ) )
255+
{
256+
parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
257+
insertCap,
258+
updateCap,
259+
deleteCap );
260+
}
261+
else // WFS 2.0.0 tested on GeoServer
262+
{
263+
QDomNodeList operationNodes = doc.elementsByTagName( "Operation" );
264+
for ( int i = 0; i < operationNodes.count(); i++ )
265+
{
266+
QDomElement operationElement = operationNodes.at( i ).toElement( );
267+
if ( operationElement.isElement( ) && "Transaction" == operationElement.attribute( "name" ) )
268+
{
269+
insertCap = true;
270+
updateCap = true;
271+
deleteCap = true;
272+
}
273+
}
274+
}
255275

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

478-
// TODO: remove me when WFS-T 1.1 or 2.0 is done
479-
if ( !mCaps.version.startsWith( "1.0" ) )
480-
return;
481-
482498
if ( operationsElem.isNull() )
483499
{
484500
return;

‎src/providers/wfs/qgswfsprovider.cpp‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,16 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
849849
{
850850
//transaction successful. Add the features to the cache
851851
QStringList idList = insertedFeatureIds( serverResponse );
852+
/* Fix issue with GeoServer and shapefile feature stores when no real
853+
feature id are returned but new0 returned instead of the featureId*/
854+
for ( const QString &v : idList )
855+
{
856+
if ( v.startsWith( "new" ) )
857+
{
858+
reloadData();
859+
return true;
860+
}
861+
}
852862
QStringList::const_iterator idIt = idList.constBegin();
853863
featureIt = flist.begin();
854864

@@ -1344,7 +1354,10 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument& doc, QDomDocum
13441354
QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const
13451355
{
13461356
QDomElement transactionElem = doc.createElementNS( QgsWFSConstants::WFS_NAMESPACE, "Transaction" );
1347-
transactionElem.setAttribute( "version", "1.0.0" );
1357+
// QString WfsVersion = mShared->mWFSVersion;
1358+
// For now: hardcoded to 1.0.0
1359+
QString WfsVersion = "1.0.0";
1360+
transactionElem.setAttribute( "version", WfsVersion );
13481361
transactionElem.setAttribute( "service", "WFS" );
13491362
transactionElem.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
13501363

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

13591372
transactionElem.setAttribute( "xsi:schemaLocation", mApplicationNamespace + ' '

‎src/providers/wfs/qgswfstransactionrequest.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bool QgsWFSTransactionRequest::send( const QDomDocument& doc, QDomDocument& serv
3636
QgsDebugMsg( errorMsg );
3737
return false;
3838
}
39+
QgsDebugMsg( mResponse );
3940
return true;
4041
}
4142
return false;

‎tests/src/python/test_provider_wfs.py‎

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,6 +2225,142 @@ def testDescribeFeatureTypeWithInlineType(self):
22252225
got = got_f[0].geometry().geometry()
22262226
self.assertEqual((got.x(), got.y()), (2.0, 49.0))
22272227

2228+
def testWFS20TransactionsDisabled(self):
2229+
"""Test WFS 2.0 Transaction disabled"""
2230+
2231+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'
2232+
2233+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
2234+
f.write("""
2235+
<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">
2236+
<ows:OperationsMetadata>
2237+
<ows:Operation name="GetFeature">
2238+
<ows:Constraint name="CountDefault">
2239+
<ows:NoValues/>
2240+
<ows:DefaultValue>1</ows:DefaultValue>
2241+
</ows:Constraint>
2242+
</ows:Operation>
2243+
<ows:Constraint name="ImplementsTransactionalWFS">
2244+
<ows:NoValues/>
2245+
<ows:DefaultValue>TRUE</ows:DefaultValue>
2246+
</ows:Constraint>
2247+
</ows:OperationsMetadata>
2248+
<FeatureTypeList>
2249+
<FeatureType>
2250+
<Name>my:typename</Name>
2251+
<Title>Title</Title>
2252+
<Abstract>Abstract</Abstract>
2253+
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
2254+
<ows:WGS84BoundingBox>
2255+
<ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
2256+
<ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
2257+
</ows:WGS84BoundingBox>
2258+
</FeatureType>
2259+
</FeatureTypeList>
2260+
</wfs:WFS_Capabilities>""".encode('UTF-8'))
2261+
2262+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
2263+
f.write("""
2264+
<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">
2265+
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
2266+
<xsd:complexType name="typenameType">
2267+
<xsd:complexContent>
2268+
<xsd:extension base="gml:AbstractFeatureType">
2269+
<xsd:sequence>
2270+
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
2271+
</xsd:sequence>
2272+
</xsd:extension>
2273+
</xsd:complexContent>
2274+
</xsd:complexType>
2275+
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
2276+
</xsd:schema>
2277+
""".encode('UTF-8'))
2278+
2279+
# Create test layer
2280+
vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
2281+
assert vl.isValid()
2282+
self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
2283+
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
2284+
2285+
def testWFS20TransactionsEnabled(self):
2286+
"""Test WFS 2.0 Transaction enabled"""
2287+
2288+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'
2289+
2290+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
2291+
f.write("""
2292+
<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">
2293+
<ows:OperationsMetadata>
2294+
<ows:Operation name="GetFeature">
2295+
<ows:Constraint name="CountDefault">
2296+
<ows:NoValues/>
2297+
<ows:DefaultValue>1</ows:DefaultValue>
2298+
</ows:Constraint>
2299+
</ows:Operation>
2300+
<ows:Constraint name="ImplementsTransactionalWFS">
2301+
<ows:NoValues/>
2302+
<ows:DefaultValue>TRUE</ows:DefaultValue>
2303+
</ows:Constraint>
2304+
<ows:Operation name="Transaction">
2305+
<ows:DCP>
2306+
<ows:HTTP>
2307+
<ows:Get xlink:href="http://{endpoint}"/>
2308+
<ows:Post xlink:href="{endpoint}"/>
2309+
</ows:HTTP>
2310+
</ows:DCP>
2311+
<ows:Parameter name="inputFormat">
2312+
<ows:AllowedValues>
2313+
<ows:Value>text/xml; subtype=gml/3.2</ows:Value>
2314+
</ows:AllowedValues>
2315+
</ows:Parameter>
2316+
<ows:Parameter name="releaseAction">
2317+
<ows:AllowedValues>
2318+
<ows:Value>ALL</ows:Value>
2319+
<ows:Value>SOME</ows:Value>
2320+
</ows:AllowedValues>
2321+
</ows:Parameter>
2322+
</ows:Operation>
2323+
</ows:OperationsMetadata>
2324+
<FeatureTypeList>
2325+
<FeatureType>
2326+
<Name>my:typename</Name>
2327+
<Title>Title</Title>
2328+
<Abstract>Abstract</Abstract>
2329+
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
2330+
<ows:WGS84BoundingBox>
2331+
<ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
2332+
<ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
2333+
</ows:WGS84BoundingBox>
2334+
</FeatureType>
2335+
</FeatureTypeList>
2336+
</wfs:WFS_Capabilities>""".format(endpoint=endpoint).encode('UTF-8'))
2337+
2338+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
2339+
f.write("""
2340+
<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">
2341+
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
2342+
<xsd:complexType name="typenameType">
2343+
<xsd:complexContent>
2344+
<xsd:extension base="gml:AbstractFeatureType">
2345+
<xsd:sequence>
2346+
<xsd:element maxOccurs="1" minOccurs="0" name="intfield" nillable="true" type="xsd:int"/>
2347+
<xsd:element maxOccurs="1" minOccurs="0" name="longfield" nillable="true" type="xsd:long"/>
2348+
<xsd:element maxOccurs="1" minOccurs="0" name="stringfield" nillable="true" type="xsd:string"/>
2349+
<xsd:element maxOccurs="1" minOccurs="0" name="datetimefield" nillable="true" type="xsd:dateTime"/>
2350+
<xsd:element maxOccurs="1" minOccurs="0" name="geomfield" nillable="true" type="gml:PointPropertyType"/>
2351+
</xsd:sequence>
2352+
</xsd:extension>
2353+
</xsd:complexContent>
2354+
</xsd:complexType>
2355+
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
2356+
</xsd:schema>
2357+
""".encode('UTF-8'))
2358+
2359+
# Create test layer
2360+
vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
2361+
assert vl.isValid()
2362+
self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
2363+
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
22282364

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

0 commit comments

Comments
 (0)