28#include "nlohmann/json.hpp" 
   35  const QStringList parts { bbox.split( 
',', Qt::SplitBehaviorFlags::SkipEmptyParts ) };
 
   38  if ( parts.count() == 4 ||  parts.count() == 6 )
 
   40    const auto hasZ { parts.count() == 6 };
 
   41    auto toDouble = [ & ]( 
const int i ) -> 
double 
   45      return parts[i].toDouble( &ok );
 
   51                           toDouble( 3 ), toDouble( 4 ) );
 
   56                           toDouble( 2 ), toDouble( 3 ) );
 
 
   70  QList< QgsMapLayerServerProperties::WmsDimensionInfo > dimensions { serverProperties->
wmsDimensions() };
 
   72  dimensions.erase( std::remove_if( dimensions.begin(),
 
   76    return dim.name.toLower() != QStringLiteral( 
"time" )
 
   77           && dim.name.toLower() != QStringLiteral( 
"date" ) ;
 
   78  } ), dimensions.end() );
 
   81  if ( dimensions.isEmpty() )
 
   83    const auto constFields { layer->
fields() };
 
   84    for ( 
const auto &f : constFields )
 
   86      if ( f.isDateOrTime() )
 
   89                           QStringLiteral( 
"time" ) :
 
   90                           QStringLiteral( 
"date" ), f.name() ) );
 
 
   99template<
typename T, 
class T2> T QgsServerApiUtils::parseTemporalInterval( 
const QString &interval )
 
  101  auto parseDate = [ ]( 
const QString & date ) -> T2
 
  104    if ( date == QLatin1String( 
".." ) || date.isEmpty() )
 
  110      T2 result { T2::fromString( date, Qt::DateFormat::ISODate ) };
 
  111      if ( !result.isValid() )
 
  118  const QStringList parts { interval.split( 
'/' ) };
 
  119  if ( parts.size() != 2 )
 
  124  T result { parseDate( parts[0] ), parseDate( parts[1] ) };
 
  126  if ( result.isEmpty() )
 
  136  return QgsServerApiUtils::parseTemporalInterval<QgsDateRange, QDate>( interval );
 
 
  141  return QgsServerApiUtils::parseTemporalInterval<QgsDateTimeRange, QDateTime>( interval );
 
 
  147  QStringList conditions;
 
  150  if ( dimensions.isEmpty() )
 
  161      return QMetaType::Type::UnknownType;
 
  168  auto refFieldCast = [ & ]( 
const QString & 
fieldName, QMetaType::Type queryType, QMetaType::Type fieldType ) -> QString
 
  171    const auto fieldRealType { fieldTypeFromName( 
fieldName, layer ) };
 
  172    if ( fieldRealType == QMetaType::Type::UnknownType )
 
  179    if ( fieldRealType == QMetaType::Type::QString )
 
  182      if ( fieldType != queryType || fieldType == QMetaType::Type::QDate )
 
  189               .arg( queryType == QMetaType::Type::QDate ? QStringLiteral( 
"to_date" ) : QStringLiteral( 
"to_datetime" ) );
 
  192    else if ( fieldType == queryType || fieldType == QMetaType::Type::QDate )
 
  199             .arg( queryType == QMetaType::Type::QDate ? QStringLiteral( 
"to_date" ) : QStringLiteral( 
"to_datetime" ) );
 
  204  auto quoteValue = [ ]( 
const QString & value ) -> QString
 
  206    if ( value.length() == 10 )
 
  217  auto makeFilter = [ "eValue ]( 
const QString & fieldBegin, 
const QString & fieldEnd,
 
  218                                     const QString & fieldBeginCasted, 
const QString & fieldEndCasted,
 
  219                                     const QString & queryBegin, 
const QString & queryEnd ) -> QString
 
  224    if ( ! queryBegin.isEmpty() && ! queryEnd.isEmpty() )
 
  227      if ( ! fieldEndCasted.isEmpty() )
 
  229        result = QStringLiteral( 
"( %1 IS NULL OR %2 <= %6 ) AND ( %4 IS NULL OR %5 >= %3 )" )
 
  232              quoteValue( queryBegin ),
 
  235              quoteValue( queryEnd ) );
 
  239        result = QStringLiteral( 
"( %1 IS NULL OR ( %2 <= %3 AND %3 <= %4 ) )" )
 
  241                       quoteValue( queryBegin ),
 
  243                       quoteValue( queryEnd ) );
 
  247    else if ( ! queryBegin.isEmpty() ) 
 
  249      if ( ! fieldEndCasted.isEmpty() )
 
  251        result = QStringLiteral( 
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldEnd, fieldEndCasted, quoteValue( queryBegin ) );
 
  255        result = QStringLiteral( 
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ) );
 
  260      result = QStringLiteral( 
"( %1 IS NULL OR %2 <= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryEnd ) );
 
  266  QString testType { interval };
 
  267  if ( interval.contains( 
'/' ) )
 
  269    const QStringList parts { interval.split( 
'/' ) };
 
  271    if ( testType.isEmpty() || testType == QLatin1String( 
".." ) )
 
  278  const bool inputQueryIsDateTime { testType.length() > 10 };
 
  279  const QMetaType::Type queryType { inputQueryIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
 
  282  if ( interval.contains( 
'/' ) )
 
  284    if ( ! inputQueryIsDateTime )
 
  288      for ( 
const auto &dimension : std::as_const( dimensions ) )
 
  292        const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String( 
"time" ) ? QMetaType::Type::QDateTime :  QMetaType::Type::QDate };
 
  294        const auto fieldBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
 
  295        if ( fieldBeginCasted.isEmpty() )
 
  304        const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
 
  305        if ( ! dateInterval.begin().isValid( ) && ! dateInterval.end().isValid( ) )
 
  311          conditions.push_back( makeFilter( fieldBegin,
 
  315                                            dateInterval.begin().toString( Qt::DateFormat::ISODate ),
 
  316                                            dateInterval.end().toString( Qt::DateFormat::ISODate ) ) );
 
  324      for ( 
const auto &dimension : std::as_const( dimensions ) )
 
  328        const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String( 
"time" ) ? QMetaType::Type::QDateTime :  QMetaType::Type::QDate };
 
  330        const auto fieldfBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
 
  331        if ( fieldfBeginCasted.isEmpty() )
 
  339        const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
 
  340        if ( ! dateTimeInterval.begin().isValid( ) && ! dateTimeInterval.end().isValid( ) )
 
  350          if ( fieldType == QMetaType::Type::QDate )
 
  352            beginQuery = dateTimeInterval.begin().date().toString( Qt::DateFormat::ISODate );
 
  353            endQuery = dateTimeInterval.end().date().toString( Qt::DateFormat::ISODate );
 
  357            beginQuery = dateTimeInterval.begin().toString( Qt::DateFormat::ISODate );
 
  358            endQuery = dateTimeInterval.end().toString( Qt::DateFormat::ISODate );
 
  360          conditions.push_back( makeFilter( fieldBegin,
 
  373    for ( 
const auto &dimension : std::as_const( dimensions ) )
 
  376      const bool fieldIsDateTime { dimension.name.toLower() == QLatin1String( 
"time" ) };
 
  377      const QMetaType::Type fieldType { fieldIsDateTime ? QMetaType::Type::QDateTime :  QMetaType::Type::QDate };
 
  379      const auto fieldRefBegin { refFieldCast( dimension.fieldName, queryType, fieldType ) };
 
  380      if ( fieldRefBegin.isEmpty() )
 
  387      const auto fieldRefEnd { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
 
  394      if ( ! inputQueryIsDateTime || ! fieldIsDateTime )
 
  396        QString castedInterval { interval };
 
  398        if ( inputQueryIsDateTime )
 
  400          castedInterval = QDate::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
 
  406        QString castedInterval { interval };
 
  408        if ( ! inputQueryIsDateTime )
 
  410          castedInterval = QDateTime::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
 
  415      if ( ! fieldRefEnd.isEmpty() )
 
  417        condition = QStringLiteral( 
"( %1 IS NULL OR %2 <= %3 ) AND ( %5 IS NULL OR %3 <= %4 )" ).arg(
 
  426        condition = QStringLiteral( 
"( %1 IS NULL OR %2 = %3 )" )
 
  432      conditions.push_back( condition );
 
  436  if ( ! conditions.isEmpty() )
 
  438    expression.
setExpression( conditions.join( QLatin1String( 
" AND " ) ) );
 
 
  445  auto extent { layer->
extent() };
 
  446  if ( layer->
crs().
authid() != QLatin1String( 
"EPSG:4326" ) )
 
  452  return {{ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() }};
 
 
  472    QDateTime min { minVal.toDateTime() };
 
  473    QDateTime max { maxVal.toDateTime() };
 
  474    if ( ! dimInfo.endFieldName.isEmpty() )
 
  483        QDateTime minEnd { minVal.toDateTime() };
 
  484        QDateTime maxEnd { maxVal.toDateTime() };
 
  485        if ( minEnd.isValid() )
 
  487          min = std::min<QDateTime>( min, minEnd );
 
  489        if ( maxEnd.isValid() )
 
  491          max = std::max<QDateTime>( max, maxEnd );
 
  499  if ( dimensions.isEmpty() )
 
  509      for ( 
const auto &dimension : dimensions )
 
  514          extent = range( dimension );
 
  519          extent.
extend( range( dimension ) );
 
  522      json ret = json::array();
 
  523      const QString beginVal { extent.
begin().toString( Qt::DateFormat::ISODate ) };
 
  524      const QString endVal { extent.
end().toString( Qt::DateFormat::ISODate ) };
 
  526      if ( beginVal.isEmpty() && endVal.isEmpty() )
 
  528        ret.push_back( { 
nullptr, 
nullptr } );
 
  530      else if ( beginVal.isEmpty() )
 
  532        ret.push_back( { 
nullptr, endVal.toStdString() } );
 
  534      else if ( endVal.isEmpty() )
 
  536        ret.push_back( { beginVal.toStdString(), 
nullptr } );
 
  540        ret.push_back( { beginVal.toStdString(), endVal.toStdString() } );
 
  544    catch ( std::exception &ex )
 
  546      const QString errorMessage { QStringLiteral( 
"Error creating temporal extent: %1" ).arg( ex.what() ) };
 
 
  566  const auto parts { QUrl( bboxCrs ).path().split( 
'/' ) };
 
  567  if ( parts.count() == 6 )
 
 
  579  return publishedWfsLayers< QgsVectorLayer * >( context );
 
 
  589  for ( 
const QgsField &field : std::as_const( fields ) )
 
  591    if ( field.displayName() == name )
 
 
  601  QString result { QUrl( value ).toString() };
 
  602  return result.replace( 
'\'', QLatin1String( 
"\'" ) );
 
 
  608  QStringList result { { QStringLiteral( 
"http://www.opengis.net/def/crs/OGC/1.3/CRS84" )}};
 
  612    for ( 
const QString &crsId : outputCrsList )
 
  615      if ( ! crsUri.isEmpty() )
 
  617        result.push_back( crsUri );
 
 
  631  QList<QPair<QString, QString> > qi;
 
  632  QString result { path };
 
  633  const auto constItems { QUrlQuery( requestUrl ).queryItems() };
 
  634  for ( 
const auto &i : constItems )
 
  636    if ( i.first.compare( QStringLiteral( 
"MAP" ), Qt::CaseSensitivity::CaseInsensitive ) == 0 )
 
  643    if ( ! path.endsWith( 
'?' ) )
 
  647    result.append( QStringLiteral( 
"MAP=%1" ).arg( qi.first().second ) );
 
 
@ Critical
Critical/error message.
 
This class represents a coordinate reference system (CRS).
 
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
 
QString toOgcUri() const
Returns the crs as OGC URI (format: http://www.opengis.net/def/crs/OGC/1.3/CRS84) Returns an empty st...
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
 
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
 
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
 
Encapsulate a field in an attribute table or data source.
 
Container of fields for a vector layer.
 
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
 
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
 
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
 
static Q_INVOKABLE QVariantList parseArray(const QString &json, QMetaType::Type type=QMetaType::Type::UnknownType)
Parse a simple array (depth=1)
 
Manages QGIS Server properties for a map layer.
 
QgsCoordinateReferenceSystem crs
 
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
 
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
 
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).
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
 
A rectangle specified with double values.
 
Bad request error API exception.
 
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...
 
Internal server error API exception.
 
static QString sanitizedFieldValue(const QString &value)
Sanitizes the input value by removing URL encoding.
 
static QgsExpression temporalFilterExpression(const QgsVectorLayer *layer, const QString &interval)
Parses the interval and constructs a (possibly invalid) temporal filter expression for the given laye...
 
static QStringList publishedCrsList(const QgsProject *project)
Returns the list of CRSs (format: http://www.opengis.net/def/crs/OGC/1.3/CRS84) available for this pr...
 
static QVariantList temporalExtentList(const QgsVectorLayer *layer)
temporalExtent returns a json array with an array of [min, max] temporal extent for the given layer.
 
static QString fieldName(const QString &name, const QgsVectorLayer *layer)
Given a field name (or display name) and a layer returns the actual name of the field.
 
static QgsCoordinateReferenceSystem parseCrs(const QString &bboxCrs)
Parses the CRS URI bboxCrs (example: "http://www.opengis.net/def/crs/OGC/1.3/CRS84") into a QGIS CRS ...
 
static Q_DECL_DEPRECATED QString crsToOgcUri(const QgsCoordinateReferenceSystem &crs)
Returns a crs as OGC URI (format: http://www.opengis.net/def/crs/OGC/1.3/CRS84) Returns an empty stri...
 
static json temporalExtent(const QgsVectorLayer *layer)
temporalExtent returns a json array with an array of [min, max] temporal extent for the given layer.
 
static const QVector< QgsVectorLayer * > publishedWfsLayers(const QgsServerApiContext &context)
Returns the list of layers accessible to the service for a given context.
 
static json layerExtent(const QgsVectorLayer *layer)
layerExtent returns json array with [xMin,yMin,xMax,yMax] CRS84 extent for the given layer
 
static QgsDateTimeRange parseTemporalDateTimeInterval(const QString &interval)
Parses a datetime interval and returns a QgsDateTimeRange.
 
static QgsDateRange parseTemporalDateInterval(const QString &interval)
Parses a date interval and returns a QgsDateRange.
 
static QList< QgsServerWmsDimensionProperties::WmsDimensionInfo > temporalDimensions(const QgsVectorLayer *layer)
Returns a list of temporal dimensions information for the given layer (either configured in wmsDimens...
 
static QgsRectangle parseBbox(const QString &bbox)
Parses a comma separated bbox into a (possibly empty) QgsRectangle.
 
static QString appendMapParameter(const QString &path, const QUrl &requestUrl)
Appends MAP query string parameter from current requestUrl to the given path.
 
const QList< QgsServerWmsDimensionProperties::WmsDimensionInfo > wmsDimensions() const
Returns the QGIS Server WMS Dimension list.
 
T begin() const
Returns the beginning of the range.
 
bool extend(const QgsTemporalRange< T > &other)
Extends the range in place by extending this range out to include an other range.
 
T end() const
Returns the upper bound of the range.
 
Represents a vector layer which manages a vector based data sets.
 
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
 
QgsRectangle extent() const FINAL
Returns the extent of the layer.
 
SERVER_EXPORT QStringList wmsOutputCrsList(const QgsProject &project)
Returns the WMS output CRS list.
 
QgsTemporalRange< QDate > QgsDateRange
QgsRange which stores a range of dates.
 
const QgsCoordinateReferenceSystem & crs
 
Setting to define QGIS Server WMS Dimension.