mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
WFS3 add ACL and other visibility options
This commit is contained in:
parent
db6d34a846
commit
95c0ad54ff
@ -12,6 +12,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsServerApiUtils
|
||||
{
|
||||
%Docstring
|
||||
@ -57,7 +58,6 @@ This method takes into account the ACL restrictions provided by QGIS Server Acce
|
||||
.. note::
|
||||
|
||||
project must not be NULL
|
||||
TODO: implement ACL
|
||||
%End
|
||||
|
||||
|
||||
|
@ -207,9 +207,11 @@ Fallback to the default content type of the handler if none of the above matches
|
||||
Returns a link to the parent page up to ``levels`` in the HTML hierarchy from the given ``url``, MAP query argument is preserved
|
||||
%End
|
||||
|
||||
static QgsVectorLayer *layerFromCollection( const QgsServerApiContext &context, const QString &collectionId );
|
||||
static QgsVectorLayer *layerFromCollectionId( const QgsServerApiContext &context, const QString &collectionId );
|
||||
%Docstring
|
||||
Returns a vector layer from the ``collectionId`` in the given ``context``
|
||||
Returns a vector layer from the ``collectionId`` in the given ``context``.
|
||||
|
||||
:raises QgsServerApiNotFoundError: if the layer could not be found.
|
||||
%End
|
||||
|
||||
|
||||
|
@ -25,6 +25,12 @@
|
||||
#include <QString>
|
||||
#include "qgsproject.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
#include "qgsserverapicontext.h"
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
#include "qgsaccesscontrol.h"
|
||||
#include "qgsserverinterface.h"
|
||||
#endif
|
||||
|
||||
class QgsRectangle;
|
||||
class QgsCoordinateReferenceSystem;
|
||||
@ -79,7 +85,6 @@ class SERVER_EXPORT QgsServerApiUtils
|
||||
* This method takes into account the ACL restrictions provided by QGIS Server Access Control plugins.
|
||||
*
|
||||
* \note project must not be NULL
|
||||
* TODO: implement ACL
|
||||
*/
|
||||
static const QVector<QgsMapLayer *> publishedWfsLayers( const QgsProject *project );
|
||||
|
||||
@ -92,28 +97,34 @@ class SERVER_EXPORT QgsServerApiUtils
|
||||
*
|
||||
* QVector<QgsVectorLayer*> vectorLayers = publishedLayers<QgsVectorLayer>();
|
||||
*
|
||||
* TODO: implement ACL
|
||||
* \note not available in Python bindings
|
||||
* \see publishedWfsLayers()
|
||||
*/
|
||||
template <typename T>
|
||||
static const QVector<T *> publishedWfsLayers( const QgsProject *project )
|
||||
static const QVector<const T *> publishedWfsLayers( const QgsServerApiContext &context )
|
||||
{
|
||||
const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
|
||||
const QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project );
|
||||
const QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project );
|
||||
const QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project );
|
||||
QVector<T *> result;
|
||||
const auto constLayers { project->layers<T *>() };
|
||||
for ( const auto &layer : constLayers )
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = context.serverInterface()->accessControls();
|
||||
#endif
|
||||
const QgsProject *project = context.project();
|
||||
QVector<const T *> result;
|
||||
if ( project )
|
||||
{
|
||||
if ( wfstUpdateLayersId.contains( layer->id() ) ||
|
||||
wfstInsertLayersId.contains( layer->id() ) ||
|
||||
wfstDeleteLayersId.contains( layer->id() ) )
|
||||
const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
|
||||
const auto constLayers { project->layers<T *>() };
|
||||
for ( const auto &layer : constLayers )
|
||||
{
|
||||
if ( ! wfsLayerIds.contains( layer->id() ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
if ( accessControl && !accessControl->layerReadPermission( layer ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
result.push_back( layer );
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ QgsVectorLayer *QgsServerOgcApiHandler::layerFromContext( const QgsServerApiCont
|
||||
}
|
||||
const QString collectionId { match.captured( QStringLiteral( "collectionId" ) ) };
|
||||
// May throw if not found
|
||||
return layerFromCollection( context, collectionId );
|
||||
return layerFromCollectionId( context, collectionId );
|
||||
|
||||
}
|
||||
|
||||
@ -463,12 +463,12 @@ QString QgsServerOgcApiHandler::parentLink( const QUrl &url, int levels )
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
QgsVectorLayer *QgsServerOgcApiHandler::layerFromCollection( const QgsServerApiContext &context, const QString &collectionId )
|
||||
QgsVectorLayer *QgsServerOgcApiHandler::layerFromCollectionId( const QgsServerApiContext &context, const QString &collectionId )
|
||||
{
|
||||
const auto mapLayers { context.project()->mapLayersByShortName<QgsVectorLayer *>( collectionId ) };
|
||||
if ( mapLayers.count() != 1 )
|
||||
{
|
||||
throw QgsServerApiImproperlyConfiguredException( QStringLiteral( "Collection with given id (%1) was not found or multiple matches were found" ).arg( collectionId ) );
|
||||
throw QgsServerApiNotFoundError( QStringLiteral( "Collection with given id (%1) was not found or multiple matches were found" ).arg( collectionId ) );
|
||||
}
|
||||
return mapLayers.first();
|
||||
}
|
||||
|
@ -314,9 +314,10 @@ class SERVER_EXPORT QgsServerOgcApiHandler
|
||||
static QString parentLink( const QUrl &url, int levels = 1 );
|
||||
|
||||
/**
|
||||
* Returns a vector layer from the \a collectionId in the given \a context
|
||||
* Returns a vector layer from the \a collectionId in the given \a context.
|
||||
* \throws QgsServerApiNotFoundError if the layer could not be found.
|
||||
*/
|
||||
static QgsVectorLayer *layerFromCollection( const QgsServerApiContext &context, const QString &collectionId );
|
||||
static QgsVectorLayer *layerFromCollectionId( const QgsServerApiContext &context, const QString &collectionId );
|
||||
|
||||
/**
|
||||
* Returns the defaultResponse as JSON
|
||||
|
@ -28,6 +28,12 @@
|
||||
#include "qgsbufferserverrequest.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
#include "qgsserverinterface.h"
|
||||
#include "qgsexpressioncontext.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
#include "qgsfilterrestorer.h"
|
||||
#endif
|
||||
|
||||
#include <QMimeDatabase>
|
||||
|
||||
@ -187,6 +193,77 @@ json QgsWfs3APIHandler::schema( const QgsServerApiContext &context ) const
|
||||
return data;
|
||||
}
|
||||
|
||||
void QgsWfs3AbstractItemsHandler::checkLayerIsAccessible( const QgsVectorLayer *mapLayer, const QgsServerApiContext &context ) const
|
||||
{
|
||||
const QVector<const QgsVectorLayer *> publishedLayers = QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context );
|
||||
if ( ! publishedLayers.contains( mapLayer ) )
|
||||
{
|
||||
throw QgsServerApiNotFoundError( QStringLiteral( "Collection was not found" ) );
|
||||
}
|
||||
}
|
||||
|
||||
QgsFeatureRequest QgsWfs3AbstractItemsHandler::filteredRequest( const QgsVectorLayer *layer, const QgsServerApiContext &context ) const
|
||||
{
|
||||
QgsFeatureRequest featureRequest;
|
||||
QgsExpressionContext expressionContext;
|
||||
expressionContext << QgsExpressionContextUtils::globalScope()
|
||||
<< QgsExpressionContextUtils::projectScope( context.project() )
|
||||
<< QgsExpressionContextUtils::layerScope( layer );
|
||||
|
||||
featureRequest.setExpressionContext( expressionContext );
|
||||
|
||||
//is there alias info for this vector layer?
|
||||
QMap< int, QString > layerAliasInfo;
|
||||
const QgsStringMap aliasMap = layer->attributeAliases();
|
||||
for ( const auto &aliasKey : aliasMap.keys() )
|
||||
{
|
||||
int attrIndex = layer->fields().lookupField( aliasKey );
|
||||
if ( attrIndex != -1 )
|
||||
{
|
||||
layerAliasInfo.insert( attrIndex, aliasIt.value() );
|
||||
}
|
||||
}
|
||||
|
||||
QgsAttributeList attrIndexes = layer->attributeList();
|
||||
|
||||
// Removed attributes
|
||||
//excluded attributes for this layer
|
||||
const QSet<QString> &layerExcludedAttributes = layer->excludeAttributesWfs();
|
||||
if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
|
||||
{
|
||||
const QgsFields &fields = layer->fields();
|
||||
for ( const QString &excludedAttribute : layerExcludedAttributes )
|
||||
{
|
||||
int fieldNameIdx = fields.indexOf( excludedAttribute );
|
||||
if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
|
||||
{
|
||||
attrIndexes.removeOne( fieldNameIdx );
|
||||
}
|
||||
}
|
||||
}
|
||||
featureRequest.setSubsetOfAttributes( attrIndexes );
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
// Python plugins can make further modifications to the allowed attributes
|
||||
QgsAccessControl *accessControl = context.serverInterface()->accessControls();
|
||||
if ( accessControl )
|
||||
{
|
||||
accessControl->filterFeatures( layer, featureRequest );
|
||||
|
||||
QStringList attributes = QStringList();
|
||||
for ( int idx : attrIndexes )
|
||||
{
|
||||
attributes.append( layer->fields().field( idx ).name() );
|
||||
}
|
||||
featureRequest.setSubsetOfAttributes(
|
||||
accessControl->layerAttributes( layer, attributes ),
|
||||
layer->fields() );
|
||||
}
|
||||
#endif
|
||||
|
||||
return featureRequest;
|
||||
}
|
||||
|
||||
QgsWfs3LandingPageHandler::QgsWfs3LandingPageHandler()
|
||||
{
|
||||
}
|
||||
@ -369,12 +446,26 @@ void QgsWfs3CollectionsHandler::handleRequest( const QgsServerApiContext &contex
|
||||
"crs", crss
|
||||
}
|
||||
};
|
||||
|
||||
if ( context.project() )
|
||||
{
|
||||
// TODO: include meshes?
|
||||
for ( const auto &layer : context.project()->layers<QgsVectorLayer *>( ) )
|
||||
|
||||
const QgsProject *project = context.project();
|
||||
const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
|
||||
for ( const QString &wfsLayerId : wfsLayerIds )
|
||||
{
|
||||
const QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( project->mapLayer( wfsLayerId ) );
|
||||
if ( !layer )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( layer->type() != QgsMapLayerType::VectorLayer )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the layer is published, raise not found if it is not
|
||||
checkLayerIsAccessible( layer, context );
|
||||
|
||||
const std::string title { layer->title().isEmpty() ? layer->name().toStdString() : layer->title().toStdString() };
|
||||
const QString shortName { layer->shortName().isEmpty() ? layer->name() : layer->shortName() };
|
||||
data["collections"].push_back(
|
||||
@ -495,9 +586,20 @@ void QgsWfs3DescribeCollectionHandler::handleRequest( const QgsServerApiContext
|
||||
}
|
||||
const QString collectionId { match.captured( QStringLiteral( "collectionId" ) ) };
|
||||
// May throw if not found
|
||||
const QgsVectorLayer *mapLayer { layerFromCollection( context, collectionId ) };
|
||||
const QgsVectorLayer *mapLayer { layerFromCollectionId( context, collectionId ) };
|
||||
Q_ASSERT( mapLayer );
|
||||
|
||||
|
||||
const QgsProject *project = context.project();
|
||||
const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
|
||||
if ( ! wfsLayerIds.contains( mapLayer->id() ) )
|
||||
{
|
||||
throw QgsServerApiNotFoundError( QStringLiteral( "Collection was not found" ) );
|
||||
}
|
||||
|
||||
// Check if the layer is published, raise not found if it is not
|
||||
checkLayerIsAccessible( mapLayer, context );
|
||||
|
||||
const std::string title { mapLayer->title().isEmpty() ? mapLayer->name().toStdString() : mapLayer->title().toStdString() };
|
||||
const QString shortName { mapLayer->shortName().isEmpty() ? mapLayer->name() : mapLayer->shortName() };
|
||||
json linksList = links( context );
|
||||
@ -561,7 +663,7 @@ json QgsWfs3DescribeCollectionHandler::schema( const QgsServerApiContext &contex
|
||||
json data;
|
||||
Q_ASSERT( context.project() );
|
||||
|
||||
const auto layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context.project() ) };
|
||||
const auto layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context ) };
|
||||
// Construct the context with collection id
|
||||
for ( const auto &mapLayer : layers )
|
||||
{
|
||||
@ -722,7 +824,7 @@ json QgsWfs3CollectionsItemsHandler::schema( const QgsServerApiContext &context
|
||||
json data;
|
||||
Q_ASSERT( context.project() );
|
||||
|
||||
const auto layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context.project() ) };
|
||||
const QVector<const QgsVectorLayer *> layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context ) };
|
||||
// Construct the context with collection id
|
||||
for ( const auto &mapLayer : layers )
|
||||
{
|
||||
@ -836,6 +938,10 @@ void QgsWfs3CollectionsItemsHandler::handleRequest( const QgsServerApiContext &c
|
||||
}
|
||||
QgsVectorLayer *mapLayer { layerFromContext( context ) };
|
||||
Q_ASSERT( mapLayer );
|
||||
|
||||
// Check if the layer is published, raise not found if it is not
|
||||
checkLayerIsAccessible( mapLayer, context );
|
||||
|
||||
const std::string title { mapLayer->title().isEmpty() ? mapLayer->name().toStdString() : mapLayer->title().toStdString() };
|
||||
const QString shortName { mapLayer->shortName().isEmpty() ? mapLayer->name() : mapLayer->shortName() };
|
||||
|
||||
@ -1063,27 +1169,49 @@ void QgsWfs3CollectionsFeatureHandler::handleRequest( const QgsServerApiContext
|
||||
{
|
||||
throw QgsServerApiImproperlyConfiguredException( QStringLiteral( "Project is invalid or undefined" ) );
|
||||
}
|
||||
|
||||
// Check collectionId
|
||||
const QRegularExpressionMatch match { path().match( context.request()->url().path( ) ) };
|
||||
if ( ! match.hasMatch() )
|
||||
{
|
||||
throw QgsServerApiNotFoundError( QStringLiteral( "Collection was not found" ) );
|
||||
}
|
||||
|
||||
const QString collectionId { match.captured( QStringLiteral( "collectionId" ) ) };
|
||||
// May throw if not found
|
||||
QgsVectorLayer *mapLayer { layerFromCollection( context, collectionId ) };
|
||||
QgsVectorLayer *mapLayer { layerFromCollectionId( context, collectionId ) };
|
||||
Q_ASSERT( mapLayer );
|
||||
|
||||
// Check if the layer is published, raise not found if it is not
|
||||
checkLayerIsAccessible( mapLayer, context );
|
||||
|
||||
const std::string title { mapLayer->title().isEmpty() ? mapLayer->name().toStdString() : mapLayer->title().toStdString() };
|
||||
|
||||
if ( context.request()->method() == QgsServerRequest::Method::GetMethod )
|
||||
{
|
||||
const QString featureId { match.captured( QStringLiteral( "featureId" ) ) };
|
||||
QgsJsonExporter exporter { mapLayer };
|
||||
const QgsFeature feature { mapLayer->getFeature( featureId.toLongLong() ) };
|
||||
if ( ! feature.isValid() )
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = context.serverInterface()->accessControls();
|
||||
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
|
||||
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
|
||||
std::unique_ptr< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
|
||||
if ( accessControl )
|
||||
{
|
||||
QgsOWSServerFilterRestorer::applyAccessControlLayerFilters( accessControl, mapLayer, filterRestorer->originalFilters() );
|
||||
}
|
||||
#endif
|
||||
|
||||
QgsFeatureRequest featureRequest = filteredRequest( mapLayer, context );
|
||||
featureRequest.setFilterFid( featureId.toLongLong() );
|
||||
QgsFeature feature;
|
||||
QgsFeatureIterator it { mapLayer->getFeatures( featureRequest ) };
|
||||
if ( ! it.nextFeature( feature ) && feature.isValid() )
|
||||
{
|
||||
QgsServerApiInternalServerError( QStringLiteral( "Invalid feature [%1]" ).arg( featureId ) );
|
||||
}
|
||||
|
||||
json data = exporter.exportFeatureToJsonObject( feature );
|
||||
data["links"] = links( context );
|
||||
json navigation = json::array();
|
||||
@ -1114,7 +1242,7 @@ json QgsWfs3CollectionsFeatureHandler::schema( const QgsServerApiContext &contex
|
||||
json data;
|
||||
Q_ASSERT( context.project() );
|
||||
|
||||
const auto layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context.project() ) };
|
||||
const auto layers { QgsServerApiUtils::publishedWfsLayers<QgsVectorLayer>( context ) };
|
||||
// Construct the context with collection id
|
||||
for ( const auto &mapLayer : layers )
|
||||
{
|
||||
|
@ -20,12 +20,35 @@
|
||||
|
||||
#include "qgsserverogcapihandler.h"
|
||||
|
||||
class QgsFeatureRequest;
|
||||
class QgsServerOgcApi;
|
||||
|
||||
/**
|
||||
* The QgsWfs3AbstractItemsHandler class provides some
|
||||
* functionality which is common to the handlers that
|
||||
* return items.
|
||||
*/
|
||||
class QgsWfs3AbstractItemsHandler: public QgsServerOgcApiHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Checks if the layer is published in WFS (and perform additional checks for access
|
||||
* control if plugins are enabled)
|
||||
* and throws an exception if it is not.
|
||||
* \param layer the map layer
|
||||
* \param context the server api context
|
||||
* \throws QgsServerApiNotFoundException if the layer is NOT published
|
||||
*/
|
||||
void checkLayerIsAccessible( const QgsVectorLayer *layer, const QgsServerApiContext &context ) const;
|
||||
|
||||
QgsFeatureRequest filteredRequest( const QgsVectorLayer *layer, const QgsServerApiContext &context ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* The APIHandler class Wfs3handles the API definition
|
||||
*/
|
||||
class QgsWfs3APIHandler: public QgsServerOgcApiHandler
|
||||
class QgsWfs3APIHandler: public QgsWfs3AbstractItemsHandler
|
||||
{
|
||||
public:
|
||||
|
||||
@ -44,6 +67,7 @@ class QgsWfs3APIHandler: public QgsServerOgcApiHandler
|
||||
|
||||
private:
|
||||
const QgsServerOgcApi *mApi = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -125,7 +149,7 @@ class QgsWfs3ConformanceHandler: public QgsServerOgcApiHandler
|
||||
* The CollectionsHandler lists all available collections for the current project
|
||||
* Path: /collections
|
||||
*/
|
||||
class QgsWfs3CollectionsHandler: public QgsServerOgcApiHandler
|
||||
class QgsWfs3CollectionsHandler: public QgsWfs3AbstractItemsHandler
|
||||
{
|
||||
public:
|
||||
|
||||
@ -155,7 +179,7 @@ class QgsWfs3CollectionsHandler: public QgsServerOgcApiHandler
|
||||
* The DescribeCollectionHandler describes a single collection
|
||||
* Path: /collections/{collectionId}
|
||||
*/
|
||||
class QgsWfs3DescribeCollectionHandler: public QgsServerOgcApiHandler
|
||||
class QgsWfs3DescribeCollectionHandler: public QgsWfs3AbstractItemsHandler
|
||||
{
|
||||
public:
|
||||
QgsWfs3DescribeCollectionHandler( );
|
||||
@ -175,7 +199,7 @@ class QgsWfs3DescribeCollectionHandler: public QgsServerOgcApiHandler
|
||||
* The CollectionsItemsHandler list all items in the collection
|
||||
* Path: /collections/{collectionId}
|
||||
*/
|
||||
class QgsWfs3CollectionsItemsHandler: public QgsServerOgcApiHandler
|
||||
class QgsWfs3CollectionsItemsHandler: public QgsWfs3AbstractItemsHandler
|
||||
{
|
||||
public:
|
||||
QgsWfs3CollectionsItemsHandler( );
|
||||
@ -204,7 +228,7 @@ class QgsWfs3CollectionsItemsHandler: public QgsServerOgcApiHandler
|
||||
};
|
||||
|
||||
|
||||
class QgsWfs3CollectionsFeatureHandler: public QgsServerOgcApiHandler
|
||||
class QgsWfs3CollectionsFeatureHandler: public QgsWfs3AbstractItemsHandler
|
||||
{
|
||||
public:
|
||||
QgsWfs3CollectionsFeatureHandler( );
|
||||
|
@ -70,7 +70,7 @@ class QgsServerAPIUtilsTest(QgsServerTestBase):
|
||||
"""Test published WMS CRSs"""
|
||||
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
crss = QgsServerApiUtils.publishedCrsList(project)
|
||||
self.assertTrue('http://www.opengis.net/def/crs/OGC/1.3/CRS84' in crss)
|
||||
self.assertTrue('http://www.opengis.net/def/crs/EPSG/9.6.2/3857' in crss)
|
||||
@ -118,7 +118,7 @@ class QgsServerAPITestBase(QgsServerTestBase):
|
||||
""" QGIS API server tests"""
|
||||
|
||||
# Set to True in child classes to re-generate reference files for this class
|
||||
regeregenerate_api_reference = False
|
||||
regeregenerate_api_reference = True
|
||||
|
||||
def dump(self, response):
|
||||
"""Returns the response body as str"""
|
||||
@ -282,7 +282,7 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/api.openapi3')
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
self.compareApi(request, project, 'test_wfs3_api_project.json')
|
||||
|
||||
def test_wfs3_conformance(self):
|
||||
@ -304,14 +304,14 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
"""Test WFS3 API collections in json format"""
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections.json')
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_project.json')
|
||||
|
||||
def test_wfs3_collections_html(self):
|
||||
"""Test WFS3 API collections in html format"""
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections.html')
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_project.html')
|
||||
|
||||
def test_wfs3_collections_content_type(self):
|
||||
@ -320,7 +320,7 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections')
|
||||
request.setHeader('Accept', 'text/html')
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
response = QgsBufferServerResponse()
|
||||
self.server.handleRequest(request, response, project)
|
||||
self.assertEqual(response.headers()['Content-Type'], 'text/html')
|
||||
@ -328,14 +328,14 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
def test_wfs3_collection_items(self):
|
||||
"""Test WFS3 API items"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_èé.json')
|
||||
|
||||
def test_wfs3_collection_items_crs(self):
|
||||
"""Test WFS3 API items with CRS"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
encoded_crs = parse.quote('http://www.opengis.net/def/crs/EPSG/9.6.2/3857', safe='')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?crs={}'.format(encoded_crs))
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_èé_crs_3857.json')
|
||||
@ -343,7 +343,7 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
def test_invalid_args(self):
|
||||
"""Test wrong args"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1')
|
||||
response = QgsBufferServerResponse()
|
||||
self.server.handleRequest(request, response, project)
|
||||
@ -359,14 +359,14 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
def test_wfs3_collection_items_limit(self):
|
||||
"""Test WFS3 API item limits"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_èé_limit_1.json')
|
||||
|
||||
def test_wfs3_collection_items_limit_offset(self):
|
||||
"""Test WFS3 API offset"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=1')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_èé_limit_1_offset_1.json')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=-1')
|
||||
@ -383,7 +383,7 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
def test_wfs3_collection_items_bbox(self):
|
||||
"""Test WFS3 API bbox"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_èé_bbox.json')
|
||||
|
||||
@ -411,16 +411,23 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
def test_wfs3_field_filters(self):
|
||||
"""Test field filters"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
# Check not published
|
||||
response = QgsBufferServerResponse()
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer3/items?name=two')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer3_name_eq_two.json')
|
||||
self.server.handleRequest(request, response, project)
|
||||
self.assertEqual(response.statusCode(), 404) # Not found
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/layer_with_short_name/items?name=two')
|
||||
self.server.handleRequest(request, response, project)
|
||||
self.assertEqual(response.statusCode(), 200) # Bad request
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_with_short_name_eq_two.json')
|
||||
|
||||
def test_wfs3_field_filters_star(self):
|
||||
"""Test field filters"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer3/items?name=tw*')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer3_name_eq_tw_star.json')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer_with_short_name/items?name=tw*')
|
||||
self.compareApi(request, project, 'test_wfs3_collections_items_testlayer_with_short_name_eq_tw_star.json')
|
||||
|
||||
|
||||
class Handler1(QgsServerOgcApiHandler):
|
||||
@ -552,7 +559,7 @@ class QgsServerOgcAPITest(QgsServerAPITestBase):
|
||||
"""Test OGC API Handler"""
|
||||
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1')
|
||||
response = QgsBufferServerResponse()
|
||||
|
||||
@ -632,7 +639,7 @@ class QgsServerOgcAPITest(QgsServerAPITestBase):
|
||||
"""Test OGC API Handler content types"""
|
||||
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project.qgs')
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/api3/handlerthree?value1=9.5')
|
||||
response = QgsBufferServerResponse()
|
||||
|
||||
|
@ -584,6 +584,200 @@ Content-Type: application/openapi+json;version=3.0
|
||||
"tags": "Capabilities"
|
||||
}
|
||||
},
|
||||
"/wfs3/collections/exclude_attribute/items": {
|
||||
"get": {
|
||||
"description": "Every feature in a dataset belongs to a collection. A dataset may consist of multiple feature collections. A feature collection is often a collection of features of a similar type, based on a common schema. Use content negotiation or specify a file extension to request HTML (.html) or GeoJSON (.json).",
|
||||
"operationId": "getFeatures_testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de",
|
||||
"parameters": [
|
||||
[
|
||||
{
|
||||
"$ref": "#/components/parameters/limit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/offset"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/resultType"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/bbox"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/bbox-crs"
|
||||
}
|
||||
],
|
||||
{
|
||||
"description": "Filter the collection by 'id'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
{
|
||||
"description": "Filter the collection by 'name'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "name",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
{
|
||||
"description": "Filter the collection by 'utf8nameè'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "utf8nameè",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
}
|
||||
],
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/geo+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/featureCollectionGeoJSON"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Metadata about the collection 'A test vector layer' shared by this API."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Retrieve features of 'A test vector layer' feature collection",
|
||||
"tags": "Features"
|
||||
}
|
||||
},
|
||||
"/wfs3/collections/short-name/items": {
|
||||
"get": {
|
||||
"description": "Every feature in a dataset belongs to a collection. A dataset may consist of multiple feature collections. A feature collection is often a collection of features of a similar type, based on a common schema. Use content negotiation or specify a file extension to request HTML (.html) or GeoJSON (.json).",
|
||||
"operationId": "getFeatures_testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774",
|
||||
"parameters": [
|
||||
[
|
||||
{
|
||||
"$ref": "#/components/parameters/limit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/offset"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/resultType"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/bbox"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/parameters/bbox-crs"
|
||||
}
|
||||
],
|
||||
{
|
||||
"description": "Filter the collection by 'id'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
{
|
||||
"description": "Filter the collection by 'name'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "name",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
{
|
||||
"description": "Filter the collection by 'utf8nameè'",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "utf8nameè",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
}
|
||||
],
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/geo+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/featureCollectionGeoJSON"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Metadata about the collection 'A test vector layer' shared by this API."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Retrieve features of 'A test vector layer' feature collection",
|
||||
"tags": "Features"
|
||||
}
|
||||
},
|
||||
"/wfs3/collections/testlayer èé/items": {
|
||||
"get": {
|
||||
"description": "Every feature in a dataset belongs to a collection. A dataset may consist of multiple feature collections. A feature collection is often a collection of features of a similar type, based on a common schema. Use content negotiation or specify a file extension to request HTML (.html) or GeoJSON (.json).",
|
||||
@ -771,6 +965,186 @@ Content-Type: application/openapi+json;version=3.0
|
||||
"tags": "Capabilities"
|
||||
}
|
||||
},
|
||||
"/wfs3collections/exclude_attribute": {
|
||||
"get": {
|
||||
"description": "Metadata about a feature collection.",
|
||||
"operationId": "describeCollection_testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de",
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/collectionInfo"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Metadata about the collection 'A test vector layer' shared by this API."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Describe the 'A test vector layer' feature collection",
|
||||
"tags": "Capabilities"
|
||||
}
|
||||
},
|
||||
"/wfs3collections/exclude_attribute/items/{featureId}": {
|
||||
"get": {
|
||||
"description": "Retrieve a feature; use content negotiation or specify a file extension to request HTML (.html or GeoJSON (.json)",
|
||||
"operationId": "getFeature_testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de",
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/geo+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/featureGeoJSON"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a 'A test vector layer' feature by 'featureId'."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Retrieve a single feature from the 'A test vector layer' feature collection",
|
||||
"tags": "Features"
|
||||
}
|
||||
},
|
||||
"/wfs3collections/short-name": {
|
||||
"get": {
|
||||
"description": "Metadata about a feature collection.",
|
||||
"operationId": "describeCollection_testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774",
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/collectionInfo"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Metadata about the collection 'A test vector layer' shared by this API."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Describe the 'A test vector layer' feature collection",
|
||||
"tags": "Capabilities"
|
||||
}
|
||||
},
|
||||
"/wfs3collections/short-name/items/{featureId}": {
|
||||
"get": {
|
||||
"description": "Retrieve a feature; use content negotiation or specify a file extension to request HTML (.html or GeoJSON (.json)",
|
||||
"operationId": "getFeature_testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774",
|
||||
"responses": [
|
||||
[
|
||||
"200",
|
||||
{
|
||||
"content": {
|
||||
"application/geo+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/featureGeoJSON"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a 'A test vector layer' feature by 'featureId'."
|
||||
}
|
||||
],
|
||||
{
|
||||
"default": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/exception"
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "An error occurred."
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Retrieve a single feature from the 'A test vector layer' feature collection",
|
||||
"tags": "Features"
|
||||
}
|
||||
},
|
||||
"/wfs3collections/testlayer èé": {
|
||||
"get": {
|
||||
"description": "Metadata about a feature collection.",
|
||||
@ -877,5 +1251,5 @@ Content-Type: application/openapi+json;version=3.0
|
||||
"name": "Features"
|
||||
}
|
||||
],
|
||||
"timeStamp": "2019-08-19T14:43:48Z"
|
||||
"timeStamp": "2019-08-27T20:35:54Z"
|
||||
}
|
@ -19,5 +19,5 @@ Content-Type: application/json
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"timeStamp": "2019-07-30T09:17:49Z"
|
||||
"timeStamp": "2019-08-27T20:35:54Z"
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
Content-Type: application/geo+json
|
||||
|
||||
{
|
||||
"features": [
|
||||
{
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
8.203547,
|
||||
44.901436
|
||||
],
|
||||
"type": "Point"
|
||||
},
|
||||
"id": 1,
|
||||
"properties": {
|
||||
"id": 2,
|
||||
"name": "two",
|
||||
"utf8nameè": "two àò"
|
||||
},
|
||||
"type": "Feature"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.geojson?name=tw*",
|
||||
"rel": "self",
|
||||
"title": "Retrieve the features of the collection as GEOJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.html?name=tw*",
|
||||
"rel": "alternate",
|
||||
"title": "Retrieve the features of the collection as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"numberMatched": 1,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
Content-Type: application/geo+json
|
||||
|
||||
{
|
||||
"features": [
|
||||
{
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
8.203547,
|
||||
44.901436
|
||||
],
|
||||
"type": "Point"
|
||||
},
|
||||
"id": 1,
|
||||
"properties": {
|
||||
"id": 2,
|
||||
"name": "two",
|
||||
"utf8nameè": "two àò"
|
||||
},
|
||||
"type": "Feature"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.geojson?name=two",
|
||||
"rel": "self",
|
||||
"title": "Retrieve the features of the collection as GEOJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.html?name=two",
|
||||
"rel": "alternate",
|
||||
"title": "Retrieve the features of the collection as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"numberMatched": 1,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
Content-Type: application/json
|
||||
|
||||
[{"code":"API not found error","description":"Collection with given id (testlayer_with_short_name) was not found or multiple matches were found"}]
|
@ -67,6 +67,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 3,
|
||||
"numberReturned": 3,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -35,6 +35,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 1,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -51,6 +51,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 2,
|
||||
"numberReturned": 2,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -67,6 +67,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 3,
|
||||
"numberReturned": 3,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -42,6 +42,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 3,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -49,6 +49,6 @@ Content-Type: application/geo+json
|
||||
],
|
||||
"numberMatched": 3,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-07-30T09:17:49Z",
|
||||
"timeStamp": "2019-08-27T20:35:54Z",
|
||||
"type": "FeatureCollection"
|
||||
}
|
@ -54,28 +54,13 @@
|
||||
">A test vector layer</a></h3>
|
||||
|
||||
|
||||
<h3><a href="
|
||||
http://server.qgis.org/wfs3/collections/testlayer3.html
|
||||
">testlayer3</a></h3>
|
||||
|
||||
|
||||
<h3><a href="
|
||||
http://server.qgis.org/wfs3/collections/testlayer2.html
|
||||
">testlayer2</a></h3>
|
||||
|
||||
|
||||
<h3><a href="
|
||||
http://server.qgis.org/wfs3/collections/layer_with_short_name.html
|
||||
">A Layer with a short name</a></h3>
|
||||
|
||||
|
||||
<h3><a href="
|
||||
http://server.qgis.org/wfs3/collections/exclude_attribute.html
|
||||
">A test vector layer</a></h3>
|
||||
|
||||
|
||||
<h3><a href="
|
||||
http://server.qgis.org/wfs3/collections/fields_alias.html
|
||||
http://server.qgis.org/wfs3/collections/short-name.html
|
||||
">A test vector layer</a></h3>
|
||||
|
||||
|
||||
|
@ -37,111 +37,6 @@ Content-Type: application/json
|
||||
"name": "testlayer èé",
|
||||
"title": "A test vector layer"
|
||||
},
|
||||
{
|
||||
"crs": [
|
||||
"http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/4326",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/3857"
|
||||
],
|
||||
"description": "",
|
||||
"extent": {
|
||||
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"spatial": [
|
||||
[
|
||||
8.203459307036344,
|
||||
44.90139483904469,
|
||||
8.203546993993488,
|
||||
44.901482526001836
|
||||
]
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.json",
|
||||
"rel": "item",
|
||||
"title": "testlayer3 as GeoJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer3/items.html",
|
||||
"rel": "item",
|
||||
"title": "testlayer3 as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"name": "testlayer3",
|
||||
"title": "testlayer3"
|
||||
},
|
||||
{
|
||||
"crs": [
|
||||
"http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/4326",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/3857"
|
||||
],
|
||||
"description": "",
|
||||
"extent": {
|
||||
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"spatial": [
|
||||
[
|
||||
8.203459307036344,
|
||||
44.90139483904469,
|
||||
8.203546993993488,
|
||||
44.901482526001836
|
||||
]
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer2/items.json",
|
||||
"rel": "item",
|
||||
"title": "testlayer2 as GeoJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/testlayer2/items.html",
|
||||
"rel": "item",
|
||||
"title": "testlayer2 as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"name": "testlayer2",
|
||||
"title": "testlayer2"
|
||||
},
|
||||
{
|
||||
"crs": [
|
||||
"http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/4326",
|
||||
"http://www.opengis.net/def/crs/EPSG/9.6.2/3857"
|
||||
],
|
||||
"description": "A Layer with an abstract",
|
||||
"extent": {
|
||||
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
"spatial": [
|
||||
[
|
||||
8.203459307036344,
|
||||
44.90139483904469,
|
||||
8.203546993993488,
|
||||
44.901482526001836
|
||||
]
|
||||
]
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/layer_with_short_name/items.json",
|
||||
"rel": "item",
|
||||
"title": "A Layer with a short name as GeoJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/layer_with_short_name/items.html",
|
||||
"rel": "item",
|
||||
"title": "A Layer with a short name as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"name": "layer_with_short_name",
|
||||
"title": "A Layer with a short name"
|
||||
},
|
||||
{
|
||||
"crs": [
|
||||
"http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
||||
@ -197,19 +92,19 @@ Content-Type: application/json
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/fields_alias/items.json",
|
||||
"href": "http://server.qgis.org/wfs3/collections/short-name/items.json",
|
||||
"rel": "item",
|
||||
"title": "A test vector layer as GeoJSON",
|
||||
"type": "application/geo+json"
|
||||
},
|
||||
{
|
||||
"href": "http://server.qgis.org/wfs3/collections/fields_alias/items.html",
|
||||
"href": "http://server.qgis.org/wfs3/collections/short-name/items.html",
|
||||
"rel": "item",
|
||||
"title": "A test vector layer as HTML",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"name": "fields_alias",
|
||||
"name": "short-name",
|
||||
"title": "A test vector layer"
|
||||
}
|
||||
],
|
||||
@ -232,5 +127,5 @@ Content-Type: application/json
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"timeStamp": "2019-07-30T09:17:49Z"
|
||||
"timeStamp": "2019-08-27T20:35:54Z"
|
||||
}
|
@ -22,5 +22,5 @@ Content-Type: application/json
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"timeStamp": "2019-07-30T09:17:49Z"
|
||||
"timeStamp": "2019-08-27T20:35:54Z"
|
||||
}
|
@ -33,5 +33,5 @@ Content-Type: application/json
|
||||
"type": "application/openapi+json;version=3.0"
|
||||
}
|
||||
],
|
||||
"timeStamp": "2019-07-30T09:17:49Z"
|
||||
"timeStamp": "2019-08-27T20:35:54Z"
|
||||
}
|
2201
tests/testdata/qgis_server/test_project_api.qgs
vendored
Normal file
2201
tests/testdata/qgis_server/test_project_api.qgs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user