Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions pygeoapi/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1747,3 +1747,53 @@ def evaluate_limit(requested: Union[None, int], server_limits: dict,
else:
LOGGER.debug('limit requested')
return min(requested2, max_)


def evaluate_limit_distance(server_limits: dict, collection_limits: dict,
request_bbox: list = []) -> bool:
"""
Helper function to evaluate limit parameter

:param server_limits: `dict` of server limits
:param collection_limits: `dict` of collection limits
:param request_bbox: `list` bbox of request

:returns: `bool` successful distance check
"""

exceed_msg = None

effective_limits = ChainMap(collection_limits, server_limits)

on_exceed = effective_limits.get('on_exceed', 'throttle')
max_distance_x = effective_limits.get('max_distance_x')
max_distance_y = effective_limits.get('max_distance_y')
max_distance_units = effective_limits.get('max_distance_units')

LOGGER.debug(f'On exceed: {on_exceed}')
LOGGER.debug(f'Maximum distance x: {max_distance_x}')
LOGGER.debug(f'Maximum distance y: {max_distance_y}')
LOGGER.debug(f'Maximum distance units: {max_distance_units}')

# TODO: assess distance units

if not request_bbox:
LOGGER.debug('no bbox requested')
return True

if max_distance_x is not None:
requested_distance_x = abs(request_bbox[2] - request_bbox[0])
if requested_distance_x > max_distance_x:
exceed_msg = 'Maximum distance x exceeded'

if max_distance_y is not None:
requested_distance_y = abs(request_bbox[3] - request_bbox[1])
if requested_distance_y > max_distance_y:
exceed_msg = 'Maximum distance y exceeded'

if exceed_msg is not None:
LOGGER.warning(exceed_msg)
if on_exceed == 'error':
raise ValueError(exceed_msg)

return True
10 changes: 7 additions & 3 deletions pygeoapi/api/coverages.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@
)

from . import (
APIRequest, API, F_JSON, SYSTEM_LOCALE, validate_bbox, validate_datetime,
validate_subset
)
APIRequest, API, F_JSON, SYSTEM_LOCALE, evaluate_limit_distance,
validate_bbox, validate_datetime, validate_subset)

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -112,6 +111,11 @@ def get_collection_coverage(
else:
try:
bbox = validate_bbox(bbox)
server_limits = api.config['server'].get('limits', {})
collection_limits = api.config['resources'][dataset].get('limits', {}) # noqa

_ = evaluate_limit_distance(request.params.get('bbox', []),
server_limits, collection_limits)
except ValueError as err:
msg = str(err)
return api.get_exception(
Expand Down
8 changes: 7 additions & 1 deletion pygeoapi/api/environmental_data_retrieval.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from shapely.wkt import loads as shapely_loads

from pygeoapi import l10n
from pygeoapi.api import evaluate_limit
from pygeoapi.api import evaluate_limit, evaluate_limit_distance
from pygeoapi.formatter.base import FormatterSerializationError
from pygeoapi.crs import (create_crs_transform_spec, set_content_crs_header)
from pygeoapi.openapi import get_oas_30_parameters
Expand Down Expand Up @@ -345,6 +345,12 @@ def get_collection_edr_query(api: API, request: APIRequest,
LOGGER.debug('Processing cube bbox')
try:
bbox = validate_bbox(request.params.get('bbox'))
server_limits = api.config['server'].get('limits', {})
collection_limits = api.config['resources'][dataset].get('limits', {}) # noqa

_ = evaluate_limit_distance(request.params.get('bbox', []),
server_limits, collection_limits)

if not bbox and query_type == 'cube':
raise ValueError('bbox parameter required by cube queries')
except ValueError as err:
Expand Down
10 changes: 7 additions & 3 deletions pygeoapi/api/itemtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from pyproj.exceptions import CRSError

from pygeoapi import l10n
from pygeoapi.api import evaluate_limit
from pygeoapi.api import evaluate_limit, evaluate_limit_distance
from pygeoapi.api.pubsub import publish_message
from pygeoapi.crs import (DEFAULT_CRS, DEFAULT_STORAGE_CRS,
create_crs_transform_spec, get_supported_crs_list,
Expand Down Expand Up @@ -290,9 +290,13 @@ def get_collection_items(
'level (RFC5)')
LOGGER.warning(msg)
try:
server_limits = api.config['server'].get('limits', {})
collection_limits = collections[dataset].get('limits', {})

limit = evaluate_limit(request.params.get('limit'),
api.config['server'].get('limits', {}),
collections[dataset].get('limits', {}))
server_limits, collection_limits)
_ = evaluate_limit_distance(request.params.get('bbox', []),
server_limits, collection_limits)
except ValueError as err:
return api.get_exception(
HTTPStatus.BAD_REQUEST, headers, request.format,
Expand Down
26 changes: 23 additions & 3 deletions tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@
from pygeoapi.api import (
API, APIRequest, FORMAT_TYPES, F_HTML, F_JSON, F_JSONLD, F_GZIP,
__version__, validate_bbox, validate_datetime, evaluate_limit,
validate_subset, landing_page, openapi_, conformance, describe_collections,
get_collection_schema,
)
evaluate_limit_distance, validate_subset, landing_page, openapi_,
conformance, describe_collections, get_collection_schema)
from pygeoapi.util import yaml_load, get_api_rules, get_base_url

from tests.util import (get_test_file_path, mock_api_request, mock_flask,
Expand Down Expand Up @@ -913,3 +912,24 @@ def test_evaluate_limit():

assert evaluate_limit(None, server, collection) == 10
assert evaluate_limit('40', server, collection) == 3


def test_evaluate_limit_distance():
collection = {
'on_exceed': 'error',
'max_distance_x': 10,
'max_distance_y': 10
}

with pytest.raises(ValueError):
assert evaluate_limit_distance(
{}, collection, request_bbox=[-180, -90, 180, 90])

assert evaluate_limit_distance({}, collection,
request_bbox=[-142, 42, -140, 44])

assert evaluate_limit_distance({}, {}, request_bbox=[-180, -90, 180, 90])

collection['on_exceed'] = 'throttle'
assert evaluate_limit_distance(
{}, collection, request_bbox=[-180, -90, 180, 90])