Skip to content

Commit 2a0040d

Browse files
authored
Merge pull request #215 from GeoinformationSystems/feature/165_add_locate_functionality
2 parents fb490c4 + a7c3559 commit 2a0040d

24 files changed

+2979
-163
lines changed

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"Bash(gh issue view:*)",
88
"Bash(pytest:*)",
99
"Bash(pip search:*)",
10-
"Bash(psql:*)"
10+
"Bash(psql:*)",
11+
"Bash(OPTIMAP_LOGGING_LEVEL=WARNING python manage.py test tests.test_work_landing_page.PublicationStatusVisibilityTest)"
1112
],
1213
"deny": [],
1314
"ask": []

.claude/temp.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
# OPTIMAP
1+
add a button to the work landing page for the logged in admin that takes the user directly to the editing view in the Django backend.
22

3+
for the article http://127.0.0.1:8000/work/10.1007/s11368-020-02742-9/ with the internal ID 949
34

5+
the editing page is http://127.0.0.1:8000/admin/publications/publication/949/change/
46

5-
# geoextent
7+
--
68

9+
10+
expand all harvesting to identify an existing OpenAlex record based on the available unique identifier and store the OpenAlex ID together with the record; if there is no perfet match then the property of the record should be set to None and a seperate field should indicate which partial match(es) were found and what kind of match it was (e.g. DOI match, title+author match, etc);
11+
12+
expand all harvesting to include the messages that led to a warning log also in the email that is sent after the harvesting run, so that the user can see what went wrong without having to check the logs;
13+
14+
--
15+
16+
17+
add feed-based harvesting support (RSS/Atom) for EarthArxiv;
18+
19+
all articles from EarthArxiv are available via https://eartharxiv.org/repository/list/
20+
21+
there is a feed at https://eartharxiv.org/feed/ but it is unclear how many articles it contains

CHANGELOG.md

Lines changed: 17 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,135 +4,26 @@
44

55
### Added
66

7-
- **RSS/Atom feed harvesting support** (`publications/tasks.py`)
8-
- `parse_rss_feed_and_save_publications()` function for parsing RSS/Atom feeds
9-
- `harvest_rss_endpoint()` function for complete RSS harvesting workflow
10-
- Support for RDF-based RSS feeds (Scientific Data journal)
11-
- DOI extraction from multiple feed fields (prism:doi, dc:identifier)
12-
- Duplicate detection by DOI and URL
13-
- Abstract/description extraction from feed content
14-
- feedparser library integration (v6.0.12)
15-
- Added to requirements.txt for RSS/Atom feed parsing
16-
- Supports RSS 1.0/2.0, Atom, and RDF feeds
17-
- Django management command `harvest_journals` enhanced for RSS/Atom feeds
18-
- Added Scientific Data journal with RSS feed support
19-
- Support for both OAI-PMH and RSS/Atom feed types
20-
- Automatic feed type detection based on journal configuration
21-
- Now supports 4 journals: ESSD, AGILE-GISS, GEO-LEO (OAI-PMH), Scientific Data (RSS)
22-
- Comprehensive RSS harvesting tests (`RSSFeedHarvestingTests`)
23-
- 7 test cases covering RSS parsing, duplicate detection, error handling
24-
- Test fixture with sample RDF/RSS feed (`tests/harvesting/rss_feed_sample.xml`)
25-
- Tests for max_records limit, invalid feeds, and HTTP errors
26-
- Django management command `harvest_journals` for harvesting real journal sources
27-
- Command-line options for journal selection, record limits, and source creation
28-
- Detailed progress reporting with colored output
29-
- Statistics for spatial/temporal metadata extraction
30-
- Integration tests for real journal harvesting (`tests/test_real_harvesting.py`)
31-
- 6 tests covering ESSD, AGILE-GISS, GEO-LEO, and EssOAr
32-
- Tests skipped by default (use `SKIP_REAL_HARVESTING=0` to enable)
33-
- Max records parameter to limit harvesting for testing
34-
- Comprehensive error handling tests for OAI-PMH harvesting (`HarvestingErrorTests`)
35-
- 10 test cases covering malformed XML, missing metadata, HTTP errors, network timeouts
36-
- Test fixtures for various error conditions in `tests/harvesting/error_cases/`
37-
- Verification of graceful error handling and logging
38-
- pytest configuration with custom markers (`pytest.ini`)
39-
- `real_harvesting` marker for integration tests
40-
- Configuration for Django test discovery
7+
- **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.
8+
- **Complete status workflow documentation** - Documented all 6 publication statuses (Draft, Harvested, Contributed, Published, Testing, Withdrawn) with workflow transitions and visibility rules in README.md.
9+
- **Map popup enhancement** - Added "View Publication Details" button to map popups linking to work landing pages.
10+
- **Admin unpublish functionality** - Admins can unpublish works, changing status from Published to Draft.
11+
- **RSS/Atom feed harvesting support** - Added support for harvesting publications from RSS/Atom feeds in addition to OAI-PMH.
12+
- **Django management command `harvest_journals`** - Command-line tool for harvesting from real journal sources with progress reporting and statistics.
13+
- **Comprehensive test coverage** - Added 40+ new tests covering temporal contribution, status workflow, RSS harvesting, error handling, and real journal harvesting.
4114

4215
### Changed
4316

44-
- Fixed OAI-PMH harvesting test failures by updating response format parameters
45-
- Changed from invalid 'structured'/'raw' to valid 'geojson'/'wkt'/'wkb' formats
46-
- Updated test assertions to expect GeoJSON FeatureCollection
47-
- Fixed syntax errors in `publications/tasks.py`
48-
- Fixed import statement typo
49-
- Fixed indentation in `extract_timeperiod_from_html` function
50-
- Fixed misplaced return statement in `regenerate_geopackage_cache` function
51-
- Fixed test setup method in `tests/test_harvesting.py`
52-
- Removed incorrect `@classmethod` decorator from `setUp` method
53-
- Fixed `test_regular_harvesting.py` to include `max_records` parameter in mock function
54-
- Updated README.md with comprehensive documentation for:
55-
- Integration test execution
56-
- `harvest_journals` management command usage
57-
- Journal harvesting workflows
17+
- **Unified contribution workflow** - Single "Submit contribution" button for both spatial and temporal extent. Users can submit either or both in one action.
18+
- **Unified admin control panel** - Consolidated admin status display, publish/unpublish buttons, and "Edit in Admin" link into single highlighted box at top of work landing page.
19+
- **Improved text wrapping** - Page titles and abstract text now properly wrap on narrow windows instead of overflowing.
20+
- **Unified URL structure** - Changed ID-based URLs from `/publication/<id>/` to `/work/<id>/` for consistency with DOI-based URLs.
21+
- **Refactored views_geometry.py** - Eliminated code duplication by making DOI-based functions wrap ID-based functions. Reduced from 375 to 240 lines (~36% reduction).
22+
- **Renamed "Locate" to "Contribute"** - URL, page title, and navigation updated for clarity about crowdsourcing purpose.
23+
- **Contribute page layout refactored** - Fixed text overflow issues with proper CSS containment strategy.
24+
- **Flexible publishing requirements** - Harvested publications with geometry can be published directly without requiring user contribution.
25+
- **Contribute page login button improved** - Changed to informational disabled button with clear text: "Please log in to contribute (user menu at top right)".
5826

5927
### Fixed
6028

61-
- Docker build for geoextent installation (added git dependency to Dockerfile)
62-
- 18 geoextent API test failures due to invalid response format values
63-
- 8 test setup errors in OAI-PMH harvesting tests
64-
- Test harvesting function signature mismatch
65-
66-
### Deprecated
67-
68-
- None.
69-
70-
### Removed
71-
72-
- None.
73-
74-
### Security
75-
76-
- None.
77-
78-
## [0.2.0] - 2025-10-09
79-
80-
### Added
81-
82-
- Work landing page improvements:
83-
- Clickable DOI links to https://doi.org resolver
84-
- Clickable source links to journal homepages
85-
- Link to raw JSON API response
86-
- Publication title and DOI in HTML `<title>` tag
87-
- Map enhancements on work landing page:
88-
- Fullscreen control using Leaflet Fullscreen plugin
89-
- Custom "Zoom to All Features" button
90-
- Scroll wheel zoom enabled
91-
- Comprehensive test suite for work landing page (9 tests)
92-
- Comprehensive test suite for geoextent API (24 tests)
93-
94-
### Changed
95-
96-
- None.
97-
98-
### Fixed
99-
100-
- None.
101-
102-
### Deprecated
103-
104-
- None.
105-
106-
### Removed
107-
108-
- None.
109-
110-
### Security
111-
112-
- External links (DOI, source, API) now use `target="_blank"` with `rel="noopener"` for security
113-
114-
## [0.1.0] - 2025-04-16
115-
116-
### Added
117-
118-
- Changelog
119-
120-
### Changed
121-
122-
- None.
123-
124-
### Fixed
125-
126-
- None.
127-
128-
### Deprecated
129-
130-
- None.
131-
132-
### Removed
133-
134-
- None.
135-
136-
### Security
137-
138-
- None.
29+
- **JavaScript scope error** - Fixed "drawnItems is not defined" error in contribution form by declaring variable in outer scope.

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,56 @@ The OPTIMAP has the following features:
1212
- Start page with a full screen map (showing geometries and metadata) and a time line of the areas and time periods of interest for scientific publications
1313
- Passwordless login via email
1414
- RESTful API at `/api`
15+
- **Crowdsourced metadata contribution**: Logged-in users can contribute spatial and temporal extent data for publications
16+
- **Publication workflow**: Harvested → Contributed → Published status transitions with full provenance tracking
17+
- **Admin controls**: Publish/unpublish functionality with audit trails
18+
19+
## Publication Status Workflow
20+
21+
Publications in OPTIMAP follow a status-based workflow with six possible states:
22+
23+
### Status Definitions
24+
25+
- **Draft** (`d`): Internal draft state. Not visible to public. Can be edited by admins. Created when unpublishing a published work.
26+
- **Harvested** (`h`): Automatically harvested from OAI-PMH or RSS feeds. May or may not have spatial/temporal extent. Not publicly visible.
27+
- **Contributed** (`c`): User has contributed spatial and/or temporal extent. Awaits admin review. Not publicly visible.
28+
- **Published** (`p`): Public-facing works visible to all users via website, map, API, and feeds.
29+
- **Testing** (`t`): Reserved for testing purposes. Not publicly visible. Admin access only.
30+
- **Withdrawn** (`w`): Publication has been withdrawn or retracted. Not publicly visible.
31+
32+
### Workflow Transitions
33+
34+
**Harvesting → Publishing:**
35+
36+
1. Publication harvested from external source → Status: **Harvested** (`h`)
37+
2. User contributes spatial/temporal extent → Status: **Contributed** (`c`)
38+
3. Admin reviews and approves → Status: **Published** (`p`)
39+
4. If needed, admin can unpublish → Status: **Draft** (`d`)
40+
41+
**Direct Publishing (Skip Contribution):**
42+
43+
- Harvested publications with **at least one extent type** (spatial OR temporal) can be published directly by admins without user contribution
44+
45+
**Contribution Requirements:**
46+
47+
- Users can only contribute to publications with **Harvested** (`h`) status
48+
- Harvested publications **without any extent** require user contribution before publishing
49+
- Contributed publications can always be published after admin review
50+
51+
**Visibility Rules:**
52+
53+
- Only **Published** (`p`) status is visible to non-admin users
54+
- All other statuses require admin privileges to view
55+
- Published works appear in: main map, work list, API responses, RSS/Atom feeds
56+
57+
**Extent Contribution:**
58+
59+
- Users can contribute **spatial extent** (geographic location) via interactive map with drawing tools
60+
- Users can contribute **temporal extent** (time period) via date form (formats: YYYY, YYYY-MM, YYYY-MM-DD)
61+
- Both extent types can be contributed separately or together in a single submission
62+
- Publications without DOI are supported via ID-based URLs (`/work/<id>/`)
63+
- All contributions are tracked with full provenance (user, timestamp, changes)
64+
- Contribute page lists publications missing either spatial OR temporal extent
1565

1666
OPTIMAP is based on [Django](https://www.djangoproject.com/) (with [GeoDjango](https://docs.djangoproject.com/en/4.1/ref/contrib/gis/) and [Django REST framework](https://www.django-rest-framework.org/)) with a [PostgreSQL](https://www.postgresql.org/)/[PostGIS](https://postgis.net/) database backend.
1767

fixtures/test_data_optimap.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,81 @@
7272
"timeperiod_enddate": "[\"2024\"]",
7373
"provenance": "Manually added from file test_data.json using the Django management script."
7474
}
75+
},
76+
{
77+
"model": "publications.publication",
78+
"pk": 903,
79+
"fields": {
80+
"status": "c",
81+
"title": "Contributed Paper - Hamburg Harbor Study",
82+
"abstract": "This paper has been contributed by a user with geolocation data. It studies shipping traffic in Hamburg harbor.",
83+
"publicationDate": "2022-05-15",
84+
"doi": "10.5555/contrib1",
85+
"url": "http://paper.url/contrib1",
86+
"geometry": "SRID=4326;GEOMETRYCOLLECTION(POINT (9.9937 53.5511))",
87+
"creationDate": "2023-01-15T10:20:30.086Z",
88+
"lastUpdate": "2023-01-16T14:35:22.086Z",
89+
"source": 9,
90+
"timeperiod_startdate": "[\"2020\"]",
91+
"timeperiod_enddate": "[\"2021\"]",
92+
"provenance": "Harvested via OAI-PMH on 2023-01-15T10:20:30Z.\n\nGeometry contributed by user [email protected] on 2023-01-16T14:35:22Z. Changed geometry from empty to Point. Status changed from Harvested to Contributed."
93+
}
94+
},
95+
{
96+
"model": "publications.publication",
97+
"pk": 904,
98+
"fields": {
99+
"status": "c",
100+
"title": "Contributed Paper - Bavarian Alps Research",
101+
"abstract": "User-contributed geolocation for a study about alpine ecosystems in Bavaria.",
102+
"publicationDate": "2023-03-20",
103+
"doi": "10.5555/contrib2",
104+
"url": "http://paper.url/contrib2",
105+
"geometry": "SRID=4326;GEOMETRYCOLLECTION(POLYGON ((10.5 47.3, 10.5 47.7, 11.2 47.7, 11.2 47.3, 10.5 47.3)))",
106+
"creationDate": "2023-06-10T08:15:45.086Z",
107+
"lastUpdate": "2023-06-11T16:22:10.086Z",
108+
"source": 9,
109+
"timeperiod_startdate": "[\"2022-06\"]",
110+
"timeperiod_enddate": "[\"2023-06\"]",
111+
"provenance": "Harvested via OAI-PMH on 2023-06-10T08:15:45Z.\n\nGeometry contributed by user [email protected] on 2023-06-11T16:22:10Z. Changed geometry from empty to Polygon. Status changed from Harvested to Contributed."
112+
}
113+
},
114+
{
115+
"model": "publications.publication",
116+
"pk": 905,
117+
"fields": {
118+
"status": "h",
119+
"title": "Harvested Paper Without DOI - Frankfurt Study",
120+
"abstract": "This harvested paper has no DOI but has a URL identifier. It needs geolocation contribution.",
121+
"publicationDate": "2022-08-10",
122+
"doi": null,
123+
"url": "http://repository.example.org/id/12345",
124+
"geometry": "SRID=4326;GEOMETRYCOLLECTION EMPTY",
125+
"creationDate": "2023-08-01T09:30:00.086Z",
126+
"lastUpdate": "2023-08-01T09:30:00.086Z",
127+
"source": 9,
128+
"timeperiod_startdate": "[\"2021\"]",
129+
"timeperiod_enddate": "[\"2022\"]",
130+
"provenance": "Harvested via RSS feed on 2023-08-01T09:30:00Z from OPTIMAP Test Journal."
131+
}
132+
},
133+
{
134+
"model": "publications.publication",
135+
"pk": 906,
136+
"fields": {
137+
"status": "c",
138+
"title": "Contributed Paper Without DOI - Stuttgart Research",
139+
"abstract": "This paper was harvested without a DOI, but a user contributed geolocation data using the URL identifier.",
140+
"publicationDate": "2023-02-14",
141+
"doi": null,
142+
"url": "http://repository.example.org/id/67890",
143+
"geometry": "SRID=4326;GEOMETRYCOLLECTION(POINT (9.1829 48.7758))",
144+
"creationDate": "2023-09-05T11:45:00.086Z",
145+
"lastUpdate": "2023-09-06T15:20:30.086Z",
146+
"source": 9,
147+
"timeperiod_startdate": "[\"2022\"]",
148+
"timeperiod_enddate": "[\"2023\"]",
149+
"provenance": "Harvested via RSS feed on 2023-09-05T11:45:00Z from OPTIMAP Test Journal.\n\nGeometry contributed by user [email protected] on 2023-09-06T15:20:30Z. Changed geometry from empty to Point. Status changed from Harvested to Contributed."
150+
}
75151
}
76152
]

optimap/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = "0.3.0"
1+
__version__ = "0.4.0"
22
VERSION = __version__

publications/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
("t", "Testing"),
2424
("w", "Withdrawn"),
2525
("h", "Harvested"),
26+
("c", "Contributed"),
2627
)
2728

2829
EMAIL_STATUS_CHOICES = [

0 commit comments

Comments
 (0)