QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
58  QObject *obj = new QObject( this );
59  connect( this, &QgsGeoNodeRequest::requestFinished, obj, [obj, this ]
60  {
61  if ( !mParsingLayers )
62  {
63  mParsingLayers = true;
64  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
65  if ( mError.isEmpty() )
66  {
67  layers = parseLayers( lastResponse() );
68  }
69  emit layersFetched( layers );
70  mParsingLayers = false;
71  obj->deleteLater();
72  }
73  } );
74 }
75 
76 QList<QgsGeoNodeRequest::ServiceLayerDetail> QgsGeoNodeRequest::fetchLayersBlocking()
77 {
78  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
79 
80  QEventLoop loop;
81  QObject *obj = new QObject( this );
82  connect( this, &QgsGeoNodeRequest::layersFetched, obj, [&]( const QList<QgsGeoNodeRequest::ServiceLayerDetail> &fetched )
83  {
84  layers = fetched;
85  loop.exit();
86  } );
87  fetchLayers();
88  loop.exec( QEventLoop::ExcludeUserInputEvents );
89  delete obj;
90  return layers;
91 }
92 
94 {
95  QgsGeoNodeStyle defaultStyle;
96  bool success = requestBlocking( QStringLiteral( "/api/layers?name=" ) + layerName );
97  if ( !success )
98  {
99  return defaultStyle;
100  }
101 
102  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
103  const QJsonObject jsonObject = jsonDocument.object();
104  const QList<QVariant> layers = jsonObject.toVariantMap().value( QStringLiteral( "objects" ) ).toList();
105  if ( layers.count() < 1 )
106  {
107  return defaultStyle;
108  }
109  QString defaultStyleUrl = layers.at( 0 ).toMap().value( QStringLiteral( "default_style" ) ).toString();
110 
111  defaultStyle = retrieveStyle( defaultStyleUrl );
112 
113  return defaultStyle;
114 
115 }
116 
117 QList<QgsGeoNodeStyle> QgsGeoNodeRequest::fetchStylesBlocking( const QString &layerName )
118 {
119  QList<QgsGeoNodeStyle> geoNodeStyles;
120  bool success = requestBlocking( QStringLiteral( "/api/styles?layer__name=" ) + layerName );
121  if ( !success )
122  {
123  return geoNodeStyles;
124  }
125 
126  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
127  const QJsonObject jsobObject = jsonDocument.object();
128  const QList<QVariant> styles = jsobObject.toVariantMap().value( QStringLiteral( "objects" ) ).toList();
129 
130  for ( const QVariant &style : styles )
131  {
132  const QVariantMap styleMap = style.toMap();
133  QString styleUrl = styleMap.value( QStringLiteral( "resource_uri" ) ).toString();
134  QgsGeoNodeStyle geoNodeStyle = retrieveStyle( styleUrl );
135  if ( !geoNodeStyle.name.isEmpty() )
136  {
137  geoNodeStyles.append( geoNodeStyle );
138  }
139  }
140 
141  return geoNodeStyles;
142 
143 }
144 
146 {
147  QString endPoint = QStringLiteral( "/api/styles/" ) + styleId;
148 
149  return retrieveStyle( endPoint );
150 }
151 
152 void QgsGeoNodeRequest::replyProgress( qint64 bytesReceived, qint64 bytesTotal )
153 {
154  QString msg = tr( "%1 of %2 bytes of request downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral( "unknown number of" ) : QString::number( bytesTotal ) );
155  QgsDebugMsgLevel( msg, 3 );
156  emit statusChanged( msg );
157 }
158 
160 {
161  return mProtocol;
162 }
163 
164 void QgsGeoNodeRequest::setProtocol( const QString &protocol )
165 {
166  mProtocol = protocol;
167 }
168 
169 void QgsGeoNodeRequest::replyFinished()
170 {
171  QgsDebugMsgLevel( QStringLiteral( "Reply finished" ), 2 );
172  if ( !mIsAborted && mGeoNodeReply )
173  {
174  if ( mGeoNodeReply->error() == QNetworkReply::NoError )
175  {
176  QgsDebugMsgLevel( QStringLiteral( "reply OK" ), 2 );
177  QVariant redirect = mGeoNodeReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
178  if ( !redirect.isNull() )
179  {
180 
181  emit statusChanged( QStringLiteral( "GeoNode request redirected." ) );
182 
183  const QUrl &toUrl = redirect.toUrl();
184  if ( toUrl == mGeoNodeReply->url() )
185  {
186  mError = tr( "Redirect loop detected: %1" ).arg( toUrl.toString() );
187  QgsMessageLog::logMessage( mError, tr( "GeoNode" ) );
188  mHttpGeoNodeResponse.clear();
189  }
190  else
191  {
192  QNetworkRequest request( toUrl );
193  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) );
194  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
195  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
196 
197  mGeoNodeReply->deleteLater();
198  mGeoNodeReply = nullptr;
199 
200  QgsDebugMsgLevel( QStringLiteral( "redirected getcapabilities: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ), 3 );
201  mGeoNodeReply = QgsNetworkAccessManager::instance()->get( request );
202 
203  connect( mGeoNodeReply, &QNetworkReply::finished, this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
204  connect( mGeoNodeReply, &QNetworkReply::downloadProgress, this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
205  return;
206  }
207  }
208  else
209  {
211 
212  if ( nam->cache() )
213  {
214  QNetworkCacheMetaData cmd = nam->cache()->metaData( mGeoNodeReply->request().url() );
215 
216  QNetworkCacheMetaData::RawHeaderList hl;
217  const QNetworkCacheMetaData::RawHeaderList cmdHeaders = cmd.rawHeaders();
218  for ( const QNetworkCacheMetaData::RawHeader &h : cmdHeaders )
219  {
220  if ( h.first != QStringLiteral( "Cache-Control" ) )
221  hl.append( h );
222  }
223  cmd.setRawHeaders( hl );
224 
225  QgsDebugMsgLevel( QStringLiteral( "expirationDate:%1" ).arg( cmd.expirationDate().toString() ), 2 );
226  if ( cmd.expirationDate().isNull() )
227  {
228  QgsSettings settings;
229  cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( settings.value( QStringLiteral( "qgis/defaultCapabilitiesExpiry" ), "24", QgsSettings::Providers ).toInt() * 60 * 60 ) );
230  }
231 
232  nam->cache()->updateMetaData( cmd );
233  }
234  else
235  {
236  QgsDebugMsg( QStringLiteral( "No cache for capabilities!" ) );
237  }
238 
239  mHttpGeoNodeResponse = mGeoNodeReply->readAll();
240 
241  if ( mHttpGeoNodeResponse.isEmpty() )
242  {
243  mError = tr( "Empty capabilities: %1" ).arg( mGeoNodeReply->errorString() );
244  }
245  }
246  }
247  else
248  {
249  mError = tr( "Request failed: %1" ).arg( mGeoNodeReply->errorString() );
250  QgsMessageLog::logMessage( mError, tr( "GeoNode" ) );
251  mHttpGeoNodeResponse.clear();
252  }
253  }
254 
255  if ( mGeoNodeReply )
256  {
257  mGeoNodeReply->deleteLater();
258  mGeoNodeReply = nullptr;
259  }
260 
261  emit requestFinished();
262 }
263 
264 QList<QgsGeoNodeRequest::ServiceLayerDetail> QgsGeoNodeRequest::parseLayers( const QByteArray &layerResponse )
265 {
266  QList<QgsGeoNodeRequest::ServiceLayerDetail> layers;
267  if ( layerResponse.isEmpty() )
268  {
269  return layers;
270  }
271 
272  const QJsonDocument jsonDocument = QJsonDocument::fromJson( layerResponse );
273  const QJsonObject jsonObject = jsonDocument.object();
274  const QVariantMap jsonVariantMap = jsonObject.toVariantMap();
275  const QVariantList layerList = jsonVariantMap.value( QStringLiteral( "objects" ) ).toList();
276 
277  QString wmsURLFormat, wfsURLFormat, wcsURLFormat, xyzURLFormat;
278 
279  for ( const QVariant &layer : std::as_const( layerList ) )
280  {
282  const QVariantMap layerMap = layer.toMap();
283  QVariantList layerLinks = layerMap.value( QStringLiteral( "links" ) ).toList();
284 
285  if ( layerMap.value( QStringLiteral( "typename" ) ).toString().isEmpty() )
286  {
287  const QStringList splitUrl = layerMap.value( QStringLiteral( "detail_url" ) ).toString().split( '/' );
288  layerStruct.typeName = !splitUrl.isEmpty() ? splitUrl.last() : QString();
289  }
290  layerStruct.uuid = QUuid( layerMap.value( QStringLiteral( "uuid" ) ).toString() );
291  layerStruct.id = layerMap.value( QStringLiteral( "id" ) ).toString();
292  layerStruct.name = layerMap.value( QStringLiteral( "name" ) ).toString();
293  layerStruct.typeName = layerMap.value( QStringLiteral( "typename" ) ).toString();
294  layerStruct.title = layerMap.value( QStringLiteral( "title" ) ).toString();
295 
296  if ( ! layerMap.contains( QStringLiteral( "links" ) ) )
297  {
298  if ( wmsURLFormat.isEmpty() && wfsURLFormat.isEmpty() && wcsURLFormat.isEmpty() && xyzURLFormat.isEmpty() )
299  {
300  bool success = requestBlocking( QStringLiteral( "/api/layers/%1/" ).arg( layerStruct.id ) );
301  if ( success )
302  {
303  const QJsonDocument resourceUriDocument = QJsonDocument::fromJson( this->lastResponse() );
304  const QJsonObject resourceUriObject = resourceUriDocument.object();
305  const QVariantMap resourceUriMap = resourceUriObject.toVariantMap();
306  QVariantList resourceUriLinks = resourceUriMap.value( QStringLiteral( "links" ) ).toList();
308  tempLayerStruct = parseOwsUrl( tempLayerStruct, resourceUriLinks );
309 
310  if ( tempLayerStruct.wmsURL.isEmpty() && tempLayerStruct.wfsURL.isEmpty() && tempLayerStruct.wcsURL.isEmpty() && tempLayerStruct.xyzURL.isEmpty() )
311  continue;
312 
313  // Avoid iterating all the layers to get the service url. Instead, generate a string format once we found one service url
314  // for every service (wms, wfs, wcs, xyz). And then use the string format for the other layers since they are identical.
315  switch ( tempLayerStruct.server )
316  {
318  {
319  wmsURLFormat = ! tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
320  wfsURLFormat = ! tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
321  wcsURLFormat = ! tempLayerStruct.wcsURL.isEmpty() ? tempLayerStruct.wcsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
322  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
323  break;
324  }
326  {
327  wmsURLFormat = ! tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL : QString();
328  wfsURLFormat = ! tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL : QString();
329  wcsURLFormat = ! tempLayerStruct.wcsURL.isEmpty() ? tempLayerStruct.wcsURL : QString();
330  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
331  break;
332  }
334  break;
335  }
336  }
337  else
338  continue;
339  }
340  else
341  {
342  // Replace string argument with the layer id.
343  layerStruct.wmsURL = wmsURLFormat.contains( "%1" ) ? wmsURLFormat.arg( layerStruct.name ) : wmsURLFormat;
344  layerStruct.wfsURL = wfsURLFormat.contains( "%1" ) ? wfsURLFormat.arg( layerStruct.name ) : wfsURLFormat;
345  layerStruct.wcsURL = wcsURLFormat.contains( "%1" ) ? wcsURLFormat.arg( layerStruct.name ) : wcsURLFormat;
346  layerStruct.xyzURL = xyzURLFormat.contains( "%1" ) ? xyzURLFormat.arg( layerStruct.name ) : xyzURLFormat;
347  }
348  }
349  else
350  layerStruct = parseOwsUrl( layerStruct, layerLinks );
351 
352  layers.append( layerStruct );
353  }
354 
355  return layers;
356 }
357 
359 {
360  QString urlFound;
361  for ( const QVariant &link : layerLinks )
362  {
363  const QVariantMap linkMap = link.toMap();
364  if ( linkMap.contains( QStringLiteral( "link_type" ) ) )
365  {
366  if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WMS" ) )
367  {
368  urlFound = layerStruct.wmsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
369  }
370  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WFS" ) )
371  {
372  urlFound = layerStruct.wfsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
373  }
374  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WCS" ) )
375  {
376  urlFound = layerStruct.wcsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
377  }
378  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "image" ) )
379  {
380  if ( linkMap.contains( QStringLiteral( "name" ) ) && linkMap.value( QStringLiteral( "name" ) ) == QLatin1String( "Tiles" ) )
381  {
382  urlFound = layerStruct.xyzURL = linkMap.value( QStringLiteral( "url" ) ).toString();
383  }
384  }
385  }
386 
387  switch ( layerStruct.server )
388  {
391  break;
392 
394  {
395  layerStruct.server = urlFound.contains( QStringLiteral( "qgis-server" ) ) ? QgsGeoNodeRequest::BackendServer::QgisServer : QgsGeoNodeRequest::BackendServer::Geoserver;
396  break;
397  }
398  }
399  }
400 
401  return layerStruct;
402 }
403 
404 QgsGeoNodeStyle QgsGeoNodeRequest::retrieveStyle( const QString &styleUrl )
405 {
406  QgsGeoNodeStyle geoNodeStyle;
407 
408  bool success = requestBlocking( styleUrl );
409  if ( !success )
410  {
411  return geoNodeStyle;
412  }
413  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
414  const QJsonObject jsonObject = jsonDocument.object();
415 
416  const QVariantMap jsonMap = jsonObject.toVariantMap();
417  geoNodeStyle.id = jsonMap.value( QStringLiteral( "id" ) ).toString();
418  geoNodeStyle.name = jsonMap.value( QStringLiteral( "name" ) ).toString();
419  geoNodeStyle.title = jsonMap.value( QStringLiteral( "title" ) ).toString();
420  geoNodeStyle.styleUrl = jsonMap.value( QStringLiteral( "style_url" ) ).toString();
421 
422  success = requestBlocking( geoNodeStyle.styleUrl );
423  if ( !success )
424  {
425  return geoNodeStyle;
426  }
427 
428  success = geoNodeStyle.body.setContent( this->lastResponse() );
429  if ( !success )
430  {
431  return geoNodeStyle;
432  }
433 
434  return geoNodeStyle;
435 }
436 
437 QStringList QgsGeoNodeRequest::fetchServiceUrlsBlocking( const QString &serviceType )
438 {
439  QStringList urls;
440 
441  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
442 
443  if ( layers.empty() )
444  {
445  return urls;
446  }
447 
448  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
449  {
450  QString url;
451  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
452  {
453  url = layer.wmsURL;
454  }
455  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
456  {
457  url = layer.wfsURL;
458  }
459  else if ( QString::compare( serviceType, QStringLiteral( "wcs" ), Qt::CaseInsensitive ) == 0 )
460  {
461  url = layer.wcsURL;
462  }
463  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
464  {
465  url = layer.xyzURL;
466  }
467 
468  if ( url.isEmpty() )
469  continue;
470 
471  if ( !url.contains( QLatin1String( "://" ) ) )
472  {
473  url.prepend( protocol() );
474  }
475  if ( !urls.contains( url ) )
476  {
477  urls.append( url );
478  }
479  }
480 
481  return urls;
482 }
483 
485 {
486  QgsStringMap urls;
487 
488  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
489 
490  if ( layers.empty() )
491  {
492  return urls;
493  }
494 
495  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
496  {
497  QString url;
498 
499  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
500  {
501  url = layer.wmsURL;
502  }
503  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
504  {
505  url = layer.wfsURL;
506  }
507  else if ( QString::compare( serviceType, QStringLiteral( "wcs" ), Qt::CaseInsensitive ) == 0 )
508  {
509  url = layer.wcsURL;
510  }
511  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
512  {
513  url = layer.xyzURL;
514  }
515 
516  if ( url.isEmpty() )
517  continue;
518 
519  QString layerName = layer.name;
520  if ( !url.contains( QLatin1String( "://" ) ) )
521  {
522  url.prepend( protocol() );
523  }
524  if ( !urls.contains( url ) )
525  {
526  urls.insert( layerName, url );
527  }
528  }
529 
530  return urls;
531 }
532 
533 void QgsGeoNodeRequest::request( const QString &endPoint )
534 {
535  abort();
536  mIsAborted = false;
537  // Handle case where the endpoint is full url
538  QString url = endPoint.startsWith( mBaseUrl ) ? endPoint : mBaseUrl + endPoint;
539  QgsDebugMsgLevel( "Requesting to " + url, 2 );
540  setProtocol( url.split( QStringLiteral( "://" ) ).at( 0 ) );
541  QUrl layerUrl( url );
542  layerUrl.setScheme( protocol() );
543 
544  mError.clear();
545 
546  mGeoNodeReply = requestUrl( url );
547  connect( mGeoNodeReply, &QNetworkReply::finished, this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
548  connect( mGeoNodeReply, &QNetworkReply::downloadProgress, this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
549 }
550 
551 bool QgsGeoNodeRequest::requestBlocking( const QString &endPoint )
552 {
553  QEventLoop loop;
554  connect( this, &QgsGeoNodeRequest::requestFinished, &loop, &QEventLoop::quit );
555 
556  request( endPoint );
557  loop.exec( QEventLoop::ExcludeUserInputEvents );
558 
559  return mError.isEmpty();
560 }
561 
562 QNetworkReply *QgsGeoNodeRequest::requestUrl( const QString &url )
563 {
564  QNetworkRequest request( url );
565  request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, 1 );
566 
567  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) );
568  // Add authentication check here
569 
570  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
571  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
572 
574 }
575 
576 
void layersFetched(const QList< QgsGeoNodeRequest::ServiceLayerDetail > &layers)
Emitted when the result of a fetchLayers call has been received and processed.
bool requestBlocking(const QString &endPoint)
Triggers a new request to the GeoNode server, with the requested endPoint.
QgsGeoNodeRequest(const QString &baseUrl, bool forceRefresh, QObject *parent=nullptr)
Constructor for QgsGeoNodeRequest.
void requestFinished()
Emitted when the existing request has been completed.
QList< QgsGeoNodeStyle > fetchStylesBlocking(const QString &layerName)
Requests the list of available styles for the layer with matching layerName from the server.
@ Geoserver
Geoserver used as backend.
@ QgisServer
QGIS server used as backend.
void fetchLayers()
Triggers a new request to fetch the list of available layers from the server.
QgsGeoNodeStyle fetchStyleBlocking(const QString &styleId)
Requests the details for the style with matching styleId from the server.
QList< QgsGeoNodeRequest::ServiceLayerDetail > fetchLayersBlocking()
Requests the list of available layers from the server.
QgsGeoNodeStyle fetchDefaultStyleBlocking(const QString &layerName)
Requests the default style for the layer with matching layerName from the server.
QStringList fetchServiceUrlsBlocking(const QString &serviceType)
Requests the list of unique URLs for available services with matching serviceType from the server.
QgsGeoNodeRequest::ServiceLayerDetail parseOwsUrl(QgsGeoNodeRequest::ServiceLayerDetail &layerStruct, const QVariantList &layerLinks)
Returns the updated ServiceLayerDetail struct with WMS/WFS/XYZ url.
QgsStringMap fetchServiceUrlDataBlocking(const QString &serviceType)
Obtains a map of layer name to URL for available services with matching serviceType from the server.
void statusChanged(const QString &statusQString)
Emitted when the status of an ongoing request is changed.
QString protocol() const
Returns the network protocol (e.g.
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.
void abort()
Aborts any active network request immediately.
void setProtocol(const QString &protocol)
Sets the network protocol (e.g.
~QgsGeoNodeRequest() override
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
network access manager for QGIS
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2026
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)
Service layer details for an individual layer from a GeoNode connection.
QString xyzURL
XYZ tileserver URL for layer.
BackendServer server
Backend server (geoserver or qgis-server)
QUuid uuid
Unique identifier (generate on the client side, not at the GeoNode server)
Encapsulates information about a GeoNode layer style.
QString id
Unique style ID.
QString styleUrl
Associated URL.
QDomDocument body
DOM documenting containing style.
QString name
Style name.
QString title
Style title.