This plugin adds geospatial and temporal metadata support for articles (journals) and preprints (repositories) in Janeway.
This plugin is part of the KOMET project ("Kompetenznetzwerk für das Management und die Erschließung von textbasierten Forschungsdaten"), funded by the German Federal Ministry for Research, Technology Assessment and Space (BMFTR), formerly BMBF. It brings spatiotemporal metadata capabilities to the Janeway publishing platform, complementing existing work for Open Journal Systems (OJS).
The plugin builds on concepts and experience from the geoMetadata plugin for OJS. While geoMetadata targets OJS, this plugin implements equivalent functionality for Janeway, adapted to its plugin architecture and hook system. Geospatial metadata collected by this plugin and its OJS counterparts can be aggregated and made discoverable through OPTIMAP, a web portal for geospatial discovery of research articles based on open metadata.
- Spatial Metadata: Store geographic coverage as Well-Known Text (WKT) geometry
- Temporal Metadata: Record time periods covered by research
- Interactive Maps: Leaflet.js-based map display and editing interface
- JSON API: GeoJSON endpoints for map data retrieval
- Admin Integration: Edit geometadata from article/preprint management pages
- Full-Page Map: Browse all articles/preprints with geographic metadata on a single map
- Per-Version Preprint Geometadata: Each
PreprintVersioncan carry its own geometry and temporal periods, so a preprint's footprint can evolve across submissions. The sidebar map, embedded HTML metadata, and JSON API surface the current version's row (with a legacy / canonical fallback for preprints that aren't tracked per-version).
-
Clone this repository into the Janeway
src/pluginsfolder:cd path/to/janeway/src/plugins git clone https://github.com/GeoinformationSystems/janeway_geometadata geometadata -
From the
srcdirectory, install the plugin and run migrations:python3 manage.py install_plugins geometadata python3 manage.py migrate
-
Restart your server (Apache, Passenger, etc.)
-
Enable the plugin via the Janeway manager interface
- Janeway 1.7+ (tested with current main branch)
- geopy ~2.4 (pip, MIT) - reverse geocoding
- geomet ~1.1 (pip, Apache-2.0) - WKT/GeoJSON conversion
- Leaflet.js 1.9.4 (bundled, BSD-2-Clause) - interactive maps
- Leaflet.draw 1.0.4 (bundled, MIT) - drawing tools for geometry editing
- leaflet-providers (bundled, BSD-2-Clause) - basemap provider definitions
Settings are configurable per journal/repository via the manager at
/plugins/geometadata/manager/. Press-level defaults apply to all
journals/repositories and can be overridden per journal.
| Setting | Default | Description |
|---|---|---|
| Enable Geometadata Collection | off | Master switch for the plugin |
| Enable Spatial Metadata | on | Allow geographic location/area input |
| Enable Temporal Metadata | on | Allow time period input |
| Enable Map Page | on | Enable the aggregated map page (press-wide or journal-wide) |
| Require Geometadata on Submission | off | Require authors to provide geospatial metadata |
| Setting | Default | Description |
|---|---|---|
| Show Map on Article Pages | on | Display an interactive map on article/preprint pages |
| Show Temporal Coverage | on | Display temporal coverage (date range) on article pages |
| Show Place Names | on | Display place name labels alongside the map |
| Setting | Default | Description |
|---|---|---|
| Show Temporal Coverage on Issue Pages | on | Display aggregated temporal coverage on issue landing pages |
Note: Issue page features require the
issue_footer_blockhook which is not present in standard Janeway. See Template Requirements below. The settings page will detect if the hook is missing and disable these settings with an explanatory message.
| Setting | Default | Description |
|---|---|---|
| Show GeoJSON Download Links | on | Show download links for geometadata in GeoJSON format on article pages, issue pages, and the journal-wide map page |
Controls which metadata formats are embedded in the HTML <head> of article
pages for harvesters and search engines. All embedding respects the
Enable Spatial / Enable Temporal toggles — e.g., when temporal metadata is
disabled, Schema.org output omits temporalCoverage but still includes
spatialCoverage.
| Setting | Default | Description |
|---|---|---|
| Dublin Core Coverage | on | Embed DC.SpatialCoverage (GeoJSON), DC.box, DC.temporal, DC.PeriodOfTime meta tags |
| WKT Geometry Meta Tag | on | Embed the raw geometry as <meta name="DC.SpatialCoverage" scheme="WKT" content="..."> alongside the GeoJSON variant |
| geo.* Meta Tags | on | Embed geo.placename meta tags |
| Schema.org Coverage (JSON-LD) | on | Embed Schema.org spatialCoverage/temporalCoverage as JSON-LD |
| GeoJSON Link Element | off | Include a <link rel="alternate" type="application/geo+json"> to the GeoJSON API endpoint |
| ISO 19139 XML | on | Embed an ISO 19139 gmd:EX_Extent fragment (geographic bounding box, geographic description, and one gml:TimePeriod per temporal period) inside a <script type="application/xml" id="geometadata-iso19139"> block |
| Enable Overlap Picker on Aggregated Maps | on | When a click on the journal/press/issue map hits multiple article geometries at the same location, open a paginated popup that lets readers page through all overlapping articles with prev/next buttons (and ArrowLeft / ArrowRight / Escape keys). When off, only the topmost article's popup opens — Leaflet's default behaviour. |
Colour-code geometries on aggregated maps (journal and press map pages) by issue or journal.
| Setting | Default | Description |
|---|---|---|
| Enable Colour Coding | off | Assign colours to markers and geometries based on their grouping (issue on journal maps, journal on press maps) |
| Colour Method | colorbrewer |
How to generate the palette: colorbrewer (ColorBrewer schemes), startrek (Star Trek themed palettes), custom (enter your own colours) |
| Colour Scheme | Set2 |
Palette name for the selected method. Qualitative schemes recommended for categorical data. |
| Custom Colours | (empty) | One HTML colour code per line (e.g., #3388ff). Used when method is custom. |
| Colour Palette | (auto) | JSON array of hex colours. Auto-populated from the selected method/scheme. |
| Map Feature Colour | #3388ff |
Colour for map features on article and issue pages (when colour coding is disabled). Enter a hex code or select from the palette. |
The plugin uses leaflet-providers for basemap selection. Only providers that work without registration or API keys are included.
| Setting | Default | Description |
|---|---|---|
| Basemap Provider | OpenStreetMap.Mapnik |
Basemap provider key from leaflet-providers |
Available basemaps:
| Provider Key | Description |
|---|---|
OpenStreetMap.Mapnik |
Standard OpenStreetMap style |
OpenStreetMap.DE |
German OpenStreetMap style |
OpenStreetMap.CH |
Swiss OpenStreetMap style (Switzerland only) |
OpenStreetMap.France |
French OpenStreetMap style |
OpenStreetMap.HOT |
Humanitarian OpenStreetMap Team style |
OpenStreetMap.BZH |
Breton OpenStreetMap style (Brittany region) |
OpenTopoMap |
Topographic map with contour lines |
CyclOSM |
Cycling-focused map style |
GeoportailFrance.plan |
French IGN Plan map |
GeoportailFrance.orthos |
French IGN aerial photos |
TopPlusOpen.Color |
German BKG topographic map (colour) |
TopPlusOpen.Grey |
German BKG topographic map (greyscale) |
To preview all basemaps interactively, visit the leaflet-providers demo.
Automatically derive place names and administrative units from drawn geometries using reverse geocoding services.
| Setting | Default | Description |
|---|---|---|
| Enable Reverse Geocoding | on | Enable the "Lookup Location Names" button on edit pages |
| Geocoding Provider | nominatim |
Service to use: nominatim (OpenStreetMap), photon, or geonames |
| User Agent | janeway-geometadata |
Identifies your instance to Nominatim/Photon (required by their usage policies) |
| GeoNames Username | (empty) | Required when using GeoNames provider. Register at geonames.org |
| Setting | Default | Description |
|---|---|---|
| Default Map Latitude | 0 | Default center latitude (-90 to 90) |
| Default Map Longitude | 0 | Default center longitude (-180 to 180) |
| Default Map Zoom | 2 | Default zoom level (1-18) |
When maps are displayed, the user's browser connects directly to an external tile server to load map tiles (the background map images). No map tile data is proxied through the Janeway server — the browser makes requests to the tile provider, which will receive the user's IP address, browser user agent, and the geographic extent of the requested map area.
By default, the plugin uses tile servers operated by the OpenStreetMap Foundation (OSMF), located in the United Kingdom and other countries. The Janeway site operator has no control over these connections or OSMF's data processing practices.
If you select a different basemap provider (see Map Basemap), the browser will connect to that provider instead. Each provider has its own privacy policy and usage terms.
The use of this map service can be justified under the legitimate interest of displaying map functions to users of the website (cf. Article 6(1)(f) GDPR).
OSMF Privacy Policy: https://wiki.osmfoundation.org/wiki/Privacy_Policy
OSMF Tile Usage Policy: https://operations.osmfoundation.org/policies/tiles/
If your journal or press displays maps to visitors, your data privacy statement should inform users that:
- Map tiles are loaded from an external service (identify which one).
- The user's browser connects directly to that service, transmitting the IP address, browser user agent, and the map area viewed.
- The site operator has no control over the external service's data processing.
- Link to the tile provider's privacy policy.
Example paragraph (adapt to your tile provider and legal requirements):
This website uses map services provided by the OpenStreetMap Foundation (OSMF). When you view a page containing a map, your browser connects to servers operated by the OSMF to load map tiles. This transmits your IP address and other request data to the OSMF. We have no control over this data processing. The legal basis for this processing is our legitimate interest in displaying geographic information (Art. 6(1)(f) GDPR). For details, see the OSMF Privacy Policy.
Some plugin features require hooks that are not present in standard Janeway templates. The plugin's settings page automatically detects which hooks are available and disables settings that cannot function without them.
These hooks are present in Janeway out of the box and require no template edits:
| Hook | Purpose |
|---|---|
article_footer_block |
Display map on journal article pages (preprints route through article_sidebar) |
article_sidebar |
Display map in the article/preprint sidebar — preprints render here so the Time and Location section matches the journal article landing page |
nav_block (journal + press) |
Add navigation link to journal/press map page |
base_head_css |
Inject Leaflet CSS and custom styling |
in_review_editor_actions |
Display link to geometadata editing in editor review workflow |
These hooks require adding a single line to your theme templates:
| Hook | Template File | Purpose |
|---|---|---|
issue_footer_block |
journal/issue_display.html |
Display aggregated map and temporal coverage on issue pages |
nav_block (repository) |
repository/nav.html (OLH theme) |
Add Map link to the repository main menu. The Material theme already fires this hook in its repository/nav.html; the OLH theme does not by default. |
article_sidebar (preprint) |
repository/preprint.html (OLH + Material themes) |
Display the Time and Location section in the preprint sidebar (matching the journal article landing page). Both built-in themes have been updated to fire {% hook 'article_sidebar' preprint %} inside their sidebar columns; third-party themes that ship their own preprint template need the same one-line addition. |
For repositories rendered with the OLH theme (or its subthemes, e.g. clean,
which inherits OLH's repository templates), add the hook inside the existing
<ul> in src/themes/OLH/templates/repository/nav.html:
{% load hooks %}
<nav>
<div class="top-bar" id="main-menu" style="display: block;">
<ul class="menu vertical medium-horizontal" data-responsive-menu="drilldown medium-dropdown">
<li><a href="{% url 'website_index' %}">{% trans 'Home' %}</a></li>
<li><a href="{% url 'repository_about' %}">{% trans 'About' %}</a></li>
<li><a href="{% url 'repository_list' %}">{{ request.repository.object_name_plural | capfirst }}</a></li>
<li><a href="{% url 'repository_subject_list' %}">{% trans 'Subjects' %}</a></li>
<li><a href="{% url 'repository_submit' %}">{% trans 'Submit' %} {{ request.repository.object_name }}</a></li>
{% hook 'nav_block' %}
</ul>
</div>
</nav>Without this, the repository-wide map page is still reachable at
/<repo-short-name>/plugins/geometadata/map/ but no link to it is shown
in the main navigation.
To enable issue page features, add the following line to your theme's
journal/issue_display.html template, typically after the issue article list:
{% load hooks %}{% hook 'issue_footer_block' %}For all three standard themes (OLH, material, clean), the recommended location
is after the {% include "elements/journal/issue_block.html" %} line:
{% include "elements/journal/issue_block.html" %}
{% load hooks %}{% hook 'issue_footer_block' %}After adding this line to your theme templates, the issue page settings (Show Temporal Coverage on Issue Pages) will become available in the plugin settings.
Editors can access geometadata editing from multiple locations:
| Access Point | Description |
|---|---|
| Review Workflow | Click "Edit Geometadata" button in the editor actions during article review |
| Curation Queue | Navigate to /plugins/geometadata/curation-queue/ for a list of all articles with their geometadata status |
| Direct URL | Access editing directly at /plugins/geometadata/edit/article/<article_id>/ |
| Article Archive Page | The "Edit Geometadata" link appears on the article's archive/management page |
Editing geometadata:
- Navigate to the geometadata editing page via any of the methods above
- Draw shapes on the map or paste WKT geometry in the text field
- Use "Lookup Location Names" to auto-fill place name and administrative units
- Add temporal information (start date, end date) for relevant time periods
- Save
| Endpoint | Description |
|---|---|
/plugins/geometadata/api/article/<pk>.json |
GeoJSON Feature for a single article |
/plugins/geometadata/api/preprint/<pk>.json |
GeoJSON Feature for a single preprint |
/plugins/geometadata/api/all.json |
GeoJSON FeatureCollection for all articles/preprints in the current journal/repository |
/plugins/geometadata/api/issue/<pk>.json |
GeoJSON FeatureCollection for all articles in an issue |
/plugins/geometadata/api/press.json |
GeoJSON FeatureCollection across all journals and repositories |
/plugins/geometadata/api/palette.json |
Colour palette array for map colour coding |
Bounding box filtering: The all.json, issue/<pk>.json, and press.json
endpoints support optional query parameters for spatial filtering:
| Parameter | Description |
|---|---|
north |
Maximum latitude (-90 to 90) |
south |
Minimum latitude (-90 to 90) |
east |
Maximum longitude (-180 to 180) |
west |
Minimum longitude (-180 to 180) |
Records are returned if their bounding box intersects the query box. All parameters are optional — you can filter by a single boundary if needed.
Example: /plugins/geometadata/api/all.json?south=40&north=60&west=-10&east=30
A public map page showing all articles/preprints with geographic metadata is
available at /plugins/geometadata/map/. A navigation link is automatically
added via the nav_block hook when viewing journal or repository pages.
A press-wide map showing articles from all journals and repositories is
available at /plugins/geometadata/press-map/. This requires the "Enable Map
Page" setting to be turned on at the press level (via
/plugins/geometadata/manager/ when accessed outside a journal context).
Note: The nav_block hook only adds navigation links within journal or
repository contexts. To add a map link to your press landing page, manually
add a link to your press theme template:
<a href="{% url 'geometadata_press_map_page' %}">Map</a>Or add it to your press navigation in themes/<your-theme>/templates/press/nav.html
or equivalent.
Geometry is stored as WKT (Well-Known Text), a standard text format:
POINT(-122.4194 37.7749)
POLYGON((-10 35, 40 35, 40 70, -10 70, -10 35))This approach was chosen over GeoDjango/PostGIS for:
- No additional database requirements
- CSV import/export compatibility
- Simpler deployment
Each record includes automatically-calculated bounding box fields
(bbox_north, bbox_south, bbox_east, bbox_west) for efficient spatial
queries without requiring PostGIS. A composite B-tree index on these four
fields enables fast bounding-box intersection queries used by the API's
spatial filtering feature.
PreprintGeometadata carries a nullable preprint_version FK so each
PreprintVersion can record its own geometry and temporal periods.
Rows form three layers per preprint:
- Per-version rows (
preprint_versionset): one row per version that needs its own footprint. Different versions of the same preprint can have different geometries. - Legacy / canonical row (
preprint_version=None): the cross-version state. Used by preprints that aren't tracked per-version and by deployments migrated from before the per-version schema. - Uniqueness is enforced on
(preprint, preprint_version).
Display surfaces (preprint sidebar map, embedded HTML metadata in the
page head, the JSON API) resolve which row to show via
logic.get_current_geometadata(preprint):
- Row for
preprint.current_version, if it exists. - Row with
preprint_version=None(legacy slot). None.
The edit-metadata view binds the form to the current version's row (creating it on demand), so editors mutate the same row the sidebar displays.
Core Janeway stores plugin settings as SettingValue rows keyed on
Journal. The plugin therefore ships an additional
RepositoryPluginSetting table ((repository, setting_name, value),
unique on (repository, setting_name)) so repositories can carry their
own toggle state.
The plugin's logic.get_plugin_setting / is_setting_on /
get_setting_value consult scopes in this order:
journalargument → coreSettingValue(per-journal override).repositoryargument →RepositoryPluginSettingrow (per-repo override).- Press-level default
SettingValue.
logic.save_plugin_setting mirrors the same routing for writes —
per-repository writes update_or_create a RepositoryPluginSetting
row; journal and press writes go through the core setting_handler.
This plugin supports Janeway's multilingual system. All user-facing strings
are wrapped with Django's translation functions (gettext_lazy in Python,
{% trans %} in templates), so the plugin can be displayed in any language
that Janeway supports.
Janeway uses three layers for internationalization:
- Django's standard i18n (
USE_I18N = True,LocaleMiddleware) — translates Python strings and template text via.po/.mofiles - Per-journal language settings — each journal can configure which
languages are available and which is the default
(via
journal_languagesanddefault_journal_languagesettings) - django-modeltranslation — translates model field values stored in the database (e.g., article titles, CMS page content)
Plugins participate in layer 1: they provide .po translation files in a
locales/ directory. Janeway automatically discovers plugin locale
directories via plugin_installed_apps.load_plugin_locales() in
janeway_global_settings.py.
- English (source language, all strings)
- German
-
Create the locale directory:
mkdir -p src/plugins/geometadata/locales/fr/LC_MESSAGES
-
Generate a
.pofile from the existing source strings. You can either copy the German.pofile as a template and replace themsgstrvalues, or use Django'smakemessagescommand:cd src/plugins/geometadata django-admin makemessages -l frThis scans all Python files and templates for
_()and{% trans %}strings and createslocales/fr/LC_MESSAGES/django.po. -
Translate the
msgstrentries in the.pofile. Each entry has amsgid(English source) and amsgstr(your translation). Leavemsgstr ""empty for untranslated strings — Django will fall back to English. -
Compile the
.pofile into a binary.mofile:cd src/plugins/geometadata/locales/fr/LC_MESSAGES msgfmt -o django.mo django.poOr use Django's command:
cd src python3 manage.py compilemessages -l fr -
Restart the server. Django loads
.mofiles at startup.
You need to regenerate/update .po files when:
- You add new user-facing strings in Python code (wrapped in
_()orgettext_lazy()) - You add or change
{% trans %}or{% blocktrans %}tags in templates - You change existing English source strings (the
msgidvalues)
After modifying source strings, run makemessages again for each language,
then update the translations and recompile with msgfmt or
compilemessages.
plugins/geometadata/
└── locales/
├── de/
│ └── LC_MESSAGES/
│ ├── django.po # German translations (editable text)
│ └── django.mo # Compiled binary (generated, do not edit)
└── en/
└── LC_MESSAGES/
├── django.po # English (empty — source strings are English)
└── django.mo # Compiled binaryLeaflet map controls (zoom buttons, fullscreen toggle, drawing toolbar) are
translated without modifying any vendor JavaScript files. Django {% trans %}
strings are passed to JS at runtime via two mechanisms:
data-i18n-*attributes on the map container<div>— read bygeometadata-display.jsandgeometadata-edit.jsto set Leaflet'szoomInTitle/zoomOutTitleand fullscreen controltitle/titleCancel.L.drawLocaloverrides in a<script>block in the edit templates (edit_article.html,edit_preprint.html) — sets all ~35 Leaflet.draw toolbar and tooltip strings before the draw control is initialised.
This keeps all vendor files (leaflet.js, leaflet.draw.js,
leaflet.fullscreen.js) unmodified and updatable independently.
- Python code: Use
from django.utils.translation import gettext_lazy as _for model fields, form labels, and anything evaluated at import time. Usefrom django.utils.translation import gettext as _in views for strings evaluated at request time. - Templates: Add
{% load i18n %}at the top, then wrap strings with{% trans "text" %}or{% blocktrans %}...{% endblocktrans %}for strings with variables. .pofile encoding: Files must be UTF-8. Literal double-quote characters inside translated strings must be escaped as\".- Janeway auto-discovers plugin locales: The directory must be named
locales/(notlocale/) and placed in the plugin root.
The plugin includes a management command to load demo data for testing and development. The demo data is based on articles from the OJS geoMetadata Demo Journal.
Loading demo data:
# Create the demo journal and load all data (recommended for fresh installs)
python3 manage.py load_geometadata_demo --create-journal
# Load into an existing journal
python3 manage.py load_geometadata_demo --journal-code=geodemo
# Include placeholder PDF galleys
python3 manage.py load_geometadata_demo --create-journal --with-galleys
# Also create the demo repository + preprints (versions, promotion links,
# mixed-stage preprints)
python3 manage.py load_geometadata_demo --create-journal --with-preprints
# Clear existing demo articles before loading (only affects articles;
# preprints, versions, and promotion links are upserted idempotently)
python3 manage.py load_geometadata_demo --journal-code=geodemo --clear-existingArguments:
| Argument | Default | Description |
|---|---|---|
--journal-code |
dqj |
Journal short code to load data into |
--create-journal |
off | Create the demo journal from demo_journal.json if it doesn't exist |
--owner-email |
admin@example.com |
Email of user to be set as article owner |
--with-galleys |
off | Attach a placeholder PDF galley to each article |
--with-preprints |
off | Also create the demo repository and preprints from demo_preprints.json (covers the full WKT palette plus version history, preprint→article promotion links, and mixed-stage examples) |
--clear-existing |
off | Delete existing demo articles before loading (matches by title prefix). Does not clear preprints — preprint loading is fully idempotent and refreshes existing rows in place |
--skip-settings |
off | Don't override the plugin settings on the target journal |
What gets created:
- Journal (when using
--create-journal): "Delta Quadrant Journal" (dqj) - 2 issues: Vol. 1 No. 1 (12 articles) and Vol. 1 No. 2 (6 articles)
- 18 articles with titles, abstracts, authors, and keywords
- Geographic metadata: WKT geometries (points, polygons, multipoints) and place names
- Temporal metadata: Various historical and modern time periods
- Repository (when using
--with-preprints): "Geometadata Demo Repository" (geo-repo)- 16 preprints covering the full WKT palette (Point, LineString, Polygon, Polygon-with-hole, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection, antimeridian-crossing polygon, etc.)
- Version history: two preprints (
Urban heat-island sensors deployed in BerlinandContinental-scale habitat suitability for European bison) carry an explicit v1 → v2 history with refined titles/abstracts. Every other preprint receives an implicit v1 so theme templates that readpreprint.current_versionalways have a row to render. - Promotion linkage: two preprints (
Crowdsourced air-temperature monitoring across central Europe: preliminary PALM evaluationandpIRIR dating of volcanic sediments from Sulawesi: a preliminary report) are linked viaPreprint.articleto the journal articles they were later published as. - Mixed-stage examples: two preprints (
Sea-ice extent in the Beaufort Gyre,Urban tree canopy survey in Curitiba, Brazil) live inSTAGE_PREPRINT_REVIEWso the repository moderation queue isn't empty.
Demo data files:
| File | Description |
|---|---|
test/data/demo_journal.json |
Journal metadata (name, code, settings) |
test/data/demo_issues.json |
Issue metadata (volume, number, title, description) |
test/data/demo_articles.json |
Article data with authors, keywords, and geometadata |
test/data/demo_preprints.json |
Repository + preprint data, including optional per-entry versions, linked_article_title, and stage fields |
test/data/placeholder.pdf |
Placeholder PDF for galleys |
Preprint JSON schema extensions (all optional, additive on top of the core preprint fields):
stage: one ofpreprint_published(default),preprint_review,preprint_unsubmitted,preprint_rejected. Maps to therepository.modelsstage constants. Non-published preprints are not visible to anonymous users.linked_article_title: title of an existing journal Article to bind to this preprint viaPreprint.article. Resolved by exact match, falling back to atitle__startswithlookup on the first 80 characters. Logs a warning if nothing matches.versions: list of{version, date_time, title, abstract, notes}objects, each materialised as aPreprintVersionrow. Per-version geometadata is intentionally not stored at the moment; tracked as a separate follow-up because it requires aPreprintGeometadataschema change.
These JSON files can be customized or extended with additional test data.
The default demo journal "Delta Quadrant Journal" (code: dqj) is configured
with sensible defaults for testing the geometadata plugin.
For running tests outside of the Janeway Docker environment, create a virtual
environment in the Janeway src directory:
cd path/to/janeway/src
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install Janeway and plugin dependencies
pip install -r ../requirements.txt -r ../dev-requirements.txt
pip install -r plugins/geometadata/requirements.txtThe .venv directory is already in Janeway's .gitignore.
Note: If you've previously run Janeway with Docker, log files may be owned
by root. Fix with: sudo chown -R $USER:$USER logs/
Run the Django unit tests with SQLite (requires environment variables):
cd src
source .venv/bin/activate # If not already activated
# Set required environment variables
export DB_VENDOR=sqlite
export JANEWAY_SETTINGS_MODULE=core.janeway_global_settings
# Run all plugin tests
python3 manage.py test plugins.geometadata
# Or run specific test modules
python3 manage.py test plugins.geometadata.tests.test_models
python3 manage.py test plugins.geometadata.tests.test_geojson_validationYou can also set these variables inline:
DB_VENDOR=sqlite JANEWAY_SETTINGS_MODULE=core.janeway_global_settings \
python3 manage.py test plugins.geometadataThe plugin includes end-to-end tests using Playwright to verify map functionality in a real browser. These tests check that maps render correctly on article, issue, journal, and press pages.
Prerequisites:
cd src
source .venv/bin/activate # If not already activated
# Install E2E test dependencies
pip install -r plugins/geometadata/requirements-e2e.txt
# Install Playwright browsers (first time only)
playwright install chromiumRun E2E tests (headless):
cd src
source .venv/bin/activate
export DB_VENDOR=sqlite
export JANEWAY_SETTINGS_MODULE=core.janeway_global_settings
pytest plugins/geometadata/tests/e2e/ -vBy default the live test server binds to an OS-assigned free port — fine for
CI and most local runs. If you happen to be running a non-test development
server (e.g. make janeway on 8000) and want the test server pinned to a
known port to avoid edge-case clashes, export GEOMETADATA_E2E_PORT:
GEOMETADATA_E2E_PORT=9001 \
DB_VENDOR=sqlite JANEWAY_SETTINGS_MODULE=core.janeway_global_settings \
pytest plugins/geometadata/tests/e2e/ -vThe env var maps to Django's standard DJANGO_LIVE_TEST_SERVER_ADDRESS
under the hood. Tests address the server through base_url, never a
hardcoded host:port — so changing the port doesn't require touching tests.
Run E2E tests with visible browser (useful for debugging or following along):
cd src
source .venv/bin/activate
DB_VENDOR=sqlite JANEWAY_SETTINGS_MODULE=core.janeway_global_settings \
pytest plugins/geometadata/tests/e2e/ -v --headed --slowmo=500The --headed flag opens a browser window so you can watch the tests run.
The --slowmo=500 adds a 500ms delay between actions for easier observation.
Run a specific test:
DB_VENDOR=sqlite JANEWAY_SETTINGS_MODULE=core.janeway_global_settings \
pytest plugins/geometadata/tests/e2e/test_maps.py::TestJournalMapPage::test_map_page_contains_leaflet_map -v --headedTest Artifacts:
When tests run, they generate several artifacts in tests/e2e/test-results/:
| Artifact | Description |
|---|---|
screenshots/*.png |
Screenshots of map pages (captured for visual verification) |
traces/*.zip |
Playwright traces for failed tests (can be viewed with playwright show-trace) |
To view a trace file for debugging a failed test:
playwright show-trace tests/e2e/test-results/traces/test-name-trace.zipFollow Janeway's code style:
ruff check src/plugins/geometadata
ruff format src/plugins/geometadataSee static/geometadata/README.md for details on the bundled Leaflet libraries, their licenses, and update instructions.
Several enhancements to Janeway's core would improve geometadata integration. These are tracked in Issue #1.
This plugin is part of the KOMET project and is licensed under AGPL v3+, consistent with Janeway.
- Daniel Nüst, TU Dresden
- Janeway Issue #1928 - Original feature request
- Janeway Documentation
- Janeway Plugin Documentation
If you use this plugin in your research or publication workflow, please cite it:
Nüst, D. (2026). Geometadata Plugin for Janeway (v0.1.0). Zenodo. https://doi.org/10.5281/zenodo.18495577
BibTeX:
@software{nust_geometadata_2026,
author = {Nüst, Daniel},
title = {Geometadata Plugin for Janeway},
year = 2026,
publisher = {Zenodo},
version = {v0.1.0},
doi = {10.5281/zenodo.18495577},
url = {https://doi.org/10.5281/zenodo.18495577}
}