Skip to content

Commit

Permalink
Fix QGIS Server WFS geometryless DescribeFeatureType
Browse files Browse the repository at this point in the history
Fixes #30381
  • Loading branch information
elpaso committed Jun 26, 2019
1 parent e8c1b29 commit b572a4d
Show file tree
Hide file tree
Showing 4 changed files with 485 additions and 98 deletions.
192 changes: 94 additions & 98 deletions src/server/services/wfs/qgswfsdescribefeaturetype.cpp
Expand Up @@ -144,10 +144,6 @@ namespace QgsWfs
{
continue;
}
if ( layer->type() != QgsMapLayerType::VectorLayer )
{
continue;
}

QString name = layerTypeName( layer );

Expand Down Expand Up @@ -254,113 +250,113 @@ namespace QgsWfs
geomElem.setAttribute( QStringLiteral( "minOccurs" ), QStringLiteral( "0" ) );
geomElem.setAttribute( QStringLiteral( "maxOccurs" ), QStringLiteral( "1" ) );
sequenceElem.appendChild( geomElem );
}

//Attributes
QgsFields fields = layer->fields();
//hidden attributes for this layer
const QSet<QString> &layerExcludedAttributes = layer->excludeAttributesWfs();
for ( int idx = 0; idx < fields.count(); ++idx )
//Attributes
QgsFields fields = layer->fields();
//hidden attributes for this layer
const QSet<QString> &layerExcludedAttributes = layer->excludeAttributesWfs();
for ( int idx = 0; idx < fields.count(); ++idx )
{
const QgsField field = fields.at( idx );
QString attributeName = field.name();
//skip attribute if excluded from WFS publication
if ( layerExcludedAttributes.contains( attributeName ) )
{
const QgsField field = fields.at( idx );
QString attributeName = field.name();
//skip attribute if excluded from WFS publication
if ( layerExcludedAttributes.contains( attributeName ) )
{
continue;
}
continue;
}

//xsd:element
QDomElement attElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
attElem.setAttribute( QStringLiteral( "name" ), attributeName.replace( ' ', '_' ).replace( cleanTagNameRegExp, QString() ) );
QVariant::Type attributeType = field.type();
if ( attributeType == QVariant::Int )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
}
else if ( attributeType == QVariant::UInt )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "unsignedInt" ) );
}
else if ( attributeType == QVariant::LongLong )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "long" ) );
}
else if ( attributeType == QVariant::ULongLong )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "unsignedLong" ) );
}
else if ( attributeType == QVariant::Double )
{
if ( field.length() > 0 && field.precision() == 0 )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) );
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "decimal" ) );
}
else if ( attributeType == QVariant::Bool )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "boolean" ) );
}
else if ( attributeType == QVariant::Date )
{
//xsd:element
QDomElement attElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
attElem.setAttribute( QStringLiteral( "name" ), attributeName.replace( ' ', '_' ).replace( cleanTagNameRegExp, QString() ) );
QVariant::Type attributeType = field.type();
if ( attributeType == QVariant::Int )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
}
else if ( attributeType == QVariant::UInt )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "unsignedInt" ) );
}
else if ( attributeType == QVariant::LongLong )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "long" ) );
}
else if ( attributeType == QVariant::ULongLong )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "unsignedLong" ) );
}
else if ( attributeType == QVariant::Double )
{
if ( field.length() > 0 && field.precision() == 0 )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) );
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "decimal" ) );
}
else if ( attributeType == QVariant::Bool )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "boolean" ) );
}
else if ( attributeType == QVariant::Date )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
}
else if ( attributeType == QVariant::Time )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
}
else if ( attributeType == QVariant::DateTime )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) );
}
else
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "string" ) );
}

const QgsEditorWidgetSetup setup = field.editorWidgetSetup();
if ( setup.type() == QStringLiteral( "DateTime" ) )
{
QgsDateTimeFieldFormatter fieldFormatter;
const QVariantMap config = setup.config();
const QString fieldFormat = config.value( QStringLiteral( "field_format" ), fieldFormatter.defaultFormat( field.type() ) ).toString();
if ( fieldFormat == QStringLiteral( "yyyy-MM-dd" ) )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
}
else if ( attributeType == QVariant::Time )
{
else if ( fieldFormat == QStringLiteral( "HH:mm:ss" ) )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
}
else if ( attributeType == QVariant::DateTime )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) );
}
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) );
}
else if ( setup.type() == QStringLiteral( "Range" ) )
{
const QVariantMap config = setup.config();
if ( config.contains( QStringLiteral( "Precision" ) ) )
{
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "string" ) );
}

const QgsEditorWidgetSetup setup = field.editorWidgetSetup();
if ( setup.type() == QStringLiteral( "DateTime" ) )
{
QgsDateTimeFieldFormatter fieldFormatter;
const QVariantMap config = setup.config();
const QString fieldFormat = config.value( QStringLiteral( "field_format" ), fieldFormatter.defaultFormat( field.type() ) ).toString();
if ( fieldFormat == QStringLiteral( "yyyy-MM-dd" ) )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
else if ( fieldFormat == QStringLiteral( "HH:mm:ss" ) )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "dateTime" ) );
}
else if ( setup.type() == QStringLiteral( "Range" ) )
{
const QVariantMap config = setup.config();
if ( config.contains( QStringLiteral( "Precision" ) ) )
// if precision in range config is not the same as the attributePrec
// we need to update type
bool ok;
int configPrec( config[ QStringLiteral( "Precision" ) ].toInt( &ok ) );
if ( ok && configPrec != field.precision() )
{
// if precision in range config is not the same as the attributePrec
// we need to update type
bool ok;
int configPrec( config[ QStringLiteral( "Precision" ) ].toInt( &ok ) );
if ( ok && configPrec != field.precision() )
{
if ( configPrec == 0 )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) );
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "decimal" ) );
}
if ( configPrec == 0 )
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "integer" ) );
else
attElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "decimal" ) );
}
}
}

if ( !( field.constraints().constraints() & QgsFieldConstraints::Constraint::ConstraintNotNull ) )
{
attElem.setAttribute( QStringLiteral( "nillable" ), QStringLiteral( "true" ) );
}
if ( !( field.constraints().constraints() & QgsFieldConstraints::Constraint::ConstraintNotNull ) )
{
attElem.setAttribute( QStringLiteral( "nillable" ), QStringLiteral( "true" ) );
}

sequenceElem.appendChild( attElem );
sequenceElem.appendChild( attElem );

QString alias = field.alias();
if ( !alias.isEmpty() )
{
attElem.setAttribute( QStringLiteral( "alias" ), alias );
}
QString alias = field.alias();
if ( !alias.isEmpty() )
{
attElem.setAttribute( QStringLiteral( "alias" ), alias );
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions tests/src/python/test_qgsserver_wfs.py
Expand Up @@ -533,6 +533,14 @@ def _round_trip(value, field, version='1.1.0'):
self.assertTrue(b'<TotalUpdated>0</TotalUpdated>' in body)
self.assertTrue(b'<Message>NOT NULL constraint error on layer \'cdb_lines\', field \'name\'</Message>' in body, body)

def test_describeFeatureTypeGeometryless(self):
"""Test DescribeFeatureType with geometryless tables - bug GH-30381"""

project_file = "test_project_geometryless_gh30381.qgs"
self.wfs_request_compare("DescribeFeatureType", '1.1.0',
reference_base_name='wfs_describeFeatureType_1_1_0_geometryless',
project_file=project_file)


if __name__ == '__main__':
unittest.main()

0 comments on commit b572a4d

Please sign in to comment.