Skip to content

Commit cc55ae1

Browse files
authoredApr 14, 2017
Merge pull request #4344 from rldhont/server-wfs-configparser
[Server] WFS refactoring and QgsWfsProjectParser removal
2 parents 1eaa486 + 7a48d07 commit cc55ae1

25 files changed

+2371
-1961
lines changed
 

‎python/server/qgsconfigcache.sip

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ class QgsConfigCache: QObject
3232
~QgsConfigCache();
3333

3434
QgsServerProjectParser* serverConfiguration( const QString& filePath );
35-
QgsWfsProjectParser* wfsConfiguration( const QString& filePath, const QgsAccessControl* accessControl );
3635
QgsWmsConfigParser* wmsConfiguration( const QString& filePath, const QgsAccessControl* accessControl, const QMap<QString, QString>& parameterMap = QMap< QString, QString >() );
3736

3837
private:

‎python/server/qgsserverprojectutils.sip

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,30 @@ namespace QgsServerProjectUtils
123123
*/
124124
QString wfsServiceUrl( const QgsProject& project );
125125

126+
/** Returns the Layer ids list defined in a QGIS project as published in WFS.
127+
* @param project the QGIS project
128+
* @return the Layer ids list.
129+
*/
130+
QStringList wfsLayerIds( const QgsProject& project );
131+
132+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities.
133+
* @param project the QGIS project
134+
* @return the Layer ids list.
135+
*/
136+
QStringList wfstUpdateLayerIds( const QgsProject& project );
137+
138+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities.
139+
* @param project the QGIS project
140+
* @return the Layer ids list.
141+
*/
142+
QStringList wfstInsertLayerIds( const QgsProject& project );
143+
144+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities.
145+
* @param project the QGIS project
146+
* @return the Layer ids list.
147+
*/
148+
QStringList wfstDeleteLayerIds( const QgsProject& project );
149+
126150
/** Returns the WCS service url defined in a QGIS project.
127151
* @param project the QGIS project
128152
* @return url if defined in project, an empty string otherwise.

‎python/server/qgswfserver.sip

Lines changed: 0 additions & 125 deletions
This file was deleted.

‎python/server/server.sip

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
%Include qgsserverprojectparser.sip
2424
%Include qgswmsconfigparser.sip
2525
%Include qgswmsprojectparser.sip
26-
%Include qgswfsprojectparser.sip
2726
%Include qgsconfigcache.sip
2827
%Include qgsserversettings.sip
2928
%Include qgsserverprojectutils.sip

‎src/server/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ SET(qgis_mapserv_SRCS
3434
qgsremotedatasourcebuilder.cpp
3535
qgssentdatasourcebuilder.cpp
3636
qgsserverlogger.cpp
37-
qgswfsprojectparser.cpp
3837
qgswmsconfigparser.cpp
3938
qgswmsprojectparser.cpp
4039
qgsserverprojectparser.cpp

‎src/server/qgsconfigcache.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "qgsconfigcache.h"
1919
#include "qgsmessagelog.h"
2020
#include "qgsmslayercache.h"
21-
#include "qgswfsprojectparser.h"
2221
#include "qgswmsprojectparser.h"
2322
#include "qgssldconfigparser.h"
2423
#include "qgsaccesscontrol.h"
@@ -76,32 +75,6 @@ QgsServerProjectParser *QgsConfigCache::serverConfiguration( const QString &file
7675
return new QgsServerProjectParser( doc, filePath );
7776
}
7877

79-
QgsWfsProjectParser *QgsConfigCache::wfsConfiguration(
80-
const QString &filePath
81-
, const QgsAccessControl *accessControl
82-
)
83-
{
84-
QgsWfsProjectParser *p = mWFSConfigCache.object( filePath );
85-
if ( !p )
86-
{
87-
QDomDocument *doc = xmlDocument( filePath );
88-
if ( !doc )
89-
{
90-
return nullptr;
91-
}
92-
p = new QgsWfsProjectParser(
93-
filePath
94-
, accessControl
95-
);
96-
mWFSConfigCache.insert( filePath, p );
97-
p = mWFSConfigCache.object( filePath );
98-
Q_ASSERT( p );
99-
}
100-
101-
QgsMSLayerCache::instance()->setProjectMaxLayers( p->wfsLayers().size() );
102-
return p;
103-
}
104-
10578
QgsWmsConfigParser *QgsConfigCache::wmsConfiguration(
10679
const QString &filePath
10780
, const QgsAccessControl *accessControl
@@ -182,7 +155,6 @@ QDomDocument *QgsConfigCache::xmlDocument( const QString &filePath )
182155
void QgsConfigCache::removeChangedEntry( const QString &path )
183156
{
184157
mWMSConfigCache.remove( path );
185-
mWFSConfigCache.remove( path );
186158

187159
//xml document must be removed last, as other config cache destructors may require it
188160
mXmlDocumentCache.remove( path );

‎src/server/qgsconfigcache.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
#include "qgis_server.h"
2929
#include "qgswmsconfigparser.h"
30-
#include "qgswfsprojectparser.h"
3130

3231
class QgsServerProjectParser;
3332
class QgsAccessControl;
@@ -41,10 +40,6 @@ class SERVER_EXPORT QgsConfigCache : public QObject
4140
static QgsConfigCache *instance();
4241

4342
QgsServerProjectParser *serverConfiguration( const QString &filePath );
44-
QgsWfsProjectParser *wfsConfiguration(
45-
const QString &filePath
46-
, const QgsAccessControl *accessControl
47-
);
4843
QgsWmsConfigParser *wmsConfiguration(
4944
const QString &filePath
5045
, const QgsAccessControl *accessControl
@@ -64,7 +59,6 @@ class SERVER_EXPORT QgsConfigCache : public QObject
6459

6560
QCache<QString, QDomDocument> mXmlDocumentCache;
6661
QCache<QString, QgsWmsConfigParser> mWMSConfigCache;
67-
QCache<QString, QgsWfsProjectParser> mWFSConfigCache;
6862

6963
private slots:
7064
//! Removes changed entry from this cache

‎src/server/qgsserverprojectutils.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,31 @@ QString QgsServerProjectUtils::wfsServiceUrl( const QgsProject &project )
9797
return project.readEntry( QStringLiteral( "WFSUrl" ), QStringLiteral( "/" ), "" );
9898
}
9999

100+
QStringList QgsServerProjectUtils::wfsLayerIds( const QgsProject &project )
101+
{
102+
return project.readListEntry( QStringLiteral( "WFSLayers" ), QStringLiteral( "/" ) );
103+
}
104+
105+
int QgsServerProjectUtils::wfsLayerPrecision( const QString &layerId, const QgsProject &project )
106+
{
107+
return project.readNumEntry( QStringLiteral( "WFSLayersPrecision" ), "/" + layerId, 6 );
108+
}
109+
110+
QStringList QgsServerProjectUtils::wfstUpdateLayerIds( const QgsProject &project )
111+
{
112+
return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Update" ) );
113+
}
114+
115+
QStringList QgsServerProjectUtils::wfstInsertLayerIds( const QgsProject &project )
116+
{
117+
return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Insert" ) );
118+
}
119+
120+
QStringList QgsServerProjectUtils::wfstDeleteLayerIds( const QgsProject &project )
121+
{
122+
return project.readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Delete" ) );
123+
}
124+
100125
QString QgsServerProjectUtils::wcsServiceUrl( const QgsProject &project )
101126
{
102127
return project.readEntry( QStringLiteral( "WCSUrl" ), QStringLiteral( "/" ), "" );

‎src/server/qgsserverprojectutils.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,32 @@ namespace QgsServerProjectUtils
125125
*/
126126
SERVER_EXPORT QString wfsServiceUrl( const QgsProject &project );
127127

128+
/** Returns the Layer ids list defined in a QGIS project as published in WFS.
129+
* @param project the QGIS project
130+
* @return the Layer ids list.
131+
*/
132+
SERVER_EXPORT QStringList wfsLayerIds( const QgsProject &project );
133+
134+
SERVER_EXPORT int wfsLayerPrecision( const QString &layerId, const QgsProject &project );
135+
136+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities.
137+
* @param project the QGIS project
138+
* @return the Layer ids list.
139+
*/
140+
SERVER_EXPORT QStringList wfstUpdateLayerIds( const QgsProject &project );
141+
142+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities.
143+
* @param project the QGIS project
144+
* @return the Layer ids list.
145+
*/
146+
SERVER_EXPORT QStringList wfstInsertLayerIds( const QgsProject &project );
147+
148+
/** Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities.
149+
* @param project the QGIS project
150+
* @return the Layer ids list.
151+
*/
152+
SERVER_EXPORT QStringList wfstDeleteLayerIds( const QgsProject &project );
153+
128154
/** Returns the WCS service url defined in a QGIS project.
129155
* \param project the QGIS project
130156
* \returns url if defined in project, an empty string otherwise.

‎src/server/qgswfsprojectparser.cpp

Lines changed: 0 additions & 572 deletions
This file was deleted.

‎src/server/qgswfsprojectparser.h

Lines changed: 0 additions & 61 deletions
This file was deleted.

‎src/server/services/wfs/qgswfs.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler ( parts fron qgswmshandler)
6+
(C) 2012 by René-Luc D'Hont ( parts fron qgswmshandler)
67
(C) 2014 by Alessandro Pasotti ( parts from qgswmshandler)
78
(C) 2016 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -78,11 +79,11 @@ namespace QgsWfs
7879
}
7980
else if ( QSTR_COMPARE( req, "DescribeFeatureType" ) )
8081
{
81-
writeDescribeFeatureType( mServerIface, versionString, request, response );
82+
writeDescribeFeatureType( mServerIface, project, versionString, request, response );
8283
}
8384
else if ( QSTR_COMPARE( req, "Transaction" ) )
8485
{
85-
writeTransaction( mServerIface, versionString, request, response );
86+
writeTransaction( mServerIface, project, versionString, request, response );
8687
}
8788
else
8889
{

‎src/server/services/wfs/qgswfsdescribefeaturetype.cpp

Lines changed: 207 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -19,31 +20,42 @@
1920
* *
2021
***************************************************************************/
2122
#include "qgswfsutils.h"
23+
#include "qgsserverprojectutils.h"
2224
#include "qgswfsdescribefeaturetype.h"
2325

26+
#include "qgsproject.h"
27+
#include "qgscsexception.h"
28+
#include "qgsvectorlayer.h"
29+
#include "qgsvectordataprovider.h"
30+
#include "qgsmapserviceexception.h"
31+
#include "qgscoordinatereferencesystem.h"
32+
33+
#include <QStringList>
34+
2435
namespace QgsWfs
2536
{
2637

27-
void writeDescribeFeatureType( QgsServerInterface *serverIface, const QString &version,
38+
void writeDescribeFeatureType( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
2839
const QgsServerRequest &request, QgsServerResponse &response )
2940
{
30-
QDomDocument doc = createDescribeFeatureTypeDocument( serverIface, version, request );
41+
QDomDocument doc = createDescribeFeatureTypeDocument( serverIface, project, version, request );
3142

3243
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
3344
response.write( doc.toByteArray() );
3445
}
3546

3647

37-
QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QString &version,
48+
QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
3849
const QgsServerRequest &request )
3950
{
4051
Q_UNUSED( version );
4152

4253
QDomDocument doc;
4354

44-
QgsWfsProjectParser *configParser = getConfigParser( serverIface );
4555
QgsServerRequest::Parameters parameters = request.parameters();
4656

57+
QgsAccessControl *accessControl = serverIface->accessControls();
58+
4759
//xsd:schema
4860
QDomElement schemaElement = doc.createElement( QStringLiteral( "schema" )/*xsd:schema*/ );
4961
schemaElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) );
@@ -62,9 +74,7 @@ namespace QgsWfs
6274
importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ) );
6375
schemaElement.appendChild( importElement );
6476

65-
//defining typename
66-
QString typeName = QLatin1String( "" );
67-
77+
QStringList typeNameList;
6878
QDomDocument queryDoc;
6979
QString errorMsg;
7080
if ( queryDoc.setContent( parameters.value( QStringLiteral( "REQUEST_BODY" ) ), true, &errorMsg ) )
@@ -79,23 +89,208 @@ namespace QgsWfs
7989
QDomElement docChildElem = docChildNodes.at( i ).toElement();
8090
if ( docChildElem.tagName() == QLatin1String( "TypeName" ) )
8191
{
82-
if ( typeName == QLatin1String( "" ) )
83-
typeName = docChildElem.text();
92+
QString typeName = docChildElem.text().trimmed();
93+
if ( typeName.contains( QLatin1String( ":" ) ) )
94+
typeNameList << typeName.section( QStringLiteral( ":" ), 1, 1 );
8495
else
85-
typeName += "," + docChildElem.text();
96+
typeNameList << typeName;
8697
}
8798
}
8899
}
89100
}
90101
else
91102
{
92-
typeName = request.getParameter( QStringLiteral( "TYPENAME" ) );
103+
QString typeNames = request.getParameter( QStringLiteral( "TYPENAME" ) );
104+
if ( !typeNames.isEmpty() )
105+
{
106+
QStringList typeNameSplit = typeNames.split( QStringLiteral( "," ) );
107+
for ( int i = 0; i < typeNameSplit.size(); ++i )
108+
{
109+
QString typeName = typeNameSplit.at( i ).trimmed();
110+
if ( typeName.contains( QLatin1String( ":" ) ) )
111+
typeNameList << typeName.section( QStringLiteral( ":" ), 1, 1 );
112+
else
113+
typeNameList << typeName;
114+
}
115+
}
93116
}
94117

95-
configParser->describeFeatureType( typeName, schemaElement, doc );
118+
QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
119+
for ( int i = 0; i < wfsLayerIds.size(); ++i )
120+
{
121+
QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) );
122+
if ( layer->type() != QgsMapLayer::LayerType::VectorLayer )
123+
{
124+
continue;
125+
}
126+
127+
QString name = layer->name();
128+
if ( !layer->shortName().isEmpty() )
129+
name = layer->shortName();
130+
name = name.replace( QLatin1String( " " ), QLatin1String( "_" ) );
131+
132+
if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) )
133+
{
134+
continue;
135+
}
136+
137+
if ( accessControl && !accessControl->layerReadPermission( layer ) )
138+
{
139+
if ( !typeNameList.isEmpty() )
140+
{
141+
throw QgsSecurityAccessException( QStringLiteral( "Feature access permission denied" ) );
142+
}
143+
else
144+
{
145+
continue;
146+
}
147+
}
148+
149+
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
150+
QgsVectorDataProvider *provider = vLayer->dataProvider();
151+
if ( !provider )
152+
{
153+
continue;
154+
}
155+
setSchemaLayer( schemaElement, doc, const_cast<QgsVectorLayer *>( vLayer ) );
156+
}
96157
return doc;
97158
}
98159

160+
void setSchemaLayer( QDomElement &parentElement, QDomDocument &doc, const QgsVectorLayer *layer )
161+
{
162+
const QgsVectorDataProvider *provider = layer->dataProvider();
163+
if ( !provider )
164+
{
165+
return;
166+
}
167+
168+
QString typeName = layer->name();
169+
if ( !layer->shortName().isEmpty() )
170+
typeName = layer->shortName();
171+
typeName = typeName.replace( QLatin1String( " " ), QLatin1String( "_" ) );
172+
173+
//xsd:element
174+
QDomElement elementElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
175+
elementElem.setAttribute( QStringLiteral( "name" ), typeName );
176+
elementElem.setAttribute( QStringLiteral( "type" ), "qgs:" + typeName + "Type" );
177+
elementElem.setAttribute( QStringLiteral( "substitutionGroup" ), QStringLiteral( "gml:_Feature" ) );
178+
parentElement.appendChild( elementElem );
179+
180+
//xsd:complexType
181+
QDomElement complexTypeElem = doc.createElement( QStringLiteral( "complexType" )/*xsd:complexType*/ );
182+
complexTypeElem.setAttribute( QStringLiteral( "name" ), typeName + "Type" );
183+
parentElement.appendChild( complexTypeElem );
184+
185+
//xsd:complexType
186+
QDomElement complexContentElem = doc.createElement( QStringLiteral( "complexContent" )/*xsd:complexContent*/ );
187+
complexTypeElem.appendChild( complexContentElem );
188+
189+
//xsd:extension
190+
QDomElement extensionElem = doc.createElement( QStringLiteral( "extension" )/*xsd:extension*/ );
191+
extensionElem.setAttribute( QStringLiteral( "base" ), QStringLiteral( "gml:AbstractFeatureType" ) );
192+
complexContentElem.appendChild( extensionElem );
193+
194+
//xsd:sequence
195+
QDomElement sequenceElem = doc.createElement( QStringLiteral( "sequence" )/*xsd:sequence*/ );
196+
extensionElem.appendChild( sequenceElem );
197+
198+
//xsd:element
199+
if ( layer->hasGeometryType() )
200+
{
201+
QDomElement geomElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
202+
geomElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "geometry" ) );
203+
if ( provider->name() == QLatin1String( "ogr" ) )
204+
{
205+
// because some ogr drivers (e.g. ESRI ShapeFile, GML)
206+
// are not able to determine the geometry type of a layer.
207+
// we set to GeometryType
208+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:GeometryPropertyType" ) );
209+
}
210+
else
211+
{
212+
QgsWkbTypes::Type wkbType = layer->wkbType();
213+
switch ( wkbType )
214+
{
215+
case QgsWkbTypes::Point25D:
216+
case QgsWkbTypes::Point:
217+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:PointPropertyType" ) );
218+
break;
219+
case QgsWkbTypes::LineString25D:
220+
case QgsWkbTypes::LineString:
221+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:LineStringPropertyType" ) );
222+
break;
223+
case QgsWkbTypes::Polygon25D:
224+
case QgsWkbTypes::Polygon:
225+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:PolygonPropertyType" ) );
226+
break;
227+
case QgsWkbTypes::MultiPoint25D:
228+
case QgsWkbTypes::MultiPoint:
229+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiPointPropertyType" ) );
230+
break;
231+
case QgsWkbTypes::MultiLineString25D:
232+
case QgsWkbTypes::MultiLineString:
233+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiLineStringPropertyType" ) );
234+
break;
235+
case QgsWkbTypes::MultiPolygon25D:
236+
case QgsWkbTypes::MultiPolygon:
237+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:MultiPolygonPropertyType" ) );
238+
break;
239+
default:
240+
geomElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "gml:GeometryPropertyType" ) );
241+
break;
242+
}
243+
}
244+
geomElem.setAttribute( QStringLiteral( "minOccurs" ), QStringLiteral( "0" ) );
245+
geomElem.setAttribute( QStringLiteral( "maxOccurs" ), QStringLiteral( "1" ) );
246+
sequenceElem.appendChild( geomElem );
247+
248+
//Attributes
249+
const QgsFields &fields = layer->pendingFields();
250+
//hidden attributes for this layer
251+
const QSet<QString> &layerExcludedAttributes = layer->excludeAttributesWfs();
252+
for ( int idx = 0; idx < fields.count(); ++idx )
253+
{
254+
255+
QString attributeName = fields.at( idx ).name();
256+
//skip attribute if excluded from WFS publication
257+
if ( layerExcludedAttributes.contains( attributeName ) )
258+
{
259+
continue;
260+
}
261+
262+
//xsd:element
263+
QDomElement attElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
264+
attElem.setAttribute( QStringLiteral( "name" ), attributeName );
265+
QVariant::Type attributeType = fields.at( idx ).type();
266+
if ( attributeType == QVariant::Int )
267+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) );
268+
else if ( attributeType == QVariant::LongLong )
269+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "long" ) );
270+
else if ( attributeType == QVariant::Double )
271+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "double" ) );
272+
else if ( attributeType == QVariant::Bool )
273+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "boolean" ) );
274+
else if ( attributeType == QVariant::Date )
275+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
276+
else if ( attributeType == QVariant::Time )
277+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
278+
else if ( attributeType == QVariant::DateTime )
279+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) );
280+
else
281+
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "string" ) );
282+
283+
sequenceElem.appendChild( attElem );
284+
285+
QString alias = fields.at( idx ).alias();
286+
if ( !alias.isEmpty() )
287+
{
288+
attElem.setAttribute( QStringLiteral( "alias" ), alias );
289+
}
290+
}
291+
}
292+
}
293+
99294
} // samespace QgsWfs
100295

101296

‎src/server/services/wfs/qgswfsdescribefeaturetype.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -21,20 +22,24 @@
2122
#ifndef QGSWFSDESCRIBEFEATURETYPE_H
2223
#define QGSWFSDESCRIBEFEATURETYPE_H
2324

25+
#include "qgsvectorlayer.h"
26+
2427
#include <QDomDocument>
28+
#include <QDomElement>
2529

2630
namespace QgsWfs
2731
{
32+
void setSchemaLayer( QDomElement &parentElement, QDomDocument &doc, const QgsVectorLayer *layer );
2833

2934
/**
3035
* Create get capabilities document
3136
*/
32-
QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QString &version,
37+
QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
3338
const QgsServerRequest &request );
3439

3540
/** Output WFS GetCapabilities response
3641
*/
37-
void writeDescribeFeatureType( QgsServerInterface *serverIface, const QString &version,
42+
void writeDescribeFeatureType( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
3843
const QgsServerRequest &request, QgsServerResponse &response );
3944

4045
} // samespace QgsWfs

‎src/server/services/wfs/qgswfsgetcapabilities.cpp

Lines changed: 234 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -19,8 +20,18 @@
1920
* *
2021
***************************************************************************/
2122
#include "qgswfsutils.h"
23+
#include "qgsserverprojectutils.h"
2224
#include "qgswfsgetcapabilities.h"
2325

26+
#include "qgsproject.h"
27+
#include "qgscsexception.h"
28+
#include "qgsvectorlayer.h"
29+
#include "qgsvectordataprovider.h"
30+
#include "qgsmapserviceexception.h"
31+
#include "qgscoordinatereferencesystem.h"
32+
33+
#include <QStringList>
34+
2435
namespace QgsWfs
2536
{
2637

@@ -44,8 +55,6 @@ namespace QgsWfs
4455

4556
QDomDocument doc;
4657

47-
QgsWfsProjectParser *configParser = getConfigParser( serverIface );
48-
4958
//wfs:WFS_Capabilities element
5059
QDomElement wfsCapabilitiesElement = doc.createElement( QStringLiteral( "WFS_Capabilities" )/*wms:WFS_Capabilities*/ );
5160
wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE );
@@ -59,7 +68,9 @@ namespace QgsWfs
5968
wfsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
6069
doc.appendChild( wfsCapabilitiesElement );
6170

62-
configParser->serviceCapabilities( wfsCapabilitiesElement, doc );
71+
//configParser->serviceCapabilities( wfsCapabilitiesElement, doc );
72+
//INSERT Service
73+
wfsCapabilitiesElement.appendChild( getServiceElement( doc, project ) );
6374

6475
//wfs:Capability element
6576
QDomElement capabilityElement = doc.createElement( QStringLiteral( "Capability" )/*wfs:Capability*/ );
@@ -125,19 +136,8 @@ namespace QgsWfs
125136
transactionDhcTypeElement.firstChild().firstChild().toElement().setTagName( QStringLiteral( "Post" ) );
126137
transactionElement.appendChild( transactionDhcTypeElement );
127138

128-
//wfs:FeatureTypeList element
129-
QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ );
130-
wfsCapabilitiesElement.appendChild( featureTypeListElement );
131-
//wfs:Operations element
132-
QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
133-
featureTypeListElement.appendChild( operationsElement );
134-
//wfs:Query element
135-
QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ );
136-
operationsElement.appendChild( queryElement );
137-
/*
138-
* Adding layer liste in featureTypeListElement
139-
*/
140-
configParser->featureTypeList( featureTypeListElement, doc );
139+
//wfs:FeatureTypeList
140+
wfsCapabilitiesElement.appendChild( getFeatureTypeListElement( doc, serverIface, project ) );
141141

142142
/*
143143
* Adding ogc:Filter_Capabilities in capabilityElement
@@ -169,6 +169,224 @@ namespace QgsWfs
169169

170170
}
171171

172+
QDomElement getServiceElement( QDomDocument &doc, const QgsProject *project )
173+
{
174+
//Service element
175+
QDomElement serviceElem = doc.createElement( QStringLiteral( "Service" ) );
176+
177+
//Service name
178+
QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) );
179+
QDomText nameText = doc.createTextNode( "WFS" );
180+
nameElem.appendChild( nameText );
181+
serviceElem.appendChild( nameElem );
182+
183+
QString title = QgsServerProjectUtils::owsServiceTitle( *project );
184+
if ( !title.isEmpty() )
185+
{
186+
QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) );
187+
QDomText titleText = doc.createTextNode( title );
188+
titleElem.appendChild( titleText );
189+
serviceElem.appendChild( titleElem );
190+
}
191+
192+
QString abstract = QgsServerProjectUtils::owsServiceAbstract( *project );
193+
if ( !abstract.isEmpty() )
194+
{
195+
QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) );
196+
QDomText abstractText = doc.createCDATASection( abstract );
197+
abstractElem.appendChild( abstractText );
198+
serviceElem.appendChild( abstractElem );
199+
}
200+
201+
QStringList keywords = QgsServerProjectUtils::owsServiceKeywords( *project );
202+
if ( !keywords.isEmpty() && !keywords.join( QStringLiteral( ", " ) ).isEmpty() )
203+
{
204+
QDomElement keywordsElem = doc.createElement( QStringLiteral( "Keywords" ) );
205+
QDomText keywordsText = doc.createTextNode( keywords.join( QStringLiteral( ", " ) ) );
206+
keywordsElem.appendChild( keywordsText );
207+
serviceElem.appendChild( keywordsElem );
208+
}
209+
210+
QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "OnlineResource" ) );
211+
QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project );
212+
if ( !onlineResource.isEmpty() )
213+
{
214+
QDomText onlineResourceText = doc.createTextNode( onlineResource );
215+
onlineResourceElem.appendChild( onlineResourceText );
216+
}
217+
serviceElem.appendChild( onlineResourceElem );
218+
219+
QString fees = QgsServerProjectUtils::owsServiceFees( *project );
220+
if ( !fees.isEmpty() )
221+
{
222+
QDomElement feesElem = doc.createElement( QStringLiteral( "Fees" ) );
223+
QDomText feesText = doc.createTextNode( fees );
224+
feesElem.appendChild( feesText );
225+
serviceElem.appendChild( feesElem );
226+
}
227+
228+
QString accessConstraints = QgsServerProjectUtils::owsServiceAccessConstraints( *project );
229+
if ( !accessConstraints.isEmpty() )
230+
{
231+
QDomElement accessConstraintsElem = doc.createElement( QStringLiteral( "AccessConstraints" ) );
232+
QDomText accessConstraintsText = doc.createTextNode( accessConstraints );
233+
accessConstraintsElem.appendChild( accessConstraintsText );
234+
serviceElem.appendChild( accessConstraintsElem );
235+
}
236+
237+
return serviceElem;
238+
239+
}
240+
241+
QDomElement getFeatureTypeListElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project )
242+
{
243+
QgsAccessControl *accessControl = serverIface->accessControls();
244+
245+
//wfs:FeatureTypeList element
246+
QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ );
247+
//wfs:Operations element
248+
QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
249+
featureTypeListElement.appendChild( operationsElement );
250+
//wfs:Query element
251+
QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ );
252+
operationsElement.appendChild( queryElement );
253+
254+
QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
255+
QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project );
256+
QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project );
257+
QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project );
258+
for ( int i = 0; i < wfsLayerIds.size(); ++i )
259+
{
260+
QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) );
261+
if ( layer->type() != QgsMapLayer::LayerType::VectorLayer )
262+
{
263+
continue;
264+
}
265+
if ( accessControl && !accessControl->layerReadPermission( layer ) )
266+
{
267+
continue;
268+
}
269+
270+
QDomElement layerElem = doc.createElement( QStringLiteral( "FeatureType" ) );
271+
272+
//create Name
273+
QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) );
274+
QString typeName = layer->name();
275+
if ( !layer->shortName().isEmpty() )
276+
typeName = layer->shortName();
277+
typeName = typeName.replace( QLatin1String( " " ), QLatin1String( "_" ) );
278+
QDomText nameText = doc.createTextNode( typeName );
279+
nameElem.appendChild( nameText );
280+
layerElem.appendChild( nameElem );
281+
282+
//create Title
283+
QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) );
284+
QString title = layer->title();
285+
if ( title.isEmpty() )
286+
{
287+
title = layer->name();
288+
}
289+
QDomText titleText = doc.createTextNode( title );
290+
titleElem.appendChild( titleText );
291+
layerElem.appendChild( titleElem );
292+
293+
//create Abstract
294+
QString abstract = layer->abstract();
295+
if ( !abstract.isEmpty() )
296+
{
297+
QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) );
298+
QDomText abstractText = doc.createTextNode( abstract );
299+
abstractElem.appendChild( abstractText );
300+
layerElem.appendChild( abstractElem );
301+
}
302+
303+
//create keywords
304+
QString keywords = layer->keywordList();
305+
if ( !keywords.isEmpty() )
306+
{
307+
QDomElement keywordsElem = doc.createElement( QStringLiteral( "Keywords" ) );
308+
QDomText keywordsText = doc.createTextNode( keywords );
309+
keywordsElem.appendChild( keywordsText );
310+
layerElem.appendChild( keywordsElem );
311+
}
312+
313+
//create SRS
314+
QDomElement srsElem = doc.createElement( QStringLiteral( "SRS" ) );
315+
QDomText srsText = doc.createTextNode( layer->crs().authid() );
316+
srsElem.appendChild( srsText );
317+
layerElem.appendChild( srsElem );
318+
319+
//create LatLongBoundingBox
320+
QgsRectangle layerExtent = layer->extent();
321+
QDomElement bBoxElement = doc.createElement( QStringLiteral( "LatLongBoundingBox" ) );
322+
bBoxElement.setAttribute( QStringLiteral( "minx" ), QString::number( layerExtent.xMinimum() ) );
323+
bBoxElement.setAttribute( QStringLiteral( "miny" ), QString::number( layerExtent.yMinimum() ) );
324+
bBoxElement.setAttribute( QStringLiteral( "maxx" ), QString::number( layerExtent.xMaximum() ) );
325+
bBoxElement.setAttribute( QStringLiteral( "maxy" ), QString::number( layerExtent.yMaximum() ) );
326+
layerElem.appendChild( bBoxElement );
327+
328+
// layer metadata URL
329+
QString metadataUrl = layer->metadataUrl();
330+
if ( !metadataUrl.isEmpty() )
331+
{
332+
QDomElement metaUrlElem = doc.createElement( QStringLiteral( "MetadataURL" ) );
333+
QString metadataUrlType = layer->metadataUrlType();
334+
metaUrlElem.setAttribute( QStringLiteral( "type" ), metadataUrlType );
335+
QString metadataUrlFormat = layer->metadataUrlFormat();
336+
if ( metadataUrlFormat == QLatin1String( "text/xml" ) )
337+
{
338+
metaUrlElem.setAttribute( QStringLiteral( "format" ), QStringLiteral( "XML" ) );
339+
}
340+
else
341+
{
342+
metaUrlElem.setAttribute( QStringLiteral( "format" ), QStringLiteral( "TXT" ) );
343+
}
344+
QDomText metaUrlText = doc.createTextNode( metadataUrl );
345+
metaUrlElem.appendChild( metaUrlText );
346+
layerElem.appendChild( metaUrlElem );
347+
}
348+
349+
//wfs:Operations element
350+
QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
351+
//wfs:Query element
352+
QDomElement queryElement = doc.createElement( QStringLiteral( "Query" )/*wfs:Query*/ );
353+
operationsElement.appendChild( queryElement );
354+
if ( wfstUpdateLayersId.contains( layer->id() ) ||
355+
wfstInsertLayersId.contains( layer->id() ) ||
356+
wfstDeleteLayersId.contains( layer->id() ) )
357+
{
358+
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
359+
QgsVectorDataProvider *provider = vlayer->dataProvider();
360+
if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) )
361+
{
362+
//wfs:Insert element
363+
QDomElement insertElement = doc.createElement( QStringLiteral( "Insert" )/*wfs:Insert*/ );
364+
operationsElement.appendChild( insertElement );
365+
}
366+
if ( ( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) &&
367+
( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) &&
368+
wfstUpdateLayersId.contains( layer->id() ) )
369+
{
370+
//wfs:Update element
371+
QDomElement updateElement = doc.createElement( QStringLiteral( "Update" )/*wfs:Update*/ );
372+
operationsElement.appendChild( updateElement );
373+
}
374+
if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) )
375+
{
376+
//wfs:Delete element
377+
QDomElement deleteElement = doc.createElement( QStringLiteral( "Delete" )/*wfs:Delete*/ );
378+
operationsElement.appendChild( deleteElement );
379+
}
380+
}
381+
382+
layerElem.appendChild( operationsElement );
383+
384+
featureTypeListElement.appendChild( layerElem );
385+
}
386+
387+
return featureTypeListElement;
388+
}
389+
172390
} // samespace QgsWfs
173391

174392

‎src/server/services/wfs/qgswfsgetcapabilities.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -26,6 +27,16 @@
2627
namespace QgsWfs
2728
{
2829

30+
/**
31+
* Create FeatureTypeList element for get capabilities document
32+
*/
33+
QDomElement getFeatureTypeListElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project );
34+
35+
/**
36+
* Create Service element for get capabilities document
37+
*/
38+
QDomElement getServiceElement( QDomDocument &doc, const QgsProject *project );
39+
2940
/**
3041
* Create get capabilities document
3142
*/

‎src/server/services/wfs/qgswfsgetfeature.cpp

Lines changed: 593 additions & 684 deletions
Large diffs are not rendered by default.

‎src/server/services/wfs/qgswfsgetfeature.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -24,6 +25,39 @@
2425

2526
namespace QgsWfs
2627
{
28+
struct getFeatureQuery
29+
{
30+
QString typeName;
31+
32+
QgsFeatureRequest featureRequest;
33+
34+
QStringList propertyList;
35+
};
36+
37+
struct getFeatureRequest
38+
{
39+
long maxFeatures;
40+
41+
long startIndex;
42+
43+
QString outputFormat;
44+
45+
QList< getFeatureQuery > queries;
46+
47+
QString geometryName;
48+
};
49+
50+
/** Transform Query element to getFeatureQuery
51+
*/
52+
getFeatureQuery parseQueryElement( QDomElement &queryElem );
53+
54+
/** Transform RequestBody root element to getFeatureRequest
55+
*/
56+
getFeatureRequest parseGetFeatureRequestBody( QDomElement &docElem );
57+
58+
/** Transform parameters to getFeatureRequest
59+
*/
60+
getFeatureRequest parseGetFeatureParameters( QgsServerRequest::Parameters parameters );
2761

2862
/** Output WFS GetFeature response
2963
*/

‎src/server/services/wfs/qgswfstransaction.cpp

Lines changed: 1014 additions & 397 deletions
Large diffs are not rendered by default.

‎src/server/services/wfs/qgswfstransaction.h

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler (original code)
6+
(C) 2012 by René-Luc D'Hont (original code)
67
(C) 2014 by Alessandro Pasotti (original code)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -24,19 +25,99 @@
2425

2526
namespace QgsWfs
2627
{
28+
struct transactionInsert
29+
{
30+
QString typeName;
31+
32+
QString handle;
33+
34+
QDomNodeList featureNodeList;
35+
36+
QStringList insertFeatureIds;
37+
38+
bool error;
39+
40+
QString errorMsg;
41+
};
42+
43+
struct transactionUpdate
44+
{
45+
QString typeName;
46+
47+
QString handle;
48+
49+
QMap<QString, QString> propertyMap;
50+
51+
QDomElement geometryElement;
52+
53+
QgsFeatureRequest featureRequest;
54+
55+
bool error;
56+
57+
QString errorMsg;
58+
};
59+
60+
struct transactionDelete
61+
{
62+
QString typeName;
63+
64+
QString handle;
65+
66+
QgsFeatureRequest featureRequest;
67+
68+
bool error;
69+
70+
QString errorMsg;
71+
};
72+
73+
struct transactionRequest
74+
{
75+
QList< transactionInsert > inserts;
76+
77+
QList< transactionUpdate > updates;
78+
79+
QList< transactionDelete > deletes;
80+
};
81+
82+
/** Transform Insert element to transactionInsert
83+
*/
84+
transactionInsert parseInsertActionElement( QDomElement &actionElem );
85+
86+
/** Transform Update element to transactionUpdate
87+
*/
88+
transactionUpdate parseUpdateActionElement( QDomElement &actionElem );
89+
90+
/** Transform Delete element to transactionDelete
91+
*/
92+
transactionDelete parseDeleteActionElement( QDomElement &actionElem );
93+
94+
/** Transform RequestBody root element to getFeatureRequest
95+
*/
96+
transactionRequest parseTransactionRequestBody( QDomElement &docElem );
97+
98+
transactionRequest parseTransactionParameters( QgsServerRequest::Parameters parameters );
99+
100+
/** Transform GML feature nodes to features
101+
*/
102+
QgsFeatureList featuresFromGML( QDomNodeList featureNodeList, QgsVectorDataProvider *provider );
103+
104+
/** Perform the transaction
105+
*/
106+
void performTransaction( transactionRequest &aRequest, QgsServerInterface *serverIface, const QgsProject *project );
27107

28108
/**
29109
* Output WFS transaction response
30110
*/
31-
void writeTransaction( QgsServerInterface *serverIface, const QString &version,
32-
const QgsServerRequest &request, QgsServerResponse &response );
111+
void writeTransaction( QgsServerInterface *serverIface, const QgsProject *project,
112+
const QString &version, const QgsServerRequest &request,
113+
QgsServerResponse &response );
33114

34115

35116
/**
36117
* Create a wfs transaction document
37118
*/
38-
QDomDocument createTransactionDocument( QgsServerInterface *serverIface, const QString &version,
39-
const QgsServerRequest &request );
119+
QDomDocument createTransactionDocument( QgsServerInterface *serverIface, const QgsProject *project,
120+
const QString &version, const QgsServerRequest &request );
40121

41122
} // samespace QgsWfs
42123

‎src/server/services/wfs/qgswfsutils.cpp

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
-------------------------
44
begin : December 20 , 2016
55
copyright : (C) 2007 by Marco Hugentobler ( parts fron qgswmshandler)
6+
(C) 2012 by René-Luc D'Hont ( parts from qgswmshandler)
67
(C) 2014 by Alessandro Pasotti ( parts from qgswmshandler)
78
(C) 2017 by David Marteau
89
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -20,6 +21,7 @@
2021
***************************************************************************/
2122

2223
#include "qgswfsutils.h"
24+
#include "qgsogcutils.h"
2325
#include "qgsconfigcache.h"
2426
#include "qgsserverprojectutils.h"
2527

@@ -30,21 +32,6 @@ namespace QgsWfs
3032
return QStringLiteral( "1.0.0" );
3133
}
3234

33-
// Return the wms config parser (Transitional)
34-
QgsWfsProjectParser *getConfigParser( QgsServerInterface *serverIface )
35-
{
36-
QString configFilePath = serverIface->configFilePath();
37-
38-
QgsWfsProjectParser *parser = QgsConfigCache::instance()->wfsConfiguration( configFilePath, serverIface->accessControls() );
39-
if ( !parser )
40-
{
41-
throw QgsServiceException(
42-
QStringLiteral( "WFS configuration error" ),
43-
QStringLiteral( "There was an error reading the project file or the SLD configuration" ) );
44-
}
45-
return parser;
46-
}
47-
4835
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project )
4936
{
5037
QString href;
@@ -71,6 +58,86 @@ namespace QgsWfs
7158
return href;
7259
}
7360

61+
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem )
62+
{
63+
QgsFeatureRequest request;
64+
65+
QDomNodeList fidNodes = filterElem.elementsByTagName( QStringLiteral( "FeatureId" ) );
66+
if ( !fidNodes.isEmpty() )
67+
{
68+
QgsFeatureIds fids;
69+
QDomElement fidElem;
70+
for ( int f = 0; f < fidNodes.size(); f++ )
71+
{
72+
fidElem = fidNodes.at( f ).toElement();
73+
if ( !fidElem.hasAttribute( QStringLiteral( "fid" ) ) )
74+
{
75+
throw QgsRequestNotWellFormedException( "FeatureId element without fid attribute" );
76+
}
77+
78+
QString fid = fidElem.attribute( QStringLiteral( "fid" ) );
79+
if ( fid.contains( QLatin1String( "." ) ) )
80+
{
81+
if ( fid.section( QStringLiteral( "." ), 0, 0 ) != typeName )
82+
continue;
83+
fid = fid.section( QStringLiteral( "." ), 1, 1 );
84+
}
85+
fids.insert( fid.toInt() );
86+
}
87+
88+
if ( fids.size() > 0 )
89+
{
90+
request.setFilterFids( fids );
91+
}
92+
else
93+
{
94+
throw QgsRequestNotWellFormedException( QStringLiteral( "No FeatureId element corrcetly parse against typeName '%1'" ).arg( typeName ) );
95+
}
96+
request.setFlags( QgsFeatureRequest::NoFlags );
97+
return request;
98+
}
99+
else if ( filterElem.firstChildElement().tagName() == QLatin1String( "BBOX" ) )
100+
{
101+
QDomElement bboxElem = filterElem.firstChildElement();
102+
QDomElement childElem = bboxElem.firstChildElement();
103+
104+
while ( !childElem.isNull() )
105+
{
106+
if ( childElem.tagName() == QLatin1String( "Box" ) )
107+
{
108+
request.setFilterRect( QgsOgcUtils::rectangleFromGMLBox( childElem ) );
109+
}
110+
else if ( childElem.tagName() != QLatin1String( "PropertyName" ) )
111+
{
112+
QgsGeometry geom = QgsOgcUtils::geometryFromGML( childElem );
113+
request.setFilterRect( geom.boundingBox() );
114+
}
115+
childElem = childElem.nextSiblingElement();
116+
}
117+
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
118+
return request;
119+
}
120+
else
121+
{
122+
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );
123+
if ( filter )
124+
{
125+
if ( filter->hasParserError() )
126+
{
127+
throw QgsRequestNotWellFormedException( filter->parserErrorString() );
128+
}
129+
130+
if ( filter->needsGeometry() )
131+
{
132+
request.setFlags( QgsFeatureRequest::NoFlags );
133+
}
134+
request.setFilterExpression( filter->expression() );
135+
return request;
136+
}
137+
}
138+
return request;
139+
}
140+
74141
} // namespace QgsWfs
75142

76143

‎src/server/services/wfs/qgswfsutils.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
------------------------------------
66
begin : December 20 , 2016
77
copyright : (C) 2007 by Marco Hugentobler ( parts fron qgswfshandler)
8+
(C) 2012 by René-Luc D'Hont ( parts from qgswmshandler)
89
(C) 2014 by Alessandro Pasotti ( parts from qgswfshandler)
910
(C) 2017 by David Marteau
1011
email : marco dot hugentobler at karto dot baug dot ethz dot ch
@@ -24,7 +25,7 @@
2425
#define QGSWFSUTILS_H
2526

2627
#include "qgsmodule.h"
27-
#include "qgswfsprojectparser.h"
28+
#include "qgsfeaturerequest.h"
2829
#include "qgswfsserviceexception.h"
2930

3031
/**
@@ -40,19 +41,15 @@ namespace QgsWfs
4041
*/
4142
QString implementationVersion();
4243

43-
/**
44-
* Return the wms config parser (Transitional)
45-
*
46-
* XXX This is needed in the current implementation.
47-
* This should disappear as soon we get rid of singleton.
48-
*/
49-
QgsWfsProjectParser *getConfigParser( QgsServerInterface *serverIface );
50-
5144
/**
5245
* Service URL string
5346
*/
5447
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project );
5548

49+
/** Transform a Filter element to a feature request
50+
*/
51+
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem );
52+
5653
// Define namespaces used in WFS documents
5754
const QString WFS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wfs" );
5855
const QString GML_NAMESPACE = QStringLiteral( "http://www.opengis.net/gml" );

‎tests/src/python/test_qgsserver_accesscontrol.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def test_wfs_getcapabilities(self):
458458
query_string = "&".join(["%s=%s" % i for i in list({
459459
"MAP": urllib.parse.quote(self.projectPath),
460460
"SERVICE": "WFS",
461-
"VERSION": "1.1.0",
461+
"VERSION": "1.0.0",
462462
"REQUEST": "GetCapabilities"
463463
}.items())])
464464

@@ -482,7 +482,7 @@ def test_wfs_describefeaturetype_hello(self):
482482
query_string = "&".join(["%s=%s" % i for i in list({
483483
"MAP": urllib.parse.quote(self.projectPath),
484484
"SERVICE": "WFS",
485-
"VERSION": "1.1.0",
485+
"VERSION": "1.0.0",
486486
"REQUEST": "DescribeFeatureType",
487487
"TYPENAME": "Hello"
488488
}.items())])
@@ -501,7 +501,7 @@ def test_wfs_describefeaturetype_country(self):
501501
query_string = "&".join(["%s=%s" % i for i in list({
502502
"MAP": urllib.parse.quote(self.projectPath),
503503
"SERVICE": "WFS",
504-
"VERSION": "1.1.0",
504+
"VERSION": "1.0.0",
505505
"REQUEST": "DescribeFeatureType",
506506
"TYPENAME": "Country"
507507
}.items())])
@@ -722,8 +722,7 @@ def test_wfstransaction_insert(self):
722722
headers.get("Content-Type"), "text/xml; charset=utf-8",
723723
"Content type for Insert is wrong: %s" % headers.get("Content-Type"))
724724
self.assertTrue(
725-
str(response).find(
726-
'<ServiceException code="Security">Feature modify permission denied</ServiceException>') != -1,
725+
str(response).find("<SUCCESS/>") == -1,
727726
"WFS/Transactions Insert succeed\n%s" % response)
728727

729728
response, headers = self._post_restricted(data.format(color="red"), "LAYER_PERM=no")
@@ -732,7 +731,7 @@ def test_wfstransaction_insert(self):
732731
"Content type for Insert is wrong: %s" % headers.get("Content-Type"))
733732
self.assertTrue(
734733
str(response).find(
735-
'<ServiceException code="Security">Feature insert permission denied</ServiceException>') != -1,
734+
'<ServiceException code="Security">No permissions to do WFS changes on layer \\\'db_point\\\'</ServiceException>') != -1,
736735
"WFS/Transactions Insert succeed\n%s" % response)
737736

738737
response, headers = self._post_restricted(data.format(color="yellow"), "LAYER_PERM=yes")
@@ -753,8 +752,7 @@ def test_wfstransaction_update(self):
753752
headers.get("Content-Type"), "text/xml; charset=utf-8",
754753
"Content type for GetMap is wrong: %s" % headers.get("Content-Type"))
755754
self.assertTrue(
756-
str(response).find(
757-
'<ServiceException code="Security">Feature modify permission denied</ServiceException>') != -1,
755+
str(response).find("<SUCCESS/>") == -1,
758756
"WFS/Transactions Update succeed\n%s" % response)
759757
self._test_colors({1: "blue"})
760758

@@ -772,8 +770,7 @@ def test_wfstransaction_update(self):
772770
headers.get("Content-Type"), "text/xml; charset=utf-8",
773771
"Content type for Update is wrong: %s" % headers.get("Content-Type"))
774772
self.assertTrue(
775-
str(response).find(
776-
'<ServiceException code="Security">Feature modify permission denied</ServiceException>') != -1,
773+
str(response).find("<SUCCESS/>") == -1,
777774
"WFS/Transactions Update succeed\n%s" % response)
778775
self._test_colors({1: "red"})
779776

@@ -783,7 +780,7 @@ def test_wfstransaction_update(self):
783780
"Content type for Update is wrong: %s" % headers.get("Content-Type"))
784781
self.assertTrue(
785782
str(response).find(
786-
'<ServiceException code="Security">Feature update permission denied</ServiceException>') != -1,
783+
'<ServiceException code="Security">No permissions to do WFS changes on layer \\\'db_point\\\'</ServiceException>') != -1,
787784
"WFS/Transactions Update succeed\n%s" % response)
788785
self._test_colors({1: "red"})
789786

@@ -817,8 +814,7 @@ def test_wfstransaction_delete_restricted(self):
817814
headers.get("Content-Type"), "text/xml; charset=utf-8",
818815
"Content type for GetMap is wrong: %s" % headers.get("Content-Type"))
819816
self.assertTrue(
820-
str(response).find(
821-
'<ServiceException code="Security">Feature modify permission denied</ServiceException>') != -1,
817+
str(response).find("<SUCCESS/>") == -1,
822818
"WFS/Transactions Delete succeed\n%s" % response)
823819

824820
data_update = WFS_TRANSACTION_UPDATE.format(id="1", color="red", xml_ns=XML_NS)
@@ -831,7 +827,7 @@ def test_wfstransaction_delete_restricted(self):
831827
"Content type for GetMap is wrong: %s" % headers.get("Content-Type"))
832828
self.assertTrue(
833829
str(response).find(
834-
'<ServiceException code="Security">Feature delete permission denied</ServiceException>') != -1,
830+
'<ServiceException code="Security">No permissions to do WFS changes on layer \\\'db_point\\\'</ServiceException>') != -1,
835831
"WFS/Transactions Delete succeed\n%s" % response)
836832

837833
response, headers = self._post_restricted(data, "LAYER_PERM=yes")

‎tests/src/python/test_qgsserver_wfst.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def _checkAddFeatures(self, wfs_layer, layer, features):
183183
layer = self._getLayer(layer.name())
184184
self.assertTrue(layer.isValid())
185185
self.assertEqual(layer.featureCount(), len(features))
186+
self.assertEqual(wfs_layer.dataProvider().featureCount(), len(features))
186187

187188
def _checkUpdateFeatures(self, wfs_layer, old_features, new_features):
188189
"""

‎tests/testdata/qgis_server/wfs_getcapabilities.txt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@ Content-Type: text/xml; charset=utf-8
66
<Name>WFS</Name>
77
<Title>QGIS TestProject</Title>
88
<Abstract>Some UTF8 text èòù</Abstract>
9-
<OnlineResource></OnlineResource>
10-
<Fees>None</Fees>
11-
<AccessConstraints>None</AccessConstraints>
9+
<OnlineResource/>
1210
</Service>
1311
<Capability>
1412
<Request>
1513
<GetCapabilities>
1614
<DCPType>
1715
<HTTP>
18-
<Get onlineResource="http:"/>
16+
<Get onlineResource="?"/>
1917
</HTTP>
2018
</DCPType>
2119
<DCPType>
2220
<HTTP>
23-
<Post onlineResource="http:"/>
21+
<Post onlineResource="?"/>
2422
</HTTP>
2523
</DCPType>
2624
</GetCapabilities>
@@ -30,12 +28,12 @@ Content-Type: text/xml; charset=utf-8
3028
</SchemaDescriptionLanguage>
3129
<DCPType>
3230
<HTTP>
33-
<Get onlineResource="http:"/>
31+
<Get onlineResource="?"/>
3432
</HTTP>
3533
</DCPType>
3634
<DCPType>
3735
<HTTP>
38-
<Post onlineResource="http:"/>
36+
<Post onlineResource="?"/>
3937
</HTTP>
4038
</DCPType>
4139
</DescribeFeatureType>
@@ -47,19 +45,19 @@ Content-Type: text/xml; charset=utf-8
4745
</ResultFormat>
4846
<DCPType>
4947
<HTTP>
50-
<Get onlineResource="http:"/>
48+
<Get onlineResource="?"/>
5149
</HTTP>
5250
</DCPType>
5351
<DCPType>
5452
<HTTP>
55-
<Post onlineResource="http:"/>
53+
<Post onlineResource="?"/>
5654
</HTTP>
5755
</DCPType>
5856
</GetFeature>
5957
<Transaction>
6058
<DCPType>
6159
<HTTP>
62-
<Post onlineResource="http:"/>
60+
<Post onlineResource="?"/>
6361
</HTTP>
6462
</DCPType>
6563
</Transaction>
@@ -74,13 +72,13 @@ Content-Type: text/xml; charset=utf-8
7472
<Title>A test vector layer</Title>
7573
<Abstract>A test vector layer with unicode òà</Abstract>
7674
<SRS>EPSG:4326</SRS>
75+
<LatLongBoundingBox maxx="8.20355" minx="8.20346" maxy="44.9015" miny="44.9014"/>
7776
<Operations>
7877
<Query/>
7978
<Insert/>
8079
<Update/>
8180
<Delete/>
8281
</Operations>
83-
<LatLongBoundingBox maxx="8.20355" minx="8.20346" maxy="44.9015" miny="44.9014"/>
8482
</FeatureType>
8583
</FeatureTypeList>
8684
<ogc:Filter_Capabilities>

0 commit comments

Comments
 (0)
Please sign in to comment.