QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsserverapiutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsserverapiutils.cpp
3 
4  Class defining utilities for QGIS server APIs.
5  -------------------
6  begin : 2019-04-16
7  copyright : (C) 2019 by Alessandro Pasotti
8  email : elpaso at itopen dot it
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
20 #include "qgsserverapiutils.h"
21 #include "qgsrectangle.h"
22 #include "qgsvectorlayer.h"
24 #include "qgsserverprojectutils.h"
25 #include "qgsmessagelog.h"
26 
27 
28 #include "nlohmann/json.hpp"
29 
30 #include <QUrl>
31 
33 {
34  const auto parts { bbox.split( ',', QString::SplitBehavior::SkipEmptyParts ) };
35  // Note: Z is ignored
36  auto ok { true };
37  if ( parts.count() == 4 || parts.count() == 6 )
38  {
39  const auto hasZ { parts.count() == 6 };
40  auto toDouble = [ & ]( const int i ) -> double
41  {
42  if ( ! ok )
43  return 0;
44  return parts[i].toDouble( &ok );
45  };
46  QgsRectangle rect;
47  if ( hasZ )
48  {
49  rect = QgsRectangle( toDouble( 0 ), toDouble( 1 ),
50  toDouble( 3 ), toDouble( 4 ) );
51  }
52  else
53  {
54  rect = QgsRectangle( toDouble( 0 ), toDouble( 1 ),
55  toDouble( 2 ), toDouble( 3 ) );
56  }
57  if ( ok )
58  {
59  return rect;
60  }
61  }
62  return QgsRectangle();
63 }
64 
65 QList< QgsVectorLayerServerProperties::WmsDimensionInfo > QgsServerApiUtils::temporalDimensions( const QgsVectorLayer *layer )
66 {
67  QList< QgsVectorLayerServerProperties::WmsDimensionInfo > dimensions { layer->serverProperties()->wmsDimensions() };
68  // Filter only date and time
69  dimensions.erase( std::remove_if( dimensions.begin(),
70  dimensions.end(),
72  {
73  return dim.name.toLower() != QStringLiteral( "time" )
74  && dim.name.toLower() != QStringLiteral( "date" ) ;
75  } ), dimensions.end() );
76 
77  // Automatically pick up the first date/datetime field if dimensions is empty
78  if ( dimensions.isEmpty() )
79  {
80  const auto constFields { layer->fields() };
81  for ( const auto &f : constFields )
82  {
83  if ( f.isDateOrTime() )
84  {
85  dimensions.append( QgsVectorLayerServerProperties::WmsDimensionInfo( f.type() == QVariant::DateTime ?
86  QStringLiteral( "time" ) :
87  QStringLiteral( "date" ), f.name() ) );
88  break;
89  }
90  }
91  }
92  return dimensions;
93 }
94 
96 template<typename T, class T2> T QgsServerApiUtils::parseTemporalInterval( const QString &interval )
97 {
98  auto parseDate = [ ]( const QString & date ) -> T2
99  {
100  T2 result;
101  if ( date == QLatin1String( ".." ) || date.isEmpty() )
102  {
103  return result;
104  }
105  else
106  {
107  T2 result { T2::fromString( date, Qt::DateFormat::ISODate ) };
108  if ( !result.isValid() )
109  {
110  throw QgsServerApiBadRequestException( QStringLiteral( "%1 is not a valid date/datetime." ).arg( date ) );
111  }
112  return result;
113  }
114  };
115  const QStringList parts { interval.split( '/' ) };
116  if ( parts.length() != 2 )
117  {
118  throw QgsServerApiBadRequestException( QStringLiteral( "%1 is not a valid datetime interval." ).arg( interval ), QStringLiteral( "Server" ), Qgis::Critical );
119  }
120  T result { parseDate( parts[0] ), parseDate( parts[1] ) };
121  // Check validity
122  if ( result.isEmpty() )
123  {
124  throw QgsServerApiBadRequestException( QStringLiteral( "%1 is not a valid datetime interval (empty)." ).arg( interval ), QStringLiteral( "Server" ), Qgis::Critical );
125  }
126  return result;
127 }
129 
130 QgsDateRange QgsServerApiUtils::parseTemporalDateInterval( const QString &interval )
131 {
132  return QgsServerApiUtils::parseTemporalInterval<QgsDateRange, QDate>( interval );
133 }
134 
135 QgsDateTimeRange QgsServerApiUtils::parseTemporalDateTimeInterval( const QString &interval )
136 {
137  return QgsServerApiUtils::parseTemporalInterval<QgsDateTimeRange, QDateTime>( interval );
138 }
139 
141 {
142  QgsExpression expression;
143  QStringList conditions;
144 
145  const auto dimensions { QgsServerApiUtils::temporalDimensions( layer ) };
146  if ( dimensions.isEmpty() )
147  {
148  return expression;
149  }
150 
151  // helper to get the field type from the field name
152  auto fieldTypeFromName = [ & ]( const QString & fieldName, const QgsVectorLayer * layer ) -> QVariant::Type
153  {
154  int fieldIdx { layer->fields().lookupField( fieldName ) };
155  if ( fieldIdx < 0 )
156  {
157  return QVariant::Type::Invalid;
158  }
159  const QgsField field { layer->fields().at( fieldIdx ) };
160  return field.type();
161  };
162 
163  // helper to cast the field value
164  auto refFieldCast = [ & ]( const QString & fieldName, QVariant::Type queryType, QVariant::Type fieldType ) -> QString
165  {
166 
167  const auto fieldRealType { fieldTypeFromName( fieldName, layer ) };
168  if ( fieldRealType == QVariant::Type::Invalid )
169  {
170  return QString();
171  }
172 
173  // Downcast only datetime -> date
174  // always cast strings
175  if ( fieldRealType == QVariant::Type::String )
176  {
177  // Cast to query type but only downcast
178  if ( fieldType != queryType || fieldType == QVariant::Type::Date )
179  {
180  return QStringLiteral( "to_date( %1 )" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
181  }
182  else
183  {
184  return QStringLiteral( "%2( %1 )" ).arg( QgsExpression::quotedColumnRef( fieldName ) )
185  .arg( queryType == QVariant::Type::Date ? QStringLiteral( "to_date" ) : QStringLiteral( "to_datetime" ) );
186  }
187  }
188  else if ( fieldType == queryType || fieldType == QVariant::Type::Date )
189  {
190  return QgsExpression::quotedColumnRef( fieldName );
191  }
192  else
193  {
194  return QStringLiteral( "%2( %1 )" ).arg( QgsExpression::quotedColumnRef( fieldName ) )
195  .arg( queryType == QVariant::Type::Date ? QStringLiteral( "to_date" ) : QStringLiteral( "to_datetime" ) );
196  }
197  };
198 
199  // Quote and cast a query value
200  auto quoteValue = [ ]( const QString & value ) -> QString
201  {
202  if ( value.length() == 10 )
203  {
204  return QStringLiteral( "to_date( %1 )" ).arg( QgsExpression::quotedValue( value ) );
205  }
206  else
207  {
208  return QStringLiteral( "to_datetime( %1 )" ).arg( QgsExpression::quotedValue( value ) );
209  }
210  };
211 
212  // helper to build the interval filter, fieldType is the underlying field type, queryType is the input query type
213  auto makeFilter = [ &quoteValue ]( const QString & fieldBegin, const QString & fieldEnd,
214  const QString & fieldBeginCasted, const QString & fieldEndCasted,
215  const QString & queryBegin, const QString & queryEnd ) -> QString
216  {
217  QString result;
218 
219  // It's a closed interval query, go for overlap
220  if ( ! queryBegin.isEmpty() && ! queryEnd.isEmpty() )
221  {
222  // Overlap of two intervals
223  if ( ! fieldEndCasted.isEmpty() )
224  {
225  result = QStringLiteral( "( %1 IS NULL OR %2 <= %6 ) AND ( %4 IS NULL OR %5 >= %3 )" )
226  .arg( fieldBegin,
227  fieldBeginCasted,
228  quoteValue( queryBegin ),
229  fieldEnd,
230  fieldEndCasted,
231  quoteValue( queryEnd ) );
232  }
233  else // Overlap of single value
234  {
235  result = QStringLiteral( "( %1 IS NULL OR ( %2 <= %3 AND %3 <= %4 ) )" )
236  .arg( fieldBegin,
237  quoteValue( queryBegin ),
238  fieldBeginCasted,
239  quoteValue( queryEnd ) );
240  }
241 
242  }
243  else if ( ! queryBegin.isEmpty() ) // >=
244  {
245  if ( ! fieldEndCasted.isEmpty() )
246  {
247  result = QStringLiteral( "( %1 IS NULL OR %2 >= %3 )" ).arg( fieldEnd, fieldEndCasted, quoteValue( queryBegin ) );
248  }
249  else
250  {
251  result = QStringLiteral( "( %1 IS NULL OR %2 >= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ) );
252  }
253  }
254  else // <=
255  {
256  result = QStringLiteral( "( %1 IS NULL OR %2 <= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryEnd ) );
257  }
258  return result;
259  };
260 
261  // Determine if it is a date or a datetime interval (mixed are not supported)
262  QString testType { interval };
263  if ( interval.contains( '/' ) )
264  {
265  const QStringList parts { interval.split( '/' ) };
266  testType = parts[0];
267  if ( testType.isEmpty() || testType == QLatin1String( ".." ) )
268  {
269  testType = parts[1];
270  }
271  }
272  // Determine query input type: datetime is always longer than 10 chars
273  const bool inputQueryIsDateTime { testType.length() > 10 };
274  const QVariant::Type queryType { inputQueryIsDateTime ? QVariant::Type::DateTime : QVariant::Type::Date };
275 
276  // Is it an interval?
277  if ( interval.contains( '/' ) )
278  {
279  if ( ! inputQueryIsDateTime )
280  {
281  QgsDateRange dateInterval { QgsServerApiUtils::parseTemporalDateInterval( interval ) };
282 
283  for ( const auto &dimension : qgis::as_const( dimensions ) )
284  {
285 
286  // Determine the field type from the dimension name "time"/"date"
287  const QVariant::Type fieldType { dimension.name.toLower() == QLatin1String( "time" ) ? QVariant::Type::DateTime : QVariant::Type::Date };
288 
289  const auto fieldBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
290  if ( fieldBeginCasted.isEmpty() )
291  {
292  continue;
293  }
294 
295  const auto fieldBegin = QgsExpression::quotedColumnRef( dimension.fieldName );
296  const auto fieldEnd = QgsExpression::quotedColumnRef( dimension.endFieldName );
297 
298  // This may be empty:
299  const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
300  if ( ! dateInterval.begin().isValid( ) && ! dateInterval.end().isValid( ) )
301  {
302  // Nothing to do here: log?
303  }
304  else
305  {
306  conditions.push_back( makeFilter( fieldBegin,
307  fieldEnd,
308  fieldBeginCasted,
309  fieldEndCasted,
310  dateInterval.begin().toString( Qt::DateFormat::ISODate ),
311  dateInterval.end().toString( Qt::DateFormat::ISODate ) ) );
312 
313  }
314  }
315  }
316  else // try datetime
317  {
318  QgsDateTimeRange dateTimeInterval { QgsServerApiUtils::parseTemporalDateTimeInterval( interval ) };
319  for ( const auto &dimension : qgis::as_const( dimensions ) )
320  {
321 
322  // Determine the field type from the dimension name "time"/"date"
323  const QVariant::Type fieldType { dimension.name.toLower() == QLatin1String( "time" ) ? QVariant::Type::DateTime : QVariant::Type::Date };
324 
325  const auto fieldfBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
326  if ( fieldfBeginCasted.isEmpty() )
327  {
328  continue;
329  }
330  const auto fieldBegin = QgsExpression::quotedColumnRef( dimension.fieldName );
331  const auto fieldEnd = QgsExpression::quotedColumnRef( dimension.endFieldName );
332 
333  // This may be empty:
334  const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
335  if ( ! dateTimeInterval.begin().isValid( ) && ! dateTimeInterval.end().isValid( ) )
336  {
337  // Nothing to do here: log?
338  }
339  else
340  {
341  // Cast the query value according to the field type
342  QString beginQuery;
343  QString endQuery;
344  // Drop the time
345  if ( fieldType == QVariant::Type::Date )
346  {
347  beginQuery = dateTimeInterval.begin().date().toString( Qt::DateFormat::ISODate );
348  endQuery = dateTimeInterval.end().date().toString( Qt::DateFormat::ISODate );
349  }
350  else
351  {
352  beginQuery = dateTimeInterval.begin().toString( Qt::DateFormat::ISODate );
353  endQuery = dateTimeInterval.end().toString( Qt::DateFormat::ISODate );
354  }
355  conditions.push_back( makeFilter( fieldBegin,
356  fieldEnd,
357  fieldfBeginCasted,
358  fieldEndCasted,
359  beginQuery,
360  endQuery ) );
361  }
362  }
363  }
364  }
365  else // single value
366  {
367 
368  for ( const auto &dimension : qgis::as_const( dimensions ) )
369  {
370  // Determine the field type from the dimension name "time"/"date"
371  const bool fieldIsDateTime { dimension.name.toLower() == QLatin1String( "time" ) };
372  const QVariant::Type fieldType { fieldIsDateTime ? QVariant::Type::DateTime : QVariant::Type::Date };
373 
374  const auto fieldRefBegin { refFieldCast( dimension.fieldName, queryType, fieldType ) };
375  if ( fieldRefBegin.isEmpty() )
376  {
377  continue;
378  }
379  const auto fieldBegin = QgsExpression::quotedColumnRef( dimension.fieldName );
380 
381  // This may be empty:
382  const auto fieldRefEnd { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
383  const auto fieldEnd = QgsExpression::quotedColumnRef( dimension.endFieldName );
384 
385  QString condition;
386  QString castedValue;
387 
388  // field has possibly been downcasted
389  if ( ! inputQueryIsDateTime || ! fieldIsDateTime )
390  {
391  QString castedInterval { interval };
392  // Check if we need to downcast interval from datetime
393  if ( inputQueryIsDateTime )
394  {
395  castedInterval = QDate::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
396  }
397  castedValue = QStringLiteral( "to_date( %1 )" ).arg( QgsExpression::quotedValue( castedInterval ) );
398  }
399  else
400  {
401  QString castedInterval { interval };
402  // Check if we need to upcast interval to datetime
403  if ( ! inputQueryIsDateTime )
404  {
405  castedInterval = QDateTime::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
406  }
407  castedValue = QStringLiteral( "to_datetime( %1 )" ).arg( QgsExpression::quotedValue( castedInterval ) );
408  }
409 
410  if ( ! fieldRefEnd.isEmpty() )
411  {
412  condition = QStringLiteral( "( %1 IS NULL OR %2 <= %3 ) AND ( %5 IS NULL OR %3 <= %4 )" ).arg(
413  fieldBegin,
414  fieldRefBegin,
415  castedValue,
416  fieldRefEnd,
417  fieldEnd );
418  }
419  else
420  {
421  condition = QStringLiteral( "( %1 IS NULL OR %2 = %3 )" )
422  .arg( fieldBegin,
423  fieldRefBegin,
424  castedValue );
425 
426  }
427  conditions.push_back( condition );
428 
429  }
430  }
431  if ( ! conditions.isEmpty() )
432  {
433  expression.setExpression( conditions.join( QLatin1String( " AND " ) ) );
434  }
435  return expression;
436 }
437 
439 {
440  auto extent { layer->extent() };
441  if ( layer->crs().authid() != QLatin1String( "EPSG:4326" ) )
442  {
443  static const QgsCoordinateReferenceSystem targetCrs( QStringLiteral( "EPSG:4326" ) );
444  const QgsCoordinateTransform ct( layer->crs(), targetCrs, layer->transformContext() );
445  extent = ct.transform( extent );
446  }
447  return {{ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() }};
448 }
449 
451 {
452  // Helper to get min/max from a dimension
453  auto range = [ & ]( const QgsVectorLayerServerProperties::WmsDimensionInfo & dimInfo ) -> QgsDateTimeRange
454  {
455  QgsDateTimeRange result;
456  // min
457  int fieldIdx { layer->fields().lookupField( dimInfo.fieldName )};
458  if ( fieldIdx < 0 )
459  {
460  return result;
461  }
462  QDateTime min { layer->minimumValue( fieldIdx ).toDateTime() };
463  QDateTime max { layer->maximumValue( fieldIdx ).toDateTime() };
464  if ( ! dimInfo.endFieldName.isEmpty() )
465  {
466  fieldIdx = layer->fields().lookupField( dimInfo.endFieldName );
467  if ( fieldIdx >= 0 )
468  {
469  QDateTime minEnd { layer->minimumValue( fieldIdx ).toDateTime() };
470  QDateTime maxEnd { layer->maximumValue( fieldIdx ).toDateTime() };
471  if ( minEnd.isValid() )
472  {
473  min = std::min<QDateTime>( min, layer->minimumValue( fieldIdx ).toDateTime() );
474  }
475  if ( maxEnd.isValid() )
476  {
477  max = std::max<QDateTime>( max, layer->maximumValue( fieldIdx ).toDateTime() );
478  }
479  }
480  }
481  return { min, max };
482  };
483 
484  const QList<QgsVectorLayerServerProperties::WmsDimensionInfo> dimensions { QgsServerApiUtils::temporalDimensions( layer ) };
485  if ( dimensions.isEmpty() )
486  {
487  return nullptr;
488  }
489  else
490  {
491  try
492  {
493  QgsDateTimeRange extent;
494  bool isFirst = true;
495  for ( const auto &dimension : dimensions )
496  {
497  // Get min/max for dimension
498  if ( isFirst )
499  {
500  extent = range( dimension );
501  isFirst = false;
502  }
503  else
504  {
505  extent.extend( range( dimension ) );
506  }
507  }
508  json ret = json::array();
509  const QString beginVal { extent.begin().toString( Qt::DateFormat::ISODate ) };
510  const QString endVal { extent.end().toString( Qt::DateFormat::ISODate ) };
511  // We cannot mix nullptr and std::string :(
512  if ( beginVal.isEmpty() && endVal.isEmpty() )
513  {
514  ret.push_back( { nullptr, nullptr } );
515  }
516  else if ( beginVal.isEmpty() )
517  {
518  ret.push_back( { nullptr, endVal.toStdString() } );
519  }
520  else if ( endVal.isEmpty() )
521  {
522  ret.push_back( { beginVal.toStdString(), nullptr } );
523  }
524  else
525  {
526  ret.push_back( { beginVal.toStdString(), endVal.toStdString() } );
527  }
528  return ret;
529  }
530  catch ( std::exception &ex )
531  {
532  const QString errorMessage { QStringLiteral( "Error creating temporal extent: %1" ).arg( ex.what() ) };
533  QgsMessageLog::logMessage( errorMessage, QStringLiteral( "Server" ), Qgis::Critical );
534  throw QgsServerApiInternalServerError( errorMessage );
535  }
536  }
537 }
538 
539 QVariantList QgsServerApiUtils::temporalExtentList( const QgsVectorLayer *layer ) SIP_PYNAME( temporalExtent )
540 {
541  QVariantList list;
542  list.push_back( QgsJsonUtils::parseArray( QString::fromStdString( temporalExtent( layer )[0].dump() ) ) );
543  return list;
544 }
545 
547 {
549  // We get this:
550  // http://www.opengis.net/def/crs/OGC/1.3/CRS84
551  // We want this:
552  // "urn:ogc:def:crs:<auth>:[<version>]:<code>"
553  const auto parts { QUrl( bboxCrs ).path().split( '/' ) };
554  if ( parts.count() == 6 )
555  {
556  return crs.fromOgcWmsCrs( QStringLiteral( "urn:ogc:def:crs:%1:%2:%3" ).arg( parts[3], parts[4], parts[5] ) );
557  }
558  else
559  {
560  return crs;
561  }
562 }
563 
564 const QVector<QgsVectorLayer *> QgsServerApiUtils::publishedWfsLayers( const QgsServerApiContext &context )
565 {
566  return publishedWfsLayers< QgsVectorLayer * >( context );
567 }
568 
569 QString QgsServerApiUtils::sanitizedFieldValue( const QString &value )
570 {
571  QString result { QUrl( value ).toString() };
572  return result.replace( '\'', QLatin1String( "\'" ) );
573 }
574 
575 QStringList QgsServerApiUtils::publishedCrsList( const QgsProject *project )
576 {
577  // This must be always available in OGC APIs
578  QStringList result { { QStringLiteral( "http://www.opengis.net/def/crs/OGC/1.3/CRS84" )}};
579  if ( project )
580  {
581  const QStringList outputCrsList = QgsServerProjectUtils::wmsOutputCrsList( *project );
582  for ( const QString &crsId : outputCrsList )
583  {
584  const auto crsUri { crsToOgcUri( QgsCoordinateReferenceSystem::fromOgcWmsCrs( crsId ) ) };
585  if ( ! crsUri.isEmpty() )
586  {
587  result.push_back( crsUri );
588  }
589  }
590  }
591  return result;
592 }
593 
595 {
596  const auto parts { crs.authid().split( ':' ) };
597  if ( parts.length() == 2 )
598  {
599  if ( parts[0] == QLatin1String( "EPSG" ) )
600  return QStringLiteral( "http://www.opengis.net/def/crs/EPSG/9.6.2/%1" ).arg( parts[1] ) ;
601  else if ( parts[0] == QLatin1String( "OGC" ) )
602  {
603  return QStringLiteral( "http://www.opengis.net/def/crs/OGC/1.3/%1" ).arg( parts[1] ) ;
604  }
605  else
606  {
607  QgsMessageLog::logMessage( QStringLiteral( "Error converting published CRS to URI %1: (not OGC or EPSG)" ).arg( crs.authid() ), QStringLiteral( "Server" ), Qgis::Critical );
608  }
609  }
610  else
611  {
612  QgsMessageLog::logMessage( QStringLiteral( "Error converting published CRS to URI: %1" ).arg( crs.authid() ), QStringLiteral( "Server" ), Qgis::Critical );
613  }
614  return QString();
615 }
616 
617 QString QgsServerApiUtils::appendMapParameter( const QString &path, const QUrl &requestUrl )
618 {
619  QList<QPair<QString, QString> > qi;
620  QString result { path };
621  const auto constItems { QUrlQuery( requestUrl ).queryItems() };
622  for ( const auto &i : constItems )
623  {
624  if ( i.first.compare( QStringLiteral( "MAP" ), Qt::CaseSensitivity::CaseInsensitive ) == 0 )
625  {
626  qi.push_back( i );
627  }
628  }
629  if ( ! qi.empty() )
630  {
631  if ( ! path.endsWith( '?' ) )
632  {
633  result += '?';
634  }
635  result.append( QStringLiteral( "MAP=%1" ).arg( qi.first().second ) );
636  }
637  return result;
638 }
639 
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
SIP_PYNAME
#define SIP_PYNAME(name)
Definition: qgis_sip.h:81
QgsServerApiContext
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...
Definition: qgsserverapicontext.h:39
qgsrectangle.h
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:51
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:200
QgsServerApiUtils::parseTemporalDateInterval
static QgsDateRange parseTemporalDateInterval(const QString &interval) SIP_THROW(QgsServerApiBadRequestException)
Parses a date interval and returns a QgsDateRange.
Definition: qgsserverapiutils.cpp:130
qgsserverprojectutils.h
QgsServerApiInternalServerError
Internal server error API exception.
Definition: qgsserverexception.h:203
QgsExpression::setExpression
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
Definition: qgsexpression.cpp:48
QgsServerApiUtils::sanitizedFieldValue
static QString sanitizedFieldValue(const QString &value)
Sanitizes the input value by removing URL encoding.
Definition: qgsserverapiutils.cpp:569
QgsVectorLayerServerProperties::WmsDimensionInfo
Setting to define QGIS Server WMS Dimension.
Definition: qgsvectorlayerserverproperties.h:61
QgsServerApiUtils::temporalFilterExpression
static QgsExpression temporalFilterExpression(const QgsVectorLayer *layer, const QString &interval)
Parses the interval and constructs a (possibly invalid) temporal filter expression for the given laye...
Definition: qgsserverapiutils.cpp:140
field
const QgsField & field
Definition: qgsfield.h:456
QgsFields::append
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:239
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsServerApiUtils::publishedCrsList
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...
Definition: qgsserverapiutils.cpp:575
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:95
qgsserverapiutils.h
QgsExpression::quotedValue
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
Definition: qgsexpression.cpp:79
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
QgsServerProjectUtils::wmsOutputCrsList
SERVER_EXPORT QStringList wmsOutputCrsList(const QgsProject &project)
Returns the WMS output CRS list.
Definition: qgsserverprojectutils.cpp:256
QgsVectorLayerServerProperties::wmsDimensions
const QList< QgsVectorLayerServerProperties::WmsDimensionInfo > wmsDimensions() const
Returns the QGIS Server WMS Dimension list.
Definition: qgsvectorlayerserverproperties.cpp:64
QgsServerApiUtils::temporalDimensions
static QList< QgsVectorLayerServerProperties::WmsDimensionInfo > temporalDimensions(const QgsVectorLayer *layer)
Returns a list of temporal dimensions information for the given layer (either configured in wmsDimens...
Definition: qgsserverapiutils.cpp:65
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1321
QgsServerApiUtils::appendMapParameter
static QString appendMapParameter(const QString &path, const QUrl &requestUrl)
Appends MAP query string parameter from current requestUrl to the given path.
Definition: qgsserverapiutils.cpp:617
QgsServerApiUtils::layerExtent
static json layerExtent(const QgsVectorLayer *layer)
layerExtent returns json array with [xMin,yMin,xMax,yMax] CRS84 extent for the given layer
Definition: qgsserverapiutils.cpp:438
QgsServerApiUtils::parseCrs
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 ...
Definition: qgsserverapiutils.cpp:546
QgsVectorLayer::maximumValue
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
Definition: qgsvectorlayer.cpp:4181
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsVectorLayer::minimumValue
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
Definition: qgsvectorlayer.cpp:4176
QgsVectorLayer::extent
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Definition: qgsvectorlayer.cpp:833
qgsvectorlayer.h
QgsVectorLayer::serverProperties
QgsVectorLayerServerProperties * serverProperties() const
Returns QGIS Server Properties of the vector layer.
Definition: qgsvectorlayer.h:743
QgsMapLayer::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
Definition: qgsmaplayer.cpp:785
QgsServerApiUtils::parseBbox
static QgsRectangle parseBbox(const QString &bbox)
Parses a comma separated bbox into a (possibly empty) QgsRectangle.
Definition: qgsserverapiutils.cpp:32
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
Qgis::Critical
@ Critical
Definition: qgis.h:92
QgsServerApiUtils::crsToOgcUri
static 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...
Definition: qgsserverapiutils.cpp:594
QgsServerApiUtils::parseTemporalDateTimeInterval
static QgsDateTimeRange parseTemporalDateTimeInterval(const QString &interval) SIP_THROW(QgsServerApiBadRequestException)
Parses a datetime interval and returns a QgsDateTimeRange.
Definition: qgsserverapiutils.cpp:135
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
QgsServerApiUtils::publishedWfsLayers
static const QVector< QgsVectorLayer * > publishedWfsLayers(const QgsServerApiContext &context)
Returns the list of layers accessible to the service for a given context.
Definition: qgsserverapiutils.cpp:564
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsServerApiUtils::temporalExtent
static json temporalExtent(const QgsVectorLayer *layer)
temporalExtent returns a json array with an array of [min, max] temporal extent for the given layer.
Definition: qgsserverapiutils.cpp:450
QgsServerApiUtils::temporalExtentList
static QVariantList temporalExtentList(const QgsVectorLayer *layer)
temporalExtent returns a json array with an array of [min, max] temporal extent for the given layer.
Definition: qgsserverapiutils.cpp:539
qgscoordinatereferencesystem.h
QgsServerApiBadRequestException
Bad request error API exception.
Definition: qgsserverexception.h:245
QgsJsonUtils::parseArray
static QVariantList parseArray(const QString &json, QVariant::Type type=QVariant::Invalid)
Parse a simple array (depth=1)
Definition: qgsjsonutils.cpp:331
QgsField::type
QVariant::Type type
Definition: qgsfield.h:57
qgsmessagelog.h
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50