[afs][needs-docs] Allow users to set a specific referer for AFS connections, for

use with ArcGIS feature server requests

Some servers are locked down to only allow requests with a specific
referer URL - this allows us to open them in QGIS (but it requires
users to manually determine the correct referer string and populate
this setting for the connection -- we cannot do this for them!)
This commit is contained in:
Nyall Dawson 2019-01-24 10:07:37 +10:00
parent b0b196a97c
commit 996f48670d
14 changed files with 287 additions and 211 deletions

View File

@ -36,6 +36,7 @@ information for an HTTP Server for WMS, etc.
{
FlagShowTestConnection,
FlagHideAuthenticationGroup,
FlagShowHttpSettings,
};
typedef QFlags<QgsNewHttpConnection::Flag> Flags;

View File

@ -65,6 +65,13 @@ QgsOwsConnection::QgsOwsConnection( const QString &service, const QString &connN
}
mConnectionInfo.append( ",authcfg=" + authcfg );
const QString referer = settings.value( key + "/referer" ).toString();
if ( !referer.isEmpty() )
{
mUri.setParam( QStringLiteral( "referer" ), referer );
mConnectionInfo.append( ",referer=" + referer );
}
if ( mService.compare( QLatin1String( "WMS" ), Qt::CaseInsensitive ) == 0
|| mService.compare( QLatin1String( "WCS" ), Qt::CaseInsensitive ) == 0 )
{

View File

@ -34,6 +34,9 @@ QgsNewHttpConnection::QgsNewHttpConnection( QWidget *parent, ConnectionTypes typ
{
setupUi( this );
if ( !( flags & FlagShowHttpSettings ) )
mHttpGroupBox->hide();
QgsGui::enableAutoGeometryRestore( this );
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsNewHttpConnection::showHelp );
@ -88,6 +91,7 @@ QgsNewHttpConnection::QgsNewHttpConnection( QWidget *parent, ConnectionTypes typ
QString credentialsKey = "qgis/" + mCredentialsBaseKey + '/' + connectionName;
txtName->setText( connectionName );
txtUrl->setText( settings.value( key + "/url" ).toString() );
mRefererLineEdit->setText( settings.value( key + "/referer" ).toString() );
updateServiceSpecificSettings();
@ -444,6 +448,9 @@ void QgsNewHttpConnection::accept()
settings.setValue( credentialsKey + "/authcfg", mAuthSettings->configId() );
if ( mHttpGroupBox->isVisible() )
settings.setValue( key + "/referer", mRefererLineEdit->text() );
settings.setValue( mBaseKey + "/selected", txtName->text() );
QDialog::accept();

View File

@ -57,6 +57,7 @@ class GUI_EXPORT QgsNewHttpConnection : public QDialog, private Ui::QgsNewHttpCo
{
FlagShowTestConnection = 1 << 1, //!< Display the 'test connection' button
FlagHideAuthenticationGroup = 1 << 2, //!< Hide the Authentication group
FlagShowHttpSettings = 1 << 3, //!< Display the 'http' group
};
Q_DECLARE_FLAGS( Flags, Flag )

View File

@ -75,7 +75,7 @@ void QgsAfsRootItem::onConnectionsChanged()
void QgsAfsRootItem::newConnection()
{
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-arcgisfeatureserver/" ) );
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-arcgisfeatureserver/" ), QString(), QgsNewHttpConnection::FlagShowHttpSettings );
nc.setWindowTitle( tr( "Create a New ArcGIS Feature Server Connection" ) );
if ( nc.exec() )
@ -87,31 +87,31 @@ void QgsAfsRootItem::newConnection()
///////////////////////////////////////////////////////////////////////////////
void addFolderItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, QgsDataItem *parent )
void addFolderItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
{
QgsArcGisRestUtils::visitFolderItems( [parent, &baseUrl, &items, authcfg]( const QString & name, const QString & url )
QgsArcGisRestUtils::visitFolderItems( [parent, &baseUrl, &items, headers, authcfg]( const QString & name, const QString & url )
{
std::unique_ptr< QgsAfsFolderItem > folderItem = qgis::make_unique< QgsAfsFolderItem >( parent, name, url, baseUrl, authcfg );
std::unique_ptr< QgsAfsFolderItem > folderItem = qgis::make_unique< QgsAfsFolderItem >( parent, name, url, baseUrl, authcfg, headers );
items.append( folderItem.release() );
}, serviceData, baseUrl );
}
void addServiceItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, QgsDataItem *parent )
void addServiceItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
{
QgsArcGisRestUtils::visitServiceItems(
[&items, parent, authcfg]( const QString & name, const QString & url )
[&items, parent, authcfg, headers]( const QString & name, const QString & url )
{
std::unique_ptr< QgsAfsServiceItem > serviceItem = qgis::make_unique< QgsAfsServiceItem >( parent, name, url, url, authcfg );
std::unique_ptr< QgsAfsServiceItem > serviceItem = qgis::make_unique< QgsAfsServiceItem >( parent, name, url, url, authcfg, headers );
items.append( serviceItem.release() );
}, serviceData, baseUrl );
}
void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &parentUrl, const QString &authcfg, QgsDataItem *parent )
void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &parentUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
{
QMap< QString, QgsDataItem * > layerItems;
QMap< QString, QString > parents;
QgsArcGisRestUtils::addLayerItems( [parent, &layerItems, &parents, authcfg]( const QString & parentLayerId, const QString & id, const QString & name, const QString & description, const QString & url, bool isParent, const QString & authid )
QgsArcGisRestUtils::addLayerItems( [parent, &layerItems, &parents, authcfg, headers]( const QString & parentLayerId, const QString & id, const QString & name, const QString & description, const QString & url, bool isParent, const QString & authid )
{
Q_UNUSED( description );
@ -120,12 +120,12 @@ void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceD
if ( isParent )
{
std::unique_ptr< QgsAfsParentLayerItem > layerItem = qgis::make_unique< QgsAfsParentLayerItem >( parent, name, url, authcfg );
std::unique_ptr< QgsAfsParentLayerItem > layerItem = qgis::make_unique< QgsAfsParentLayerItem >( parent, name, url, authcfg, headers );
layerItems.insert( id, layerItem.release() );
}
else
{
std::unique_ptr< QgsAfsLayerItem > layerItem = qgis::make_unique< QgsAfsLayerItem >( parent, name, url, name, authid, authcfg );
std::unique_ptr< QgsAfsLayerItem > layerItem = qgis::make_unique< QgsAfsLayerItem >( parent, name, url, name, authid, authcfg, headers );
layerItems.insert( id, layerItem.release() );
}
@ -158,10 +158,14 @@ QVector<QgsDataItem *> QgsAfsConnectionItem::createChildren()
const QgsOwsConnection connection( QStringLiteral( "ARCGISFEATURESERVER" ), mConnName );
const QString url = connection.uri().param( QStringLiteral( "url" ) );
const QString authcfg = connection.uri().param( QStringLiteral( "authcfg" ) );
const QString referer = connection.uri().param( QStringLiteral( "referer" ) );
QgsStringMap headers;
if ( ! referer.isEmpty() )
headers[ QStringLiteral( "Referer" )] = referer;
QVector<QgsDataItem *> items;
QString errorTitle, errorMessage;
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, authcfg, errorTitle, errorMessage );
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, authcfg, errorTitle, errorMessage, headers );
if ( serviceData.isEmpty() )
{
if ( !errorMessage.isEmpty() )
@ -174,9 +178,9 @@ QVector<QgsDataItem *> QgsAfsConnectionItem::createChildren()
return items;
}
addFolderItems( items, serviceData, url, authcfg, this );
addServiceItems( items, serviceData, url, authcfg, this );
addLayerItems( items, serviceData, url, authcfg, this );
addFolderItems( items, serviceData, url, authcfg, headers, this );
addServiceItems( items, serviceData, url, authcfg, headers, this );
addLayerItems( items, serviceData, url, authcfg, headers, this );
return items;
}
@ -219,7 +223,7 @@ QList<QAction *> QgsAfsConnectionItem::actions( QWidget *parent )
void QgsAfsConnectionItem::editConnection()
{
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-arcgisfeatureserver/" ), mName );
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-arcgisfeatureserver/" ), mName, QgsNewHttpConnection::FlagShowHttpSettings );
nc.setWindowTitle( tr( "Modify ArcGIS Feature Server Connection" ) );
if ( nc.exec() )
@ -255,10 +259,11 @@ void QgsAfsConnectionItem::refreshConnection()
#endif
QgsAfsFolderItem::QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg )
QgsAfsFolderItem::QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers )
: QgsDataCollectionItem( parent, name, path )
, mBaseUrl( baseUrl )
, mAuthCfg( authcfg )
, mHeaders( headers )
{
mIconName = QStringLiteral( "mIconDbSchema.svg" );
mCapabilities |= Collapse;
@ -272,7 +277,7 @@ QVector<QgsDataItem *> QgsAfsFolderItem::createChildren()
QVector<QgsDataItem *> items;
QString errorTitle, errorMessage;
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage );
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage, mHeaders );
if ( serviceData.isEmpty() )
{
if ( !errorMessage.isEmpty() )
@ -285,9 +290,9 @@ QVector<QgsDataItem *> QgsAfsFolderItem::createChildren()
return items;
}
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, this );
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, this );
addLayerItems( items, serviceData, mPath, mAuthCfg, this );
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
addLayerItems( items, serviceData, mPath, mAuthCfg, mHeaders, this );
return items;
}
@ -297,10 +302,11 @@ bool QgsAfsFolderItem::equal( const QgsDataItem *other )
return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
}
QgsAfsServiceItem::QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg )
QgsAfsServiceItem::QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers )
: QgsDataCollectionItem( parent, name, path )
, mBaseUrl( baseUrl )
, mAuthCfg( authcfg )
, mHeaders( headers )
{
mIconName = QStringLiteral( "mIconDbSchema.svg" );
mCapabilities |= Collapse;
@ -313,7 +319,7 @@ QVector<QgsDataItem *> QgsAfsServiceItem::createChildren()
QVector<QgsDataItem *> items;
QString errorTitle, errorMessage;
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage );
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage, mHeaders );
if ( serviceData.isEmpty() )
{
if ( !errorMessage.isEmpty() )
@ -326,9 +332,9 @@ QVector<QgsDataItem *> QgsAfsServiceItem::createChildren()
return items;
}
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, this );
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, this );
addLayerItems( items, serviceData, mPath, mAuthCfg, this );
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
addLayerItems( items, serviceData, mPath, mAuthCfg, mHeaders, this );
return items;
}
@ -338,20 +344,23 @@ bool QgsAfsServiceItem::equal( const QgsDataItem *other )
return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
}
QgsAfsLayerItem::QgsAfsLayerItem( QgsDataItem *parent, const QString &, const QString &url, const QString &title, const QString &authid, const QString &authcfg )
QgsAfsLayerItem::QgsAfsLayerItem( QgsDataItem *parent, const QString &, const QString &url, const QString &title, const QString &authid, const QString &authcfg, const QgsStringMap &headers )
: QgsLayerItem( parent, title, url, QString(), QgsLayerItem::Vector, QStringLiteral( "arcgisfeatureserver" ) )
{
mUri = QStringLiteral( "crs='%1' url='%2'" ).arg( authid, url );
if ( !authcfg.isEmpty() )
mUri += QStringLiteral( " authcfg='%1'" ).arg( authcfg );
if ( !headers.value( QStringLiteral( "Referer" ) ).isEmpty() )
mUri += QStringLiteral( " referer='%1'" ).arg( headers.value( QStringLiteral( "Referer" ) ) );
setState( Populated );
mIconName = QStringLiteral( "mIconAfs.svg" );
setToolTip( url );
}
QgsAfsParentLayerItem::QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg )
QgsAfsParentLayerItem::QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg, const QgsStringMap &headers )
: QgsDataItem( QgsDataItem::Collection, parent, name, path )
, mAuthCfg( authcfg )
, mHeaders( headers )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mIconDbSchema.svg" );

View File

@ -73,7 +73,7 @@ class QgsAfsFolderItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg );
QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers );
QVector<QgsDataItem *> createChildren() override;
bool equal( const QgsDataItem *other ) override;
@ -81,13 +81,14 @@ class QgsAfsFolderItem : public QgsDataCollectionItem
QString mFolder;
QString mBaseUrl;
QString mAuthCfg;
QgsStringMap mHeaders;
};
class QgsAfsServiceItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg );
QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers );
QVector<QgsDataItem *> createChildren() override;
bool equal( const QgsDataItem *other ) override;
@ -95,6 +96,7 @@ class QgsAfsServiceItem : public QgsDataCollectionItem
QString mFolder;
QString mBaseUrl;
QString mAuthCfg;
QgsStringMap mHeaders;
};
class QgsAfsParentLayerItem : public QgsDataItem
@ -102,12 +104,13 @@ class QgsAfsParentLayerItem : public QgsDataItem
Q_OBJECT
public:
QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg );
QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg, const QgsStringMap &headers );
bool equal( const QgsDataItem *other ) override;
private:
QString mAuthCfg;
QgsStringMap mHeaders;
};
@ -117,7 +120,7 @@ class QgsAfsLayerItem : public QgsLayerItem
public:
QgsAfsLayerItem( QgsDataItem *parent, const QString &name, const QString &url, const QString &title, const QString &authid, const QString &authcfg );
QgsAfsLayerItem( QgsDataItem *parent, const QString &name, const QString &url, const QString &title, const QString &authid, const QString &authcfg, const QgsStringMap &headers );
};

View File

@ -54,8 +54,13 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
// Get layer info
QString errorTitle, errorMessage;
const QString referer = mSharedData->mDataSource.param( QStringLiteral( "referer" ) );
if ( !referer.isEmpty() )
mRequestHeaders[ QStringLiteral( "Referer" )] = referer;
const QVariantMap layerData = QgsArcGisRestUtils::getLayerInfo( mSharedData->mDataSource.param( QStringLiteral( "url" ) ),
authcfg, errorTitle, errorMessage );
authcfg, errorTitle, errorMessage, mRequestHeaders );
if ( layerData.isEmpty() )
{
pushError( errorTitle + ": " + errorMessage );
@ -170,7 +175,7 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
// and we need to store these to iterate through the features. This query
// also returns the name of the ObjectID field.
QVariantMap objectIdData = QgsArcGisRestUtils::getObjectIds( mSharedData->mDataSource.param( QStringLiteral( "url" ) ), authcfg,
objectIdFieldName, errorTitle, errorMessage, limitBbox ? mSharedData->mExtent : QgsRectangle() );
objectIdFieldName, errorTitle, errorMessage, mRequestHeaders, limitBbox ? mSharedData->mExtent : QgsRectangle() );
if ( objectIdData.isEmpty() )
{
appendError( QgsErrorMessage( tr( "getObjectIds failed: %1 - %2" ).arg( errorTitle, errorMessage ), QStringLiteral( "AFSProvider" ) ) );

View File

@ -82,6 +82,7 @@ class QgsAfsProvider : public QgsVectorDataProvider
QgsLayerMetadata mLayerMetadata;
QVariantMap mRendererDataMap;
QVariantList mLabelingDataList;
QgsStringMap mRequestHeaders;
};
#endif // QGSAFSPROVIDER_H

View File

@ -70,10 +70,15 @@ bool QgsAfsSharedData::getFeature( QgsFeatureId id, QgsFeature &f, const QgsRect
QString errorTitle, errorMessage;
const QString authcfg = mDataSource.authConfigId();
QgsStringMap headers;
const QString referer = mDataSource.param( QStringLiteral( "referer" ) );
if ( !referer.isEmpty() )
headers[ QStringLiteral( "Referer" )] = referer;
const QVariantMap queryData = QgsArcGisRestUtils::getObjects(
mDataSource.param( QStringLiteral( "url" ) ), authcfg, objectIds, mDataSource.param( QStringLiteral( "crs" ) ), true,
fetchAttribNames, QgsWkbTypes::hasM( mGeometryType ), QgsWkbTypes::hasZ( mGeometryType ),
filterRect, errorTitle, errorMessage, feedback );
filterRect, errorTitle, errorMessage, headers, feedback );
if ( queryData.isEmpty() )
{
@ -159,9 +164,13 @@ QgsFeatureIds QgsAfsSharedData::getFeatureIdsInExtent( const QgsRectangle &exten
QString errorText;
const QString authcfg = mDataSource.authConfigId();
QgsStringMap headers;
const QString referer = mDataSource.param( QStringLiteral( "referer" ) );
if ( !referer.isEmpty() )
headers[ QStringLiteral( "Referer" )] = referer;
const QList<quint32> featuresInRect = QgsArcGisRestUtils::getObjectIdsByExtent( mDataSource.param( QStringLiteral( "url" ) ),
mObjectIdFieldName,
extent, errorTitle, errorText, authcfg, feedback );
extent, errorTitle, errorText, authcfg, headers, feedback );
QgsFeatureIds ids;
for ( quint32 id : featuresInRect )

View File

@ -40,11 +40,15 @@ bool QgsAfsSourceSelect::connectToService( const QgsOwsConnection &connection )
const QString authcfg = connection.uri().param( QStringLiteral( "authcfg" ) );
const QString baseUrl = connection.uri().param( QStringLiteral( "url" ) );
const QString referer = connection.uri().param( QStringLiteral( "referer" ) );
QgsStringMap headers;
if ( ! referer.isEmpty() )
headers[ QStringLiteral( "Referer" )] = referer;
std::function< bool( const QString &, QStandardItem * )> visitItemsRecursive;
visitItemsRecursive = [this, &visitItemsRecursive, baseUrl, authcfg, &errorTitle, &errorMessage]( const QString & baseItemUrl, QStandardItem * parentItem ) -> bool
visitItemsRecursive = [this, &visitItemsRecursive, baseUrl, authcfg, headers, &errorTitle, &errorMessage]( const QString & baseItemUrl, QStandardItem * parentItem ) -> bool
{
const QVariantMap serviceInfoMap = QgsArcGisRestUtils::getServiceInfo( baseItemUrl, authcfg, errorTitle, errorMessage );
const QVariantMap serviceInfoMap = QgsArcGisRestUtils::getServiceInfo( baseItemUrl, authcfg, errorTitle, errorMessage, headers );
if ( serviceInfoMap.isEmpty() )
{

View File

@ -367,23 +367,23 @@ QgsCoordinateReferenceSystem QgsArcGisRestUtils::parseSpatialReference( const QV
}
QVariantMap QgsArcGisRestUtils::getServiceInfo( const QString &baseurl, const QString &authcfg, QString &errorTitle, QString &errorText )
QVariantMap QgsArcGisRestUtils::getServiceInfo( const QString &baseurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders )
{
// http://sampleserver5.arcgisonline.com/arcgis/rest/services/Energy/Geology/FeatureServer?f=json
QUrl queryUrl( baseurl );
queryUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "json" ) );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders );
}
QVariantMap QgsArcGisRestUtils::getLayerInfo( const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText )
QVariantMap QgsArcGisRestUtils::getLayerInfo( const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders )
{
// http://sampleserver5.arcgisonline.com/arcgis/rest/services/Energy/Geology/FeatureServer/1?f=json
QUrl queryUrl( layerurl );
queryUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "json" ) );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders );
}
QVariantMap QgsArcGisRestUtils::getObjectIds( const QString &layerurl, const QString &authcfg, const QString &objectIdFieldName, QString &errorTitle, QString &errorText, const QgsRectangle &bbox )
QVariantMap QgsArcGisRestUtils::getObjectIds( const QString &layerurl, const QString &authcfg, const QString &objectIdFieldName, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, const QgsRectangle &bbox )
{
// http://sampleserver5.arcgisonline.com/arcgis/rest/services/Energy/Geology/FeatureServer/1/query?where=objectid%3Dobjectid&returnIdsOnly=true&f=json
QUrl queryUrl( layerurl + "/query" );
@ -398,14 +398,14 @@ QVariantMap QgsArcGisRestUtils::getObjectIds( const QString &layerurl, const QSt
queryUrl.addQueryItem( QStringLiteral( "geometryType" ), QStringLiteral( "esriGeometryEnvelope" ) );
queryUrl.addQueryItem( QStringLiteral( "spatialRel" ), QStringLiteral( "esriSpatialRelEnvelopeIntersects" ) );
}
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders );
}
QVariantMap QgsArcGisRestUtils::getObjects( const QString &layerurl, const QString &authcfg, const QList<quint32> &objectIds, const QString &crs,
bool fetchGeometry, const QStringList &fetchAttributes,
bool fetchM, bool fetchZ,
const QgsRectangle &filterRect,
QString &errorTitle, QString &errorText, QgsFeedback *feedback )
QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, QgsFeedback *feedback )
{
QStringList ids;
for ( int id : objectIds )
@ -439,10 +439,10 @@ QVariantMap QgsArcGisRestUtils::getObjects( const QString &layerurl, const QStri
queryUrl.addQueryItem( QStringLiteral( "geometryType" ), QStringLiteral( "esriGeometryEnvelope" ) );
queryUrl.addQueryItem( QStringLiteral( "spatialRel" ), QStringLiteral( "esriSpatialRelEnvelopeIntersects" ) );
}
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, feedback );
return queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders, feedback );
}
QList<quint32> QgsArcGisRestUtils::getObjectIdsByExtent( const QString &layerurl, const QString &objectIdField, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, QgsFeedback *feedback )
QList<quint32> QgsArcGisRestUtils::getObjectIdsByExtent( const QString &layerurl, const QString &objectIdField, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, const QgsStringMap &requestHeaders, QgsFeedback *feedback )
{
QUrl queryUrl( layerurl + "/query" );
queryUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "json" ) );
@ -453,7 +453,7 @@ QList<quint32> QgsArcGisRestUtils::getObjectIdsByExtent( const QString &layerurl
.arg( filterRect.xMaximum(), 0, 'f', -1 ).arg( filterRect.yMaximum(), 0, 'f', -1 ) );
queryUrl.addQueryItem( QStringLiteral( "geometryType" ), QStringLiteral( "esriGeometryEnvelope" ) );
queryUrl.addQueryItem( QStringLiteral( "spatialRel" ), QStringLiteral( "esriSpatialRelEnvelopeIntersects" ) );
const QVariantMap objectIdData = queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, feedback );
const QVariantMap objectIdData = queryServiceJSON( queryUrl, authcfg, errorTitle, errorText, requestHeaders, feedback );
if ( objectIdData.isEmpty() )
{
@ -470,12 +470,16 @@ QList<quint32> QgsArcGisRestUtils::getObjectIdsByExtent( const QString &layerurl
return ids;
}
QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback )
QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, QgsFeedback *feedback )
{
QEventLoop loop;
QUrl url = parseUrl( u );
QNetworkRequest request( url );
for ( auto it = requestHeaders.constBegin(); it != requestHeaders.constEnd(); ++it )
{
request.setRawHeader( it.key().toUtf8(), it.value().toUtf8() );
}
if ( !authcfg.isEmpty() )
{
@ -525,9 +529,9 @@ QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authc
return result;
}
QVariantMap QgsArcGisRestUtils::queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback )
QVariantMap QgsArcGisRestUtils::queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, QgsFeedback *feedback )
{
QByteArray reply = queryService( url, authcfg, errorTitle, errorText, feedback );
QByteArray reply = queryService( url, authcfg, errorTitle, errorText, requestHeaders, feedback );
if ( !errorTitle.isEmpty() )
{
return QVariantMap();

View File

@ -41,16 +41,16 @@ class QgsArcGisRestUtils
static std::unique_ptr< QgsAbstractGeometry > parseEsriGeoJSON( const QVariantMap &geometryData, const QString &esriGeometryType, bool readM, bool readZ, QgsCoordinateReferenceSystem *crs = nullptr );
static QgsCoordinateReferenceSystem parseSpatialReference( const QVariantMap &spatialReferenceMap );
static QVariantMap getServiceInfo( const QString &baseurl, const QString &authcfg, QString &errorTitle, QString &errorText );
static QVariantMap getLayerInfo( const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText );
static QVariantMap getObjectIds( const QString &layerurl, const QString &authcfg, const QString &objectIdFieldName, QString &errorTitle, QString &errorText,
static QVariantMap getServiceInfo( const QString &baseurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap() );
static QVariantMap getLayerInfo( const QString &layerurl, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap() );
static QVariantMap getObjectIds( const QString &layerurl, const QString &authcfg, const QString &objectIdFieldName, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(),
const QgsRectangle &bbox = QgsRectangle() );
static QVariantMap getObjects( const QString &layerurl, const QString &authcfg, const QList<quint32> &objectIds, const QString &crs,
bool fetchGeometry, const QStringList &fetchAttributes, bool fetchM, bool fetchZ,
const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
static QList<quint32> getObjectIdsByExtent( const QString &layerurl, const QString &objectIdField, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, QgsFeedback *feedback = nullptr );
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
static QVariantMap queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, QgsFeedback *feedback = nullptr );
const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QList<quint32> getObjectIdsByExtent( const QString &layerurl, const QString &objectIdField, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QVariantMap queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static std::unique_ptr< QgsSymbol > parseEsriSymbolJson( const QVariantMap &symbolData );
static std::unique_ptr< QgsLineSymbol > parseEsriLineSymbolJson( const QVariantMap &symbolData );

View File

@ -208,7 +208,7 @@ void QgsArcGisServiceSourceSelect::refresh()
void QgsArcGisServiceSourceSelect::addEntryToServerList()
{
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-%1/" ).arg( mServiceName.toLower() ) );
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-%1/" ).arg( mServiceName.toLower() ), QString(), QgsNewHttpConnection::FlagShowHttpSettings );
nc.setWindowTitle( tr( "Create a New %1 Connection" ).arg( mServiceName ) );
if ( nc.exec() )
@ -220,7 +220,7 @@ void QgsArcGisServiceSourceSelect::addEntryToServerList()
void QgsArcGisServiceSourceSelect::modifyEntryOfServerList()
{
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-%1/" ).arg( mServiceName.toLower() ), cmbConnections->currentText() );
QgsNewHttpConnection nc( nullptr, QgsNewHttpConnection::ConnectionOther, QStringLiteral( "qgis/connections-%1/" ).arg( mServiceName.toLower() ), cmbConnections->currentText(), QgsNewHttpConnection::FlagShowHttpSettings );
nc.setWindowTitle( tr( "Modify %1 Connection" ).arg( mServiceName ) );
if ( nc.exec() )

View File

@ -26,7 +26,160 @@
<string>Connection Details</string>
</property>
<layout class="QGridLayout">
<item row="2" column="0" colspan="2">
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="TextLabel1_2">
<property name="text">
<string>Name</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtName">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Name of the new connection</string>
</property>
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="TextLabel1">
<property name="text">
<string>URL</string>
</property>
<property name="margin">
<number>5</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtUrl">
<property name="toolTip">
<string>HTTP address of the Web Map Server</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="mWmsOptionsGroupBox">
<property name="title">
<string>WMS/WMTS Options</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="cbxWmsInvertAxisOrientation">
<property name="text">
<string>Invert axis orientation</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="cbxIgnoreGetFeatureInfoURI">
<property name="text">
<string>Ignore GetFeatureInfo URI reported in capabilities</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cbxIgnoreGetMapURI">
<property name="text">
<string>Ignore GetMap/GetTile URI reported in capabilities</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QCheckBox" name="cbxSmoothPixmapTransform">
<property name="text">
<string>Smooth pixmap transform</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtReferer"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmbDpiMode"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDpiMode">
<property name="text">
<string>DPI-&amp;Mode</string>
</property>
<property name="buddy">
<cstring>cmbDpiMode</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblReferer">
<property name="text">
<string>&amp;Referer</string>
</property>
<property name="buddy">
<cstring>txtReferer</cstring>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="cbxWmsIgnoreAxisOrientation">
<property name="text">
<string>Ignore axis orientation (WMS 1.3/WMTS)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="mWfsOptionsGroupBox">
<property name="title">
<string>WFS Options</string>
@ -108,13 +261,6 @@
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QPushButton" name="mTestConnectionButton">
<property name="text">
<string>&amp;Test Connection</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="mAuthGroupBox">
<property name="title">
@ -146,159 +292,32 @@
</layout>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="mWmsOptionsGroupBox">
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="mTestConnectionButton">
<property name="text">
<string>&amp;Test Connection</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="mHttpGroupBox">
<property name="title">
<string>WMS/WMTS Options</string>
<string>HTTP</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="cbxWmsInvertAxisOrientation">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Invert axis orientation</string>
<string>Referer</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="cbxIgnoreGetFeatureInfoURI">
<property name="text">
<string>Ignore GetFeatureInfo URI reported in capabilities</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cbxIgnoreGetMapURI">
<property name="text">
<string>Ignore GetMap/GetTile URI reported in capabilities</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QCheckBox" name="cbxSmoothPixmapTransform">
<property name="text">
<string>Smooth pixmap transform</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtReferer"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmbDpiMode"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDpiMode">
<property name="text">
<string>DPI-&amp;Mode</string>
</property>
<property name="buddy">
<cstring>cmbDpiMode</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblReferer">
<property name="text">
<string>&amp;Referer</string>
</property>
<property name="buddy">
<cstring>txtReferer</cstring>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="cbxWmsIgnoreAxisOrientation">
<property name="text">
<string>Ignore axis orientation (WMS 1.3/WMTS)</string>
</property>
</widget>
<item>
<widget class="QgsFilterLineEdit" name="mRefererLineEdit"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="TextLabel1_2">
<property name="text">
<string>Name</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtName">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Name of the new connection</string>
</property>
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="TextLabel1">
<property name="text">
<string>URL</string>
</property>
<property name="margin">
<number>5</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtUrl">
<property name="toolTip">
<string>HTTP address of the Web Map Server</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -313,6 +332,11 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsFilterLineEdit</class>
<extends>QLineEdit</extends>
<header>qgsfilterlineedit.h</header>
</customwidget>
<customwidget>
<class>QgsAuthSettingsWidget</class>
<extends>QWidget</extends>
@ -323,6 +347,7 @@
<tabstops>
<tabstop>txtName</tabstop>
<tabstop>txtUrl</tabstop>
<tabstop>mRefererLineEdit</tabstop>
<tabstop>cmbVersion</tabstop>
<tabstop>mWfsVersionDetectButton</tabstop>
<tabstop>txtMaxNumFeatures</tabstop>