umlaut 3.0.0alpha1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -0
- data/README.md +49 -0
- data/Rakefile +37 -0
- data/app/assets/images/error.gif +0 -0
- data/app/assets/images/export_bg_bot.gif +0 -0
- data/app/assets/images/export_bg_mid.gif +0 -0
- data/app/assets/images/export_bg_top.gif +0 -0
- data/app/assets/images/famfamfam/book_open.png +0 -0
- data/app/assets/images/famfamfam/cross.png +0 -0
- data/app/assets/images/famfamfam/page_sound.gif +0 -0
- data/app/assets/images/famfamfam/page_text.gif +0 -0
- data/app/assets/images/famfamfam/page_up.gif +0 -0
- data/app/assets/images/famfamfam/page_white.png +0 -0
- data/app/assets/images/famfamfam/readme.html +1495 -0
- data/app/assets/images/famfamfam/tiny_cross.png +0 -0
- data/app/assets/images/frame_remove.gif +0 -0
- data/app/assets/images/ico_go.gif +0 -0
- data/app/assets/images/jhu_findit.gif +0 -0
- data/app/assets/images/list_closed.png +0 -0
- data/app/assets/images/list_open.png +0 -0
- data/app/assets/images/more_info.gif +0 -0
- data/app/assets/images/rails.png +0 -0
- data/app/assets/images/request.gif +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/javascripts/umlaut/ajax_windows.js +35 -0
- data/app/assets/javascripts/umlaut/ensure_window_size.js.erb +34 -0
- data/app/assets/javascripts/umlaut/expand_contract_toggle.js +25 -0
- data/app/assets/javascripts/umlaut/search_autocomplete.js +46 -0
- data/app/assets/javascripts/umlaut/simple_visible_toggle.js +8 -0
- data/app/assets/javascripts/umlaut/update_html.js +152 -0
- data/app/assets/javascripts/umlaut.js +17 -0
- data/app/assets/stylesheets/umlaut.css +857 -0
- data/app/controllers/application_controller.rb +14 -0
- data/app/controllers/export_email_controller.rb +123 -0
- data/app/controllers/js_helper_controller.rb +10 -0
- data/app/controllers/link_router_controller.rb +87 -0
- data/app/controllers/open_search_controller.rb +9 -0
- data/app/controllers/resolve_controller.rb +288 -0
- data/app/controllers/resource_controller.rb +83 -0
- data/app/controllers/search_controller.rb +328 -0
- data/app/controllers/search_methods/sfx3.rb +148 -0
- data/app/controllers/search_methods/sfx4.rb +257 -0
- data/app/controllers/search_methods/sfx_api.rb +47 -0
- data/app/controllers/store_controller.rb +64 -0
- data/app/controllers/umlaut/controller_behavior.rb +20 -0
- data/app/controllers/umlaut/controller_logic.rb +96 -0
- data/app/controllers/umlaut/error_handling.rb +48 -0
- data/app/controllers/umlaut_controller.rb +112 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/emailer_helper.rb +43 -0
- data/app/helpers/export_email_helper.rb +34 -0
- data/app/helpers/open_search_helper.rb +7 -0
- data/app/helpers/resolve_helper.rb +225 -0
- data/app/helpers/search_helper.rb +50 -0
- data/app/helpers/umlaut/footer_helper.rb +64 -0
- data/app/helpers/umlaut/helper.rb +62 -0
- data/app/helpers/umlaut/html_head_helper.rb +37 -0
- data/app/helpers/umlaut/url_generation.rb +77 -0
- data/app/mailers/emailer.rb +48 -0
- data/app/models/clickthrough.rb +2 -0
- data/app/models/collection.rb +259 -0
- data/app/models/crossref_lookup.rb +2 -0
- data/app/models/dispatched_service.rb +58 -0
- data/app/models/permalink.rb +29 -0
- data/app/models/referent.rb +473 -0
- data/app/models/referent_value.rb +14 -0
- data/app/models/request.rb +449 -0
- data/app/models/service_response.rb +179 -0
- data/app/models/service_store.rb +59 -0
- data/app/models/service_type_value.rb +58 -0
- data/app/models/service_wave.rb +150 -0
- data/app/models/sfx_db/az_additional_title.rb +11 -0
- data/app/models/sfx_db/az_letter_group.rb +11 -0
- data/app/models/sfx_db/az_title.rb +38 -0
- data/app/models/sfx_db/az_title_v2.rb +34 -0
- data/app/models/sfx_db/isbn.rb +12 -0
- data/app/models/sfx_db/issn.rb +12 -0
- data/app/models/sfx_db/object.rb +35 -0
- data/app/models/sfx_db/object_portfolio.rb +6 -0
- data/app/models/sfx_db/publisher.rb +10 -0
- data/app/models/sfx_db/sfx_db_base.rb +54 -0
- data/app/models/sfx_db/target.rb +9 -0
- data/app/models/sfx_db/target_service.rb +10 -0
- data/app/models/sfx_db/title.rb +10 -0
- data/app/models/sfx_db.rb +10 -0
- data/app/models/sfx_url.rb +35 -0
- data/app/views/emailer/citation.text.erb +28 -0
- data/app/views/emailer/short_citation.text.erb +8 -0
- data/app/views/export_email/_email.html.erb +25 -0
- data/app/views/export_email/_send_email.html.erb +3 -0
- data/app/views/export_email/_send_txt.html.erb +3 -0
- data/app/views/export_email/_txt.html.erb +62 -0
- data/app/views/export_email/email.html.erb +3 -0
- data/app/views/export_email/send_email.html.erb +1 -0
- data/app/views/export_email/send_txt.html.erb +1 -0
- data/app/views/export_email/txt.html.erb +3 -0
- data/app/views/js_helper/loader.erb.js +13 -0
- data/app/views/layouts/umlaut.html.erb +52 -0
- data/app/views/open_search/index.html.erb +9 -0
- data/app/views/resolve/_api_in_progress.xml.erb +21 -0
- data/app/views/resolve/_background_progress.html.erb +51 -0
- data/app/views/resolve/_background_updater.html.erb +38 -0
- data/app/views/resolve/_citation.html.erb +87 -0
- data/app/views/resolve/_coins.html.erb +1 -0
- data/app/views/resolve/_compact_citation.html.erb +33 -0
- data/app/views/resolve/_cover_image.html.erb +35 -0
- data/app/views/resolve/_fulltext.html.erb +55 -0
- data/app/views/resolve/_help.html.erb +17 -0
- data/app/views/resolve/_holding.html.erb +91 -0
- data/app/views/resolve/_related_items.html.erb +35 -0
- data/app/views/resolve/_search_inside.html.erb +62 -0
- data/app/views/resolve/_section_display.html.erb +49 -0
- data/app/views/resolve/_service_errors.html.erb +29 -0
- data/app/views/resolve/_standard_response_item.html.erb +89 -0
- data/app/views/resolve/api.xml.builder +72 -0
- data/app/views/resolve/background_status.html.erb +26 -0
- data/app/views/resolve/index.html.erb +73 -0
- data/app/views/resolve/partial_html_sections.xml.erb +30 -0
- data/app/views/search/_a_to_z.html.erb +6 -0
- data/app/views/search/_citation.html.erb +94 -0
- data/app/views/search/_pager.html.erb +60 -0
- data/app/views/search/books.html.erb +103 -0
- data/app/views/search/journal_search.html.erb +90 -0
- data/app/views/search/journals.html.erb +167 -0
- data/app/views/search/opensearch_description.rxml +10 -0
- data/app/views/testing/index.html.erb +1 -0
- data/app/views/umlaut/README +5 -0
- data/app/views/umlaut/error.html.erb +45 -0
- data/db/migrate/01_umlaut_init.rb +113 -0
- data/db/orig_fixed_data/service_type_values.yml +120 -0
- data/db/seeds.rb +7 -0
- data/lib/CronTab.rb +192 -0
- data/lib/aws_product_sign.rb +146 -0
- data/lib/exlibris/aleph/patron.rb +64 -0
- data/lib/exlibris/aleph/record.rb +54 -0
- data/lib/exlibris/aleph/rest_api.rb +29 -0
- data/lib/exlibris/primo/holding.rb +192 -0
- data/lib/exlibris/primo/rsrc.rb +17 -0
- data/lib/exlibris/primo/searcher.rb +276 -0
- data/lib/exlibris/primo/source/aleph.rb +46 -0
- data/lib/exlibris/primo/source/distribution/nyu_aleph.rb +323 -0
- data/lib/exlibris/primo/toc.rb +17 -0
- data/lib/exlibris/primo_ws.rb +140 -0
- data/lib/generators/templates/umlaut_services.yml +237 -0
- data/lib/generators/umlaut/asset_hooks_generator.rb +44 -0
- data/lib/generators/umlaut/install_generator.rb +110 -0
- data/lib/hip3/bib.rb +291 -0
- data/lib/hip3/bib_searcher.rb +302 -0
- data/lib/hip3/custom_field_lookup.rb +44 -0
- data/lib/hip3/holding.rb +50 -0
- data/lib/hip3/item.rb +65 -0
- data/lib/hip3/receipt.rb +7 -0
- data/lib/hip3/serial_copy.rb +82 -0
- data/lib/holding.rb +32 -0
- data/lib/marc_helper.rb +254 -0
- data/lib/metadata_helper.rb +312 -0
- data/lib/opensearch_feed.rb +398 -0
- data/lib/opensearch_query.rb +98 -0
- data/lib/referent_filter.rb +16 -0
- data/lib/referent_filters/dissertation_catch.rb +45 -0
- data/lib/section_renderer.rb +503 -0
- data/lib/service.rb +336 -0
- data/lib/service_adaptors/ajax_export.rb +37 -0
- data/lib/service_adaptors/amazon.rb +412 -0
- data/lib/service_adaptors/blacklight.rb +327 -0
- data/lib/service_adaptors/book_finder.rb +40 -0
- data/lib/service_adaptors/bx.rb +51 -0
- data/lib/service_adaptors/cover_thing.rb +73 -0
- data/lib/service_adaptors/elsevier_cover.rb +57 -0
- data/lib/service_adaptors/email_export.rb +10 -0
- data/lib/service_adaptors/ezproxy.rb +171 -0
- data/lib/service_adaptors/google_book_search.rb +442 -0
- data/lib/service_adaptors/gpo.rb +124 -0
- data/lib/service_adaptors/hathi_trust.rb +308 -0
- data/lib/service_adaptors/hip3_service.rb +150 -0
- data/lib/service_adaptors/hip_holding_search.rb +237 -0
- data/lib/service_adaptors/internet_archive.rb +488 -0
- data/lib/service_adaptors/isbn_db.rb +86 -0
- data/lib/service_adaptors/isi.rb +258 -0
- data/lib/service_adaptors/jcr.rb +146 -0
- data/lib/service_adaptors/opac.rb +351 -0
- data/lib/service_adaptors/open_library.rb +316 -0
- data/lib/service_adaptors/open_library_cover.rb +73 -0
- data/lib/service_adaptors/primo_service.rb +392 -0
- data/lib/service_adaptors/primo_source.rb +78 -0
- data/lib/service_adaptors/pubmed.rb +133 -0
- data/lib/service_adaptors/request_to_fixture.rb +68 -0
- data/lib/service_adaptors/scopus.rb +295 -0
- data/lib/service_adaptors/sfx-new.rb +557 -0
- data/lib/service_adaptors/sfx.rb +566 -0
- data/lib/service_adaptors/sfx_backchannel_record.rb +69 -0
- data/lib/service_adaptors/txt_holding_export.rb +32 -0
- data/lib/service_adaptors/ulrichs_cover.rb +57 -0
- data/lib/service_adaptors/ulrichs_link.rb +47 -0
- data/lib/service_adaptors/worldcat.rb +116 -0
- data/lib/service_adaptors/worldcat_identities.rb +591 -0
- data/lib/tasks/umlaut.rake +134 -0
- data/lib/umlaut/default_configuration.rb +5 -0
- data/lib/umlaut/routes.rb +136 -0
- data/lib/umlaut/version.rb +3 -0
- data/lib/umlaut.rb +37 -0
- data/lib/umlaut_configurable.rb +343 -0
- data/lib/umlaut_http.rb +100 -0
- data/lib/xml_schema_helper.rb +109 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/umlaut_controller.rb +112 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database-jhu.yml +44 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +34 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +61 -0
- data/test/dummy/config/umlaut_services.yml +237 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20111228211210_umlaut_init.rb +113 -0
- data/test/dummy/db/schema.rb +124 -0
- data/test/dummy/log/development.log +12981 -0
- data/test/dummy/log/production.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C5F/340/sprockets%2F99692920160b7a279b86a80415b79db7 +0 -0
- data/test/dummy/tmp/cache/assets/C70/4D0/sprockets%2F034ad2036e623081bd352800786dfe80 +0 -0
- data/test/dummy/tmp/cache/assets/C73/920/sprockets%2Fd371318f22900492fd180f17c5e2a504 +9268 -0
- data/test/dummy/tmp/cache/assets/C80/980/sprockets%2Fc94807409c1523d43e18d25f35d93c41 +0 -0
- data/test/dummy/tmp/cache/assets/C8F/780/sprockets%2Fe47e28558116fb5f8038754e60d1961d +11769 -0
- data/test/dummy/tmp/cache/assets/CAA/EB0/sprockets%2F1d179210e8b76f1ea63c802688a015e4 +9271 -0
- data/test/dummy/tmp/cache/assets/CBB/9C0/sprockets%2F706f28923fb754cad04b9107c89986a1 +0 -0
- data/test/dummy/tmp/cache/assets/CBF/B60/sprockets%2F08ca89671549936265dcb673bf02e36f +0 -0
- data/test/dummy/tmp/cache/assets/CC9/9F0/sprockets%2F306166316e2cafd13c15e62b51a2339d +0 -0
- data/test/dummy/tmp/cache/assets/CF6/F20/sprockets%2F5b2ffa1103079dfd555197838f87a99f +0 -0
- data/test/dummy/tmp/cache/assets/CF7/2B0/sprockets%2F25a7c73655bd3598173b39d9f98bcd46 +862 -0
- data/test/dummy/tmp/cache/assets/CFE/080/sprockets%2F37fe9f4255baddbd549a659914929398 +0 -0
- data/test/dummy/tmp/cache/assets/D22/060/sprockets%2F9aec77b768e91a802d284271c58e2f7e +21357 -0
- data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/D33/6D0/sprockets%2F500129c57f1146e556ec3aacd6cd38c1 +0 -0
- data/test/dummy/tmp/cache/assets/D33/FD0/sprockets%2F2ba0b4e6334a77b923e5f770381bb2bf +0 -0
- data/test/dummy/tmp/cache/assets/D42/C20/sprockets%2Fbcf14e437b1582bf93b77670acf8e090 +21353 -0
- data/test/dummy/tmp/cache/assets/D50/A30/sprockets%2F7d8b294ac433db5d056538f8cf7c66b9 +0 -0
- data/test/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +872 -0
- data/test/dummy/tmp/cache/assets/D65/590/sprockets%2Fc1bb92fc3406a126b7dd302edc96d629 +0 -0
- data/test/dummy/tmp/cache/assets/D71/6B0/sprockets%2Fde558b71b494cf09b1bf055c8dff0353 +0 -0
- data/test/dummy/tmp/cache/assets/D72/610/sprockets%2Fa8c708eeb30ef93de34d755d4f45d023 +859 -0
- data/test/dummy/tmp/cache/assets/D76/AD0/sprockets%2Fe2158cde93188cf5ab6457bc6d6602ec +0 -0
- data/test/dummy/tmp/cache/assets/D7A/E40/sprockets%2F9622ffcc499a57627cd1bb18fe31b8e4 +11772 -0
- data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +0 -0
- data/test/dummy/tmp/cache/assets/D9B/770/sprockets%2F8aacf02eb7dbb0949704b28f27b87e0b +0 -0
- data/test/dummy/tmp/cache/assets/DA6/A80/sprockets%2F92e26d8e58d5bcc8b8f6c25d1b05b9c1 +0 -0
- data/test/dummy/tmp/cache/assets/DE8/790/sprockets%2Fd1333bde2b9aafcc712d11dd09ab35d8 +0 -0
- data/test/dummy/tmp/cache/assets/DF7/F30/sprockets%2F7bc16c4109b17fabe29f8ddbbf732d1c +374 -0
- data/test/dummy/tmp/cache/assets/E03/570/sprockets%2F493bdc0ac14cd4f57fdfe4253f992bde +0 -0
- data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/E0B/4B0/sprockets%2F7988df51a61c81ce6ede4a2d4c8cce4f +377 -0
- data/test/dummy/tmp/cache/assets/E5F/960/sprockets%2Fdc007b6cad5c7ef08e33ec28cfff0ef6 +0 -0
- data/test/fixtures/dispatched_services.yml +5 -0
- data/test/fixtures/permalinks.yml +5 -0
- data/test/fixtures/referent_values.yml +1734 -0
- data/test/fixtures/referents.yml +156 -0
- data/test/fixtures/requests.yml +284 -0
- data/test/fixtures/service_responses.yml +5 -0
- data/test/fixtures/sfx_urls.yml +4 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +10 -0
- data/test/umlaut_test.rb +7 -0
- data/test/unit/aleph_patron_test.rb +39 -0
- data/test/unit/aleph_record_benchmarks.rb +28 -0
- data/test/unit/aleph_record_test.rb +30 -0
- data/test/unit/aws_product_sign_test.rb +93 -0
- data/test/unit/collection_test.rb +76 -0
- data/test/unit/google_book_search_test.rb +101 -0
- data/test/unit/primo_searcher_test.rb +403 -0
- data/test/unit/primo_service_test.rb +939 -0
- data/test/unit/primo_ws_test.rb +131 -0
- data/test/unit/service_response_test.rb +9 -0
- data/test/unit/service_test.rb +33 -0
- metadata +580 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
# We proxy cover images from foreign sources through Umlaut sometimes, in order
|
2
|
+
# to switch their access from http to https to avoid browser warnings on an
|
3
|
+
# https page. This controller does that.
|
4
|
+
#
|
5
|
+
# It does NOT take URL in request parameters, but instead takes a response ID.
|
6
|
+
# it will only proxy urls already stored in umlaut responses, so this is not
|
7
|
+
# an open proxy with the security problems that would cause.
|
8
|
+
class ResourceController < UmlautController
|
9
|
+
require 'open-uri'
|
10
|
+
|
11
|
+
# We really ought to _stream_ the remote response to our client, but I
|
12
|
+
# couldn't get that to work how I wanted in Rails2. Even using
|
13
|
+
# render :text=>proc, problem is we needed to know the content-type before
|
14
|
+
# we read any of the response, which we didn't. This implementation holds
|
15
|
+
# the whole image in memory for a second while it delivers it, oh well.
|
16
|
+
# doesn't seem to effect speed much, even though it's not optimal.
|
17
|
+
def proxy
|
18
|
+
svc_type = ServiceType.find(params[:id])
|
19
|
+
url_str = svc_type.view_data[:url]
|
20
|
+
uri = nil
|
21
|
+
begin
|
22
|
+
uri = URI(url_str)
|
23
|
+
rescue
|
24
|
+
raise Exception.new("resource#proxy can only handle String urls, not '#{url.inspect}'")
|
25
|
+
end
|
26
|
+
|
27
|
+
proxied_headers = proxy_headers( request, uri.host )
|
28
|
+
remote_response = open(uri, 'rb', proxied_headers)
|
29
|
+
|
30
|
+
# copy certain headers to our proxied response
|
31
|
+
["content-type", "cache-control", "expires", "content-length", "last-modified", "etag", "date"].each do |key|
|
32
|
+
response.headers[key] = remote_response.meta[key]
|
33
|
+
end
|
34
|
+
response.headers["X-Original-Url"] = url_str
|
35
|
+
|
36
|
+
# And send the actual result out
|
37
|
+
render(:text => remote_response.read)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
# Generate headers as if we are a proxy server, to be more or less honest
|
44
|
+
# and to maybe keep Google et al from rate throttling us.
|
45
|
+
# This is kind of copy and paste of UmlautHttp#proxy_like_headers, but that
|
46
|
+
# method was written to require an UmlautRequest, which we don't have here.
|
47
|
+
# TODO should refactor to DRY.
|
48
|
+
# Argument here is a Rails Request
|
49
|
+
def proxy_headers( request, host )
|
50
|
+
orig_env = request.headers
|
51
|
+
|
52
|
+
header = {}
|
53
|
+
|
54
|
+
|
55
|
+
header["User-Agent"] = orig_env['HTTP_USER_AGENT'] || 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0'
|
56
|
+
header['Accept'] = orig_env['HTTP_ACCEPT'] || 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
57
|
+
header['Accept-Language'] = orig_env['HTTP_ACCEPT_LANGUAGE'] || 'en-us,en;q=0.5'
|
58
|
+
header['Accept-Encoding'] = orig_env['HTTP_ACCEPT_ENCODING'] || ''
|
59
|
+
header["Accept-Charset"] = orig_env['HTTP_ACCEPT_CHARSET'] || 'UTF-8,*'
|
60
|
+
|
61
|
+
# Set referrer to be, well, an Umlaut page, like the one we are
|
62
|
+
# currently generating would be best. That is, the resolve link.
|
63
|
+
|
64
|
+
header["Referer"] = "http://#{orig_env['HTTP_HOST']}#{orig_env['REQUEST_URI']}"
|
65
|
+
|
66
|
+
# Proxy X-Forwarded headers.
|
67
|
+
|
68
|
+
# The original Client's ip, most important and honest. Look for
|
69
|
+
# and add on to any existing x-forwarded-for, if neccesary, as per
|
70
|
+
# x-forwarded-for convention.
|
71
|
+
header['X-Forwarded-For'] = (orig_env['HTTP_X_FORWARDED_FOR']) ?
|
72
|
+
(orig_env['HTTP_X_FORWARDED_FOR'].to_s + ', ' + request.remote_ip.to_s) :
|
73
|
+
request.remote_ip.to_s
|
74
|
+
|
75
|
+
#Theoretically the original host requested by the client in the Host HTTP request header. We're disembling a bit.
|
76
|
+
header['X-Forwarded-Host'] = host if host
|
77
|
+
# The proxy server: That is, Umlaut, us.
|
78
|
+
header['X-Forwarded-Server'] = orig_env['SERVER_NAME'] || ''
|
79
|
+
|
80
|
+
return header
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
# The search controller handles searches fo manually entered citations,
|
2
|
+
# or possibly ambiguous citations generally. It also provides an A-Z list.
|
3
|
+
#
|
4
|
+
# As a source of this data, it generally talks to the SFX database directly.
|
5
|
+
# The particular method it uses to get this data is defined in a SearchMethod
|
6
|
+
# module (app/controllers/search_methods), that gets applied to the controller.
|
7
|
+
# Currently Sfx3 direct database or Sfx4 direct database are supported. In
|
8
|
+
# either case with database connection info in your database.yml file under
|
9
|
+
# sfx_db.
|
10
|
+
#
|
11
|
+
# Future plans include a local database of titles, perhaps loaded from an
|
12
|
+
# external KB. Not done yet.
|
13
|
+
#
|
14
|
+
# = SearchMethod module implementation
|
15
|
+
# A search method is just a ruby module, that will be applied to a controller,
|
16
|
+
# that defines two methods:
|
17
|
+
# [#find_by_title]
|
18
|
+
# Takes no arguments, instead use methods in the controller like
|
19
|
+
# #sfx_az_profile, #title_query_param, #search_type_param, #batch_size and
|
20
|
+
# #page to return state. Returns a two-element array pair, first element
|
21
|
+
# is a list of OpenURL::ContextObject for current batch, send element
|
22
|
+
# is int total hit count.
|
23
|
+
# [#find_by_group]
|
24
|
+
# Used for clicks on "A", "B" ... "0-9", "Other" links. Find the group
|
25
|
+
# link clicked on in params[:id]. Use #batch_size and #page for paging.
|
26
|
+
# As in #find_by_title, return two element array, first elememt is array
|
27
|
+
# of OpenURL::ContextObject, second element is total hit count.
|
28
|
+
class SearchController < UmlautController
|
29
|
+
@@search_batch_size = 20
|
30
|
+
@@az_batch_size = 20
|
31
|
+
@@autocomplete_limit = 15
|
32
|
+
|
33
|
+
layout umlaut_config.search_layout, :except => [ :opensearch, :opensearch_description ]
|
34
|
+
|
35
|
+
before_filter :normalize_params
|
36
|
+
|
37
|
+
def initialize(*params)
|
38
|
+
super(*params)
|
39
|
+
|
40
|
+
self.extend( search_method_module )
|
41
|
+
end
|
42
|
+
|
43
|
+
def index
|
44
|
+
@page_title = "Journals"
|
45
|
+
journals()
|
46
|
+
end
|
47
|
+
|
48
|
+
def journals
|
49
|
+
@submit_hash = params["umlaut.display_coins"] ? {:controller=>'resolve', :action=>'display_coins'} : {:controller=>'search', :action=>'journal_search'}
|
50
|
+
|
51
|
+
# Render configed view, if configed, or default
|
52
|
+
render umlaut_config.lookup!("search_view", "journals")
|
53
|
+
end
|
54
|
+
|
55
|
+
# Not sure if this action actually works or does anything at present.
|
56
|
+
def books
|
57
|
+
@submit_action = params["umlaut.display_coins"] ? "display_coins" : "index"
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# @display_results is left as an array of ContextObject objects.
|
62
|
+
# Or, redirect to resolve action for single hit.
|
63
|
+
# O hit also redirects to resolve action, as per SFX behavior--this
|
64
|
+
# gives a catalog lookup and an ILL form for 0-hit.
|
65
|
+
# param umlaut.title_search_type (aka sfx.title_search)
|
66
|
+
# can be 'begins', 'exact', or 'contains'. Other
|
67
|
+
# form params should be OpenURL, generally
|
68
|
+
def journal_search
|
69
|
+
@batch_size = batch_size
|
70
|
+
@start_result_num = (page * batch_size) - (batch_size - 1)
|
71
|
+
|
72
|
+
@search_context_object = context_object_from_params
|
73
|
+
|
74
|
+
if (! params["rft.object_id"].blank? ||
|
75
|
+
! params["rft.issn"].blank? ||
|
76
|
+
! params["rft_id"].blank? )
|
77
|
+
# If we have an exact-type 'search', just switch to 'resolve' action
|
78
|
+
redirect_to url_for_with_co( {:controller => 'resolve'}, context_object_from_params )
|
79
|
+
|
80
|
+
# don't do anything else.
|
81
|
+
return
|
82
|
+
elsif (params['rft.jtitle'].blank?)
|
83
|
+
#Bad, error condition. If we don't have any of that other stuff above,
|
84
|
+
# we need a title! Send them back to entry page with an error message.
|
85
|
+
flash[:error] = "You must enter a journal title or other identifying information."
|
86
|
+
redirect_to :controller=>:search, :action=>:index
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
# Call our particular search method, #find_by_title added by search
|
93
|
+
# method module.
|
94
|
+
(@display_results, @hits) = self.find_by_title
|
95
|
+
#find_by_title_via_sfx_db
|
96
|
+
|
97
|
+
# Calculate end-result number for display
|
98
|
+
@end_result_num = @start_result_num + batch_size - 1
|
99
|
+
if @end_result_num > @hits
|
100
|
+
@end_result_num = @hits
|
101
|
+
end
|
102
|
+
|
103
|
+
if (@page == 1) && (@display_results.length == 1)
|
104
|
+
# If we narrowed down to one result redirect
|
105
|
+
# to resolve action.
|
106
|
+
redirect_to( url_for_with_co({:controller => 'resolve'}, @display_results[0]) )
|
107
|
+
elsif (@display_results.length == 0)
|
108
|
+
# 0 hits, do it too.
|
109
|
+
redirect_to( url_for_with_co({:controller => 'resolve'}, @search_context_object) )
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Used for browse-by-letter
|
116
|
+
def journal_list
|
117
|
+
@batch_size = batch_size
|
118
|
+
@page = page
|
119
|
+
@start_result_num = (@page * @batch_size) - (@batch_size - 1)
|
120
|
+
|
121
|
+
|
122
|
+
(@display_results, @hits) = find_by_group
|
123
|
+
|
124
|
+
|
125
|
+
# Calculate end-result number for display
|
126
|
+
@end_result_num = @start_result_num + @batch_size - 1
|
127
|
+
if @end_result_num > @hits
|
128
|
+
@end_result_num = @hits
|
129
|
+
end
|
130
|
+
|
131
|
+
# Use our ordinary search displayer to display
|
132
|
+
# It'll notice the action and do just a bit of special stuff.
|
133
|
+
render(:template => "search/journal_search")
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
# Should return an array of hashes, with each has having :title and :object_id
|
141
|
+
# keys. Can come from local journal index or SFX or somewhere else.
|
142
|
+
# :object_id is the SFX rft.object_id, and can be blank. (I think it's SFX
|
143
|
+
# rft.object_id for local journal index too)
|
144
|
+
def auto_complete_for_journal_title
|
145
|
+
# Don't search on blank query.
|
146
|
+
query = params['rft.jtitle']
|
147
|
+
search_type = params["umlaut.title_search_type"] || "contains"
|
148
|
+
unless ( query.blank? )
|
149
|
+
(context_objects, total_count) = find_by_title
|
150
|
+
@titles = context_objects.collect do |co|
|
151
|
+
metadata = co.referent.metadata
|
152
|
+
{:object_id => metadata["object_id"], :title => (metadata["jtitle"] || metadata["btitle"] || metadata["title"])}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
render :text => @titles.to_json, :content_type => "application/json"
|
156
|
+
end
|
157
|
+
|
158
|
+
def opensearch_description
|
159
|
+
@headers['Content-Type'] = 'application/opensearchdescription+xml'
|
160
|
+
end
|
161
|
+
|
162
|
+
protected
|
163
|
+
|
164
|
+
def normalize_params
|
165
|
+
# citation search params
|
166
|
+
|
167
|
+
# sfx.title_search and umlaut.title_search_type are synonyms
|
168
|
+
params["sfx.title_search"] = params["umlaut.title_search_type"] if params["sfx.title_search"].blank?
|
169
|
+
params["umlaut.title_search_type"] = params["sfx.title_search"] if params["umlaut.title_search_type"].blank?
|
170
|
+
|
171
|
+
# Likewise, params[:journal][:title] is legacy params['rft.jtitle']
|
172
|
+
unless (params[:journal].blank? || params[:journal][:title].blank? ||
|
173
|
+
! params['rft.jtitle'].blank? )
|
174
|
+
params['rft.jtitle'] = params[:journal][:title]
|
175
|
+
end
|
176
|
+
|
177
|
+
if ( (params[:journal].blank? || params[:journal][:title].blank?) &&
|
178
|
+
params['rft.jtitle'] )
|
179
|
+
params[:journal] ||= {}
|
180
|
+
params[:journal][:title] = params['rft.jtitle']
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
# Grab identifiers out of the way we've encoded em
|
185
|
+
# Accept legacy SFX-style encodings too
|
186
|
+
if ( ! params['rft_id_value'].blank? ||
|
187
|
+
! params['pmid_value'].blank? ||
|
188
|
+
! params['doi_value'].blank? )
|
189
|
+
|
190
|
+
if (! params['rft_id_value'].blank?)
|
191
|
+
id_type = params['rft_id_type'] || 'doi'
|
192
|
+
id_value = params['rft_id_value']
|
193
|
+
elsif (! params['pmid_value'].blank?)
|
194
|
+
id_type = params['pmid_id'] || 'pmid'
|
195
|
+
id_value = params['pmid_value']
|
196
|
+
else # sfx-style doi
|
197
|
+
id_type = params['doi_id'] || 'doi'
|
198
|
+
id_value = params['doi_value']
|
199
|
+
end
|
200
|
+
|
201
|
+
params['rft_id'] = "info:#{id_type}/#{id_value}"
|
202
|
+
end
|
203
|
+
|
204
|
+
# SFX v2 A-Z list url format---convert to Umlaut
|
205
|
+
if params[:letter_group]
|
206
|
+
params[:id] = case params[:letter_group].to_i
|
207
|
+
when 1 then '0-9'
|
208
|
+
# 2-27 mean A-Z, convert via ASCII value arithmetic.
|
209
|
+
when 2..27 then ((params[:letter_group].to_i) +63 ).chr
|
210
|
+
when 28 then 'Others'
|
211
|
+
end
|
212
|
+
params.delete(:letter_group) if params[:id]
|
213
|
+
end
|
214
|
+
|
215
|
+
# SFX v3 A-Z list url format--convert to Umlaut
|
216
|
+
if params[:param_letter_group_value]
|
217
|
+
params[:id] = case params[:param_letter_group_value]
|
218
|
+
when /^0/ then '0-9'
|
219
|
+
when 'Others' then 'Other'
|
220
|
+
else params[:param_letter_group_value]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Normalize request for 'Others'
|
225
|
+
if params[:id] =~ /^other/i
|
226
|
+
params[:id] = 'Others'
|
227
|
+
end
|
228
|
+
|
229
|
+
# for reasons I can't tell, our JS on IE ends up putting some
|
230
|
+
# newlines in the object_id, which messes us all up.
|
231
|
+
params['rft.object_id'].strip! if params['rft.object_id']
|
232
|
+
|
233
|
+
## If needed combine date elements to an OpenURL date
|
234
|
+
unless (params["__year"].blank? &&
|
235
|
+
params["__month"].blank? &&
|
236
|
+
params["__day"].blank?)
|
237
|
+
isoDate = ""
|
238
|
+
unless ["", "****", "Year"].include?(params["__year"])
|
239
|
+
isoDate += params["__year"]
|
240
|
+
unless ["", "***", "Month"].include?(params["__month"])
|
241
|
+
isoDate += "-" + params["__month"]
|
242
|
+
unless ["", "**", "Day"].include?(params["__day"])
|
243
|
+
isoDate += "-" + params["__day"]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
unless isoDate.blank?
|
248
|
+
params["date"] = isoDate
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
def context_object_from_params
|
255
|
+
@context_object_from_params ||=
|
256
|
+
begin
|
257
|
+
params_c = params.clone
|
258
|
+
|
259
|
+
# Take out the weird ones that aren't really part of the OpenURL
|
260
|
+
ignored_keys = [:journal, "utf8", "__year", "__month", "__day", "action", "controller", "Generate_OpenURL2", "rft_id_type", "rft_id_value"]
|
261
|
+
ignored_keys.each { |k| params_c.delete(k) }
|
262
|
+
|
263
|
+
# Normalize ISSN to have dash
|
264
|
+
if ( ! params['rft.issn'].blank? && params['rft.issn'][4,1] != '-' && params['rft.issn'].length >= 4)
|
265
|
+
params['rft.issn'].insert(4,'-')
|
266
|
+
end
|
267
|
+
|
268
|
+
ctx = OpenURL::ContextObject.new
|
269
|
+
# Make sure it uses a journal type referent please, that's what we've
|
270
|
+
# got here.
|
271
|
+
ctx.referent = OpenURL::ContextObjectEntity.new_from_format( 'info:ofi/fmt:xml:xsd:journal' )
|
272
|
+
ctx.import_hash( params_c )
|
273
|
+
|
274
|
+
# Not sure where ":rft_id_value" as opposed to 'rft_id' comes from, but
|
275
|
+
# it was in old code. We do it after CO creation to handle multiple
|
276
|
+
# identifiers
|
277
|
+
if (! params_c[:rft_id_value].blank?)
|
278
|
+
ctx.referent.add_identifier( params_c[:rft_id_value] )
|
279
|
+
end
|
280
|
+
ctx
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def search_method_module
|
285
|
+
umlaut_config.lookup!("az_search_method", SearchMethods::Sfx4)
|
286
|
+
end
|
287
|
+
|
288
|
+
# sfx a-z profile as defined in config, used for direct db connections
|
289
|
+
# to sfx.
|
290
|
+
def sfx_az_profile
|
291
|
+
umlaut_config.lookup!("sfx_az_profile", "default")
|
292
|
+
end
|
293
|
+
helper_method :sfx_az_profile
|
294
|
+
|
295
|
+
def title_query_param
|
296
|
+
params['rft.jtitle']
|
297
|
+
end
|
298
|
+
helper_method :title_query_param
|
299
|
+
|
300
|
+
def search_type_param
|
301
|
+
params['umlaut.title_search_type'] || 'contains'
|
302
|
+
end
|
303
|
+
helper_method :search_type_param
|
304
|
+
|
305
|
+
def batch_size
|
306
|
+
case params[:action]
|
307
|
+
when "journal_list"
|
308
|
+
@@az_batch_size
|
309
|
+
when "auto_complete_for_journal_title"
|
310
|
+
@@autocomplete_limit
|
311
|
+
else
|
312
|
+
@@search_batch_size
|
313
|
+
end
|
314
|
+
end
|
315
|
+
helper_method :batch_size
|
316
|
+
|
317
|
+
def page
|
318
|
+
@page ||= params['page'].blank? ? 1 : params['page'].to_i
|
319
|
+
end
|
320
|
+
helper_method :page
|
321
|
+
|
322
|
+
|
323
|
+
|
324
|
+
|
325
|
+
|
326
|
+
|
327
|
+
|
328
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module SearchMethods
|
2
|
+
module Sfx3
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
#returns pair of 1) array of context object results for current page, 2) hit count
|
7
|
+
def find_by_title
|
8
|
+
(object_ids, hit_count) = object_ids_az_v3(title_query_param, search_type_param, batch_size, page )
|
9
|
+
|
10
|
+
# Now fetch objects with publication information
|
11
|
+
# Sometimes SFX db lacks referential integrity, so we don't count
|
12
|
+
# on these object_ids actually being there, doing a find all instead
|
13
|
+
# of just a 'find'.
|
14
|
+
sfx_objects = SfxDb::Object.find( :all, :conditions => {:OBJECT_ID => object_ids},
|
15
|
+
:include => [:publishers, :main_titles, :primary_issns, :primary_isbns])
|
16
|
+
|
17
|
+
# We got the right set of @batch_size objects, but they're not sorted
|
18
|
+
# by title.
|
19
|
+
# Too hard to include the sort in the SQL, let's re-sort in memory
|
20
|
+
sfx_objects.sort! do |a,b|
|
21
|
+
if (a.main_titles.first && b.main_titles.first)
|
22
|
+
a.main_titles.first.TITLE_DISPLAY <=> b.main_titles.first.TITLE_DISPLAY
|
23
|
+
else
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Now we need to convert to ContextObjects.
|
29
|
+
context_objects = sfx_objects.collect do |sfx_obj|
|
30
|
+
ctx = OpenURL::ContextObject.new
|
31
|
+
# Start out with everything in the search, to preserve date/vol info
|
32
|
+
ctx.import_context_object( context_object_from_params )
|
33
|
+
|
34
|
+
# Put SFX object id in rft.object_id, that's what SFX does.
|
35
|
+
ctx.referent.set_metadata('object_id', sfx_obj.id.to_s)
|
36
|
+
|
37
|
+
publisher_obj = sfx_obj.publishers.first
|
38
|
+
if ( publisher_obj )
|
39
|
+
ctx.referent.set_metadata('pub', publisher_obj.PUBLISHER_DISPLAY)
|
40
|
+
ctx.referent.set_metadata('place', publisher_obj.PLACE_OF_PUBLICATION_DISPLAY)
|
41
|
+
end
|
42
|
+
|
43
|
+
title_obj = sfx_obj.main_titles.first
|
44
|
+
title = title_obj ? title_obj.TITLE_DISPLAY : "Unknown Title"
|
45
|
+
ctx.referent.set_metadata('jtitle', title)
|
46
|
+
|
47
|
+
issn_obj = sfx_obj.primary_issns.first
|
48
|
+
ctx.referent.set_metadata('issn', issn_obj.ISSN_ID) if issn_obj
|
49
|
+
|
50
|
+
isbn_obj = sfx_obj.primary_isbns.first
|
51
|
+
ctx.referent.set_metadata('isbn', isbn_obj.ISBN_ID) if isbn_obj
|
52
|
+
|
53
|
+
ctx
|
54
|
+
end
|
55
|
+
return [context_objects, hit_count]
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
# Object Ids from SFX A-Z list 'version 3'. The A-Z v3 title list
|
61
|
+
# is cranky, so we have a v2 version too.
|
62
|
+
# input title query, search_type
|
63
|
+
# Returns an array [ batch_obj_id_array, count ].
|
64
|
+
def object_ids_az_v3(title_q, search_type, batch_size, page)
|
65
|
+
# MySQL 'like' is case-insensitive, fortunately, don't need to worry
|
66
|
+
# about that. But to deal with non-filing chars, need to search against
|
67
|
+
# TITLE_DISPLAY and TITLE_SORT for begins with. We're going to join
|
68
|
+
# to AZ_TITLE_SEARCH_VER3 for alternate titles too.
|
69
|
+
conditions = case search_type
|
70
|
+
when 'contains'
|
71
|
+
['ts.AZ_PROFILE = ? AND TITLE_DISPLAY like ? OR ts.TITLE_SEARCH like ?',
|
72
|
+
sfx_az_profile,
|
73
|
+
"%" + title_q.upcase + "%", "%" + title_q.upcase + "%"]
|
74
|
+
when 'begins'
|
75
|
+
['ts.AZ_PROFILE = ? AND TITLE_DISPLAY like ? OR TITLE_SORT like ? OR ts.TITLE_SEARCH like ?',
|
76
|
+
sfx_az_profile,
|
77
|
+
title_q + '%', title_q + '%', title_q + "%"]
|
78
|
+
else # exact
|
79
|
+
['ts.AZ_PROFILE = ? AND TITLE_DISPLAY = ? OR TITLE_SORT = ? OR ts.TITLE_SEARCH = ?',
|
80
|
+
sfx_az_profile,
|
81
|
+
title_q, title_q, title_q]
|
82
|
+
end
|
83
|
+
|
84
|
+
# First get object_ids we're interested in, then
|
85
|
+
# we'll bulk fetch with all their data.
|
86
|
+
# Tricky-ass query for efficiency and power, sorry.
|
87
|
+
joins = "left outer join AZ_TITLE_SEARCH_VER3 as ts on `AZ_TITLE_VER3`.AZ_TITLE_VER3_ID = ts.AZ_TITLE_VER3_ID"
|
88
|
+
|
89
|
+
|
90
|
+
# Actually, _first_ we'll do a total count.
|
91
|
+
total_hits = SfxDb::AzTitle.count(:OBJECT_ID,
|
92
|
+
:distinct=>true,
|
93
|
+
:conditions=>conditions,
|
94
|
+
:joins=>joins,
|
95
|
+
:order=>'TITLE_SORT ASC')
|
96
|
+
|
97
|
+
# Now fetch object_ids for just the display batch
|
98
|
+
object_ids = SfxDb::AzTitle.find(:all, :select=>"distinct (OBJECT_ID)",
|
99
|
+
:conditions => conditions,
|
100
|
+
:joins => joins,
|
101
|
+
:limit => batch_size,
|
102
|
+
:offset => batch_size * (page - 1),
|
103
|
+
:order=>'TITLE_SORT ASC').collect { |title_obj| title_obj.OBJECT_ID}
|
104
|
+
|
105
|
+
|
106
|
+
return [ object_ids, total_hits]
|
107
|
+
end
|
108
|
+
|
109
|
+
# params[:id] will have a capital letter, or "0-9" or "Other"
|
110
|
+
def find_by_group
|
111
|
+
|
112
|
+
joins = " inner join AZ_LETTER_GROUP_VER3 as lg on AZ_TITLE_VER3.AZ_TITLE_VER3_ID = lg.AZ_TITLE_VER3_ID"
|
113
|
+
# Need a special condition for 0-9
|
114
|
+
if ( params[:id] == '0-9')
|
115
|
+
conditions = ["AZ_PROFILE=? AND lg.AZ_LETTER_GROUP_VER3_NAME IN ('0','1','2','3','4','5','6','7','8','9')",
|
116
|
+
sfx_az_profile]
|
117
|
+
else
|
118
|
+
conditions = ["AZ_PROFILE=? AND lg.AZ_LETTER_GROUP_VER3_NAME = ?",
|
119
|
+
sfx_az_profile,
|
120
|
+
params[:id].upcase]
|
121
|
+
end
|
122
|
+
|
123
|
+
hits = SfxDb::AzTitle.count(:joins => joins,
|
124
|
+
:conditions => conditions)
|
125
|
+
|
126
|
+
|
127
|
+
# Sorry this find is so crazy, trying to manage to do it
|
128
|
+
# efficiently and get what we need in large SFX db.
|
129
|
+
# For crazy nested include below, see:
|
130
|
+
# http://snippets.dzone.com/posts/show/2089
|
131
|
+
az_titles = SfxDb::AzTitle.find(:all,
|
132
|
+
:joins => joins,
|
133
|
+
:conditions => conditions,
|
134
|
+
:limit => batch_size,
|
135
|
+
:offset=> batch_size * (page - 1),
|
136
|
+
:order=>'TITLE_SORT',
|
137
|
+
:include=>[{:object => [:publishers, :titles] }])
|
138
|
+
|
139
|
+
# Convert to context objects
|
140
|
+
display_results = az_titles.collect do | azt |
|
141
|
+
co = azt.to_context_object
|
142
|
+
co.referrer.add_identifier('info:sid/umlaut.code4lib.org:azlist')
|
143
|
+
co
|
144
|
+
end
|
145
|
+
return [display_results, hits]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|