Skip to content

Commit c35c715

Browse files
authored
Merge pull request #887 from aaxelb/feat/9046/shtrove-rss-followup
[ENG-9046][followup] fix rss/atom validation errors
2 parents 71ebed7 + 8d48649 commit c35c715

File tree

5 files changed

+49
-16
lines changed

5 files changed

+49
-16
lines changed

tests/trove/render/test_cardsearch_atom_renderer.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from unittest import mock
2+
import datetime
3+
14
from trove.render.cardsearch_atom import CardsearchAtomRenderer
25
from trove.render.rendering import EntireRendering
36
from . import _base
@@ -15,8 +18,9 @@ class TestCardsearchAtomRenderer(_base.TrovesearchRendererTests):
1518
b'<feed xmlns="http://www.w3.org/2005/Atom">'
1619
b'<title>shtrove search results</title>'
1720
b'<subtitle>feed of metadata records matching given filters</subtitle>'
18-
b'<link>http://blarg.example/vocab/aSearch</link>'
21+
b'<link href="http://blarg.example/vocab/aSearch" />'
1922
b'<id>http://blarg.example/vocab/aSearch</id>'
23+
b'<updated>2345-06-07T08:09:10Z</updated>'
2024
b'</feed>'
2125
),
2226
),
@@ -27,8 +31,9 @@ class TestCardsearchAtomRenderer(_base.TrovesearchRendererTests):
2731
b'<feed xmlns="http://www.w3.org/2005/Atom">'
2832
b'<title>shtrove search results</title>'
2933
b'<subtitle>feed of metadata records matching given filters</subtitle>'
30-
b'<link>http://blarg.example/vocab/aSearchFew</link>'
34+
b'<link href="http://blarg.example/vocab/aSearchFew" />'
3135
b'<id>http://blarg.example/vocab/aSearchFew</id>'
36+
b'<updated>2345-06-07T08:09:10Z</updated>'
3237
b'<entry>'
3338
b'<link href="http://blarg.example/vocab/anItem" />'
3439
b'<id>http://blarg.example/vocab/aCard</id>'
@@ -42,7 +47,14 @@ class TestCardsearchAtomRenderer(_base.TrovesearchRendererTests):
4247
b'<id>http://blarg.example/vocab/aCarddd</id>'
4348
b'<title>an itemmm, yes</title>'
4449
b'<published>2001-02-03T00:00:00Z</published>'
50+
b'<author><name>a person indeed</name><uri>http://blarg.example/vocab/aPerson</uri></author>'
4551
b'</entry></feed>'
4652
),
4753
),
4854
}
55+
56+
def setUp(self):
57+
self.enterContext(mock.patch(
58+
'django.utils.timezone.now',
59+
return_value=datetime.datetime(2345, 6, 7, 8, 9, 10, tzinfo=datetime.UTC),
60+
))

tests/trove/render/test_cardsearch_rss_renderer.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ class TestCardsearchRssRenderer(_base.TrovesearchRendererTests):
1212
mediatype='application/rss+xml',
1313
entire_content=(
1414
b"<?xml version='1.0' encoding='utf-8'?>\n"
15-
b'<rss version="2.0">'
15+
b'<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">'
1616
b'<channel>'
1717
b'<title>shtrove search results</title>'
1818
b'<link>http://blarg.example/vocab/aSearch</link>'
19+
b'<atom:link rel="self" href="http://blarg.example/vocab/aSearch" />'
1920
b'<description>feed of metadata records matching given filters</description>'
2021
b'<webMaster>[email protected]</webMaster>'
2122
b'</channel></rss>'
@@ -25,9 +26,11 @@ class TestCardsearchRssRenderer(_base.TrovesearchRendererTests):
2526
mediatype='application/rss+xml',
2627
entire_content=(
2728
b"<?xml version='1.0' encoding='utf-8'?>\n"
28-
b'<rss version="2.0"><channel>'
29+
b'<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">'
30+
b'<channel>'
2931
b'<title>shtrove search results</title>'
3032
b'<link>http://blarg.example/vocab/aSearchFew</link>'
33+
b'<atom:link rel="self" href="http://blarg.example/vocab/aSearchFew" />'
3134
b'<description>feed of metadata records matching given filters</description>'
3235
b'<webMaster>[email protected]</webMaster>'
3336
b'<item>'
@@ -43,7 +46,7 @@ class TestCardsearchRssRenderer(_base.TrovesearchRendererTests):
4346
b'<guid isPermaLink="true">http://blarg.example/vocab/anItemmm</guid>'
4447
b'<title>an itemmm, yes</title>'
4548
b'<pubDate>Sat, 03 Feb 2001 00:00:00 -0000</pubDate>'
46-
b'<author>http://blarg.example/vocab/aPerson (a person indeed)</author>'
49+
b'<dc:creator>http://blarg.example/vocab/aPerson (a person indeed)</dc:creator>'
4750
b'</item></channel></rss>'
4851
),
4952
),

trove/render/cardsearch_atom.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import itertools
33
import typing
44

5+
from django.utils import timezone
56
from django.utils.translation import gettext as _
67
from primitive_metadata import primitive_rdf as rdf
78

@@ -38,31 +39,37 @@ def _dates(*path: str) -> Iterator[str]:
3839
_xb = XmlBuilder('feed', {'xmlns': 'http://www.w3.org/2005/Atom'})
3940
_xb.leaf('title', text=_('shtrove search results'))
4041
_xb.leaf('subtitle', text=_('feed of metadata records matching given filters'))
41-
_xb.leaf('link', text=self.response_focus.single_iri())
42+
_xb.leaf('link', {'href': self.response_focus.single_iri()})
4243
_xb.leaf('id', text=self.response_focus.single_iri())
44+
_xb.leaf('updated', text=datetime_isoformat_z(timezone.now()))
4345
for _card_iri, _osfmap_json in itertools.chain.from_iterable(card_pages):
4446
with _xb.nest('entry'):
4547
_iri = _osfmap_json.get('@id', _card_iri)
4648
_xb.leaf('link', {'href': _iri})
4749
_xb.leaf('id', text=self._atom_id(_card_iri))
4850
for _title in _strs('title'):
4951
_xb.leaf('title', text=_title)
52+
for _filename in _strs('fileName'):
53+
_xb.leaf('title', text=_filename)
5054
for _desc in _strs('description'):
5155
_xb.leaf('summary', text=_desc)
5256
for _keyword in _strs('keyword'):
53-
_xb.leaf('category', text=_keyword)
57+
_xb.leaf('category', {'term': _keyword})
5458
for _created in _dates('dateCreated'):
5559
_xb.leaf('published', text=_created)
56-
for _creator_obj in json_vals(_osfmap_json, 'creator'):
60+
for _modified in _dates('dateModified'):
61+
_xb.leaf('updated', text=_modified)
62+
_creator_objs = list(json_vals(_osfmap_json, ['creator']))
63+
if not _creator_objs:
64+
_creator_objs = list(json_vals(_osfmap_json, ['isContainedBy', 'creator']))
65+
for _creator_obj in _creator_objs:
5766
assert isinstance(_creator_obj, dict)
5867
with _xb.nest('author'):
5968
for _name in json_strs(_creator_obj, ['name']):
6069
_xb.leaf('name', text=_name)
6170
_creator_iri = _creator_obj.get('@id')
6271
if _creator_iri:
6372
_xb.leaf('uri', text=_creator_iri)
64-
for _sameas_iri in json_strs(_creator_obj, ['sameAs']):
65-
_xb.leaf('uri', text=_sameas_iri)
6673
return EntireRendering(
6774
mediatype=self.MEDIATYPE,
6875
entire_content=bytes(_xb),

trove/render/cardsearch_rss.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,19 @@ def _dates(*path: str) -> Iterator[str]:
3535
for _dt in json_datetimes(_osfmap_json, path):
3636
yield rfc2822_datetime(_dt)
3737

38-
_xb = XmlBuilder('rss', {'version': '2.0'})
38+
_xb = XmlBuilder('rss', {
39+
'version': '2.0',
40+
'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
41+
'xmlns:atom': 'http://www.w3.org/2005/Atom',
42+
})
3943
with _xb.nest('channel'):
4044
# see https://www.rssboard.org/rss-specification#requiredChannelElements
4145
_xb.leaf('title', text=_('shtrove search results'))
4246
_xb.leaf('link', text=self.response_focus.single_iri())
47+
_xb.leaf('atom:link', {
48+
'rel': 'self',
49+
'href': self.response_focus.single_iri(),
50+
})
4351
_xb.leaf('description', text=_('feed of metadata records matching given filters'))
4452
_xb.leaf('webMaster', text=settings.SHARE_SUPPORT_EMAIL)
4553
for _card_iri, _osfmap_json in itertools.chain.from_iterable(card_pages):
@@ -48,8 +56,8 @@ def _dates(*path: str) -> Iterator[str]:
4856
_iri = _osfmap_json.get('@id', _card_iri)
4957
_xb.leaf('link', text=_iri)
5058
_xb.leaf('guid', {'isPermaLink': 'true'}, text=_iri)
51-
for _title in _strs('title'):
52-
_xb.leaf('title', text=_title)
59+
_titles = itertools.chain(_strs('title'), _strs('fileName'))
60+
_xb.leaf('title', text=next(_titles, ''))
5361
for _desc in _strs('description'):
5462
_xb.leaf('description', text=_desc)
5563
for _keyword in _strs('keyword'):
@@ -60,7 +68,7 @@ def _dates(*path: str) -> Iterator[str]:
6068
assert isinstance(_creator_obj, dict)
6169
_creator_name = next(json_strs(_creator_obj, ['name']))
6270
_creator_id = _creator_obj.get('@id', _creator_name)
63-
_xb.leaf('author', text=f'{_creator_id} ({_creator_name})')
71+
_xb.leaf('dc:creator', text=f'{_creator_id} ({_creator_name})')
6472
return EntireRendering(
6573
mediatype=self.MEDIATYPE,
6674
entire_content=bytes(_xb),

trove/render/trovesearch_json.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from __future__ import annotations
2+
import itertools
23
import json
34
import re
45
import typing
56

67
from primitive_metadata import primitive_rdf as rdf
78

89
from trove.vocab.jsonapi import (
10+
JSONAPI_LINK,
911
JSONAPI_LINK_OBJECT,
1012
JSONAPI_MEMBERNAME,
1113
)
@@ -91,8 +93,9 @@ def _render_meta(self) -> dict[str, int | str]:
9193

9294
def _render_links(self) -> JsonObject:
9395
_links = {}
94-
for _pagelink in self._page_links:
95-
_twopledict = rdf.twopledict_from_twopleset(_pagelink)
96+
_response_links = self.response_gathering.ask(JSONAPI_LINK, focus=self.response_focus)
97+
for _link_obj in itertools.chain(self._page_links, _response_links):
98+
_twopledict = rdf.twopledict_from_twopleset(_link_obj)
9699
if JSONAPI_LINK_OBJECT in _twopledict.get(RDF.type, ()):
97100
(_membername,) = _twopledict[JSONAPI_MEMBERNAME]
98101
(_link_url,) = _twopledict[RDF.value]

0 commit comments

Comments
 (0)