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,50 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module SearchHelper
|
4
|
+
|
5
|
+
def search_result_target_window
|
6
|
+
umlaut_config.lookup!("search.result_link_target","")
|
7
|
+
end
|
8
|
+
|
9
|
+
# pass in an openurl context obj.
|
10
|
+
# return an OpenStruct with atitle_label, title_label
|
11
|
+
def referent_labels(context_obj = @current_context_object)
|
12
|
+
ref_meta = context_obj.referent.metadata
|
13
|
+
|
14
|
+
result = OpenStruct.new
|
15
|
+
|
16
|
+
if ref_meta['genre'].blank?
|
17
|
+
case @current_context_object.referent.format
|
18
|
+
when 'book'
|
19
|
+
result.atitle = 'Chapter/Part Title'
|
20
|
+
when @current_context_object.referent.format == 'journal'
|
21
|
+
result.atitle = 'Article Title'
|
22
|
+
end
|
23
|
+
result.title = 'Title'
|
24
|
+
else
|
25
|
+
case ref_meta["genre"]
|
26
|
+
when /article|journal|issue/
|
27
|
+
result.atitle = 'Article Title'
|
28
|
+
result.title = 'Journal Title'
|
29
|
+
when /bookitem|book/
|
30
|
+
result.atitle = 'Chapter/Part Title'
|
31
|
+
result.title = 'Book Title'
|
32
|
+
when /proceeding|conference/
|
33
|
+
result.atitle = 'Proceeding Title'
|
34
|
+
result.title = 'Conference Name'
|
35
|
+
when 'report'
|
36
|
+
result.atitle = 'Report Title'
|
37
|
+
result.title = 'Report'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return result
|
42
|
+
end
|
43
|
+
|
44
|
+
# A-Z buttons in search page
|
45
|
+
def group_list
|
46
|
+
group_list ||= ('A'..'Z').to_a.push('0-9').push('Other')
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Some rails view helpers useful for debugging links, and rendering credits
|
2
|
+
# in footer.
|
3
|
+
module Umlaut::FooterHelper
|
4
|
+
|
5
|
+
# Renders list of external services used by currently configured Umlaut,
|
6
|
+
# with URLs. In some cases ToS of third party services may require this.
|
7
|
+
# Gets list from "credits" config in Service plugins.
|
8
|
+
# Requires @collection ivar in controller holding an umlaut Collection
|
9
|
+
# object, as there will be in ResolveController.
|
10
|
+
def render_service_credits
|
11
|
+
if @collection
|
12
|
+
content = "".html_safe
|
13
|
+
|
14
|
+
content << "Powered by ".html_safe + link_to("Umlaut", "http://github.com/team_umlaut/umlaut") + ". ".html_safe
|
15
|
+
|
16
|
+
credit_segments = []
|
17
|
+
|
18
|
+
services = @collection.instantiate_services!
|
19
|
+
|
20
|
+
# put em all in one hash to eliminate exact-name dups
|
21
|
+
credits = {}
|
22
|
+
services.each {|s| credits.merge! s.credits }
|
23
|
+
|
24
|
+
credits.keys.sort.each do |name|
|
25
|
+
if credits[name].blank?
|
26
|
+
credit_segments << html_escape(name)
|
27
|
+
else
|
28
|
+
credit_segments << link_to(name, credits[name])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
if credit_segments.length > 0
|
34
|
+
content << "Using services from ".html_safe
|
35
|
+
content << credit_segments.join(", ").html_safe
|
36
|
+
content << " and others.".html_safe
|
37
|
+
end
|
38
|
+
|
39
|
+
return content
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# tiny [S] link directly to SFX, in footer. For debugging.
|
44
|
+
# Only if sfx.sfx_base_url is configured.
|
45
|
+
def link_to_direct_sfx
|
46
|
+
if (base = umlaut_config.lookup!("sfx.sfx_base_url")) && @user_request
|
47
|
+
url = base.chomp("?") + "?"
|
48
|
+
url += @user_request.to_context_object.kev
|
49
|
+
url += "&sfx.ignore_date_threshold=1" if respond_to?(:title_level_request) && title_level_request?
|
50
|
+
|
51
|
+
link_to "[S]", url
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# If you have a config.test_resolve_base configured,
|
56
|
+
# will output a [T] link, usually for footer, for staff
|
57
|
+
# debugging.
|
58
|
+
def link_to_test_resolve
|
59
|
+
if (test_base = umlaut_config.lookup!("test_resolve_base")) && @user_request
|
60
|
+
link_to "[T]", test_base.chomp("?") + "?" + @user_request.to_context_object.kev
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Rails view helpers needed accross Umlaut controllers are collected
|
2
|
+
# here. Generally UmlautController will call "helper Umlaut::Helper" to
|
3
|
+
# expose these to all umlaut controllers.
|
4
|
+
|
5
|
+
module Umlaut::Helper
|
6
|
+
include Umlaut::UrlGeneration
|
7
|
+
include Umlaut::FooterHelper
|
8
|
+
include Umlaut::HtmlHeadHelper
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
# pass in an OpenURL::ContextObject, outputs a link.
|
13
|
+
def resolver_link(context_object, params={})
|
14
|
+
|
15
|
+
# Content of the link.
|
16
|
+
if ( umlaut_config.link_img_url && params[:text].blank? )
|
17
|
+
link_content = image_tag(umlaut_config.link_img_url, :border=>0, :alt=>umlaut_config.app_name)
|
18
|
+
elsif ! params[:text].blank?
|
19
|
+
link_content = params[:text]
|
20
|
+
else
|
21
|
+
link_content = umlaut_config.app_name
|
22
|
+
end
|
23
|
+
|
24
|
+
# url of the link.
|
25
|
+
if ( params[:params])
|
26
|
+
link_to_arg = params[:params]
|
27
|
+
else
|
28
|
+
link_params = {:controller=>'resolve'}
|
29
|
+
link_params.merge!( params[:extra_params] ) if params[:extra_params]
|
30
|
+
link_to_arg = url_for_with_co( link_params, context_object )
|
31
|
+
end
|
32
|
+
|
33
|
+
link_to(link_content, link_to_arg , :target=>params[:target])
|
34
|
+
end
|
35
|
+
|
36
|
+
# formats dates sent in an OpenURL into a more human-friendly
|
37
|
+
# format. Input Dates look like '20000304'. Can be just year, or just
|
38
|
+
# year/month, or all. Not sure what this format
|
39
|
+
# is officially called. Not sure if they can have dashes sometimes?
|
40
|
+
def date_format(date_string)
|
41
|
+
date_string =~ /(\d\d\d\d)\-?(\d\d)?\-?(\d\d)?/
|
42
|
+
|
43
|
+
begin
|
44
|
+
year, month, day_of_month = $1, $2, $3
|
45
|
+
|
46
|
+
if ( month )
|
47
|
+
date = Date.civil(year.to_i, month.to_i)
|
48
|
+
formatted_month = date.strftime('%b')
|
49
|
+
end
|
50
|
+
|
51
|
+
output = year
|
52
|
+
output += ' ' + formatted_month if formatted_month
|
53
|
+
output += ' ' + day_of_month if day_of_month && day_of_month.to_i != 0
|
54
|
+
|
55
|
+
return output
|
56
|
+
rescue
|
57
|
+
return date_string
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Rails view helpers for outputting standard Umlaut content included
|
2
|
+
# in html <head>. Generally a layout will call #render_umlaut_head_content
|
3
|
+
# to render all standard Umlaut <head> content in a future-compatible way.
|
4
|
+
module Umlaut::HtmlHeadHelper
|
5
|
+
|
6
|
+
# usually called in layout, render a link tag with opensearch auto-discovery
|
7
|
+
def render_opensearch_link
|
8
|
+
tag("link",
|
9
|
+
:rel => "search",
|
10
|
+
:type => "application/opensearchdescription+xml",
|
11
|
+
:title => umlaut_config.opensearch_short_name,
|
12
|
+
:href => url_for(:controller=>'open_search', :only_path=>false)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
# used on non-js progress page, we need to refresh the page
|
17
|
+
# if requested by presence of @meta_refresh_self ivar.
|
18
|
+
# this method usually called in a layout.
|
19
|
+
def render_meta_refresh
|
20
|
+
if @meta_refresh_self
|
21
|
+
tag( "meta",
|
22
|
+
"http-equiv" => "refresh",
|
23
|
+
"content" => @meta_refresh_self
|
24
|
+
)
|
25
|
+
else
|
26
|
+
""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# standard umlaut head content, may later include more
|
31
|
+
# stuff, local/custom layouts should call this in HEAD
|
32
|
+
# to get forwards-compatible umlaut standard head content
|
33
|
+
def render_umlaut_head_content
|
34
|
+
render_opensearch_link + render_meta_refresh
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# A Rails view helper module, which over-rides #url_for and some other
|
2
|
+
# rails url-generating methods, so that they can be forced to generate
|
3
|
+
# absolute URLs if a controller iVar is set to say so.
|
4
|
+
#
|
5
|
+
# This is used by our partial HTML api responses, so make sure html snippets
|
6
|
+
# have absolute URLs in them.
|
7
|
+
|
8
|
+
module Umlaut::UrlGeneration
|
9
|
+
|
10
|
+
# Over-ride to allow default forcing of urls with hostnames.
|
11
|
+
# This is neccesary for our partial_html_sections service
|
12
|
+
# to work properly. Just set @generate_url_with_host = true
|
13
|
+
# in your controller, and urls will be generated with hostnames
|
14
|
+
# for the remainder of that action.
|
15
|
+
def url_for(argument = {})
|
16
|
+
if @generate_urls_with_host
|
17
|
+
case argument
|
18
|
+
when Hash
|
19
|
+
# Force only_path = false if not already set
|
20
|
+
argument[:only_path] = false if argument[:only_path].nil?
|
21
|
+
return super(argument)
|
22
|
+
when String
|
23
|
+
# We already have a straight string, if it looks relative,
|
24
|
+
# absolutize it.
|
25
|
+
if argument.starts_with?("/")
|
26
|
+
return root_url.chomp("/") + argument
|
27
|
+
else
|
28
|
+
return super(argument)
|
29
|
+
end
|
30
|
+
when :back
|
31
|
+
return super(argument)
|
32
|
+
else
|
33
|
+
# polymorphic, we want to force polymorphic_url instead
|
34
|
+
# of default polymorphic_path
|
35
|
+
return polymorphic_url(argument)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# @generate_urls_with_host not set, just super
|
39
|
+
super(argument)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# over-ride path_to_image to generate complete urls with hostname and everything
|
44
|
+
# if @generate_url_with_host is set. This makes image_tag generate
|
45
|
+
# src with full url with host. See #url_for
|
46
|
+
def path_to_image(source)
|
47
|
+
path = super(source)
|
48
|
+
if @generate_urls_with_host
|
49
|
+
protocol = request.protocol()
|
50
|
+
path = protocol + request.host_with_port() + path
|
51
|
+
end
|
52
|
+
return path
|
53
|
+
end
|
54
|
+
# Rails2 uses 'path_to_image' instead, that's what we have to override,
|
55
|
+
# we used to use image_path, so let's alias that too.
|
56
|
+
alias :image_path :path_to_image
|
57
|
+
|
58
|
+
|
59
|
+
# We want stylesheets and javascripts to do the exact same thing,
|
60
|
+
# magic of polymorphous super() makes it work:
|
61
|
+
def path_to_stylesheet(source)
|
62
|
+
path = super
|
63
|
+
if @generate_urls_with_host
|
64
|
+
path = request.protocol() + request.host_with_port() + path
|
65
|
+
end
|
66
|
+
return path
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_to_javascript(source)
|
70
|
+
path = super
|
71
|
+
if @generate_urls_with_host
|
72
|
+
path = request.protocol() + request.host_with_port() + path
|
73
|
+
end
|
74
|
+
return path
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Emailer < ActionMailer::Base
|
2
|
+
include UmlautConfigurable
|
3
|
+
|
4
|
+
self.umlaut_config = UmlautController.umlaut_config
|
5
|
+
|
6
|
+
helper :application
|
7
|
+
|
8
|
+
|
9
|
+
def citation(recipient, user_request, fulltexts, holdings)
|
10
|
+
@title = find_good_title(user_request.referent)
|
11
|
+
@fulltexts = fulltexts
|
12
|
+
@holdings = holdings
|
13
|
+
@user_request = user_request
|
14
|
+
|
15
|
+
mail(:to => recipient,
|
16
|
+
:from => umlaut_config.from_email_addr,
|
17
|
+
:'Reply-to' => umlaut_config.from_email_addr,
|
18
|
+
:subject => "#{umlaut_config.app_name} result: #{find_good_title(user_request.referent)}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def short_citation(recipient, user_request, location, call_number)
|
22
|
+
|
23
|
+
|
24
|
+
@title = find_good_title(user_request.referent)
|
25
|
+
@location = location
|
26
|
+
@call_number = call_number
|
27
|
+
@user_request = user_request
|
28
|
+
|
29
|
+
mail(:to => recipient,
|
30
|
+
:from => umlaut_config.from_email_addr,
|
31
|
+
:'Reply-to' => umlaut_config.from_email_addr,
|
32
|
+
:subject => "#{umlaut_config.app_name} result")
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def find_good_title(referent)
|
38
|
+
citation = referent.to_citation
|
39
|
+
if citation[:container_title]
|
40
|
+
return citation[:container_title]
|
41
|
+
else
|
42
|
+
return "#{citation[:title]} / #{citation[:author]}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'CronTab' # for understanding CronTab format for expiring responses.
|
2
|
+
|
3
|
+
# A Collection object encapsulates a given UmlautRequest, and a given
|
4
|
+
# list of Umlaut services that should be run off that request.
|
5
|
+
#
|
6
|
+
# That's exactly what it's initialized with: an umlaut request, and
|
7
|
+
# list of service definitions. Third parameter pass in an umlaut configuration
|
8
|
+
# object, to get various timeout values. If you don't pass one in, defaults
|
9
|
+
# will be used.
|
10
|
+
#
|
11
|
+
# The Collection holds and executes the logic for running those services,
|
12
|
+
# foreground and background, making sure no service is run twice if it's
|
13
|
+
# already in progress, timing out expired services, etc.
|
14
|
+
class Collection
|
15
|
+
|
16
|
+
attr_accessor :umlaut_request
|
17
|
+
attr_accessor :logger
|
18
|
+
# configs
|
19
|
+
attr_accessor :response_expire_interval, :response_expire_crontab_format, :background_service_timeout, :requeue_failedtemporary_services
|
20
|
+
|
21
|
+
|
22
|
+
def initialize(a_umlaut_request, service_hash, config = Confstruct::Configuration.new)
|
23
|
+
self.umlaut_request = a_umlaut_request
|
24
|
+
|
25
|
+
self.logger = Rails.logger
|
26
|
+
|
27
|
+
self.response_expire_interval = config.lookup!("response_expire_interval", 1.day)
|
28
|
+
self.response_expire_crontab_format = config.lookup!("response_expire_crontab_format", nil)
|
29
|
+
self.background_service_timeout = config.lookup!("background_service_timeout", 30.seconds)
|
30
|
+
self.requeue_failedtemporary_services = config.lookup!("requeue_failedtemporary_services", 500.seconds)
|
31
|
+
|
32
|
+
# @service_definitions will be a two-level hash, pointing to an array.. Task is Standard, LinkOut, etc.
|
33
|
+
# { [task] => { [priority_level] => [config1, config2, config3],
|
34
|
+
# [priority_level_2] => [configa], }
|
35
|
+
# [...]
|
36
|
+
# }
|
37
|
+
@service_definitions_flat = service_hash
|
38
|
+
@service_definitions = {}
|
39
|
+
|
40
|
+
# Arrange services by type and priority in @service_definitions
|
41
|
+
gather_services
|
42
|
+
end
|
43
|
+
|
44
|
+
# Starts running all services that are in this collection, for the given
|
45
|
+
# request set for this collection, if and only if they are not already
|
46
|
+
# in progress.
|
47
|
+
#
|
48
|
+
# This method can be run on a request multiple times, it'll only re-execute
|
49
|
+
# services that are executable (not already running, or timed out).
|
50
|
+
# That characteristic is used when this method is called on a page refresh
|
51
|
+
# or background update status check.
|
52
|
+
#
|
53
|
+
# Sets all services in collection to have a 'queued' status if appropriate.
|
54
|
+
# Then actually executes the services that are dispatchable (queued).
|
55
|
+
def dispatch_services!
|
56
|
+
# Go through currently dispatched services, looking for timed out
|
57
|
+
# services -- services still in progress that have taken too long,
|
58
|
+
# as well as service responses that are too old to be used.
|
59
|
+
umlaut_request.dispatched_services.each do | ds |
|
60
|
+
# go through dispatched_services and set stil in progress but too long to failed temporary
|
61
|
+
if ( (ds.status == DispatchedService::InProgress ||
|
62
|
+
ds.status == DispatchedService::Queued ) &&
|
63
|
+
(Time.now - ds.updated_at) > self.background_service_timeout)
|
64
|
+
|
65
|
+
ds.store_exception( Exception.new("background service timed out (took longer than #{self.background_service_timeout} to run); thread assumed dead.")) unless ds.exception_info
|
66
|
+
# Fail it temporary, it'll be run again.
|
67
|
+
ds.status = DispatchedService::FailedTemporary
|
68
|
+
ds.save!
|
69
|
+
logger.warn("Background service timed out, thread assumed dead. #{umlaut_request.id} / #{ds.service_id}")
|
70
|
+
end
|
71
|
+
|
72
|
+
# go through dispatched_services and delete:
|
73
|
+
# 1) old completed dispatches, too old to use.
|
74
|
+
# 2) failedtemporary dispatches that are older than our resurrection time
|
75
|
+
# -> And all responses associated with those dispatches.
|
76
|
+
# After being deleted, they'll end up re-queued.
|
77
|
+
if ( (ds.completed? && completed_dispatch_expired?(ds) ) ||
|
78
|
+
( ds.status == DispatchedService::FailedTemporary &&
|
79
|
+
(Time.now - ds.updated_at) > self.requeue_failedtemporary_services
|
80
|
+
)
|
81
|
+
)
|
82
|
+
|
83
|
+
# Need to expire. Delete all the service responses, and
|
84
|
+
# the DispatchedService record, and service will be automatically
|
85
|
+
# run again.
|
86
|
+
serv_id = ds.service_id
|
87
|
+
|
88
|
+
umlaut_request.service_responses.each do |response|
|
89
|
+
if response.service_id == serv_id
|
90
|
+
umlaut_request.service_responses.delete(response)
|
91
|
+
response.destroy
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
umlaut_request.dispatched_services.delete(ds)
|
96
|
+
ds.destroy
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Queue any services without a dispatch marker at all, keeping
|
101
|
+
# track of queued services, already existing or newly created.
|
102
|
+
|
103
|
+
# Just in case, we're going to refetch dispatched_services from the db,
|
104
|
+
# in case some other http request or background service updated things
|
105
|
+
# recently.
|
106
|
+
umlaut_request.dispatched_services.reset
|
107
|
+
|
108
|
+
queued_service_ids = []
|
109
|
+
self.get_service_definitions.each do |service|
|
110
|
+
service_id = service['service_id']
|
111
|
+
# use in-memory #to_a search, don't go to db each time!
|
112
|
+
if found = umlaut_request.dispatched_services.to_a.find {|s| s.service_id == service_id}
|
113
|
+
queued_service_ids.push(service_id) if found.status == DispatchedService::Queued
|
114
|
+
else
|
115
|
+
umlaut_request.new_dispatch_object!(service_id, DispatchedService::Queued).save!
|
116
|
+
queued_service_ids.push(service_id)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
# Now actually dispatch.
|
123
|
+
|
124
|
+
# Foreground services
|
125
|
+
(0..9).each do | priority |
|
126
|
+
services_to_run = self.instantiate_services!(:level => priority, :ids => queued_service_ids)
|
127
|
+
next if services_to_run.empty?
|
128
|
+
ServiceWave.new(services_to_run , priority).handle(umlaut_request, umlaut_request.session_id)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Need to reload the request from db, so it gets changes
|
132
|
+
# made by services in threads.
|
133
|
+
umlaut_request.reload
|
134
|
+
|
135
|
+
# Now we run background services.
|
136
|
+
# Now we do some crazy magic, start a Thread to run our background
|
137
|
+
# services. We are NOT going to wait for this thread to join,
|
138
|
+
# we're going to let it keep doing it's thing in the background after
|
139
|
+
# we return a response to the browser
|
140
|
+
backgroundThread = Thread.new(self, umlaut_request) do | t_collection, t_request|
|
141
|
+
# Tell our AR extension not to allow implicit checkouts
|
142
|
+
ActiveRecord::Base.forbid_implicit_checkout_for_thread! if ActiveRecord::Base.respond_to?("forbid_implicit_checkout_for_thread!")
|
143
|
+
|
144
|
+
# got to reserve an AR connection for our main 'background traffic director'
|
145
|
+
# thread, so it has a connection to use to mark services as failed, at least.
|
146
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
147
|
+
begin
|
148
|
+
# Deal with ruby's brain dead thread scheduling by setting
|
149
|
+
# bg threads to a lower priority so they don't interfere with fg
|
150
|
+
# threads.
|
151
|
+
Thread.current.priority = -1
|
152
|
+
|
153
|
+
('a'..'z').each do | priority |
|
154
|
+
services_to_run = self.instantiate_services!(:level => priority, :ids => queued_service_ids)
|
155
|
+
next if services_to_run.empty?
|
156
|
+
ServiceWave.new(services_to_run , priority).handle(umlaut_request, umlaut_request.session_id)
|
157
|
+
end
|
158
|
+
rescue Exception => e
|
159
|
+
#debugger
|
160
|
+
# We are divorced from any request at this point, not much
|
161
|
+
# we can do except log it. Actually, we'll also store it in the
|
162
|
+
# db, and clean up after any dispatched services that need cleaning up.
|
163
|
+
# If we're catching an exception here, service processing was
|
164
|
+
# probably interrupted, which is bad. You should not intentionally
|
165
|
+
# raise exceptions to be caught here.
|
166
|
+
Thread.current[:exception] = e
|
167
|
+
logger.error("Background Service execution exception1: #{e}\n\n " + clean_backtrace(e).join("\n"))
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
def completed_dispatch_expired?(ds)
|
177
|
+
interval = self.response_expire_interval
|
178
|
+
crontab = self.response_expire_crontab_format
|
179
|
+
now = Time.now
|
180
|
+
|
181
|
+
return nil unless interval || crontab
|
182
|
+
|
183
|
+
expired_interval = interval && (now - ds.created_at > interval)
|
184
|
+
expired_crontab = crontab && (now > CronTab.new(crontab).nexttime(ds.created_at))
|
185
|
+
|
186
|
+
return expired_interval || expired_crontab
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
# Instantiate new copies of services included in this collection, which
|
193
|
+
# services specified by options, can combine:
|
194
|
+
# :task => Service::StandardTask (default) or Service::LinkOutFilterTask
|
195
|
+
# :level => priority level, default to returning services from all.
|
196
|
+
# :ids => list of id's, only those.
|
197
|
+
def instantiate_services!(options ={})
|
198
|
+
get_service_definitions(options).collect do |svc_def|
|
199
|
+
ServiceStore.instantiate_service!(svc_def, umlaut_request)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
# Deprecated, use #instantiate_services! with :task => Service::LinkOutFilter.
|
205
|
+
def link_out_service_level(level)
|
206
|
+
instantiate_services!(:task => Service::LinkOutFilterTask,
|
207
|
+
:level => level)
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
|
212
|
+
# Get service definition hashes for services in this institution.
|
213
|
+
# options, returned in an array.
|
214
|
+
# Does return a mutatable array that Collection mutates
|
215
|
+
# internally, but clients really ought not to mutate.
|
216
|
+
# :task => Service::StandardTask (default) or Service::LinkOutFilterTask
|
217
|
+
# :level => priority level, default to returning services from all.
|
218
|
+
# :ids => list of service unique ids, return only these.
|
219
|
+
def get_service_definitions(options = {})
|
220
|
+
options[:task] ||= Service::StandardTask
|
221
|
+
|
222
|
+
configs_for_task = @service_definitions[ options[:task] ] || {}
|
223
|
+
|
224
|
+
service_configs = case options[:level]
|
225
|
+
when nil
|
226
|
+
# All of of them for this task
|
227
|
+
configs_for_task.values.flatten
|
228
|
+
else
|
229
|
+
configs_for_task[ options[:level] ] || []
|
230
|
+
end
|
231
|
+
if options[:ids]
|
232
|
+
service_configs = service_configs.find_all {|s| options[:ids].include? s["service_id"] }
|
233
|
+
end
|
234
|
+
|
235
|
+
return service_configs
|
236
|
+
end
|
237
|
+
|
238
|
+
protected
|
239
|
+
|
240
|
+
# Arrange services in hash according to task type and priority.
|
241
|
+
def gather_services
|
242
|
+
@service_definitions_flat.each_pair do | unique_id, svc_def |
|
243
|
+
next if svc_def.nil?
|
244
|
+
|
245
|
+
svc_def['service_id'] = unique_id
|
246
|
+
task = svc_def['task'] || Service::StandardTask
|
247
|
+
level = svc_def['priority'] || 3
|
248
|
+
|
249
|
+
@service_definitions[task] ||= {}
|
250
|
+
@service_definitions[task][level] ||= []
|
251
|
+
@service_definitions[task][level] << svc_def
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
end
|