Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix gh60185 server wfs aspatial forbidden update #60266

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Loading