Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PP-129 OPDS 2 with acquisition links #1340

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc45a75
Added acquisition link serialization for OPDS2
RishiDiwanTT Aug 21, 2023
6c78807
OPDS2 serialization with acuqisition links
RishiDiwanTT Aug 23, 2023
3abfc09
OPDS2 serializer contributors
RishiDiwanTT Aug 23, 2023
4e617f0
Availabilty state revert
RishiDiwanTT Aug 23, 2023
8a7801a
Loan and hold specific statuses for acquisition links
RishiDiwanTT Aug 23, 2023
6aef252
Mypy fixes
RishiDiwanTT Aug 23, 2023
ea99429
Content types come from the serializer now
RishiDiwanTT Aug 23, 2023
c8a7d7c
Fix minor error
RishiDiwanTT Aug 23, 2023
009a6ab
Test fixes
RishiDiwanTT Aug 24, 2023
bad77e6
Additional test cases
RishiDiwanTT Aug 24, 2023
cf6bf9d
Mypy fixes
RishiDiwanTT Aug 24, 2023
49af1b0
Test Fix
RishiDiwanTT Aug 29, 2023
a9137d1
Typing fixes
RishiDiwanTT Aug 29, 2023
03715d3
rebase fixes
RishiDiwanTT Aug 30, 2023
90defb3
Ensure test_url_for is only used during testing
RishiDiwanTT Aug 30, 2023
f77e2dd
Rebase fixes
RishiDiwanTT Sep 1, 2023
498c879
OPDS2 schema validation fixes
RishiDiwanTT Sep 1, 2023
8c4941b
Comment update
RishiDiwanTT Sep 4, 2023
508b81a
Mimetypes are iterated in priority order before serialization
RishiDiwanTT Sep 6, 2023
fbb7223
Fixed up the get_serializer method and wrote tests
RishiDiwanTT Sep 6, 2023
8e0bbe7
Fixed the opds2 mimetype
RishiDiwanTT Sep 6, 2023
ec2620e
Sort MIMEAccept type values in get_serializer
RishiDiwanTT Sep 7, 2023
fcad7b7
Fix for none types
RishiDiwanTT Sep 7, 2023
79fcb0d
Mypy fix
RishiDiwanTT Sep 7, 2023
0cbc81b
Only allow MIMEAccept information when getting the serializer
RishiDiwanTT Sep 7, 2023
9772860
Reverted OPDSMessage responses to type specific responses
RishiDiwanTT Sep 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from sqlalchemy import select
from sqlalchemy.orm import eagerload
from sqlalchemy.orm.exc import NoResultFound
from werkzeug.datastructures import MIMEAccept

from api.authentication.access_token import AccessTokenProvider
from api.model.patron_auth import PatronAuthAccessToken
Expand Down Expand Up @@ -1323,7 +1324,7 @@ def publications(self):
self.search_engine,
)
return feed.as_response(
mime_types=[("application/opds+json", 1)], # Force the type
mime_types=MIMEAccept([("application/opds+json", 1)]), # Force the type
max_age=int(max_age) if max_age is not None else None,
)

Expand Down
4 changes: 2 additions & 2 deletions core/feed_protocol/navigation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Any, List, Optional, Tuple
from typing import Any, Optional

from sqlalchemy.orm import Session
from typing_extensions import Self
Expand Down Expand Up @@ -84,7 +84,7 @@ def add_entry(

def as_response(
self,
mime_types: Optional[MIMEAccept | List[Tuple[str, float]]] = None,
mime_types: Optional[MIMEAccept] = None,
**kwargs: Any,
) -> OPDSFeedResponse:
response = super().as_response(mime_types=mime_types, **kwargs)
Expand Down
28 changes: 14 additions & 14 deletions core/feed_protocol/opds.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import logging
from typing import Any, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Type

from werkzeug.datastructures import MIMEAccept

Expand All @@ -14,17 +14,19 @@


def get_serializer(
jonathangreen marked this conversation as resolved.
Show resolved Hide resolved
mime_types: Optional[MIMEAccept | List[Tuple[str, float]]],
mime_types: Optional[MIMEAccept],
) -> OPDS1Serializer | OPDS2Serializer:
# Loop through and return whichever mimetype is encountered first
# Sort values by q-value first
if mime_types is not None:
mime_types = sorted(mime_types, key=lambda mime: mime[1], reverse=True)
for mime in mime_types or []:
if "application/opds+json" in mime[0]:
return OPDS2Serializer()
elif "application/atom+xml" in mime[0]:
return OPDS1Serializer()
serializers: Dict[str, Type[Any]] = {
"application/opds+json": OPDS2Serializer,
"application/atom+xml": OPDS1Serializer,
}
if mime_types:
match = mime_types.best_match(
serializers.keys(), default="application/atom+xml"
)
return serializers[match]() # type: ignore[no-any-return]
jonathangreen marked this conversation as resolved.
Show resolved Hide resolved
# Default
return OPDS1Serializer()

Expand All @@ -42,9 +44,7 @@ def __init__(
self._feed = FeedData()
self.log = logging.getLogger(self.__class__.__name__)

def serialize(
self, mime_types: Optional[MIMEAccept | List[Tuple[str, float]]] = None
) -> bytes:
def serialize(self, mime_types: Optional[MIMEAccept] = None) -> bytes:
serializer = get_serializer(mime_types)
return serializer.serialize_feed(self._feed)

Expand All @@ -53,7 +53,7 @@ def add_link(self, href: str, rel: Optional[str] = None, **kwargs: Any) -> None:

def as_response(
self,
mime_types: Optional[MIMEAccept | List[Tuple[str, float]]] = None,
mime_types: Optional[MIMEAccept] = None,
**kwargs: Any,
) -> OPDSFeedResponse:
"""Serialize the feed using the serializer protocol"""
Expand All @@ -70,7 +70,7 @@ def as_response(
def entry_as_response(
cls,
entry: WorkEntry,
mime_types: Optional[MIMEAccept | List[Tuple[str, float]]] = None,
mime_types: Optional[MIMEAccept] = None,
**response_kwargs: Any,
) -> OPDSEntryResponse:
if not entry.computed:
Expand Down
3 changes: 2 additions & 1 deletion tests/api/feed_protocol/test_opds_acquisition_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import pytest
from sqlalchemy.orm import Session
from werkzeug.datastructures import MIMEAccept

from core.entrypoint import (
AudiobooksEntryPoint,
Expand Down Expand Up @@ -63,7 +64,7 @@ def test_entry_as_response(self, db: DatabaseTransactionFixture):

# Specifically asking for a json type
response = BaseOPDSFeed.entry_as_response(
entry, mime_types=[("application/opds+json", 0.9)]
entry, mime_types=MIMEAccept([("application/opds+json", 0.9)])
)
assert isinstance(response, OPDSEntryResponse)
assert response.content_type == "application/opds+json"
Expand Down
12 changes: 2 additions & 10 deletions tests/api/feed_protocol/test_opds_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ def test_get_serializer(self):
)
assert isinstance(get_serializer(request.accept_mimetypes), OPDS1Serializer)

# The default q-value should be 1
# The default q-value should be 1, but opds2 specificity is higher
request = Request.from_values(
headers=dict(
Accept="application/atom+xml;profile=feed,application/opds+json;q=0.9"
)
)
assert isinstance(get_serializer(request.accept_mimetypes), OPDS1Serializer)
assert isinstance(get_serializer(request.accept_mimetypes), OPDS2Serializer)

# The default q-value should sort above 0.9
request = Request.from_values(
Expand All @@ -55,11 +55,3 @@ def test_get_serializer(self):
# No valid accept mimetype should default to OPDS1.x
request = Request.from_values(headers=dict(Accept="text/html"))
assert isinstance(get_serializer(request.accept_mimetypes), OPDS1Serializer)

# Sorting occurs on list type values
assert isinstance(
get_serializer(
[("application/opds+json", 0.9), ("application/atom+xml", 1)]
),
OPDS1Serializer,
)
Loading