diff --git a/locale/en/LC_MESSAGES/messages.po b/locale/en/LC_MESSAGES/messages.po index 34ad8c485..fab76819a 100644 --- a/locale/en/LC_MESSAGES/messages.po +++ b/locale/en/LC_MESSAGES/messages.po @@ -485,6 +485,18 @@ msgstr "" msgid "Display Tiles of" msgstr "" +#: pygeoapi/templates/collections/collection.html:92 +msgid "Coverages" +msgstr "" + +#: pygeoapi/templates/collections/collection.html:96 +msgid "Display Coverage" +msgstr "" + +#: pygeoapi/templates/collections/collection.html:97 +msgid "Display Coverage of" +msgstr "" + #: pygeoapi/templates/collections/index.html:13 msgid "Type" msgstr "" diff --git a/pygeoapi/api/collection.py b/pygeoapi/api/collection.py index 3b1f24922..2cd8b3ea6 100644 --- a/pygeoapi/api/collection.py +++ b/pygeoapi/api/collection.py @@ -228,13 +228,7 @@ def gen_collection(api, request, dataset: str, 'rel': f'{OGC_RELTYPES_BASE}/schema', 'title': l10n.translate('Schema of collection in HTML', locale_), 'href': f'{api.get_collections_url()}/{dataset}/schema?f={F_HTML}' - }]) - - if is_vector_tile or collection_data_type in ['feature', 'record']: - # TODO: translate - data['itemType'] = collection_data_type - LOGGER.debug('Adding feature/record based links') - data['links'].extend([{ + }, { 'type': 'application/schema+json', 'rel': f'{OGC_RELTYPES_BASE}/queryables', 'title': l10n.translate('Queryables for this collection as JSON', locale_), # noqa @@ -244,7 +238,13 @@ def gen_collection(api, request, dataset: str, 'rel': f'{OGC_RELTYPES_BASE}/queryables', 'title': l10n.translate('Queryables for this collection as HTML', locale_), # noqa 'href': f'{api.get_collections_url()}/{dataset}/queryables?f={F_HTML}' # noqa - }, { + }]) + + if is_vector_tile or collection_data_type in ['feature', 'record']: + # TODO: translate + LOGGER.debug('Adding feature/record based links') + data['itemType'] = collection_data_type + data['links'].extend([{ 'type': 'application/geo+json', 'rel': 'items', 'title': l10n.translate('Items as GeoJSON', locale_), @@ -278,12 +278,17 @@ def gen_collection(api, request, dataset: str, elif collection_data_type == 'coverage': LOGGER.debug('Adding coverage based links') - data['links'].append({ + data['links'].extend([{ 'type': 'application/prs.coverage+json', 'rel': f'{OGC_RELTYPES_BASE}/coverage', 'title': l10n.translate('Coverage data', locale_), 'href': f'{api.get_collections_url()}/{dataset}/coverage?f={F_JSON}' # noqa - }) + }, { + 'type': 'text/html', + 'rel': f'{OGC_RELTYPES_BASE}/coverage', + 'title': l10n.translate('Coverage data', locale_), + 'href': f'{api.get_collections_url()}/{dataset}/coverage?f={F_HTML}' # noqa + }]) if collection_data_format is not None: title_ = l10n.translate('Coverage data as', locale_) title_ = f"{title_} {collection_data_format['name']}" diff --git a/pygeoapi/api/coverages.py b/pygeoapi/api/coverages.py index 67755407d..2564071e8 100644 --- a/pygeoapi/api/coverages.py +++ b/pygeoapi/api/coverages.py @@ -41,14 +41,15 @@ import logging from http import HTTPStatus from typing import Tuple +import urllib from pygeoapi import l10n -from pygeoapi.formats import F_JSON +from pygeoapi.formats import F_JSON, F_COVERAGEJSON, F_HTML from pygeoapi.openapi import get_oas_30_parameters from pygeoapi.plugin import load_plugin from pygeoapi.provider.base import ProviderGenericError, ProviderTypeError from pygeoapi.provider import get_provider_by_type -from pygeoapi.util import filter_dict_by_key_value, to_json +from pygeoapi.util import filter_dict_by_key_value, to_json, render_j2_template from . import ( APIRequest, API, SYSTEM_LOCALE, validate_bbox, validate_datetime, @@ -86,6 +87,8 @@ def get_collection_coverage( # Force response content type and language (en-US only) headers headers = request.get_response_headers(SYSTEM_LOCALE, **api.api_headers) + collections = filter_dict_by_key_value(api.config['resources'], + 'type', 'collection') LOGGER.debug('Loading provider') try: @@ -142,6 +145,10 @@ def get_collection_coverage( query_args['datetime_'] = datetime_ query_args['format_'] = format_ + if request.format == F_HTML: + # Request as JSON to render HTML + query_args['format_'] = F_COVERAGEJSON + properties = request.params.get('properties') if properties: LOGGER.debug('Processing properties parameter') @@ -191,6 +198,39 @@ def get_collection_coverage( headers['Content-Type'] = collection_def['format']['mimetype'] return headers, HTTPStatus.OK, data + elif format_ == F_HTML: # render + tpl_config = api.get_dataset_templates(dataset) + + uri = f'{api.get_collections_url()}/{dataset}/coverage' + 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=',') + + data['query_path'] = uri + data['dataset_path'] = '/'.join(uri.split('/')[:-1]) + data['collections_path'] = api.get_collections_url() + + data['links'] = [{ + 'rel': 'collection', + 'title': collections[dataset]['title'], + 'href': data['dataset_path'] + }, { + 'type': 'application/vnd.cov+json', + 'rel': request.get_linkrel(F_COVERAGEJSON), + 'title': l10n.translate('This document as CoverageJSON', request.locale), # noqa + 'href': f'{uri}?f={F_COVERAGEJSON}{serialized_query_params}' + }] + + content = render_j2_template(api.tpl_config, tpl_config, + 'collections/coverage/index.html', + data, api.default_locale) + + return headers, HTTPStatus.OK, content + elif format_ == F_JSON: headers['Content-Type'] = 'application/prs.coverage+json' return headers, HTTPStatus.OK, to_json(data, api.pretty_print) diff --git a/pygeoapi/templates/collections/collection.html b/pygeoapi/templates/collections/collection.html index 2b3904dcc..4cfbfca0b 100644 --- a/pygeoapi/templates/collections/collection.html +++ b/pygeoapi/templates/collections/collection.html @@ -74,20 +74,40 @@

{% trans %}Schema{% endtrans %}

{% trans %}Display Schema of{% endtrans %} "{{ data['title'] }}" + {% endif %} + {% for provider in config['resources'][data['id']]['providers'] %} {% if 'tile' in provider['type'] %} -

{% trans %}Tiles{% endtrans %}

- +

{% trans %}Tiles{% endtrans %}

+ + {% endif %} + + {% if 'coverage' in provider['type'] %} +

{% trans %}Coverage{% endtrans %}

+ +

{% trans %}Schema{% endtrans %}

+ {% endif %} - {% endfor %} - {% endif %} + {% endfor %} {%- if data['data_queries'] -%}

Data Queries

diff --git a/pygeoapi/templates/collections/coverage/index.html b/pygeoapi/templates/collections/coverage/index.html new file mode 100644 index 000000000..59cc2afc4 --- /dev/null +++ b/pygeoapi/templates/collections/coverage/index.html @@ -0,0 +1,271 @@ +{% 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 query_type=data.query_type %}Coverage{% endtrans %} +{% endblock %} +{% block extrahead %} + + + + {% if data.type == "Coverage" or data.type == "CoverageCollection" %} + + + + + + + {% elif data.type == "Feature" or data.type == "FeatureCollection" %} + + + + {% endif %} +{% endblock %} + +{% block body %} +
+ {% if data.features or data.coverages or data.ranges or data.references %} +
+ {% else %} +
+

{% trans %}No items{% endtrans %}

+
+ {% endif %} +
+{% endblock %} + +{% block extrafoot %} +{% if data %} + +{% endif %} +{% endblock %} diff --git a/tests/api/test_coverages.py b/tests/api/test_coverages.py index bea6ac612..0ea2372ad 100644 --- a/tests/api/test_coverages.py +++ b/tests/api/test_coverages.py @@ -57,7 +57,7 @@ def test_describe_collections(config, api_): collection = json.loads(response) assert collection['id'] == 'gdps-temperature' - assert len(collection['links']) == 10 + assert len(collection['links']) == 13 assert collection['extent']['spatial']['grid'][0]['cellsCount'] == 2400 assert collection['extent']['spatial']['grid'][0]['resolution'] == 0.15000000000000002 # noqa assert collection['extent']['spatial']['grid'][1]['cellsCount'] == 1201 @@ -122,17 +122,14 @@ def test_get_collection_coverage(config, api_): rsp_headers, code, response = get_collection_coverage( api_, req, 'gdps-temperature') - assert code == HTTPStatus.BAD_REQUEST + assert code == HTTPStatus.OK assert rsp_headers['Content-Type'] == 'text/html' req = mock_api_request(HTTP_ACCEPT='text/html') rsp_headers, code, response = get_collection_coverage( api_, req, 'gdps-temperature') - # NOTE: This test used to assert the code to be 200 OK, - # but it requested HTML, which is not available, - # so it should be 400 Bad Request - assert code == HTTPStatus.BAD_REQUEST + assert code == HTTPStatus.OK assert rsp_headers['Content-Type'] == 'text/html' req = mock_api_request({'subset': 'Lat(5:10),Long(5:10)'})