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     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     for ( auto parameter : mWfsParameters.toStdMap() )
208     {
209       const QString value = parameter.second.toString();
210 
211       if ( ! value.isEmpty() )
212       {
213         const QString name = QgsWfsParameter::name( parameter.first );
214         log( QStringLiteral( " - %1 : %2" ).arg( name, value ) );
215       }
216     }
217 
218     if ( !version().isEmpty() )
219       log( QStringLiteral( " - VERSION : %1" ).arg( version() ) );
220   }
221 
outputFormatAsString() const222   QString QgsWfsParameters::outputFormatAsString() const
223   {
224     return mWfsParameters[ QgsWfsParameter::OUTPUTFORMAT ].toString();
225   }
226 
outputFormat() const227   QgsWfsParameters::Format QgsWfsParameters::outputFormat() const
228   {
229     QString fStr = outputFormatAsString();
230 
231     if ( fStr.isEmpty() )
232     {
233       if ( versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
234         return Format::GML3;
235       else
236         return Format::GML2;
237     }
238 
239     Format f = Format::NONE;
240     if ( fStr.compare( QLatin1String( "text/xml; subtype=gml/2.1.2" ), Qt::CaseInsensitive ) == 0 )
241       f = Format::GML2;
242     else if ( fStr.compare( QLatin1String( "text/xml; subtype=gml/3.1.1" ), Qt::CaseInsensitive ) == 0 )
243       f = Format::GML3;
244     else if ( fStr.compare( QLatin1String( "application/vnd.geo+json" ), Qt::CaseInsensitive ) == 0 ||
245               // Needs to check for space too, because a + sign in the query string is interpreted as a space
246               fStr.compare( QLatin1String( "application/vnd.geo json" ), Qt::CaseInsensitive ) == 0 ||
247               fStr.compare( QLatin1String( "application/geo+json" ), Qt::CaseInsensitive ) == 0 ||
248               fStr.compare( QLatin1String( "application/geo json" ), Qt::CaseInsensitive ) == 0 ||
249               fStr.compare( QLatin1String( "application/json" ), Qt::CaseInsensitive ) == 0 ||
250               fStr.compare( QLatin1String( "geojson" ), Qt::CaseInsensitive ) == 0
251             )
252       f = Format::GeoJSON;
253     else if ( fStr.compare( QLatin1String( "gml2" ), Qt::CaseInsensitive ) == 0 )
254       f = Format::GML2;
255     else if ( fStr.compare( QLatin1String( "gml3" ), Qt::CaseInsensitive ) == 0 )
256       f = Format::GML3;
257 
258     if ( f == Format::NONE &&
259          request().compare( QLatin1String( "describefeaturetype" ), Qt::CaseInsensitive ) == 0 &&
260          fStr.compare( QLatin1String( "xmlschema" ), Qt::CaseInsensitive ) == 0 )
261       f = Format::GML2;
262 
263     return f;
264   }
265 
resultTypeAsString() const266   QString QgsWfsParameters::resultTypeAsString() const
267   {
268     return mWfsParameters[ QgsWfsParameter::RESULTTYPE ].toString();
269   }
270 
resultType() const271   QgsWfsParameters::ResultType QgsWfsParameters::resultType() const
272   {
273     QString rtStr = resultTypeAsString();
274     if ( rtStr.isEmpty() )
275       return ResultType::RESULTS;
276 
277     ResultType rt = ResultType::RESULTS;
278     if ( rtStr.compare( QLatin1String( "hits" ), Qt::CaseInsensitive ) == 0 )
279       rt = ResultType::HITS;
280     return rt;
281   }
282 
propertyNames() const283   QStringList QgsWfsParameters::propertyNames() const
284   {
285     return mWfsParameters[ QgsWfsParameter::PROPERTYNAME ].toStringListWithExp();
286   }
287 
maxFeatures() const288   QString QgsWfsParameters::maxFeatures() const
289   {
290     return mWfsParameters[ QgsWfsParameter::MAXFEATURES ].toString();
291   }
292 
maxFeaturesAsInt() const293   int QgsWfsParameters::maxFeaturesAsInt() const
294   {
295     return mWfsParameters[ QgsWfsParameter::MAXFEATURES ].toInt();
296   }
297 
startIndex() const298   QString QgsWfsParameters::startIndex() const
299   {
300     return mWfsParameters[ QgsWfsParameter::STARTINDEX ].toString();
301   }
302 
startIndexAsInt() const303   int QgsWfsParameters::startIndexAsInt() const
304   {
305     return mWfsParameters[ QgsWfsParameter::STARTINDEX ].toInt();
306   }
307 
srsName() const308   QString QgsWfsParameters::srsName() const
309   {
310     return mWfsParameters[ QgsWfsParameter::SRSNAME ].toString();
311   }
312 
typeNames() const313   QStringList QgsWfsParameters::typeNames() const
314   {
315     return mWfsParameters[ QgsWfsParameter::TYPENAME ].toStringList();
316   }
317 
featureIds() const318   QStringList QgsWfsParameters::featureIds() const
319   {
320     return mWfsParameters[ QgsWfsParameter::FEATUREID ].toStringList();
321   }
322 
filters() const323   QStringList QgsWfsParameters::filters() const
324   {
325     return mWfsParameters[ QgsWfsParameter::FILTER ].toStringListWithExp();
326   }
327 
bbox() const328   QString QgsWfsParameters::bbox() const
329   {
330     return mWfsParameters[ QgsWfsParameter::BBOX ].toString();
331   }
332 
bboxAsRectangle() const333   QgsRectangle QgsWfsParameters::bboxAsRectangle() const
334   {
335     return mWfsParameters[ QgsWfsParameter::BBOX ].toRectangle();
336   }
337 
sortBy() const338   QStringList QgsWfsParameters::sortBy() const
339   {
340     return mWfsParameters[ QgsWfsParameter::SORTBY ].toStringListWithExp();
341   }
342 
expFilters() const343   QStringList QgsWfsParameters::expFilters() const
344   {
345     return mWfsParameters[ QgsWfsParameter::EXP_FILTER ].toStringListWithExp( QString( ) );
346   }
347 
geometryNameAsString() const348   QString QgsWfsParameters::geometryNameAsString() const
349   {
350     return mWfsParameters[ QgsWfsParameter::GEOMETRYNAME ].toString();
351   }
352 
versionAsNumber() const353   QgsProjectVersion QgsWfsParameters::versionAsNumber() const
354   {
355     QString vStr = version();
356     QgsProjectVersion version;
357 
358     if ( vStr.isEmpty() )
359       version = QgsProjectVersion( 1, 1, 0 ); // default value
360     else if ( mVersions.contains( QgsProjectVersion( vStr ) ) )
361       version = QgsProjectVersion( vStr );
362 
363     return version;
364   }
365 
log(const QString & msg) const366   void QgsWfsParameters::log( const QString &msg ) const
367   {
368     QgsMessageLog::logMessage( msg, "Server", Qgis::Info );
369   }
370 }
371