Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…erty on the sort and facet relations in OPDS1V2 and OPDS2V2 feeds.
  • Loading branch information
dbernstein committed Oct 28, 2024
1 parent 4f42602 commit bffda05
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 15 deletions.
21 changes: 15 additions & 6 deletions src/palace/manager/feed/acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def facet_links(
circumstances apply. You need to decide whether to call
add_entrypoint_links in addition to calling this method.
"""
for group, value, new_facets, selected in facets.facet_groups:
for group, value, new_facets, selected, default_facet in facets.facet_groups:
url = annotator.facet_url(new_facets)
if not url:
continue
Expand All @@ -160,11 +160,18 @@ def facet_links(
# system. It may be left over from an earlier version,
# or just weird junk data.
continue
yield cls.facet_link(url, str(facet_title), str(group_title), selected)
yield cls.facet_link(
url, str(facet_title), str(group_title), selected, default_facet
)

@classmethod
def facet_link(
cls, href: str, title: str, facet_group_name: str, is_active: bool
cls,
href: str,
title: str,
facet_group_name: str,
is_active: bool,
is_default: bool,
) -> Link:
"""Build a set of attributes for a facet link.
Expand All @@ -174,15 +181,17 @@ def facet_link(
e.g. "Sort By".
:param is_active: True if this is the client's currently
selected facet.
:retusrn: A dictionary of attributes, suitable for passing as
:param is_default: True if this is the default facet
:return: A dictionary of attributes, suitable for passing as
keyword arguments into OPDSFeed.add_link_to_feed.
"""
args = dict(href=href, title=title)
args["rel"] = LinkRelations.FACET_REL
args["facetGroup"] = facet_group_name
if is_active:
args["activeFacet"] = "true"
if is_default:
args["defaultFacet"] = "true"
return Link.create(**args)

def as_error_response(self, **kwargs: Any) -> OPDSFeedResponse:
Expand Down Expand Up @@ -266,7 +275,7 @@ def _entrypoint_link(

url = url_generator(entrypoint)
is_selected = entrypoint is selected_entrypoint
link = cls.facet_link(url, display_title, group_name, is_selected)
link = cls.facet_link(url, display_title, group_name, is_selected, is_default)

# Unlike a normal facet group, every link in this facet
# group has an additional attribute marking it as an entry
Expand Down
11 changes: 8 additions & 3 deletions src/palace/manager/feed/serializer/opds.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"facetGroup": f"{{{OPDSFeed.OPDS_NS}}}facetGroup",
"facetGroupType": f"{{{OPDSFeed.SIMPLIFIED_NS}}}facetGroupType",
"activeFacet": f"{{{OPDSFeed.OPDS_NS}}}activeFacet",
"defaultFacet": f"{{{OPDSFeed.PALACE_PROPS_NS}}}default",
"ratingValue": f"{{{OPDSFeed.SCHEMA_NS}}}ratingValue",
"activeSort": f"{{{OPDSFeed.PALACE_PROPS_NS}}}active-sort",
}
Expand Down Expand Up @@ -413,7 +414,7 @@ def _serialize_facet_links(self, facet_links: list[Link]) -> list[Link]:
links.append(self._serialize_feed_entry("link", link))
return links

def _serialize_sort_links(self, facet_links):
def _serialize_sort_links(self, facet_links: list[Link]) -> list[Link]:
return []


Expand All @@ -437,14 +438,18 @@ def _serialize_sort_links(self, facet_links: list[Link]) -> list[Link]:
if facet_links:
for link in facet_links:
if is_sort_link(link):
links.append(self._serialize_sort_link("link", link))
links.append(self._serialize_sort_link(link))
return links

def _serialize_sort_link(self, link: Link) -> etree._Element:
sort_link = Link(
href=link.href, title=link.title, rel=AtomFeed.PALACE_REL_NS + "sort"
)
attributes: dict[str, Any] = dict()
if link.get("activeFacet", False):
sort_link.add_attributes(dict(activeSort="true"))
attributes.update(dict(activeSort="true"))
if link.get("defaultFacet", False):
attributes.update(dict(defaultFacet="true"))
sort_link.add_attributes(attributes)

return self._serialize_feed_entry("link", sort_link)
11 changes: 10 additions & 1 deletion src/palace/manager/feed/serializer/opds2.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

PALACE_REL_SORT = AtomFeed.PALACE_REL_SORT
PALACE_PROPERTIES_ACTIVE_SORT = AtomFeed.PALACE_PROPS_NS + "active-sort"
PALACE_PROPERTIES_DEFAULT = AtomFeed.PALACE_PROPERTIES_DEFAULT


class OPDS2Version1Serializer(SerializerInterface[dict[str, Any]]):
Expand Down Expand Up @@ -255,6 +256,14 @@ def _serialize_sort_link(cls, link: Link) -> dict[str, Any]:
"title": link.title,
"rel": PALACE_REL_SORT,
}

properties: dict[str, str] = {}

sort_link["properties"] = properties

if link.get("activeFacet", False):
sort_link["properties"] = {PALACE_PROPERTIES_ACTIVE_SORT: "true"}
properties.update({PALACE_PROPERTIES_ACTIVE_SORT: "true"})

if link.get("defaultFacet", False):
properties.update({PALACE_PROPERTIES_DEFAULT: "true"})
return sort_link
4 changes: 2 additions & 2 deletions src/palace/manager/sqlalchemy/model/lane.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ def query_string(self):

@property
def facet_groups(self):
"""Yield a list of 4-tuples
(facet group, facet value, new Facets object, selected)
"""Yield a list of 5-tuples
(facet group, facet value, new Facets object, selected, default)
for use in building OPDS facets.
This does not include the 'entry point' facet group,
Expand Down
1 change: 1 addition & 0 deletions src/palace/manager/util/opds_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class AtomFeed:
PALACE_PROPS_NS = "http://palaceproject.io/terms/properties/"

PALACE_REL_SORT = PALACE_REL_NS + "sort"
PALACE_PROPERTIES_DEFAULT = PALACE_PROPS_NS + "default"

nsmap = {
None: ATOM_NS,
Expand Down
10 changes: 8 additions & 2 deletions tests/manager/feed/test_opds2_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from palace.manager.feed.serializer.opds2 import (
PALACE_PROPERTIES_ACTIVE_SORT,
PALACE_PROPERTIES_DEFAULT,
PALACE_REL_SORT,
OPDS2Version1Serializer,
OPDS2Version2Serializer,
Expand Down Expand Up @@ -236,7 +237,9 @@ def test_serialize_opds_message(self):
def test_serialize_v2_sort_links(self):
feed_data = FeedData()
link = Link(href="test", rel="test_rel", title="text1")
link.add_attributes(dict(facetGroup="Sort by", activeFacet="true"))
link.add_attributes(
dict(facetGroup="Sort by", activeFacet="true", defaultFacet="true")
)
feed_data.facet_links.append(link)
links = OPDS2Version2Serializer()._serialize_feed_links(feed=feed_data)

Expand All @@ -246,7 +249,10 @@ def test_serialize_v2_sort_links(self):
"href": "test",
"rel": PALACE_REL_SORT,
"title": "text1",
"properties": {PALACE_PROPERTIES_ACTIVE_SORT: "true"},
"properties": {
PALACE_PROPERTIES_ACTIVE_SORT: "true",
PALACE_PROPERTIES_DEFAULT: "true",
},
}
],
"facets": [],
Expand Down
8 changes: 7 additions & 1 deletion tests/manager/feed/test_opds_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ def test_serialize_opds_message(self):

def test_serialize_sort_link(self):
link = Link(href="test", rel="test_rel", title="text1")
link.add_attributes(dict(facetGroup="Sort by", activeFacet="true"))
link.add_attributes(
dict(facetGroup="Sort by", activeFacet="true", defaultFacet="true")
)
serializer = OPDS1Version2Serializer()
assert is_sort_link(link)
sort_link = serializer._serialize_sort_link(link)
Expand All @@ -274,3 +276,7 @@ def test_serialize_sort_link(self):
sort_link.attrib["{http://palaceproject.io/terms/properties/}active-sort"]
== "true"
)
assert (
sort_link.attrib["{http://palaceproject.io/terms/properties/}default"]
== "true"
)

0 comments on commit bffda05

Please sign in to comment.