QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
160 void QgsGeoNodeRequest::setProtocol( const QString &protocol )
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, wcsURLFormat, xyzURLFormat;
274 
275  for ( const QVariant &layer : std::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 = QUuid( 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() && wcsURLFormat.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.wcsURL.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, wcs, 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  wcsURLFormat = ! tempLayerStruct.wcsURL.isEmpty() ? tempLayerStruct.wcsURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
318  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
319  break;
320  }
322  {
323  wmsURLFormat = ! tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL : QString();
324  wfsURLFormat = ! tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL : QString();
325  wcsURLFormat = ! tempLayerStruct.wcsURL.isEmpty() ? tempLayerStruct.wcsURL : QString();
326  xyzURLFormat = ! tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, QStringLiteral( "%1" ) ) : QString();
327  break;
328  }
330  break;
331  }
332  }
333  else
334  continue;
335  }
336  else
337  {
338  // Replace string argument with the layer id.
339  layerStruct.wmsURL = wmsURLFormat.contains( "%1" ) ? wmsURLFormat.arg( layerStruct.name ) : wmsURLFormat;
340  layerStruct.wfsURL = wfsURLFormat.contains( "%1" ) ? wfsURLFormat.arg( layerStruct.name ) : wfsURLFormat;
341  layerStruct.wcsURL = wcsURLFormat.contains( "%1" ) ? wcsURLFormat.arg( layerStruct.name ) : wcsURLFormat;
342  layerStruct.xyzURL = xyzURLFormat.contains( "%1" ) ? xyzURLFormat.arg( layerStruct.name ) : xyzURLFormat;
343  }
344  }
345  else
346  layerStruct = parseOwsUrl( layerStruct, layerLinks );
347 
348  layers.append( layerStruct );
349  }
350 
351  return layers;
352 }
353 
355 {
356  QString urlFound;
357  for ( const QVariant &link : layerLinks )
358  {
359  const QVariantMap linkMap = link.toMap();
360  if ( linkMap.contains( QStringLiteral( "link_type" ) ) )
361  {
362  if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WMS" ) )
363  {
364  urlFound = layerStruct.wmsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
365  }
366  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WFS" ) )
367  {
368  urlFound = layerStruct.wfsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
369  }
370  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "OGC:WCS" ) )
371  {
372  urlFound = layerStruct.wcsURL = linkMap.value( QStringLiteral( "url" ) ).toString();
373  }
374  else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QLatin1String( "image" ) )
375  {
376  if ( linkMap.contains( QStringLiteral( "name" ) ) && linkMap.value( QStringLiteral( "name" ) ) == QLatin1String( "Tiles" ) )
377  {
378  urlFound = layerStruct.xyzURL = linkMap.value( QStringLiteral( "url" ) ).toString();
379  }
380  }
381  }
382 
383  switch ( layerStruct.server )
384  {
387  break;
388 
390  {
391  layerStruct.server = urlFound.contains( QStringLiteral( "qgis-server" ) ) ? QgsGeoNodeRequest::BackendServer::QgisServer : QgsGeoNodeRequest::BackendServer::Geoserver;
392  break;
393  }
394  }
395  }
396 
397  return layerStruct;
398 }
399 
400 QgsGeoNodeStyle QgsGeoNodeRequest::retrieveStyle( const QString &styleUrl )
401 {
402  QgsGeoNodeStyle geoNodeStyle;
403 
404  bool success = requestBlocking( styleUrl );
405  if ( !success )
406  {
407  return geoNodeStyle;
408  }
409  const QJsonDocument jsonDocument = QJsonDocument::fromJson( this->lastResponse() );
410  const QJsonObject jsonObject = jsonDocument.object();
411 
412  const QVariantMap jsonMap = jsonObject.toVariantMap();
413  geoNodeStyle.id = jsonMap.value( QStringLiteral( "id" ) ).toString();
414  geoNodeStyle.name = jsonMap.value( QStringLiteral( "name" ) ).toString();
415  geoNodeStyle.title = jsonMap.value( QStringLiteral( "title" ) ).toString();
416  geoNodeStyle.styleUrl = jsonMap.value( QStringLiteral( "style_url" ) ).toString();
417 
418  success = requestBlocking( geoNodeStyle.styleUrl );
419  if ( !success )
420  {
421  return geoNodeStyle;
422  }
423 
424  success = geoNodeStyle.body.setContent( this->lastResponse() );
425  if ( !success )
426  {
427  return geoNodeStyle;
428  }
429 
430  return geoNodeStyle;
431 }
432 
433 QStringList QgsGeoNodeRequest::fetchServiceUrlsBlocking( const QString &serviceType )
434 {
435  QStringList urls;
436 
437  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
438 
439  if ( layers.empty() )
440  {
441  return urls;
442  }
443 
444  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
445  {
446  QString url;
447  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
448  {
449  url = layer.wmsURL;
450  }
451  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
452  {
453  url = layer.wfsURL;
454  }
455  else if ( QString::compare( serviceType, QStringLiteral( "wcs" ), Qt::CaseInsensitive ) == 0 )
456  {
457  url = layer.wcsURL;
458  }
459  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
460  {
461  url = layer.xyzURL;
462  }
463 
464  if ( url.isEmpty() )
465  continue;
466 
467  if ( !url.contains( QLatin1String( "://" ) ) )
468  {
469  url.prepend( protocol() );
470  }
471  if ( !urls.contains( url ) )
472  {
473  urls.append( url );
474  }
475  }
476 
477  return urls;
478 }
479 
481 {
482  QgsStringMap urls;
483 
484  const QList<QgsGeoNodeRequest::ServiceLayerDetail> layers = fetchLayersBlocking();
485 
486  if ( layers.empty() )
487  {
488  return urls;
489  }
490 
491  for ( const QgsGeoNodeRequest::ServiceLayerDetail &layer : layers )
492  {
493  QString url;
494 
495  if ( QString::compare( serviceType, QStringLiteral( "wms" ), Qt::CaseInsensitive ) == 0 )
496  {
497  url = layer.wmsURL;
498  }
499  else if ( QString::compare( serviceType, QStringLiteral( "wfs" ), Qt::CaseInsensitive ) == 0 )
500  {
501  url = layer.wfsURL;
502  }
503  else if ( QString::compare( serviceType, QStringLiteral( "wcs" ), Qt::CaseInsensitive ) == 0 )
504  {
505  url = layer.wcsURL;
506  }
507  else if ( QString::compare( serviceType, QStringLiteral( "xyz" ), Qt::CaseInsensitive ) == 0 )
508  {
509  url = layer.xyzURL;
510  }
511 
512  if ( url.isEmpty() )
513  continue;
514 
515  QString layerName = layer.name;
516  if ( !url.contains( QLatin1String( "://" ) ) )
517  {
518  url.prepend( protocol() );
519  }
520  if ( !urls.contains( url ) )
521  {
522  urls.insert( layerName, url );
523  }
524  }
525 
526  return urls;
527 }
528 
529 void QgsGeoNodeRequest::request( const QString &endPoint )
530 {
531  abort();
532  mIsAborted = false;
533  // Handle case where the endpoint is full url
534  QString url = endPoint.startsWith( mBaseUrl ) ? endPoint : mBaseUrl + endPoint;
535  QgsDebugMsgLevel( "Requesting to " + url, 2 );
536  setProtocol( url.split( QStringLiteral( "://" ) ).at( 0 ) );
537  QUrl layerUrl( url );
538  layerUrl.setScheme( protocol() );
539 
540  mError.clear();
541 
542  mGeoNodeReply = requestUrl( url );
543  connect( mGeoNodeReply, &QNetworkReply::finished, this, &QgsGeoNodeRequest::replyFinished, Qt::DirectConnection );
544  connect( mGeoNodeReply, &QNetworkReply::downloadProgress, this, &QgsGeoNodeRequest::replyProgress, Qt::DirectConnection );
545 }
546 
547 bool QgsGeoNodeRequest::requestBlocking( const QString &endPoint )
548 {
549  request( endPoint );
550 
551  QEventLoop loop;
552  connect( this, &QgsGeoNodeRequest::requestFinished, &loop, &QEventLoop::quit );
553  loop.exec( QEventLoop::ExcludeUserInputEvents );
554 
555  return mError.isEmpty();
556 }
557 
558 QNetworkReply *QgsGeoNodeRequest::requestUrl( const QString &url )
559 {
560  QNetworkRequest request( url );
561  request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, 1 );
562 
563  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) );
564  // Add authentication check here
565 
566  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
567  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
568 
570 }
571 
572 
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.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:1041
#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.