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