diff --git a/ckanext/nhm/lib/helpers.py b/ckanext/nhm/lib/helpers.py index 0188c10f..d434e6cc 100644 --- a/ckanext/nhm/lib/helpers.py +++ b/ckanext/nhm/lib/helpers.py @@ -1599,3 +1599,31 @@ def get_record_iiif_manifest_url(resource_id: str, record_id: int) -> str: {'builder_id': 'record', 'resource_id': resource_id, 'record_id': record_id}, ) return toolkit.url_for('iiif.resource', identifier=manifest_id, _external=True) + + +def get_status_indicator(): + """ + Check if we need to display a status indicator, and if so what type. + + :return: 'red', 'amber', or None (if no alerts) + """ + # is there a status message? + status_message = toolkit.config.get('ckanext.status.message', None) + if status_message: + return 'red' + + try: + status_reports = toolkit.get_action('status_list')({}, {}).get('reports', []) + except KeyError: + # if the action doesn't exist + status_reports = [] + + # are there any 'bad' items? + red_status = [r for r in status_reports if r['state'] == 'bad'] + if len(red_status) > 0: + return 'red' + + # are there any reports with small issues? + amber_status = [r for r in status_reports if r['state'] == 'ok'] + if len(amber_status) > 0: + return 'amber' diff --git a/ckanext/nhm/lib/mail.py b/ckanext/nhm/lib/mail.py index e9b5f668..398b8333 100644 --- a/ckanext/nhm/lib/mail.py +++ b/ckanext/nhm/lib/mail.py @@ -29,7 +29,7 @@ def create_department_email(mail_dict: dict, department: str): mail_dict['recipient_email'] = COLLECTION_CONTACTS[department] except KeyError: # Other/unknown etc., - so don't set recipient email - mail_dict['body'] += f'\nDepartment: {department}\n' + mail_dict['body'] += f'\nDepartment or team: {department}\n' else: mail_dict['recipient_name'] = department mail_dict['body'] += ( @@ -74,6 +74,9 @@ def get_package_owners(package: dict) -> List[Recipient]: :param package: the package dict """ + maintainer_name = package.get('maintainer', 'Maintainer') + maintainer_email = package.get('maintainer_email') + collaborators = toolkit.get_action('package_collaborator_list')( # ignore auth to ensure we can access the list of collaborators {'ignore_auth': True}, @@ -81,14 +84,19 @@ def get_package_owners(package: dict) -> List[Recipient]: {'id': package['id'], 'capacity': 'admin'}, ) - recipient_ids = [] - if collaborators: - recipient_ids.extend(collaborator['user_id'] for collaborator in collaborators) + recipients = [] + if maintainer_email: + recipients.append(Recipient(maintainer_name, maintainer_email)) + elif collaborators: + recipients = [ + Recipient.from_user_id(collaborator['user_id']) + for collaborator in collaborators + ] else: - # if there aren't any collaborators, use the creator - recipient_ids.append(package['creator_user_id']) + # if there's no maintainer and there aren't any collaborators, use the creator + recipients.append(Recipient.from_user_id(package['creator_user_id'])) - return list(map(Recipient.from_user_id, recipient_ids)) + return recipients def create_package_email(mail_dict: dict, package: dict): diff --git a/ckanext/nhm/lib/utils.py b/ckanext/nhm/lib/utils.py new file mode 100644 index 00000000..490a05c4 --- /dev/null +++ b/ckanext/nhm/lib/utils.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# This file is part of ckanext-nhm +# Created by the Natural History Museum in London, UK + +from ckan.plugins import toolkit +import requests + + +def get_iiif_status(): + health = {} + + url = toolkit.config.get('ckanext.iiif.image_server_url') + r = requests.get(url + '/status') + if r.ok: + health['ping'] = True + response_json = r.json() + else: + response_json = {} + + health['status'] = response_json.get('status') + mss = response_json.get('profiles', {}).get('mss', {}) + health['specimens'] = mss.get('mss_status', {}).get('status', ':(') + health['es'] = mss.get('es', {'status': 'red', 'response_time': None}) + + return health diff --git a/ckanext/nhm/plugin.py b/ckanext/nhm/plugin.py index 4466db24..b1eb9b89 100644 --- a/ckanext/nhm/plugin.py +++ b/ckanext/nhm/plugin.py @@ -31,6 +31,14 @@ IVersionedDatastore, IVersionedDatastoreDownloads, ) +from ckanext.nhm.lib.utils import get_iiif_status + +try: + from ckanext.status.interfaces import IStatus + + status_available = True +except ImportError: + status_available = False log = logging.getLogger(__name__) @@ -63,6 +71,8 @@ class NHMPlugin(SingletonPlugin, toolkit.DefaultDatasetForm): implements(interfaces.IClick) implements(interfaces.IConfigurable) implements(IVersionedDatastoreDownloads, inherit=True) + if status_available: + implements(IStatus) ## IConfigurable def configure(self, config): @@ -710,3 +720,52 @@ def download_modify_eml(self, eml_dict, query): ) eml_dict['creator'] = creators return eml_dict + + ## IStatus + def modify_status_reports(self, status_reports): + iiif_health = get_iiif_status() + + # overall image server status + if iiif_health['ping'] and iiif_health['status'] == ':)': + status_text = toolkit._('available') + status_type = 'good' + elif iiif_health['ping'] and iiif_health['status'] != ':)': + status_text = toolkit._('available (issues)') + status_type = 'ok' + else: + status_text = toolkit._('unavailable') + status_type = 'bad' + + status_reports.append( + { + 'label': toolkit._('Image server'), + 'value': status_text, + 'group': toolkit._('Images'), + 'help': toolkit._( + 'The IIIF server provides most of the images in datasets (some are externally hosted)' + ), + 'state': status_type, + } + ) + + # specimen images + if iiif_health['ping'] and iiif_health['specimens'] == ':)': + status_text = toolkit._('available') + status_type = 'good' + else: + status_text = toolkit._('unavailable') + status_type = 'bad' + + status_reports.append( + { + 'label': toolkit._('Specimen images'), + 'value': status_text, + 'group': toolkit._('Images'), + 'help': toolkit._( + 'Specimen images are a specific subset of images used primarily in the Collection specimens and Index lots datasets' + ), + 'state': status_type, + } + ) + + return status_reports diff --git a/ckanext/nhm/settings.py b/ckanext/nhm/settings.py index d51d86f2..87a8ba28 100644 --- a/ckanext/nhm/settings.py +++ b/ckanext/nhm/settings.py @@ -17,6 +17,7 @@ ('Library & Archives', 'library@nhm.ac.uk'), ('Mineral & Planetary Sciences', 'm.rumsey@nhm.ac.uk'), ('Vertebrates', 'simon.loader@nhm.ac.uk'), + ('Biodiversity Intactness Index', 'biodiversityfuturesexplorer@nhm.ac.uk'), ('Data Portal / Other', 'data@nhm.ac.uk'), ] ) diff --git a/ckanext/nhm/theme/assets/less/nhm.less b/ckanext/nhm/theme/assets/less/nhm.less index ef4c14eb..c913c8a7 100644 --- a/ckanext/nhm/theme/assets/less/nhm.less +++ b/ckanext/nhm/theme/assets/less/nhm.less @@ -236,6 +236,23 @@ body { & .notifications { padding-right: 10px; } + + & .status-indicator { + font-size: @font-size-body-s; + position: absolute; + top: 0; + margin-left: 1.3em; + padding: 0 2px; + border-radius: @rounding; + + &.status-indicator-red { + background: @warning2; + } + + &.status-indicator-amber { + background: orange; + } + } } .icon-pad() { @@ -1370,6 +1387,7 @@ iframe { margin: 5px 0; } +.info-block, .form-group .info-block { color: @grey4; font-size: @font-size-body-s; @@ -1379,6 +1397,11 @@ iframe { } } +.form-group + .info-block { + margin-top: -25px; // the margin-bottom for .form-group is 30px + margin-bottom: 30px; +} + input[type='radio'], input[type='checkbox'] { position: relative; diff --git a/ckanext/nhm/theme/templates/contact/snippets/form.html b/ckanext/nhm/theme/templates/contact/snippets/form.html index deca40e2..1e2858ea 100644 --- a/ckanext/nhm/theme/templates/contact/snippets/form.html +++ b/ckanext/nhm/theme/templates/contact/snippets/form.html @@ -27,7 +27,7 @@ {# If this is the collections dataset, still add the department select #} {% if package['name'] == 'collection-specimens' %} - {{ form.select('department', label=_('Department'), options=h.get_contact_form_department_options(), selected=data.department, error=errors.department, is_required=true) }} + {{ form.select('department', label=_('Department or team'), options=h.get_contact_form_department_options(), selected=data.department, error=errors.department, is_required=true) }} {% endif %}