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

Conversation

RishiDiwanTT
Copy link
Contributor

@RishiDiwanTT RishiDiwanTT commented Aug 23, 2023

This PR should be reviewed in tandem with the Feed Refactor PR.

Description

Acquisition links for the OPDS 2 feeds as per the De Marque document.
This PR also adds the ability for certain feeds to be served as either XML or JSON based on the requests content-type.
This PR was also used to complete the OPDS2 serializer which was left out of #1308 .

Example

      {
          "href": "http://localhost:6500/VT0014/works/Overdrive%20ID/0e20dfec-501f-4b5d-926f-dd712aa39160/borrow",
          "rel": "http://opds-spec.org/acquisition/borrow",
          "type": "application/atom+xml;type=entry;profile=opds-catalog",
          "properties": {
            "availability": {
              "state": "available"
            },
            "indirectAcquisition": [
              {
                "type": "application/vnd.adobe.adept+xml",
                "child": [
                  {
                    "type": "application/pdf"
                  }
                ]
              },
              {
                "type": "application/vnd.overdrive.circulation.api+json;profile=ebook"
              },
              {
                "type": "application/atom+xml;type=entry;profile=opds-catalog",
                "child": [
                  {
                    "type": "text/html;profile=\"http://librarysimplified.org/terms/profiles/streaming-media\""
                  }
                ]
              }
            ]
          }
        }

Missing

The authenticate property has not been added, since we are currently providing the authentication document link as part of the feed links. Wasn't sure is we wanted to change that behaviour.

Motivation and Context

JIRA-129 and JIRA-78

How Has This Been Tested?

Manually checked

Checklist

  • I have updated the documentation accordingly.
  • All new and existing tests passed.

@RishiDiwanTT RishiDiwanTT requested a review from a team August 23, 2023 13:01
@RishiDiwanTT RishiDiwanTT self-assigned this Aug 23, 2023
@RishiDiwanTT RishiDiwanTT changed the base branch from main to feature/refactor-opds-feeds August 23, 2023 13:06
@RishiDiwanTT RishiDiwanTT force-pushed the feature/opds2-with-acqusition-links branch from 16d8c6a to 5138840 Compare August 23, 2023 13:27
@RishiDiwanTT RishiDiwanTT changed the title OPDS 2 with acquisition links PP-129 OPDS 2 with acquisition links Aug 23, 2023
@codecov
Copy link

codecov bot commented Aug 24, 2023

Codecov Report

Patch coverage: 93.49% and project coverage change: +0.08% 🎉

Comparison is base (45a2f09) 89.96% compared to head (9772860) 90.04%.

Additional details and impacted files
@@                       Coverage Diff                       @@
##           feature/refactor-opds-feeds    #1340      +/-   ##
===============================================================
+ Coverage                        89.96%   90.04%   +0.08%     
===============================================================
  Files                              225      227       +2     
  Lines                            30473    30660     +187     
  Branches                          6979     7039      +60     
===============================================================
+ Hits                             27416    27609     +193     
+ Misses                            1965     1957       -8     
- Partials                          1092     1094       +2     
Files Changed Coverage Δ
core/opds_schema.py 76.78% <0.00%> (-2.85%) ⬇️
core/feed_protocol/serializer/opds.py 89.75% <85.71%> (+0.25%) ⬆️
core/feed_protocol/serializer/opds2.py 93.66% <92.30%> (ø)
core/feed_protocol/acquisition.py 93.76% <100.00%> (+3.73%) ⬆️
core/feed_protocol/annotator/base.py 92.09% <100.00%> (+0.07%) ⬆️
core/feed_protocol/annotator/circulation.py 89.30% <100.00%> (ø)
core/feed_protocol/navigation.py 100.00% <100.00%> (ø)
core/feed_protocol/opds.py 100.00% <100.00%> (+10.71%) ⬆️
core/feed_protocol/serializer/base.py 100.00% <100.00%> (ø)
core/feed_protocol/types.py 91.41% <100.00%> (+0.16%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@RishiDiwanTT RishiDiwanTT force-pushed the feature/refactor-opds-feeds branch from b50811b to f70ec00 Compare August 24, 2023 06:10
@RishiDiwanTT RishiDiwanTT force-pushed the feature/opds2-with-acqusition-links branch from 39ec230 to 122365c Compare August 24, 2023 06:40
@RishiDiwanTT RishiDiwanTT force-pushed the feature/refactor-opds-feeds branch from c4b041b to f1f1b6b Compare August 29, 2023 07:41
@RishiDiwanTT RishiDiwanTT force-pushed the feature/opds2-with-acqusition-links branch from d1d5769 to 857ba47 Compare August 29, 2023 09:23
@RishiDiwanTT RishiDiwanTT force-pushed the feature/opds2-with-acqusition-links branch from 857ba47 to aecc464 Compare August 30, 2023 12:05
@jonathangreen
Copy link
Member

jonathangreen commented Aug 30, 2023

@RishiDiwanTT The first thing I was trying to do with this PR is to load the OPDS2 version of the feed in my test environment to see what the serialized OPDS2 looks like. Can you give me some pointers how I can get an OPDS2 response?

I tried a few incantations to coerce a OPDS2 response, but I came up empty. I would have expected that I could set an Accept header to be able to control the response, but that doesn't seem to be working for me. What were you doing to test this?

@RishiDiwanTT
Copy link
Contributor Author

RishiDiwanTT commented Aug 31, 2023 via email

@jonathangreen
Copy link
Member

Typically the content-type header indicates the type of the data included in the request. I'd expect to do content negotiation like this via an accept header included on the request, which would cause the content-type header to be included in the response.

@RishiDiwanTT
Copy link
Contributor Author

RishiDiwanTT commented Aug 31, 2023 via email

@jonathangreen
Copy link
Member

Okay. So I pointed this branch at an existing DB with some books in it, and then I ran the resulting OPDS2 feed through our OPDS2 validator /bin/opds2_schema_validate and our feed is failing our own validation. So i think we need to get that sorted out to start with.

@RishiDiwanTT RishiDiwanTT force-pushed the feature/opds2-with-acqusition-links branch from 127b5bb to f77e2dd Compare September 1, 2023 08:23
The only real fix was to the audience category
@RishiDiwanTT
Copy link
Contributor Author

Okay. So I pointed this branch at an existing DB with some books in it, and then I ran the resulting OPDS2 feed through our OPDS2 validator /bin/opds2_schema_validate and our feed is failing our own validation. So i think we need to get that sorted out to start with.

This ended up being trivial, changes required were 2

  • Use the "Accept" header instead of the "Content-Type" header
  • The "audience" scheme should be an URL always

Apart from that the actual validator code was broken, I guess somewhere along the way the OPDSImporter code changed a bit and the validator did not reflect those changes.

@jonathangreen
Copy link
Member

From the comment on #1308:

jonathangreen Aug 30, 2023
Can we rename the package (directory) for this code as well? Right now its feed_protocol, I'd suggest feed.

RishiDiwanTT Sep 1, 2023
This will cause all kinds of unpleasantness while rebasing with #1340 . I will do this once that PR has been merged with this.

Moving this to a comment here so we don't forget the package needs to be renamed.

@RishiDiwanTT
Copy link
Contributor Author

RishiDiwanTT commented Sep 5, 2023

From the comment on #1308:

jonathangreen Aug 30, 2023
Can we rename the package (directory) for this code as well? Right now its feed_protocol, I'd suggest feed.

RishiDiwanTT Sep 1, 2023
This will cause all kinds of unpleasantness while rebasing with #1340 . I will do this once that PR has been merged with this.

Moving this to a comment here so we don't forget the package needs to be renamed.

Do we have anymore feedback for this PR or should I merge it into the refactor branch? Once merged I can rename the module.

@jonathangreen
Copy link
Member

@RishiDiwanTT I'm taking another look over this PR now. I'll post a comment once I'm done.

Copy link
Member

@jonathangreen jonathangreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RishiDiwanTT I made a few more comments here

core/feed_protocol/acquisition.py Outdated Show resolved Hide resolved
tests/api/feed_protocol/test_opds_acquisition_feed.py Outdated Show resolved Hide resolved
api/controller.py Outdated Show resolved Hide resolved
elif entry is None:
return None
elif isinstance(entry, OPDSMessage):
return ProblemDetail(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this new case isn't covered by a test, and it seems like the original code doesn't return a problem detail in this case, but converts the OPDSMessage into an error response?

Can you write up a test for this and verify that we aren't changing the behavior of the single item loans feed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I realised when I changed the order of the return statements, that the single_entry method does not return a ProblemDetail at all, it only returns an OPDSMessage with the problem.
This does change the behaviour from one of returning an XML document (from OPDSMessage.tag ) to that of returning a ProblemDetail when a problem occurs in the single_entry method. This change has been made since the response types are not bound to always being XML.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think either:

  • we need to handle this at the serialization step, so that we get the same XML response we used to get in the case of an OPDS 1 feed
  • Or check with the mobile apps and see how returning a problem detail here instead of a feed will be handled

Since our mobile apps are the primary consumer of this feed still, we need to make sure they are in sync with any changes that get made to the responses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can return to the XML format easily, will that be an acceptable behaviour when the client is expecting JSON though?
Re: ProblemDetail: The same method also returns problem details in different circumstances so a problem detail should be already handled by the client side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior of the mobile apps in the case still worries me. It seems like the thing to do here is to modify OPDSMessage to be non-XML specific, so we are able to serialize it in both OPDS1 and OPDS2 instead of changing the feed behavior.

If that is too much work here, or if you don't want to do that as part of this PR. Can we modify the responses here so that the OPDS1 response (the one that is currently used by the mobile apps) remains the same, rendering the OPDSMessage in the feed as XML and put a follow up ticket in JIRA to handle this case in OPDS2.

@RishiDiwanTT what do you think of those ideas or do you have another idea how we could handle this. The main thing I am concerned about is how this will impact the mobile apps using the OPDS1 feed. The OPDS2 is more "beta" and we can continue to iterate there. I'd like to impact our existing users as little as possible while doing so.

Copy link
Contributor Author

@RishiDiwanTT RishiDiwanTT Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I reverted to protocol specific data, OPDS1 will be the same XML and OPDS2 will be JSON.

core/feed_protocol/opds.py Show resolved Hide resolved
Copy link
Member

@jonathangreen jonathangreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still concerned here about the change in behavior of the OPDSMessage class as part of this PR. I don't want to hold up merging this, but I also don't want it to have a negative impact on the experience of our users consuming the OPDS 1 feed through the app.

core/feed_protocol/opds.py Outdated Show resolved Hide resolved
elif entry is None:
return None
elif isinstance(entry, OPDSMessage):
return ProblemDetail(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior of the mobile apps in the case still worries me. It seems like the thing to do here is to modify OPDSMessage to be non-XML specific, so we are able to serialize it in both OPDS1 and OPDS2 instead of changing the feed behavior.

If that is too much work here, or if you don't want to do that as part of this PR. Can we modify the responses here so that the OPDS1 response (the one that is currently used by the mobile apps) remains the same, rendering the OPDSMessage in the feed as XML and put a follow up ticket in JIRA to handle this case in OPDS2.

@RishiDiwanTT what do you think of those ideas or do you have another idea how we could handle this. The main thing I am concerned about is how this will impact the mobile apps using the OPDS1 feed. The OPDS2 is more "beta" and we can continue to iterate there. I'd like to impact our existing users as little as possible while doing so.

Created a Serializer base for better typing and OOP
Copy link
Member

@jonathangreen jonathangreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 I think this is looking good @RishiDiwanTT

@jonathangreen jonathangreen added the feature New feature label Sep 13, 2023
@RishiDiwanTT RishiDiwanTT merged commit 38f4da5 into feature/refactor-opds-feeds Sep 14, 2023
28 checks passed
@RishiDiwanTT RishiDiwanTT deleted the feature/opds2-with-acqusition-links branch September 14, 2023 09:33
RishiDiwanTT added a commit that referenced this pull request Sep 14, 2023
* Added acquisition link serialization for OPDS2

* OPDS2 serialization with acuqisition links

* Loan and hold specific statuses for acquisition links

* Content types come from the serializer now

OPDS2 publication feed is now the same as the OPDS1 page feed, with a different serializer

* Ensure test_url_for is only used during testing

* Mimetypes are iterated in priority order before serialization

Created a Serializer base for better typing and OOP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants