QGIS API Documentation  3.6.0-Noosa (5873452)
qgswfstransaction_1_0_0.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgswfstransaction.cpp
3  -------------------------
4  begin : December 20 , 2016
5  copyright : (C) 2007 by Marco Hugentobler (original code)
6  (C) 2012 by RenĂ©-Luc D'Hont (original code)
7  (C) 2014 by Alessandro Pasotti (original code)
8  (C) 2017 by David Marteau
9  email : marco dot hugentobler at karto dot baug dot ethz dot ch
10  a dot pasotti at itopen dot it
11  david dot marteau at 3liz dot com
12  ***************************************************************************/
13 
14 /***************************************************************************
15  * *
16  * This program is free software; you can redistribute it and/or modify *
17  * it under the terms of the GNU General Public License as published by *
18  * the Free Software Foundation; either version 2 of the License, or *
19  * (at your option) any later version. *
20  * *
21  ***************************************************************************/
22 
23 
24 #include "qgswfsutils.h"
25 #include "qgsserverprojectutils.h"
26 #include "qgsfields.h"
27 #include "qgsexpression.h"
28 #include "qgsgeometry.h"
29 #include "qgsmaplayer.h"
30 #include "qgsproject.h"
31 #include "qgsfeatureiterator.h"
32 #include "qgsvectordataprovider.h"
33 #include "qgsvectorlayer.h"
34 #include "qgsfilterrestorer.h"
35 #include "qgsogcutils.h"
38 
39 namespace QgsWfs
40 {
41  namespace v1_0_0
42  {
43  namespace
44  {
45  void addTransactionResult( QDomDocument &responseDoc, QDomElement &responseElem, const QString &status,
46  const QString &locator, const QString &message );
47  }
48 
49 
50  void writeTransaction( QgsServerInterface *serverIface, const QgsProject *project,
51  const QString &version, const QgsServerRequest &request,
52  QgsServerResponse &response )
53 
54  {
55  QDomDocument doc = createTransactionDocument( serverIface, project, version, request );
56 
57  response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
58  response.write( doc.toByteArray() );
59  }
60 
61  QDomDocument createTransactionDocument( QgsServerInterface *serverIface, const QgsProject *project,
62  const QString &version, const QgsServerRequest &request )
63  {
64  Q_UNUSED( version );
65 
66  QgsServerRequest::Parameters parameters = request.parameters();
67  transactionRequest aRequest;
68 
69  QDomDocument doc;
70  QString errorMsg;
71 
72  if ( doc.setContent( parameters.value( QStringLiteral( "REQUEST_BODY" ) ), true, &errorMsg ) )
73  {
74  QDomElement docElem = doc.documentElement();
75  aRequest = parseTransactionRequestBody( docElem );
76  }
77  else
78  {
79  aRequest = parseTransactionParameters( parameters );
80  }
81 
82  int actionCount = aRequest.inserts.size() + aRequest.updates.size() + aRequest.deletes.size();
83  if ( actionCount == 0 )
84  {
85  throw QgsRequestNotWellFormedException( QStringLiteral( "No actions found" ) );
86  }
87 
88  performTransaction( aRequest, serverIface, project );
89 
90  // It's time to make the transaction
91  // Create the response document
92  QDomDocument resp;
93  //wfs:WFS_TransactionRespone element
94  QDomElement respElem = resp.createElement( QStringLiteral( "WFS_TransactionResponse" )/*wfs:WFS_TransactionResponse*/ );
95  respElem.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE );
96  respElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
97  respElem.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WFS_NAMESPACE + " http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
98  respElem.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE );
99  respElem.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
100  resp.appendChild( respElem );
101 
102  int errorCount = 0;
103  QStringList errorLocators;
104  QStringList errorMessages;
105 
106  QList<transactionUpdate>::iterator tuIt = aRequest.updates.begin();
107  for ( ; tuIt != aRequest.updates.end(); ++tuIt )
108  {
109  transactionUpdate &action = *tuIt;
110  if ( action.error )
111  {
112  errorCount += 1;
113  if ( action.handle.isEmpty() )
114  {
115  errorLocators << QStringLiteral( "Update:%1" ).arg( action.typeName );
116  }
117  else
118  {
119  errorLocators << action.handle;
120  }
121  errorMessages << action.errorMsg;
122  }
123  }
124 
125  QList<transactionDelete>::iterator tdIt = aRequest.deletes.begin();
126  for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
127  {
128  transactionDelete &action = *tdIt;
129  if ( action.error )
130  {
131  errorCount += 1;
132  if ( action.handle.isEmpty() )
133  {
134  errorLocators << QStringLiteral( "Delete:%1" ).arg( action.typeName );
135  }
136  else
137  {
138  errorLocators << action.handle;
139  }
140  errorMessages << action.errorMsg;
141  }
142  }
143 
144  QList<transactionInsert>::iterator tiIt = aRequest.inserts.begin();
145  for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
146  {
147  transactionInsert &action = *tiIt;
148  if ( action.error )
149  {
150  errorCount += 1;
151  if ( action.handle.isEmpty() )
152  {
153  errorLocators << QStringLiteral( "Insert:%1" ).arg( action.typeName );
154  }
155  else
156  {
157  errorLocators << action.handle;
158  }
159  errorMessages << action.errorMsg;
160  }
161  else
162  {
163  QStringList::const_iterator fidIt = action.insertFeatureIds.constBegin();
164  for ( ; fidIt != action.insertFeatureIds.constEnd(); ++fidIt )
165  {
166  QString fidStr = *fidIt;
167  QDomElement irElem = doc.createElement( QStringLiteral( "InsertResult" ) );
168  if ( !action.handle.isEmpty() )
169  {
170  irElem.setAttribute( QStringLiteral( "handle" ), action.handle );
171  }
172  QDomElement fiElem = doc.createElement( QStringLiteral( "ogc:FeatureId" ) );
173  fiElem.setAttribute( QStringLiteral( "fid" ), fidStr );
174  irElem.appendChild( fiElem );
175  respElem.appendChild( irElem );
176  }
177  }
178  }
179 
180  // addTransactionResult
181  if ( errorCount == 0 )
182  {
183  addTransactionResult( resp, respElem, QStringLiteral( "SUCCESS" ), QString(), QString() );
184  }
185  else
186  {
187  QString locator = errorLocators.join( QStringLiteral( "; " ) );
188  QString message = errorMessages.join( QStringLiteral( "; " ) );
189  if ( errorCount != actionCount )
190  {
191  addTransactionResult( resp, respElem, QStringLiteral( "PARTIAL" ), locator, message );
192  }
193  else
194  {
195  addTransactionResult( resp, respElem, QStringLiteral( "ERROR" ), locator, message );
196  }
197  }
198  return resp;
199  }
200 
201  void performTransaction( transactionRequest &aRequest, QgsServerInterface *serverIface, const QgsProject *project )
202  {
203  // store typeName
204  QStringList typeNameList;
205 
206  QList<transactionInsert>::iterator tiIt = aRequest.inserts.begin();
207  for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
208  {
209  QString name = ( *tiIt ).typeName;
210  if ( !typeNameList.contains( name ) )
211  typeNameList << name;
212  }
213  QList<transactionUpdate>::iterator tuIt = aRequest.updates.begin();
214  for ( ; tuIt != aRequest.updates.end(); ++tuIt )
215  {
216  QString name = ( *tuIt ).typeName;
217  if ( !typeNameList.contains( name ) )
218  typeNameList << name;
219  }
220  QList<transactionDelete>::iterator tdIt = aRequest.deletes.begin();
221  for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
222  {
223  QString name = ( *tdIt ).typeName;
224  if ( !typeNameList.contains( name ) )
225  typeNameList << name;
226  }
227 
228  // get access controls
229  QgsAccessControl *accessControl = serverIface->accessControls();
230 
231  //scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
232  //there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
233  std::unique_ptr< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
234 
235  // get layers
236  QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
240  QMap<QString, QgsVectorLayer *> mapLayerMap;
241  for ( int i = 0; i < wfsLayerIds.size(); ++i )
242  {
243  QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) );
244  if ( layer->type() != QgsMapLayer::LayerType::VectorLayer )
245  {
246  continue;
247  }
248 
249  QString name = layerTypeName( layer );
250 
251  if ( !typeNameList.contains( name ) )
252  {
253  continue;
254  }
255 
256  // get vector layer
257  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
258  if ( !vlayer )
259  {
260  throw QgsRequestNotWellFormedException( QStringLiteral( "Layer error on '%1'" ).arg( name ) );
261  }
262 
263  //get provider
264  QgsVectorDataProvider *provider = vlayer->dataProvider();
265  if ( !provider )
266  {
267  throw QgsRequestNotWellFormedException( QStringLiteral( "Provider error on layer '%1'" ).arg( name ) );
268  }
269 
270  // get provider capabilities
271  int cap = provider->capabilities();
274  {
275  throw QgsRequestNotWellFormedException( QStringLiteral( "No capabilities to do WFS changes on layer '%1'" ).arg( name ) );
276  }
277 
278  if ( !wfstUpdateLayerIds.contains( vlayer->id() )
279  && !wfstDeleteLayerIds.contains( vlayer->id() )
280  && !wfstInsertLayerIds.contains( vlayer->id() ) )
281  {
282  throw QgsSecurityAccessException( QStringLiteral( "No permissions to do WFS changes on layer '%1'" ).arg( name ) );
283  }
284  if ( accessControl && !accessControl->layerUpdatePermission( vlayer )
285  && !accessControl->layerDeletePermission( vlayer ) && !accessControl->layerInsertPermission( vlayer ) )
286  {
287  throw QgsSecurityAccessException( QStringLiteral( "No permissions to do WFS changes on layer '%1'" ).arg( name ) );
288  }
289 
290  if ( accessControl )
291  {
292  QgsOWSServerFilterRestorer::applyAccessControlLayerFilters( accessControl, vlayer, filterRestorer->originalFilters() );
293  }
294 
295  // store layers
296  mapLayerMap[name] = vlayer;
297  }
298 
299  // perform updates
300  tuIt = aRequest.updates.begin();
301  for ( ; tuIt != aRequest.updates.end(); ++tuIt )
302  {
303  transactionUpdate &action = *tuIt;
304  QString typeName = action.typeName;
305 
306  if ( !mapLayerMap.keys().contains( typeName ) )
307  {
308  action.error = true;
309  action.errorMsg = QStringLiteral( "TypeName '%1' unknown" ).arg( typeName );
310  continue;
311  }
312 
313  // get vector layer
314  QgsVectorLayer *vlayer = mapLayerMap[typeName];
315 
316  // verifying specific permissions
317  if ( !wfstUpdateLayerIds.contains( vlayer->id() ) )
318  {
319  action.error = true;
320  action.errorMsg = QStringLiteral( "No permissions to do WFS updates on layer '%1'" ).arg( typeName );
321  continue;
322  }
323  if ( accessControl && !accessControl->layerUpdatePermission( vlayer ) )
324  {
325  action.error = true;
326  action.errorMsg = QStringLiteral( "No permissions to do WFS updates on layer '%1'" ).arg( typeName );
327  continue;
328  }
329 
330  //get provider
331  QgsVectorDataProvider *provider = vlayer->dataProvider();
332 
333  // verifying specific capabilities
334  int cap = provider->capabilities();
336  {
337  action.error = true;
338  action.errorMsg = QStringLiteral( "No capabilities to do WFS updates on layer '%1'" ).arg( typeName );
339  continue;
340  }
341  // start editing
342  vlayer->startEditing();
343 
344  // update request
345  QgsFeatureRequest featureRequest = action.featureRequest;
346 
347  // expression context
348  QgsExpressionContext expressionContext;
349  expressionContext << QgsExpressionContextUtils::globalScope()
352  featureRequest.setExpressionContext( expressionContext );
353 
354  if ( accessControl )
355  {
356  accessControl->filterFeatures( vlayer, featureRequest );
357  }
358 
359  // get iterator
360  QgsFeatureIterator fit = vlayer->getFeatures( featureRequest );
361  QgsFeature feature;
362  // get action properties
363  QMap<QString, QString> propertyMap = action.propertyMap;
364  QDomElement geometryElem = action.geometryElement;
365  // get field information
366  QgsFields fields = provider->fields();
367  QMap<QString, int> fieldMap = provider->fieldNameMap();
368  QMap<QString, int>::const_iterator fieldMapIt;
369  QString fieldName;
370  bool conversionSuccess;
371  // Update the features
372  while ( fit.nextFeature( feature ) )
373  {
374  if ( accessControl && !accessControl->allowToEdit( vlayer, feature ) )
375  {
376  action.error = true;
377  action.errorMsg = QStringLiteral( "Feature modify permission denied on layer '%1'" ).arg( typeName );
378  vlayer->rollBack();
379  break;
380  }
381  QMap< QString, QString >::const_iterator it = propertyMap.constBegin();
382  for ( ; it != propertyMap.constEnd(); ++it )
383  {
384  fieldName = it.key();
385  fieldMapIt = fieldMap.find( fieldName );
386  if ( fieldMapIt == fieldMap.constEnd() )
387  {
388  continue;
389  }
390  QgsField field = fields.at( fieldMapIt.value() );
391  QVariant value = it.value();
392  if ( value.isNull() )
393  {
394  if ( field.constraints().constraints() & QgsFieldConstraints::Constraint::ConstraintNotNull )
395  {
396  action.error = true;
397  action.errorMsg = QStringLiteral( "NOT NULL constraint error on layer '%1', field '%2'" ).arg( typeName, field.name() );
398  vlayer->rollBack();
399  break;
400  }
401  }
402  else // Not NULL
403  {
404  if ( field.type() == QVariant::Type::Int )
405  {
406  value = it.value().toInt( &conversionSuccess );
407  if ( !conversionSuccess )
408  {
409  action.error = true;
410  action.errorMsg = QStringLiteral( "Property conversion error on layer '%1'" ).arg( typeName );
411  vlayer->rollBack();
412  break;
413  }
414  }
415  else if ( field.type() == QVariant::Type::Double )
416  {
417  value = it.value().toDouble( &conversionSuccess );
418  if ( !conversionSuccess )
419  {
420  action.error = true;
421  action.errorMsg = QStringLiteral( "Property conversion error on layer '%1'" ).arg( typeName );
422  vlayer->rollBack();
423  break;
424  }
425  }
426  else if ( field.type() == QVariant::Type::LongLong )
427  {
428  value = it.value().toLongLong( &conversionSuccess );
429  if ( !conversionSuccess )
430  {
431  action.error = true;
432  action.errorMsg = QStringLiteral( "Property conversion error on layer '%1'" ).arg( typeName );
433  vlayer->rollBack();
434  break;
435  }
436  }
437  }
438  vlayer->changeAttributeValue( feature.id(), fieldMapIt.value(), value );
439  }
440  if ( action.error )
441  {
442  break;
443  }
444 
445  if ( !geometryElem.isNull() )
446  {
447  QgsGeometry g = QgsOgcUtils::geometryFromGML( geometryElem );
448  if ( g.isNull() )
449  {
450  action.error = true;
451  action.errorMsg = QStringLiteral( "Geometry from GML error on layer '%1'" ).arg( typeName );
452  vlayer->rollBack();
453  break;
454  }
455  if ( !vlayer->changeGeometry( feature.id(), g ) )
456  {
457  action.error = true;
458  action.errorMsg = QStringLiteral( "Error in change geometry on layer '%1'" ).arg( typeName );
459  vlayer->rollBack();
460  break;
461  }
462  }
463  }
464  if ( action.error )
465  {
466  continue;
467  }
468  // verifying changes
469  if ( accessControl )
470  {
471  fit = vlayer->getFeatures( featureRequest );
472  while ( fit.nextFeature( feature ) )
473  {
474  if ( accessControl && !accessControl->allowToEdit( vlayer, feature ) )
475  {
476  action.error = true;
477  action.errorMsg = QStringLiteral( "Feature modify permission denied on layer '%1'" ).arg( typeName );
478  vlayer->rollBack();
479  break;
480  }
481  }
482  }
483  if ( action.error )
484  {
485  continue;
486  }
487 
488  // Commit the changes of the update elements
489  if ( !vlayer->commitChanges() )
490  {
491  action.error = true;
492  action.errorMsg = QStringLiteral( "Error committing updates: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
493  vlayer->rollBack();
494  continue;
495  }
496  // all the changes are OK!
497  action.error = false;
498 
499  }
500 
501  // perform deletes
502  tdIt = aRequest.deletes.begin();
503  for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
504  {
505  transactionDelete &action = *tdIt;
506  QString typeName = action.typeName;
507 
508  if ( !mapLayerMap.keys().contains( typeName ) )
509  {
510  action.error = true;
511  action.errorMsg = QStringLiteral( "TypeName '%1' unknown" ).arg( typeName );
512  continue;
513  }
514 
515  // get vector layer
516  QgsVectorLayer *vlayer = mapLayerMap[typeName];
517 
518  // verifying specific permissions
519  if ( !wfstDeleteLayerIds.contains( vlayer->id() ) )
520  {
521  action.error = true;
522  action.errorMsg = QStringLiteral( "No permissions to do WFS deletes on layer '%1'" ).arg( typeName );
523  continue;
524  }
525  if ( accessControl && !accessControl->layerDeletePermission( vlayer ) )
526  {
527  action.error = true;
528  action.errorMsg = QStringLiteral( "No permissions to do WFS deletes on layer '%1'" ).arg( typeName );
529  continue;
530  }
531 
532  //get provider
533  QgsVectorDataProvider *provider = vlayer->dataProvider();
534 
535  // verifying specific capabilities
536  int cap = provider->capabilities();
537  if ( !( cap & QgsVectorDataProvider::DeleteFeatures ) )
538  {
539  action.error = true;
540  action.errorMsg = QStringLiteral( "No capabilities to do WFS deletes on layer '%1'" ).arg( typeName );
541  continue;
542  }
543  // start editing
544  vlayer->startEditing();
545 
546  // update request
547  QgsFeatureRequest featureRequest = action.featureRequest;
548 
549  // expression context
550  QgsExpressionContext expressionContext;
551  expressionContext << QgsExpressionContextUtils::globalScope()
554  featureRequest.setExpressionContext( expressionContext );
555 
556  // get iterator
557  QgsFeatureIterator fit = vlayer->getFeatures( featureRequest );
558  QgsFeature feature;
559  // get deleted fids
560  QgsFeatureIds fids;
561  while ( fit.nextFeature( feature ) )
562  {
563  if ( accessControl && !accessControl->allowToEdit( vlayer, feature ) )
564  {
565  action.error = true;
566  action.errorMsg = QStringLiteral( "Feature modify permission denied" );
567  vlayer->rollBack();
568  break;
569  }
570  fids << feature.id();
571  }
572  if ( action.error )
573  {
574  continue;
575  }
576  // delete features
577  if ( !vlayer->deleteFeatures( fids ) )
578  {
579  action.error = true;
580  action.errorMsg = QStringLiteral( "Delete features failed on layer '%1'" ).arg( typeName );
581  vlayer->rollBack();
582  continue;
583  }
584 
585  // Commit the changes of the update elements
586  if ( !vlayer->commitChanges() )
587  {
588  action.error = true;
589  action.errorMsg = QStringLiteral( "Error committing deletes: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
590  vlayer->rollBack();
591  continue;
592  }
593  // all the changes are OK!
594  action.error = false;
595  }
596 
597  // perform inserts
598  tiIt = aRequest.inserts.begin();
599  for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
600  {
601  transactionInsert &action = *tiIt;
602  QString typeName = action.typeName;
603 
604  if ( !mapLayerMap.keys().contains( typeName ) )
605  {
606  action.error = true;
607  action.errorMsg = QStringLiteral( "TypeName '%1' unknown" ).arg( typeName );
608  continue;
609  }
610 
611  // get vector layer
612  QgsVectorLayer *vlayer = mapLayerMap[typeName];
613 
614  // verifying specific permissions
615  if ( !wfstInsertLayerIds.contains( vlayer->id() ) )
616  {
617  action.error = true;
618  action.errorMsg = QStringLiteral( "No permissions to do WFS inserts on layer '%1'" ).arg( typeName );
619  continue;
620  }
621  if ( accessControl && !accessControl->layerDeletePermission( vlayer ) )
622  {
623  action.error = true;
624  action.errorMsg = QStringLiteral( "No permissions to do WFS inserts on layer '%1'" ).arg( typeName );
625  continue;
626  }
627 
628  //get provider
629  QgsVectorDataProvider *provider = vlayer->dataProvider();
630 
631  // verifying specific capabilities
632  int cap = provider->capabilities();
633  if ( !( cap & QgsVectorDataProvider::AddFeatures ) )
634  {
635  action.error = true;
636  action.errorMsg = QStringLiteral( "No capabilities to do WFS inserts on layer '%1'" ).arg( typeName );
637  continue;
638  }
639 
640  // start editing
641  vlayer->startEditing();
642 
643  // get inserting features
644  QgsFeatureList featureList;
645  try
646  {
647  featureList = featuresFromGML( action.featureNodeList, provider );
648  }
649  catch ( QgsOgcServiceException &ex )
650  {
651  action.error = true;
652  action.errorMsg = QStringLiteral( "%1 '%2'" ).arg( ex.message() ).arg( typeName );
653  continue;
654  }
655  // control features
656  if ( accessControl )
657  {
658  QgsFeatureList::iterator featureIt = featureList.begin();
659  while ( featureIt != featureList.end() )
660  {
661  if ( !accessControl->allowToEdit( vlayer, *featureIt ) )
662  {
663  action.error = true;
664  action.errorMsg = QStringLiteral( "Feature modify permission denied on layer '%1'" ).arg( typeName );
665  vlayer->rollBack();
666  break;
667  }
668  featureIt++;
669  }
670  }
671  if ( action.error )
672  {
673  continue;
674  }
675 
676  // perform add features
677  if ( !provider->addFeatures( featureList ) )
678  {
679  action.error = true;
680  action.errorMsg = QStringLiteral( "Insert features failed on layer '%1'" ).arg( typeName );
681  if ( provider ->hasErrors() )
682  {
683  provider->clearErrors();
684  }
685  vlayer->rollBack();
686  continue;
687  }
688 
689  // Commit the changes of the update elements
690  if ( !vlayer->commitChanges() )
691  {
692  action.error = true;
693  action.errorMsg = QStringLiteral( "Error committing inserts: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
694  vlayer->rollBack();
695  continue;
696  }
697  // all changes are OK!
698  action.error = false;
699 
700  // Get the Feature Ids of the inserted feature
701  for ( int j = 0; j < featureList.size(); j++ )
702  {
703  action.insertFeatureIds << typeName + "." + QString::number( featureList[j].id() );
704  }
705  }
706 
707  //force restoration of original layer filters
708  filterRestorer.reset();
709  }
710 
711  QgsFeatureList featuresFromGML( QDomNodeList featureNodeList, QgsVectorDataProvider *provider )
712  {
713  // Store the inserted features
714  QgsFeatureList featList;
715 
716  // Get Layer Field Information
717  QgsFields fields = provider->fields();
718  QMap<QString, int> fieldMap = provider->fieldNameMap();
719  QMap<QString, int>::const_iterator fieldMapIt;
720 
721  for ( int i = 0; i < featureNodeList.count(); i++ )
722  {
723  QgsFeature feat( fields );
724 
725  QDomElement featureElem = featureNodeList.at( i ).toElement();
726  QDomNode currentAttributeChild = featureElem.firstChild();
727  bool conversionSuccess = true;
728 
729  while ( !currentAttributeChild.isNull() )
730  {
731  QDomElement currentAttributeElement = currentAttributeChild.toElement();
732  QString attrName = currentAttributeElement.localName();
733 
734  if ( attrName != QLatin1String( "boundedBy" ) )
735  {
736  if ( attrName != QLatin1String( "geometry" ) ) //a normal attribute
737  {
738  fieldMapIt = fieldMap.find( attrName );
739  if ( fieldMapIt == fieldMap.constEnd() )
740  {
741  continue;
742  }
743 
744  QgsField field = fields.at( fieldMapIt.value() );
745  QString attrValue = currentAttributeElement.text();
746  int attrType = field.type();
747 
748  QgsMessageLog::logMessage( QStringLiteral( "attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) );
749 
750  if ( attrType == QVariant::Int )
751  feat.setAttribute( fieldMapIt.value(), attrValue.toInt( &conversionSuccess ) );
752  else if ( attrType == QVariant::Double )
753  feat.setAttribute( fieldMapIt.value(), attrValue.toDouble( &conversionSuccess ) );
754  else
755  feat.setAttribute( fieldMapIt.value(), attrValue );
756 
757  if ( !conversionSuccess )
758  {
759  throw QgsRequestNotWellFormedException( QStringLiteral( "Property conversion error on layer insert" ) );
760  }
761  }
762  else //a geometry attribute
763  {
764  QgsGeometry g = QgsOgcUtils::geometryFromGML( currentAttributeElement );
765  if ( g.isNull() )
766  {
767  throw QgsRequestNotWellFormedException( QStringLiteral( "Geometry from GML error on layer insert" ) );
768  }
769  feat.setGeometry( g );
770  }
771  }
772  currentAttributeChild = currentAttributeChild.nextSibling();
773  }
774  // update feature list
775  featList << feat;
776  }
777  return featList;
778  }
779 
781  {
782  if ( !parameters.contains( QStringLiteral( "OPERATION" ) ) )
783  {
784  throw QgsRequestNotWellFormedException( QStringLiteral( "OPERATION parameter is mandatory" ) );
785  }
786  if ( parameters.value( QStringLiteral( "OPERATION" ) ).toUpper() != QStringLiteral( "DELETE" ) )
787  {
788  throw QgsRequestNotWellFormedException( QStringLiteral( "Only DELETE value is defined for OPERATION parameter" ) );
789  }
790 
791  // Verifying parameters mutually exclusive
792  if ( ( parameters.contains( QStringLiteral( "FEATUREID" ) )
793  && ( parameters.contains( QStringLiteral( "FILTER" ) ) || parameters.contains( QStringLiteral( "BBOX" ) ) ) )
794  || ( parameters.contains( QStringLiteral( "FILTER" ) )
795  && ( parameters.contains( QStringLiteral( "FEATUREID" ) ) || parameters.contains( QStringLiteral( "BBOX" ) ) ) )
796  || ( parameters.contains( QStringLiteral( "BBOX" ) )
797  && ( parameters.contains( QStringLiteral( "FEATUREID" ) ) || parameters.contains( QStringLiteral( "FILTER" ) ) ) )
798  )
799  {
800  throw QgsRequestNotWellFormedException( QStringLiteral( "FEATUREID FILTER and BBOX parameters are mutually exclusive" ) );
801  }
802 
803  transactionRequest request;
804 
805  QStringList typeNameList;
806  // parse FEATUREID
807  if ( parameters.contains( QStringLiteral( "FEATUREID" ) ) )
808  {
809  QStringList fidList = parameters.value( QStringLiteral( "FEATUREID" ) ).split( ',' );
810 
811  QMap<QString, QgsFeatureIds> fidsMap;
812 
813  QStringList::const_iterator fidIt = fidList.constBegin();
814  for ( ; fidIt != fidList.constEnd(); ++fidIt )
815  {
816  // Get FeatureID
817  QString fid = *fidIt;
818  fid = fid.trimmed();
819  // testing typename in the WFS featureID
820  if ( !fid.contains( '.' ) )
821  {
822  throw QgsRequestNotWellFormedException( QStringLiteral( "FEATUREID has to have TYPENAME in the values" ) );
823  }
824 
825  QString typeName = fid.section( '.', 0, 0 );
826  fid = fid.section( '.', 1, 1 );
827  if ( !typeNameList.contains( typeName ) )
828  {
829  typeNameList << typeName;
830  }
831 
832  QgsFeatureIds fids;
833  if ( fidsMap.contains( typeName ) )
834  {
835  fids = fidsMap.value( typeName );
836  }
837  fids.insert( fid.toInt() );
838  fidsMap.insert( typeName, fids );
839  }
840 
841  QMap<QString, QgsFeatureIds>::const_iterator fidsMapIt = fidsMap.constBegin();
842  while ( fidsMapIt != fidsMap.constEnd() )
843  {
844  transactionDelete action;
845  action.typeName = fidsMapIt.key();
846 
847  QgsFeatureIds fids = fidsMapIt.value();
848  action.featureRequest = QgsFeatureRequest( fids );
849 
850  request.deletes.append( action );
851  }
852  return request;
853  }
854 
855  if ( !parameters.contains( QStringLiteral( "TYPENAME" ) ) )
856  {
857  throw QgsRequestNotWellFormedException( QStringLiteral( "TYPENAME is mandatory except if FEATUREID is used" ) );
858  }
859 
860  typeNameList = parameters.value( QStringLiteral( "TYPENAME" ) ).split( ',' );
861 
862  // Create actions based on TypeName
863  QStringList::const_iterator typeNameIt = typeNameList.constBegin();
864  for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
865  {
866  QString typeName = *typeNameIt;
867  typeName = typeName.trimmed();
868 
869  transactionDelete action;
870  action.typeName = typeName;
871 
872  request.deletes.append( action );
873  }
874 
875  // Manage extra parameter exp_filter
876  if ( parameters.contains( QStringLiteral( "EXP_FILTER" ) ) )
877  {
878  QString expFilterName = parameters.value( QStringLiteral( "EXP_FILTER" ) );
879  QStringList expFilterList;
880  QRegExp rx( "\\(([^()]+)\\)" );
881  if ( rx.indexIn( expFilterName, 0 ) == -1 )
882  {
883  expFilterList << expFilterName;
884  }
885  else
886  {
887  int pos = 0;
888  while ( ( pos = rx.indexIn( expFilterName, pos ) ) != -1 )
889  {
890  expFilterList << rx.cap( 1 );
891  pos += rx.matchedLength();
892  }
893  }
894 
895  // Verifying the 1:1 mapping between TYPENAME and EXP_FILTER but without exception
896  if ( request.deletes.size() == expFilterList.size() )
897  {
898  // set feature request filter expression based on filter element
899  QList<transactionDelete>::iterator dIt = request.deletes.begin();
900  QStringList::const_iterator expFilterIt = expFilterList.constBegin();
901  for ( ; dIt != request.deletes.end(); ++dIt )
902  {
903  transactionDelete &action = *dIt;
904  // Get Filter for this typeName
905  QString expFilter;
906  if ( expFilterIt != expFilterList.constEnd() )
907  {
908  expFilter = *expFilterIt;
909  }
910  std::shared_ptr<QgsExpression> filter( new QgsExpression( expFilter ) );
911  if ( filter )
912  {
913  if ( filter->hasParserError() )
914  {
915  QgsMessageLog::logMessage( filter->parserErrorString() );
916  }
917  else
918  {
919  if ( filter->needsGeometry() )
920  {
922  }
923  action.featureRequest.setFilterExpression( filter->expression() );
924  }
925  }
926  }
927  }
928  else
929  {
930  QgsMessageLog::logMessage( "There has to be a 1:1 mapping between each element in a TYPENAME and the EXP_FILTER list" );
931  }
932  }
933 
934  if ( parameters.contains( QStringLiteral( "BBOX" ) ) )
935  {
936  // get bbox value
937  QString bbox = parameters.value( QStringLiteral( "BBOX" ) );
938  if ( bbox.isEmpty() )
939  {
940  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX parameter is empty" ) );
941  }
942 
943  // get bbox corners
944  QStringList corners = bbox.split( ',' );
945  if ( corners.size() != 4 )
946  {
947  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX has to be composed of 4 elements: '%1'" ).arg( bbox ) );
948  }
949 
950  // convert corners to double
951  double d[4];
952  bool ok;
953  for ( int i = 0; i < 4; i++ )
954  {
955  corners[i].replace( ' ', '+' );
956  d[i] = corners[i].toDouble( &ok );
957  if ( !ok )
958  {
959  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX has to be composed of 4 double: '%1'" ).arg( bbox ) );
960  }
961  }
962  // create extent
963  QgsRectangle extent( d[0], d[1], d[2], d[3] );
964 
965  // set feature request filter rectangle
966  QList<transactionDelete>::iterator dIt = request.deletes.begin();
967  for ( ; dIt != request.deletes.end(); ++dIt )
968  {
969  transactionDelete &action = *dIt;
970  action.featureRequest.setFilterRect( extent );
971  }
972  return request;
973  }
974  else if ( parameters.contains( QStringLiteral( "FILTER" ) ) )
975  {
976  QString filterName = parameters.value( QStringLiteral( "FILTER" ) );
977  QStringList filterList;
978  QRegExp rx( "\\(([^()]+)\\)" );
979  if ( rx.indexIn( filterName, 0 ) == -1 )
980  {
981  filterList << filterName;
982  }
983  else
984  {
985  int pos = 0;
986  while ( ( pos = rx.indexIn( filterName, pos ) ) != -1 )
987  {
988  filterList << rx.cap( 1 );
989  pos += rx.matchedLength();
990  }
991  }
992 
993  // Verifying the 1:1 mapping between TYPENAME and FILTER
994  if ( request.deletes.size() != filterList.size() )
995  {
996  throw QgsRequestNotWellFormedException( QStringLiteral( "There has to be a 1:1 mapping between each element in a TYPENAME and the FILTER list" ) );
997  }
998 
999  // set feature request filter expression based on filter element
1000  QList<transactionDelete>::iterator dIt = request.deletes.begin();
1001  QStringList::const_iterator filterIt = filterList.constBegin();
1002  for ( ; dIt != request.deletes.end(); ++dIt )
1003  {
1004  transactionDelete &action = *dIt;
1005 
1006  // Get Filter for this typeName
1007  QDomDocument filter;
1008  if ( filterIt != filterList.constEnd() )
1009  {
1010  QString errorMsg;
1011  if ( !filter.setContent( *filterIt, true, &errorMsg ) )
1012  {
1013  throw QgsRequestNotWellFormedException( QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, *filterIt ) );
1014  }
1015  }
1016 
1017  QDomElement filterElem = filter.firstChildElement();
1018  action.featureRequest = parseFilterElement( action.typeName, filterElem );
1019 
1020  if ( filterIt != filterList.constEnd() )
1021  {
1022  ++filterIt;
1023  }
1024  }
1025  return request;
1026  }
1027 
1028  return request;
1029  }
1030 
1032  {
1033  transactionRequest request;
1034 
1035  QDomNodeList docChildNodes = docElem.childNodes();
1036 
1037  QDomElement actionElem;
1038  QString actionName;
1039 
1040  for ( int i = docChildNodes.count(); 0 < i; --i )
1041  {
1042  actionElem = docChildNodes.at( i - 1 ).toElement();
1043  actionName = actionElem.localName();
1044 
1045  if ( actionName == QLatin1String( "Insert" ) )
1046  {
1047  transactionInsert action = parseInsertActionElement( actionElem );
1048  request.inserts.append( action );
1049  }
1050  else if ( actionName == QLatin1String( "Update" ) )
1051  {
1052  transactionUpdate action = parseUpdateActionElement( actionElem );
1053  request.updates.append( action );
1054  }
1055  else if ( actionName == QLatin1String( "Delete" ) )
1056  {
1057  transactionDelete action = parseDeleteActionElement( actionElem );
1058  request.deletes.append( action );
1059  }
1060  }
1061 
1062  return request;
1063  }
1064 
1065  transactionDelete parseDeleteActionElement( QDomElement &actionElem )
1066  {
1067  QString typeName = actionElem.attribute( QStringLiteral( "typeName" ) );
1068  if ( typeName.contains( ':' ) )
1069  typeName = typeName.section( ':', 1, 1 );
1070 
1071  QDomElement filterElem = actionElem.firstChild().toElement();
1072  if ( filterElem.tagName() != QLatin1String( "Filter" ) )
1073  {
1074  throw QgsRequestNotWellFormedException( QStringLiteral( "Delete action element first child is not Filter" ) );
1075  }
1076 
1077  QgsFeatureRequest featureRequest = parseFilterElement( typeName, filterElem );
1078 
1079  transactionDelete action;
1080  action.typeName = typeName;
1081  action.featureRequest = featureRequest;
1082  action.error = false;
1083 
1084  if ( actionElem.hasAttribute( QStringLiteral( "handle" ) ) )
1085  {
1086  action.handle = actionElem.attribute( QStringLiteral( "handle" ) );
1087  }
1088 
1089  return action;
1090  }
1091 
1092  transactionUpdate parseUpdateActionElement( QDomElement &actionElem )
1093  {
1094  QString typeName = actionElem.attribute( QStringLiteral( "typeName" ) );
1095  if ( typeName.contains( ':' ) )
1096  typeName = typeName.section( ':', 1, 1 );
1097 
1098  QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral( "Property" ) );
1099  if ( propertyNodeList.isEmpty() )
1100  {
1101  throw QgsRequestNotWellFormedException( QStringLiteral( "Update action element must have one or more Property element" ) );
1102  }
1103 
1104  QMap<QString, QString> propertyMap;
1105  QDomElement propertyElem;
1106  QDomElement nameElem;
1107  QDomElement valueElem;
1108  QDomElement geometryElem;
1109 
1110  for ( int l = 0; l < propertyNodeList.count(); ++l )
1111  {
1112  propertyElem = propertyNodeList.at( l ).toElement();
1113  nameElem = propertyElem.elementsByTagName( QStringLiteral( "Name" ) ).at( 0 ).toElement();
1114  valueElem = propertyElem.elementsByTagName( QStringLiteral( "Value" ) ).at( 0 ).toElement();
1115  if ( nameElem.text() != QLatin1String( "geometry" ) )
1116  {
1117  propertyMap.insert( nameElem.text(), valueElem.text() );
1118  }
1119  else
1120  {
1121  geometryElem = valueElem;
1122  }
1123  }
1124 
1125  QDomNodeList filterNodeList = actionElem.elementsByTagName( QStringLiteral( "Filter" ) );
1126  QgsFeatureRequest featureRequest;
1127  if ( filterNodeList.size() != 0 )
1128  {
1129  QDomElement filterElem = filterNodeList.at( 0 ).toElement();
1130  featureRequest = parseFilterElement( typeName, filterElem );
1131  }
1132 
1133  transactionUpdate action;
1134  action.typeName = typeName;
1135  action.propertyMap = propertyMap;
1136  action.geometryElement = geometryElem;
1137  action.featureRequest = featureRequest;
1138  action.error = false;
1139 
1140  if ( actionElem.hasAttribute( QStringLiteral( "handle" ) ) )
1141  {
1142  action.handle = actionElem.attribute( QStringLiteral( "handle" ) );
1143  }
1144 
1145  return action;
1146  }
1147 
1148  transactionInsert parseInsertActionElement( QDomElement &actionElem )
1149  {
1150  QDomNodeList featureNodeList = actionElem.childNodes();
1151  if ( featureNodeList.size() != 1 )
1152  {
1153  throw QgsRequestNotWellFormedException( QStringLiteral( "Insert action element must have one or more child node" ) );
1154  }
1155 
1156  QString typeName;
1157  for ( int i = 0; i < featureNodeList.count(); ++i )
1158  {
1159  QString tempTypeName = featureNodeList.at( i ).toElement().localName();
1160  if ( tempTypeName.contains( ':' ) )
1161  tempTypeName = tempTypeName.section( ':', 1, 1 );
1162 
1163  if ( typeName.isEmpty() )
1164  {
1165  typeName = tempTypeName;
1166  }
1167  else if ( tempTypeName != typeName )
1168  {
1169  throw QgsRequestNotWellFormedException( QStringLiteral( "Insert action element must have one typename features" ) );
1170  }
1171  }
1172 
1173  transactionInsert action;
1174  action.typeName = typeName;
1175  action.featureNodeList = featureNodeList;
1176  action.error = false;
1177 
1178  if ( actionElem.hasAttribute( QStringLiteral( "handle" ) ) )
1179  {
1180  action.handle = actionElem.attribute( QStringLiteral( "handle" ) );
1181  }
1182 
1183  return action;
1184  }
1185 
1186  namespace
1187  {
1188 
1189  void addTransactionResult( QDomDocument &responseDoc, QDomElement &responseElem, const QString &status,
1190  const QString &locator, const QString &message )
1191  {
1192  QDomElement trElem = responseDoc.createElement( QStringLiteral( "TransactionResult" ) );
1193  QDomElement stElem = responseDoc.createElement( QStringLiteral( "Status" ) );
1194  QDomElement successElem = responseDoc.createElement( status );
1195  stElem.appendChild( successElem );
1196  trElem.appendChild( stElem );
1197  responseElem.appendChild( trElem );
1198 
1199  if ( !locator.isEmpty() )
1200  {
1201  QDomElement locElem = responseDoc.createElement( QStringLiteral( "Locator" ) );
1202  locElem.appendChild( responseDoc.createTextNode( locator ) );
1203  trElem.appendChild( locElem );
1204  }
1205 
1206  if ( !message.isEmpty() )
1207  {
1208  QDomElement mesElem = responseDoc.createElement( QStringLiteral( "Message" ) );
1209  mesElem.appendChild( responseDoc.createTextNode( message ) );
1210  trElem.appendChild( mesElem );
1211  }
1212  }
1213 
1214  }
1215 
1216  } // namespace v1_0_0
1217 } // namespace QgsWfs
1218 
1219 
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:64
bool layerInsertPermission(const QgsVectorLayer *layer) const
Returns the layer insert right.
Wrapper for iterator of features from vector data provider or vector layer.
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Base class for all map layer types.
Definition: qgsmaplayer.h:64
SERVER_EXPORT QStringList wfstUpdateLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
QMap< QString, int > fieldNameMap() const
Returns a map where the key is the name of the field and the value is its index.
QString name
Definition: qgsfield.h:58
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
bool commitChanges()
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
bool startEditing()
Makes the layer editable.
Exception base class for service exceptions.
bool deleteFeatures(const QgsFeatureIds &fids)
Deletes a set of features from the layer (but does not commit it)
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
QString message() const
Returns the exception message.
bool layerDeletePermission(const QgsVectorLayer *layer) const
Returns the layer delete right.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device...
QgsMapLayer::LayerType type() const
Returns the type of the layer.
transactionUpdate parseUpdateActionElement(QDomElement &actionElem)
Transform Update element to transactionUpdate.
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
Definition: qgswfsutils.cpp:71
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
static void applyAccessControlLayerFilters(const QgsAccessControl *accessControl, QgsMapLayer *mapLayer, QHash< QgsMapLayer *, QString > &originalLayerFilters)
Apply filter from AccessControl.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
transactionRequest parseTransactionRequestBody(QDomElement &docElem)
Transform RequestBody root element to getFeatureRequest.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature&#39;s geometry within the layer&#39;s edit buffer (but does not immediately commit the chan...
bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
Exception thrown in case of malformed request.
SERVER_EXPORT QStringList wfstDeleteLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities...
QgsFields fields() const override=0
Returns the fields associated with this data provider.
const QString & typeName
WMS implementation.
Definition: qgswfs.cpp:35
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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).
This class wraps a request for features to a vector layer (or directly its vector data provider)...
const QString WFS_NAMESPACE
Definition: qgswfsutils.h:66
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureRequest parseFilterElement(const QString &typeName, QDomElement &filterElem, const QgsProject *project)
Transform a Filter element to a feature request.
Allows modifications of geometries.
Reads and writes project states.
Definition: qgsproject.h:89
void clearErrors()
Clear recorded errors.
transactionRequest parseTransactionParameters(QgsServerRequest::Parameters parameters)
transactionInsert parseInsertActionElement(QDomElement &actionElem)
Transform Insert element to transactionInsert.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
const QString OGC_NAMESPACE
Definition: qgswfsutils.h:68
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
static QgsGeometry geometryFromGML(const QString &xmlString)
Static method that creates geometry from GML.
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
QgsFieldConstraints constraints
Definition: qgsfield.h:61
void writeTransaction(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS transaction response.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
RAII class to restore layer filters on destruction.
A helper class that centralizes restrictions given by all the access control filter plugins...
QgsFeatureList featuresFromGML(QDomNodeList featureNodeList, QgsVectorDataProvider *provider)
Transform GML feature nodes to features.
void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures) const override
Filter the features of the layer.
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
SERVER_EXPORT QStringList wfstInsertLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities...
Exception thrown when data access violates access controls.
bool layerUpdatePermission(const QgsVectorLayer *layer) const
Returns the layer update right.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be null.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
Represents a vector layer which manages a vector based data sets.
transactionDelete parseDeleteActionElement(QDomElement &actionElem)
Transform Delete element to transactionDelete.
void performTransaction(transactionRequest &aRequest, QgsServerInterface *serverIface, const QgsProject *project)
Perform the transaction.
Allows modification of attribute values.
QVariant::Type type
Definition: qgsfield.h:56
QDomDocument createTransactionDocument(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request)
Create a wfs transaction document.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QMap< QString, QString > Parameters
bool allowToEdit(const QgsVectorLayer *layer, const QgsFeature &feature) const
Are we authorized to modify the following geometry.