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,86 @@
|
|
1
|
+
# Talks to the ISBNDb (isbndb.com) to get pricing info and links to pricing
|
2
|
+
# info for online sellers. There are potentially other services we could
|
3
|
+
# make use of there in the future too.
|
4
|
+
#
|
5
|
+
# jrochkind talked to the operators of isbndb and got a very high traffic limit
|
6
|
+
# (instead of the default free 500 requests/day), for free. You could try the
|
7
|
+
# same.
|
8
|
+
#
|
9
|
+
# config params in services.yml:
|
10
|
+
#
|
11
|
+
# access_key: Your API access key from isbnDB.
|
12
|
+
# display_text: (Optional) name of link.
|
13
|
+
# timeout: (Optional) seconds to wait for response
|
14
|
+
# display_name: (Optional) what to call the service in display
|
15
|
+
class IsbnDb < Service
|
16
|
+
require 'nokogiri'
|
17
|
+
|
18
|
+
required_config_params :access_key
|
19
|
+
|
20
|
+
def service_types_generated
|
21
|
+
return [ServiceTypeValue['highlighted_link']]
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(config)
|
25
|
+
@timeout = 7
|
26
|
+
@display_text = "Compare online prices"
|
27
|
+
@display_name = "ISBNdb.com"
|
28
|
+
|
29
|
+
@credits = {
|
30
|
+
"ISBNdb" => "http://isbndb.com/"
|
31
|
+
}
|
32
|
+
|
33
|
+
super(config)
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle(umlaut_request)
|
37
|
+
|
38
|
+
isbn = umlaut_request.referent.metadata['isbn']
|
39
|
+
|
40
|
+
# No isbn, nothing we can do.
|
41
|
+
return umlaut_request.dispatched(self, true) if isbn.blank?
|
42
|
+
|
43
|
+
response = do_request(isbn)
|
44
|
+
xml = Nokogiri::XML( response.body )
|
45
|
+
book_xml = xml.at('ISBNdb/BookList/BookData')
|
46
|
+
|
47
|
+
# No hits?
|
48
|
+
return umlaut_request.dispatched(self, true) if book_xml.blank?
|
49
|
+
|
50
|
+
prices_link = get_prices_link( book_xml )
|
51
|
+
|
52
|
+
umlaut_request.add_service_response(
|
53
|
+
:service=>self,
|
54
|
+
:url=> prices_link,
|
55
|
+
:display_text=> @display_text,
|
56
|
+
:service_type_value => ServiceTypeValue[:highlighted_link]
|
57
|
+
)
|
58
|
+
|
59
|
+
return umlaut_request.dispatched(self, true)
|
60
|
+
end
|
61
|
+
|
62
|
+
def do_request(isbn)
|
63
|
+
host = "isbndb.com"
|
64
|
+
# including results=details will prime isbndb to refresh pricing, Andrew tells me.
|
65
|
+
path = "/api/books.xml?access_key=#{@access_key}&results=details,prices&index1=isbn&value1=#{isbn}"
|
66
|
+
|
67
|
+
http = Net::HTTP.new( host )
|
68
|
+
http.open_timeout = @timeout
|
69
|
+
http.read_timeout = @timeout
|
70
|
+
|
71
|
+
response = http.get( path )
|
72
|
+
# raise if not 200 OK response
|
73
|
+
response.value
|
74
|
+
|
75
|
+
return response
|
76
|
+
end
|
77
|
+
|
78
|
+
# Pass in nokogiri object representing the <BookData> element.
|
79
|
+
# passes back string url of isbndb prices/availability page
|
80
|
+
def get_prices_link( book_data )
|
81
|
+
book_id = book_data.attributes['book_id']
|
82
|
+
|
83
|
+
return (book_id) ? "http://isbndb.com/d/book/#{book_id}/prices.html" : nil
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Uses ISI Web of Knowledge to generates links to "cited by" and "similar"
|
4
|
+
# articles.
|
5
|
+
#
|
6
|
+
# REQUIREMENTS: You must be an ISI customer if you want these links to actually
|
7
|
+
# work for your users. Off-campus users should be sent through EZProxy, see
|
8
|
+
# the EZProxy plug-in.
|
9
|
+
#
|
10
|
+
# You need to register for the the Thomson 'Links Article Match Retrieval'
|
11
|
+
# (LAMR) service api, which is used here. To register, see:
|
12
|
+
# http://isiwebofknowledge.com/products_tools/products/related/trlinks/.
|
13
|
+
#
|
14
|
+
# You register by IP address, so no API key is needed once your registration
|
15
|
+
# goes through.
|
16
|
+
#
|
17
|
+
# If you later need to change the IP addresses entitled to use this API, use
|
18
|
+
# http://scientific.thomson.com/scientific/techsupport/cpe/form.html.
|
19
|
+
# to request a change.
|
20
|
+
#
|
21
|
+
# Note, as of 13 april 09, there's a bug in ISI where journal titles including
|
22
|
+
# ampersands cause an error. We will catch those errors and output a 'warning'
|
23
|
+
# instead of an 'error', since it's a known problem.
|
24
|
+
class Isi < Service
|
25
|
+
require 'open-uri'
|
26
|
+
require 'nokogiri'
|
27
|
+
require 'net/http'
|
28
|
+
require 'builder'
|
29
|
+
|
30
|
+
include MetadataHelper
|
31
|
+
|
32
|
+
|
33
|
+
def service_types_generated
|
34
|
+
return [ServiceTypeValue[:cited_by]]
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(config)
|
38
|
+
#defaults
|
39
|
+
@wos_app_name = "Umlaut"
|
40
|
+
@display_name = "Web of Knowledge\xc2\xae" # trademark symbol
|
41
|
+
@api_url = "https://ws.isiknowledge.com/cps/xrpc"
|
42
|
+
@include_cited_by = true
|
43
|
+
@include_similar = true
|
44
|
+
|
45
|
+
@credits = {
|
46
|
+
@display_name => "http://apps.webofknowledge.com"
|
47
|
+
}
|
48
|
+
|
49
|
+
super(config)
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle(request)
|
53
|
+
|
54
|
+
unless ( sufficient_metadata?(request.referent))
|
55
|
+
return request.dispatched(self, true)
|
56
|
+
end
|
57
|
+
|
58
|
+
xml = gen_lamr_request(request)
|
59
|
+
|
60
|
+
isi_response = do_lamr_request(xml)
|
61
|
+
|
62
|
+
|
63
|
+
begin
|
64
|
+
add_responses( request, isi_response )
|
65
|
+
rescue IsiResponseException => e
|
66
|
+
# Is this the known problem with ampersands?
|
67
|
+
# if so, output a warning, but report success not exception,
|
68
|
+
# because this is a known condition.
|
69
|
+
metadata = request.referent.metadata
|
70
|
+
if ( (metadata["title"] && metadata["title"].include?('&')) ||
|
71
|
+
(metadata["jtitle"] && metadata['jtitle'].include?('&')))
|
72
|
+
Rails.logger.warn("ISI LAMR still exhibiting ampersand problems: #{e.message} ; OpenURL: ?#{request.to_context_object.kev}")
|
73
|
+
return request.dispatched(self, true)
|
74
|
+
else
|
75
|
+
# Log the error, return exception condition.
|
76
|
+
Rails.logger.error("#{e.message} ; OpenURL: ?#{request.to_context_object.kev}")
|
77
|
+
return request.dispatched(self, false, e)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
return request.dispatched(self, true)
|
82
|
+
end
|
83
|
+
|
84
|
+
# A DOI is always sufficient. Otherwise, it gets complicated because the ISI
|
85
|
+
# service is kind of picky in weird ways. ISSN alone is not enough, we need
|
86
|
+
# jtitle. Once you have jtitle, Vol/issue/start page are often enough, but
|
87
|
+
# article title really helps, and jtitle+atitle+year is often enough too.
|
88
|
+
def sufficient_metadata?(referent)
|
89
|
+
metadata = referent.metadata
|
90
|
+
return get_doi(referent) || get_pmid(referent) ||
|
91
|
+
( ( metadata['jtitle'] ||
|
92
|
+
metadata['title'] ) &&
|
93
|
+
(! (metadata['atitle'].blank? ||
|
94
|
+
metadata['date'].blank?
|
95
|
+
) ||
|
96
|
+
! ( metadata['volume'].blank? || metadata['issue'].blank? ||
|
97
|
+
metadata['spage'].blank?))
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
# produces XML to be posted to Thomson 'Links Article Match Retrieval' service api.
|
102
|
+
def gen_lamr_request(request)
|
103
|
+
output = ""
|
104
|
+
|
105
|
+
builder = Builder::XmlMarkup.new(:target => output, :indent => 2)
|
106
|
+
builder.instruct!(:xml, :encoding => "UTF-8")
|
107
|
+
|
108
|
+
builder.request(:xmlns => "http://www.isinet.com/xrpc41", :src => "app.id=Umlaut") do
|
109
|
+
builder.fn(:name => "LinksAMR.retrieve") do
|
110
|
+
builder.list do
|
111
|
+
# first map is authentication info. empty 'map' element since we are IP authenticated.
|
112
|
+
builder.map
|
113
|
+
# specify what we're requesting
|
114
|
+
builder.map do
|
115
|
+
builder.list(:name=>"WOS") do
|
116
|
+
builder.val("timesCited")
|
117
|
+
builder.val("ut")
|
118
|
+
builder.val("doi")
|
119
|
+
builder.val("sourceURL")
|
120
|
+
builder.val("citingArticlesURL")
|
121
|
+
builder.val("relatedRecordsURL")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
# specify our query
|
125
|
+
builder.map do
|
126
|
+
builder.map(:name => "cite_id") do
|
127
|
+
# Here's the tricky part, depends on what we've got.
|
128
|
+
metadata = request.referent.metadata
|
129
|
+
|
130
|
+
# DOI
|
131
|
+
if ( doi = get_doi(request.referent))
|
132
|
+
builder.val(doi, :name => "doi")
|
133
|
+
end
|
134
|
+
|
135
|
+
if ( pmid = get_pmid(request.referent))
|
136
|
+
builder.val(pmid, :name => "pmid")
|
137
|
+
end
|
138
|
+
|
139
|
+
# Journal title is crucial for ISI -- ISSN alone is
|
140
|
+
# not enough, weirdly!
|
141
|
+
if ( ! metadata['jtitle'].blank? )
|
142
|
+
builder.val(metadata['jtitle'], :name => "stitle" )
|
143
|
+
else
|
144
|
+
builder.val(metadata['title'], :name => 'stitle' )
|
145
|
+
end
|
146
|
+
|
147
|
+
# ISSN, not actually used much by ISI, but can't hurt.
|
148
|
+
if ( issn = request.referent.issn )
|
149
|
+
# ISSN _needs_ a hyphen for WoS, bah!
|
150
|
+
unless issn.match( /\-/ )
|
151
|
+
issn = issn[0,4] + '-' + issn[4,7]
|
152
|
+
end
|
153
|
+
builder.val(issn, :name => "issn")
|
154
|
+
end
|
155
|
+
|
156
|
+
# article title often helpful.
|
157
|
+
unless ( metadata['atitle'].blank?)
|
158
|
+
builder.val( metadata['atitle'], :name => "atitle")
|
159
|
+
end
|
160
|
+
# year
|
161
|
+
unless ( metadata['date'].blank?)
|
162
|
+
#first four digits are year
|
163
|
+
builder.val( metadata["date"][0,4], :name => "year" )
|
164
|
+
end
|
165
|
+
|
166
|
+
# Vol/issue/page. Oddly, issue isn't used very strongly
|
167
|
+
# by ISI, but can't hurt.
|
168
|
+
unless ( metadata['volume'].blank? )
|
169
|
+
builder.val(metadata['volume'], :name => 'vol')
|
170
|
+
end
|
171
|
+
unless ( metadata['issue'].blank? )
|
172
|
+
builder.val( metadata['issue'] , :name => 'issue')
|
173
|
+
end
|
174
|
+
unless ( metadata['spage'].blank? )
|
175
|
+
builder.val(metadata['spage'], :name => 'spage ')
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
return output
|
184
|
+
end
|
185
|
+
|
186
|
+
def do_lamr_request(xml)
|
187
|
+
uri = URI.parse(@api_url)
|
188
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
189
|
+
http.use_ssl = true if (uri.scheme == 'https')
|
190
|
+
|
191
|
+
headers = {'Content-Type' => 'application/xml'}
|
192
|
+
|
193
|
+
return http.post(uri.request_uri, xml, headers)
|
194
|
+
end
|
195
|
+
|
196
|
+
def add_responses(request, isi_response)
|
197
|
+
#raise if it's an error HTTP response
|
198
|
+
isi_response.value
|
199
|
+
|
200
|
+
response_xml = Nokogiri::XML(isi_response.body)
|
201
|
+
|
202
|
+
# Check for errors.
|
203
|
+
if (error = (response_xml.at('val[@name = "error"]') || response_xml.at("error") || response_xml.at('null[@name = "error"]')))
|
204
|
+
raise IsiResponseException.new("ISI service reported error: #{error.inner_text}")
|
205
|
+
end
|
206
|
+
|
207
|
+
results = response_xml.at('map[@name ="cite_id"] map[@name="WOS"]')
|
208
|
+
unless (results)
|
209
|
+
error_message = "#{self.id}: "
|
210
|
+
error_message << 'Unexpected ISI response. The ISI response was not reported as an error, but did not contain a <map name="WOS"> inside a <map name="cite_id"> as we expected it to:'
|
211
|
+
error_message << "\n ISI XML request:\n#{gen_lamr_request(request)}\n"
|
212
|
+
error_message << "\n ISI http response status: #{isi_response.code}\n"
|
213
|
+
error_message << "\n ISI http response body:\n#{isi_response.body}\n"
|
214
|
+
Rails.logger.error(error_message)
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# cited by
|
219
|
+
count = results.at('val[@name="timesCited"]')
|
220
|
+
count = count ? count.inner_text.to_i : 0
|
221
|
+
|
222
|
+
cited_by_url = results.at('val[@name="citingArticlesURL"]')
|
223
|
+
cited_by_url = cited_by_url.inner_text if cited_by_url
|
224
|
+
|
225
|
+
if (@include_cited_by && count > 0 && cited_by_url )
|
226
|
+
label = ServiceTypeValue[:cited_by].display_name_pluralize.downcase.capitalize
|
227
|
+
if count && count == 1
|
228
|
+
label = ServiceTypeValue[:cited_by].display_name.downcase.capitalize
|
229
|
+
end
|
230
|
+
|
231
|
+
request.add_service_response(:service=>self,
|
232
|
+
:display_text => "#{count} #{label}",
|
233
|
+
:count=> count,
|
234
|
+
:url => cited_by_url,
|
235
|
+
:debug_info => "url: " + cited_by_url,
|
236
|
+
:service_type_value => :cited_by)
|
237
|
+
end
|
238
|
+
|
239
|
+
# similar
|
240
|
+
|
241
|
+
similar_url = results.at('val[@name ="relatedRecordsURL"]')
|
242
|
+
similar_url = similar_url.inner_text if similar_url
|
243
|
+
|
244
|
+
if (@include_similar && similar_url )
|
245
|
+
request.add_service_response( :service=>self,
|
246
|
+
:display_text => " #{ServiceTypeValue[:similar].display_name_pluralize.downcase.capitalize}",
|
247
|
+
:url => similar_url,
|
248
|
+
:debug_info => "url: " + similar_url,
|
249
|
+
:service_type_value => :similar)
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
class IsiResponseException < StandardError
|
257
|
+
|
258
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Link to Thomson JCR impact report for journal title.
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# REQUIREMENTS: You must be an ISI customer if you want these links to actually
|
7
|
+
# work for your users. Off-campus users should be sent through EZProxy, see
|
8
|
+
# the EZProxy plug-in.
|
9
|
+
#
|
10
|
+
# You need to register for the the Thomson 'Links Article Match Retrieval'
|
11
|
+
# (LAMR) service api, which is used here (and also in the Isi plugin). To
|
12
|
+
# register, see:
|
13
|
+
# http://isiwebofknowledge.com/products_tools/products/related/trlinks/.
|
14
|
+
#
|
15
|
+
# You register by IP address, so no API key is needed once your registration
|
16
|
+
# goes through.
|
17
|
+
#
|
18
|
+
# If you later need to change the IP addresses entitled to use this API, use
|
19
|
+
# http://scientific.thomson.com/scientific/techsupport/cpe/form.html.
|
20
|
+
# to request a change.
|
21
|
+
class Jcr < Service
|
22
|
+
require 'open-uri'
|
23
|
+
require 'nokogiri'
|
24
|
+
require 'net/http'
|
25
|
+
require 'builder'
|
26
|
+
|
27
|
+
include MetadataHelper
|
28
|
+
|
29
|
+
|
30
|
+
def service_types_generated
|
31
|
+
return [ServiceTypeValue[:highlighted_link]]
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(config)
|
35
|
+
#defaults
|
36
|
+
@wos_app_name = "Umlaut"
|
37
|
+
@display_name = "Journal Citation Reports\xc2\xae" # trademark symbol, utf-8
|
38
|
+
@link_text = "Journal impact factor"
|
39
|
+
@api_url = "https://ws.isiknowledge.com/cps/xrpc"
|
40
|
+
@include_for_article_level = true
|
41
|
+
|
42
|
+
@credits = {
|
43
|
+
@display_name => "http://thomsonreuters.com/products_services/science/science_products/a-z/journal_citation_reports/"
|
44
|
+
}
|
45
|
+
|
46
|
+
super(config)
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle(request)
|
50
|
+
|
51
|
+
unless ( sufficient_metadata?(request.referent))
|
52
|
+
return request.dispatched(self, true)
|
53
|
+
end
|
54
|
+
|
55
|
+
xml = gen_lamr_request(request)
|
56
|
+
|
57
|
+
isi_response = do_lamr_request(xml)
|
58
|
+
|
59
|
+
add_responses( request, isi_response )
|
60
|
+
|
61
|
+
return request.dispatched(self, true)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Need an ISSN.
|
65
|
+
def sufficient_metadata?(referent)
|
66
|
+
return ! referent.issn.blank?
|
67
|
+
end
|
68
|
+
|
69
|
+
# produces XML to be posted to Thomson 'Links Article Match Retrieval' service api.
|
70
|
+
def gen_lamr_request(request)
|
71
|
+
output = ""
|
72
|
+
|
73
|
+
builder = Builder::XmlMarkup.new(:target => output, :indent => 2)
|
74
|
+
builder.instruct!(:xml, :encoding => "UTF-8")
|
75
|
+
|
76
|
+
builder.request(:xmlns => "http://www.isinet.com/xrpc41", :src => "app.id=Umlaut") do
|
77
|
+
builder.fn(:name => "LinksAMR.retrieve") do
|
78
|
+
builder.list do
|
79
|
+
# first map is authentication info. empty 'map' element since we are IP authenticated.
|
80
|
+
builder.map
|
81
|
+
# specify what we're requesting
|
82
|
+
builder.map do
|
83
|
+
builder.list(:name=>"JCR") do
|
84
|
+
builder.val("impactGraphURL")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
# specify our query
|
88
|
+
builder.map do
|
89
|
+
builder.map(:name => "cite_id") do
|
90
|
+
metadata = request.referent.metadata
|
91
|
+
if (issn = request.referent.issn)
|
92
|
+
issn = issn[0,4] + '-' + issn[4,7] unless issn =~ /\-/
|
93
|
+
builder.val(issn, :name => "issn")
|
94
|
+
end
|
95
|
+
# Journal title.
|
96
|
+
if (! metadata['jtitle'].blank? )
|
97
|
+
builder.val(metadata['jtitle'], :name => "stitle" )
|
98
|
+
elsif (! metadata['title'].blank? )
|
99
|
+
builder.val(metadata['title'], :name => 'stitle' )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return output
|
107
|
+
end
|
108
|
+
|
109
|
+
def do_lamr_request(xml)
|
110
|
+
uri = URI.parse(@api_url)
|
111
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
112
|
+
http.use_ssl = true if (uri.scheme == 'https')
|
113
|
+
|
114
|
+
headers = {'Content-Type' => 'application/xml'}
|
115
|
+
|
116
|
+
return http.post(uri.request_uri, xml, headers)
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_responses(request, isi_response)
|
120
|
+
# raise if it's an HTTP error code
|
121
|
+
isi_response.value
|
122
|
+
|
123
|
+
nokogiri = Nokogiri::XML(isi_response.body)
|
124
|
+
|
125
|
+
# Check for errors.
|
126
|
+
if (error = (nokogiri.at('val[@name = "error"]') || nokogiri.at('error') || nokogiri.at('null[@name = "error"]')))
|
127
|
+
raise Exception.new("Third party service error: #{error.inner_text}")
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
results = nokogiri.at('map[@name ="cite_id"] map[@name="JCR"]')
|
132
|
+
|
133
|
+
impact_url = results.at('val[@name ="impactGraphURL"]')
|
134
|
+
|
135
|
+
if (impact_url )
|
136
|
+
request.add_service_response(:service=>self,
|
137
|
+
:display_text => @link_text,
|
138
|
+
:url => impact_url.inner_text,
|
139
|
+
:service_type_value => :highlighted_link,
|
140
|
+
:debug_info => "url: #{impact_url.inner_text}")
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|