Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #41823 from elpaso/bugfix-gh41800-server-geprint-a…
…ccesscontrol

Server WMS GetPrint accesscontrol support
  • Loading branch information
elpaso authored and github-actions[bot] committed Mar 2, 2021
1 parent da9a255 commit 71b0977
Show file tree
Hide file tree
Showing 31 changed files with 1,992 additions and 21 deletions.
20 changes: 20 additions & 0 deletions python/core/auto_generated/layout/qgslayoutrendercontext.sip.in
Expand Up @@ -311,6 +311,26 @@ Returns the current list of predefined scales for use with the layout.
.. seealso:: :py:func:`setPredefinedScales`

.. versionadded:: 3.10
%End

QgsFeatureFilterProvider *featureFilterProvider() const;
%Docstring
Returns the possibly NULL feature filter provider.

A feature filter provider for filtering visible features or attributes.
It is currently used by QGIS Server Access Control Plugins.

.. versionadded:: 3.18
%End

void setFeatureFilterProvider( QgsFeatureFilterProvider *featureFilterProvider );
%Docstring
Sets feature filter provider to ``featureFilterProvider``.

A feature filter provider for filtering visible features or attributes.
It is currently used by QGIS Server Access Control Plugins.

.. versionadded:: 3.18
%End

signals:
Expand Down
11 changes: 9 additions & 2 deletions python/core/auto_generated/qgsfeaturefilterprovider.sip.in
Expand Up @@ -16,10 +16,10 @@
class QgsFeatureFilterProvider
{
%Docstring
Abstract interface for use by classes that filter the features of a layer.
Abstract interface for use by classes that filter the features or attributes of a layer.

A :py:class:`QgsFeatureFilterProvider` provides a method for modifying a :py:class:`QgsFeatureRequest` in place to apply
additional filters to the request.
additional filters to the request, since QGIS 3.18 a method to filter allowed attributes is also available.

.. versionadded:: 2.14
%End
Expand All @@ -37,6 +37,13 @@ Derived classes must implement this method.

:param layer: the layer to filter
:param featureRequest: the feature request to update
%End

virtual QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const = 0;
%Docstring
Returns the list of visible attribute names from a list of ``attributes`` names for the given ``layer``

.. versionadded:: 3.18
%End

virtual QgsFeatureFilterProvider *clone() const = 0 /Factory/;
Expand Down
3 changes: 2 additions & 1 deletion python/server/auto_generated/qgsaccesscontrol.sip.in
Expand Up @@ -108,7 +108,8 @@ Returns the layer delete right
:return: ``True`` if we can do a delete
%End

QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const;
virtual QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const;

%Docstring
Returns the authorized layer attributes

Expand Down
3 changes: 3 additions & 0 deletions python/server/auto_generated/qgsfeaturefilter.sip.in
Expand Up @@ -37,6 +37,9 @@ Filter the features of the layer
:param filterFeatures: the request to fill
%End

virtual QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const;


virtual QgsFeatureFilterProvider *clone() const /Factory/;

%Docstring
Expand Down
Expand Up @@ -30,12 +30,15 @@ Constructor
virtual void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const;

%Docstring
Filter the features of the layer
Filter the features of the layer.

:param layer: the layer to control
:param filterFeatures: the request to fill
%End

virtual QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const;


virtual QgsFeatureFilterProvider *clone() const /Factory/;

%Docstring
Expand All @@ -53,6 +56,7 @@ Add another filter provider to the group
:return: itself
%End


};

/************************************************************************
Expand Down
7 changes: 7 additions & 0 deletions src/core/layout/qgslayoutatlas.cpp
Expand Up @@ -288,6 +288,13 @@ int QgsLayoutAtlas::updateFeatures()
req.setFilterExpression( mFilterExpression );
}

#ifdef HAVE_SERVER_PYTHON_PLUGINS
if ( mLayout->renderContext().featureFilterProvider() )
{
mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.get(), req );
}
#endif

QgsFeatureIterator fit = mCoverageLayer->getFeatures( req );

std::unique_ptr<QgsExpression> nameExpression;
Expand Down
75 changes: 74 additions & 1 deletion src/core/layout/qgslayoutitemattributetable.cpp
Expand Up @@ -29,6 +29,7 @@
#include "qgsexception.h"
#include "qgsmapsettings.h"
#include "qgsexpressioncontextutils.h"
#include "qgsexpressionnodeimpl.h"
#include "qgsgeometryengine.h"
#include "qgsconditionalstyle.h"

Expand Down Expand Up @@ -176,6 +177,7 @@ void QgsLayoutItemAttributeTable::resetColumns()
//rebuild columns list from vector layer fields
int idx = 0;
const QgsFields sourceFields = source->fields();

for ( const auto &field : sourceFields )
{
QString currentAlias = source->attributeDisplayName( idx );
Expand Down Expand Up @@ -329,8 +331,9 @@ void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields,
{
int attrIdx = layerFields.lookupField( field );
if ( attrIdx < 0 )
{
continue;

}
QString currentAlias = source->attributeDisplayName( attrIdx );
QgsLayoutTableColumn col;
col.setAttribute( layerFields.at( attrIdx ).name() );
Expand Down Expand Up @@ -413,6 +416,13 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
}
}

#ifdef HAVE_SERVER_PYTHON_PLUGINS
if ( mLayout->renderContext().featureFilterProvider() )
{
mLayout->renderContext().featureFilterProvider()->filterFeatures( layer, req );
}
#endif

QgsRectangle selectionRect;
QgsGeometry visibleRegion;
std::unique_ptr< QgsGeometryEngine > visibleMapEngine;
Expand Down Expand Up @@ -541,6 +551,9 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
// We also need a list of just the cell contents, so that we can do a quick check for row uniqueness (when the
// corresponding option is enabled)
QVector< Cell > currentRow;
#ifdef HAVE_SERVER_PYTHON_PLUGINS
mColumns = filteredColumns();
#endif
currentRow.reserve( mColumns.count() );
QgsLayoutTableRow rowContents;
rowContents.reserve( mColumns.count() );
Expand Down Expand Up @@ -693,6 +706,66 @@ QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant )
return replaced;
}

#ifdef HAVE_SERVER_PYTHON_PLUGINS
QgsLayoutTableColumns QgsLayoutItemAttributeTable::filteredColumns()
{
QgsLayoutTableColumns allowedColumns { mColumns };

QgsVectorLayer *source { sourceLayer() };

if ( ! source )
{
return allowedColumns;
}

QHash<const QString, QSet<QString>> columnAttributesMap;
QSet<QString> allowedAttributes;

for ( const auto &c : qgis::as_const( allowedColumns ) )
{
if ( ! c.attribute().isEmpty() && ! columnAttributesMap.contains( c.attribute() ) )
{
columnAttributesMap[ c.attribute() ] = QSet<QString>();
const QgsExpression columnExp { c.attribute() };
const auto constRefs { columnExp.findNodes<QgsExpressionNodeColumnRef>() };
for ( const auto &cref : constRefs )
{
columnAttributesMap[ c.attribute() ].insert( cref->name() );
allowedAttributes.insert( cref->name() );
}
}
}

if ( mLayout->renderContext().featureFilterProvider() )
{
const QStringList filteredAttributes { layout()->renderContext().featureFilterProvider()->layerAttributes( source, allowedAttributes.values() ) };
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
const QSet<QString> filteredAttributesSet( filteredAttributes.constBegin(), filteredAttributes.constEnd() );
#else
const QSet<QString> filteredAttributesSet { filteredAttributes.toSet() };
#endif
if ( filteredAttributesSet != allowedAttributes )
{
const auto forbidden { allowedAttributes.subtract( filteredAttributesSet ) };
allowedColumns.erase( std::remove_if( allowedColumns.begin(), allowedColumns.end(), [ &columnAttributesMap, &forbidden ]( QgsLayoutTableColumn & c ) -> bool
{
for ( const auto &f : qgis::as_const( forbidden ) )
{
if ( columnAttributesMap[ c.attribute() ].contains( f ) )
{
return true;
}
}
return false;
} ), allowedColumns.end() );

}
}

return allowedColumns;
}
#endif

QgsVectorLayer *QgsLayoutItemAttributeTable::sourceLayer() const
{
switch ( mSource )
Expand Down
8 changes: 8 additions & 0 deletions src/core/layout/qgslayoutitemattributetable.h
Expand Up @@ -390,6 +390,14 @@ class CORE_EXPORT QgsLayoutItemAttributeTable: public QgsLayoutTable
*/
QVariant replaceWrapChar( const QVariant &variant ) const;

#ifdef HAVE_SERVER_PYTHON_PLUGINS

/**
* Returns the list of visible columns filtered by the access control filter rules.
*/
QgsLayoutTableColumns filteredColumns( );
#endif

private slots:
//! Checks if this vector layer will be removed (and sets mVectorLayer to 0 if yes)
void removeLayer( const QString &layerId );
Expand Down
4 changes: 4 additions & 0 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -1346,6 +1346,10 @@ void QgsLayoutItemMap::drawMap( QPainter *painter, const QgsRectangle &extent, Q
}

QgsMapRendererCustomPainterJob job( ms, painter );
#ifdef HAVE_SERVER_PYTHON_PLUGINS
job.setFeatureFilterProvider( mLayout->renderContext().featureFilterProvider() );
#endif

// Render the map in this thread. This is done because of problems
// with printing to printer on Windows (printing to PDF is fine though).
// Raster images were not displayed - see #10599
Expand Down
10 changes: 10 additions & 0 deletions src/core/layout/qgslayoutrendercontext.cpp
Expand Up @@ -133,3 +133,13 @@ void QgsLayoutRenderContext::setPredefinedScales( const QVector<qreal> &scales )
std::sort( mPredefinedScales.begin(), mPredefinedScales.end() ); // clazy:exclude=detaching-member
emit predefinedScalesChanged();
}

QgsFeatureFilterProvider *QgsLayoutRenderContext::featureFilterProvider() const
{
return mFeatureFilterProvider;
}

void QgsLayoutRenderContext::setFeatureFilterProvider( QgsFeatureFilterProvider *featureFilterProvider )
{
mFeatureFilterProvider = featureFilterProvider;
}
22 changes: 22 additions & 0 deletions src/core/layout/qgslayoutrendercontext.h
Expand Up @@ -297,6 +297,26 @@ class CORE_EXPORT QgsLayoutRenderContext : public QObject
*/
QVector<qreal> predefinedScales() const { return mPredefinedScales; }

/**
* Returns the possibly NULL feature filter provider.
*
* A feature filter provider for filtering visible features or attributes.
* It is currently used by QGIS Server Access Control Plugins.
*
* \since QGIS 3.18
*/
QgsFeatureFilterProvider *featureFilterProvider() const;

/**
* Sets feature filter provider to \a featureFilterProvider.
*
* A feature filter provider for filtering visible features or attributes.
* It is currently used by QGIS Server Access Control Plugins.
*
* \since QGIS 3.18
*/
void setFeatureFilterProvider( QgsFeatureFilterProvider *featureFilterProvider );

signals:

/**
Expand Down Expand Up @@ -342,6 +362,8 @@ class CORE_EXPORT QgsLayoutRenderContext : public QObject

QVector<qreal> mPredefinedScales;

QgsFeatureFilterProvider *mFeatureFilterProvider = nullptr;

friend class QgsLayoutExporter;
friend class TestQgsLayout;
friend class LayoutContextPreviewSettingRestorer;
Expand Down
12 changes: 10 additions & 2 deletions src/core/qgsfeaturefilterprovider.h
Expand Up @@ -19,6 +19,7 @@
#define QGSFEATUREFILTERPROVIDER_H

#include <QtGlobal>
#include <QStringList>
#include "qgis_sip.h"

#include "qgis_core.h"
Expand All @@ -31,10 +32,11 @@ class QgsFeatureRequest;
/**
* \ingroup core
* \class QgsFeatureFilterProvider
* \brief Abstract interface for use by classes that filter the features of a layer.
* \brief Abstract interface for use by classes that filter the features or attributes of a layer.
*
* A QgsFeatureFilterProvider provides a method for modifying a QgsFeatureRequest in place to apply
* additional filters to the request.
* additional filters to the request, since QGIS 3.18 a method to filter allowed attributes is also available.
*
* \since QGIS 2.14
*/

Expand All @@ -59,6 +61,12 @@ class CORE_EXPORT QgsFeatureFilterProvider
*/
virtual void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &featureRequest ) const = 0;

/**
* Returns the list of visible attribute names from a list of \a attributes names for the given \a layer
* \since QGIS 3.18
*/
virtual QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const = 0;

/**
* Create a clone of the feature filter provider
* \returns a new clone
Expand Down
2 changes: 1 addition & 1 deletion src/server/qgsaccesscontrol.cpp
Expand Up @@ -64,7 +64,7 @@ void QgsAccessControl::filterFeatures( const QgsVectorLayer *layer, QgsFeatureRe

QString expression;

if ( mResolved && mFilterFeaturesExpressions.keys().contains( layer->id() ) )
if ( mResolved && mFilterFeaturesExpressions.contains( layer->id() ) )
{
expression = mFilterFeaturesExpressions[layer->id()];
}
Expand Down
3 changes: 2 additions & 1 deletion src/server/qgsaccesscontrol.h
Expand Up @@ -134,7 +134,7 @@ class SERVER_EXPORT QgsAccessControl : public QgsFeatureFilterProvider
* \param attributes the list of attribute
* \returns the list of visible attributes
*/
QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const;
QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const override;

/**
* Are we authorized to modify the following geometry
Expand Down Expand Up @@ -166,6 +166,7 @@ class SERVER_EXPORT QgsAccessControl : public QgsFeatureFilterProvider

QMap<QString, QString> mFilterFeaturesExpressions;
bool mResolved;

};

#endif
6 changes: 6 additions & 0 deletions src/server/qgsfeaturefilter.cpp
Expand Up @@ -29,6 +29,12 @@ void QgsFeatureFilter::filterFeatures( const QgsVectorLayer *layer, QgsFeatureRe
}
}

QStringList QgsFeatureFilter::layerAttributes( const QgsVectorLayer *, const QStringList &attributes ) const
{
// Do nothing
return attributes;
}

QgsFeatureFilterProvider *QgsFeatureFilter::clone() const
{
auto result = new QgsFeatureFilter();
Expand Down
3 changes: 3 additions & 0 deletions src/server/qgsfeaturefilter.h
Expand Up @@ -44,6 +44,8 @@ class SERVER_EXPORT QgsFeatureFilter : public QgsFeatureFilterProvider
*/
void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const override;

QStringList layerAttributes( const QgsVectorLayer *layer, const QStringList &attributes ) const override;

/**
* Returns a clone of the object
* \returns A clone
Expand All @@ -59,6 +61,7 @@ class SERVER_EXPORT QgsFeatureFilter : public QgsFeatureFilterProvider

private:
QMap<QString, QString> mFilters;

};

#endif

0 comments on commit 71b0977

Please sign in to comment.