QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsgeonoderequest.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeonoderequest.h
3  ---------------------
4  begin : Jul 2017
5  copyright : (C) 2017 by Muhammad Yarjuna Rohmat, Ismail Sunni
6  email : rohmat at kartoza dot com, ismail at kartoza dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgssettings.h"
18 #include "qgsmessagelog.h"
19 #include "qgslogger.h"
20 #include "qgsgeonoderequest.h"
21 
22 #include <QEventLoop>
23 #include <QNetworkCacheMetaData>
24 #include <QByteArray>
25 #include <QJsonDocument>
26 #include <QJsonObject>
27 #include <QUrl>
28 #include <QDomDocument>
29 #include <QRegularExpression>
30 
31 QgsGeoNodeRequest::QgsGeoNodeRequest( const QString &baseUrl, bool forceRefresh, QObject *parent )
32  : QObject( parent )
33  , mBaseUrl( baseUrl )
34  , mForceRefresh( forceRefresh )
35 {
36 
37 }
38 
40 {
41  abort();
42 }
43 
45 {
46  mIsAborted = true;
47  if ( mGeoNodeReply )
48  {
49  mGeoNodeReply->deleteLater();
50  mGeoNodeReply = nullptr;
51  }
52 }
53 
55 {
56  request( QStringLiteral( "/api/layers/" ) );
57  QObject *obj = new QObject( this );
58 
59  connect( this, &QgsGeoNodeRequest::requestFinished, obj, [obj, this ]
60  {
61  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
62  if ( mError.isEmpty() )
63  {
64  layers = parseLayers( this->lastResponse() );
65  }
66  emit layersFetched( layers );
67 
68  obj->deleteLater();
69  } );
70 }
71 
72 QList<QgsGeoNodeRequest::ServiceLayerDetail> QgsGeoNodeRequest::fetchLayersBlocking()
73 {
74  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
75 
76  QEventLoop loop;
77  connect( this, &QgsGeoNodeRequest::requestFinished, &loop, &QEventLoop::quit );
78  QObject *obj = new QObject( this );
79  connect( this, &QgsGeoNodeRequest::layersFetched, obj, [&]( const QList<QgsGeoNodeRequest::ServiceLayerDetail> &fetched )
80  {
81  layers = fetched;
82  } );
83  fetchLayers();
84  loop.exec( QEventLoop::ExcludeUserInputEvents );
85  delete obj;
86  return layers;
87 }
88 
90 {
91  QgsGeoNodeStyle defaultStyle;
92  bool success = requestBlocking( QStringLiteral( "/api/layers?name=" ) + layerName );
93  if ( !success )
94  {
95  return defaultStyle;
96  }
97 
98  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
99  const QJsonObject jsonObject = jsonDocument.object();
100  const QList<QVariant> layers = jsonObject.toVariantMap().value( QStringLiteral( "objects" ) ).toList();
101  if ( layers.count() < 1 )
102  {
103  return defaultStyle;
104  }
105  QString defaultStyleUrl = layers.at( 0 ).toMap().value( QStringLiteral( "default_style" ) ).toString();
106 
107  defaultStyle = retrieveStyle( defaultStyleUrl );
108 
109  return defaultStyle;
110 
111 }
112 
113 QList<QgsGeoNodeStyle> QgsGeoNodeRequest::fetchStylesBlocking( const QString &layerName )
114 {
115  QList<QgsGeoNodeStyle> geoNodeStyles;
116  bool success = requestBlocking( QStringLiteral( "/api/styles?layer__name=" ) + layerName );
117  if ( !success )
118  {
119  return geoNodeStyles;
120  }
121 
122  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
123  const QJsonObject jsobObject = jsonDocument.object();
124  const QList<QVariant> styles = jsobObject.toVariantMap().value( QStringLiteral( "objects" ) ).toList();
125 
126  for ( const QVariant &style : styles )
127  {
128  const QVariantMap styleMap = style.toMap();
129  QString styleUrl = styleMap.value( QStringLiteral( "resource_uri" ) ).toString();
130  QgsGeoNodeStyle geoNodeStyle = retrieveStyle( styleUrl );
131  if ( !geoNodeStyle.name.isEmpty() )
132  {
133  geoNodeStyles.append( geoNodeStyle );
134  }
135  }
136 
137  return geoNodeStyles;
138 
139 }
140 
142 {
143  QString endPoint = QStringLiteral( "/api/styles/" ) + styleId;
144 
145  return retrieveStyle( endPoint );
146 }
147 
148 void QgsGeoNodeRequest::replyProgress( qint64 bytesReceived, qint64 bytesTotal )
149 {
150  QString msg = tr( "%1 of %2 bytes of request downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral( "unknown number of" ) : QString::number( bytesTotal ) );
151  QgsDebugMsgLevel( msg, 3 );
152  emit statusChanged( msg );
153 }
154 
156 {
157  return mProtocol;
158 }
159 
161 {
162  mProtocol = protocol;
163 }
164 
165 void QgsGeoNodeRequest::replyFinished()
166 {
167  QgsDebugMsgLevel( QStringLiteral( "Reply finished" ), 2 );
168  if ( !mIsAborted && mGeoNodeReply )
169  {
170  if ( mGeoNodeReply->error() == QNetworkReply::NoError )
171  {
172  QgsDebugMsgLevel( QStringLiteral( "reply OK" ), 2 );
173  QVariant redirect = mGeoNodeReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
174  if ( !redirect.isNull() )
175  {
176 
177  emit statusChanged( QStringLiteral( "GeoNode request redirected." ) );
178 
179  const QUrl &toUrl = redirect.toUrl();
180  if ( toUrl == mGeoNodeReply->url() )
181  {
182  mError = tr( "Redirect loop detected: %1" ).arg( toUrl.toString() );
183  QgsMessageLog::logMessage( mError, tr( "GeoNode" ) );
184  mHttpGeoNodeResponse.clear();
185  }
186  else
187  {
188  QNetworkRequest request( toUrl );
189  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) );
190  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
191  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
192 
193  mGeoNodeReply->deleteLater();
194  mGeoNodeReply = nullptr;
195 
196  QgsDebugMsgLevel( QStringLiteral( "redirected getcapabilities: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ), 3 );
197  mGeoNodeReply = QgsNetworkAccessManager::instance()->get( request );
198 
199  connect( mGeoNodeReply, &QNetworkReply::finished, this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
200  connect( mGeoNodeReply, &QNetworkReply::downloadProgress, this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
201  return;
202  }
203  }
204  else
205  {
207 
208  if ( nam->cache() )
209  {
210  QNetworkCacheMetaData cmd = nam->cache()->metaData( mGeoNodeReply->request().url() );
211 
212  QNetworkCacheMetaData::RawHeaderList hl;
213  const QNetworkCacheMetaData::RawHeaderList cmdHeaders = cmd.rawHeaders();
214  for ( const QNetworkCacheMetaData::RawHeader &h : cmdHeaders )
215  {
216  if ( h.first != QStringLiteral( "Cache-Control" ) )
217  hl.append( h );
218  }
219  cmd.setRawHeaders( hl );
220 
221  QgsDebugMsgLevel( QStringLiteral( "expirationDate:%1" ).arg( cmd.expirationDate().toString() ), 2 );
222  if ( cmd.expirationDate().isNull() )
223  {
224  QgsSettings settings;
225  cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( settings.value( QStringLiteral( "qgis/defaultCapabilitiesExpiry" ), "24", QgsSettings::Providers ).toInt() * 60 * 60 ) );
226  }
227 
228  nam->cache()->updateMetaData( cmd );
229  }
230  else
231  {
232  QgsDebugMsg( QStringLiteral( "No cache for capabilities!" ) );
233  }
234 
235  mHttpGeoNodeResponse = mGeoNodeReply->readAll();
236 
237  if ( mHttpGeoNodeResponse.isEmpty() )
238  {
239  mError = tr( "Empty capabilities: %1" ).arg( mGeoNodeReply->errorString() );
240  }
241  }
242  }
243  else
244  {
245  mError = tr( "Request failed: %1" ).arg( mGeoNodeReply->errorString() );
246  QgsMessageLog::logMessage( mError, tr( "GeoNode" ) );
247  mHttpGeoNodeResponse.clear();
248  }
249  }
250 
251  if ( mGeoNodeReply )
252  {
253  mGeoNodeReply->deleteLater();
254  mGeoNodeReply = nullptr;
255  }
256 
257  emit requestFinished();
258 }
259 
260 QList<QgsGeoNodeRequest::ServiceLayerDetail> QgsGeoNodeRequest::parseLayers( const QByteArray &layerResponse )
261 {
262  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
263  if ( layerResponse.isEmpty() )
264  {
265  return layers;
266  }
267 
268  const QJsonDocument jsonDocument = QJsonDocument::fromJson( layerResponse );
269  const QJsonObject jsonObject = jsonDocument.object();
270  const QVariantMap jsonVariantMap = jsonObject.toVariantMap();
271  const QVariantList layerList = jsonVariantMap.value( QStringLiteral( "objects" ) ).toList();
272 
273  QString wmsURLFormat, wfsURLFormat, xyzURLFormat;
274 
275  for ( const QVariant &layer : qgis::as_const( layerList ) )
276  {
278  const QVariantMap layerMap = layer.toMap();
279  QVariantList layerLinks = layerMap.value( QStringLiteral( "links" ) ).toList();
280 
281  if ( layerMap.value( QStringLiteral( "typename" ) ).toString().isEmpty() )
282  {
283  const QStringList splitUrl = layerMap.value( QStringLiteral( "detail_url" ) ).toString().split( '/' );
284  layerStruct.typeName = !splitUrl.isEmpty() ? splitUrl.last() : QString();
285  }
286  layerStruct.uuid = layerMap.value( QStringLiteral( "uuid" ) ).toString();
287  layerStruct.id = layerMap.value( QStringLiteral( "id" ) ).toString();
288  layerStruct.name = layerMap.value( QStringLiteral( "name" ) ).toString();
289  layerStruct.typeName = layerMap.value( QStringLiteral( "typename" ) ).toString();
290  layerStruct.title = layerMap.value( QStringLiteral( "title" ) ).toString();
291 
292  if ( ! layerMap.contains( QStringLiteral( "links" ) ) )
293  {
294  if ( wmsURLFormat.isEmpty() && wfsURLFormat.isEmpty() && xyzURLFormat.isEmpty() )
295  {
296  bool success = requestBlocking( QStringLiteral( "/api/layers/" ) + layerStruct.id );
297  if ( success )
298  {
299  const QJsonDocument resourceUriDocument = QJsonDocument::fromJson( this->lastResponse() );
300  const QJsonObject resourceUriObject = resourceUriDocument.object();
301  const QVariantMap resourceUriMap = resourceUriObject.toVariantMap();
302  QVariantList resourceUriLinks = resourceUriMap.value( QStringLiteral( "links" ) ).toList();
304  tempLayerStruct = parseOwsUrl( tempLayerStruct, resourceUriLinks );
305 
306  if ( tempLayerStruct.wmsURL.isEmpty() && tempLayerStruct.wfsURL.isEmpty() && tempLayerStruct.xyzURL.isEmpty() )
307  continue;
308 
309  // Avoid iterating all the layers to get the service url. Instead, generate a string format once we found one service url
310  // for every service (wms, wfs, xyz). And then use the string format for the other layers since they are identical.
311  switch ( tempLayerStruct.server )
312  {
314  {
315  wmsURLFormat = ! tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
316  wfsURLFormat = ! tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
317  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
318  break;
319  }
321  {
322  wmsURLFormat = ! tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL : QString();
323  wfsURLFormat = ! tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL : QString();
324  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
325  break;
326  }
328  break;
329  }
330  }
331  else
332  continue;
333  }
334  else
335  {
336  // Replace string argument with the layer id.
337  layerStruct.wmsURL = wmsURLFormat.contains( "%1" ) ? wmsURLFormat.arg( layerStruct.name ) : wmsURLFormat;
338  layerStruct.wfsURL = wfsURLFormat.contains( "%1" ) ? wfsURLFormat.arg( layerStruct.name ) : wfsURLFormat;
339  layerStruct.xyzURL = xyzURLFormat.contains( "%1" ) ? xyzURLFormat.arg( layerStruct.name ) : xyzURLFormat;
340  }
341  }
342  else
343  layerStruct = parseOwsUrl( layerStruct, layerLinks );
344 
345  layers.append( layerStruct );
346  }
347 
348  return layers;
349 }
350 
352 {
353  QString urlFound;
354  for ( const QVariant &link : layerLinks )
355  {
356  const QVariantMap linkMap = link.toMap();
357  if ( linkMap.contains( QStringLiteral( "link_type" ) ) )
358  {
359  if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WMS" ) )
360  {
361  urlFound = layerStruct.wmsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
362  }
363  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WFS" ) )
364  {
365  urlFound = layerStruct.wfsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
366  }
367  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "image" ) )
368  {
369  if ( linkMap.contains( QStringLiteral( "name" ) ) && linkMap.value( QStringLiteral( "name" ) ) == QStringLiteral( "Tiles" ) )
370  {
371  urlFound = layerStruct.xyzURL = linkMap.value( QStringLiteral( "url" ) ).toString();
372  }
373  }
374  }
375 
376  switch ( layerStruct.server )
377  {
380  break;
381 
383  {
384  layerStruct.server = urlFound.contains( QStringLiteral( "qgis-server" ) ) ? QgsGeoNodeRequest::BackendServer::QgisServer : QgsGeoNodeRequest::BackendServer::Geoserver;
385  break;
386  }
387  }
388  }
389 
390  return layerStruct;
391 }
392 
393 QgsGeoNodeStyle QgsGeoNodeRequest::retrieveStyle( const QString &styleUrl )
394 {
395  QgsGeoNodeStyle geoNodeStyle;
396 
397  bool success = requestBlocking( styleUrl );
398  if ( !success )
399  {
400  return geoNodeStyle;
401  }
402  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
403  const QJsonObject jsonObject = jsonDocument.object();
404 
405  const QVariantMap jsonMap = jsonObject.toVariantMap();
406  geoNodeStyle.id = jsonMap.value( QStringLiteral( "id" ) ).toString();
407  geoNodeStyle.name = jsonMap.value( QStringLiteral( "name" ) ).toString();
408  geoNodeStyle.title = jsonMap.value( QStringLiteral( "title" ) ).toString();
409  geoNodeStyle.styleUrl = jsonMap.value( QStringLiteral( "style_url" ) ).toString();
410 
411  success = requestBlocking( geoNodeStyle.styleUrl );
412  if ( !success )
413  {
414  return geoNodeStyle;
415  }
416 
417  success = geoNodeStyle.body.setContent( this->lastResponse() );
418  if ( !success )
419  {
420  return geoNodeStyle;
421  }
422 
423  return geoNodeStyle;
424 }
425 
426 QStringList QgsGeoNodeRequest::fetchServiceUrlsBlocking( const QString &serviceType )
427 {
428  QStringList urls;
429 
430  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
431 
432  if ( layers.empty() )
433  {
434  return urls;
435  }
436 
437  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
438  {
439  QString url;
440  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
441  {
442  url = layer.wmsURL;
443  }
444  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
445  {
446  url = layer.wfsURL;
447  }
448  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
449  {
450  url = layer.xyzURL;
451  }
452 
453  if ( url.isEmpty() )
454  continue;
455 
456  if ( !url.contains( QLatin1String( "://" ) ) )
457  {
458  url.prepend( protocol() );
459  }
460  if ( !urls.contains( url ) )
461  {
462  urls.append( url );
463  }
464  }
465 
466  return urls;
467 }
468 
470 {
471  QgsStringMap urls;
472 
473  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
474 
475  if ( layers.empty() )
476  {
477  return urls;
478  }
479 
480  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
481  {
482  QString url;
483 
484  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
485  {
486  url = layer.wmsURL;
487  }
488  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
489  {
490  url = layer.wfsURL;
491  }
492  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
493  {
494  url = layer.xyzURL;
495  }
496 
497  if ( url.isEmpty() )
498  continue;
499 
500  QString layerName = layer.name;
501  if ( !url.contains( QLatin1String( "://" ) ) )
502  {
503  url.prepend( protocol() );
504  }
505  if ( !urls.contains( url ) )
506  {
507  urls.insert( layerName, url );
508  }
509  }
510 
511  return urls;
512 }
513 
514 void QgsGeoNodeRequest::request( const QString &endPoint )
515 {
516  abort();
517  mIsAborted = false;
518  // Handle case where the endpoint is full url
519  QString url = endPoint.startsWith( mBaseUrl ) ? endPoint : mBaseUrl + endPoint;
520  QgsDebugMsgLevel( "Requesting to " + url, 2 );
521  setProtocol( url.split( QStringLiteral( "://" ) ).at( 0 ) );
522  QUrl layerUrl( url );
523  layerUrl.setScheme( protocol() );
524 
525  mError.clear();
526 
527  mGeoNodeReply = requestUrl( url );
528  connect( mGeoNodeReply, &QNetworkReply::finished, this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
529  connect( mGeoNodeReply, &QNetworkReply::downloadProgress, this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
530 }
531 
532 bool QgsGeoNodeRequest::requestBlocking( const QString &endPoint )
533 {
534  request( endPoint );
535 
536  QEventLoop loop;
537  connect( this, &QgsGeoNodeRequest::requestFinished, &loop, &QEventLoop::quit );
538  loop.exec( QEventLoop::ExcludeUserInputEvents );
539 
540  return mError.isEmpty();
541 }
542 
543 QNetworkReply *QgsGeoNodeRequest::requestUrl( const QString &url )
544 {
545  QNetworkRequest request( url );
546  request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true );
547 
548  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) );
549  // Add authentication check here
550 
551  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
552  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
553 
554  return QgsNetworkAccessManager::instance()->get( request );
555 }
556 
557 
void fetchLayers()
Triggers a new request to fetch the list of available layers from the server.
#define QgsSetRequestInitiatorClass(request, _class)
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:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
~QgsGeoNodeRequest() override
BackendServer server
Backend server (geoserver or qgis-server)
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
Definition: qgis.h:694
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)
Definition: qgslogger.h:39
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString xyzURL
XYZ tileserver URL for layer.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
QList< QgsGeoNodeRequest::ServiceLayerDetail > fetchLayersBlocking()
Requests the list of available layers from the server.
QString wfsURL
WFS URL for layer.
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.
QgsGeoNodeRequest::ServiceLayerDetail parseOwsUrl(QgsGeoNodeRequest::ServiceLayerDetail &layerStruct, const QVariantList &layerLinks)
Returns the updated ServiceLayerDetail struct with WMS/WFS/XYZ url.
QString protocol() const
Returns the network protocol (e.g.
QString name
Style name.
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 QGISThis class implements the QGIS network access manager.
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.