QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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( QStringLiteral( "; " ) );
189  QString message = errorMessages.join( QStringLiteral( "; " ) );
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  QgsGeometry g = QgsOgcUtils::geometryFromGML( geometryElem );
465  if ( g.isNull() )
466  {
467  action.error = true;
468  action.errorMsg = QStringLiteral( "Geometry from GML error on layer '%1'" ).arg( typeName );
469  vlayer->rollBack();
470  break;
471  }
472  if ( !vlayer->changeGeometry( feature.id(), g ) )
473  {
474  action.error = true;
475  action.errorMsg = QStringLiteral( "Error in change geometry on layer '%1'" ).arg( typeName );
476  vlayer->rollBack();
477  break;
478  }
479  }
480  }
481  if ( action.error )
482  {
483  continue;
484  }
485 #ifdef HAVE_SERVER_PYTHON_PLUGINS
486  // verifying changes
487  if ( accessControl )
488  {
489  fit = vlayer->getFeatures( featureRequest );
490  while ( fit.nextFeature( feature ) )
491  {
492  if ( accessControl && !accessControl->allowToEdit( vlayer, feature ) )
493  {
494  action.error = true;
495  action.errorMsg = QStringLiteral( "Feature modify permission denied on layer '%1'" ).arg( typeName );
496  vlayer->rollBack();
497  break;
498  }
499  }
500  }
501  if ( action.error )
502  {
503  continue;
504  }
505 #endif
506 
507  // Commit the changes of the update elements
508  if ( !vlayer->commitChanges() )
509  {
510  action.error = true;
511  action.errorMsg = QStringLiteral( "Error committing updates: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
512  vlayer->rollBack();
513  continue;
514  }
515  // all the changes are OK!
516  action.error = false;
517 
518  }
519 
520  // perform deletes
521  tdIt = aRequest.deletes.begin();
522  for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
523  {
524  transactionDelete &action = *tdIt;
525  QString typeName = action.typeName;
526 
527  if ( !mapLayerMap.keys().contains( typeName ) )
528  {
529  action.error = true;
530  action.errorMsg = QStringLiteral( "TypeName '%1' unknown" ).arg( typeName );
531  continue;
532  }
533 
534  // get vector layer
535  QgsVectorLayer *vlayer = mapLayerMap[typeName];
536 
537  // verifying specific permissions
538  if ( !wfstDeleteLayerIds.contains( vlayer->id() ) )
539  {
540  action.error = true;
541  action.errorMsg = QStringLiteral( "No permissions to do WFS deletes on layer '%1'" ).arg( typeName );
542  continue;
543  }
544 #ifdef HAVE_SERVER_PYTHON_PLUGINS
545  if ( accessControl && !accessControl->layerDeletePermission( vlayer ) )
546  {
547  action.error = true;
548  action.errorMsg = QStringLiteral( "No permissions to do WFS deletes on layer '%1'" ).arg( typeName );
549  continue;
550  }
551 #endif
552  //get provider
553  QgsVectorDataProvider *provider = vlayer->dataProvider();
554 
555  // verifying specific capabilities
556  int cap = provider->capabilities();
557  if ( !( cap & QgsVectorDataProvider::DeleteFeatures ) )
558  {
559  action.error = true;
560  action.errorMsg = QStringLiteral( "No capabilities to do WFS deletes on layer '%1'" ).arg( typeName );
561  continue;
562  }
563  // start editing
564  vlayer->startEditing();
565 
566  // delete request
567  QgsFeatureRequest featureRequest = action.featureRequest;
568 
569  // expression context
570  QgsExpressionContext expressionContext;
571  expressionContext << QgsExpressionContextUtils::globalScope()
574  featureRequest.setExpressionContext( expressionContext );
575 
576  // verifying feature ids list
577  if ( action.serverFids.isEmpty() )
578  {
579  action.error = true;
580  action.errorMsg = QStringLiteral( "No feature ids to do WFS deletes on layer '%1'" ).arg( typeName );
581  continue;
582  }
583 
584  // update request based on feature ids
585  QgsServerFeatureId::updateFeatureRequestFromServerFids( featureRequest, action.serverFids, provider );
586 
587 #ifdef HAVE_SERVER_PYTHON_PLUGINS
588  if ( accessControl )
589  {
590  accessControl->filterFeatures( vlayer, featureRequest );
591  }
592 #endif
593 
594  // get iterator
595  QgsFeatureIterator fit = vlayer->getFeatures( featureRequest );
596  QgsFeature feature;
597  // get deleted fids
598  QgsFeatureIds fids;
599  while ( fit.nextFeature( feature ) )
600  {
601 #ifdef HAVE_SERVER_PYTHON_PLUGINS
602  if ( accessControl && !accessControl->allowToEdit( vlayer, feature ) )
603  {
604  action.error = true;
605  action.errorMsg = QStringLiteral( "Feature modify permission denied" );
606  vlayer->rollBack();
607  break;
608  }
609 #endif
610  fids << feature.id();
611  }
612  if ( action.error )
613  {
614  continue;
615  }
616  // delete features
617  if ( !vlayer->deleteFeatures( fids ) )
618  {
619  action.error = true;
620  action.errorMsg = QStringLiteral( "Delete features failed on layer '%1'" ).arg( typeName );
621  vlayer->rollBack();
622  continue;
623  }
624 
625  // Commit the changes of the update elements
626  if ( !vlayer->commitChanges() )
627  {
628  action.error = true;
629  action.errorMsg = QStringLiteral( "Error committing deletes: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
630  vlayer->rollBack();
631  continue;
632  }
633  // all the changes are OK!
634  action.error = false;
635  }
636 
637  // perform inserts
638  tiIt = aRequest.inserts.begin();
639  for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
640  {
641  transactionInsert &action = *tiIt;
642  QString typeName = action.typeName;
643 
644  if ( !mapLayerMap.keys().contains( typeName ) )
645  {
646  action.error = true;
647  action.errorMsg = QStringLiteral( "TypeName '%1' unknown" ).arg( typeName );
648  continue;
649  }
650 
651  // get vector layer
652  QgsVectorLayer *vlayer = mapLayerMap[typeName];
653 
654  // verifying specific permissions
655  if ( !wfstInsertLayerIds.contains( vlayer->id() ) )
656  {
657  action.error = true;
658  action.errorMsg = QStringLiteral( "No permissions to do WFS inserts on layer '%1'" ).arg( typeName );
659  continue;
660  }
661 #ifdef HAVE_SERVER_PYTHON_PLUGINS
662  if ( accessControl && !accessControl->layerInsertPermission( vlayer ) )
663  {
664  action.error = true;
665  action.errorMsg = QStringLiteral( "No permissions to do WFS inserts on layer '%1'" ).arg( typeName );
666  continue;
667  }
668 #endif
669  //get provider
670  QgsVectorDataProvider *provider = vlayer->dataProvider();
671 
672  // verifying specific capabilities
673  int cap = provider->capabilities();
674  if ( !( cap & QgsVectorDataProvider::AddFeatures ) )
675  {
676  action.error = true;
677  action.errorMsg = QStringLiteral( "No capabilities to do WFS inserts on layer '%1'" ).arg( typeName );
678  continue;
679  }
680 
681  // start editing
682  vlayer->startEditing();
683 
684  // get inserting features
685  QgsFeatureList featureList;
686  try
687  {
688  featureList = featuresFromGML( action.featureNodeList, provider );
689  }
690  catch ( QgsOgcServiceException &ex )
691  {
692  action.error = true;
693  action.errorMsg = QStringLiteral( "%1 '%2'" ).arg( ex.message() ).arg( typeName );
694  continue;
695  }
696 
697  if ( featureList.empty() )
698  {
699  action.error = true;
700  action.errorMsg = QStringLiteral( "No features to insert in layer '%1'" ).arg( typeName );
701  continue;
702  }
703 
704 #ifdef HAVE_SERVER_PYTHON_PLUGINS
705  // control features
706  if ( accessControl )
707  {
708  QgsFeatureList::iterator featureIt = featureList.begin();
709  while ( featureIt != featureList.end() )
710  {
711  if ( !accessControl->allowToEdit( vlayer, *featureIt ) )
712  {
713  action.error = true;
714  action.errorMsg = QStringLiteral( "Feature modify permission denied on layer '%1'" ).arg( typeName );
715  vlayer->rollBack();
716  break;
717  }
718  featureIt++;
719  }
720  }
721 #endif
722  if ( action.error )
723  {
724  continue;
725  }
726 
727  // perform add features
728  if ( !provider->addFeatures( featureList ) )
729  {
730  action.error = true;
731  action.errorMsg = QStringLiteral( "Insert features failed on layer '%1'" ).arg( typeName );
732  if ( provider ->hasErrors() )
733  {
734  provider->clearErrors();
735  }
736  vlayer->rollBack();
737  continue;
738  }
739 
740  // Commit the changes of the update elements
741  if ( !vlayer->commitChanges() )
742  {
743  action.error = true;
744  action.errorMsg = QStringLiteral( "Error committing inserts: %1" ).arg( vlayer->commitErrors().join( QStringLiteral( "; " ) ) );
745  vlayer->rollBack();
746  continue;
747  }
748  // all changes are OK!
749  action.error = false;
750 
751  // Get the Feature Ids of the inserted feature
752  QgsAttributeList pkAttributes = provider->pkAttributeIndexes();
753  for ( const QgsFeature &feat : qgis::as_const( featureList ) )
754  {
755  action.insertFeatureIds << QStringLiteral( "%1.%2" ).arg( typeName, QgsServerFeatureId::getServerFid( feat, pkAttributes ) );
756  }
757  }
758 
759  //force restoration of original layer filters
760  filterRestorer.reset();
761  }
762 
763  QgsFeatureList featuresFromGML( QDomNodeList featureNodeList, QgsVectorDataProvider *provider )
764  {
765  // Store the inserted features
766  QgsFeatureList featList;
767 
768  // Get Layer Field Information
769  QgsFields fields = provider->fields();
770  const QMap<QString, int> fieldMap = provider->fieldNameMap();
771  QMap<QString, int>::const_iterator fieldMapIt;
772 
773  for ( int i = 0; i < featureNodeList.count(); i++ )
774  {
775  QgsFeature feat( fields );
776 
777  QDomElement featureElem = featureNodeList.at( i ).toElement();
778  QDomNode currentAttributeChild = featureElem.firstChild();
779  bool conversionSuccess = true;
780 
781  while ( !currentAttributeChild.isNull() )
782  {
783  QDomElement currentAttributeElement = currentAttributeChild.toElement();
784  QString attrName = currentAttributeElement.localName();
785 
786  if ( attrName != QLatin1String( "boundedBy" ) )
787  {
788  if ( attrName != QLatin1String( "geometry" ) ) //a normal attribute
789  {
790  fieldMapIt = fieldMap.find( attrName );
791  if ( fieldMapIt == fieldMap.constEnd() )
792  {
793  continue;
794  }
795 
796  QgsField field = fields.at( fieldMapIt.value() );
797  QString attrValue = currentAttributeElement.text();
798  int attrType = field.type();
799 
800  QgsMessageLog::logMessage( QStringLiteral( "attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) );
801 
802  if ( attrType == QVariant::Int )
803  feat.setAttribute( fieldMapIt.value(), attrValue.toInt( &conversionSuccess ) );
804  else if ( attrType == QVariant::Double )
805  feat.setAttribute( fieldMapIt.value(), attrValue.toDouble( &conversionSuccess ) );
806  else
807  feat.setAttribute( fieldMapIt.value(), attrValue );
808 
809  if ( !conversionSuccess )
810  {
811  throw QgsRequestNotWellFormedException( QStringLiteral( "Property conversion error on layer insert" ) );
812  }
813  }
814  else //a geometry attribute
815  {
816  QgsGeometry g = QgsOgcUtils::geometryFromGML( currentAttributeElement );
817  if ( g.isNull() )
818  {
819  throw QgsRequestNotWellFormedException( QStringLiteral( "Geometry from GML error on layer insert" ) );
820  }
821  feat.setGeometry( g );
822  }
823  }
824  currentAttributeChild = currentAttributeChild.nextSibling();
825  }
826  // update feature list
827  featList << feat;
828  }
829  return featList;
830  }
831 
832  transactionRequest parseTransactionParameters( QgsServerRequest::Parameters parameters, const QgsProject *project )
833  {
834  if ( !parameters.contains( QStringLiteral( "OPERATION" ) ) )
835  {
836  throw QgsRequestNotWellFormedException( QStringLiteral( "OPERATION parameter is mandatory" ) );
837  }
838  if ( parameters.value( QStringLiteral( "OPERATION" ) ).toUpper() != QStringLiteral( "DELETE" ) )
839  {
840  throw QgsRequestNotWellFormedException( QStringLiteral( "Only DELETE value is defined for OPERATION parameter" ) );
841  }
842 
843  // Verifying parameters mutually exclusive
844  if ( ( parameters.contains( QStringLiteral( "FEATUREID" ) )
845  && ( parameters.contains( QStringLiteral( "FILTER" ) ) || parameters.contains( QStringLiteral( "BBOX" ) ) ) )
846  || ( parameters.contains( QStringLiteral( "FILTER" ) )
847  && ( parameters.contains( QStringLiteral( "FEATUREID" ) ) || parameters.contains( QStringLiteral( "BBOX" ) ) ) )
848  || ( parameters.contains( QStringLiteral( "BBOX" ) )
849  && ( parameters.contains( QStringLiteral( "FEATUREID" ) ) || parameters.contains( QStringLiteral( "FILTER" ) ) ) )
850  )
851  {
852  throw QgsRequestNotWellFormedException( QStringLiteral( "FEATUREID FILTER and BBOX parameters are mutually exclusive" ) );
853  }
854 
855  transactionRequest request;
856 
857  QStringList typeNameList;
858  // parse FEATUREID
859  if ( parameters.contains( QStringLiteral( "FEATUREID" ) ) )
860  {
861  QStringList fidList = parameters.value( QStringLiteral( "FEATUREID" ) ).split( ',' );
862 
863  QMap<QString, QStringList> fidsMap;
864 
865  QStringList::const_iterator fidIt = fidList.constBegin();
866  for ( ; fidIt != fidList.constEnd(); ++fidIt )
867  {
868  // Get FeatureID
869  QString fid = *fidIt;
870  fid = fid.trimmed();
871  // testing typename in the WFS featureID
872  if ( !fid.contains( '.' ) )
873  {
874  throw QgsRequestNotWellFormedException( QStringLiteral( "FEATUREID has to have TYPENAME in the values" ) );
875  }
876 
877  QString typeName = fid.section( '.', 0, 0 );
878  fid = fid.section( '.', 1, 1 );
879  if ( !typeNameList.contains( typeName ) )
880  {
881  typeNameList << typeName;
882  }
883 
884  QStringList fids;
885  if ( fidsMap.contains( typeName ) )
886  {
887  fids = fidsMap.value( typeName );
888  }
889  fids.append( fid );
890  fidsMap.insert( typeName, fids );
891  }
892 
893  QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
894  while ( fidsMapIt != fidsMap.constEnd() )
895  {
896  transactionDelete action;
897  action.typeName = fidsMapIt.key();
898 
899  action.serverFids = fidsMapIt.value();
900  action.featureRequest = QgsFeatureRequest();
901 
902  request.deletes.append( action );
903  }
904  return request;
905  }
906 
907  if ( !parameters.contains( QStringLiteral( "TYPENAME" ) ) )
908  {
909  throw QgsRequestNotWellFormedException( QStringLiteral( "TYPENAME is mandatory except if FEATUREID is used" ) );
910  }
911 
912  typeNameList = parameters.value( QStringLiteral( "TYPENAME" ) ).split( ',' );
913 
914  // Create actions based on TypeName
915  QStringList::const_iterator typeNameIt = typeNameList.constBegin();
916  for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
917  {
918  QString typeName = *typeNameIt;
919  typeName = typeName.trimmed();
920 
921  transactionDelete action;
922  action.typeName = typeName;
923 
924  request.deletes.append( action );
925  }
926 
927  // Manage extra parameter exp_filter
928  if ( parameters.contains( QStringLiteral( "EXP_FILTER" ) ) )
929  {
930  QString expFilterName = parameters.value( QStringLiteral( "EXP_FILTER" ) );
931  QStringList expFilterList;
932  QRegExp rx( "\\(([^()]+)\\)" );
933  if ( rx.indexIn( expFilterName, 0 ) == -1 )
934  {
935  expFilterList << expFilterName;
936  }
937  else
938  {
939  int pos = 0;
940  while ( ( pos = rx.indexIn( expFilterName, pos ) ) != -1 )
941  {
942  expFilterList << rx.cap( 1 );
943  pos += rx.matchedLength();
944  }
945  }
946 
947  // Verifying the 1:1 mapping between TYPENAME and EXP_FILTER but without exception
948  if ( request.deletes.size() == expFilterList.size() )
949  {
950  // set feature request filter expression based on filter element
951  QList<transactionDelete>::iterator dIt = request.deletes.begin();
952  QStringList::const_iterator expFilterIt = expFilterList.constBegin();
953  for ( ; dIt != request.deletes.end(); ++dIt )
954  {
955  transactionDelete &action = *dIt;
956  // Get Filter for this typeName
957  QString expFilter;
958  if ( expFilterIt != expFilterList.constEnd() )
959  {
960  expFilter = *expFilterIt;
961  }
962  std::shared_ptr<QgsExpression> filter( new QgsExpression( expFilter ) );
963  if ( filter )
964  {
965  if ( filter->hasParserError() )
966  {
967  QgsMessageLog::logMessage( filter->parserErrorString() );
968  }
969  else
970  {
971  if ( filter->needsGeometry() )
972  {
973  action.featureRequest.setFlags( QgsFeatureRequest::NoFlags );
974  }
975  action.featureRequest.setFilterExpression( filter->expression() );
976  }
977  }
978  }
979  }
980  else
981  {
982  QgsMessageLog::logMessage( "There has to be a 1:1 mapping between each element in a TYPENAME and the EXP_FILTER list" );
983  }
984  }
985 
986  if ( parameters.contains( QStringLiteral( "BBOX" ) ) )
987  {
988  // get bbox value
989  QString bbox = parameters.value( QStringLiteral( "BBOX" ) );
990  if ( bbox.isEmpty() )
991  {
992  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX parameter is empty" ) );
993  }
994 
995  // get bbox corners
996  QStringList corners = bbox.split( ',' );
997  if ( corners.size() != 4 )
998  {
999  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX has to be composed of 4 elements: '%1'" ).arg( bbox ) );
1000  }
1001 
1002  // convert corners to double
1003  double d[4];
1004  bool ok;
1005  for ( int i = 0; i < 4; i++ )
1006  {
1007  corners[i].replace( ' ', '+' );
1008  d[i] = corners[i].toDouble( &ok );
1009  if ( !ok )
1010  {
1011  throw QgsRequestNotWellFormedException( QStringLiteral( "BBOX has to be composed of 4 double: '%1'" ).arg( bbox ) );
1012  }
1013  }
1014  // create extent
1015  QgsRectangle extent( d[0], d[1], d[2], d[3] );
1016 
1017  // set feature request filter rectangle
1018  QList<transactionDelete>::iterator dIt = request.deletes.begin();
1019  for ( ; dIt != request.deletes.end(); ++dIt )
1020  {
1021  transactionDelete &action = *dIt;
1022  action.featureRequest.setFilterRect( extent );
1023  }
1024  return request;
1025  }
1026  else if ( parameters.contains( QStringLiteral( "FILTER" ) ) )
1027  {
1028  QString filterName = parameters.value( QStringLiteral( "FILTER" ) );
1029  QStringList filterList;
1030  QRegExp rx( "\\(([^()]+)\\)" );
1031  if ( rx.indexIn( filterName, 0 ) == -1 )
1032  {
1033  filterList << filterName;
1034  }
1035  else
1036  {
1037  int pos = 0;
1038  while ( ( pos = rx.indexIn( filterName, pos ) ) != -1 )
1039  {
1040  filterList << rx.cap( 1 );
1041  pos += rx.matchedLength();
1042  }
1043  }
1044 
1045  // Verifying the 1:1 mapping between TYPENAME and FILTER
1046  if ( request.deletes.size() != filterList.size() )
1047  {
1048  throw QgsRequestNotWellFormedException( QStringLiteral( "There has to be a 1:1 mapping between each element in a TYPENAME and the FILTER list" ) );
1049  }
1050 
1051  // set feature request filter expression based on filter element
1052  QList<transactionDelete>::iterator dIt = request.deletes.begin();
1053  QStringList::const_iterator filterIt = filterList.constBegin();
1054  for ( ; dIt != request.deletes.end(); ++dIt )
1055  {
1056  transactionDelete &action = *dIt;
1057 
1058  // Get Filter for this typeName
1059  QDomDocument filter;
1060  if ( filterIt != filterList.constEnd() )
1061  {
1062  QString errorMsg;
1063  if ( !filter.setContent( *filterIt, true, &errorMsg ) )
1064  {
1065  throw QgsRequestNotWellFormedException( QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, *filterIt ) );
1066  }
1067  }
1068 
1069  QDomElement filterElem = filter.firstChildElement();
1070  QStringList serverFids;
1071  action.featureRequest = parseFilterElement( action.typeName, filterElem, serverFids, project );
1072  action.serverFids = serverFids;
1073 
1074  if ( filterIt != filterList.constEnd() )
1075  {
1076  ++filterIt;
1077  }
1078  }
1079  return request;
1080  }
1081 
1082  return request;
1083  }
1084 
1085  transactionRequest parseTransactionRequestBody( QDomElement &docElem, const QgsProject *project )
1086  {
1087  transactionRequest request;
1088 
1089  QDomNodeList docChildNodes = docElem.childNodes();
1090 
1091  QDomElement actionElem;
1092  QString actionName;
1093 
1094  for ( int i = docChildNodes.count(); 0 < i; --i )
1095  {
1096  actionElem = docChildNodes.at( i - 1 ).toElement();
1097  actionName = actionElem.localName();
1098 
1099  if ( actionName == QLatin1String( "Insert" ) )
1100  {
1101  transactionInsert action = parseInsertActionElement( actionElem );
1102  request.inserts.append( action );
1103  }
1104  else if ( actionName == QLatin1String( "Update" ) )
1105  {
1106  transactionUpdate action = parseUpdateActionElement( actionElem, project );
1107  request.updates.append( action );
1108  }
1109  else if ( actionName == QLatin1String( "Delete" ) )
1110  {
1111  transactionDelete action = parseDeleteActionElement( actionElem, project );
1112  request.deletes.append( action );
1113  }
1114  }
1115 
1116  return request;
1117  }
1118 
1119  transactionDelete parseDeleteActionElement( QDomElement &actionElem, const QgsProject *project )
1120  {
1121  QString typeName = actionElem.attribute( QStringLiteral( "typeName" ) );
1122  if ( typeName.contains( ':' ) )
1123  typeName = typeName.section( ':', 1, 1 );
1124 
1125  QDomElement filterElem = actionElem.firstChild().toElement();
1126  if ( filterElem.tagName() != QLatin1String( "Filter" ) )
1127  {
1128  throw QgsRequestNotWellFormedException( QStringLiteral( "Delete action element first child is not Filter" ) );
1129  }
1130 
1131  QStringList serverFids;
1132  QgsFeatureRequest featureRequest = parseFilterElement( typeName, filterElem, serverFids, project );
1133 
1134  transactionDelete action;
1135  action.typeName = typeName;
1136  action.featureRequest = featureRequest;
1137  action.serverFids = serverFids;
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  transactionUpdate parseUpdateActionElement( QDomElement &actionElem, const QgsProject *project )
1149  {
1150  QString typeName = actionElem.attribute( QStringLiteral( "typeName" ) );
1151  if ( typeName.contains( ':' ) )
1152  typeName = typeName.section( ':', 1, 1 );
1153 
1154  QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral( "Property" ) );
1155  if ( propertyNodeList.isEmpty() )
1156  {
1157  throw QgsRequestNotWellFormedException( QStringLiteral( "Update action element must have one or more Property element" ) );
1158  }
1159 
1160  QMap<QString, QString> propertyMap;
1161  QDomElement propertyElem;
1162  QDomElement nameElem;
1163  QDomElement valueElem;
1164  QDomElement geometryElem;
1165 
1166  for ( int l = 0; l < propertyNodeList.count(); ++l )
1167  {
1168  propertyElem = propertyNodeList.at( l ).toElement();
1169  nameElem = propertyElem.elementsByTagName( QStringLiteral( "Name" ) ).at( 0 ).toElement();
1170  valueElem = propertyElem.elementsByTagName( QStringLiteral( "Value" ) ).at( 0 ).toElement();
1171  if ( nameElem.text() != QLatin1String( "geometry" ) )
1172  {
1173  propertyMap.insert( nameElem.text(), valueElem.text() );
1174  }
1175  else
1176  {
1177  geometryElem = valueElem;
1178  }
1179  }
1180 
1181  QDomNodeList filterNodeList = actionElem.elementsByTagName( QStringLiteral( "Filter" ) );
1182  QgsFeatureRequest featureRequest;
1183  QStringList serverFids;
1184  if ( filterNodeList.size() != 0 )
1185  {
1186  QDomElement filterElem = filterNodeList.at( 0 ).toElement();
1187  featureRequest = parseFilterElement( typeName, filterElem, serverFids, project );
1188  }
1189 
1190  transactionUpdate action;
1191  action.typeName = typeName;
1192  action.propertyMap = propertyMap;
1193  action.geometryElement = geometryElem;
1194  action.featureRequest = featureRequest;
1195  action.serverFids = serverFids;
1196  action.error = false;
1197 
1198  if ( actionElem.hasAttribute( QStringLiteral( "handle" ) ) )
1199  {
1200  action.handle = actionElem.attribute( QStringLiteral( "handle" ) );
1201  }
1202 
1203  return action;
1204  }
1205 
1206  transactionInsert parseInsertActionElement( QDomElement &actionElem )
1207  {
1208  QDomNodeList featureNodeList = actionElem.childNodes();
1209  if ( featureNodeList.size() != 1 )
1210  {
1211  throw QgsRequestNotWellFormedException( QStringLiteral( "Insert action element must have one or more child node" ) );
1212  }
1213 
1214  QString typeName;
1215  for ( int i = 0; i < featureNodeList.count(); ++i )
1216  {
1217  QString tempTypeName = featureNodeList.at( i ).toElement().localName();
1218  if ( tempTypeName.contains( ':' ) )
1219  tempTypeName = tempTypeName.section( ':', 1, 1 );
1220 
1221  if ( typeName.isEmpty() )
1222  {
1223  typeName = tempTypeName;
1224  }
1225  else if ( tempTypeName != typeName )
1226  {
1227  throw QgsRequestNotWellFormedException( QStringLiteral( "Insert action element must have one typename features" ) );
1228  }
1229  }
1230 
1231  transactionInsert action;
1232  action.typeName = typeName;
1233  action.featureNodeList = featureNodeList;
1234  action.error = false;
1235 
1236  if ( actionElem.hasAttribute( QStringLiteral( "handle" ) ) )
1237  {
1238  action.handle = actionElem.attribute( QStringLiteral( "handle" ) );
1239  }
1240 
1241  return action;
1242  }
1243 
1244  namespace
1245  {
1246 
1247  void addTransactionResult( QDomDocument &responseDoc, QDomElement &responseElem, const QString &status,
1248  const QString &locator, const QString &message )
1249  {
1250  QDomElement trElem = responseDoc.createElement( QStringLiteral( "TransactionResult" ) );
1251  QDomElement stElem = responseDoc.createElement( QStringLiteral( "Status" ) );
1252  QDomElement successElem = responseDoc.createElement( status );
1253  stElem.appendChild( successElem );
1254  trElem.appendChild( stElem );
1255  responseElem.appendChild( trElem );
1256 
1257  if ( !locator.isEmpty() )
1258  {
1259  QDomElement locElem = responseDoc.createElement( QStringLiteral( "Locator" ) );
1260  locElem.appendChild( responseDoc.createTextNode( locator ) );
1261  trElem.appendChild( locElem );
1262  }
1263 
1264  if ( !message.isEmpty() )
1265  {
1266  QDomElement mesElem = responseDoc.createElement( QStringLiteral( "Message" ) );
1267  mesElem.appendChild( responseDoc.createTextNode( message ) );
1268  trElem.appendChild( mesElem );
1269  }
1270  }
1271 
1272  }
1273 
1274  } // namespace v1_0_0
1275 } // namespace QgsWfs
1276 
1277 
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:369
qgsfields.h
qgsexpressioncontextutils.h
qgswfsutils.h
qgsserverfeatureid.h
QgsVectorDataProvider::DeleteFeatures
@ DeleteFeatures
Allows deletion of features.
Definition: qgsvectordataprovider.h:76
QgsWfs::v1_0_0::featuresFromGML
QgsFeatureList featuresFromGML(QDomNodeList featureNodeList, QgsVectorDataProvider *provider)
Transform GML feature nodes to features.
Definition: qgswfstransaction_1_0_0.cpp:799
QgsVectorDataProvider::pkAttributeIndexes
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
Definition: qgsvectordataprovider.cpp:333
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsWfs::parseFilterElement
QgsFeatureRequest parseFilterElement(const QString &typeName, QDomElement &filterElem, QgsProject *project)
Transform a Filter element to a feature request.
Definition: qgswfsutils.cpp:121
QgsExpressionContextUtils::globalScope
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Definition: qgsexpressioncontextutils.cpp:33
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
QgsWfs::transactionDelete
Definition: qgswfstransaction.h:82
QgsVectorDataProvider::fields
QgsFields fields() const override=0
Returns the fields associated with this data provider.
QgsWfs::layerTypeName
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
Definition: qgswfsutils.cpp:89
QgsAccessControl::filterFeatures
void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures) const override
Filter the features of the layer.
Definition: qgsaccesscontrol.cpp:62
QgsWfs::transactionUpdate::error
bool error
Definition: qgswfstransaction.h:77
qgsfeatureiterator.h
QgsFields
Definition: qgsfields.h:44
QgsExpressionContextUtils::layerScope
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Definition: qgsexpressioncontextutils.cpp:264
qgsserverprojectutils.h
QgsServerRequest
Definition: qgsserverrequest.h:38
QgsVectorLayer::startEditing
Q_INVOKABLE bool startEditing()
Makes the layer editable.
Definition: qgsvectorlayer.cpp:1411
QgsWfs::v1_0_0::transactionUpdate::handle
QString handle
Definition: qgswfstransaction_1_0_0.h:85
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
QgsProject::mapLayer
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Definition: qgsproject.cpp:3124
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.
QgsWfs::transactionUpdate
Definition: qgswfstransaction.h:61
QgsRectangle
Definition: qgsrectangle.h:41
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:2965
qgsogcutils.h
QgsVectorDataProvider::ChangeGeometries
@ ChangeGeometries
Allows modifications of geometries.
Definition: qgsvectordataprovider.h:82
QgsProject
Definition: qgsproject.h:92
QgsWfs::v1_0_0::parseTransactionParameters
transactionRequest parseTransactionParameters(QgsServerRequest::Parameters parameters, const QgsProject *project)
Definition: qgswfstransaction_1_0_0.cpp:868
QgsFeatureRequest::setExpressionContext
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
Definition: qgsfeaturerequest.cpp:149
QgsServerRequest::Parameters
QMap< QString, QString > Parameters
Definition: qgsserverrequest.h:59
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:98
QgsWfs::v1_0_0::parseUpdateActionElement
transactionUpdate parseUpdateActionElement(QDomElement &actionElem, const QgsProject *project)
Transform Update element to transactionUpdate.
Definition: qgswfstransaction_1_0_0.cpp:1184
QgsWfs::WFS_NAMESPACE
const QString WFS_NAMESPACE
Definition: qgswfsutils.h:91
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
QgsOWSServerFilterRestorer
RAII class to restore layer filters on destruction.
Definition: qgsfilterrestorer.h:36
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:2941
QgsWfs::v1_0_0::transactionUpdate
Definition: qgswfstransaction_1_0_0.h:81
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsWfs::transactionUpdate::typeName
QString typeName
Definition: qgswfstransaction.h:63
QgsVectorDataProvider::capabilities
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Definition: qgsvectordataprovider.cpp:191
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:315
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:221
QgsAccessControl::layerUpdatePermission
bool layerUpdatePermission(const QgsVectorLayer *layer) const
Returns the layer update right.
Definition: qgsaccesscontrol.cpp:133
QgsFeatureRequest::NoFlags
@ NoFlags
Definition: qgsfeaturerequest.h:106
QgsWfs::v1_0_0::transactionUpdate::errorMsg
QString errorMsg
Definition: qgswfstransaction_1_0_0.h:97
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
QgsWfs::v1_0_0::parseInsertActionElement
transactionInsert parseInsertActionElement(QDomElement &actionElem)
Transform Insert element to transactionInsert.
Definition: qgswfstransaction_1_0_0.cpp:1242
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:3374
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:3379
QgsFieldConstraints::constraints
Constraints constraints
Definition: qgsfieldconstraints.h:36
QgsWfs::OGC_NAMESPACE
const QString OGC_NAMESPACE
Definition: qgswfsutils.h:93
qgsmaplayer.h
QgsWfs
WMS implementation.
Definition: qgswfs.cpp:35
QgsWfs::transactionDelete::typeName
QString typeName
Definition: qgswfstransaction.h:84
qgsvectordataprovider.h
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:572
QgsVectorLayer::commitChanges
Q_INVOKABLE bool commitChanges()
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
Definition: qgsvectorlayer.cpp:3329
QgsWfs::transactionDelete::featureRequest
QgsFeatureRequest featureRequest
Definition: qgswfstransaction.h:88
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
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:125
QgsAccessControl::layerInsertPermission
bool layerInsertPermission(const QgsVectorLayer *layer) const
Returns the layer insert right.
Definition: qgsaccesscontrol.cpp:119
QgsWfs::transactionUpdate::propertyMap
QMap< QString, QString > propertyMap
Definition: qgswfstransaction.h:67
typeName
const QString & typeName
Definition: qgswfsgetfeature.cpp:109
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:103
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
QgsOgcServiceException
Exception base class for service exceptions.
Definition: qgsserverexception.h:82
QgsWfs::transactionUpdate::serverFids
QStringList serverFids
Definition: qgswfstransaction.h:73
QgsVectorDataProvider::clearErrors
void clearErrors()
Clear recorded errors.
Definition: qgsvectordataprovider.cpp:697
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:36
QgsWfs::v1_0_0::transactionUpdate::typeName
QString typeName
Definition: qgswfstransaction_1_0_0.h:83
QgsServerRequest::data
virtual QByteArray data() const
Returns post/put data Check for QByteArray::isNull() to check if data is available.
Definition: qgsserverrequest.cpp:95
QgsVectorDataProvider::addFeatures
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
Definition: qgsvectordataprovider.cpp: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:1121
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:373
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:3264
QgsOgcServiceException::message
QString message() const
Returns the exception message.
Definition: qgsserverexception.h:94
QgsGeometry
Definition: qgsgeometry.h:122
QgsVectorDataProvider::ChangeAttributeValues
@ ChangeAttributeValues
Allows modification of attribute values.
Definition: qgsvectordataprovider.h:77
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsWfs::transactionUpdate::handle
QString handle
Definition: qgswfstransaction.h:65
QgsAccessControl::layerDeletePermission
bool layerDeletePermission(const QgsVectorLayer *layer) const
Returns the layer delete right.
Definition: qgsaccesscontrol.cpp:147
QgsMapLayer
Definition: qgsmaplayer.h:81
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:238
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:87
QgsField::constraints
QgsFieldConstraints constraints
Definition: qgsfield.h:62
QgsWfs::v1_0_0::transactionUpdate::error
bool error
Definition: qgswfstransaction_1_0_0.h:95
QgsVectorDataProvider
Definition: qgsvectordataprovider.h:58
QgsFeature
Definition: qgsfeature.h:55
QgsWfs::v1_0_0::parseDeleteActionElement
transactionDelete parseDeleteActionElement(QDomElement &actionElem, const QgsProject *project)
Transform Delete element to transactionDelete.
Definition: qgswfstransaction_1_0_0.cpp:1155
QgsWfs::transactionUpdate::featureRequest
QgsFeatureRequest featureRequest
Definition: qgswfstransaction.h:71
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
QgsWfs::transactionDelete::errorMsg
QString errorMsg
Definition: qgswfstransaction.h:96
QgsWfs::transactionUpdate::geometryElement
QDomElement geometryElement
Definition: qgswfstransaction.h:69
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsExpression
Definition: qgsexpression.h:113
QgsWfs::transactionDelete::error
bool error
Definition: qgswfstransaction.h:94
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsMapLayer::type
QgsMapLayerType type() const
Returns the type of the layer.
Definition: qgsmaplayer.cpp:129
QgsServerInterface
Definition: qgsserverinterface.h:60
qgsproject.h
QgsField::type
QVariant::Type type
Definition: qgsfield.h:57
QgsServerResponse
Definition: qgsserverresponse.h:43
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...
QgsWfs::transactionDelete::handle
QString handle
Definition: qgswfstransaction.h:86
QgsWfs::transactionDelete::serverFids
QStringList serverFids
Definition: qgswfstransaction.h:90
QgsMapLayer::error
virtual QgsError error() const
Gets current status error.
Definition: qgsmaplayer.cpp:1728
QgsField
Definition: qgsfield.h:49