Skip to content

Conversation

@Aayushdev18
Copy link
Contributor

Closes #11618

feature

Technical

This PR implements local storage tracking for open access and borrowable book reading history. The implementation includes:

Frontend (JavaScript):

  • ReadingHistory class: Manages a bounded queue (100 items) in localStorage with deduplication
  • ReadingHistoryCarousel component: Dynamically renders reading history on My Books page
  • Click tracking: Captures edition IDs from Borrow/Read button clicks
  • XSS protection: All user data is escaped using htmlquote()
  • Analytics: Tracks clicks with data-ol-link-track attributes
  • i18n support: Uses window._() for translation with English fallback

Backend (Python):

  • New API endpoint /reading-history: Accepts comma-separated edition IDs and returns work data from Solr
  • Converts edition IDs → edition keys → work keys → Solr documents
  • Adds availability data using existing add_availability() function
  • Proper error handling and input validation

Key Features:

  • Bounded queue: Keeps last 100 items, automatically removes oldest
  • Deduplication: Removes duplicates while preserving recency (most recent entry wins)
  • Edge case handling: Private browsing mode, localStorage quota exceeded, corrupted data
  • Configurable: No hardcoded values, uses constants and config functions

Files Changed:

  • New: openlibrary/plugins/openlibrary/js/reading-history/ (3 files)
  • New: tests/unit/js/reading-history/ReadingHistory.test.js
  • Modified: openlibrary/plugins/openlibrary/api.py (new endpoint)
  • Modified: openlibrary/plugins/openlibrary/js/index.js (initialization)
  • Modified: openlibrary/templates/account/mybooks.html (carousel container)
  • Modified: openlibrary/macros/ReadButton.html (data attributes)
  • Modified: openlibrary/templates/book_providers/read_button.html (data attributes)

Testing

Manual Testing:

  1. Visit any book page with a "Read" or "Borrow" button
  2. Click the button to add it to reading history
  3. Navigate to /people/{username}/books (My Books page)
  4. Verify the "Reading History" carousel appears with the book
  5. Click multiple books and verify they appear in reverse chronological order
  6. Verify deduplication: Click the same book twice, it should move to the top

Automated Testing:

  • Run: npm test -- tests/unit/js/reading-history/ReadingHistory.test.js
  • Tests cover: adding entries, deduplication, MAX_ITEMS limit, sorting, error handling

Edge Cases Tested:

  • Private browsing mode (localStorage unavailable)
  • localStorage quota exceeded
  • Corrupted localStorage data
  • Empty edition IDs
  • Missing book data from API

Aayushdev18 and others added 8 commits November 5, 2025 03:05
When a specific edition is logged in reading logs, fetch availability
at the edition level instead of work level. This ensures correct borrow
buttons are shown instead of 'Locate' buttons when the logged edition
is available.

Fixes internetarchive#11329
Simplify the add_availability_with_edition_preference function by using
the safeget helper to extract editions directly, following the pattern
from work_search.html. This makes the code more concise and handles
both dict and list edition structures gracefully.
The previous implementation was calling add_availability on editions,
but the template reads availability from work documents. This fix:
- Extracts editions using safeget
- Gets edition-level availability using get_availability('openlibrary_edition')
- Attaches availability to work documents (not editions)
- Falls back to work-level availability when no edition is available

This should fix the 'Locate' button issue by properly setting
availability on work docs that the template expects.
The link_editions_to_works function sets editions as a list [edition],
but the code was only checking for dict format {'docs': [edition]}.
This fix handles both cases to properly extract editions and get
edition-level availability.
…rnetarchive#11618)

- Add ReadingHistory class to track edition IDs in localStorage
- Implement bounded queue (100 items) with deduplication
- Create /reading-history API endpoint to fetch book data
- Add ReadingHistoryCarousel component for My Books page
- Track clicks on Borrow/Read buttons with edition ID extraction
- Add XSS protection with htmlquote for all user data
- Add analytics tracking with data-ol-link-track
- Add i18n support for Reading History label
- Add unit tests for ReadingHistory class
- Handle edge cases: private browsing, quota exceeded, corrupted data
Aayushdev18 and others added 10 commits December 31, 2025 19:31
- Add eslint-disable comments for console statements
- Remove unused event parameters
- Fix unnecessary escape character in regex
- Remove unnecessary console.warn statements
- Remove unused error parameter in catch block
- Replace javascript:; with #reading-history for anchor link
- Remove unused MAX_LIMIT variable that was causing linting error
- Fix incorrect relative import path (was 6 levels up, should be 4 levels up)
- Test file is at tests/unit/js/reading-history/
- Source file is at openlibrary/plugins/openlibrary/js/reading-history/
- Fix sorting issue when items added in same millisecond
- Ensure each entry gets unique timestamp for proper sorting
- Fixes test failures where getEditionIds should return newest first
- Replace **params dict unpacking with explicit keyword arguments
- Fixes mypy error: Argument 2 to get_works has incompatible type
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local storage to track open access book history

2 participants