48 void addTransactionResult( QDomDocument &responseDoc, QDomElement &resultsElem,
49 const QString &locator,
const QString &message );
60 response.
setHeader(
"Content-Type",
"text/xml; charset=utf-8" );
61 response.
write( doc.toByteArray() );
75 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
77 QDomElement docElem = doc.documentElement();
86 if ( actionCount == 0 )
97 QDomElement respElem = resp.createElement( QStringLiteral(
"TransactionResponse" ) );
98 respElem.setAttribute( QStringLiteral(
"xmlns" ),
WFS_NAMESPACE );
99 respElem.setAttribute( QStringLiteral(
"xmlns:xsi" ), QStringLiteral(
"http://www.w3.org/2001/XMLSchema-instance" ) );
100 respElem.setAttribute( QStringLiteral(
"xsi:schemaLocation" ),
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
101 respElem.setAttribute( QStringLiteral(
"xmlns:ogc" ),
OGC_NAMESPACE );
102 respElem.setAttribute( QStringLiteral(
"version" ), QStringLiteral(
"1.1.0" ) );
103 resp.appendChild( respElem );
105 int totalInserted = 0;
106 int totalUpdated = 0;
107 int totalDeleted = 0;
111 QDomElement trsElem = doc.createElement( QStringLiteral(
"TransactionResults" ) );
114 QDomElement irsElem = doc.createElement( QStringLiteral(
"InsertResults" ) );
115 QList<transactionInsert>::iterator tiIt = aRequest.
inserts.begin();
116 for ( ; tiIt != aRequest.
inserts.end(); ++tiIt )
122 QString locator = action.
handle;
123 if ( locator.isEmpty() )
125 locator = QStringLiteral(
"Insert:%1" ).arg( action.
typeName );
127 addTransactionResult( resp, trsElem, locator, action.
errorMsg );
134 QString fidStr = *fidIt;
135 QDomElement irElem = doc.createElement( QStringLiteral(
"Feature" ) );
136 if ( !action.
handle.isEmpty() )
138 irElem.setAttribute( QStringLiteral(
"handle" ), action.
handle );
140 QDomElement fiElem = doc.createElement( QStringLiteral(
"ogc:FeatureId" ) );
141 fiElem.setAttribute( QStringLiteral(
"fid" ), fidStr );
142 irElem.appendChild( fiElem );
143 irsElem.appendChild( irElem );
149 QList<transactionUpdate>::iterator tuIt = aRequest.
updates.begin();
150 for ( ; tuIt != aRequest.
updates.end(); ++tuIt )
156 QString locator = action.
handle;
157 if ( locator.isEmpty() )
159 locator = QStringLiteral(
"Update:%1" ).arg( action.
typeName );
161 addTransactionResult( resp, trsElem, locator, action.
errorMsg );
166 QList<transactionDelete>::iterator tdIt = aRequest.
deletes.begin();
167 for ( ; tdIt != aRequest.
deletes.end(); ++tdIt )
173 QString locator = action.
handle;
174 if ( locator.isEmpty() )
176 locator = QStringLiteral(
"Delete:%1" ).arg( action.
typeName );
178 addTransactionResult( resp, trsElem, locator, action.
errorMsg );
184 QDomElement summaryElem = doc.createElement( QStringLiteral(
"TransactionSummary" ) );
185 if ( aRequest.
inserts.size() > 0 )
187 QDomElement totalInsertedElem = doc.createElement( QStringLiteral(
"totalInserted" ) );
188 totalInsertedElem.appendChild( doc.createTextNode( QString::number( totalInserted ) ) );
189 summaryElem.appendChild( totalInsertedElem );
191 if ( aRequest.
updates.size() > 0 )
193 QDomElement totalUpdatedElem = doc.createElement( QStringLiteral(
"totalUpdated" ) );
194 totalUpdatedElem.appendChild( doc.createTextNode( QString::number( totalUpdated ) ) );
195 summaryElem.appendChild( totalUpdatedElem );
197 if ( aRequest.
deletes.size() > 0 )
199 QDomElement totalDeletedElem = doc.createElement( QStringLiteral(
"totalDeleted" ) );
200 totalDeletedElem.appendChild( doc.createTextNode( QString::number( totalDeleted ) ) );
201 summaryElem.appendChild( totalDeletedElem );
203 respElem.appendChild( summaryElem );
206 if ( errorCount > 0 && trsElem.hasChildNodes() )
208 respElem.appendChild( trsElem );
212 if ( aRequest.
inserts.size() > 0 && irsElem.hasChildNodes() )
214 respElem.appendChild( irsElem );
221 #ifndef HAVE_SERVER_PYTHON_PLUGINS
225 QStringList typeNameList;
227 QList<transactionInsert>::iterator tiIt = aRequest.
inserts.begin();
228 for ( ; tiIt != aRequest.
inserts.end(); ++tiIt )
230 QString name = ( *tiIt ).typeName;
231 if ( !typeNameList.contains( name ) )
232 typeNameList << name;
234 QList<transactionUpdate>::iterator tuIt = aRequest.
updates.begin();
235 for ( ; tuIt != aRequest.
updates.end(); ++tuIt )
237 QString name = ( *tuIt ).typeName;
238 if ( !typeNameList.contains( name ) )
239 typeNameList << name;
241 QList<transactionDelete>::iterator tdIt = aRequest.
deletes.begin();
242 for ( ; tdIt != aRequest.
deletes.end(); ++tdIt )
244 QString name = ( *tdIt ).typeName;
245 if ( !typeNameList.contains( name ) )
246 typeNameList << name;
249 #ifdef HAVE_SERVER_PYTHON_PLUGINS
263 QMap<QString, QgsVectorLayer *> mapLayerMap;
278 if ( !typeNameList.contains( name ) )
311 #ifdef HAVE_SERVER_PYTHON_PLUGINS
324 mapLayerMap[name] = vlayer;
328 tuIt = aRequest.
updates.begin();
329 for ( ; tuIt != aRequest.
updates.end(); ++tuIt )
334 if ( !mapLayerMap.keys().contains(
typeName ) )
337 action.
errorMsg = QStringLiteral(
"TypeName '%1' unknown" ).arg(
typeName );
348 action.
errorMsg = QStringLiteral(
"No permissions to do WFS updates on layer '%1'" ).arg(
typeName );
351 #ifdef HAVE_SERVER_PYTHON_PLUGINS
355 action.
errorMsg = QStringLiteral(
"No permissions to do WFS updates on layer '%1'" ).arg(
typeName );
367 action.
errorMsg = QStringLiteral(
"No capabilities to do WFS updates on layer '%1'" ).arg(
typeName );
390 #ifdef HAVE_SERVER_PYTHON_PLUGINS
399 int totalUpdated = 0;
401 QMap<QString, QString> propertyMap = action.
propertyMap;
405 const QMap<QString, int> fieldMap = provider->
fieldNameMap();
406 QMap<QString, int>::const_iterator fieldMapIt;
408 bool conversionSuccess;
412 #ifdef HAVE_SERVER_PYTHON_PLUGINS
413 if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
416 action.
errorMsg = QStringLiteral(
"Feature modify permission denied on layer '%1'" ).arg(
typeName );
421 QMap< QString, QString >::const_iterator it = propertyMap.constBegin();
422 for ( ; it != propertyMap.constEnd(); ++it )
424 fieldName = it.key();
425 fieldMapIt = fieldMap.find( fieldName );
426 if ( fieldMapIt == fieldMap.constEnd() )
431 QVariant value = it.value();
432 if ( value.isNull() )
444 if (
field.
type() == QVariant::Type::Int )
446 value = it.value().toInt( &conversionSuccess );
447 if ( !conversionSuccess )
450 action.
errorMsg = QStringLiteral(
"Property conversion error on layer '%1'" ).arg(
typeName );
455 else if (
field.
type() == QVariant::Type::Double )
457 value = it.value().toDouble( &conversionSuccess );
458 if ( !conversionSuccess )
461 action.
errorMsg = QStringLiteral(
"Property conversion error on layer '%1'" ).arg(
typeName );
466 else if (
field.
type() == QVariant::Type::LongLong )
468 value = it.value().toLongLong( &conversionSuccess );
469 if ( !conversionSuccess )
472 action.
errorMsg = QStringLiteral(
"Property conversion error on layer '%1'" ).arg(
typeName );
485 if ( !geometryElem.isNull() )
491 action.
errorMsg = QStringLiteral(
"Geometry from GML error on layer '%1'" ).arg(
typeName );
498 action.
errorMsg = QStringLiteral(
"Error in change geometry on layer '%1'" ).arg(
typeName );
509 #ifdef HAVE_SERVER_PYTHON_PLUGINS
516 if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
519 action.
errorMsg = QStringLiteral(
"Feature modify permission denied on layer '%1'" ).arg(
typeName );
535 action.
errorMsg = QStringLiteral(
"Error committing updates: %1" ).arg( vlayer->
commitErrors().join( QLatin1String(
"; " ) ) );
541 action.
error =
false;
546 tdIt = aRequest.
deletes.begin();
547 for ( ; tdIt != aRequest.
deletes.end(); ++tdIt )
552 if ( !mapLayerMap.keys().contains(
typeName ) )
555 action.
errorMsg = QStringLiteral(
"TypeName '%1' unknown" ).arg(
typeName );
566 action.
errorMsg = QStringLiteral(
"No permissions to do WFS deletes on layer '%1'" ).arg(
typeName );
569 #ifdef HAVE_SERVER_PYTHON_PLUGINS
573 action.
errorMsg = QStringLiteral(
"No permissions to do WFS deletes on layer '%1'" ).arg(
typeName );
585 action.
errorMsg = QStringLiteral(
"No capabilities to do WFS deletes on layer '%1'" ).arg(
typeName );
605 action.
errorMsg = QStringLiteral(
"No feature ids to do WFS deletes on layer '%1'" ).arg(
typeName );
612 #ifdef HAVE_SERVER_PYTHON_PLUGINS
626 #ifdef HAVE_SERVER_PYTHON_PLUGINS
627 if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
630 action.
errorMsg = QStringLiteral(
"Feature modify permission denied" );
635 fids << feature.
id();
645 action.
errorMsg = QStringLiteral(
"Delete features failed on layer '%1'" ).arg(
typeName );
654 action.
errorMsg = QStringLiteral(
"Error committing deletes: %1" ).arg( vlayer->
commitErrors().join( QLatin1String(
"; " ) ) );
660 action.
error =
false;
664 tiIt = aRequest.
inserts.begin();
665 for ( ; tiIt != aRequest.
inserts.end(); ++tiIt )
670 if ( !mapLayerMap.keys().contains(
typeName ) )
673 action.
errorMsg = QStringLiteral(
"TypeName '%1' unknown" ).arg(
typeName );
684 action.
errorMsg = QStringLiteral(
"No permissions to do WFS inserts on layer '%1'" ).arg(
typeName );
687 #ifdef HAVE_SERVER_PYTHON_PLUGINS
691 action.
errorMsg = QStringLiteral(
"No permissions to do WFS inserts on layer '%1'" ).arg(
typeName );
703 action.
errorMsg = QStringLiteral(
"No capabilities to do WFS inserts on layer '%1'" ).arg(
typeName );
723 if ( featureList.empty() )
726 action.
errorMsg = QStringLiteral(
"No features to insert in layer '%1'" ).arg(
typeName );
730 #ifdef HAVE_SERVER_PYTHON_PLUGINS
734 QgsFeatureList::iterator featureIt = featureList.begin();
735 while ( featureIt != featureList.end() )
737 if ( !accessControl->
allowToEdit( vlayer, *featureIt ) )
740 action.
errorMsg = QStringLiteral(
"Feature modify permission denied on layer '%1'" ).arg(
typeName );
757 action.
errorMsg = QStringLiteral(
"Insert features failed on layer '%1'" ).arg(
typeName );
758 if ( provider ->hasErrors() )
770 action.
errorMsg = QStringLiteral(
"Error committing inserts: %1" ).arg( vlayer->
commitErrors().join( QLatin1String(
"; " ) ) );
775 action.
error =
false;
779 for (
const QgsFeature &feat : qgis::as_const( featureList ) )
786 filterRestorer.reset();
798 const QMap<QString, int> fieldMap = provider->fieldNameMap();
799 QMap<QString, int>::const_iterator fieldMapIt;
801 for (
int i = 0; i < featureNodeList.count(); i++ )
805 QDomElement featureElem = featureNodeList.at( i ).toElement();
806 QDomNode currentAttributeChild = featureElem.firstChild();
807 bool conversionSuccess =
true;
809 while ( !currentAttributeChild.isNull() )
811 QDomElement currentAttributeElement = currentAttributeChild.toElement();
812 QString attrName = currentAttributeElement.localName();
814 if ( attrName != QLatin1String(
"boundedBy" ) )
816 if ( attrName != QLatin1String(
"geometry" ) )
818 fieldMapIt = fieldMap.find( attrName );
819 if ( fieldMapIt == fieldMap.constEnd() )
825 QString attrValue = currentAttributeElement.text();
828 QgsMessageLog::logMessage( QStringLiteral(
"attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) );
830 if ( attrType == QVariant::Int )
831 feat.
setAttribute( fieldMapIt.value(), attrValue.toInt( &conversionSuccess ) );
832 else if ( attrType == QVariant::Double )
833 feat.
setAttribute( fieldMapIt.value(), attrValue.toDouble( &conversionSuccess ) );
837 if ( !conversionSuccess )
853 currentAttributeChild = currentAttributeChild.nextSibling();
863 if ( !parameters.contains( QStringLiteral(
"OPERATION" ) ) )
867 if ( parameters.value( QStringLiteral(
"OPERATION" ) ).toUpper() != QLatin1String(
"DELETE" ) )
873 if ( ( parameters.contains( QStringLiteral(
"FEATUREID" ) )
874 && ( parameters.contains( QStringLiteral(
"FILTER" ) ) || parameters.contains( QStringLiteral(
"BBOX" ) ) ) )
875 || ( parameters.contains( QStringLiteral(
"FILTER" ) )
876 && ( parameters.contains( QStringLiteral(
"FEATUREID" ) ) || parameters.contains( QStringLiteral(
"BBOX" ) ) ) )
877 || ( parameters.contains( QStringLiteral(
"BBOX" ) )
878 && ( parameters.contains( QStringLiteral(
"FEATUREID" ) ) || parameters.contains( QStringLiteral(
"FILTER" ) ) ) )
886 QStringList typeNameList;
888 if ( parameters.contains( QStringLiteral(
"FEATUREID" ) ) )
890 QStringList fidList = parameters.value( QStringLiteral(
"FEATUREID" ) ).split(
',' );
892 QMap<QString, QStringList> fidsMap;
894 QStringList::const_iterator fidIt = fidList.constBegin();
895 for ( ; fidIt != fidList.constEnd(); ++fidIt )
898 QString fid = *fidIt;
901 if ( !fid.contains(
'.' ) )
906 QString
typeName = fid.section(
'.', 0, 0 );
907 fid = fid.section(
'.', 1, 1 );
908 if ( !typeNameList.contains(
typeName ) )
922 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
923 while ( fidsMapIt != fidsMap.constEnd() )
931 request.
deletes.append( action );
936 if ( !parameters.contains( QStringLiteral(
"TYPENAME" ) ) )
941 typeNameList = parameters.value( QStringLiteral(
"TYPENAME" ) ).split(
',' );
944 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
945 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
953 request.
deletes.append( action );
957 if ( parameters.contains( QStringLiteral(
"EXP_FILTER" ) ) )
959 QString expFilterName = parameters.value( QStringLiteral(
"EXP_FILTER" ) );
960 QStringList expFilterList;
961 QRegExp rx(
"\\(([^()]+)\\)" );
962 if ( rx.indexIn( expFilterName, 0 ) == -1 )
964 expFilterList << expFilterName;
969 while ( ( pos = rx.indexIn( expFilterName, pos ) ) != -1 )
971 expFilterList << rx.cap( 1 );
972 pos += rx.matchedLength();
977 if ( request.
deletes.size() == expFilterList.size() )
980 QList<transactionDelete>::iterator dIt = request.
deletes.begin();
981 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
982 for ( ; dIt != request.
deletes.end(); ++dIt )
987 if ( expFilterIt != expFilterList.constEnd() )
989 expFilter = *expFilterIt;
991 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
994 if ( filter->hasParserError() )
1000 if ( filter->needsGeometry() )
1011 QgsMessageLog::logMessage(
"There has to be a 1:1 mapping between each element in a TYPENAME and the EXP_FILTER list" );
1015 if ( parameters.contains( QStringLiteral(
"BBOX" ) ) )
1018 QString bbox = parameters.value( QStringLiteral(
"BBOX" ) );
1019 if ( bbox.isEmpty() )
1025 QStringList corners = bbox.split(
',' );
1026 if ( corners.size() != 4 )
1034 for (
int i = 0; i < 4; i++ )
1036 corners[i].replace(
' ',
'+' );
1037 d[i] = corners[i].toDouble( &ok );
1047 QList<transactionDelete>::iterator dIt = request.
deletes.begin();
1048 for ( ; dIt != request.
deletes.end(); ++dIt )
1055 else if ( parameters.contains( QStringLiteral(
"FILTER" ) ) )
1057 QString filterName = parameters.value( QStringLiteral(
"FILTER" ) );
1058 QStringList filterList;
1059 QRegExp rx(
"\\(([^()]+)\\)" );
1060 if ( rx.indexIn( filterName, 0 ) == -1 )
1062 filterList << filterName;
1067 while ( ( pos = rx.indexIn( filterName, pos ) ) != -1 )
1069 filterList << rx.cap( 1 );
1070 pos += rx.matchedLength();
1075 if ( request.
deletes.size() != filterList.size() )
1081 QList<transactionDelete>::iterator dIt = request.
deletes.begin();
1082 QStringList::const_iterator filterIt = filterList.constBegin();
1083 for ( ; dIt != request.
deletes.end(); ++dIt )
1088 QDomDocument filter;
1089 if ( filterIt != filterList.constEnd() )
1092 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
1098 QDomElement filterElem = filter.firstChildElement();
1099 QStringList serverFids;
1103 if ( filterIt != filterList.constEnd() )
1118 QDomNodeList docChildNodes = docElem.childNodes();
1120 QDomElement actionElem;
1123 for (
int i = docChildNodes.count(); 0 < i; --i )
1125 actionElem = docChildNodes.at( i - 1 ).toElement();
1126 actionName = actionElem.localName();
1128 if ( actionName == QLatin1String(
"Insert" ) )
1131 request.
inserts.append( action );
1133 else if ( actionName == QLatin1String(
"Update" ) )
1136 request.
updates.append( action );
1138 else if ( actionName == QLatin1String(
"Delete" ) )
1141 request.
deletes.append( action );
1150 QString
typeName = actionElem.attribute( QStringLiteral(
"typeName" ) );
1154 QDomElement filterElem = actionElem.firstChild().toElement();
1155 if ( filterElem.tagName() != QLatin1String(
"Filter" ) )
1160 QStringList serverFids;
1167 action.
error =
false;
1169 if ( actionElem.hasAttribute( QStringLiteral(
"handle" ) ) )
1171 action.
handle = actionElem.attribute( QStringLiteral(
"handle" ) );
1180 QString
typeName = actionElem.attribute( QStringLiteral(
"typeName" ) );
1184 QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral(
"Property" ) );
1185 if ( propertyNodeList.isEmpty() )
1190 QMap<QString, QString> propertyMap;
1191 QDomElement propertyElem;
1192 QDomElement nameElem;
1193 QDomElement valueElem;
1194 QDomElement geometryElem;
1196 for (
int l = 0; l < propertyNodeList.count(); ++l )
1198 propertyElem = propertyNodeList.at( l ).toElement();
1199 nameElem = propertyElem.elementsByTagName( QStringLiteral(
"Name" ) ).at( 0 ).toElement();
1200 valueElem = propertyElem.elementsByTagName( QStringLiteral(
"Value" ) ).at( 0 ).toElement();
1201 if ( nameElem.text() != QLatin1String(
"geometry" ) )
1203 propertyMap.insert( nameElem.text(), valueElem.text() );
1207 geometryElem = valueElem;
1211 QDomNodeList filterNodeList = actionElem.elementsByTagName( QStringLiteral(
"Filter" ) );
1213 QStringList serverFids;
1214 if ( filterNodeList.size() != 0 )
1216 QDomElement filterElem = filterNodeList.at( 0 ).toElement();
1227 action.
error =
false;
1229 if ( actionElem.hasAttribute( QStringLiteral(
"handle" ) ) )
1231 action.
handle = actionElem.attribute( QStringLiteral(
"handle" ) );
1239 QDomNodeList featureNodeList = actionElem.childNodes();
1240 if ( featureNodeList.size() != 1 )
1246 for (
int i = 0; i < featureNodeList.count(); ++i )
1248 QString tempTypeName = featureNodeList.at( i ).toElement().localName();
1249 if ( tempTypeName.contains(
':' ) )
1250 tempTypeName = tempTypeName.section(
':', 1, 1 );
1256 else if ( tempTypeName !=
typeName )
1265 action.
error =
false;
1267 if ( actionElem.hasAttribute( QStringLiteral(
"handle" ) ) )
1269 action.
handle = actionElem.attribute( QStringLiteral(
"handle" ) );
1278 void addTransactionResult( QDomDocument &responseDoc, QDomElement &resultsElem,
1279 const QString &locator,
const QString &message )
1281 QDomElement trElem = responseDoc.createElement( QStringLiteral(
"Action" ) );
1282 resultsElem.appendChild( trElem );
1284 if ( !locator.isEmpty() )
1286 trElem.setAttribute( QStringLiteral(
"locator" ), locator );
1289 if ( !message.isEmpty() )
1291 QDomElement mesElem = responseDoc.createElement( QStringLiteral(
"Message" ) );
1292 mesElem.appendChild( responseDoc.createTextNode( message ) );
1293 trElem.appendChild( mesElem );