mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Server: datetime basic filter support for OAPIF
This commit is contained in:
parent
6112da45f6
commit
595807171d
@ -49,11 +49,17 @@ Parses a comma separated ``bbox`` into a (possibly empty) :py:class:`QgsRectangl
|
||||
|
||||
static TemporalDateInterval parseTemporalDateInterval( const QString &interval ) throw( QgsServerApiBadRequestException );
|
||||
%Docstring
|
||||
Parse a date time ``interval`` and returns a TemporalInterval
|
||||
Parse a date ``interval`` and returns a TemporalDateInterval
|
||||
|
||||
:raises QgsServerApiBadRequestException: if interval cannot be parsed
|
||||
%End
|
||||
|
||||
static TemporalDateTimeInterval parseTemporalDateTimeInterval( const QString &interval ) throw( QgsServerApiBadRequestException );
|
||||
%Docstring
|
||||
Parse a datetime ``interval`` and returns a TemporalDateTimeInterval
|
||||
|
||||
:raises QgsServerApiBadRequestException: if interval cannot be parsed
|
||||
%End
|
||||
|
||||
|
||||
|
||||
|
@ -306,10 +306,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"time" : {
|
||||
"name" : "time",
|
||||
"datetime" : {
|
||||
"name" : "datetime",
|
||||
"in" : "query",
|
||||
"description" : "Either a date-time or a period string that adheres to RFC 3339. Examples:\n\n* A date-time: \"2018-02-12T23:20:50Z\"\n* A period: \"2018-02-12T00:00:00Z/2018-03-18T12:31:12Z\" or \"2018-02-12T00:00:00Z/P1M6DT12H31M12S\"\n\nOnly features that have a temporal property that intersects the value of\n`time` are selected.\n\nIf a feature has multiple temporal properties, it is the decision of the\nserver whether only a single temporal property is used to determine\nthe extent or all relevant temporal properties.",
|
||||
"description" : "Either a date-time or an interval, open or closed. Date and time expressions\nadhere to RFC 3339. Open intervals are expressed using double-dots.\n\nExamples:\n * A date-time: \"2018-02-12T23:20:50Z\"\n * A closed interval: \"2018-02-12T00:00:00Z/2018-03-18T12:31:12Z\"\n * Open intervals: \"2018-02-12T00:00:00Z/..\" or \"../2018-03-18T12:31:12Z\"\nOnly features that have a temporal property that intersects the value of\n`datetime` are selected.\nIf a feature has multiple temporal properties, it is the decision of the\nserver whether only a single temporal property is used to determine\nthe extent or all relevant temporal properties.",
|
||||
"required" : false,
|
||||
"style" : "form",
|
||||
"explode" : false,
|
||||
|
@ -279,7 +279,7 @@ void QgsSourceFieldsProperties::setRow( int row, int idx, const QgsField &field
|
||||
// ok, in theory, we could support any field type that
|
||||
// can contain something convertible to a date/datetime, but
|
||||
// let's keep it simple for now
|
||||
if ( field.isDateOrTime() )
|
||||
if ( field.isDateOrTime() || field.type() == QVariant::String )
|
||||
{
|
||||
oapifAttrItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
|
||||
oapifAttrItem->setCheckState( mLayer->includeAttributesOapifTemporalFilters().contains( field.name() ) ? Qt::Checked : Qt::Unchecked );
|
||||
|
@ -83,6 +83,10 @@ template<typename T, class T2> T QgsServerApiUtils::parseTemporalInterval( const
|
||||
}
|
||||
};
|
||||
const QStringList parts { interval.split( '/' ) };
|
||||
if ( parts.length() != 2 )
|
||||
{
|
||||
throw QgsServerApiBadRequestException( QStringLiteral( "%1 is not a valid datetime interval." ).arg( interval ), QStringLiteral( "Server" ), Qgis::Critical );
|
||||
}
|
||||
return { parseDate( parts[0] ), parseDate( parts[1] ) };
|
||||
|
||||
}
|
||||
@ -103,6 +107,25 @@ QgsExpression QgsServerApiUtils::temporalFilterExpression( const QgsVectorLayer
|
||||
QgsExpression expression;
|
||||
QStringList conditions;
|
||||
|
||||
QSet<QString> temporalFields { layer->includeAttributesOapifTemporalFilters() };
|
||||
// Automatically pick any date/datetime fields if empty
|
||||
if ( temporalFields.isEmpty() )
|
||||
{
|
||||
const auto constFields { layer->fields() };
|
||||
for ( const auto &f : constFields )
|
||||
{
|
||||
if ( f.isDateOrTime() )
|
||||
{
|
||||
temporalFields.insert( f.name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( temporalFields.isEmpty() )
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
|
||||
// Is it an interval?
|
||||
if ( interval.contains( '/' ) )
|
||||
{
|
||||
@ -110,7 +133,7 @@ QgsExpression QgsServerApiUtils::temporalFilterExpression( const QgsVectorLayer
|
||||
try
|
||||
{
|
||||
TemporalDateInterval dateInterval { QgsServerApiUtils::parseTemporalDateInterval( interval ) };
|
||||
for ( const auto &fieldName : layer->includeAttributesOapifTemporalFilters() )
|
||||
for ( const auto &fieldName : temporalFields )
|
||||
{
|
||||
int fieldIdx { layer->fields().lookupField( fieldName ) };
|
||||
if ( fieldIdx < 0 )
|
||||
@ -155,7 +178,7 @@ QgsExpression QgsServerApiUtils::temporalFilterExpression( const QgsVectorLayer
|
||||
catch ( QgsServerApiBadRequestException & ) // try datetime
|
||||
{
|
||||
TemporalDateTimeInterval dateTimeInterval { QgsServerApiUtils::parseTemporalDateTimeInterval( interval ) };
|
||||
for ( const auto &fieldName : layer->includeAttributesOapifTemporalFilters() )
|
||||
for ( const auto &fieldName : qgis::as_const( temporalFields ) )
|
||||
{
|
||||
int fieldIdx { layer->fields().lookupField( fieldName ) };
|
||||
if ( fieldIdx < 0 )
|
||||
@ -199,7 +222,7 @@ QgsExpression QgsServerApiUtils::temporalFilterExpression( const QgsVectorLayer
|
||||
}
|
||||
else // plain value
|
||||
{
|
||||
for ( const auto &fieldName : layer->includeAttributesOapifTemporalFilters() )
|
||||
for ( const auto &fieldName : qgis::as_const( temporalFields ) )
|
||||
{
|
||||
int fieldIdx { layer->fields().lookupField( fieldName ) };
|
||||
if ( fieldIdx < 0 )
|
||||
|
@ -59,12 +59,20 @@ class SERVER_EXPORT QgsServerApiUtils
|
||||
*/
|
||||
static QgsRectangle parseBbox( const QString &bbox );
|
||||
|
||||
/**
|
||||
* A temporal date interval, if only one of "begin" or "end" are valid, the interval is open.
|
||||
* If both "begin" and "end"a re invalid the interval is invalid.
|
||||
*/
|
||||
struct TemporalDateInterval
|
||||
{
|
||||
QDate begin;
|
||||
QDate end;
|
||||
};
|
||||
|
||||
/**
|
||||
* A temporal datetime interval, if only one of "begin" or "end" are valid, the interval is open.
|
||||
* If both "begin" and "end"a re invalid the interval is invalid.
|
||||
*/
|
||||
struct TemporalDateTimeInterval
|
||||
{
|
||||
QDateTime begin;
|
||||
@ -72,14 +80,21 @@ class SERVER_EXPORT QgsServerApiUtils
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a date time \a interval and returns a TemporalInterval
|
||||
* Parse a date \a interval and returns a TemporalDateInterval
|
||||
*
|
||||
* \throws QgsServerApiBadRequestException if interval cannot be parsed
|
||||
*/
|
||||
static TemporalDateInterval parseTemporalDateInterval( const QString &interval ) SIP_THROW( QgsServerApiBadRequestException );
|
||||
|
||||
/**
|
||||
* Parse a datetime \a interval and returns a TemporalDateTimeInterval
|
||||
*
|
||||
* \throws QgsServerApiBadRequestException if interval cannot be parsed
|
||||
*/
|
||||
static TemporalDateTimeInterval parseTemporalDateTimeInterval( const QString &interval ) SIP_THROW( QgsServerApiBadRequestException );
|
||||
|
||||
///@cond PRIVATE
|
||||
// T is TemporalDateInterval|TemporalDateTimeInterval, T2 is QDate|QdateTime
|
||||
template<typename T, class T2> static T parseTemporalInterval( const QString &interval ) SIP_SKIP;
|
||||
/// @endcond
|
||||
|
||||
@ -99,9 +114,6 @@ class SERVER_EXPORT QgsServerApiUtils
|
||||
|
||||
/**
|
||||
* layerExtent returns json array with [xMin,yMin,xMax,yMax] CRS84 extent for the given \a layer
|
||||
* FIXME: the OpenAPI swagger docs say that it is inverted axis order: West, north, east, south edges of the spatial extent.
|
||||
* but current example implementations and GDAL assume it's not.
|
||||
* TODO: maybe consider advertised extent instead?
|
||||
*/
|
||||
static json layerExtent( const QgsVectorLayer *layer ) SIP_SKIP;
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "qgsserverinterface.h"
|
||||
#include "qgsexpressioncontext.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
#include "qgsfilterrestorer.h"
|
||||
@ -759,12 +760,38 @@ QList<QgsServerQueryStringParameter> QgsWfs3CollectionsItemsHandler::parameters(
|
||||
|
||||
// datetime
|
||||
QgsServerQueryStringParameter datetime { QStringLiteral( "datetime" ), false,
|
||||
QgsServerQueryStringParameter::Type::Integer,
|
||||
QStringLiteral( "Date time filter" ),
|
||||
QgsServerQueryStringParameter::Type::String,
|
||||
QStringLiteral( "Datetime filter" ),
|
||||
};
|
||||
datetime.setCustomValidator( [ = ]( const QgsServerApiContext &, QVariant & value ) -> bool
|
||||
datetime.setCustomValidator( [ ]( const QgsServerApiContext &, QVariant & value ) -> bool
|
||||
{
|
||||
// TODO
|
||||
const QString stringValue { value.toString() };
|
||||
if ( stringValue.contains( '/' ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
QgsServerApiUtils::parseTemporalDateInterval( stringValue );
|
||||
}
|
||||
catch ( QgsServerException & )
|
||||
{
|
||||
try
|
||||
{
|
||||
QgsServerApiUtils::parseTemporalDateTimeInterval( stringValue );
|
||||
}
|
||||
catch ( QgsServerException & )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! QDate::fromString( stringValue, Qt::DateFormat::ISODate ).isValid( ) &&
|
||||
! QDateTime::fromString( stringValue, Qt::DateFormat::ISODate ).isValid( ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} );
|
||||
params.push_back( datetime );
|
||||
@ -870,7 +897,7 @@ json QgsWfs3CollectionsItemsHandler::schema( const QgsServerApiContext &context
|
||||
{ "$ref", "#/components/parameters/resultType" },
|
||||
{ "$ref", "#/components/parameters/bbox" },
|
||||
{ "$ref", "#/components/parameters/bbox-crs" },
|
||||
{ "$ref", "#/components/parameters/time" },
|
||||
{ "$ref", "#/components/parameters/datetime" },
|
||||
}
|
||||
};
|
||||
|
||||
@ -1044,7 +1071,7 @@ void QgsWfs3CollectionsItemsHandler::handleRequest( const QgsServerApiContext &c
|
||||
QString filterExpression;
|
||||
QStringList expressions;
|
||||
|
||||
/*/ datetime
|
||||
// datetime
|
||||
const QString datetime { context.request()->queryParameter( QStringLiteral( "datetime" ) ) };
|
||||
if ( ! datetime.isEmpty() )
|
||||
{
|
||||
@ -1057,7 +1084,7 @@ void QgsWfs3CollectionsItemsHandler::handleRequest( const QgsServerApiContext &c
|
||||
{
|
||||
expressions.push_back( timeExpression.expression() );
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Inputs are valid, process request
|
||||
QgsFeatureRequest featureRequest = filteredRequest( mapLayer, context );
|
||||
@ -1092,8 +1119,13 @@ void QgsWfs3CollectionsItemsHandler::handleRequest( const QgsServerApiContext &c
|
||||
}
|
||||
|
||||
// Join all expression filters
|
||||
filterExpression = expressions.join( QStringLiteral( " AND " ) );
|
||||
featureRequest.setFilterExpression( filterExpression );
|
||||
if ( ! expressions.isEmpty() )
|
||||
{
|
||||
filterExpression = expressions.join( QStringLiteral( " AND " ) );
|
||||
featureRequest.setFilterExpression( filterExpression );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Filter expression: %1" ).arg( featureRequest.filterExpression()->expression() ), 4 );
|
||||
}
|
||||
|
||||
|
||||
// WFS3 core specs only serves 4326
|
||||
featureRequest.setDestinationCrs( crs, context.project()->transformContext() );
|
||||
|
@ -471,14 +471,19 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
response = self.compareApi(request, project, 'test_wfs3_collections_items_layer1_with_short_name_eq_tw_star.json')
|
||||
self.assertEqual(response.statusCode(), 200)
|
||||
|
||||
def test_wfs3_excluded_attributes(self):
|
||||
"""Test excluded attributes"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/exclude_attribute/items/0.geojson')
|
||||
response = self.compareApi(request, project, 'test_wfs3_collections_items_exclude_attribute_0.json')
|
||||
self.assertEqual(response.statusCode(), 200)
|
||||
|
||||
def test_wfs3_time_filters(self):
|
||||
"""Test datetime filters"""
|
||||
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api_timefilters.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/points/items?name=lus*')
|
||||
response = self.compareApi(request, project, 'test_wfs3_collections_items_points_eq_lus.json')
|
||||
self.assertEqual(response.statusCode(), 200)
|
||||
|
||||
# Prepare 3 projects with all three options: "created", "updated", both.
|
||||
tmpDir = QtCore.QTemporaryDir()
|
||||
@ -493,10 +498,14 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
both_path = os.path.join(tmpDir.path(), 'test_project_api_timefilters_both.qgs')
|
||||
project.write(both_path)
|
||||
|
||||
# Test data:
|
||||
#wkt_geom fid name created updated
|
||||
#Point (7.30355493642693343 44.82162158126364915) 2 bricherasio 2019-05-05 2020-05-05T05:05:05.000
|
||||
#Point (7.2500747591236081 44.81342128741047048) 1 luserna 2019-01-01 2020-01-01T10:10:10.000
|
||||
'''
|
||||
Test data:
|
||||
wkt_geom fid name created updated
|
||||
Point (7.2500747591236081 44.81342128741047048) 1 luserna 2019-01-01 2020-01-01T10:10:10.000
|
||||
Point (7.30355493642693343 44.82162158126364915) 2 bricherasio 2019-05-05 2020-05-05T05:05:05.000
|
||||
Point (7.28848021144956881 44.79768920192042714) 3 bibiana
|
||||
Point (7.22555186948937145 44.82015087638781381) 4 torre 2019-10-10 2019-10-10T10:10:10.000
|
||||
'''
|
||||
|
||||
# What to test:
|
||||
#interval-closed = date-time "/" date-time
|
||||
@ -505,9 +514,9 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
#interval = interval-closed / interval-open-start / interval-open-end
|
||||
#datetime = date-time / interval
|
||||
|
||||
def _date_tester(project_path, expected, unexpected):
|
||||
def _date_tester(project_path, datetime, expected, unexpected):
|
||||
# Test "created" date field exact
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/points/items?datetime=2019-05-05')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/points/items?datetime=%s' % datetime)
|
||||
response = QgsBufferServerResponse()
|
||||
project.read(project_path)
|
||||
self.server.handleRequest(request, response, project)
|
||||
@ -517,16 +526,89 @@ class QgsServerAPITest(QgsServerAPITestBase):
|
||||
for unexp in unexpected:
|
||||
self.assertFalse(unexp in body)
|
||||
|
||||
# Test "created" date field exact
|
||||
_date_tester(created_path, ['bricherasio'], ['luserna'])
|
||||
# Test single values
|
||||
|
||||
def test_wfs3_excluded_attributes(self):
|
||||
"""Test excluded attributes"""
|
||||
project = QgsProject()
|
||||
project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs')
|
||||
request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/exclude_attribute/items/0.geojson')
|
||||
response = self.compareApi(request, project, 'test_wfs3_collections_items_exclude_attribute_0.json')
|
||||
self.assertEqual(response.statusCode(), 200)
|
||||
##################################################################################
|
||||
# Test "created" date field
|
||||
# Test exact
|
||||
_date_tester(created_path, '2019-05-05', ['bricherasio'], ['luserna', 'torre'])
|
||||
# Test datetime field exact (test that we can use a time on a date type field)
|
||||
_date_tester(created_path, '2019-05-05T01:01:01', ['bricherasio'], ['luserna', 'torre'])
|
||||
# Test exact no match
|
||||
_date_tester(created_path, '2019-05-06', [], ['luserna', 'bricherasio', 'torre'])
|
||||
|
||||
##################################################################################
|
||||
# Test "updated" datetime field
|
||||
# Test exact
|
||||
_date_tester(updated_path, '2020-05-05T05:05:05', ['bricherasio'], ['luserna', 'torre'])
|
||||
# Test date field exact (test that we can NOT use a date on a datetime type field)
|
||||
_date_tester(updated_path, '2020-05-05', [], ['luserna', 'bricherasio', 'torre'])
|
||||
# Test exact no match
|
||||
_date_tester(updated_path, '2020-05-06T05:05:05', [], ['luserna', 'bricherasio', 'torre'])
|
||||
|
||||
##################################################################################
|
||||
# Test both
|
||||
# Test exact
|
||||
_date_tester(both_path, '2019-10-10T10:10:10', ['torre'], ['bricherasio', 'luserna'])
|
||||
# Test date field exact (test that we can NOT use a date on a datetime type field)
|
||||
_date_tester(both_path, '2020-05-05', [], ['luserna', 'bricherasio', 'torre'])
|
||||
# Test exact no match
|
||||
_date_tester(both_path, '2020-05-06T05:05:05', [], ['luserna', 'bricherasio', 'torre'])
|
||||
|
||||
# Test intervals
|
||||
|
||||
##################################################################################
|
||||
# Test "created" date field
|
||||
_date_tester(created_path, '2019-05-04/2019-05-06', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(created_path, '2019-05-04/..', ['bricherasio', 'torre'], ['luserna'])
|
||||
_date_tester(created_path, '2019-05-04/', ['bricherasio', 'torre'], ['luserna'])
|
||||
_date_tester(created_path, '2100-05-04/', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(created_path, '2100-05-04/..', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(created_path, '/2019-05-06', ['bricherasio', 'luserna'], ['torre'])
|
||||
_date_tester(created_path, '/2019-01-02', ['luserna'], ['torre', 'bricherasio'])
|
||||
_date_tester(created_path, '../2019-05-06', ['bricherasio', 'luserna'], ['torre'])
|
||||
_date_tester(created_path, '../2019-01-02', ['luserna'], ['torre', 'bricherasio'])
|
||||
|
||||
# Test datetimes on "created" date field
|
||||
_date_tester(created_path, '2019-05-04T01:01:01/2019-05-06T01:01:01', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(created_path, '2019-05-04T01:01:01/..', ['bricherasio', 'torre'], ['luserna'])
|
||||
_date_tester(created_path, '2019-05-04T01:01:01/', ['bricherasio', 'torre'], ['luserna'])
|
||||
_date_tester(created_path, '2100-05-04T01:01:01/', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(created_path, '2100-05-04T01:01:01/..', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(created_path, '/2019-05-06T01:01:01', ['bricherasio', 'luserna'], ['torre'])
|
||||
_date_tester(created_path, '/2019-01-02T01:01:01', ['luserna'], ['torre', 'bricherasio'])
|
||||
_date_tester(created_path, '../2019-05-06T01:01:01', ['bricherasio', 'luserna'], ['torre'])
|
||||
_date_tester(created_path, '../2019-01-02T01:01:01', ['luserna'], ['torre', 'bricherasio'])
|
||||
|
||||
##################################################################################
|
||||
# Test "updated" date field
|
||||
_date_tester(updated_path, '2020-05-04/2020-05-06', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2020-05-04/..', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2020-05-04/', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2100-05-04/', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(updated_path, '2100-05-04/..', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(updated_path, '/2020-02-02', ['torre', 'luserna'], ['bricherasio'])
|
||||
_date_tester(updated_path, '/2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
_date_tester(updated_path, '../2020-02-02', ['torre', 'luserna'], ['bricherasio'])
|
||||
_date_tester(updated_path, '../2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
|
||||
# Test datetimes on "updated" datetime field
|
||||
_date_tester(updated_path, '2020-05-04/2020-05-06', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2020-05-04/..', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2020-05-04/', ['bricherasio'], ['luserna', 'torre'])
|
||||
_date_tester(updated_path, '2100-05-04/', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(updated_path, '2100-05-04/..', [], ['luserna', 'bricherasio', 'torre'])
|
||||
_date_tester(updated_path, '/2020-02-02', ['torre', 'luserna'], ['bricherasio'])
|
||||
_date_tester(updated_path, '/2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
_date_tester(updated_path, '../2020-02-02', ['torre', 'luserna'], ['bricherasio'])
|
||||
_date_tester(updated_path, '../2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
|
||||
##################################################################################
|
||||
# Test both
|
||||
_date_tester(both_path, '2019-10-09/2019-10-11', ['torre'], ['luserna', 'bricherasio'])
|
||||
_date_tester(both_path, '2019-05-04/2020-05-06', ['torre', 'bricherasio'], ['luserna'])
|
||||
_date_tester(both_path, '../2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
_date_tester(both_path, '/2020-01-01', ['luserna', 'torre'], ['bricherasio'])
|
||||
|
||||
|
||||
class Handler1(QgsServerOgcApiHandler):
|
||||
|
@ -53,6 +53,17 @@ Content-Type: application/openapi+json;version=3.0
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
"datetime": {
|
||||
"description": "Either a date-time or an interval, open or closed. Date and time expressions\nadhere to RFC 3339. Open intervals are expressed using double-dots.\n\nExamples:\n * A date-time: \"2018-02-12T23:20:50Z\"\n * A closed interval: \"2018-02-12T00:00:00Z/2018-03-18T12:31:12Z\"\n * Open intervals: \"2018-02-12T00:00:00Z/..\" or \"../2018-03-18T12:31:12Z\"\nOnly features that have a temporal property that intersects the value of\n`datetime` are selected.\nIf a feature has multiple temporal properties, it is the decision of the\nserver whether only a single temporal property is used to determine\nthe extent or all relevant temporal properties.",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "datetime",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
"featureId": {
|
||||
"description": "Local identifier of a specific feature",
|
||||
"in": "path",
|
||||
@ -121,17 +132,6 @@ Content-Type: application/openapi+json;version=3.0
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
},
|
||||
"time": {
|
||||
"description": "Either a date-time or a period string that adheres to RFC 3339. Examples:\n\n* A date-time: \"2018-02-12T23:20:50Z\"\n* A period: \"2018-02-12T00:00:00Z/2018-03-18T12:31:12Z\" or \"2018-02-12T00:00:00Z/P1M6DT12H31M12S\"\n\nOnly features that have a temporal property that intersects the value of\n`time` are selected.\n\nIf a feature has multiple temporal properties, it is the decision of the\nserver whether only a single temporal property is used to determine\nthe extent or all relevant temporal properties.",
|
||||
"explode": false,
|
||||
"in": "query",
|
||||
"name": "time",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"style": "form"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
|
BIN
tests/testdata/qgis_server/test_project_api_timefilters.gpkg
vendored
Normal file
BIN
tests/testdata/qgis_server/test_project_api_timefilters.gpkg
vendored
Normal file
Binary file not shown.
765
tests/testdata/qgis_server/test_project_api_timefilters.qgs
vendored
Normal file
765
tests/testdata/qgis_server/test_project_api_timefilters.qgs
vendored
Normal file
@ -0,0 +1,765 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis projectname="QGIS Test Project API" version="3.9.0-Master">
|
||||
<homePath path=""/>
|
||||
<title>QGIS Test Project API</title>
|
||||
<autotransaction active="0"/>
|
||||
<evaluateDefaultValues active="0"/>
|
||||
<trust active="0"/>
|
||||
<projectCrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</projectCrs>
|
||||
<layer-tree-group>
|
||||
<customproperties/>
|
||||
<layer-tree-layer providerKey="ogr" source="./test_project_api_timefilters.gpkg|layername=points" checked="Qt::Checked" expanded="1" id="points_47ad3bc8_35bd_4392_8994_2dc5ff04be60" name="points">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<custom-order enabled="0">
|
||||
<item>points_47ad3bc8_35bd_4392_8994_2dc5ff04be60</item>
|
||||
</custom-order>
|
||||
</layer-tree-group>
|
||||
<snapping-settings mode="1" type="2" tolerance="0" unit="2" enabled="0" intersection-snapping="0">
|
||||
<individual-layer-settings>
|
||||
<layer-setting units="1" type="1" tolerance="12" enabled="0" id="points_47ad3bc8_35bd_4392_8994_2dc5ff04be60"/>
|
||||
</individual-layer-settings>
|
||||
</snapping-settings>
|
||||
<relations/>
|
||||
<mapcanvas annotationsVisible="1" name="theMapCanvas">
|
||||
<units>degrees</units>
|
||||
<extent>
|
||||
<xmin>7.25418797910206159</xmin>
|
||||
<ymin>44.7955945616427087</ymin>
|
||||
<xmax>7.3179146610253607</xmax>
|
||||
<ymax>44.85094654515160784</ymax>
|
||||
</extent>
|
||||
<rotation>0</rotation>
|
||||
<destinationsrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</destinationsrs>
|
||||
<rendermaptile>0</rendermaptile>
|
||||
<expressionContextScope/>
|
||||
</mapcanvas>
|
||||
<projectModels/>
|
||||
<legend updateDrawingOrder="true">
|
||||
<legendlayer drawingOrder="-1" checked="Qt::Checked" open="true" name="points" showFeatureCount="0">
|
||||
<filegroup hidden="false" open="true">
|
||||
<legendlayerfile isInOverview="0" visible="1" layerid="points_47ad3bc8_35bd_4392_8994_2dc5ff04be60"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
</legend>
|
||||
<mapViewDocks/>
|
||||
<projectlayers>
|
||||
<maplayer simplifyDrawingTol="1.2" maxScale="0" refreshOnNotifyMessage="" styleCategories="AllStyleCategories" readOnly="0" geometry="Point" refreshOnNotifyEnabled="0" minScale="1e+08" autoRefreshTime="0" simplifyMaxScale="1" labelsEnabled="0" simplifyDrawingHints="0" autoRefreshEnabled="0" wkbType="Point" simplifyLocal="1" hasScaleBasedVisibilityFlag="0" simplifyAlgorithm="0" type="vector">
|
||||
<extent>
|
||||
<xmin>7.25007390975952148</xmin>
|
||||
<ymin>44.79768753051757813</ymin>
|
||||
<xmax>7.30355501174926758</xmax>
|
||||
<ymax>44.82162857055664063</ymax>
|
||||
</extent>
|
||||
<id>points_47ad3bc8_35bd_4392_8994_2dc5ff04be60</id>
|
||||
<datasource>./test_project_api_timefilters.gpkg|layername=points</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>points</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type>dataset</type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial maxz="0" miny="0" minz="0" maxx="0" dimensions="2" crs="" maxy="0" minx="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<legend type="default-vector"/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<auxiliaryLayer/>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<renderer-v2 type="singleSymbol" symbollevels="0" enableorderby="0" forceraster="0">
|
||||
<symbols>
|
||||
<symbol clip_to_extent="1" type="marker" alpha="1" force_rhr="0" name="0">
|
||||
<layer enabled="1" class="SimpleMarker" pass="0" locked="0">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="232,113,141,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="circle"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="2"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<customproperties>
|
||||
<property key="dualview/previewExpressions">
|
||||
<value>name</value>
|
||||
</property>
|
||||
<property key="embeddedWidgets/count" value="0"/>
|
||||
<property key="variableNames"/>
|
||||
<property key="variableValues"/>
|
||||
</customproperties>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<SingleCategoryDiagramRenderer diagramType="Histogram" attributeLegend="1">
|
||||
<DiagramCategory minScaleDenominator="0" barWidth="5" labelPlacementMethod="XHeight" sizeScale="3x:0,0,0,0,0,0" rotationOffset="270" maxScaleDenominator="1e+08" enabled="0" diagramOrientation="Up" backgroundAlpha="255" lineSizeScale="3x:0,0,0,0,0,0" sizeType="MM" penAlpha="255" width="15" scaleBasedVisibility="0" backgroundColor="#ffffff" lineSizeType="MM" penColor="#000000" height="15" scaleDependency="Area" opacity="1" minimumSize="0" penWidth="0">
|
||||
<fontProperties description="Noto Sans,10,-1,5,50,0,0,0,0,0,Regular" style="Regular"/>
|
||||
<attribute field="" color="#000000" label=""/>
|
||||
</DiagramCategory>
|
||||
</SingleCategoryDiagramRenderer>
|
||||
<DiagramLayerSettings zIndex="0" showAll="1" placement="0" priority="0" dist="0" linePlacementFlags="18" obstacle="0">
|
||||
<properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</properties>
|
||||
</DiagramLayerSettings>
|
||||
<geometryOptions removeDuplicateNodes="0" geometryPrecision="0">
|
||||
<activeChecks/>
|
||||
<checkConfiguration/>
|
||||
</geometryOptions>
|
||||
<fieldConfiguration>
|
||||
<field name="fid">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="name">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="created">
|
||||
<editWidget type="DateTime">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="updated">
|
||||
<editWidget type="DateTime">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<aliases>
|
||||
<alias field="fid" index="0" name=""/>
|
||||
<alias field="name" index="1" name=""/>
|
||||
<alias field="created" index="2" name=""/>
|
||||
<alias field="updated" index="3" name=""/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<includeAttributesOapifTemporalFilters/>
|
||||
<defaults>
|
||||
<default applyOnUpdate="0" field="fid" expression=""/>
|
||||
<default applyOnUpdate="0" field="name" expression=""/>
|
||||
<default applyOnUpdate="0" field="created" expression=""/>
|
||||
<default applyOnUpdate="0" field="updated" expression=""/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint exp_strength="0" field="fid" constraints="3" notnull_strength="1" unique_strength="1"/>
|
||||
<constraint exp_strength="0" field="name" constraints="0" notnull_strength="0" unique_strength="0"/>
|
||||
<constraint exp_strength="0" field="created" constraints="0" notnull_strength="0" unique_strength="0"/>
|
||||
<constraint exp_strength="0" field="updated" constraints="0" notnull_strength="0" unique_strength="0"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint field="fid" desc="" exp=""/>
|
||||
<constraint field="name" desc="" exp=""/>
|
||||
<constraint field="created" desc="" exp=""/>
|
||||
<constraint field="updated" desc="" exp=""/>
|
||||
</constraintExpressions>
|
||||
<expressionfields/>
|
||||
<attributeactions>
|
||||
<defaultAction key="Canvas" value="{00000000-0000-0000-0000-000000000000}"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig sortOrder="0" sortExpression="" actionWidgetStyle="dropDown">
|
||||
<columns>
|
||||
<column type="field" width="-1" hidden="0" name="fid"/>
|
||||
<column type="field" width="-1" hidden="0" name="name"/>
|
||||
<column type="actions" width="-1" hidden="1"/>
|
||||
<column type="field" width="-1" hidden="0" name="created"/>
|
||||
<column type="field" width="497" hidden="0" name="updated"/>
|
||||
</columns>
|
||||
</attributetableconfig>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<storedexpressions/>
|
||||
<editform tolerant="1"></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS forms can have a Python function that is called when the form is
|
||||
opened.
|
||||
|
||||
Use this function to add extra logic to your forms.
|
||||
|
||||
Enter the name of the function in the "Python Init function"
|
||||
field.
|
||||
An example follows:
|
||||
"""
|
||||
from qgis.PyQt.QtWidgets import QWidget
|
||||
|
||||
def my_form_open(dialog, layer, feature):
|
||||
geom = feature.geometry()
|
||||
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||
]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<editable>
|
||||
<field editable="1" name="created"/>
|
||||
<field editable="1" name="fid"/>
|
||||
<field editable="1" name="name"/>
|
||||
<field editable="1" name="updated"/>
|
||||
</editable>
|
||||
<labelOnTop>
|
||||
<field name="created" labelOnTop="0"/>
|
||||
<field name="fid" labelOnTop="0"/>
|
||||
<field name="name" labelOnTop="0"/>
|
||||
<field name="updated" labelOnTop="0"/>
|
||||
</labelOnTop>
|
||||
<widgets/>
|
||||
<previewExpression>name</previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
</projectlayers>
|
||||
<layerorder>
|
||||
<layer id="points_47ad3bc8_35bd_4392_8994_2dc5ff04be60"/>
|
||||
</layerorder>
|
||||
<properties>
|
||||
<DefaultStyles>
|
||||
<AlphaInt type="int">255</AlphaInt>
|
||||
<ColorRamp type="QString"></ColorRamp>
|
||||
<Fill type="QString"></Fill>
|
||||
<Line type="QString"></Line>
|
||||
<Marker type="QString"></Marker>
|
||||
<Opacity type="double">1</Opacity>
|
||||
<RandomColors type="bool">true</RandomColors>
|
||||
</DefaultStyles>
|
||||
<Digitizing>
|
||||
<AvoidIntersectionsList type="QStringList"/>
|
||||
<DefaultSnapTolerance type="double">0</DefaultSnapTolerance>
|
||||
<DefaultSnapToleranceUnit type="int">2</DefaultSnapToleranceUnit>
|
||||
<DefaultSnapType type="QString">off</DefaultSnapType>
|
||||
<LayerSnapToList type="QStringList"/>
|
||||
<LayerSnappingEnabledList type="QStringList"/>
|
||||
<LayerSnappingList type="QStringList"/>
|
||||
<LayerSnappingToleranceList type="QStringList"/>
|
||||
<LayerSnappingToleranceUnitList type="QStringList"/>
|
||||
<SnappingMode type="QString">current_layer</SnappingMode>
|
||||
</Digitizing>
|
||||
<Gui>
|
||||
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
|
||||
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
|
||||
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
|
||||
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
|
||||
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
|
||||
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
|
||||
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
|
||||
</Gui>
|
||||
<Identify>
|
||||
<disabledLayers type="QStringList">
|
||||
<value>testlayer_0b835118_a5d5_4255_b5dd_f42253c0a4a0</value>
|
||||
</disabledLayers>
|
||||
</Identify>
|
||||
<Legend>
|
||||
<filterByMap type="bool">false</filterByMap>
|
||||
</Legend>
|
||||
<Macros>
|
||||
<pythonCode type="QString"></pythonCode>
|
||||
</Macros>
|
||||
<Measure>
|
||||
<Ellipsoid type="QString">WGS84</Ellipsoid>
|
||||
</Measure>
|
||||
<Measurement>
|
||||
<AreaUnits type="QString">m2</AreaUnits>
|
||||
<DistanceUnits type="QString">meters</DistanceUnits>
|
||||
</Measurement>
|
||||
<PAL>
|
||||
<CandidatesLine type="int">50</CandidatesLine>
|
||||
<CandidatesPoint type="int">16</CandidatesPoint>
|
||||
<CandidatesPolygon type="int">30</CandidatesPolygon>
|
||||
<DrawOutlineLabels type="bool">true</DrawOutlineLabels>
|
||||
<DrawRectOnly type="bool">false</DrawRectOnly>
|
||||
<DrawUnplaced type="bool">false</DrawUnplaced>
|
||||
<SearchMethod type="int">0</SearchMethod>
|
||||
<ShowingAllLabels type="bool">false</ShowingAllLabels>
|
||||
<ShowingCandidates type="bool">false</ShowingCandidates>
|
||||
<ShowingPartialsLabels type="bool">true</ShowingPartialsLabels>
|
||||
<TextFormat type="int">0</TextFormat>
|
||||
<UnplacedColor type="QString">255,0,0,255</UnplacedColor>
|
||||
</PAL>
|
||||
<Paths>
|
||||
<Absolute type="bool">false</Absolute>
|
||||
</Paths>
|
||||
<PositionPrecision>
|
||||
<Automatic type="bool">true</Automatic>
|
||||
<DecimalPlaces type="int">2</DecimalPlaces>
|
||||
<DegreeFormat type="QString">D</DegreeFormat>
|
||||
</PositionPrecision>
|
||||
<RequiredLayers>
|
||||
<Layers type="QStringList"/>
|
||||
</RequiredLayers>
|
||||
<SpatialRefSys>
|
||||
<ProjectCRSID type="int">3452</ProjectCRSID>
|
||||
<ProjectCRSProj4String type="QString">+proj=longlat +datum=WGS84 +no_defs</ProjectCRSProj4String>
|
||||
<ProjectCrs type="QString">EPSG:4326</ProjectCrs>
|
||||
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
|
||||
</SpatialRefSys>
|
||||
<Variables>
|
||||
<variableNames type="QStringList"/>
|
||||
<variableValues type="QStringList"/>
|
||||
</Variables>
|
||||
<WCSLayers type="QStringList"/>
|
||||
<WCSUrl type="QString"></WCSUrl>
|
||||
<WFSLayers type="QStringList">
|
||||
<value>points_47ad3bc8_35bd_4392_8994_2dc5ff04be60</value>
|
||||
</WFSLayers>
|
||||
<WFSLayersPrecision>
|
||||
<points_47ad3bc8_35bd_4392_8994_2dc5ff04be60 type="int">8</points_47ad3bc8_35bd_4392_8994_2dc5ff04be60>
|
||||
<testlayer20150528120452665 type="int">8</testlayer20150528120452665>
|
||||
<testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a type="int">8</testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a>
|
||||
<testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de type="int">8</testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de>
|
||||
<testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774 type="int">8</testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774>
|
||||
</WFSLayersPrecision>
|
||||
<WFSTLayers>
|
||||
<Delete type="QStringList"/>
|
||||
<Insert type="QStringList"/>
|
||||
<Update type="QStringList"/>
|
||||
</WFSTLayers>
|
||||
<WFSUrl type="QString"></WFSUrl>
|
||||
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
|
||||
<WMSAddWktGeometry type="bool">true</WMSAddWktGeometry>
|
||||
<WMSContactMail type="QString">elpaso@itopen.it</WMSContactMail>
|
||||
<WMSContactOrganization type="QString">QGIS dev team</WMSContactOrganization>
|
||||
<WMSContactPerson type="QString">Alessandro Pasotti</WMSContactPerson>
|
||||
<WMSContactPhone type="QString"></WMSContactPhone>
|
||||
<WMSContactPosition type="QString"></WMSContactPosition>
|
||||
<WMSDefaultMapUnitsPerMm type="double">1</WMSDefaultMapUnitsPerMm>
|
||||
<WMSExtent type="QStringList">
|
||||
<value>8.20315414376310059</value>
|
||||
<value>44.901236559338642</value>
|
||||
<value>8.204164917965862</value>
|
||||
<value>44.90159838674664172</value>
|
||||
</WMSExtent>
|
||||
<WMSFees type="QString">conditions unknown</WMSFees>
|
||||
<WMSImageQuality type="int">90</WMSImageQuality>
|
||||
<WMSKeywordList type="QStringList">
|
||||
<value></value>
|
||||
</WMSKeywordList>
|
||||
<WMSMaxAtlasFeatures type="int">1</WMSMaxAtlasFeatures>
|
||||
<WMSOnlineResource type="QString"></WMSOnlineResource>
|
||||
<WMSPrecision type="QString">4</WMSPrecision>
|
||||
<WMSRequestDefinedDataSources type="bool">false</WMSRequestDefinedDataSources>
|
||||
<WMSRestrictedComposers type="QStringList"/>
|
||||
<WMSRestrictedLayers type="QStringList"/>
|
||||
<WMSRootName type="QString"></WMSRootName>
|
||||
<WMSSegmentizeFeatureInfoGeometry type="bool">false</WMSSegmentizeFeatureInfoGeometry>
|
||||
<WMSServiceAbstract type="QString">Some UTF8 text èòù</WMSServiceAbstract>
|
||||
<WMSServiceCapabilities type="bool">true</WMSServiceCapabilities>
|
||||
<WMSServiceTitle type="QString">QGIS TestProject</WMSServiceTitle>
|
||||
<WMSTileBuffer type="int">0</WMSTileBuffer>
|
||||
<WMSUrl type="QString"></WMSUrl>
|
||||
<WMSUseLayerIDs type="bool">false</WMSUseLayerIDs>
|
||||
<WMTSGrids>
|
||||
<CRS type="QStringList"/>
|
||||
<Config type="QStringList"/>
|
||||
</WMTSGrids>
|
||||
<WMTSJpegLayers>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
</WMTSJpegLayers>
|
||||
<WMTSLayers>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
</WMTSLayers>
|
||||
<WMTSMinScale type="int">5000</WMTSMinScale>
|
||||
<WMTSPngLayers>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
</WMTSPngLayers>
|
||||
<WMTSUrl type="QString"></WMTSUrl>
|
||||
</properties>
|
||||
<visibility-presets/>
|
||||
<transformContext/>
|
||||
<projectMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title>QGIS Test Project API</title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<author></author>
|
||||
<creation>2000-01-01T00:00:00</creation>
|
||||
</projectMetadata>
|
||||
<Annotations/>
|
||||
<Layouts>
|
||||
<Layout units="mm" printResolution="300" worldFileMap="" name="mytemplate">
|
||||
<Snapper snapToGuides="1" tolerance="5" snapToItems="1" snapToGrid="0"/>
|
||||
<Grid resolution="10" offsetUnits="mm" offsetX="0" offsetY="0" resUnits="mm"/>
|
||||
<PageCollection>
|
||||
<symbol clip_to_extent="1" type="fill" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleFill" pass="0" locked="0">
|
||||
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="color" v="255,255,255,255"/>
|
||||
<prop k="joinstyle" v="miter"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_style" v="no"/>
|
||||
<prop k="outline_width" v="0.26"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="style" v="solid"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
<LayoutItem referencePoint="0" groupUuid="" positionOnPage="0,0,mm" positionLock="false" background="true" visibility="1" excludeFromExports="0" id="" zValue="0" frameJoinStyle="miter" uuid="{45febe5f-bfdd-455a-aef5-c096b4677622}" size="297,210,mm" itemRotation="0" outlineWidthM="0.3,mm" position="0,0,mm" templateUuid="{45febe5f-bfdd-455a-aef5-c096b4677622}" blendMode="0" opacity="1" frame="false" type="65638">
|
||||
<FrameColor blue="0" alpha="255" green="0" red="0"/>
|
||||
<BackgroundColor blue="255" alpha="255" green="255" red="255"/>
|
||||
<LayoutObject>
|
||||
<dataDefinedProperties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</dataDefinedProperties>
|
||||
<customproperties/>
|
||||
</LayoutObject>
|
||||
<symbol clip_to_extent="1" type="fill" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleFill" pass="0" locked="0">
|
||||
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="color" v="255,255,255,255"/>
|
||||
<prop k="joinstyle" v="miter"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="no"/>
|
||||
<prop k="outline_width" v="0.26"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="style" v="solid"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</LayoutItem>
|
||||
<GuideCollection visible="1"/>
|
||||
</PageCollection>
|
||||
<LayoutItem referencePoint="0" followPreset="false" followPresetName="" groupUuid="" positionOnPage="126,143,mm" mapRotation="0" positionLock="false" background="true" visibility="1" excludeFromExports="0" mapFlags="1" id="" zValue="2" frameJoinStyle="miter" uuid="{5ed7a90f-8af2-4535-a15e-e18a7f6c5d1f}" size="61,26,mm" itemRotation="0" outlineWidthM="0.3,mm" position="126,143,mm" drawCanvasItems="true" labelMargin="0,mm" templateUuid="{5ed7a90f-8af2-4535-a15e-e18a7f6c5d1f}" blendMode="0" opacity="1" keepLayerSet="false" frame="false" type="65639">
|
||||
<FrameColor blue="0" alpha="255" green="0" red="0"/>
|
||||
<BackgroundColor blue="255" alpha="255" green="255" red="255"/>
|
||||
<LayoutObject>
|
||||
<dataDefinedProperties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</dataDefinedProperties>
|
||||
<customproperties/>
|
||||
</LayoutObject>
|
||||
<Extent xmax="8.20679772684772146" ymin="44.90025542156142535" xmin="8.20128754650006186" ymax="44.90260402302108389"/>
|
||||
<LayerSet/>
|
||||
<ComposerMapGrid leftAnnotationPosition="1" name="Grille 1" topAnnotationDirection="0" unit="0" annotationFontColor="0,0,0,255" topAnnotationDisplay="0" rightAnnotationPosition="1" minimumIntervalWidth="50" annotationPrecision="3" gridFrameWidth="2" gridStyle="0" bottomAnnotationDirection="0" topFrameDivisions="0" show="0" leftFrameDivisions="0" annotationExpression="" position="3" bottomAnnotationPosition="1" offsetX="0" rightFrameDivisions="0" leftAnnotationDirection="0" frameFillColor1="255,255,255,255" bottomAnnotationDisplay="0" rightAnnotationDirection="0" annotationFormat="0" offsetY="0" gridFramePenColor="0,0,0,255" showAnnotation="0" topAnnotationPosition="1" uuid="{ca78854d-b53f-4d8b-97bd-6bbf0df72ad0}" frameFillColor2="0,0,0,255" intervalX="0" rightAnnotationDisplay="0" crossLength="3" intervalY="0" gridFrameStyle="0" leftAnnotationDisplay="0" blendMode="0" gridFramePenThickness="0.5" frameAnnotationDistance="1" gridFrameSideFlags="15" gridFrameMargin="0" maximumIntervalWidth="100" bottomFrameDivisions="0">
|
||||
<lineStyle>
|
||||
<symbol clip_to_extent="1" type="line" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleLine" pass="0" locked="0">
|
||||
<prop k="capstyle" v="square"/>
|
||||
<prop k="customdash" v="5;2"/>
|
||||
<prop k="customdash_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="customdash_unit" v="MM"/>
|
||||
<prop k="draw_inside_polygon" v="0"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="line_color" v="0,0,0,255"/>
|
||||
<prop k="line_style" v="solid"/>
|
||||
<prop k="line_width" v="0"/>
|
||||
<prop k="line_width_unit" v="MM"/>
|
||||
<prop k="offset" v="0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="ring_filter" v="0"/>
|
||||
<prop k="use_custom_dash" v="0"/>
|
||||
<prop k="width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</lineStyle>
|
||||
<markerStyle>
|
||||
<symbol clip_to_extent="1" type="marker" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleMarker" pass="0" locked="0">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="0,0,0,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="circle"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="2"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</markerStyle>
|
||||
<annotationFontProperties description="Cantarell,11,-1,5,50,0,0,0,0,0" style=""/>
|
||||
<LayoutObject>
|
||||
<dataDefinedProperties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</dataDefinedProperties>
|
||||
<customproperties/>
|
||||
</LayoutObject>
|
||||
</ComposerMapGrid>
|
||||
<AtlasMap atlasDriven="0" scalingMode="2" margin="0.10000000000000001"/>
|
||||
<labelBlockingItems/>
|
||||
</LayoutItem>
|
||||
<LayoutItem referencePoint="0" followPreset="false" followPresetName="" groupUuid="" positionOnPage="98.7716,20.1872,mm" mapRotation="0" positionLock="false" background="true" visibility="1" excludeFromExports="0" mapFlags="1" id="" zValue="1" frameJoinStyle="miter" uuid="{8fec18d6-8ba0-47d6-914e-3daffe8a8633}" size="87,103,mm" itemRotation="0" outlineWidthM="0.3,mm" position="98.7716,20.1872,mm" drawCanvasItems="true" labelMargin="0,mm" templateUuid="{8fec18d6-8ba0-47d6-914e-3daffe8a8633}" blendMode="0" opacity="1" keepLayerSet="false" frame="false" type="65639">
|
||||
<FrameColor blue="0" alpha="255" green="0" red="0"/>
|
||||
<BackgroundColor blue="255" alpha="255" green="255" red="255"/>
|
||||
<LayoutObject>
|
||||
<dataDefinedProperties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</dataDefinedProperties>
|
||||
<customproperties/>
|
||||
</LayoutObject>
|
||||
<Extent xmax="8.20606418507941449" ymin="44.89903639486862374" xmin="8.20202108826836884" ymax="44.9038230497138855"/>
|
||||
<LayerSet/>
|
||||
<ComposerMapGrid leftAnnotationPosition="1" name="Grille 1" topAnnotationDirection="0" unit="0" annotationFontColor="0,0,0,255" topAnnotationDisplay="0" rightAnnotationPosition="1" minimumIntervalWidth="50" annotationPrecision="3" gridFrameWidth="2" gridStyle="0" bottomAnnotationDirection="0" topFrameDivisions="0" show="0" leftFrameDivisions="0" annotationExpression="" position="3" bottomAnnotationPosition="1" offsetX="0" rightFrameDivisions="0" leftAnnotationDirection="0" frameFillColor1="255,255,255,255" bottomAnnotationDisplay="0" rightAnnotationDirection="0" annotationFormat="0" offsetY="0" gridFramePenColor="0,0,0,255" showAnnotation="0" topAnnotationPosition="1" uuid="{94630841-1b07-4bc2-9cf7-1dce50a01a3e}" frameFillColor2="0,0,0,255" intervalX="0" rightAnnotationDisplay="0" crossLength="3" intervalY="0" gridFrameStyle="0" leftAnnotationDisplay="0" blendMode="0" gridFramePenThickness="0.5" frameAnnotationDistance="1" gridFrameSideFlags="15" gridFrameMargin="0" maximumIntervalWidth="100" bottomFrameDivisions="0">
|
||||
<lineStyle>
|
||||
<symbol clip_to_extent="1" type="line" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleLine" pass="0" locked="0">
|
||||
<prop k="capstyle" v="square"/>
|
||||
<prop k="customdash" v="5;2"/>
|
||||
<prop k="customdash_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="customdash_unit" v="MM"/>
|
||||
<prop k="draw_inside_polygon" v="0"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="line_color" v="0,0,0,255"/>
|
||||
<prop k="line_style" v="solid"/>
|
||||
<prop k="line_width" v="0"/>
|
||||
<prop k="line_width_unit" v="MM"/>
|
||||
<prop k="offset" v="0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="ring_filter" v="0"/>
|
||||
<prop k="use_custom_dash" v="0"/>
|
||||
<prop k="width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</lineStyle>
|
||||
<markerStyle>
|
||||
<symbol clip_to_extent="1" type="marker" alpha="1" force_rhr="0" name="">
|
||||
<layer enabled="1" class="SimpleMarker" pass="0" locked="0">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="0,0,0,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="circle"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="2"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</markerStyle>
|
||||
<annotationFontProperties description="Cantarell,11,-1,5,50,0,0,0,0,0" style=""/>
|
||||
<LayoutObject>
|
||||
<dataDefinedProperties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" value="" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" value="collection" name="type"/>
|
||||
</Option>
|
||||
</dataDefinedProperties>
|
||||
<customproperties/>
|
||||
</LayoutObject>
|
||||
</ComposerMapGrid>
|
||||
<AtlasMap atlasDriven="0" scalingMode="2" margin="0.10000000000000001"/>
|
||||
<labelBlockingItems/>
|
||||
</LayoutItem>
|
||||
<customproperties/>
|
||||
<Atlas coverageLayer="" hideCoverage="0" sortFeatures="0" enabled="0" filenamePattern="'output_'||@atlas_featurenumber" pageNameExpression="" filterFeatures="0"/>
|
||||
</Layout>
|
||||
</Layouts>
|
||||
<Bookmarks/>
|
||||
</qgis>
|
Loading…
x
Reference in New Issue
Block a user