blacklight_oai_provider 0.1.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rubocop.yml +39 -0
  4. data/.rubocop_todo.yml +130 -0
  5. data/.solr_wrapper +8 -0
  6. data/.travis.yml +16 -0
  7. data/Gemfile +34 -2
  8. data/README.md +131 -0
  9. data/Rakefile +25 -0
  10. data/VERSION +1 -1
  11. data/app/assets/{xsl → stylesheets/blacklight_oai_provider}/oai2.xsl +12 -5
  12. data/app/controllers/concerns/blacklight_oai_provider/controller.rb +38 -0
  13. data/app/models/concerns/blacklight_oai_provider/solr_document.rb +23 -0
  14. data/blacklight_oai_provider.gemspec +17 -10
  15. data/config/initializers/oai_patches.rb +20 -0
  16. data/lib/blacklight_oai_provider/engine.rb +15 -2
  17. data/lib/blacklight_oai_provider/exceptions.rb +9 -0
  18. data/lib/blacklight_oai_provider/resumption_token.rb +51 -0
  19. data/lib/blacklight_oai_provider/routes.rb +15 -0
  20. data/lib/blacklight_oai_provider/solr_document_provider.rb +2 -2
  21. data/lib/blacklight_oai_provider/solr_document_wrapper.rb +55 -27
  22. data/lib/blacklight_oai_provider/version.rb +1 -2
  23. data/lib/blacklight_oai_provider.rb +16 -14
  24. data/lib/generators/blacklight_oai_provider/install_generator.rb +27 -0
  25. data/lib/railties/blacklight_oai_provider.rake +14 -0
  26. data/solr/conf/_rest_managed.json +3 -0
  27. data/solr/conf/admin-extra.html +31 -0
  28. data/solr/conf/elevate.xml +36 -0
  29. data/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  30. data/solr/conf/protwords.txt +21 -0
  31. data/solr/conf/schema.xml +629 -0
  32. data/solr/conf/scripts.conf +24 -0
  33. data/solr/conf/solrconfig.xml +401 -0
  34. data/solr/conf/spellings.txt +2 -0
  35. data/solr/conf/stopwords.txt +58 -0
  36. data/solr/conf/stopwords_en.txt +58 -0
  37. data/solr/conf/synonyms.txt +31 -0
  38. data/solr/conf/xslt/example.xsl +132 -0
  39. data/solr/conf/xslt/example_atom.xsl +67 -0
  40. data/solr/conf/xslt/example_rss.xsl +66 -0
  41. data/solr/conf/xslt/luke.xsl +337 -0
  42. data/solr/sample_solr_documents.yml +2722 -0
  43. data/spec/controllers/catalog_controller_spec.rb +39 -0
  44. data/spec/features/html_rendering_spec.rb +24 -0
  45. data/spec/models/solr_document_spec.rb +43 -0
  46. data/spec/requests/get_record_spec.rb +47 -0
  47. data/spec/requests/identify_spec.rb +53 -0
  48. data/spec/requests/list_identifiers_spec.rb +80 -0
  49. data/spec/requests/list_metadata_formats_spec.rb +43 -0
  50. data/spec/requests/list_records_spec.rb +126 -0
  51. data/spec/spec_helper.rb +15 -38
  52. data/spec/test_app_templates/config/solr.yml +9 -0
  53. data/spec/test_app_templates/lib/generators/test_app_generator.rb +86 -0
  54. metadata +146 -87
  55. data/Gemfile.lock +0 -187
  56. data/README.rdoc +0 -74
  57. data/config/routes.rb +0 -5
  58. data/lib/blacklight_oai_provider/README.rdoc +0 -0
  59. data/lib/blacklight_oai_provider/controller_extension.rb +0 -29
  60. data/lib/blacklight_oai_provider/route_sets.rb +0 -13
  61. data/lib/blacklight_oai_provider/solr_document_extension.rb +0 -10
  62. data/lib/generators/blacklight_oai_provider/blacklight_oai_provider_generator.rb +0 -27
  63. data/spec/acceptance/blacklight_oai_provider_spec.rb +0 -49
  64. data/spec/integration/blacklight_stub_spec.rb +0 -10
  65. data/spec/internal/app/controllers/application_controller.rb +0 -4
  66. data/spec/internal/app/models/solr_document.rb +0 -3
  67. data/spec/internal/config/database.yml +0 -3
  68. data/spec/internal/config/routes.rb +0 -6
  69. data/spec/internal/config/solr.yml +0 -18
  70. data/spec/internal/db/combustion_test.sqlite +0 -0
  71. data/spec/internal/db/schema.rb +0 -53
  72. data/spec/internal/log/.gitignore +0 -1
  73. data/spec/internal/public/favicon.ico +0 -0
  74. data/spec/lib/solr_document_extension_spec.rb +0 -6
  75. data/spec/vcr_cassettes/solr.yml +0 -113
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c8443a7d656487d8e2aa2cfd0ebd3b7b659d85b
4
+ data.tar.gz: 07f9b6fb1ca30e96915f1d9ea13f1afc962ec5a1
5
+ SHA512:
6
+ metadata.gz: f0e3e076577da7493f9cb6ed7606720854e270892e85bef93d1e5959585c60cd61deb16790ee99c287625d5ddc971bacfb33446eea2b288b0108171eeb17fc21
7
+ data.tar.gz: f91efbafee6de242c66fb288b442b01cef71c70a123d6661209cc4a261ba22c1b6c0c598813e2a0b9e2ad77b396b7734fa5690d3d28d272fea29b7d3fd336258
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
11
+ .ruby-version
12
+ .ruby-gemset
13
+ .byebug_history
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
17
+
18
+ .internal_test_app
data/.rubocop.yml ADDED
@@ -0,0 +1,39 @@
1
+ require: rubocop-rspec
2
+
3
+ inherit_from:
4
+ - .rubocop_todo.yml
5
+
6
+ AllCops:
7
+ DisplayCopNames: true
8
+ Exclude:
9
+ - "blacklight_oai_provider.gemspec"
10
+
11
+ Rails:
12
+ Enabled: true
13
+
14
+ Metrics/BlockLength:
15
+ Exclude:
16
+ - 'spec/**/*'
17
+ - "lib/railties/blacklight_oai_provider.rake"
18
+
19
+ Metrics/LineLength:
20
+ Max: 200
21
+
22
+ Style/StringLiterals:
23
+ Enabled: false
24
+
25
+ Layout/IndentationConsistency:
26
+ EnforcedStyle: normal
27
+
28
+ Rails/OutputSafety:
29
+ Enabled: false
30
+
31
+ # engine_cart block includes conditional, not duplication
32
+ Bundler/DuplicatedGem:
33
+ Exclude:
34
+ - 'Gemfile'
35
+
36
+ # engine_cart block is following default Rails order
37
+ Bundler/OrderedGems:
38
+ Exclude:
39
+ - 'Gemfile'
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,130 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-10-26 15:19:14 -0400 using RuboCop version 0.50.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
12
+ # SupportedStyles: empty_lines, no_empty_lines
13
+ Layout/EmptyLinesAroundBlockBody:
14
+ Exclude:
15
+ - 'spec/requests/list_metadata_formats_spec.rb'
16
+
17
+ # Offense count: 4
18
+ Metrics/AbcSize:
19
+ Max: 25
20
+
21
+ # Offense count: 2
22
+ # Configuration parameters: CountComments.
23
+ Metrics/MethodLength:
24
+ Max: 39
25
+
26
+ # Offense count: 2
27
+ RSpec/BeforeAfterAll:
28
+ Exclude:
29
+ - 'spec/spec_helper.rb'
30
+ - 'spec/rails_helper.rb'
31
+ - 'spec/support/**/*.rb'
32
+ - 'spec/requests/list_identifiers_spec.rb'
33
+
34
+ # Offense count: 6
35
+ RSpec/DescribeClass:
36
+ Exclude:
37
+ - 'spec/features/html_rendering_spec.rb'
38
+ - 'spec/requests/get_record_spec.rb'
39
+ - 'spec/requests/identify_spec.rb'
40
+ - 'spec/requests/list_identifiers_spec.rb'
41
+ - 'spec/requests/list_metadata_formats_spec.rb'
42
+ - 'spec/requests/list_records_spec.rb'
43
+
44
+ # Offense count: 1
45
+ # Configuration parameters: CustomIncludeMethods.
46
+ RSpec/EmptyExampleGroup:
47
+ Exclude:
48
+ - 'spec/requests/list_records_spec.rb'
49
+
50
+ # Offense count: 1
51
+ # Configuration parameters: Max.
52
+ RSpec/ExampleLength:
53
+ Exclude:
54
+ - 'spec/controllers/catalog_controller_spec.rb'
55
+
56
+ # Offense count: 6
57
+ RSpec/MultipleExpectations:
58
+ Max: 2
59
+
60
+ # Offense count: 2
61
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
62
+ # SupportedStyles: strict, flexible
63
+ Rails/TimeZone:
64
+ Exclude:
65
+ - 'spec/requests/identify_spec.rb'
66
+
67
+ # Offense count: 1
68
+ # Cop supports --auto-correct.
69
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
70
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining
71
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
72
+ # FunctionalMethods: let, let!, subject, watch
73
+ # IgnoredMethods: lambda, proc, it
74
+ Style/BlockDelimiters:
75
+ Exclude:
76
+ - 'spec/models/solr_document_spec.rb'
77
+
78
+ # Offense count: 3
79
+ # Cop supports --auto-correct.
80
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
81
+ # SupportedStyles: braces, no_braces, context_dependent
82
+ Style/BracesAroundHashParameters:
83
+ Exclude:
84
+ - 'lib/blacklight_oai_provider/solr_document_wrapper.rb'
85
+ - 'spec/models/solr_document_spec.rb'
86
+
87
+ # Offense count: 12
88
+ Style/Documentation:
89
+ Exclude:
90
+ - 'spec/**/*'
91
+ - 'test/**/*'
92
+ - 'app/controllers/concerns/blacklight_oai_provider/controller.rb'
93
+ - 'app/models/concerns/blacklight_oai_provider/solr_document.rb'
94
+ - 'lib/blacklight_oai_provider.rb'
95
+ - 'lib/blacklight_oai_provider/engine.rb'
96
+ - 'lib/blacklight_oai_provider/exceptions.rb'
97
+ - 'lib/blacklight_oai_provider/resumption_token.rb'
98
+ - 'lib/blacklight_oai_provider/routes.rb'
99
+ - 'lib/blacklight_oai_provider/solr_document_provider.rb'
100
+ - 'lib/blacklight_oai_provider/solr_document_wrapper.rb'
101
+ - 'lib/blacklight_oai_provider/version.rb'
102
+ - 'lib/generators/blacklight_oai_provider/install_generator.rb'
103
+
104
+ # Offense count: 24
105
+ # Cop supports --auto-correct.
106
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
107
+ # SupportedStyles: when_needed, always, never
108
+ Style/FrozenStringLiteralComment:
109
+ Enabled: false
110
+
111
+ # Offense count: 2
112
+ # Configuration parameters: MinBodyLength.
113
+ Style/GuardClause:
114
+ Exclude:
115
+ - 'lib/generators/blacklight_oai_provider/install_generator.rb'
116
+
117
+ # Offense count: 1
118
+ # Cop supports --auto-correct.
119
+ # Configuration parameters: MinSize, SupportedStyles.
120
+ # SupportedStyles: percent, brackets
121
+ Style/SymbolArray:
122
+ EnforcedStyle: brackets
123
+
124
+ # Offense count: 1
125
+ # Cop supports --auto-correct.
126
+ # Configuration parameters: IgnoredMethods.
127
+ # IgnoredMethods: respond_to, define_method
128
+ Style/SymbolProc:
129
+ Exclude:
130
+ - 'spec/spec_helper.rb'
data/.solr_wrapper ADDED
@@ -0,0 +1,8 @@
1
+ # Place any default configuration for solr_wrapper here
2
+ port: 8983
3
+ verbose: true
4
+ version: 5.5.5
5
+ managed: true
6
+ collection:
7
+ dir: solr/conf/
8
+ name: blacklight-core
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ notifications:
2
+ email: false
3
+
4
+ language: ruby
5
+ sudo: false
6
+ rvm:
7
+ - 2.3.3
8
+ - 2.2
9
+ - 2.1
10
+
11
+ env:
12
+ - "RAILS_VERSION=4.2.9"
13
+ - "RAILS_VERSION=4.1.16"
14
+
15
+ before_install:
16
+ - gem install bundler
data/Gemfile CHANGED
@@ -2,5 +2,37 @@ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'combustion'
6
- gem 'sqlite3'
5
+ # BEGIN ENGINE_CART BLOCK
6
+ # engine_cart: 1.1.0
7
+ # engine_cart stanza: 0.10.0
8
+ # the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
9
+ file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', File.dirname(__FILE__)))
10
+ if File.exist?(file)
11
+ begin
12
+ eval_gemfile file
13
+ rescue Bundler::GemfileError => e
14
+ Bundler.ui.warn '[EngineCart] Skipping Rails application dependencies:'
15
+ Bundler.ui.warn e.message
16
+ end
17
+ else
18
+ Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
19
+
20
+ if ENV['RAILS_VERSION']
21
+ if ENV['RAILS_VERSION'] == 'edge'
22
+ gem 'rails', github: 'rails/rails'
23
+ ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
24
+ else
25
+ gem 'rails', ENV['RAILS_VERSION']
26
+ end
27
+ end
28
+
29
+ case ENV['RAILS_VERSION']
30
+ when /^4.2/
31
+ gem 'responders', '~> 2.0'
32
+ gem 'sass-rails', '>= 5.0'
33
+ gem 'coffee-rails', '~> 4.1.0'
34
+ when /^4.[01]/
35
+ gem 'sass-rails', '< 5.0'
36
+ end
37
+ end
38
+ # END ENGINE_CART BLOCK
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # BlacklightOaiProvider
2
+ OAI-PMH service endpoint for Blacklight applications
3
+
4
+ ## Description
5
+ The BlacklightOaiProvider plugin provides an [Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH)](http://www.openarchives.org/pmh/) data provider endpoint, using the [ruby-oai gem](https://github.com/code4lib/ruby-oai). This endpoint enables service providers harvest a data provider's metadata.
6
+
7
+ ### Versioning
8
+ Starting `v4.1` major plugin versions are synced with major Blacklight versions. The last known version to work with Blacklight 3.x/Rails 3.x is `v0.1.0`.
9
+
10
+ A few maintenance branches have been left in place in case there is interest to add support for older versions of Rails/Blacklight:
11
+
12
+ `v3.x` -> Support for Blacklight 3.0
13
+
14
+ `v4.x` -> Support for Blacklight 4.0 and Rails 3.0
15
+
16
+ ## Requirements
17
+ A Rails app running Rails 4.x and Blacklight 4.x.
18
+
19
+ OAI-PMH requires a timestamp field for all records. The Solr index should include an appropriate field. This field should be able to support date range queries. By default, the name of this field is `timestamp` (more on how to configure this below).
20
+
21
+ A properly configured documentHandler in the blacklight/solr configuration.
22
+
23
+ ## Installation
24
+
25
+ Add
26
+
27
+ ```ruby
28
+ gem 'blacklight_oai_provider', git: 'https://github.com/projectblacklight/blacklight_oai_provider'
29
+ ```
30
+
31
+ to your Gemfile and run `bundle install`.
32
+
33
+ Then run
34
+ ```ruby
35
+ rails generate blacklight_oai_provider:install
36
+ ```
37
+ to install the appropriate extensions into your `CatalogController` and `SolrDocument` classes. If you want to do customize the way this installs, instead you may:
38
+
39
+ - add this to your Solr Document model:
40
+ ```ruby
41
+ include BlacklightOaiProvider::SolrDocument
42
+ ```
43
+ - add this to your Controller:
44
+ ```ruby
45
+ include BlacklightOaiProvider::Controller
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ While the plugin provides some sensible (albeit generic) defaults out of the box, you probably will want to customize the OAI provider configuration.
51
+
52
+ ### Blacklight configuration
53
+ You can provide OAI-PMH provider parameters by placing the following in your blacklight configuration (most likely in `app/controllers/catalog_controller.rb`)
54
+
55
+ ```ruby
56
+ configure_blacklight do |config|
57
+
58
+ # ...
59
+
60
+ config.oai = {
61
+ :provider => {
62
+ :repository_name => 'Test',
63
+ :repository_url => 'http://localhost',
64
+ :record_prefix => '',
65
+ :admin_email => 'root@localhost'
66
+ },
67
+ :document => {
68
+ :model => SolrDocument, # SolrDocument class you are using.
69
+ :limit => 25
70
+ }
71
+ }
72
+
73
+ # ...
74
+
75
+ end
76
+ ```
77
+
78
+ The "provider" configuration is documented as part of the ruby-oai gem at http://oai.rubyforge.org/
79
+
80
+ _Note:_ The document handler in your blacklight controller must be configured properly for this plugin to correctly look up records.
81
+
82
+ ### SolrDocument configuration
83
+ To change the name of the timestamp solr field in your `SolrDocument` model change the following attribute:
84
+ ```ruby
85
+ self.timestamp_key = 'record_creation_date' # Default: 'timestamp'
86
+ ```
87
+
88
+ The metadata displayed in the xml serialization of each record is based off the `field_semantics` hash in the `SolrDocument` model. To update/change these fields add something like the following to your model:
89
+
90
+ ```ruby
91
+ field_semantics.merge!(
92
+ creator: "author_display",
93
+ date: "pub_date",
94
+ subject: "subject_topic_facet",
95
+ title: "title_display",
96
+ language: "language_facet",
97
+ format: "format"
98
+ )
99
+ ```
100
+
101
+ The fields used by the dublin core serialization are:
102
+ ```ruby
103
+ [:contributor, :coverage, :creator, :date, :description, :format, :identifier, :language, :publisher, :relation, :rights, :source, :subject, :title, :type]
104
+ ```
105
+
106
+ ## Injection
107
+ This plugin assumes it is in a Blacklight Rails app, uses Blacklight methods, Rails methods, and standard ruby module includes to inject it's behaviors into the app.
108
+
109
+ You can turn off this injection if you like, although it will make the plugin less (or non-) functional unless you manually do similar injection. See `lib/blacklight_oai_provider.rb#inject!` to see exactly what's going on.
110
+
111
+ In any initializer, you can set:
112
+ ```ruby
113
+ BlacklightOaiProvider.omit_inject = true
114
+ ```
115
+ to turn off all injection. The plugin will be completely non-functional if you do this, of course. But perhaps you could try to re-use some of it's classes in a non-Blacklight, highly hacked Blacklight, or even non-Rails application this way.
116
+
117
+ You can also turn off injection of individual components, which could be more useful:
118
+ ```ruby
119
+ BlacklightOaiProvider.omit_inject = {
120
+ :routes => false,
121
+ }
122
+ ```
123
+ ## Tests
124
+ We use `engine_cart` and `solr_wrapper` to run tests on a dummy instance of an app using this plugin.
125
+
126
+ To run the entire test suite:
127
+ ```ruby
128
+ rake ci
129
+ ```
130
+
131
+ You can test OAI-PMH conformance against http://www.openarchives.org/data/registerasprovider.html#Protocol_Conformance_Testing or browse the data at http://re.cs.uct.ac.za/
data/Rakefile CHANGED
@@ -2,3 +2,28 @@ require 'rake'
2
2
  require 'bundler'
3
3
 
4
4
  Bundler::GemHelper.install_tasks
5
+
6
+ require 'engine_cart/rake_task'
7
+ require 'solr_wrapper'
8
+
9
+ task default: [:rubocop, :ci]
10
+
11
+ require 'rspec/core/rake_task'
12
+ RSpec::Core::RakeTask.new
13
+
14
+ require 'rubocop/rake_task'
15
+ RuboCop::RakeTask.new(:rubocop)
16
+
17
+ EngineCart.fingerprint_proc = EngineCart.rails_fingerprint_proc
18
+
19
+ desc 'Run test suite'
20
+ task ci: ['engine_cart:generate'] do
21
+ SolrWrapper.wrap do |solr|
22
+ solr.with_collection(name: 'blacklight-core', dir: File.join(File.expand_path(__dir__), "solr", "conf")) do
23
+ within_test_app do
24
+ system "RAILS_ENV=test rake blacklight_oai_provider:index:seed"
25
+ end
26
+ Rake::Task['spec'].invoke
27
+ end
28
+ end
29
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 4.1.0
@@ -528,13 +528,20 @@ p.intro {
528
528
  <!-- oai resumptionToken -->
529
529
 
530
530
  <xsl:template match="oai:resumptionToken">
531
- <p>There are more results.</p>
532
- <table class="values">
533
- <tr><td class="key">resumptionToken:</td>
534
- <td class="value"><xsl:value-of select="."/>
531
+ <xsl:choose>
532
+ <xsl:when test="self::node()[text()]">
533
+ <p>There are more results.</p>
534
+ <table class="values">
535
+ <tr><td class="key">resumptionToken:</td>
536
+ <td class="value"><xsl:value-of select="."/>
535
537
  <xsl:text> </xsl:text>
536
538
  <a class="link" href="?verb={/oai:OAI-PMH/oai:request/@verb}&amp;resumptionToken={.}">Resume</a></td></tr>
537
- </table>
539
+ </table>
540
+ </xsl:when>
541
+ <xsl:otherwise>
542
+ <p>End of results.</p>
543
+ </xsl:otherwise>
544
+ </xsl:choose>
538
545
  </xsl:template>
539
546
 
540
547
  <!-- unknown metadata format -->
@@ -0,0 +1,38 @@
1
+ # Meant to be applied on top of a controller that implements
2
+ # Blacklight::SolrHelper. Will inject range limiting behaviors
3
+ # to solr parameters creation.
4
+ module BlacklightOaiProvider
5
+ module Controller
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ helper_method :oai_config
10
+ end
11
+
12
+ # Action method of our own!
13
+ # Delivers a _partial_ that's a display of a single fields range facets.
14
+ # Used when we need a second Solr query to get range facets, after the
15
+ # first found min/max from result set.
16
+ def oai
17
+ options = params.delete_if { |k, _| %w[controller action].include?(k) }
18
+ body = oai_provider
19
+ .process_request(options)
20
+ .gsub('<?xml version="1.0" encoding="UTF-8"?>') do |m|
21
+ "#{m}\n<?xml-stylesheet type=\"text/xsl\" href=\"#{ActionController::Base.helpers.asset_path('blacklight_oai_provider/oai2.xsl')}\"?>\n"
22
+ end
23
+ render text: body, content_type: 'text/xml'
24
+ end
25
+
26
+ # Uses Blacklight.config, needs to be modified when
27
+ # that changes to be controller-based. This is the only method
28
+ # in this plugin that accesses Blacklight.config, single point
29
+ # of contact.
30
+ def oai_config
31
+ blacklight_config.oai || {}
32
+ end
33
+
34
+ def oai_provider
35
+ @oai_provider ||= BlacklightOaiProvider::SolrDocumentProvider.new(self, oai_config)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module BlacklightOaiProvider
2
+ module SolrDocument
3
+ extend ActiveSupport::Concern
4
+
5
+ def timestamp
6
+ timestamp = get(self.class.timestamp_key)
7
+ raise BlacklightOaiProvider::Exceptions::MissingTimestamp if timestamp.blank?
8
+ Time.zone.parse(timestamp) # Solr timestamps are all in UTC.
9
+ end
10
+
11
+ def to_oai_dc
12
+ export_as('oai_dc_xml')
13
+ end
14
+
15
+ module ClassMethods
16
+ attr_writer :timestamp_key
17
+
18
+ def timestamp_key
19
+ @timestamp_key ||= 'timestamp'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,15 +1,19 @@
1
- # -*- coding: utf-8 -*-
2
1
  require File.join(File.dirname(__FILE__), "lib/blacklight_oai_provider/version")
3
2
 
4
3
  Gem::Specification.new do |s|
5
4
  s.name = "blacklight_oai_provider"
6
5
  s.version = BlacklightOaiProvider::VERSION
7
6
  s.platform = Gem::Platform::RUBY
8
- s.authors = ["Chris Beer"]
9
- s.email = ["chris@cbeer.info"]
7
+ s.authors = ["Chris Beer", "Carla Galarza"]
8
+ s.email = ["chris@cbeer.info", "cmg2228@columbia.edu"]
10
9
  s.homepage = "http://projectblacklight.org/"
11
10
  s.summary = "Blacklight Oai Provider plugin"
12
11
 
12
+ s.post_install_message = %q{
13
+ BlacklightOaiProvider v4.1 implements configuration changes. Please visit README for more information.
14
+
15
+ }
16
+
13
17
  s.rubyforge_project = "blacklight"
14
18
 
15
19
  s.files = `git ls-files`.split("\n")
@@ -17,13 +21,16 @@ Gem::Specification.new do |s|
17
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
22
  s.require_paths = ["lib"]
19
23
 
20
-
21
- s.add_dependency "rails", "~> 3.0"
22
- s.add_dependency "blacklight", "~> 3.2"
24
+ s.add_dependency "rails", "~> 4.0"
25
+ s.add_dependency "blacklight", "~> 4.0"
23
26
  s.add_dependency "oai"
24
- s.add_development_dependency 'rspec'
25
- s.add_development_dependency 'rspec-rails'
27
+ s.add_development_dependency 'rspec-rails', "~> 3.0"
26
28
  s.add_development_dependency 'capybara'
27
- s.add_development_dependency 'vcr'
28
- s.add_development_dependency 'fakeweb'
29
+ s.add_development_dependency 'solr_wrapper'
30
+ s.add_development_dependency 'engine_cart'
31
+ s.add_development_dependency "chromedriver-helper"
32
+ s.add_development_dependency "selenium-webdriver"
33
+ s.add_development_dependency 'byebug'
34
+ s.add_development_dependency 'rubocop', '~> 0.50.0'
35
+ s.add_development_dependency "rubocop-rspec", '~> 1.18.0'
29
36
  end
@@ -0,0 +1,20 @@
1
+ # Fix the OAI gem resource identifier format
2
+ # See: https://github.com/code4lib/ruby-oai/issues/38
3
+
4
+ Rails.application.config.to_prepare do
5
+ OAI::Provider::Response::RecordResponse.class_eval do
6
+ private
7
+
8
+ def identifier_for(record)
9
+ "#{provider.prefix}:#{record.id}"
10
+ end
11
+ end
12
+
13
+ OAI::Provider::Response::Base.class_eval do
14
+ private
15
+
16
+ def extract_identifier(id)
17
+ id.sub("#{provider.prefix}:", '')
18
+ end
19
+ end
20
+ end
@@ -4,14 +4,27 @@ require 'rails'
4
4
 
5
5
  module BlacklightOaiProvider
6
6
  class Engine < Rails::Engine
7
-
8
7
  # Do these things in a to_prepare block, to try and make them work
9
8
  # in development mode with class-reloading. The trick is we can't
10
9
  # be sure if the controllers we're modifying are being reloaded in
11
10
  # dev mode, if they are in the BL plugin and haven't been copied to
12
- # local, they won't be. But we do our best.
11
+ # local, they won't be. But we do our best.
13
12
  config.to_prepare do
14
13
  BlacklightOaiProvider.inject!
15
14
  end
15
+
16
+ # Add XSL Stylesheet to list of assets to be precompiled.
17
+ initializer "blacklight_oai_provider.assets.precompile" do |app|
18
+ app.config.assets.precompile += %w[blacklight_oai_provider/oai2.xsl]
19
+ end
20
+
21
+ # Load rake tasks.
22
+ rake_tasks do
23
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..'))) do
24
+ Dir.glob(File.join('railties', '*.rake')).each do |railtie|
25
+ load railtie
26
+ end
27
+ end
28
+ end
16
29
  end
17
30
  end
@@ -0,0 +1,9 @@
1
+ module BlacklightOaiProvider
2
+ module Exceptions
3
+ class MissingTimestamp < StandardError
4
+ def initialize(msg = "Missing required timestamp field")
5
+ super
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ module BlacklightOaiProvider
2
+ class ResumptionToken < ::OAI::Provider::ResumptionToken
3
+ # parses a token string and returns a ResumptionToken
4
+ def self.parse(token_string)
5
+ options = {}
6
+ total = nil
7
+ matches = /(.+):(\d+)$/.match(token_string)
8
+ options[:last] = matches.captures[1].to_i
9
+
10
+ parts = matches.captures[0].split('.')
11
+ options[:metadata_prefix] = parts.shift
12
+ parts.each do |part|
13
+ case part
14
+ when /^s/
15
+ options[:set] = part.sub(/^s\(/, '').sub(/\)$/, '')
16
+ when /^f/
17
+ options[:from] = parse_date(part.sub(/^f\(/, '').sub(/\)$/, ''))
18
+ when /^u/
19
+ options[:until] = parse_date(part.sub(/^u\(/, '').sub(/\)$/, ''))
20
+ when /^t/
21
+ total = part.sub(/^t\(/, '').sub(/\)$/, '').to_i
22
+ end
23
+ end
24
+ new(options, nil, total)
25
+ rescue StandardError
26
+ raise OAI::ResumptionTokenException
27
+ end
28
+
29
+ # Force date to be in UTC. If date does not have a timezone UTC is assumed.
30
+ # If date is a different timezone it is converted to UTC.
31
+ def self.parse_date(str)
32
+ ActiveSupport::TimeZone.new('UTC').parse(str)
33
+ end
34
+
35
+ def encode_conditions
36
+ encoded_token = @prefix.to_s.dup
37
+ encoded_token << ".s(#{set})" if set
38
+ encoded_token << ".f(#{from.utc.xmlschema})" if from
39
+ encoded_token << ".u(#{self.until.utc.xmlschema})" if self.until
40
+ encoded_token << ".t(#{total})" if total
41
+ encoded_token << ":#{last}"
42
+ end
43
+
44
+ def to_xml
45
+ xml = Builder::XmlMarkup.new
46
+ token = total && (last > total) ? '' : encode_conditions
47
+ xml.resumptionToken(token, hash_of_attributes)
48
+ xml.target!
49
+ end
50
+ end
51
+ end