23 #include <QNetworkCacheMetaData> 25 #include <QJsonDocument> 26 #include <QJsonObject> 28 #include <QDomDocument> 33 , mForceRefresh( forceRefresh )
48 mGeoNodeReply->deleteLater();
49 mGeoNodeReply =
nullptr;
55 request( QStringLiteral(
"/api/layers/" ) );
56 QObject *obj =
new QObject(
this );
60 QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
61 if ( mError.isEmpty() )
73 QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
77 QObject *obj =
new QObject(
this );
83 loop.exec( QEventLoop::ExcludeUserInputEvents );
91 bool success =
requestBlocking( QStringLiteral(
"/api/layers?name=" ) + layerName );
97 const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->
lastResponse() );
98 const QJsonObject jsonObject = jsonDocument.object();
99 const QList<QVariant> layers = jsonObject.toVariantMap().value( QStringLiteral(
"objects" ) ).toList();
100 if ( layers.count() < 1 )
104 QString defaultStyleUrl = layers.at( 0 ).toMap().value( QStringLiteral(
"default_style" ) ).toString();
106 defaultStyle = retrieveStyle( defaultStyleUrl );
114 QList<QgsGeoNodeStyle> geoNodeStyles;
115 bool success =
requestBlocking( QStringLiteral(
"/api/styles?layer__name=" ) + layerName );
118 return geoNodeStyles;
121 const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->
lastResponse() );
122 const QJsonObject jsobObject = jsonDocument.object();
123 const QList<QVariant> styles = jsobObject.toVariantMap().value( QStringLiteral(
"objects" ) ).toList();
125 for (
const QVariant &style : styles )
127 const QVariantMap styleMap = style.toMap();
128 QString styleUrl = styleMap.value( QStringLiteral(
"resource_uri" ) ).toString();
130 if ( !geoNodeStyle.
name.isEmpty() )
132 geoNodeStyles.append( geoNodeStyle );
136 return geoNodeStyles;
142 QString endPoint = QStringLiteral(
"/api/styles/" ) + styleId;
144 return retrieveStyle( endPoint );
147 void QgsGeoNodeRequest::replyProgress( qint64 bytesReceived, qint64 bytesTotal )
149 QString msg = tr(
"%1 of %2 bytes of request downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral(
"unknown number of" ) : QString::number( bytesTotal ) );
164 void QgsGeoNodeRequest::replyFinished()
167 if ( !mIsAborted && mGeoNodeReply )
169 if ( mGeoNodeReply->error() == QNetworkReply::NoError )
172 QVariant redirect = mGeoNodeReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
173 if ( !redirect.isNull() )
176 emit
statusChanged( QStringLiteral(
"GeoNode request redirected." ) );
178 const QUrl &toUrl = redirect.toUrl();
179 if ( toUrl == mGeoNodeReply->url() )
181 mError = tr(
"Redirect loop detected: %1" ).arg( toUrl.toString() );
183 mHttpGeoNodeResponse.clear();
187 QNetworkRequest
request( toUrl );
189 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
190 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
192 mGeoNodeReply->deleteLater();
193 mGeoNodeReply =
nullptr;
195 QgsDebugMsgLevel( QString(
"redirected getcapabilities: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ), 3 );
198 connect( mGeoNodeReply, &QNetworkReply::finished,
this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
199 connect( mGeoNodeReply, &QNetworkReply::downloadProgress,
this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
209 QNetworkCacheMetaData cmd = nam->cache()->metaData( mGeoNodeReply->request().url() );
211 QNetworkCacheMetaData::RawHeaderList hl;
212 const QNetworkCacheMetaData::RawHeaderList cmdHeaders = cmd.rawHeaders();
213 for (
const QNetworkCacheMetaData::RawHeader &h : cmdHeaders )
215 if ( h.first != QStringLiteral(
"Cache-Control" ) )
218 cmd.setRawHeaders( hl );
220 QgsDebugMsg( QString(
"expirationDate:%1" ).arg( cmd.expirationDate().toString() ) );
221 if ( cmd.expirationDate().isNull() )
224 cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( settings.
value( QStringLiteral(
"qgis/defaultCapabilitiesExpiry" ),
"24",
QgsSettings::Providers ).toInt() * 60 * 60 ) );
227 nam->cache()->updateMetaData( cmd );
234 mHttpGeoNodeResponse = mGeoNodeReply->readAll();
236 if ( mHttpGeoNodeResponse.isEmpty() )
238 mError = tr(
"Empty capabilities: %1" ).arg( mGeoNodeReply->errorString() );
244 mError = tr(
"Request failed: %1" ).arg( mGeoNodeReply->errorString() );
246 mHttpGeoNodeResponse.clear();
252 mGeoNodeReply->deleteLater();
253 mGeoNodeReply =
nullptr;
259 QList<QgsGeoNodeRequest::ServiceLayerDetail> QgsGeoNodeRequest::parseLayers(
const QByteArray &layerResponse )
261 QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
262 if ( layerResponse.isEmpty() )
267 const QJsonDocument jsonDocument = QJsonDocument::fromJson( layerResponse );
268 const QJsonObject jsonObject = jsonDocument.object();
269 const QVariantMap jsonVariantMap = jsonObject.toVariantMap();
270 const QVariantList layerList = jsonVariantMap.value( QStringLiteral(
"objects" ) ).toList();
273 if ( jsonVariantMap.contains( QStringLiteral(
"geonode_version" ) ) )
275 const QStringList geonodeVersionSplit = jsonVariantMap.value( QStringLiteral(
"geonode_version" ) ).toString().split(
'.' );
276 majorVersion = geonodeVersionSplit.at( 0 ).toInt();
277 minorVersion = geonodeVersionSplit.at( 1 ).toInt();
285 if ( majorVersion == 2 && minorVersion == 6 )
287 for (
const QVariant &layer : qgis::as_const( layerList ) )
290 const QVariantMap layerMap = layer.toMap();
293 QString layerTypeName = layerMap.value( QStringLiteral(
"detail_url" ) ).toString().split(
'/' ).last();
294 if ( layerTypeName.isEmpty() )
296 layerTypeName = layerMap.value( QStringLiteral(
"distribution_url" ) ).toString().split(
'/' ).last();
299 if ( layerTypeName.contains( QStringLiteral(
"%3A" ) ) )
301 layerTypeName.replace( QStringLiteral(
"%3A" ), QStringLiteral(
":" ) );
304 const QStringList splitURL = layerTypeName.split(
':' );
305 QString layerWorkspace = splitURL.at( 0 );
306 QString layerName = splitURL.at( 1 );
308 layerStruct.
name = layerName;
309 layerStruct.
typeName = layerTypeName;
310 layerStruct.
uuid = layerMap.value( QStringLiteral(
"uuid" ) ).toString();
311 layerStruct.
title = layerMap.value( QStringLiteral(
"title" ) ).toString();
314 layerStruct.
wmsURL = mBaseUrl + QStringLiteral(
"/geoserver/" ) + layerWorkspace + QStringLiteral(
"/wms" );
316 layerStruct.
wfsURL = mBaseUrl + QStringLiteral(
"/geoserver/" ) + layerWorkspace + QStringLiteral(
"/wfs" );
318 layerStruct.
xyzURL.clear();
320 layers.append( layerStruct );
324 else if ( ( majorVersion == 2 && minorVersion >= 7 ) || ( majorVersion >= 3 ) )
326 for (
const QVariant &layer : qgis::as_const( layerList ) )
329 const QVariantMap layerMap = layer.toMap();
331 const QVariantList layerLinks = layerMap.value( QStringLiteral(
"links" ) ).toList();
332 for (
const QVariant &link : layerLinks )
334 const QVariantMap linkMap = link.toMap();
335 if ( linkMap.contains( QStringLiteral(
"link_type" ) ) )
337 if ( linkMap.value( QStringLiteral(
"link_type" ) ) == QStringLiteral(
"OGC:WMS" ) )
339 layerStruct.
wmsURL = linkMap.value( QStringLiteral(
"url" ) ).toString();
341 else if ( linkMap.value( QStringLiteral(
"link_type" ) ) == QStringLiteral(
"OGC:WFS" ) )
343 layerStruct.
wfsURL = linkMap.value( QStringLiteral(
"url" ) ).toString();
345 else if ( linkMap.value( QStringLiteral(
"link_type" ) ) == QStringLiteral(
"image" ) )
347 if ( linkMap.contains( QStringLiteral(
"name" ) ) && linkMap.value( QStringLiteral(
"name" ) ) == QStringLiteral(
"Tiles" ) )
349 layerStruct.
xyzURL = linkMap.value( QStringLiteral(
"url" ) ).toString();
354 if ( layerMap.value( QStringLiteral(
"typename" ) ).toString().isEmpty() )
356 const QStringList splitURL = layerMap.value( QStringLiteral(
"detail_url" ) ).toString().split(
'/' );
357 layerStruct.
typeName = splitURL.at( splitURL.length() - 1 );
359 layerStruct.
uuid = layerMap.value( QStringLiteral(
"uuid" ) ).toString();
360 layerStruct.
name = layerMap.value( QStringLiteral(
"name" ) ).toString();
361 layerStruct.
typeName = layerMap.value( QStringLiteral(
"typename" ) ).toString();
362 layerStruct.
title = layerMap.value( QStringLiteral(
"title" ) ).toString();
363 layers.append( layerStruct );
369 QgsGeoNodeStyle QgsGeoNodeRequest::retrieveStyle(
const QString &styleUrl )
378 const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->
lastResponse() );
379 const QJsonObject jsonObject = jsonDocument.object();
381 const QVariantMap jsonMap = jsonObject.toVariantMap();
382 geoNodeStyle.
id = jsonMap.value( QStringLiteral(
"id" ) ).toString();
383 geoNodeStyle.
name = jsonMap.value( QStringLiteral(
"name" ) ).toString();
384 geoNodeStyle.
title = jsonMap.value( QStringLiteral(
"title" ) ).toString();
385 geoNodeStyle.
styleUrl = jsonMap.value( QStringLiteral(
"style_url" ) ).toString();
408 if ( layers.empty() )
416 if ( QString::compare( serviceType, QStringLiteral(
"wms" ), Qt::CaseInsensitive ) == 0 )
420 else if ( QString::compare( serviceType, QStringLiteral(
"wfs" ), Qt::CaseInsensitive ) == 0 )
424 else if ( QString::compare( serviceType, QStringLiteral(
"xyz" ), Qt::CaseInsensitive ) == 0 )
432 if ( !url.contains( QLatin1String(
"://" ) ) )
436 if ( !urls.contains( url ) )
451 if ( layers.empty() )
460 if ( QString::compare( serviceType, QStringLiteral(
"wms" ), Qt::CaseInsensitive ) == 0 )
464 else if ( QString::compare( serviceType, QStringLiteral(
"wfs" ), Qt::CaseInsensitive ) == 0 )
468 else if ( QString::compare( serviceType, QStringLiteral(
"xyz" ), Qt::CaseInsensitive ) == 0 )
476 QString layerName = layer.name;
477 if ( !url.contains( QLatin1String(
"://" ) ) )
481 if ( !urls.contains( url ) )
483 urls.insert( layerName, url );
495 QString url = endPoint.startsWith( mBaseUrl ) ? endPoint : mBaseUrl + endPoint;
497 setProtocol( url.split( QStringLiteral(
"://" ) ).at( 0 ) );
498 QUrl layerUrl( url );
503 mGeoNodeReply = requestUrl( url );
504 connect( mGeoNodeReply, &QNetworkReply::finished,
this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
505 connect( mGeoNodeReply, &QNetworkReply::downloadProgress,
this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
514 loop.exec( QEventLoop::ExcludeUserInputEvents );
516 return mError.isEmpty();
519 QNetworkReply *QgsGeoNodeRequest::requestUrl(
const QString &url )
521 QNetworkRequest
request( url );
524 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
525 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
void fetchLayers()
Triggers a new request to fetch the list of available layers from the server.
void layersFetched(const QList< QgsGeoNodeRequest::ServiceLayerDetail > &layers)
Emitted when the result of a fetchLayers call has been received and processed.
Encapsulates information about a GeoNode layer style.
void setProtocol(const QString &protocol)
Sets the network protocol (e.g.
This class is a composition of two QSettings instances:
~QgsGeoNodeRequest() override
QString styleUrl
Associated URL.
Service layer details for an individual layer from a GeoNode connection.
QByteArray lastResponse() const
Returns the most recent response obtained from the server.
void request(const QString &endPoint)
Triggers a new request to the GeoNode server, with the requested endPoint.
QString wmsURL
WMS URL for layer.
QgsStringMap fetchServiceUrlDataBlocking(const QString &serviceType)
Obtains a map of layer name to URL for available services with matching serviceType from the server...
QList< QgsGeoNodeStyle > fetchStylesBlocking(const QString &layerName)
Requests the list of available styles for the layer with matching layerName from the server...
QMap< QString, QString > QgsStringMap
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
QString typeName
Layer type name.
QDomDocument body
DOM documenting containing style.
void statusChanged(const QString &statusQString)
Emitted when the status of an ongoing request is changed.
QgsGeoNodeStyle fetchDefaultStyleBlocking(const QString &layerName)
Requests the default style for the layer with matching layerName from the server. ...
#define QgsDebugMsgLevel(str, level)
QString title
Layer title.
QString xyzURL
XYZ tileserver URL for layer.
QList< QgsGeoNodeRequest::ServiceLayerDetail > fetchLayersBlocking()
Requests the list of available layers from the server.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
QString wfsURL
WFS URL for layer.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QgsGeoNodeRequest(const QString &baseUrl, bool forceRefresh, QObject *parent=nullptr)
Constructor for QgsGeoNodeRequest.
void requestFinished()
Emitted when the existing request has been completed.
QString id
Unique style ID.
QString protocol() const
Returns the network protocol (e.g.
bool requestBlocking(const QString &endPoint)
Triggers a new request to the GeoNode server, with the requested endPoint.
QUuid uuid
Unique identifier (generate on the client side, not at the GeoNode server)
void abort()
Aborts any active network request immediately.
network access manager for QGIS
QgsGeoNodeStyle fetchStyleBlocking(const QString &styleId)
Requests the details for the style with matching styleId from the server.
QStringList fetchServiceUrlsBlocking(const QString &serviceType)
Requests the list of unique URLs for available services with matching serviceType from the server...
QString title
Style title.