umlaut 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/README.md +1 -1
  2. data/app/assets/stylesheets/umlaut/_resolve.scss +1 -1
  3. data/app/controllers/feedback_controller.rb +46 -0
  4. data/app/controllers/resource_controller.rb +19 -1
  5. data/app/controllers/search_methods/sfx4.rb +15 -0
  6. data/app/controllers/umlaut_controller.rb +6 -0
  7. data/app/helpers/emailer_helper.rb +17 -3
  8. data/app/mailers/feedback_mailer.rb +25 -0
  9. data/app/mixin_logic/metadata_helper.rb +37 -0
  10. data/app/models/referent.rb +22 -19
  11. data/app/models/request.rb +3 -0
  12. data/app/referent_filters/dissertation_catch.rb +1 -1
  13. data/app/service_adaptors/all_books_dot_com.rb +17 -0
  14. data/app/service_adaptors/illiad.rb +161 -0
  15. data/app/service_adaptors/isbn_db.rb +6 -1
  16. data/app/service_adaptors/isbn_link.rb +57 -0
  17. data/app/service_adaptors/scopus.rb +4 -0
  18. data/app/service_adaptors/scopus2.rb +330 -0
  19. data/app/views/feedback/_resolve_section.html.erb +16 -0
  20. data/app/views/feedback/new.html.erb +33 -0
  21. data/app/views/feedback_mailer/feedback.text.erb +23 -0
  22. data/app/views/layouts/umlaut.html.erb +2 -0
  23. data/app/views/umlaut/_alerts.html.erb +14 -0
  24. data/lib/generators/templates/umlaut_services.yml +8 -8
  25. data/lib/umlaut/routes.rb +8 -1
  26. data/lib/umlaut/version.rb +1 -1
  27. data/test/dummy/tmp/cache/assets/BFF/760/sprockets%2Fe00969069e468419c393709f042b4527 +0 -0
  28. data/test/dummy/tmp/cache/assets/C9D/060/sprockets%2F5c8956a1666824a1d214531abd22e2a2 +0 -0
  29. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  30. data/test/dummy/tmp/cache/assets/D15/FC0/sprockets%2F8cbf3a8b7acb7fc27a42168846226385 +0 -0
  31. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  32. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  33. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  34. data/test/dummy/tmp/cache/assets/D98/990/sprockets%2F710ede3e7f5ebab14e9772fa88c00c02 +0 -0
  35. data/test/dummy/tmp/cache/assets/DAD/BA0/sprockets%2F193f81f7e4eae26eaaa7d909c0c8e956 +0 -0
  36. data/test/dummy/tmp/cache/assets/DCB/620/sprockets%2F2332a294ceeab3ab9b5ee643989dc0eb +0 -0
  37. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  38. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  39. data/test/functional/feedback_controller_test.rb +59 -0
  40. data/test/test_helper.rb +13 -0
  41. data/test/unit/feedback_mailer_test.rb +57 -0
  42. data/test/unit/illiad_test.rb +146 -0
  43. data/test/unit/metadata_helper_test.rb +49 -0
  44. data/test/unit/referent_to_citation_test.rb +45 -0
  45. data/test/unit/scopus2_test.rb +147 -0
  46. data/test/vcr_cassettes/scopus/live_test_with_no_hits.yml +52 -0
  47. data/test/vcr_cassettes/scopus/live_test_with_result.yml +62 -0
  48. data/test/vcr_cassettes/scopus/live_trigger_scopus_error.yml +50 -0
  49. metadata +34 -120
  50. data/test/dummy/tmp/cache/sass/b43409235ed55124ccf6a0235156711682d0fe98/umlaut.css.scssc +0 -0
  51. data/test/dummy/tmp/cache/sass/d2b87393a9fcb33d01e765e1c09b76db7f14f647/bootstrap-responsive.scssc +0 -0
  52. data/test/dummy/tmp/cache/sass/d2b87393a9fcb33d01e765e1c09b76db7f14f647/bootstrap.scssc +0 -0
  53. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_accordion.scssc +0 -0
  54. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_alerts.scssc +0 -0
  55. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_breadcrumbs.scssc +0 -0
  56. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_button-groups.scssc +0 -0
  57. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_buttons.scssc +0 -0
  58. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_carousel.scssc +0 -0
  59. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_close.scssc +0 -0
  60. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_code.scssc +0 -0
  61. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_component-animations.scssc +0 -0
  62. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_dropdowns.scssc +0 -0
  63. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_forms.scssc +0 -0
  64. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_grid.scssc +0 -0
  65. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_hero-unit.scssc +0 -0
  66. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_labels-badges.scssc +0 -0
  67. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_layouts.scssc +0 -0
  68. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_media.scssc +0 -0
  69. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_mixins.scssc +0 -0
  70. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_modals.scssc +0 -0
  71. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_navbar.scssc +0 -0
  72. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_navs.scssc +0 -0
  73. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_pager.scssc +0 -0
  74. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_pagination.scssc +0 -0
  75. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_popovers.scssc +0 -0
  76. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_progress-bars.scssc +0 -0
  77. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_reset.scssc +0 -0
  78. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_responsive-1200px-min.scssc +0 -0
  79. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_responsive-767px-max.scssc +0 -0
  80. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_responsive-768px-979px.scssc +0 -0
  81. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_responsive-navbar.scssc +0 -0
  82. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_responsive-utilities.scssc +0 -0
  83. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_scaffolding.scssc +0 -0
  84. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_sprites.scssc +0 -0
  85. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_tables.scssc +0 -0
  86. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_thumbnails.scssc +0 -0
  87. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_tooltip.scssc +0 -0
  88. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_type.scssc +0 -0
  89. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_utilities.scssc +0 -0
  90. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_variables.scssc +0 -0
  91. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/_wells.scssc +0 -0
  92. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/bootstrap.scssc +0 -0
  93. data/test/dummy/tmp/cache/sass/db21ae7b0d8da2224e8e1d588985ee0507dc926a/responsive.scssc +0 -0
  94. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_admin.scssc +0 -0
  95. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_az.scssc +0 -0
  96. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_forms.scssc +0 -0
  97. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_icons.scssc +0 -0
  98. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_layout.scssc +0 -0
  99. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_misc.scssc +0 -0
  100. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_mixins.scssc +0 -0
  101. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_modal.scssc +0 -0
  102. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_resolve.scssc +0 -0
  103. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_results.scssc +0 -0
  104. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_search.scssc +0 -0
  105. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_spinner.scssc +0 -0
  106. data/test/dummy/tmp/cache/sass/fc140da5c32e19b5c3f84a23bb2383ebc83fcc20/_variables.scssc +0 -0
data/README.md CHANGED
@@ -24,7 +24,7 @@ advertise/recommend to it's users.
24
24
 
25
25
  Umlaut strives to supply links that take the user in as few clicks as possible to the service listed, without ever listing 'blind links' that you first have to click on to find out whether they are available. Umlaut pre-checks things when neccesary to only list services, with any needed contextual info, such that the user knows what they get when they click on it. Save the time of the user.
26
26
 
27
- [What do you mean by all this?](https://github.com/team-umlaut/umlaut/wiki/What-is-Umlaut-anyway)
27
+ [What do you mean by all this?](https://github.com/team-umlaut/umlaut/wiki/What-is-Umlaut-anyway%3F)
28
28
 
29
29
  Umlaut is distributed as a ruby Rails engine gem. It's a very heavyweight engine,
30
30
  the point of distro'ing as a gem is to make it easy to keep local
@@ -141,7 +141,7 @@
141
141
  @extend %indented-subitem;
142
142
  }
143
143
 
144
- .response_edition_warning, .response_source, .response_coverage_statement, .response_notes {
144
+ .edition_warning, .response_source, .response_coverage_statement, .response_notes {
145
145
  @extend %indented-subitem;
146
146
  @extend .muted;
147
147
  }
@@ -0,0 +1,46 @@
1
+ class FeedbackController < UmlautController
2
+ def new
3
+ contact_email_lookup(params[:contact_id])
4
+ # default render
5
+ end
6
+
7
+ def create
8
+ contact_config = contact_email_lookup(params[:contact_id])
9
+ to_address = contact_config[:email_address]
10
+
11
+ options = params.slice(:name, :email, :feedback)
12
+ if params[:request_id] && umlaut_request = Request.find_by_id(params[:request_id])
13
+ options = options.merge(
14
+ :umlaut_request => umlaut_request
15
+ )
16
+ end
17
+
18
+ FeedbackMailer.feedback(request.host_with_port, to_address, options).deliver
19
+
20
+ flash[:alert_success] = "Thanks, your message has been sent."
21
+
22
+ if umlaut_request
23
+ redirect_to :controller => "resolve", :action => :index, "umlaut.request_id" => umlaut_request.id
24
+ else
25
+ redirect_to root_url
26
+ end
27
+ end
28
+
29
+ protected
30
+ def contact_email_lookup(contact_id)
31
+ unless contact_id
32
+ raise NoFeedbackEmailFoundException.new("Missing a contact_id, needed to look up feedback destination email.")
33
+ end
34
+ contact_config = umlaut_config.feedback && umlaut_config.feedback.contacts && umlaut_config.feedback.contacts[contact_id]
35
+
36
+ unless contact_config && contact_config[:email_address]
37
+ raise NoFeedbackEmailFoundException.new("Could not find feedback destination email for contact_id: `#{contact_id}`")
38
+ end
39
+
40
+ return contact_config
41
+ end
42
+
43
+ class NoFeedbackEmailFoundException < ArgumentError
44
+ end
45
+
46
+ end
@@ -7,6 +7,11 @@
7
7
  # an open proxy with the security problems that would cause.
8
8
  class ResourceController < UmlautController
9
9
  require 'open-uri'
10
+ require 'timeout'
11
+
12
+ # seconds to wait for thing were proxying. Yeah, fairly big num seems neccesary
13
+ # for Amazon at least.
14
+ HttpTimeout = 4
10
15
 
11
16
  # We really ought to _stream_ the remote response to our client, but I
12
17
  # couldn't get that to work how I wanted in Rails2. Even using
@@ -25,7 +30,11 @@ class ResourceController < UmlautController
25
30
  end
26
31
 
27
32
  proxied_headers = proxy_headers( request, uri.host )
28
- remote_response = open(uri, 'rb', proxied_headers)
33
+
34
+ # open-uri :read_timeout is not behaving reliably, resort to Timeout.timeout
35
+ # should we just be using raw Net::Http and give up on open-uri? remember
36
+ # to update timeout exceptions in rescue below if you change.
37
+ remote_response = Timeout.timeout(HttpTimeout) { open(uri, 'rb', proxied_headers) }
29
38
 
30
39
  # copy certain headers to our proxied response
31
40
  ["Content-Type", "Cache-Control", "Expires", "Content-Length", "Last-Modified", "Etag", "Date"].each do |key|
@@ -33,10 +42,19 @@ class ResourceController < UmlautController
33
42
  # rack doens't like it if we set a nil value here.
34
43
  response.headers[key] = value unless value.blank?
35
44
  end
45
+
36
46
  response.headers["X-Original-Url"] = url_str
37
47
 
38
48
  # And send the actual result out
39
49
  render(:text => remote_response.read)
50
+ rescue Timeout::Error, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
51
+ msg = "#{e.inspect}: waiting for image proxy from `#{url_str}`; timeout is currently set to #{HttpTimeout}s; returning broken image"
52
+ relevant_backtrace = e.backtrace.find_all {|line| line =~ /umlaut/}
53
+
54
+ logger.warn("#{msg}\n #{relevant_backtrace.join("\n ")}")
55
+
56
+ response.headers['X-Original-Url'] = url_str
57
+ render :text => msg, :status => 504
40
58
  end
41
59
 
42
60
  protected
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'nokogiri'
2
3
  module SearchMethods
3
4
  module Sfx4
@@ -56,6 +57,7 @@ module SearchMethods
56
57
  # than 2 causes false negatives. Otherwise we use it to be consistent
57
58
  # with SFX. This reverse-engineering is full of pitfalls.
58
59
  query = terms.collect do |term|
60
+ term = replace_problem_tokens(term)
59
61
  "+" + connection.quote_string(term) + (term.length > 2 ? "*" : "")
60
62
  end.join(" ")
61
63
  "MATCH (TS.TITLE_SEARCH) AGAINST ('#{query}' IN BOOLEAN MODE)"
@@ -132,6 +134,19 @@ module SearchMethods
132
134
  return [context_objects, total_hits]
133
135
  end
134
136
 
137
+ # Query sanitising - remove bad characters from query
138
+ # (mimics SFX default behaviour - SFX stores them like this
139
+ # for sorting purposes)
140
+ # Note - this method is not complete, more substitutions may
141
+ # be necessary see the relevant Diacritics file in your SFX config
142
+ # directory for more details
143
+ def replace_problem_tokens(term)
144
+ term.gsub!('æ', 'a1')
145
+ term.gsub!('å', 'a2')
146
+
147
+ term
148
+ end
149
+
135
150
  # Used for clicks on A, B, C, 0-9, etc.
136
151
  def find_by_group
137
152
  connection = sfx4_db_connection
@@ -111,6 +111,12 @@ class UmlautController < ApplicationController
111
111
 
112
112
  end
113
113
 
114
+ # You can use Umlaut's built-in feedback form if you want
115
+ # See https://github.com/team-umlaut/umlaut/wiki/Umlaut's-Feedback-Form
116
+ # feedback do
117
+ # main_library {:email_address => "dummy@example.org", :label => "Main Library"}
118
+ # end
119
+
114
120
  # Advanced topic, you can declaratively configure
115
121
  # what sections of the resolve page are output where
116
122
  # and how using resolve_sections and add_resolve_sections!
@@ -8,8 +8,9 @@ module EmailerHelper
8
8
  options[:include_labels] ||= false
9
9
  rv =""
10
10
  cite = request.referent.to_citation
11
- title = truncate(cite[:title].strip, :length => 70, :seperator => '...')
12
- rv << (cite[:title_label].strip + ": ")if options[:include_labels]
11
+ title = truncate(cite[:title].strip, :length => 70, :separator => ' ')
12
+
13
+ rv << (cite[:title_label].strip + ": ")if options[:include_labels] && cite[:title_label]
13
14
  rv << title
14
15
  rv << "\n"
15
16
  if cite[:author]
@@ -18,7 +19,7 @@ module EmailerHelper
18
19
  rv << "\n"
19
20
  end
20
21
  if cite[:subtitle]
21
- rv << (cite[:subtitle_label].strip + ": ") if options[:include_labels]
22
+ rv << (cite[:subtitle_label].strip + ": ") if options[:include_labels] && cite[:subtitle_label]
22
23
  rv << cite[:subtitle].strip
23
24
  rv << "\n"
24
25
  end
@@ -33,4 +34,17 @@ module EmailerHelper
33
34
  end
34
35
  return rv
35
36
  end
37
+
38
+ def citation_identifiers(request, options = {})
39
+ citation = request.referent.to_citation
40
+ str = ""
41
+
42
+ str << "ISSN: #{citation[:issn]}\n" if citation[:issn]
43
+ str << "ISBN: #{citation[:isbn]}\n" if citation[:isbn]
44
+ citation[:identifiers].each do |identifier|
45
+ str << "#{identifier}\n"
46
+ end
47
+
48
+ return str
49
+ end
36
50
  end
@@ -0,0 +1,25 @@
1
+ class FeedbackMailer < ActionMailer::Base
2
+ add_template_helper(EmailerHelper)
3
+
4
+ default from: UmlautController.umlaut_config.from_email_addr
5
+
6
+ # feedback("findit.library.school.edu", "librarian@university.edu",:name => "Joe", :email => "joe@gmail.com", :feedback => "Whatever", :umlaut_request => urequest)
7
+ # * umlaut_request is optional
8
+ def feedback(host, to_address, options = {})
9
+ @host = host
10
+ @umlaut_request = options[:umlaut_request]
11
+ @name = options[:name]
12
+ @email = options[:email]
13
+ @feedback = options[:feedback]
14
+
15
+ # Force permalink creation if we don't have one already
16
+ if @umlaut_request && @umlaut_request.referent.permalinks.empty?
17
+ permalink = Permalink.new_with_values!(@umlaut_request.referent, @umlaut_request.referrer_id)
18
+ @umlaut_request.referent.permalinks << permalink
19
+ @umlaut_request.save!
20
+ end
21
+
22
+ mail(:to => to_address, :subject => "#{UmlautController.umlaut_config.app_name} Feedback: #{options[:name]}", :reply_to => @email)
23
+ end
24
+
25
+ end
@@ -301,6 +301,43 @@ module MetadataHelper
301
301
  return nil
302
302
  end
303
303
 
304
+ def get_month(rft)
305
+ if rft.metadata['date'] =~ /\d\d\d\d\-(\d\d?)/
306
+ return $1
307
+ elsif rft.metadata['month']
308
+ # some link generators use an illegal 'month' parameter
309
+ return rft.metadata['month']
310
+ else
311
+ return nil
312
+ end
313
+ end
314
+
315
+ # uses `spage` or tries to parse `pages`
316
+ def get_spage(rft)
317
+ if rft.metadata['spage'].present?
318
+ return rft.metadata['spage']
319
+ elsif rft.metadata['pages'] =~ /\A *(.*?) *\-.*\Z/
320
+ return $1
321
+ elsif rft.metadata['pages'].present?
322
+ return rft.metadata['pages']
323
+ else
324
+ return nil
325
+ end
326
+ end
327
+
328
+ # uses `epage` or tries to parse `pages`
329
+ def get_epage(rft)
330
+ if rft.metadata['epage'].present?
331
+ return rft.metadata['epage']
332
+ elsif rft.metadata['pages'] =~ /\A.*\- *(.*) *\Z/
333
+ return $1
334
+ elsif rft.metadata['pages'].present?
335
+ return rft.metadata['pages']
336
+ else
337
+ return nil
338
+ end
339
+ end
340
+
304
341
  # Look at weird bad OpenURLs, use heuristics to see if the 'title' probably
305
342
  # represents a journal rather than a book. A guess at best, based on the bad
306
343
  # data we've seen, sigh.
@@ -280,6 +280,8 @@ class Referent < ActiveRecord::Base
280
280
  end
281
281
 
282
282
  # Creates a hash for use in View code to display a citation
283
+ #
284
+ # Crazy if/else tree logic, should be refactored, needs more tests first prob.
283
285
  def to_citation
284
286
  citation = {}
285
287
  # call self.metadata once and use the array for efficiency, don't
@@ -290,7 +292,7 @@ class Referent < ActiveRecord::Base
290
292
  citation[:title] = my_metadata['atitle']
291
293
  citation[:title_label], citation[:container_label] =
292
294
  case my_metadata['genre']
293
- when /article|journal|issue/ then ['Article Title', 'journal']
295
+ when /article|journal|issue/ then ['Article Title', 'Journal']
294
296
  when /bookitem|book/ then ['Chapter/Part Title', 'book']
295
297
  when /proceeding|conference/ then ['Proceeding Title', 'conference']
296
298
  when 'report' then ['Report Title','report']
@@ -298,7 +300,7 @@ class Referent < ActiveRecord::Base
298
300
  if self.format == 'book'
299
301
  ['Chapter/Part Title', 'book']
300
302
  elsif self.format == 'journal'
301
- ['Article Title', 'journal']
303
+ ['Article Title', 'Journal']
302
304
  else # default fall through, use much what SFX uses.
303
305
  ['Title', '']
304
306
  end
@@ -312,11 +314,11 @@ class Referent < ActiveRecord::Base
312
314
  end
313
315
  else
314
316
  citation[:title_label] = case my_metadata["genre"]
315
- when /article|journal|issue/ then 'journal'
316
- when /bookitem|book/ then 'book'
317
- when /proceeding|conference/ then 'conference'
318
- when 'report' then 'report'
319
- else ''
317
+ when /article|journal|issue/i then 'Journal'
318
+ when /bookitem|book/i then 'Book'
319
+ when /proceeding|conference/i then 'Conference'
320
+ when 'report' then 'Report'
321
+ else nil
320
322
  end
321
323
  ['title','btitle','jtitle'].each do | t_type |
322
324
  if ! my_metadata[t_type].blank?
@@ -326,7 +328,7 @@ class Referent < ActiveRecord::Base
326
328
  end
327
329
  end
328
330
  # add publisher for books
329
- if (my_metadata['genre'] == 'book')
331
+ if (my_metadata['genre'] =~ /book/i)
330
332
  citation[:pub] = my_metadata['pub'] unless my_metadata['pub'].blank?
331
333
  end
332
334
 
@@ -336,21 +338,22 @@ class Referent < ActiveRecord::Base
336
338
  ['volume','issue','date'].each do | key |
337
339
  citation[key.to_sym] = my_metadata[key]
338
340
  end
339
- if ! my_metadata["au"].blank?
340
- citation[:author] = my_metadata["au"]
341
+
342
+ if my_metadata["au"].present?
343
+ citation[:author] = my_metadata["au"].strip
341
344
  elsif my_metadata["aulast"]
342
- citation[:author] = my_metadata["aulast"]
343
- if ! my_metadata["aufirst"].blank?
344
- citation[:author] += ', '+my_metadata["aufirst"]
345
+ citation[:author] = my_metadata["aulast"].strip
346
+ if my_metadata["aufirst"].present?
347
+ citation[:author] += ', '+my_metadata["aufirst"].strip
345
348
  else
346
- if ! my_metadata["auinit"].blank?
347
- citation[:author] += ', '+my_metadata["auinit"]
349
+ if my_metadata["auinit"].present?
350
+ citation[:author] += ', '+my_metadata["auinit"].strip
348
351
  else
349
- if ! my_metadata["auinit1"].blank?
350
- citation[:author] += ', '+my_metadata["auinit1"]
352
+ if my_metadata["auinit1"].present?
353
+ citation[:author] += ', '+my_metadata["auinit1"].strip
351
354
  end
352
- if ! my_metadata["auinitm"].blank?
353
- citation[:author] += my_metadata["auinitm"]
355
+ if my_metadata["auinitm"].present?
356
+ citation[:author] += my_metadata["auinitm"].strip
354
357
  end
355
358
  end
356
359
  end
@@ -16,6 +16,8 @@ class Request < ActiveRecord::Base
16
16
  # responses show up first
17
17
  has_many :service_responses, :order => 'id ASC'
18
18
 
19
+ has_many :clickthroughs
20
+
19
21
  belongs_to :referent, :include => :referent_values
20
22
  # holds a hash representing submitted http params
21
23
  serialize :http_env
@@ -35,6 +37,7 @@ class Request < ActiveRecord::Base
35
37
 
36
38
  # Create a context object from our http params
37
39
  context_object = OpenURL::ContextObject.new_from_form_vars( co_params )
40
+
38
41
  # Sometimes umlaut puts in a 'umlaut.request_id' parameter.
39
42
  # first look by that, if we have it, for an existing request.
40
43
  request_id = params['umlaut.request_id']
@@ -33,7 +33,6 @@ class DissertationCatch < ReferentFilter
33
33
  issn = get_identifier(:urn, "issn", referent)
34
34
  return unless issn
35
35
 
36
-
37
36
  # normalize removing hyphen
38
37
  issn.gsub!('-', '')
39
38
 
@@ -66,6 +65,7 @@ class DissertationCatch < ReferentFilter
66
65
  referent.remove_value("issue_start")
67
66
  referent.remove_value("spage")
68
67
  referent.remove_value("epage")
68
+ referent.remove_value("pages")
69
69
  end
70
70
 
71
71
  end
@@ -0,0 +1,17 @@
1
+ require 'isbn_link'
2
+
3
+ # Blind (not pre-checked for hits) link to compare prices
4
+ # at AllBookstores.com
5
+ # -- because that site seemed good, includes shipping prices, has decent UX,
6
+ # and includes independent bookstores like Powell's and The Strand.
7
+ #
8
+ # subclasses IsbnLink
9
+ class AllBooksDotCom < IsbnLink
10
+ def initialize(config)
11
+ super(config)
12
+
13
+ @display_text ||= "Compare online prices"
14
+ @display_name ||= "AllBookstores.com"
15
+ @link_template ||= "http://www.allbookstores.com/book/compare/%s"
16
+ end
17
+ end
@@ -0,0 +1,161 @@
1
+ require 'cgi'
2
+ require 'openurl'
3
+
4
+ # Just creates an OpenURL link out, corresponding to the current OpenURL.
5
+ # But tweaked in ways to try and work out for sending to ILLiad.
6
+ #
7
+ # If you use SFX, you may want to just use SFX's built-in ILLiad targets, which
8
+ # will generally be picked up by the SFX Umlaut service.
9
+ #
10
+ # But if you don't or if you are unhappy with what SFX is doing, you could turn
11
+ # off ILLiad target(s) in SFX (or configure Umlaut SFX adapter to ignore them),
12
+ # and use this instead.
13
+ #
14
+ # # Pre-empting
15
+ #
16
+ # You may want to show ILLiad links only if there is no fulltext, or only if there
17
+ # is no fulltext from a certain service. You can use Umlaut's standard service
18
+ # pre-emption configuration for that.
19
+ #
20
+ # Do not produce ILLiad links if there are ANY fulltext links already produced
21
+ # in the request. In umlaut_services.yml:
22
+ #
23
+ # illiad:
24
+ # type: Illiad
25
+ # priority: 4
26
+ # preempted_by:
27
+ # existing_type: fulltext
28
+ #
29
+ # Or, preempt ILLiad links only if there are fulltext links created by SFX
30
+ # specifically (assume "SFX" is the id of your sfx service in umlaut_services.yml)
31
+ #
32
+ # illiad:
33
+ # type: Illiad
34
+ # priority: 4
35
+ # preempted_by:
36
+ # existing_service: SFX
37
+ # existing_type: fulltext
38
+ #
39
+ # Pre-emption can only take account of services already generated before ILLiad
40
+ # service is triggered, so you'd want to make sure to give ILLiad a priority greater
41
+ # than the services you want to potentially preempt it.
42
+ #
43
+ # # Config parameters
44
+ # ## Required
45
+ #
46
+ # * base_url: Illiad base url, such as `http://ill.university.edu/site/illiad.dll/OpenURL`. It should probably end in '/illiad.dll/OpenURL'
47
+ #
48
+ # ## Optional
49
+ #
50
+ # * display_name: Default "Place ILL Request"
51
+ # * sid_suffix: Default " (via Umlaut)", appended to existing sid before sending to ILLiad.
52
+ # * notes: Some additional notes to display under the link.
53
+ class Illiad < Service
54
+ include MetadataHelper
55
+
56
+ required_config_params :base_url
57
+
58
+ def initialize(config)
59
+ @service_type = "document_delivery"
60
+ @display_name = "Place ILL Request"
61
+ @sid_suffix = " (via Umlaut)"
62
+
63
+ super(config)
64
+ end
65
+
66
+
67
+ def service_types_generated
68
+ [ServiceTypeValue[@service_type.to_sym]]
69
+ end
70
+
71
+ def handle(request)
72
+ target_url = @base_url + "?" + illiad_query_parameters(request).to_query
73
+
74
+ request.add_service_response(
75
+ :service =>self,
76
+ :display_text => @display_name,
77
+ :url => target_url,
78
+ :notes => @notes,
79
+ :service_type_value => @service_type.to_sym
80
+ )
81
+
82
+ return request.dispatched(self, true)
83
+ end
84
+
85
+
86
+ def illiad_query_parameters(request)
87
+ metadata = request.referent.metadata
88
+
89
+ qp = {}
90
+
91
+ qp['genre'] = metadata['genre']
92
+
93
+ if metadata['aulast']
94
+ qp["aulast"] = metadata['aulast']
95
+ qp["aufirst"] = [metadata['aufirst'], metadata["auinit"]].find {|a| a.present?}
96
+ else
97
+ qp["au"] = metadata["au"]
98
+ end
99
+
100
+ qp['volume'] = metadata['volume']
101
+ qp['issue'] = metadata['issue']
102
+
103
+ qp['spage'] = get_spage(request.referent)
104
+ qp['epage'] = get_epage(request.referent)
105
+
106
+ qp['issn'] = get_issn(request.referent)
107
+ qp['isbn'] = get_isbn(request.referent)
108
+ qp['pmid'] = get_pmid(request.referent)
109
+
110
+ qp['stitle'] = metadata['stitle']
111
+
112
+ qp['sid'] = sid_for_illiad(request)
113
+
114
+ qp['year'] = get_year(request.referent)
115
+ qp['month'] = get_month(request.referent)
116
+
117
+ qp['atitle'] = metadata['atitle']
118
+
119
+ # ILLiad always wants 'title', not the various title keys that exist in OpenURL
120
+ qp['title'] = [metadata['jtitle'], metadata['btitle'], metadata['title']].find {|a| a.present?}
121
+
122
+ # For some reason these go to ILLiad prefixed with rft.
123
+ qp['rft.pub'] = metadata['pub']
124
+ qp['rft.place'] = metadata['place']
125
+ qp['rft.edition'] = metadata['edition']
126
+
127
+ # ILLiad likes OCLCnum in `rfe_dat`
128
+ qp['rfe_dat'] = get_oclcnum(request.referent)
129
+
130
+
131
+ # Genre normalization. ILLiad pays a lot of attention to `&genre`, but
132
+ # doesn't use actual OpenURL rft_val_fmt
133
+ if request.referent.format == "dissertation"
134
+ qp['genre'] = 'dissertation'
135
+ elsif qp['isbn'].present? && qp['genre'] == 'book' && qp['atitle'] && (! qp['issn'].present?)
136
+ # actually a book chapter, not a book, fix it.
137
+ qp['genre'] = 'bookitem'
138
+ elsif qp['issn'].present? && qp['atitle'].present?
139
+ # Otherwise, if there is an ISSN, we force genre to 'article', seems
140
+ # to work best.
141
+ qp['genre'] = 'article'
142
+ elsif qp['genre'] == 'unknown' && qp['atitle'].blank?
143
+ # WorldCat likes to send these, ILLiad is happier considering them 'book'
144
+ qp['genre'] = "book"
145
+ end
146
+
147
+ # trim empty ones please
148
+ qp.delete_if {|k, v| v.blank?}
149
+
150
+ return qp
151
+ end
152
+
153
+ # Grab a source label out of `sid` or `rfr_id`, add on our suffix.
154
+ def sid_for_illiad(request)
155
+ sid = request.referrer_id || ""
156
+
157
+ sid = sid.gsub(%r{\Ainfo\:sid/}, '')
158
+
159
+ return "#{sid}#{@sid_suffix}"
160
+ end
161
+ end
@@ -2,6 +2,11 @@
2
2
  # info for online sellers. There are potentially other services we could
3
3
  # make use of there in the future too.
4
4
  #
5
+ # By default makes an API request in advance to check if book is available, and thus requires
6
+ # an API key. However, ISBNdb seems no longer as reliable as it once was there.
7
+ # You may not want to use ISBNdb at all, see AllBooksDotCom as an alternative
8
+ # (although with no pre-check for hits.)
9
+ #
5
10
  # jrochkind talked to the operators of isbndb and got a very high traffic limit
6
11
  # (instead of the default free 500 requests/day), for free. You could try the
7
12
  # same.
@@ -22,7 +27,7 @@ class IsbnDb < Service
22
27
  end
23
28
 
24
29
  def initialize(config)
25
- @timeout = 7
30
+ @timeout = 3
26
31
  @display_text = "Compare online prices"
27
32
  @display_name = "ISBNdb.com"
28
33
 
@@ -0,0 +1,57 @@
1
+ require 'isbn'
2
+
3
+ # A simple service to generate a blind link (NOT pre-checked for hits, just
4
+ # blindly created from a template) out to a service based on ISBN.
5
+ #
6
+ # May likely be sub-classed for specific services (see AllBooks.com),
7
+ # which set default values.
8
+ #
9
+ # * :link_template. => String where "%s" will be replaced with ISBN
10
+ # * :display_name
11
+ # * :dispaly_text. Such as "Compare online prices
12
+ # * :isbn_normalize. Default nil, set to :ten or :thirteen if you need to normalize
13
+ # ISBN before substituting in :link_template.
14
+ class IsbnLink < Service
15
+ include MetadataHelper
16
+
17
+ def service_types_generated
18
+ return [ServiceTypeValue['highlighted_link']]
19
+ end
20
+
21
+ def initialize(config)
22
+ @display_text = "Compare online prices"
23
+ @isbn_normalize = nil
24
+
25
+ super(config)
26
+ end
27
+
28
+ def handle(umlaut_request)
29
+
30
+ isbn = get_isbn(umlaut_request.referent)
31
+
32
+ # No isbn, nothing we can do.
33
+ return umlaut_request.dispatched(self, true) if isbn.blank?
34
+
35
+ # invalid isbn? forget it.
36
+ return umlaut_request.dispatched(self, true) unless ISBN.valid?(isbn)
37
+
38
+ if @isbn_normalize == :ten
39
+ isbn = ISBN.ten(isbn)
40
+ elsif @isbn_normalize == :thirteen
41
+ isbn = ISBN.thirteen(isbn)
42
+ end
43
+
44
+ # Add the link
45
+ link = @link_template.gsub("%s", isbn)
46
+
47
+ umlaut_request.add_service_response(
48
+ :service=>self,
49
+ :url=> link,
50
+ :display_text=> @display_text,
51
+ :service_type_value => ServiceTypeValue[:highlighted_link]
52
+ )
53
+
54
+ return umlaut_request.dispatched(self, true)
55
+ end
56
+
57
+ end
@@ -1,4 +1,8 @@
1
1
  # Service adapter plug-in.
2
+ #
3
+ # NOTE: This is based on deprecated Scopus API's, Scopus will take them
4
+ # away 31 December 2014. Please see scopus2.rb instead which uses
5
+ # new Scopus API's.
2
6
  #
3
7
  # PURPOSE: Includes "cited by", "similar articles" and "more by these authors"
4
8
  # links from scopus. Also will throw in an abstract from Scopus if found.