From c8bd5ff754b1605453a8e1c20cddecaca462196e Mon Sep 17 00:00:00 2001 From: Russell Cullen Date: Tue, 14 Nov 2023 11:04:59 -0500 Subject: [PATCH 1/2] Add expiration for open access books, temp hardcoded date --- .../books/controller/BookSyncTask.kt | 26 +++++++++++++++++++ .../core/OPDSAcquisitionFeedEntryParser.java | 20 +++++++++----- .../opds/core/OPDSAvailabilityOpenAccess.kt | 11 +++++--- .../simplified/opds/core/OPDSJSONParser.java | 5 +++- .../opds/core/OPDSJSONSerializer.java | 4 +++ 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/simplified-books-controller/src/main/java/org/nypl/simplified/books/controller/BookSyncTask.kt b/simplified-books-controller/src/main/java/org/nypl/simplified/books/controller/BookSyncTask.kt index 666a0f8b3..182ec3ad4 100644 --- a/simplified-books-controller/src/main/java/org/nypl/simplified/books/controller/BookSyncTask.kt +++ b/simplified-books-controller/src/main/java/org/nypl/simplified/books/controller/BookSyncTask.kt @@ -1,6 +1,7 @@ package org.nypl.simplified.books.controller import com.io7m.jfunctional.Some +import org.joda.time.DateTime import org.librarysimplified.http.api.LSHTTPClientType import org.librarysimplified.http.api.LSHTTPResponseStatus import org.nypl.simplified.accounts.api.AccountAuthenticationCredentials @@ -23,6 +24,7 @@ import org.nypl.simplified.feeds.api.FeedLoading import org.nypl.simplified.opds.core.OPDSAvailabilityRevoked import org.nypl.simplified.opds.core.OPDSFeedParserType import org.nypl.simplified.opds.core.OPDSParseException +import org.nypl.simplified.opds.core.getOrNull import org.nypl.simplified.patron.api.PatronUserProfile import org.nypl.simplified.patron.api.PatronUserProfileParsersType import org.nypl.simplified.profiles.api.ProfileID @@ -64,12 +66,14 @@ class BookSyncTask( val providerAuth = provider.authentication if (providerAuth == AccountProviderAuthenticationDescription.Anonymous) { this.logger.debug("account does not support syncing") + this.removeExpiredBooks(account) return this.taskRecorder.finishSuccess(Unit) } val credentials = account.loginState.credentials if (credentials == null) { this.logger.debug("no credentials, aborting!") + this.removeExpiredBooks(account) return this.taskRecorder.finishSuccess(Unit) } @@ -115,6 +119,28 @@ class BookSyncTask( } } + private fun removeExpiredBooks(account: AccountType) { + val bookDatabase = account.bookDatabase + val existing = bookDatabase.books() + + for (existingId in existing) { + try { + this.logger.debug("[{}] checking for deletion", existingId.brief()) + val dbEntry = bookDatabase.entry(existingId) + val avail = dbEntry.book.entry.availability + val endDate = avail.endDate.getOrNull() ?: continue + + if (endDate <= DateTime.now()) { + this.logger.debug("[{}] deleting", existingId.brief()) + bookRegistry.clearFor(existingId) + dbEntry.delete() + } + } catch (x: Throwable) { + this.logger.error("[{}]: unable to delete entry: ", existingId, x) + } + } + } + private fun fetchPatronUserProfile( account: AccountType, ) { diff --git a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java index 90e2f4aa2..508f9b08e 100644 --- a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java +++ b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java @@ -21,6 +21,7 @@ import java.net.URISyntaxException; import java.text.ParseException; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -164,7 +165,16 @@ private OPDSAcquisitionFeedEntry parseAcquisitionEntry( findAcquisitionAuthors(element, entry_builder); entry_builder.setPublisherOption(findPublisher(element)); - entry_builder.setDistribution(findDistribution(element)); + + String distribution = findDistribution(element); + entry_builder.setDistribution(distribution); + if ("Axis 360".equals(distribution)) { + DateTime end = DateTime.now().plusMonths(2); + entry_builder.setAvailability( + OPDSAvailabilityOpenAccess.get(revoke, Option.some(end)) + ); + } + entry_builder.setPublishedOption(OPDSAtom.findPublished(element)); entry_builder.setSummaryOption( OPDSXML.getFirstChildElementTextWithNameOptional(element, ATOM_URI, "summary")); @@ -280,11 +290,7 @@ private void tryConsumeAcquisitions( final OPDSAcquisition acquisition = new OPDSAcquisition(v, href, type, indirects); entry_builder.addAcquisition(acquisition); - if (v == Relation.ACQUISITION_OPEN_ACCESS) { - entry_builder.setAvailability(OPDSAvailabilityOpenAccess.get(revoke)); - } else { - tryAvailability(entry_builder, link, revoke); - } + tryAvailability(entry_builder, link, revoke); break; } } @@ -653,6 +659,8 @@ private OPDSAvailabilityType inferAvailability( return OPDSAvailabilityLoanable.get(); } else if (Relation.ACQUISITION_GENERIC.getUri().toString().equals(rel)) { return OPDSAvailabilityLoaned.get(start_date, end_date, revoke); + } else if (Relation.ACQUISITION_OPEN_ACCESS.getUri().toString().equals(rel)) { + return OPDSAvailabilityOpenAccess.get(revoke, end_date); } } } diff --git a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAvailabilityOpenAccess.kt b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAvailabilityOpenAccess.kt index fbaabded8..89e124da2 100644 --- a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAvailabilityOpenAccess.kt +++ b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAvailabilityOpenAccess.kt @@ -15,7 +15,8 @@ data class OPDSAvailabilityOpenAccess private constructor( * @return The revocation link, if any */ - val revoke: OptionType + val revoke: OptionType, + private val endDate: OptionType ) : OPDSAvailabilityType { val endDateOrNull: DateTime? @@ -30,7 +31,7 @@ data class OPDSAvailabilityOpenAccess private constructor( */ override fun getEndDate(): OptionType { - return Option.none() + return this.endDate } override fun toString(): String { @@ -57,10 +58,12 @@ data class OPDSAvailabilityOpenAccess private constructor( */ @JvmStatic + @JvmOverloads operator fun get( - revoke: OptionType + revoke: OptionType, + endDate: OptionType = Option.none(), ): OPDSAvailabilityOpenAccess { - return OPDSAvailabilityOpenAccess(revoke) + return OPDSAvailabilityOpenAccess(revoke, endDate) } } } diff --git a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONParser.java b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONParser.java index 278c08fdd..5b337283f 100644 --- a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONParser.java +++ b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONParser.java @@ -22,6 +22,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.List; import one.irradia.mime.api.MIMEType; @@ -176,7 +177,9 @@ private static OPDSAvailabilityType parseAvailability( node, "open_access"); final OptionType in_revoke = JSONParserUtilities.getURIOptional(n, "revoke"); - return OPDSAvailabilityOpenAccess.get(in_revoke); + final OptionType in_end_date = + JSONParserUtilities.getTimestampOptional(n, "end_date"); + return OPDSAvailabilityOpenAccess.get(in_revoke, in_end_date); } if (node.has("revoked")) { diff --git a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONSerializer.java b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONSerializer.java index a390879ef..1dc34630c 100644 --- a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONSerializer.java +++ b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONSerializer.java @@ -174,6 +174,10 @@ public ObjectNode onOpenAccess(final OPDSAvailabilityOpenAccess a) { oh.put("revoke", uri.toString()); return Unit.unit(); }); + a.getEndDate().map(t -> { + oh.put("end_date", fmt.print(t)); + return Unit.unit(); + }); o.set("open_access", oh); return o; } From 00aedb82277ba416a221bae648cacd4afe091229 Mon Sep 17 00:00:00 2001 From: Russell Cullen Date: Thu, 7 Dec 2023 13:50:58 -0500 Subject: [PATCH 2/2] Remove hardcoded expiry --- .../opds/core/OPDSAcquisitionFeedEntryParser.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java index 508f9b08e..88340deab 100644 --- a/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java +++ b/simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java @@ -165,16 +165,7 @@ private OPDSAcquisitionFeedEntry parseAcquisitionEntry( findAcquisitionAuthors(element, entry_builder); entry_builder.setPublisherOption(findPublisher(element)); - - String distribution = findDistribution(element); - entry_builder.setDistribution(distribution); - if ("Axis 360".equals(distribution)) { - DateTime end = DateTime.now().plusMonths(2); - entry_builder.setAvailability( - OPDSAvailabilityOpenAccess.get(revoke, Option.some(end)) - ); - } - + entry_builder.setDistribution(findDistribution(element)); entry_builder.setPublishedOption(OPDSAtom.findPublished(element)); entry_builder.setSummaryOption( OPDSXML.getFirstChildElementTextWithNameOptional(element, ATOM_URI, "summary"));