1 /***************************************************************************
2                               qgswfsparameters.cpp
3                               --------------------
4   begin                : Sept 14, 2017
5   copyright            : (C) 2017 by René-Luc Dhont
6   email                : rldhont at 3liz dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgswfsparameters.h"
19 #include "qgsmessagelog.h"
20 
21 namespace QgsWfs
22 {
23   //
24   // QgsWfsParameter
25   //
QgsWfsParameter(const QgsWfsParameter::Name name,const QVariant::Type type,const QVariant defaultValue)26   QgsWfsParameter::QgsWfsParameter( const QgsWfsParameter::Name name,
27                                     const QVariant::Type type,
28                                     const QVariant defaultValue )
29     : QgsServerParameterDefinition( type, defaultValue )
30     , mName( name )
31   {
32   }
33 
toInt() const34   int QgsWfsParameter::toInt() const
35   {
36     bool ok = false;
37     const int val = QgsServerParameterDefinition::toInt( ok );
38 
39     if ( !ok )
40     {
41       raiseError();
42     }
43 
44     return val;
45   }
46 
toRectangle() const47   QgsRectangle QgsWfsParameter::toRectangle() const
48   {
49     QString value = toString();
50     const QStringList corners = mValue.toString().split( ',' );
51     if ( corners.size() == 5 )
52     {
53       value.resize( value.size() - corners[4].size() - 1 );
54     }
55 
56     QgsServerParameterDefinition param;
57     param.mValue = QVariant( value );
58 
59     bool ok = false;
60     const QgsRectangle rectangle = param.toRectangle( ok );
61 
62     if ( !ok )
63     {
64       const QString msg = QString( "%1 ('%2') cannot be converted into rectangle" ).arg( name( mName ), toString() );
65       QgsServerParameterDefinition::raiseError( msg );
66     }
67 
68     return rectangle;
69   }
70 
toStringListWithExp(const QString & exp) const71   QStringList QgsWfsParameter::toStringListWithExp( const QString &exp ) const
72   {
73     QStringList theList;
74 
75     const QString val = mValue.toString();
76     if ( val.isEmpty() )
77       return theList;
78 
79     if ( exp.isEmpty() )
80       theList << val;
81     else
82     {
83       QRegExp rx( exp );
84       if ( rx.indexIn( val, 0 ) == -1 )
85       {
86         theList << val;
87       }
88       else
89       {
90         int pos = 0;
91         while ( ( pos = rx.indexIn( val, pos ) ) != -1 )
92         {
93           theList << rx.cap( 1 );
94           pos += rx.matchedLength();
95         }
96       }
97     }
98 
99     return theList;
100   }
101 
raiseError() const102   void QgsWfsParameter::raiseError() const
103   {
104     const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), toString(), typeName() );
105     QgsServerParameterDefinition::raiseError( msg );
106   }
107 
name(const QgsWfsParameter::Name name)108   QString QgsWfsParameter::name( const QgsWfsParameter::Name name )
109   {
110     const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWfsParameter::Name>() );
111     return metaEnum.valueToKey( name );
112   }
113 
name(const QString & name)114   QgsWfsParameter::Name QgsWfsParameter::name( const QString &name )
115   {
116     const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWfsParameter::Name>() );
117     return ( QgsWfsParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
118   }
119 
120   //
121   // QgsWfsParameters
122   //
QgsWfsParameters()123   QgsWfsParameters::QgsWfsParameters()
124     : QgsServerParameters()
125   {
126     // Available version number
127     mVersions.append( QgsProjectVersion( 1, 0, 0 ) );
128     mVersions.append( QgsProjectVersion( 1, 1, 0 ) );
129 
130     const QgsWfsParameter pOutputFormat = QgsWfsParameter( QgsWfsParameter::OUTPUTFORMAT );
131     save( pOutputFormat );
132 
133     const QgsWfsParameter pResultType = QgsWfsParameter( QgsWfsParameter::RESULTTYPE );
134     save( pResultType );
135 
136     const QgsWfsParameter pPropertyName = QgsWfsParameter( QgsWfsParameter::PROPERTYNAME );
137     save( pPropertyName );
138 
139     const QgsWfsParameter pMaxFeatures = QgsWfsParameter( QgsWfsParameter::MAXFEATURES,
140                                          QVariant::Int,
141                                          QVariant( -1 ) );
142     save( pMaxFeatures );
143 
144     const QgsWfsParameter pStartIndex = QgsWfsParameter( QgsWfsParameter::STARTINDEX,
145                                         QVariant::Int,
146                                         QVariant( 0 ) );
147     save( pStartIndex );
148 
149     const QgsWfsParameter pSrsName = QgsWfsParameter( QgsWfsParameter::SRSNAME );
150     save( pSrsName );
151 
152     const QgsWfsParameter pTypeName = QgsWfsParameter( QgsWfsParameter::TYPENAME );
153     save( pTypeName );
154 
155     const QgsWfsParameter pFeatureId = QgsWfsParameter( QgsWfsParameter::FEATUREID );
156     save( pFeatureId );
157 
158     const QgsWfsParameter pFilter = QgsWfsParameter( QgsWfsParameter::FILTER );
159     save( pFilter );
160 
161     const QgsWfsParameter pBbox = QgsWfsParameter( QgsWfsParameter::BBOX );
162     save( pBbox );
163 
164     const QgsWfsParameter pSortBy = QgsWfsParameter( QgsWfsParameter::SORTBY );
165     save( pSortBy );
166 
167     const QgsWfsParameter pExpFilter = QgsWfsParameter( QgsWfsParameter::EXP_FILTER );
168     save( pExpFilter );
169 
170     const QgsWfsParameter pGeometryName = QgsWfsParameter( QgsWfsParameter::GEOMETRYNAME );
171     save( pGeometryName );
172   }
173 
QgsWfsParameters(const QgsServerParameters & parameters)174   QgsWfsParameters::QgsWfsParameters( const QgsServerParameters &parameters )
175     : QgsWfsParameters()
176   {
177     load( parameters.urlQuery() );
178   }
179 
loadParameter(const QString & key,const QString & value)180   bool QgsWfsParameters::loadParameter( const QString &key, const QString &value )
181   {
182     bool loaded = false;
183 
184     const QgsWfsParameter::Name name = QgsWfsParameter::name( key );
185     if ( name >= 0 )
186     {
187       mWfsParameters[name].mValue = value;
188       if ( ! mWfsParameters[name].isValid() )
189       {
190         mWfsParameters[name].raiseError();
191       }
192 
193       loaded = true;
194     }
195 
196     return loaded;
197   }
198 
save(const QgsWfsParameter & parameter)199   void QgsWfsParameters::save( const QgsWfsParameter &parameter )
200   {
201     mWfsParameters[ parameter.mName ] = parameter;
202   }
203 
dump() const204   void QgsWfsParameters::dump() const
205   {
206     log( "WFS Request parameters:" );
207     const auto map = mWfsParameters.toStdMap();
208     for ( const auto &parameter : map )
209     {
210       const QString value = parameter.second.toString();
211 
212       if ( ! value.isEmpty() )
213       {
214         const QString name = QgsWfsParameter::name( parameter.first );
215         log( QStringLiteral( " - %1 : %2" ).arg( name, value ) );
216       }
217     }
218 
219     if ( !version().isEmpty() )
220       log( QStringLiteral( " - VERSION : %1" ).arg( version() ) );
221   }
222 
outputFormatAsString() const223   QString QgsWfsParameters::outputFormatAsString() const
224   {
225     return mWfsParameters[ QgsWfsParameter::OUTPUTFORMAT ].toString();
226   }
227 
outputFormat() const228   QgsWfsParameters::Format QgsWfsParameters::outputFormat() const
229   {
230     const QString fStr = outputFormatAsString();
231 
232     if ( fStr.isEmpty() )
233     {
234       if ( versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
235         return Format::GML3;
236       else
237         return Format::GML2;
238     }
239 
240     Format f = Format::NONE;
241     if ( fStr.compare( QLatin1String( "text/xml; subtype=gml/2.1.2" ), Qt::CaseInsensitive ) == 0 )
242       f = Format::GML2;
243     else if ( fStr.compare( QLatin1String( "text/xml; subtype=gml/3.1.1" ), Qt::CaseInsensitive ) == 0 )
244       f = Format::GML3;
245     else if ( fStr.compare( QLatin1String( "application/vnd.geo+json" ), Qt::CaseInsensitive ) == 0 ||
246               // Needs to check for space too, because a + sign in the query string is interpreted as a space
247               fStr.compare( QLatin1String( "application/vnd.geo json" ), Qt::CaseInsensitive ) == 0 ||
248               fStr.compare( QLatin1String( "application/geo+json" ), Qt::CaseInsensitive ) == 0 ||
249               fStr.compare( QLatin1String( "application/geo json" ), Qt::CaseInsensitive ) == 0 ||
250               fStr.compare( QLatin1String( "application/json" ), Qt::CaseInsensitive ) == 0 ||
251               fStr.compare( QLatin1String( "geojson" ), Qt::CaseInsensitive ) == 0
252             )
253       f = Format::GeoJSON;
254     else if ( fStr.compare( QLatin1String( "gml2" ), Qt::CaseInsensitive ) == 0 )
255       f = Format::GML2;
256     else if ( fStr.compare( QLatin1String( "gml3" ), Qt::CaseInsensitive ) == 0 )
257       f = Format::GML3;
258 
259     if ( f == Format::NONE &&
260          request().compare( QLatin1String( "describefeaturetype" ), Qt::CaseInsensitive ) == 0 &&
261          fStr.compare( QLatin1String( "xmlschema" ), Qt::CaseInsensitive ) == 0 )
262       f = Format::GML2;
263 
264     return f;
265   }
266 
resultTypeAsString() const267   QString QgsWfsParameters::resultTypeAsString() const
268   {
269     return mWfsParameters[ QgsWfsParameter::RESULTTYPE ].toString();
270   }
271 
resultType() const272   QgsWfsParameters::ResultType QgsWfsParameters::resultType() const
273   {
274     const QString rtStr = resultTypeAsString();
275     if ( rtStr.isEmpty() )
276       return ResultType::RESULTS;
277 
278     ResultType rt = ResultType::RESULTS;
279     if ( rtStr.compare( QLatin1String( "hits" ), Qt::CaseInsensitive ) == 0 )
280       rt = ResultType::HITS;
281     return rt;
282   }
283 
propertyNames() const284   QStringList QgsWfsParameters::propertyNames() const
285   {
286     return mWfsParameters[ QgsWfsParameter::PROPERTYNAME ].toStringListWithExp();
287   }
288 
maxFeatures() const289   QString QgsWfsParameters::maxFeatures() const
290   {
291     return mWfsParameters[ QgsWfsParameter::MAXFEATURES ].toString();
292   }
293 
maxFeaturesAsInt() const294   int QgsWfsParameters::maxFeaturesAsInt() const
295   {
296     return mWfsParameters[ QgsWfsParameter::MAXFEATURES ].toInt();
297   }
298 
startIndex() const299   QString QgsWfsParameters::startIndex() const
300   {
301     return mWfsParameters[ QgsWfsParameter::STARTINDEX ].toString();
302   }
303 
startIndexAsInt() const304   int QgsWfsParameters::startIndexAsInt() const
305   {
306     return mWfsParameters[ QgsWfsParameter::STARTINDEX ].toInt();
307   }
308 
srsName() const309   QString QgsWfsParameters::srsName() const
310   {
311     return mWfsParameters[ QgsWfsParameter::SRSNAME ].toString();
312   }
313 
typeNames() const314   QStringList QgsWfsParameters::typeNames() const
315   {
316     return mWfsParameters[ QgsWfsParameter::TYPENAME ].toStringList();
317   }
318 
featureIds() const319   QStringList QgsWfsParameters::featureIds() const
320   {
321     return mWfsParameters[ QgsWfsParameter::FEATUREID ].toStringList();
322   }
323 
filters() const324   QStringList QgsWfsParameters::filters() const
325   {
326     return mWfsParameters[ QgsWfsParameter::FILTER ].toStringListWithExp();
327   }
328 
bbox() const329   QString QgsWfsParameters::bbox() const
330   {
331     return mWfsParameters[ QgsWfsParameter::BBOX ].toString();
332   }
333 
bboxAsRectangle() const334   QgsRectangle QgsWfsParameters::bboxAsRectangle() const
335   {
336     return mWfsParameters[ QgsWfsParameter::BBOX ].toRectangle();
337   }
338 
sortBy() const339   QStringList QgsWfsParameters::sortBy() const
340   {
341     return mWfsParameters[ QgsWfsParameter::SORTBY ].toStringListWithExp();
342   }
343 
expFilters() const344   QStringList QgsWfsParameters::expFilters() const
345   {
346     return mWfsParameters[ QgsWfsParameter::EXP_FILTER ].toStringListWithExp( QString( ) );
347   }
348 
geometryNameAsString() const349   QString QgsWfsParameters::geometryNameAsString() const
350   {
351     return mWfsParameters[ QgsWfsParameter::GEOMETRYNAME ].toString();
352   }
353 
versionAsNumber() const354   QgsProjectVersion QgsWfsParameters::versionAsNumber() const
355   {
356     const QString vStr = version();
357     QgsProjectVersion version;
358 
359     if ( vStr.isEmpty() )
360       version = QgsProjectVersion( 1, 1, 0 ); // default value
361     else if ( mVersions.contains( QgsProjectVersion( vStr ) ) )
362       version = QgsProjectVersion( vStr );
363 
364     return version;
365   }
366 
log(const QString & msg) const367   void QgsWfsParameters::log( const QString &msg ) const
368   {
369     QgsMessageLog::logMessage( msg, "Server", Qgis::MessageLevel::Info );
370   }
371 }
372