Skip to content

Commit

Permalink
Merge pull request #125 from mlibrary/carousel
Browse files Browse the repository at this point in the history
Carousel
  • Loading branch information
niquerio authored Jul 19, 2024
2 parents 818ddc3 + f2f9486 commit 02a4a42
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 26 deletions.
13 changes: 13 additions & 0 deletions catalog-browse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require_relative "lib/models/author_list"
require_relative "lib/models/author_item"
require_relative "lib/models/subject_list"
require_relative "lib/models/carousel_list"
require_relative "lib/models/subject_item"
require_relative "lib/models/search_dropdown"
require_relative "lib/models/datastores"
Expand Down Expand Up @@ -61,6 +62,18 @@
end
erb :call_number, locals: {list: list}
end

get "/carousel" do
call_number = params[:query]
begin
content_type :json
headers "Access-Control-Allow-Origin" => "*"
CarouselList.list(call_number).to_json
rescue => e
logger.error(e.message)
status 500
end
end
post "/search" do
redirect SearchDropdown.for(type: params["type"], query: params["query"]).url
end
Expand Down
1 change: 1 addition & 0 deletions lib/models/author_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def self.for(direction:, reference_id:, num_rows_to_display:, original_reference
num_rows_to_display: num_rows_to_display,
original_reference: original_reference,
banner_reference: banner_reference,
match_field: "id",
browse_solr_client: BrowseSolrClient.new(core: S.authority_collection, match_field: "term", q: "browse_field:name")
)

Expand Down
15 changes: 10 additions & 5 deletions lib/models/browse_list.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
class BrowseList
attr_reader :original_reference, :num_rows_to_display, :num_matches, :exact_matches, :banner_reference, :index_docs

def self.for(direction:, reference_id:, num_rows_to_display:, original_reference:,
def self.for(
direction:,
reference_id:,
num_rows_to_display:,
original_reference:,
banner_reference:,
browse_solr_client: BrowseSolrClient.new)
browse_solr_client: BrowseSolrClient.new,
match_field: "PlACEHOLDER"
)

my_banner_reference = banner_reference
exact_matches = browse_solr_client.exact_matches(value: original_reference)
case direction
when "next"
# includes reference in results
# require "byebug"; byebug
index_response = browse_solr_client.browse_reference_on_top(reference_id: reference_id, rows: num_rows_to_display + 2)
BrowseList::ReferenceOnTop.new(
index_response: index_response&.body,
Expand All @@ -32,8 +37,8 @@ def self.for(direction:, reference_id:, num_rows_to_display:, original_reference
else
# index_before:, index_after:
return BrowseList::Empty.new if reference_id.nil? || reference_id == ""
index_before = browse_solr_client.browse_reference_on_bottom(reference_id: reference_id, rows: 3)
index_after = browse_solr_client.browse_reference_on_top(reference_id: reference_id, rows: num_rows_to_display - 1)
index_before = browse_solr_client.browse_reference_on_bottom(reference_id: reference_id, rows: 3, field: match_field)
index_after = browse_solr_client.browse_reference_on_top(reference_id: reference_id, rows: num_rows_to_display - 1, field: match_field)
my_banner_reference = index_after&.body&.dig("response", "docs")&.first&.dig("id")
# need above and below
BrowseList::ReferenceInMiddle.new(
Expand Down
3 changes: 2 additions & 1 deletion lib/models/call_number_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ def self.for(direction:, reference_id:, num_rows_to_display:, original_reference
reference_id: reference_id,
num_rows_to_display: num_rows_to_display,
original_reference: original_reference,
banner_reference: banner_reference
banner_reference: banner_reference,
match_field: "callnumber"
)

bib_ids = browse_list.docs.map { |x| x["bib_id"] }
Expand Down
59 changes: 59 additions & 0 deletions lib/models/carousel_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
class CarouselList
def self.list(call_number, browse_solr_client = BrowseSolrClient.new, catalog_client = CatalogSolrClient.client)
before = browse_solr_client.browse_reference_on_bottom(reference_id: call_number, rows: 22, field: "callnumber").body["response"]["docs"].reverse
after = browse_solr_client.browse_reference_on_top(reference_id: call_number, rows: 23, field: "callnumber").body["response"]["docs"]

ordered_call_number_docs = [before, after].flatten

bib_ids = ordered_call_number_docs.map { |x| x["bib_id"] }
catalog_response = catalog_client.get_bibs(bib_ids: bib_ids).body
items = ordered_call_number_docs.map do |browse_doc|
catalog_doc = catalog_response["response"]["docs"].find do |x|
x["id"] == browse_doc["bib_id"]
end || {}
CarouselItem.new(catalog_doc, browse_doc)
end
items.map { |x| x.to_h }
end

class CarouselItem
def initialize(catalog_doc, browse_doc)
@catalog_doc = catalog_doc
@browse_doc = browse_doc
end

def title
@catalog_doc["title_display"]&.first
end

def author
@catalog_doc["main_author_display"]&.first
end

def call_number
@browse_doc["callnumber"]&.strip
end

def mms_id
@browse_doc["bib_id"]
end

def date
@catalog_doc["display_date"]
end

def url
"https://search.lib.umich.edu/catalog/record/#{mms_id}"
end

def to_h
{
title: title,
author: author,
date: date,
call_number: call_number,
url: url
}
end
end
end
1 change: 1 addition & 0 deletions lib/models/subject_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def self.for(direction:, reference_id:, num_rows_to_display:, original_reference
num_rows_to_display: num_rows_to_display,
original_reference: original_reference,
banner_reference: banner_reference,
match_field: "id",
browse_solr_client: BrowseSolrClient.new(core: S.authority_collection, match_field: "term", q: "browse_field:subject")
)

Expand Down
12 changes: 6 additions & 6 deletions lib/utilities/browse_solr_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ def initialize(solr_url: S.solr_url, core: S.call_number_collection, match_field
@q = q
end

def browse_reference_on_top(reference_id:, rows: 20)
def browse_reference_on_top(reference_id:, rows: 20, field: "id")
# square brackets includes reference in return
range = "id:[\"#{reference_id}\" TO *]"
sort = "id asc"
range = "#{field}:[\"#{reference_id}\" TO *]"
sort = "#{field} asc"
browse(rows: rows, sort: sort, range: range)
end

def browse_reference_on_bottom(reference_id:, rows: 20)
def browse_reference_on_bottom(reference_id:, rows: 20, field: "id")
# curly brackets exclues reference in return
range = "id:{* TO \"#{reference_id}\"}"
sort = "id desc"
range = "#{field}:{* TO \"#{reference_id}\"}"
sort = "#{field} desc"
browse(rows: rows, sort: sort, range: range)
end

Expand Down
11 changes: 10 additions & 1 deletion spec/models/browse_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
num_rows_to_display: 20,
original_reference: nil,
banner_reference: nil,
browse_solr_client: @browse_client
browse_solr_client: @browse_client,
match_field: "my_match_field"
}
end
subject do
Expand All @@ -19,18 +20,26 @@
@params[:direction] = "next"
allow(@browse_client).to receive(:browse_reference_on_top)
expect(subject.class).to eq(BrowseList::ReferenceOnTop)
expect(@browse_client).to have_received(:browse_reference_on_top).with(
{reference_id: nil, rows: 22}
)
end
it "returns a ReferenceOnTop when direction is previous" do
@params[:direction] = "previous"
allow(@browse_client).to receive(:browse_reference_on_bottom)
expect(subject.class).to eq(BrowseList::ReferenceOnBottom)
expect(@browse_client).to have_received(:browse_reference_on_bottom).with(
{reference_id: nil, rows: 21}
)
end
context "direction is nil" do
it "returns a ReferenceInMiddle if there's a reference_id" do
@params[:reference_id] = "Something"
allow(@browse_client).to receive(:browse_reference_on_top)
allow(@browse_client).to receive(:browse_reference_on_bottom)
expect(subject.class).to eq(BrowseList::ReferenceInMiddle)
expect(@browse_client).to have_received(:browse_reference_on_top).with({field: "my_match_field", reference_id: "Something", rows: 19})
expect(@browse_client).to have_received(:browse_reference_on_bottom).with({field: "my_match_field", reference_id: "Something", rows: 3})
end
it "returns a Empty if there in not a reference_id" do
expect(subject.class).to eq(BrowseList::Empty)
Expand Down
58 changes: 58 additions & 0 deletions spec/models/carousel_list_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
describe CarouselList do
before(:each) do
@browse_client = instance_double(BrowseSolrClient)
@catalog_client = instance_double(CatalogSolrClient::Client, get_bibs: OpenStruct.new(body: JSON.parse(fixture("biblio_results.json"))))
end
subject do
described_class.list("my_call_number", @browse_client, @catalog_client)
end
def body(file_name)
out = JSON.parse(fixture(file_name))
OpenStruct.new(body: out)
end
it "returns a list of carousel items" do
allow(@browse_client).to receive(:browse_reference_on_bottom).and_return(body("callnumbers_before.json"))

allow(@browse_client).to receive(:browse_reference_on_top).and_return(body("callnumbers_results.json"))
expect(subject.first[:call_number]).to eq("Z 253 .U581 1952")
end
end
describe CarouselList::CarouselItem do
before(:each) do
@catalog_doc = JSON.parse(fixture("biblio_results.json"))["response"]["docs"].first
@browse_doc = JSON.parse(fixture("callnumbers_results.json"))["response"]["docs"].first
end
subject do
described_class.new(@catalog_doc, @browse_doc)
end
it "has a title" do
expect(subject.title).to eq("Theory and practice of composition.")
end
it "has an author" do
expect(subject.author).to eq("United States. Government Printing Office")
end
it "has a call_number" do
expect(subject.call_number).to eq("Z 253 .U6 1963")
end
it "has an mms_id" do
expect(subject.mms_id).to eq("990011613060106381")
end
it "has a date" do
expect(subject.date).to eq("1950")
end
it "has a url" do
expect(subject.url).to eq("#{S.search_url}/catalog/record/990011613060106381")
end
it "has a hash output" do
expect(subject.to_h).to eq(
{
author: "United States. Government Printing Office",
call_number: "Z 253 .U6 1963",
date: "1950",
title: "Theory and practice of composition.",
url: "#{S.search_url}/catalog/record/990011613060106381"

}
)
end
end
37 changes: 24 additions & 13 deletions spec/requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
before(:each) do
@call_number_collection = S.call_number_collection
@authority_collection = S.authority_collection
@authority_match_field = "id"
end
context "get /" do
it "has status OK" do
Expand All @@ -14,45 +15,45 @@
context "get /callnumber" do
it "for a successful query, returns status OK" do
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'callnumber:"Thing"'}), output: fixture("biblio_results.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({sort: "id desc"}), output: fixture("callnumbers_before.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'id:["Thing" TO *]'}), output: fixture("callnumbers_results.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({sort: "callnumber desc"}), output: fixture("callnumbers_before.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'callnumber:["Thing" TO *]'}), output: fixture("callnumbers_results.json"))
stub_biblio_get_request(url: "biblio/select", query: hash_including({}), output: fixture("biblio_results_middle.json"))
get "/callnumber", {query: "Thing"}
expect(last_response.status).to eq(200)
end
it "for a network error, it still returns a successful response, but with an error message" do
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'callnumber:"Thing"'}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({sort: "id desc"}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({sort: "callnumber desc"}), no_return: true).to_timeout
get "/callnumber", {query: "Thing"}
expect(last_response.status).to eq(200)
end
end
context "get /author" do
it "returns status OK" do
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'term:"Thing"'}), output: fixture("author_exact_matches.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "id desc"}), output: fixture("author_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'id:["Thing" TO *]'}), output: fixture("author_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "term:\"Thing\""}), output: fixture("author_exact_matches.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "#{@authority_match_field} desc"}), output: fixture("author_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "#{@authority_match_field}:[\"Thing\" TO *]"}), output: fixture("author_results.json"))
get "/author", {query: "Thing"}
expect(last_response.status).to eq(200)
end
it "for a network error, it still returns a successful response, but with an error message" do
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'term:"Thing"'}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "id desc"}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "term:\"Thing\""}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "#{@authority_match_field} desc"}), no_return: true).to_timeout
get "/author", {query: "Thing"}
expect(last_response.status).to eq(200)
end
end
context "get /subject" do
it "returns status OK" do
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'term:"Thing"'}), output: fixture("author_exact_matches.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "id desc"}), output: fixture("subject_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'id:["Thing" TO *]'}), output: fixture("subject_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "term:\"Thing\""}), output: fixture("author_exact_matches.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "#{@authority_match_field} desc"}), output: fixture("subject_results.json"))
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "#{@authority_match_field}:[\"Thing\" TO *]"}), output: fixture("subject_results.json"))
get "/subject", {query: "Thing"}
expect(last_response.status).to eq(200)
end
it "for a network error, it still returns a successful response, but with an error message" do
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: 'term:"Thing"'}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "id desc"}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({fq: "term:\"Thing\""}), no_return: true).to_timeout
stub_solr_get_request(url: "#{@authority_collection}/select", query: hash_including({sort: "#{@authority_match_field} desc"}), no_return: true).to_timeout
get "/subject", {query: "Thing"}
expect(last_response.status).to eq(200)
end
Expand All @@ -64,6 +65,16 @@
expect(last_response.headers["Location"]).to eq("#{S.base_url}/author?query=Thing")
end
end
context "get /carousel" do
it "returns some json" do
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'callnumber:"Thing"'}), output: fixture("biblio_results.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({sort: "callnumber desc"}), output: fixture("callnumbers_before.json"))
stub_solr_get_request(url: "#{@call_number_collection}/select", query: hash_including({fq: 'callnumber:["Thing" TO *]'}), output: fixture("callnumbers_results.json"))
stub_biblio_get_request(url: "biblio/select", query: hash_including({}), output: fixture("biblio_results_middle.json"))
get "/carousel", {query: "Thing"}
expect(last_response.status).to eq(200)
end
end
context "get /-/live" do
it "returns status OK" do
get "/-/live"
Expand Down
Loading

0 comments on commit 02a4a42

Please sign in to comment.