Metadata-Version: 2.4
Name: ckanext-marinerg
Version: 0.4.0
Summary: CKAN extension for the MARINERG-i data catalogue: marine metadata schema, Zenodo prefill, facility/equipment picker, and DCAT-AP export.
Author-email: Irish Centre for High End Computing <james.grogan@ichec.ie>
License: AGPL-3.0-or-later
Project-URL: Repository, https://git.ichec.ie/marinerg-i/ckanext-marinerg
Project-URL: Homepage, https://git.ichec.ie/marinerg-i/ckanext-marinerg
Keywords: CKAN,Marine Renewable Energy,Data Catalogue,EOSC,DCAT
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Paste
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ckanext-scheming
Requires-Dist: PyYAML
Requires-Dist: requests
Requires-Dist: pydantic>=2.0
Requires-Dist: prometheus-client>=0.20
Dynamic: license-file

# ckanext-marinerg

CKAN extension powering the **MARINERG-i data catalogue** — the data catalogue for the
MARINERG-i e-infrastructure, a Distributed Research Infrastructure for Marine Renewable Energy
(MRE) test facilities across the EU. On top of stock CKAN it adds a marine metadata schema,
controlled-vocabulary validation, Zenodo/DOI prefill, a facility/equipment picker, DCAT-AP 3.0 +
FAIR Signposting export, Keycloak OIDC login, and MARINERG-i theming.

> **Building a similar CKAN integration?** This README is a map of *how it works* and *where
> things live*. The exhaustive field list, DCAT mappings, and vocabulary architecture are not
> repeated here — they are generated from the schema and documented in [`docs/`](docs/).

## How it works

Everything hangs off a standard CKAN plugin, `ckanext/marinerg/plugin.py`, which implements a
handful of CKAN interfaces:

| Interface | What it does | Code |
|---|---|---|
| `IConfigurer` | Registers templates, theme assets, and the scheming dataset schema | `plugin.py` + `templates/`, `assets/` |
| `IValidators` | Rejects values outside the controlled vocabularies at save time | `validators.py` |
| `IActions` | `marinerg_zenodo_prefill`, `marinerg_facility_list`, `marinerg_equipment_list` | `actions.py` |
| `IBlueprint` | FAIR Signposting `Link` headers on dataset pages | `signposting.py` |
| `IClick` | Maintenance CLI commands | `cli.py` |

Two other pieces are registered through CKAN config rather than a plugin interface:

- **DCAT-AP 3.0 export** — `MarinergDCATProfile` (`profile.py`) stacks on `euro_dcat_ap_3` via
  `ckanext.dcat.rdf.profiles`, adding `/catalog.{rdf,ttl,jsonld}` and per-dataset serialisations.
- **Keycloak OIDC** — login and role mapping in `oidc_plugin.py` / `oidc_roles.py` /
  `oidc_redirect.py`.
- A second small plugin, `marinerg_metrics` (`metrics.py`), exposes a Prometheus metrics endpoint.

### The metadata model is defined once

[`schema/marinerg_dataset.linkml.yaml`](schema/marinerg_dataset.linkml.yaml) (LinkML) is the single
source of truth for the marine metadata fields and their controlled vocabularies. From it,
`scripts/generate_registry.py` produces the controlled-vocabulary registry
(`ckanext/marinerg/registry/controlled-metadata.yaml`) that the validators enforce and the RDF
export cites. **Edit the schema, then regenerate — never hand-edit the registry.** `tox -e registry`
(and CI) fails if the two drift.

## Where things live

| Path | Contents |
|---|---|
| `ckanext/marinerg/plugin.py` | Plugin entry points / CKAN hooks — **start here** |
| `ckanext/marinerg/actions.py` | Zenodo prefill + facility/equipment lookups (calls the Django facility service) |
| `ckanext/marinerg/validators.py` | Controlled-vocabulary validation |
| `ckanext/marinerg/profile.py` | DCAT-AP 3.0 RDF mappings |
| `ckanext/marinerg/signposting.py` | FAIR Signposting `Link` headers |
| `ckanext/marinerg/oidc_*.py` | Keycloak OIDC login + role mapping |
| `ckanext/marinerg/templates/` | Theme overrides — header, footer, scheming form/display snippets |
| `ckanext/marinerg/assets/` | Theme CSS (`marinerg-theme.css`) + webassets bundle |
| `ckanext/marinerg/public/` | Logos, favicon, background imagery |
| `ckanext/marinerg/registry/` | **Generated** vocabulary registry + cached authority labels |
| `schema/` | The LinkML metadata model (source of truth) |
| `scripts/` | Registry generation + vocabulary-cache refresh scripts |
| `infra/` | Local CKAN stack (compose) and the production image (`Dockerfile`) |
| `docs/` | Metadata-model & vocab-architecture references, EOSC roadmap, C4 diagrams |
| `tests/` | Pytest suite (stubs CKAN — no CKAN install needed) |

## Run it locally

```sh
cd infra
docker compose -f compose.yml -f compose.local.yml up -d    # or: podman compose ...
# CKAN → http://localhost:5001   (login: ckan_admin / ckan_admin)
```

`compose.local.yml` mounts this repo into the container, so Python and template edits are picked up
live — **restart the `ckan` service to reload cached Jinja templates**; only dependency changes need
`--build`. The facility/equipment picker calls the Django facility service, expected on
`http://localhost:8000` (the image resolves it as `http://host.docker.internal:8000`).

## Develop

```sh
python -m venv .venv && .venv/bin/pip install -e ".[test]"
.venv/bin/python -m pytest tests/ -v     # tests stub ckan.plugins.toolkit — run under plain pytest
tox -e format_check      # Black (format_apply to fix)
tox -e style             # flake8
tox -e type              # mypy
tox -e registry          # fails if the registry has drifted from the LinkML schema
python scripts/generate_registry.py   # regenerate the registry after a schema change
```

Vocabulary label caches (NERC NVS, SPDX, EuroSciVoc, GCMD, re3data) are pinned snapshots refreshed
by the `scripts/fetch_*` scripts; run them manually and commit the reviewed diff.

## Configuration

Marinerg config keys are baked into `ckan.ini` at image-build time (`ckan config-tool` in
[`infra/Dockerfile`](infra/Dockerfile)); OIDC credentials and `ckan.plugins` are the deliberate
runtime exceptions.

| Key | Purpose |
|---|---|
| `marinerg.zenodo_api_key` | Optional Zenodo API key for DOI prefill |
| `marinerg.facility_api_url` | Django facility service base URL |
| `marinerg.facility_api_token` | Token for authenticated facility API access |
| `marinerg.portal_base_url` | Fallback facility PID base when a facility has no ROR ID |

## Release

Run a pipeline with **`RELEASE_FIELD`** = `patch` / `minor` / `major`. The tag it creates triggers
the pipeline that publishes the pip package and the CKAN container image. Pin that image tag in the
sibling [`../infra`](../infra) repository, then run the infra deploy for the target environment.

## Roadmap

NERC P01 parameters · SeaDataNet L05 device categories · DataCite export + DOI registration ·
OAI-PMH endpoint · MARINERG-i EOSC Virtual Organisation. Detail in
[`docs/eosc-roadmap.md`](docs/eosc-roadmap.md).

## Licence

AGPL-3.0-or-later — see [`LICENSE`](LICENSE). Copyright © Irish Centre for High-End Computing
(ICHEC).
