Skip to content

Commit

Permalink
[Server] Handle bad layers at QGIS project laoding and throw exception
Browse files Browse the repository at this point in the history
This commit return exceptions if a layer is not available like other servers (e.g. UMN) and prevents caching of projects with missing datasources (a datasource may become available later on).
  • Loading branch information
rldhont committed May 20, 2019
1 parent bfe746d commit 10db307
Show file tree
Hide file tree
Showing 8 changed files with 2,110 additions and 1 deletion.
51 changes: 51 additions & 0 deletions python/server/auto_generated/qgsstorebadlayerinfo.sip.in
@@ -0,0 +1,51 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsstorebadlayerinfo.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsStoreBadLayerInfo: QgsProjectBadLayerHandler
{
%Docstring
Stores layer ids of bad layers

.. versionadded:: 3.4.8
%End

%TypeHeaderCode
#include "qgsstorebadlayerinfo.h"
%End
public:

QgsStoreBadLayerInfo();
%Docstring
Default constructor
%End

void handleBadLayers( const QList<QDomNode> &layers );
%Docstring
handleBadLayers

:param layers: layer nodes
%End

QStringList badLayers() const;
%Docstring
badLayers

:return: ids of bad layers
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsstorebadlayerinfo.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/server/server_auto.sip
Expand Up @@ -22,6 +22,7 @@
%Include auto_generated/qgsserviceregistry.sip
%Include auto_generated/qgsfeaturefilterprovidergroup.sip
%Include auto_generated/qgsfeaturefilter.sip
%Include auto_generated/qgsstorebadlayerinfo.sip
%If ( HAVE_SERVER_PYTHON_PLUGINS )
%Include auto_generated/qgsserverfilter.sip
%End
Expand Down
1 change: 1 addition & 0 deletions src/server/CMakeLists.txt
Expand Up @@ -40,6 +40,7 @@ SET(QGIS_SERVER_SRCS
qgsserviceregistry.cpp
qgsfeaturefilterprovidergroup.cpp
qgsfeaturefilter.cpp
qgsstorebadlayerinfo.cpp
)

SET (QGIS_SERVER_HDRS
Expand Down
11 changes: 10 additions & 1 deletion src/server/qgsconfigcache.cpp
Expand Up @@ -17,7 +17,8 @@

#include "qgsconfigcache.h"
#include "qgsmessagelog.h"
#include "qgsaccesscontrol.h"
#include "qgsserverexception.h"
#include "qgsstorebadlayerinfo.h"

#include <QFile>

Expand All @@ -41,8 +42,16 @@ const QgsProject *QgsConfigCache::project( const QString &path )
if ( ! mProjectCache[ path ] )
{
std::unique_ptr<QgsProject> prj( new QgsProject() );
QgsStoreBadLayerInfo *badLayerHandler = new QgsStoreBadLayerInfo();
prj->setBadLayerHandler( badLayerHandler );
if ( prj->read( path ) )
{
if ( !badLayerHandler->badLayers().isEmpty() )
{
QString errorMsg = QStringLiteral( "Layer(s) %1 not valid" ).arg( badLayerHandler->badLayers().join( ',' ) );
QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), Qgis::Critical );
throw QgsServerException( QStringLiteral( "Layer(s) not valid" ) );
}
mProjectCache.insert( path, prj.release() );
mFileSystemWatcher.addPath( path );
}
Expand Down
36 changes: 36 additions & 0 deletions src/server/qgsstorebadlayerinfo.cpp
@@ -0,0 +1,36 @@
/***************************************************************************
qgsstorebadlayerinfo.cpp
------------------------
begin : Jan 2019
copyright : (C) 2019 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsstorebadlayerinfo.h"
#include <QDomElement>

void QgsStoreBadLayerInfo::handleBadLayers( const QList<QDomNode> &layers )
{
mBadLayerIds.clear();
QList<QDomNode>::const_iterator it = layers.constBegin();
for ( ; it != layers.constEnd(); ++it )
{
if ( !it->isNull() )
{
QDomElement idElem = it->firstChildElement( "id" );
if ( !idElem.isNull() )
{
mBadLayerIds.append( idElem.text() );
}
}
}
}
47 changes: 47 additions & 0 deletions src/server/qgsstorebadlayerinfo.h
@@ -0,0 +1,47 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSSTOREBADLAYERINFO_H
#define QGSSTOREBADLAYERINFO_H

#include "qgsprojectbadlayerhandler.h"
#include "qgis_server.h"
#include <QStringList>

/**
* \ingroup server
* Stores layer ids of bad layers
* \since QGIS 3.4.8
*/
class SERVER_EXPORT QgsStoreBadLayerInfo: public QgsProjectBadLayerHandler
{
public:

/**
* Default constructor
*/
QgsStoreBadLayerInfo() = default;

/**
* \brief handleBadLayers
* \param layers layer nodes
*/
void handleBadLayers( const QList<QDomNode> &layers );

/**
* \brief badLayers
* \returns ids of bad layers
*/
QStringList badLayers() const { return mBadLayerIds; }

private:
QStringList mBadLayerIds;
};

#endif // QGSSTOREBADLAYERINFO_H
23 changes: 23 additions & 0 deletions tests/src/python/test_qgsserver_wms_getmap.py
Expand Up @@ -1427,6 +1427,29 @@ def test_wms_getmap_group_regression_20810(self):
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetMap_GroupedLayersDown")

def test_wms_getmap_datasource_error(self):
"""Must throw a server exception if datasource if not available"""
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(os.path.join(self.testdata_path, 'test_project_wms_invalid_layers.qgs')),
"SERVICE": "WMS",
"VERSION": "1.3.0",
"REQUEST": "GetMap",
"BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259",
"CRS": "EPSG:25832",
"WIDTH": "429",
"HEIGHT": "337",
"LAYERS": "areas and symbols,osm",
"STYLES": ",",
"FORMAT": "image/png",
"DPI": "200",
"MAP_RESOLUTION": "200",
"FORMAT_OPTIONS": "dpi:200"
}.items())])

r, h = self._result(self._execute_request(qs))

self.assertTrue('ServerException' in str(r))

def test_wms_getmap_root_custom_layer_order_regression_21917(self):
"""When drawing root layer, custom layer order order should be respected."""

Expand Down

0 comments on commit 10db307

Please sign in to comment.