All notable changes to OPTIMAP are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
HTTP
Referrer-Policyis nowstrict-origin-when-cross-originso the OpenStreetMap tile server stops blocking our map requests. Django'sSecurityMiddlewarewas relying on its built-in"same-origin"default, which strips theRefereron cross-origin requests — and OSM's tile-usage policy explicitly rejects clients that send noReferer. The new value sends only the origin (no URL path) on third-party requests, satisfies OSM's identification requirement, and matches modern browser defaults. -
OAI-PMH harvester is now hardened against transient and content-type errors.
harvest_oai_endpointuses arequests.Sessionwith retries (3 attempts, exponential back-off, on 429/500/502/503/504 and connection/timeout errors), a 30-second timeout, and anOPTIMAP-harvester/1.0User-Agent. The response is now sniffed before being passed to the XML parser — non-XML 200 responses (e.g. an HTML maintenance page) are rejected with a body preview in the error log, so operators can diagnose upstream changes without spelunking. The two live-endpoint tests against Copernicus (test_real_journal_harvesting_essd/_geo_leo) now skip cleanly when the upstream is unreachable.
-
Profanity filter on Recognition Board usernames — submitted display names are checked against
better-profanity's default English word list (split on-/_so slug-style names are checked word-by-word). Offensive names are rejected with a generic "please choose a different username" message; the auto-generatedcoolnamedefaults are also re-checked, so users never receive a flagged suggestion. Best-effort: profanity filters always have false positives, so admins can adjust manually if needed. -
Flash messages are now visible on every page. Django's
messagesframework was wired up in views (e.g. on Recognition Board form errors) but no template rendered them, so users only saw a redirect with no on-screen explanation.base.htmlnow renders queued messages as dismissible Bootstrap alerts above the page content, witherror-level messages mapped toalert-dangerand the rest to their matching alert class. -
Contributor Recognition Board (issue #240) — new public
/recognition-board/page recognising users who add spatial or temporal metadata to OPTIMAP works. Contributions are now tracked per event in a structuredContributionmodel in addition to the existing free-textWork.provenancelog; counts are always recorded regardless of opt-in. Users opt in and choose a display name (auto-filled with acoolname-generated slug) under Settings → Recognition Board. Contributors are grouped into five explorer-named tiers — Marco Polo, Vasco da Gama, Ferdinand Magellan, James Cook, Roald Amundsen — using a logarithmic scale (1, 10, 100, 1000, 10000 total contributions). Each tier title links to the explorer's Wikipedia page via a small info icon. Spatial and temporal contributions are shown separately in each tier withfa-map-marked-altandfa-clockicons. -
Minimal SEO surface on landing pages (issue #22) — work landing pages now emit Open Graph, Twitter Card, schema.org
ScholarlyArticleJSON-LD, and Google Scholarcitation_*tags. TheScholarlyArticleJSON-LD includesspatialCoverageandtemporalCoveragemirroring exactly what we consume from harvested Janeway pages, closing the loop. The homepage emitsWebSite+SearchAction, and the regional feed pages emitCollectionPageJSON-LD with the region as theaboutPlace.<link rel="canonical">is set on every page that ships SEO context. Built ondjango-meta. -
Open Graph preview images for work landing pages (issue #22) — a new
/work/<id>/preview.pngendpoint renders a 1200×630 PNG showing the work's spatial extent on an OSM basemap with a small "OPTIMAP" wordmark in the bottom-right. Served asog:image/twitter:image. Cached lazily on disk and invalidated by apost_savesignal onWork. Works without geometry skip theog:imagetag entirely. -
.zenodo.jsondeposit metadata (issue #16) — adds a Zenodo deposit metadata file at the repository root so that GitHub releases archived to Zenodo are populated with a curated title, description, creators, license, keywords, and links to related resources (KOMET/OPTIMETA project pages, the live instance, the GeoJSON/GeoPackage data downloads, the OpenAPI schema, and the OPTIMETA Geo OJS plugin).
- REUSE / SPDX license headers on all source files (issue #30) — every first-party
.py/.js/.css/.html/.shfile now carries a two-line SPDX header (SPDX-FileCopyrightText+SPDX-License-Identifier: GPL-3.0-or-later). AREUSE.tomlcovers migrations, fixtures, vendored static assets, and binaries. Runreuse lintto verify; the package is inrequirements-dev.txt.
- Janeway harvesting and
janeway_geometadataplugin support (issues #15, #18) — OAI-PMH harvesting now picks up geospatial and temporal metadata published by Janeway journals running thejaneway_geometadataplugin (e.g., DQJ, EarthArxiv, EcoEvoArxiv). The HTML extractor tries, in priority order:- schema.org JSON-LD
spatialCoverage/temporalCoverage(supports GeoJSONgeo, schema.orgGeoShapebox, andGeoCoordinates), <link rel="alternate" type="application/geo+json">— fetched and merged when present,DC.SpatialCoverageGeoJSONFeature/FeatureCollection,DC.box(name=…; northlimit=N; southlimit=S; westlimit=W; eastlimit=E; projection=EPSG4326). The provenance log records which signal was used per work.
- schema.org JSON-LD
- ISO 8601 open intervals in
DC.temporal/DC.PeriodOfTimeand JSON-LDtemporalCoverageare now parsed correctly:../2024-12-31produces(None, "2024-12-31")instead of storing'..'as a date string. Single instants (no/) are stored as(value, value). - Geoextent API - REST API exposing the geoextent library for extracting geospatial and temporal extents from various file formats and remote repositories. Features include:
/api/v1/geoextent/extract/- Extract from uploaded files (GeoJSON, GeoTIFF, Shapefile, GeoPackage, KML, CSV, etc.)/api/v1/geoextent/extract-remote/- Extract from remote repositories (Zenodo, PANGAEA, OSF, Figshare, Dryad, GFZ Data Services, Dataverse)/api/v1/geoextent/extract-batch/- Batch processing of multiple files with combined extent- Multiple response formats: GeoJSON (default), WKT, WKB
- Support for bbox, convex hull, temporal extent, and placename geocoding
- Interactive web UI at
/geoextent/with file upload, remote extraction, and map preview - Comprehensive documentation and integration tests
- Geoextent web interface - Interactive tool at
/geoextent/for extracting spatial/temporal extents from data files:- File upload with drag-and-drop support and size validation
- Remote resource extraction via DOI/URL (comma-separated identifiers)
- Interactive Leaflet map preview with clickable features showing properties
- Parameter customization (bbox, tbox, convex hull, placename, gazetteer selection)
- Response format selection (GeoJSON, WKT, WKB)
- Download results in selected format
- Documentation section with supported formats and providers
- Added to main menu and sitemaps
- Feeds sitemap - Dynamic
/sitemap-feeds.xmllisting all regional feeds (continents and oceans) for search engine discovery - Wikidata export - Export publication metadata to Wikibase/Wikidata instances:
- Export works with spatial metadata to Wikidata
- Support for complex geometries (points, lines, polygons, multigeometry)
- Export extreme points (northernmost, southernmost, easternmost, westernmost) and geometric center
- Configurable via
WIKIBASE_*environment variables
- Global regions layer - Interactive map overlay showing continent and ocean boundaries:
- Toggle-able layer control to show/hide global regions on the main map
- Simplified ocean geometries for efficient rendering
- Color-coded regions (brown for continents, blue for oceans)
- Dashed line styling for clear visual distinction
- Click to view region details and navigate to regional feeds
- Integrated with feed landing pages showing region outlines
- Zoom-to-all features control - Quick navigation button on all maps:
- Expands view to fit all publications in the current context
- Available on main map, feed landing pages, and work landing pages
- Accessible button with screen reader support
- Uses FontAwesome expand icon for visual clarity
- Geocoding/gazetteer search - Map search functionality allowing users to search for locations by name:
- Nominatim geocoder integration (default)
- Optional GeoNames support (requires username configuration)
- Search results displayed on map with zoom to location
- Accessible via search box in map interface
- Available on feed landing pages and work landing pages for consistent navigation
- Works list with pagination - Browse all works page at
/works/list/with:- Configurable pagination (default 50 items per page)
- User-selectable page size with min/max limits
- Cached publication statistics (total works, published works, metadata completeness)
- Direct links to work landing pages
- Regional subscription system - Users can subscribe to receive notifications for new publications from specific continents and oceans. Features include:
- Checkbox-based UI with 8 continents and 7 oceans
- "All Regions" checkbox to select/deselect all at once
- "Disable all" link for quick clearing
- Real-time subscription summary showing currently monitored regions
- Persistent subscriptions across login sessions
- Comprehensive test coverage (16 tests)
- Temporal extent contribution - Users can now contribute temporal extent (start/end dates) in addition to spatial extent. Works can be published with either spatial, temporal, or both extents. Supports flexible date formats: YYYY, YYYY-MM, YYYY-MM-DD.
- Complete status workflow documentation - Documented all 6 publication statuses (Draft, Harvested, Contributed, Published, Testing, Withdrawn) with workflow transitions and visibility rules in README.md.
- Burger menu navigation - Added top bar hamburger menu (☰) next to user icon with dropdown links to all main pages including Home, Browse Works, Contribute, Data & API, Feeds, About, Contact, Accessibility, and GitHub code repository.
- Human-readable sitemap - New
/pagesendpoint showing organized list of all pages with descriptions, categorized into Main Pages, Data & Technical, Information & Help, User Pages, and Development sections. - Custom error pages - Added styled 404 and 500 error pages matching application design with navigation links and help information directing users to About and Accessibility pages.
- Map popup enhancement - Added "View Publication Details" button to map popups linking to work landing pages.
- Paginated popup for overlapping features - When multiple publications overlap on the map, a paginated popup allows users to cycle through them with Previous/Next navigation showing "Publication X of Y".
- Point geometry highlighting - Map markers (CircleMarkers) now show visual feedback when selected with increased size (10px) and high-contrast gold/orange colors, matching polygon highlighting behavior.
- Admin unpublish functionality - Admins can unpublish works, changing status from Published to Draft.
- RSS/Atom feed harvesting support - Added support for harvesting publications from RSS/Atom feeds in addition to OAI-PMH.
- Django management command
harvest_journals- Command-line tool for harvesting from real journal sources with progress reporting and statistics. - Comprehensive test coverage - Added 40+ new tests covering temporal contribution, status workflow, RSS harvesting, error handling, and real journal harvesting.
- Contribution page pagination - Added full pagination support to the contribution page (
/contribute/) with:- Configurable page size (default 50, min 10, max 200 works per page)
- User-selectable page size dropdown with automatic form submission
- Full pagination controls at top and bottom (First, Previous, page numbers, Next, Last)
- Shows current range (e.g., "Showing 1 to 50 of 150 works")
- Fixed variable name bugs (
publication→workthroughout template) - Reuses the same pagination layout as works listing page for consistency
- Model terminology alignment - Renamed base entity from "publications" to "works" throughout the codebase to align with OpenAlex terminology:
- Django app renamed from
publications/toworks/ Publicationmodel renamed toWork- API endpoint changed from
/api/v1/publications/to/api/v1/works/ - Sitemap updated from
/sitemap-publications.xmlto/sitemap-works.xml - URL patterns updated from
/publication/<id>/to/work/<id>/ - All import statements, templates, and configuration files updated
- Fresh migrations created from scratch
- All test fixtures updated
- Django app renamed from
- Work type taxonomy - Added comprehensive
typefield to works using Crossref/OpenAlex controlled vocabulary:- 39 work types supported (article, book, book-chapter, dataset, preprint, dissertation, etc.)
- Type set from source's
default_work_typeduring harvesting - Overridden by OpenAlex API type when available
- Indexed and filterable in admin interface
- Removed external CDN dependencies - All JavaScript and CSS libraries now served locally for improved privacy, security, and offline functionality
- Improved map accessibility - Enhanced keyboard navigation and screen reader support for map interactions
- Regional subscription email notifications - Notification emails now group publications by region with dedicated sections for each subscribed continent or ocean. Each region section includes:
- Region name and type (Continent/Ocean)
- Count of new publications in that region
- Direct link to the region's landing page to view all publications
- Up to 10 publications per region in email (with link to view more)
- Subject line shows total publication count across all regions
- Unified contribution workflow - Single "Submit contribution" button for both spatial and temporal extent. Users can submit either or both in one action.
- Unified admin control panel - Consolidated admin status display, publish/unpublish buttons, provenance information, and "Edit in Admin" link into single highlighted box at top of work landing page. Provenance is collapsible.
- Improved text wrapping - Page titles and abstract text now properly wrap on narrow windows instead of overflowing.
- Unified URL structure - Changed ID-based URLs from
/publication/<id>/to/work/<id>/for consistency with DOI-based URLs. - Consolidated work identifier logic - Centralized logic for determining work identifiers (DOI or internal ID) in a
get_identifier()method on theWorkmodel:- Ensures consistent identifier usage across permalinks, sitemaps, and API responses
- Prioritizes DOI when available, falls back to internal ID
- Reduces code duplication across views and serializers
- Refactored views_geometry.py - Eliminated code duplication by making DOI-based functions wrap ID-based functions. Reduced from 375 to 240 lines (~36% reduction).
- Renamed "Locate" to "Contribute" - URL, page title, and navigation updated for clarity about crowdsourcing purpose.
- Contribute page layout refactored - Fixed text overflow issues with proper CSS containment strategy.
- Flexible publishing requirements - Harvested publications with geometry can be published directly without requiring user contribution.
- Contribute page login button improved - Changed to informational disabled button with clear text: "Please log in to contribute (user menu at top right)".
- Simplified footer navigation - Footer now contains only Sitemap, About/Contact/Imprint, Privacy, and data license. Other page links moved to burger menu and sitemap.
- JavaScript scope error - Fixed "drawnItems is not defined" error in contribution form by declaring variable in outer scope.
- GeoJSON geometry detection - Fixed map click detection for GeoJSON layers by working directly with
layer.feature.geometryinstead of unreliableinstanceofchecks. Implemented proper point-in-polygon (ray casting), point-on-line (distance threshold), and point detection algorithms. - Map popup null location error - Fixed crash when opening paginated popup by reordering operations to close existing popup before setting new location.
- Highlight persistence after popup close - Geometries now properly return to default blue style when popups close, removing gold dashed borders and explicit fill colors.
- Individual popups during pagination - Individual feature popups no longer open simultaneously with paginated popup, preventing UI conflicts.
- Close button highlight clearing - Popup close button (X) and ESC key now properly clear geometry highlights, not just map clicks.
- First page highlight race condition - Fixed race condition where first page of paginated popup wasn't highlighted due to premature clearing by
popupcloseevent handler. - CircleMarker style properties - Point geometries now use appropriate style properties (
radiusinstead ofdashArray) for proper visual feedback.