@@ -419,3 +419,129 @@ def test_api_viewset_queryset_filtering(self):
419419 self .assertIn (self .pub_testing , queryset )
420420 self .assertIn (self .pub_withdrawn , queryset )
421421 self .assertIn (self .pub_harvested , queryset )
422+
423+
424+ class MultipleIdentifierAccessTest (TestCase ):
425+ """Tests for accessing works by various identifier types (DOI, ID, future: handle)."""
426+
427+ def setUp (self ):
428+ self .client = Client ()
429+
430+ # Create test source
431+ self .source = Source .objects .create (
432+ name = "Test Journal" ,
433+ url_field = "https://example.com/oai" ,
434+ homepage_url = "https://example.com/journal" ,
435+ issn_l = "1234-5678"
436+ )
437+
438+ # Create a work with DOI
439+ self .work_with_doi = Work .objects .create (
440+ title = "Work with DOI" ,
441+ abstract = "This work has a DOI" ,
442+ url = "https://example.com/work1" ,
443+ status = "p" ,
444+ doi = "10.1234/test-doi" ,
445+ publicationDate = now () - timedelta (days = 30 ),
446+ geometry = GeometryCollection (Point (12.4924 , 41.8902 )),
447+ source = self .source
448+ )
449+
450+ # Create a work without DOI
451+ self .work_without_doi = Work .objects .create (
452+ title = "Work without DOI" ,
453+ abstract = "This work has no DOI" ,
454+ url = "https://example.com/work2" ,
455+ status = "p" ,
456+ publicationDate = now () - timedelta (days = 20 ),
457+ geometry = GeometryCollection (Point (13.4050 , 52.5200 )),
458+ source = self .source
459+ )
460+
461+ def test_access_work_by_doi (self ):
462+ """Test that a work can be accessed by its DOI."""
463+ response = self .client .get (f'/work/{ self .work_with_doi .doi } /' )
464+ self .assertEqual (response .status_code , 200 )
465+ self .assertContains (response , self .work_with_doi .title )
466+ self .assertContains (response , self .work_with_doi .doi )
467+
468+ def test_access_work_by_internal_id (self ):
469+ """Test that a work can be accessed by its internal ID."""
470+ response = self .client .get (f'/work/{ self .work_with_doi .id } /' )
471+ self .assertEqual (response .status_code , 200 )
472+ self .assertContains (response , self .work_with_doi .title )
473+
474+ def test_access_work_without_doi_by_id (self ):
475+ """Test that a work without DOI can be accessed by its internal ID."""
476+ response = self .client .get (f'/work/{ self .work_without_doi .id } /' )
477+ self .assertEqual (response .status_code , 200 )
478+ self .assertContains (response , self .work_without_doi .title )
479+ # Should not show DOI link since work has no DOI
480+ self .assertNotContains (response , 'https://doi.org/' )
481+
482+ def test_work_with_doi_prefers_doi_identifier (self ):
483+ """Test that DOI is detected correctly even if ID could also match."""
484+ # DOI starts with "10." so should be detected as DOI
485+ response = self .client .get (f'/work/{ self .work_with_doi .doi } /' )
486+ self .assertEqual (response .status_code , 200 )
487+ self .assertContains (response , self .work_with_doi .title )
488+
489+ def test_numeric_id_resolves_correctly (self ):
490+ """Test that numeric IDs are handled correctly."""
491+ # Access by numeric ID
492+ response = self .client .get (f'/work/{ self .work_with_doi .id } /' )
493+ self .assertEqual (response .status_code , 200 )
494+ self .assertContains (response , self .work_with_doi .title )
495+
496+ def test_invalid_identifier_returns_404 (self ):
497+ """Test that an invalid identifier returns 404."""
498+ response = self .client .get ('/work/99999999/' ) # Non-existent ID
499+ self .assertEqual (response .status_code , 404 )
500+
501+ response = self .client .get ('/work/10.9999/nonexistent/' ) # Non-existent DOI
502+ self .assertEqual (response .status_code , 404 )
503+
504+ def test_work_without_doi_title_format (self ):
505+ """Test that works without DOI have correct title format (no DOI in parentheses)."""
506+ response = self .client .get (f'/work/{ self .work_without_doi .id } /' )
507+ self .assertEqual (response .status_code , 200 )
508+
509+ # Extract the title tag content
510+ content = response .content .decode ('utf-8' )
511+
512+ # Should have title without DOI
513+ self .assertIn (f'<title>{ self .work_without_doi .title } - OPTIMAP</title>' , content )
514+
515+ # Should NOT have DOI in parentheses
516+ self .assertNotIn (f'({ self .work_without_doi .title } )' , content )
517+
518+ def test_template_handles_null_doi (self ):
519+ """Test that the template correctly handles works with null DOI."""
520+ response = self .client .get (f'/work/{ self .work_without_doi .id } /' )
521+ self .assertEqual (response .status_code , 200 )
522+
523+ # Should have title
524+ self .assertContains (response , self .work_without_doi .title )
525+
526+ # Should NOT have DOI section
527+ self .assertNotContains (response , '<strong>DOI:</strong>' )
528+
529+ # JavaScript variables should handle empty DOI
530+ self .assertContains (response , 'const doi = ""' )
531+ self .assertContains (response , 'const useIdUrls = true' )
532+
533+ def test_url_encoded_doi_works (self ):
534+ """Test that URL-encoded DOIs are properly decoded and work."""
535+ # Create work with DOI that has special characters
536+ work = Work .objects .create (
537+ title = "Work with special DOI" ,
538+ abstract = "Test" ,
539+ status = "p" ,
540+ doi = "10.1234/test-doi/with-slash" ,
541+ source = self .source
542+ )
543+
544+ # Django's URL routing should handle this automatically
545+ response = self .client .get (f'/work/{ work .doi } /' )
546+ self .assertEqual (response .status_code , 200 )
547+ self .assertContains (response , work .title )
0 commit comments