Skip to content

Commit

Permalink
[Backport release-3_40] Bugfix gh60185 server wfs aspatial forbidden …
Browse files Browse the repository at this point in the history
…update (#60271)

* [memory] Make sure spatial capabilities are not set for aspatial layers

* [server][wfs] Fix getcap not allowing updates on aspatial layers

Fix #60185

* memory layer expand test case
  • Loading branch information
qgis-bot authored Jan 27, 2025
1 parent d1f6107 commit 60d92d4
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 5 deletions.
11 changes: 8 additions & 3 deletions src/core/providers/memory/qgsmemoryprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,14 @@ Qgis::SpatialIndexPresence QgsMemoryProvider::hasSpatialIndex() const

Qgis::VectorProviderCapabilities QgsMemoryProvider::capabilities() const
{
return Qgis::VectorProviderCapability::AddFeatures | Qgis::VectorProviderCapability::DeleteFeatures | Qgis::VectorProviderCapability::ChangeGeometries |
Qgis::VectorProviderCapability::ChangeAttributeValues | Qgis::VectorProviderCapability::AddAttributes | Qgis::VectorProviderCapability::DeleteAttributes | Qgis::VectorProviderCapability::RenameAttributes | Qgis::VectorProviderCapability::CreateSpatialIndex |
Qgis::VectorProviderCapability::SelectAtId | Qgis::VectorProviderCapability::CircularGeometries | Qgis::VectorProviderCapability::FastTruncate;
Qgis::VectorProviderCapabilities caps { Qgis::VectorProviderCapability::AddFeatures | Qgis::VectorProviderCapability::DeleteFeatures |
Qgis::VectorProviderCapability::ChangeAttributeValues | Qgis::VectorProviderCapability::AddAttributes | Qgis::VectorProviderCapability::DeleteAttributes | Qgis::VectorProviderCapability::RenameAttributes |
Qgis::VectorProviderCapability::SelectAtId | Qgis::VectorProviderCapability::FastTruncate };
if ( mWkbType != Qgis::WkbType::NoGeometry )
{
caps |= Qgis::VectorProviderCapability::CreateSpatialIndex | Qgis::VectorProviderCapability::CircularGeometries | Qgis::VectorProviderCapability::ChangeGeometries ;
}
return caps;
}

bool QgsMemoryProvider::truncate()
Expand Down
2 changes: 1 addition & 1 deletion src/server/services/wfs/qgswfsgetcapabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ namespace QgsWfs
operationsElement.appendChild( operationElement );
}

if ( ( provider->capabilities() & Qgis::VectorProviderCapability::ChangeAttributeValues ) && ( provider->capabilities() & Qgis::VectorProviderCapability::ChangeGeometries ) && wfstUpdateLayersId.contains( layer->id() ) )
if ( ( provider->capabilities() & Qgis::VectorProviderCapability::ChangeAttributeValues ) && ( !layer->isSpatial() || provider->capabilities() & Qgis::VectorProviderCapability::ChangeGeometries ) && wfstUpdateLayersId.contains( layer->id() ) )
{
//wfs:Update element
QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
Expand Down
39 changes: 39 additions & 0 deletions tests/src/python/test_provider_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from qgis.PyQt.QtCore import QByteArray, QDate, QDateTime, QTime, QVariant
from qgis.core import (
NULL,
Qgis,
QgsCoordinateReferenceSystem,
QgsEditorWidgetSetup,
QgsFeature,
Expand Down Expand Up @@ -734,6 +735,44 @@ def testUniqueSource(self):
layer2 = QgsVectorLayer("Point", "test2", "memory")
self.assertNotEqual(layer.source(), layer2.source())

def testAspatialLayerHasNoGeometryRelatedCapabilities(self):

layer = QgsMemoryProviderUtils.createMemoryLayer("my name", QgsFields())
self.assertTrue(layer.isValid())
self.assertFalse(layer.isSpatial())
self.assertFalse(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.ChangeGeometries
)
self.assertFalse(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.CircularGeometries
)
self.assertFalse(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.CreateSpatialIndex
)

def testSpatialLayerHasGeometryRelatedCapabilities(self):

layer = QgsMemoryProviderUtils.createMemoryLayer(
"my name", QgsFields(), QgsWkbTypes.Type.Point
)
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
self.assertTrue(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.ChangeGeometries
)
self.assertTrue(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.CircularGeometries
)
self.assertTrue(
layer.dataProvider().capabilities()
& Qgis.VectorProviderCapability.CreateSpatialIndex
)

def testCreateMemoryLayer(self):
"""
Test QgsMemoryProviderUtils.createMemoryLayer()
Expand Down
41 changes: 40 additions & 1 deletion tests/src/python/test_qgsserver_wfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,16 @@
QgsGeometry,
QgsProject,
QgsVectorLayer,
QgsMemoryProviderUtils,
QgsWkbTypes,
QgsVectorDataProvider,
QgsFields,
QgsField,
)
from qgis.server import QgsServerRequest
from qgis.server import QgsServerRequest, QgsServer, QgsBufferServerResponse
from qgis.testing import unittest
from test_qgsserver import QgsServerTestBase
from qgis.PyQt.QtCore import QVariant, QUrl

# Strip path and content length because path may vary
RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+|timeStamp="[^"]+"'
Expand Down Expand Up @@ -1530,6 +1536,39 @@ def test_GetFeature_with_datetime(self):
project_file=project_file,
)

def test_wfs_aspatial_getcapabilities(self):
### Test issue GH #60185 - WFS GetCapabilities for aspatial layers"""

# create a memory layer with no geometry
fields = QgsFields()
fields.append(QgsField("id", QVariant.Int))
fields.append(QgsField("name", QVariant.String))
layer = QgsMemoryProviderUtils.createMemoryLayer(
"no_geom", fields, QgsWkbTypes.NoGeometry
)

provider = layer.dataProvider()
self.assertTrue(layer.isValid())
self.assertFalse(layer.isSpatial())
self.assertFalse(
provider.capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries
)

project = QgsProject()
project.addMapLayer(layer)
project.writeEntry("WFSLayers", "/", [layer.id()])
project.writeEntry("WFSTLayers", "Update", [layer.id()])
project.writeEntry("WFSTLayers", "Insert", [layer.id()])
project.writeEntry("WFSTLayers", "Delete", [layer.id()])

server = QgsServer()
request = QgsServerRequest()
request.setUrl(QUrl("?SERVICE=WFS&REQUEST=GetCapabilities"))
response = QgsBufferServerResponse()
server.handleRequest(request, response, project)
body = response.body().data().decode("utf8").replace("\n", "")
self.assertIn("<Operation>Update</Operation>", body)


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

0 comments on commit 60d92d4

Please sign in to comment.