umlaut 3.0.0alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|