Skip to content

Commit

Permalink
[OAPIF provider] Support extra query parameters (such as api key) (fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault authored and nyalldawson committed Sep 14, 2020
1 parent 9ea7f44 commit 6cdb866
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 9 deletions.
27 changes: 24 additions & 3 deletions src/providers/wfs/qgsoapifprovider.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsoapifapirequest.h"
#include "qgsoapifcollection.h"
#include "qgsoapifitemsrequest.h"
#include "qgswfsconstants.h"
#include "qgswfsutils.h" // for isCompatibleType()

#include <algorithm>
Expand Down Expand Up @@ -71,13 +72,20 @@ bool QgsOapifProvider::init()
const bool synchronous = true;
const bool forceRefresh = false;

const QString url = QgsDataSourceUri( mShared->mURI.uri() ).param( QgsWFSConstants::URI_PARAM_URL );
int pos = url.indexOf( '?' );
if ( pos >= 0 )
{
mShared->mExtraQueryParameters = url.mid( pos + 1 );
}

QgsOapifLandingPageRequest landingPageRequest( mShared->mURI.uri() );
if ( !landingPageRequest.request( synchronous, forceRefresh ) )
return false;
if ( landingPageRequest.errorCode() != QgsBaseNetworkRequest::NoError )
return false;

QgsOapifApiRequest apiRequest( mShared->mURI.uri(), landingPageRequest.apiUrl() );
QgsOapifApiRequest apiRequest( mShared->mURI.uri(), mShared->appendExtraQueryParameters( landingPageRequest.apiUrl() ) );
if ( !apiRequest.request( synchronous, forceRefresh ) )
return false;
if ( apiRequest.errorCode() != QgsBaseNetworkRequest::NoError )
Expand Down Expand Up @@ -127,7 +135,7 @@ bool QgsOapifProvider::init()

mShared->mCollectionUrl =
landingPageRequest.collectionsUrl() + QStringLiteral( "/" ) + mShared->mURI.typeName();
QgsOapifCollectionRequest collectionRequest( mShared->mURI.uri(), mShared->mCollectionUrl );
QgsOapifCollectionRequest collectionRequest( mShared->mURI.uri(), mShared->appendExtraQueryParameters( mShared->mCollectionUrl ) );
if ( !collectionRequest.request( synchronous, forceRefresh ) )
return false;
if ( collectionRequest.errorCode() != QgsBaseNetworkRequest::NoError )
Expand All @@ -141,7 +149,7 @@ bool QgsOapifProvider::init()

mShared->mItemsUrl = mShared->mCollectionUrl + QStringLiteral( "/items" );

QgsOapifItemsRequest itemsRequest( mShared->mURI.uri(), mShared->mItemsUrl + QStringLiteral( "?limit=10" ) );
QgsOapifItemsRequest itemsRequest( mShared->mURI.uri(), mShared->appendExtraQueryParameters( mShared->mItemsUrl + QStringLiteral( "?limit=10" ) ) );
if ( mShared->mCapabilityExtent.isNull() )
{
itemsRequest.setComputeBbox();
Expand Down Expand Up @@ -353,6 +361,16 @@ QgsOapifSharedData::~QgsOapifSharedData()
cleanup();
}

QString QgsOapifSharedData::appendExtraQueryParameters( const QString &url ) const
{
if ( mExtraQueryParameters.isEmpty() || url.indexOf( mExtraQueryParameters ) > 0 )
return url;
int nPos = url.indexOf( '?' );
if ( nPos < 0 )
return url + '?' + mExtraQueryParameters;
return url + '&' + mExtraQueryParameters;
}

bool QgsOapifSharedData::isRestrictedToRequestBBOX() const
{
return mURI.isRestrictedToRequestBBOX();
Expand Down Expand Up @@ -671,6 +689,8 @@ void QgsOapifFeatureDownloaderImpl::run( bool serializeFeatures, int maxFeatures
}
}

url = mShared->appendExtraQueryParameters( url );

while ( !url.isEmpty() )
{

Expand Down Expand Up @@ -700,6 +720,7 @@ void QgsOapifFeatureDownloaderImpl::run( bool serializeFeatures, int maxFeatures
break;
}
url = itemsRequest.nextUrl();
url = mShared->appendExtraQueryParameters( url );

// Consider if we should display a progress dialog
// We can only do that if we know how many features will be downloaded
Expand Down
6 changes: 6 additions & 0 deletions src/providers/wfs/qgsoapifprovider.h
Expand Up @@ -160,6 +160,9 @@ class QgsOapifSharedData final: public QObject, public QgsBackgroundCachedShared
//! Page size. 0 = disabled
int mPageSize = 0;

//! Extra query parameters from the URI, to append to other requests
QString mExtraQueryParameters;

//! Url to /collections/{collectionId}
QString mCollectionUrl;

Expand All @@ -172,6 +175,9 @@ class QgsOapifSharedData final: public QObject, public QgsBackgroundCachedShared
//! Translation state of filter to server-side filter.
QgsOapifProvider::FilterTranslationState mFilterTranslationState = QgsOapifProvider::FilterTranslationState::FULLY_CLIENT;

//! Append extra query parameters if needed
QString appendExtraQueryParameters( const QString &url ) const;

private:

// Translate part of an expression to a server-side filter
Expand Down
45 changes: 39 additions & 6 deletions tests/src/python/test_provider_oapif.py
Expand Up @@ -67,17 +67,25 @@ def GDAL_COMPUTE_VERSION(maj, min, rev):
ACCEPT_ITEMS = 'Accept=application/geo+json, application/json'


def create_landing_page_api_collection(endpoint):
def create_landing_page_api_collection(endpoint, extraparam=''):

questionmark_extraparam = '?' + extraparam if extraparam else ''

def add_params(x, y):
if x:
return x + '&' + y
return y

# Landing page
with open(sanitize(endpoint, '?' + ACCEPT_LANDING), 'wb') as f:
with open(sanitize(endpoint, '?' + add_params(extraparam, ACCEPT_LANDING)), 'wb') as f:
f.write(json.dumps({
"links": [
{"href": "http://" + endpoint + "/api", "rel": "service-desc"},
{"href": "http://" + endpoint + "/collections", "rel": "data"}
{"href": "http://" + endpoint + "/api" + questionmark_extraparam, "rel": "service-desc"},
{"href": "http://" + endpoint + "/collections" + questionmark_extraparam, "rel": "data"}
]}).encode('UTF-8'))

# API
with open(sanitize(endpoint, '/api?' + ACCEPT_API), 'wb') as f:
with open(sanitize(endpoint, '/api?' + add_params(extraparam, ACCEPT_API)), 'wb') as f:
f.write(json.dumps({
"components": {
"parameters": {
Expand All @@ -92,7 +100,7 @@ def create_landing_page_api_collection(endpoint):
}).encode('UTF-8'))

# collection
with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
with open(sanitize(endpoint, '/collections/mycollection?' + add_params(extraparam, ACCEPT_COLLECTION)), 'wb') as f:
f.write(json.dumps({
"id": "mycollection",
"title": "my title",
Expand Down Expand Up @@ -677,6 +685,31 @@ def testStringList(self):
else:
self.assertEqual(features[0]['my_stringlist_field'], ["a", "b"])

def testApikey(self):

endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_apikey'
create_landing_page_api_collection(endpoint, extraparam='apikey=mykey')

# first items
first_items = {
"type": "FeatureCollection",
"features": [
{"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
"geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
]
}

with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(first_items).encode('UTF-8'))

with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f:
f.write(json.dumps(first_items).encode('UTF-8'))

vl = QgsVectorLayer("url='http://" + endpoint + "?apikey=mykey' typename='mycollection'", 'test', 'OAPIF')
self.assertTrue(vl.isValid())
values = [f['id'] for f in vl.getFeatures()]
self.assertEqual(values, ['feat.1'])


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

0 comments on commit 6cdb866

Please sign in to comment.