Skip to content

Commit

Permalink
merge: PR #784 from dev
Browse files Browse the repository at this point in the history
Weekly release 2024-07-08
  • Loading branch information
alycejenni authored Jul 8, 2024
2 parents 53cab6c + 9eaacea commit 3b3f688
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 17 deletions.
28 changes: 28 additions & 0 deletions ckanext/nhm/lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
22 changes: 15 additions & 7 deletions ckanext/nhm/lib/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'] += (
Expand Down Expand Up @@ -74,21 +74,29 @@ 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},
# only email admins
{'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):
Expand Down
27 changes: 27 additions & 0 deletions ckanext/nhm/lib/utils.py
Original file line number Diff line number Diff line change
@@ -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
59 changes: 59 additions & 0 deletions ckanext/nhm/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions ckanext/nhm/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
('Library & Archives', '[email protected]'),
('Mineral & Planetary Sciences', '[email protected]'),
('Vertebrates', '[email protected]'),
('Biodiversity Intactness Index', '[email protected]'),
('Data Portal / Other', '[email protected]'),
]
)
23 changes: 23 additions & 0 deletions ckanext/nhm/theme/assets/less/nhm.less
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -1370,6 +1387,7 @@ iframe {
margin: 5px 0;
}

.info-block,
.form-group .info-block {
color: @grey4;
font-size: @font-size-body-s;
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions ckanext/nhm/theme/templates/contact/snippets/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}

<div class="control-group control-medium">
Expand All @@ -43,7 +43,7 @@
{% else %}

{# Add department selection (for non dataset forms) #}
{{ 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 %}

Expand Down
15 changes: 9 additions & 6 deletions ckanext/nhm/theme/templates/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,31 @@
<li><a href="{{ h.url_for('about.credits') }}">Credits</a></li>
</ul>
</li>
<li role="presentation">
<a href="{{ h.url_for('help.index') }}">
Help
</a>
</li>
<li role="presentation"><a
href="{{ h.url_for('contact.form') }}">Contact</a>
</li>
<li role="presentation">{{ h.api_doc_link() }}</li>
<li role="presentation"><a
href="{{ h.url_for('legal.privacy') }}">Privacy notice</a></li>
href="{{ h.url_for('legal.privacy') }}">Privacy</a></li>
<li role="presentation"><a href="{{ h.url_for('legal.terms') }}">T&amp;C</a>
</li>
<li role="presentation">
<a href="https://www.nhm.ac.uk/about-us/website-accessibility-statement.html">
Website accessibility statement
Accessibility
</a>
</li>
<li role="presentation">
<a href="{{ h.url_for('about.aohc') }}">
Acknowledgement of harmful content
Harmful content
</a>
</li>
{% if g.userobj %}
<li role="presentation">
<a href="{{ h.url_for('user.read', id=g.userobj.name) }}">{{ _('My
account') }}</a>
<a href="{{ h.url_for('user.read', id=g.userobj.name) }}">{{ _('Account') }}</a>
</li>
<li role="presentation">
<a href="{{ h.url_for('user.logout') }}">{{ _('Log out') }}</a>
Expand Down
24 changes: 24 additions & 0 deletions ckanext/nhm/theme/templates/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@

{# We do not want a search #}{% block header_site_search %}{% endblock %}

{% set status_indicator = h.get_status_indicator() %}
{% macro status_icon() %}
<div>
<a href="{{ h.url_for('status.index') }}"
title="{{ _('System status') }}">
<span class="sr-only">{{ _('System status') }}</span>
{% if status_indicator %}
<span class="status-indicator status-indicator-{{ status_indicator }}">
<span class="sr-only">{{ _('Status alert') }}</span>
<i class="fas fa-exclamation fa-xs"></i>
</span>
{% endif %}
<i class="fas fa-heartbeat fa-lg"></i>
</a>
</div>
{% endmacro %}


{% block header_wrapper %}
<header class="masthead" role="heading">
<div class="account-icons container">
Expand Down Expand Up @@ -71,6 +89,9 @@
</div>
{% endif %}

{# Status page #}
{{ status_icon() }}

{# Logout #}
{% block header_account_log_out_link %}
<a href="{{ h.url_for('user.logout') }}" title="{{ _('Log out') }}">
Expand All @@ -85,6 +106,9 @@
{# headway widget #}
<div class="headway-container"></div>

{# Status page #}
{{ status_icon() }}

{% block header_account_notlogged %}
<div>
<a href="{{ h.url_for('user.login') }}" title="{{ _('Log in') }}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
{% endblock %}

{% block package_metadata_fields_maintainer %}
{{ form.input('maintainer_email', label=_('Contact email'), id='field-maintainer-email', placeholder=_('e.g. [email protected]'), value=data.maintainer_email, error=errors.maintainer_email, classes=['control-medium']) }}
{{ form.info('Enquiries about this dataset will be sent to this address. If not set, messages will go to the collaborators or creator of the dataset.', inline=False) }}

{{ form.input('maintainer', label=_('Contact name'), id='field-maintainer', placeholder=_('e.g Project Y'), value=data.maintainer, error=errors.maintainer, classes=['control-medium']) }}
{{ form.info('Name of the person or group receiving dataset enquiries (see above). Optional.', inline=False) }}
{% endblock %}

{% block custom_fields %}
Expand All @@ -21,8 +26,8 @@
{{ super() }}
{% endblock %}

{{ form.info("What time period does this dataset cover? If not applicable, leave blank.", inline=True) }}
{{ form.input('temporal_extent', label=_('Temporal extent'), id='field-temporal-extent', placeholder=_('1970 - 1985'), value=data.temporal_extent, error=errors.temporal_extent, classes=['control-medium']) }}
{{ form.info("What time period does this dataset cover? If not applicable, leave blank.", inline=True) }}

{{ form.select('update_frequency', label=_('Update frequency'), id='field-update-frequency', options=h.form_select_update_frequency_options(), selected=data.update_frequency, error=errors.update_frequency, classes=['control-medium']) }}
{# TODO: Add map to pick spatial extent - hidden for non sysadmin until then #}
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ dependencies = [
"ckanext-ldap>=3.2.0",
"ckanext-query-dois>=4.0.0",
"ckanext-statistics>=3.1.0",
"ckanext-versioned-datastore>=5.1.0"
"ckanext-versioned-datastore>=5.1.0",
# this also depends on ckanext-dcat==1.3.0 (see readme)
"requests"
]

[project.optional-dependencies]
Expand Down

0 comments on commit 3b3f688

Please sign in to comment.