diff --git a/pygeoapi/api/environmental_data_retrieval.py b/pygeoapi/api/environmental_data_retrieval.py index 945cffb8a..b449ce257 100644 --- a/pygeoapi/api/environmental_data_retrieval.py +++ b/pygeoapi/api/environmental_data_retrieval.py @@ -48,13 +48,14 @@ from pygeoapi import l10n from pygeoapi.plugin import load_plugin, PLUGINS -from pygeoapi.provider.base import ProviderGenericError +from pygeoapi.provider.base import ( + ProviderGenericError, ProviderItemNotFoundError) from pygeoapi.util import ( filter_providers_by_type, get_provider_by_type, render_j2_template, to_json, filter_dict_by_key_value ) -from . import (APIRequest, API, F_COVERAGEJSON, F_HTML, F_JSONLD, +from . import (APIRequest, API, F_COVERAGEJSON, F_HTML, F_JSON, F_JSONLD, validate_datetime, validate_bbox) LOGGER = logging.getLogger(__name__) @@ -64,6 +65,172 @@ ] +def get_collection_edr_instances(api: API, request: APIRequest, dataset, + instance_id=None) -> Tuple[dict, int, str]: + """ + Queries collection EDR instances + + :param request: APIRequest instance with query params + :param dataset: dataset name + + :returns: tuple of headers, status code, content + """ + + data = { + 'instances': [], + 'links': [] + } + + if not request.is_valid(PLUGINS['formatter'].keys()): + return api.get_format_exception(request) + headers = request.get_response_headers(api.default_locale, + **api.api_headers) + collections = filter_dict_by_key_value(api.config['resources'], + 'type', 'collection') + + if dataset not in collections.keys(): + msg = 'Collection not found' + return api.get_exception( + HTTPStatus.NOT_FOUND, headers, request.format, 'NotFound', msg) + + uri = f'{api.get_collections_url()}/{dataset}' + + LOGGER.debug('Loading provider') + try: + p = load_plugin('provider', get_provider_by_type( + collections[dataset]['providers'], 'edr')) + except ProviderGenericError as err: + return api.get_exception( + err.http_status_code, headers, request.format, + err.ogc_exception_code, err.message) + + if instance_id is not None: + try: + instances = [p.get_instance(instance_id)] + except ProviderItemNotFoundError: + msg = 'Instance not found' + return api.get_exception( + HTTPStatus.NOT_FOUND, headers, request.format, 'NotFound', msg) + else: + instances = p.instances() + + for instance in instances: + instance_dict = { + 'id': instance, + 'links': [{ + 'href': f'{uri}/instances/{instance}?f={F_JSON}', + 'rel': request.get_linkrel(F_JSON), + 'type': 'application/json' + }, { + 'href': f'{uri}/instances/{instance}?f={F_HTML}', + 'rel': request.get_linkrel(F_HTML), + 'type': 'text/html' + }, { + 'href': f'{uri}?f={F_HTML}', + 'rel': 'collection', + 'title': collections[dataset]['title'], + 'type': 'text/html' + }, { + 'href': f'{uri}?f={F_JSON}', + 'rel': 'collection', + 'title': collections[dataset]['title'], + 'type': 'application/json' + }], + 'data_queries': {} + } + + for qt in p.get_query_types(): + if qt == 'instances': + continue + data_query = { + 'link': { + 'href': f'{uri}/instances/{instance}/{qt}', + 'rel': 'data', + 'title': f'{qt} query' + } + } + instance_dict['data_queries'][qt] = data_query + + data['instances'].append(instance_dict) + + if instance_id is not None: + data = data['instances'][0] + data.pop('instances', None) + links_uri = f'{uri}/instances/{instance_id}' + else: + links_uri = f'{uri}/instances' + + if instance_id is None: + data['links'].extend([{ + 'href': f'{links_uri}?f={F_JSON}', + 'rel': request.get_linkrel(F_JSON), + 'type': 'application/json' + }, { + 'href': f'{links_uri}?f={F_HTML}', + 'rel': request.get_linkrel(F_HTML), + 'type': 'text/html' + }]) + + if request.format == F_HTML: # render + api.set_dataset_templates(dataset) + + serialized_query_params = '' + for k, v in request.params.items(): + if k != 'f': + serialized_query_params += '&' + serialized_query_params += urllib.parse.quote(k, safe='') + serialized_query_params += '=' + serialized_query_params += urllib.parse.quote(str(v), safe=',') + + if instance_id is None: + uri = f'{uri}/instances' + else: + uri = f'{uri}/instances/{instance_id}' + + data['query_type'] = 'instances' + data['query_path'] = uri + data['title'] = collections[dataset]['title'] + data['description'] = collections[dataset]['description'] + data['keywords'] = collections[dataset]['keywords'] + data['collections_path'] = api.get_collections_url() + + if instance_id is None: + data['dataset_path'] = data['collections_path'] + '/' + uri.split('/')[-2] # noqa + template = 'collections/edr/instances.html' + else: + data['dataset_path'] = data['collections_path'] + '/' + uri.split('/')[-3] # noqa + template = 'collections/edr/instance.html' + + data['links'] = [{ + 'rel': 'collection', + 'title': collections[dataset]['title'], + 'href': f"{data['dataset_path']}?f={F_JSON}", + 'type': 'text/html' + }, { + 'rel': 'collection', + 'title': collections[dataset]['title'], + 'href': f"{data['dataset_path']}?f={F_HTML}", + 'type': 'application/json' + }, { + 'type': 'application/json', + 'rel': 'alternate', + 'title': l10n.translate('This document as JSON', request.locale), + 'href': f'{uri}?f={F_JSON}{serialized_query_params}' + }, { + 'type': 'application/ld+json', + 'rel': 'alternate', + 'title': l10n.translate('This document as JSON-LD', request.locale), # noqa + 'href': f'{uri}?f={F_JSONLD}{serialized_query_params}' + }] + + content = render_j2_template(api.tpl_config, template, data, + api.default_locale) + else: + content = to_json(data, api.pretty_print) + + return headers, HTTPStatus.OK, content + + def get_collection_edr_query(api: API, request: APIRequest, dataset, instance, query_type, location_id=None) -> Tuple[dict, int, str]: diff --git a/pygeoapi/flask_app.py b/pygeoapi/flask_app.py index 26d6094ab..a5d0c2695 100644 --- a/pygeoapi/flask_app.py +++ b/pygeoapi/flask_app.py @@ -465,8 +465,8 @@ def get_job_result(job_id=None): @BLUEPRINT.route('/collections//radius') @BLUEPRINT.route('/collections//trajectory') @BLUEPRINT.route('/collections//corridor') -@BLUEPRINT.route('/collections//locations/') # noqa -@BLUEPRINT.route('/collections//locations') # noqa +@BLUEPRINT.route('/collections//locations/') +@BLUEPRINT.route('/collections//locations') @BLUEPRINT.route('/collections//instances//position') # noqa @BLUEPRINT.route('/collections//instances//area') # noqa @BLUEPRINT.route('/collections//instances//cube') # noqa @@ -475,6 +475,8 @@ def get_job_result(job_id=None): @BLUEPRINT.route('/collections//instances//corridor') # noqa @BLUEPRINT.route('/collections//instances//locations/') # noqa @BLUEPRINT.route('/collections//instances//locations') # noqa +@BLUEPRINT.route('/collections//instances/') +@BLUEPRINT.route('/collections//instances') def get_collection_edr_query(collection_id, instance_id=None, location_id=None): """ @@ -487,6 +489,14 @@ def get_collection_edr_query(collection_id, instance_id=None, :returns: HTTP response """ + if (request.path.endswith('instances') or + (instance_id is not None and + request.path.endswith(instance_id))): + return execute_from_flask( + edr_api.get_collection_edr_instances, request, collection_id, + instance_id + ) + if location_id: query_type = 'locations' else: @@ -494,8 +504,7 @@ def get_collection_edr_query(collection_id, instance_id=None, return execute_from_flask( edr_api.get_collection_edr_query, request, collection_id, instance_id, - query_type, location_id, - skip_valid_check=True, + query_type, location_id, skip_valid_check=True ) diff --git a/pygeoapi/provider/base_edr.py b/pygeoapi/provider/base_edr.py index 021b2f403..e92f5e730 100644 --- a/pygeoapi/provider/base_edr.py +++ b/pygeoapi/provider/base_edr.py @@ -54,7 +54,7 @@ def __init__(self, provider_def): super().__init__(provider_def) - self.instances = [] +# self.instances = [] @classmethod def register(cls): diff --git a/pygeoapi/templates/collections/edr/instance.html b/pygeoapi/templates/collections/edr/instance.html new file mode 100644 index 000000000..5f4054d69 --- /dev/null +++ b/pygeoapi/templates/collections/edr/instance.html @@ -0,0 +1,42 @@ +{% extends "_base.html" %} +{% block title %}{{ super() }} {{ data['title'] }} {% endblock %} +{% block crumbs %}{{ super() }} +/ {% trans %}Collections{% endtrans %} +{% for link in data['links'] %} + {% if link.rel == 'collection' %} / + {{ link['title'] | truncate( 25 ) }} + {% set col_title = link['title'] %} + {% endif %} +{% endfor %} +/ {% trans %}Instances{% endtrans %} +/ {{ data['id'] }} +{% endblock %} +{% block body %} +
+

{{ data['title'] }}

+

{{ data['description'] }}

+

+ {% for kw in data['keywords'] %} + {{ kw }} + {% endfor %} +

+

{% trans %}Instance{% endtrans %} {{ data['id'] }}

+
+

{% trans %}Links{% endtrans %}

+ +{% endblock %} diff --git a/pygeoapi/templates/collections/edr/instances.html b/pygeoapi/templates/collections/edr/instances.html new file mode 100644 index 000000000..a3e5393dc --- /dev/null +++ b/pygeoapi/templates/collections/edr/instances.html @@ -0,0 +1,29 @@ +{% extends "_base.html" %} +{% block title %}{{ super() }} {{ data['title'] }} {% endblock %} +{% block crumbs %}{{ super() }} +/ {% trans %}Collections{% endtrans %} +{% for link in data['links'] %} + {% if link.rel == 'collection' %} / + {{ link['title'] | truncate( 25 ) }} + {% set col_title = link['title'] %} + {% endif %} +{% endfor %} +/ {% trans %}Instances{% endtrans %} +{% endblock %} +{% block body %} +
+

{{ data['title'] }}

+

{{ data['description'] }}

+

+ {% for kw in data['keywords'] %} + {{ kw }} + {% endfor %} +

+

{% trans %}Instances{% endtrans %}

+ +
+{% endblock %}