From 0ae511f1bd43ac2365782dfea7e2041c305621cc Mon Sep 17 00:00:00 2001 From: myarjunar Date: Sun, 20 Oct 2019 21:23:54 +0700 Subject: [PATCH] [geonode] a generic way to consume geonode api. fixes #31376 --- src/core/geocms/geonode/qgsgeonoderequest.cpp | 177 +++++++++--------- src/core/geocms/geonode/qgsgeonoderequest.h | 9 + 2 files changed, 96 insertions(+), 90 deletions(-) diff --git a/src/core/geocms/geonode/qgsgeonoderequest.cpp b/src/core/geocms/geonode/qgsgeonoderequest.cpp index dd0457f0a02..444a2fb51f6 100644 --- a/src/core/geocms/geonode/qgsgeonoderequest.cpp +++ b/src/core/geocms/geonode/qgsgeonoderequest.cpp @@ -269,113 +269,108 @@ QList QgsGeoNodeRequest::parseLayers( con const QJsonObject jsonObject = jsonDocument.object(); const QVariantMap jsonVariantMap = jsonObject.toVariantMap(); const QVariantList layerList = jsonVariantMap.value( QStringLiteral( "objects" ) ).toList(); - qint16 majorVersion; - qint16 minorVersion; - if ( jsonVariantMap.contains( QStringLiteral( "geonode_version" ) ) ) + + QString wmsURLFormat, wfsURLFormat, xyzURLFormat; + + for ( const QVariant &layer : qgis::as_const( layerList ) ) { - QRegularExpression re( "((\\d+)(\\.\\d+))" ); - QRegularExpressionMatch match = re.match( jsonVariantMap.value( QStringLiteral( "geonode_version" ) ).toString() ); - if ( match.hasMatch() ) + QgsGeoNodeRequest::ServiceLayerDetail layerStruct; + const QVariantMap layerMap = layer.toMap(); + QVariantList layerLinks = layerMap.value( QStringLiteral( "links" ) ).toList(); + + if ( layerMap.value( QStringLiteral( "typename" ) ).toString().isEmpty() ) { - const QStringList geonodeVersionSplit = match.captured( 0 ).split( '.' ); - majorVersion = geonodeVersionSplit.at( 0 ).toInt(); - minorVersion = geonodeVersionSplit.at( 1 ).toInt(); + const QStringList splitURL = layerMap.value( QStringLiteral( "detail_url" ) ).toString().split( '/' ); + layerStruct.typeName = splitURL.at( splitURL.length() - 1 ); } - else + layerStruct.uuid = layerMap.value( QStringLiteral( "uuid" ) ).toString(); + layerStruct.id = layerMap.value( QStringLiteral( "id" ) ).toString(); + layerStruct.name = layerMap.value( QStringLiteral( "name" ) ).toString(); + layerStruct.typeName = layerMap.value( QStringLiteral( "typename" ) ).toString(); + layerStruct.title = layerMap.value( QStringLiteral( "title" ) ).toString(); + + layerStruct = parseOWSUrl( layerStruct, layerLinks ); + + if ( layerStruct.wmsURL.isEmpty() && layerStruct.wfsURL.isEmpty() && layerStruct.xyzURL.isEmpty() ) { - return layers; - } - } - else - { - majorVersion = 2; - minorVersion = 6; - } - - if ( majorVersion == 2 && minorVersion == 6 ) - { - for ( const QVariant &layer : qgis::as_const( layerList ) ) - { - QgsGeoNodeRequest::ServiceLayerDetail layerStruct; - const QVariantMap layerMap = layer.toMap(); - // Find WMS and WFS. XYZ is not available - // Trick to get layer's typename from distribution_url or detail_url - QString layerTypeName = layerMap.value( QStringLiteral( "detail_url" ) ).toString().split( '/' ).last(); - if ( layerTypeName.isEmpty() ) + if ( wmsURLFormat.isEmpty() && wfsURLFormat.isEmpty() && xyzURLFormat.isEmpty() ) { - layerTypeName = layerMap.value( QStringLiteral( "distribution_url" ) ).toString().split( '/' ).last(); - } - // On this step, layerTypeName is in WORKSPACE%3ALAYERNAME or WORKSPACE:LAYERNAME format - if ( layerTypeName.contains( QStringLiteral( "%3A" ) ) ) - { - layerTypeName.replace( QStringLiteral( "%3A" ), QStringLiteral( ":" ) ); - } - // On this step, layerTypeName is in WORKSPACE:LAYERNAME format - const QStringList splitURL = layerTypeName.split( ':' ); - QString layerWorkspace = splitURL.at( 0 ); - QString layerName = splitURL.at( 1 ); - - layerStruct.name = layerName; - layerStruct.typeName = layerTypeName; - layerStruct.uuid = layerMap.value( QStringLiteral( "uuid" ) ).toString(); - layerStruct.title = layerMap.value( QStringLiteral( "title" ) ).toString(); - - // WMS url : BASE_URI/geoserver/WORKSPACE/wms - layerStruct.wmsURL = mBaseUrl + QStringLiteral( "/geoserver/" ) + layerWorkspace + QStringLiteral( "/wms" ); - // WFS url : BASE_URI/geoserver/WORKSPACE/wfs - layerStruct.wfsURL = mBaseUrl + QStringLiteral( "/geoserver/" ) + layerWorkspace + QStringLiteral( "/wfs" ); - // XYZ url : set to empty string - layerStruct.xyzURL.clear(); - - layers.append( layerStruct ); - } - } - // Geonode version 2.7 or newer - else if ( ( majorVersion == 2 && minorVersion >= 7 ) || ( majorVersion >= 3 ) ) - { - for ( const QVariant &layer : qgis::as_const( layerList ) ) - { - QgsGeoNodeRequest::ServiceLayerDetail layerStruct; - const QVariantMap layerMap = layer.toMap(); - // Find WMS, WFS, and XYZ link - const QVariantList layerLinks = layerMap.value( QStringLiteral( "links" ) ).toList(); - for ( const QVariant &link : layerLinks ) - { - const QVariantMap linkMap = link.toMap(); - if ( linkMap.contains( QStringLiteral( "link_type" ) ) ) + bool success = requestBlocking( QStringLiteral( "/api/layers/" ) + layerStruct.id ); + if ( success ) { - if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WMS" ) ) + const QJsonDocument resourceUriDocument = QJsonDocument::fromJson( this->lastResponse() ); + const QJsonObject resourceUriObject = resourceUriDocument.object(); + const QVariantMap resourceUriMap = resourceUriObject.toVariantMap(); + QVariantList resourceUriLinks = resourceUriMap.value( QStringLiteral( "links" ) ).toList(); + QgsGeoNodeRequest::ServiceLayerDetail tempLayerStruct; + tempLayerStruct = parseOWSUrl( tempLayerStruct, resourceUriLinks ); + + // Avoid iterating all the layers to get the service url. Instead, generate a string format once we found one service url + // for every service (wms, wfs, xyz). And then use the string format for the other layers since they are identical. + if ( tempLayerStruct.server == "qgis-server" ) { - layerStruct.wmsURL = linkMap.value( QStringLiteral( "url" ) ).toString(); + wmsURLFormat = !tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL.replace( layerStruct.name, "%1" ) : ""; + wfsURLFormat = !tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL.replace( layerStruct.name, "%1" ) : ""; + xyzURLFormat = !tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, "%1" ) : ""; } - else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WFS" ) ) + else if ( tempLayerStruct.server == "geoserver" ) { - layerStruct.wfsURL = linkMap.value( QStringLiteral( "url" ) ).toString(); - } - else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "image" ) ) - { - if ( linkMap.contains( QStringLiteral( "name" ) ) && linkMap.value( QStringLiteral( "name" ) ) == QStringLiteral( "Tiles" ) ) - { - layerStruct.xyzURL = linkMap.value( QStringLiteral( "url" ) ).toString(); - } + wmsURLFormat = !tempLayerStruct.wmsURL.isEmpty() ? tempLayerStruct.wmsURL : ""; + wfsURLFormat = !tempLayerStruct.wfsURL.isEmpty() ? tempLayerStruct.wfsURL : ""; + xyzURLFormat = !tempLayerStruct.xyzURL.isEmpty() ? tempLayerStruct.xyzURL.replace( layerStruct.name, "%1" ) : ""; } } + else + { + layers.append( layerStruct ); + continue; + } } - if ( layerMap.value( QStringLiteral( "typename" ) ).toString().isEmpty() ) - { - const QStringList splitURL = layerMap.value( QStringLiteral( "detail_url" ) ).toString().split( '/' ); - layerStruct.typeName = splitURL.at( splitURL.length() - 1 ); - } - layerStruct.uuid = layerMap.value( QStringLiteral( "uuid" ) ).toString(); - layerStruct.name = layerMap.value( QStringLiteral( "name" ) ).toString(); - layerStruct.typeName = layerMap.value( QStringLiteral( "typename" ) ).toString(); - layerStruct.title = layerMap.value( QStringLiteral( "title" ) ).toString(); - layers.append( layerStruct ); + + // Replace string argument with the layer id. + layerStruct.wmsURL = wmsURLFormat.contains( "%1" ) ? wmsURLFormat.arg( layerStruct.name ) : wmsURLFormat; + layerStruct.wfsURL = wfsURLFormat.contains( "%1" ) ? wfsURLFormat.arg( layerStruct.name ) : wfsURLFormat; + layerStruct.xyzURL = xyzURLFormat.contains( "%1" ) ? xyzURLFormat.arg( layerStruct.name ) : xyzURLFormat; } + + layers.append( layerStruct ); } + return layers; } +QgsGeoNodeRequest::ServiceLayerDetail QgsGeoNodeRequest::parseOWSUrl( QgsGeoNodeRequest::ServiceLayerDetail &layerStruct, const QVariantList &layerLinks ) +{ + QString urlFound; + for ( const QVariant &link : layerLinks ) + { + const QVariantMap linkMap = link.toMap(); + if ( linkMap.contains( QStringLiteral( "link_type" ) ) ) + { + if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WMS" ) ) + { + urlFound = layerStruct.wmsURL = linkMap.value( QStringLiteral( "url" ) ).toString(); + } + else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "OGC:WFS" ) ) + { + urlFound = layerStruct.wfsURL = linkMap.value( QStringLiteral( "url" ) ).toString(); + } + else if ( linkMap.value( QStringLiteral( "link_type" ) ) == QStringLiteral( "image" ) ) + { + if ( linkMap.contains( QStringLiteral( "name" ) ) && linkMap.value( QStringLiteral( "name" ) ) == QStringLiteral( "Tiles" ) ) + { + urlFound = layerStruct.xyzURL = linkMap.value( QStringLiteral( "url" ) ).toString(); + } + } + } + + if ( layerStruct.server.isEmpty() ) + layerStruct.server = urlFound.contains( QStringLiteral( "qgis-server" ) ) ? QStringLiteral( "qgis-server" ) : QStringLiteral( "geoserver" ); + } + + return layerStruct; +} + QgsGeoNodeStyle QgsGeoNodeRequest::retrieveStyle( const QString &styleUrl ) { QgsGeoNodeStyle geoNodeStyle; @@ -529,6 +524,8 @@ bool QgsGeoNodeRequest::requestBlocking( const QString &endPoint ) QNetworkReply *QgsGeoNodeRequest::requestUrl( const QString &url ) { QNetworkRequest request( url ); + request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true ); + QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsGeoNodeRequest" ) ); // Add authentication check here diff --git a/src/core/geocms/geonode/qgsgeonoderequest.h b/src/core/geocms/geonode/qgsgeonoderequest.h index b6503b50935..702b14b35c1 100644 --- a/src/core/geocms/geonode/qgsgeonoderequest.h +++ b/src/core/geocms/geonode/qgsgeonoderequest.h @@ -74,6 +74,8 @@ class CORE_EXPORT QgsGeoNodeRequest : public QObject { //! Unique identifier (generate on the client side, not at the GeoNode server) QUuid uuid; + //! Layer id + QString id; //! Layer name QString name; //! Layer type name @@ -86,6 +88,8 @@ class CORE_EXPORT QgsGeoNodeRequest : public QObject QString wfsURL; //! XYZ tileserver URL for layer QString xyzURL; + //! Backend server (geoserver or qgis-server) + QString server; }; /** @@ -213,6 +217,11 @@ class CORE_EXPORT QgsGeoNodeRequest : public QObject */ void setProtocol( const QString &protocol ); + /** + * Returns the updated ServiceLayerDetail struct with WMS/WFS/XYZ url. + */ + QgsGeoNodeRequest::ServiceLayerDetail parseOWSUrl( QgsGeoNodeRequest::ServiceLayerDetail &layerStruct, const QVariantList &layerLinks ); + public slots: /**