europeana-blacklight 0.2.7 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.ruby-style.yml +2 -1
- data/QUICKSTART.md +42 -0
- data/README.md +31 -52
- data/app/controllers/concerns/europeana/blacklight/catalog.rb +73 -0
- data/europeana-blacklight.gemspec +4 -1
- data/lib/europeana/blacklight.rb +8 -2
- data/lib/europeana/blacklight/api_repository.rb +9 -64
- data/lib/europeana/blacklight/document.rb +15 -20
- data/lib/europeana/blacklight/document/relations.rb +25 -0
- data/lib/europeana/blacklight/document_presenter.rb +1 -1
- data/lib/europeana/blacklight/engine.rb +11 -0
- data/lib/europeana/blacklight/facet_paginator.rb +1 -1
- data/lib/europeana/blacklight/response/pagination.rb +10 -0
- data/lib/europeana/blacklight/routes.rb +26 -0
- data/lib/europeana/blacklight/search_builder.rb +42 -11
- data/lib/europeana/blacklight/search_builder/overlay_params.rb +39 -0
- data/lib/europeana/blacklight/search_builder/ranges.rb +1 -1
- data/lib/europeana/blacklight/search_helper.rb +41 -0
- data/lib/europeana/blacklight/version.rb +1 -1
- data/lib/generators/europeana/blacklight/install_generator.rb +28 -0
- data/lib/generators/europeana/blacklight/templates/catalog_controller.rb +81 -0
- data/lib/generators/europeana/blacklight/templates/config/blacklight.yml +8 -0
- metadata +61 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78442f9dbd68b04249c1bb5d6e0820ef4f75d925
|
4
|
+
data.tar.gz: bfcb4792d1cc6412a5551b76f67706f4b8aa7a6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e0cde651009ecd7b881c0f34edc745d2b431a9f4664cf168c9f436521f664b4f08e127d1e5d4efcfa3721bac065a36ea05dd313ad31dd58fd6d0079b9aca9e8
|
7
|
+
data.tar.gz: c88b697f78b65c586ac09b377e4b166b9c028de0284fc8c22ca7600c202434a069890b70e3cedcbdb57b5a9373285641beb06812860a32d7dea649febc07ab5c
|
data/.ruby-style.yml
CHANGED
@@ -6,6 +6,7 @@ AllCops:
|
|
6
6
|
Exclude:
|
7
7
|
- "vendor/**/*"
|
8
8
|
- "db/**/*"
|
9
|
+
- "lib/generators/europeana/blacklight/templates/**/*"
|
9
10
|
RunRailsCops: true
|
10
11
|
DisplayCopNames: false
|
11
12
|
StyleGuideCopsOnly: false
|
@@ -497,7 +498,7 @@ Metrics/LineLength:
|
|
497
498
|
Description: Limit lines to 80 characters.
|
498
499
|
StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits
|
499
500
|
Enabled: true
|
500
|
-
Max:
|
501
|
+
Max: 140
|
501
502
|
AllowURI: true
|
502
503
|
URISchemes:
|
503
504
|
- http
|
data/QUICKSTART.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Europeana Blacklight Quick Start Guide
|
2
|
+
|
3
|
+
## Install Rails 4
|
4
|
+
```
|
5
|
+
gem install rails
|
6
|
+
rails -v
|
7
|
+
# Rails 4.2.4
|
8
|
+
```
|
9
|
+
|
10
|
+
## Create a new Rails application
|
11
|
+
```
|
12
|
+
rails new culture_vulture
|
13
|
+
cd culture_vulture
|
14
|
+
```
|
15
|
+
|
16
|
+
## Bundle europeana-blacklight
|
17
|
+
Add to the Gemfile:
|
18
|
+
```ruby
|
19
|
+
gem 'europeana-blacklight',
|
20
|
+
github: 'europeana/europeana-blacklight',
|
21
|
+
require: 'europeana/blacklight'
|
22
|
+
```
|
23
|
+
|
24
|
+
## Get a Europeana API key
|
25
|
+
From http://labs.europeana.eu/api/
|
26
|
+
|
27
|
+
## Install Blacklight with the Europeana API adapter
|
28
|
+
```
|
29
|
+
bundle install
|
30
|
+
bundle exec rails generate blacklight:install --devise
|
31
|
+
bundle exec rails generate europeana:blacklight:install YOUR_API_KEY
|
32
|
+
bundle exec rake db:migrate
|
33
|
+
```
|
34
|
+
|
35
|
+
## Customise the config
|
36
|
+
Review the generated `CatalogController` and adjust the default configuration
|
37
|
+
to your preferences.
|
38
|
+
|
39
|
+
## Start the application
|
40
|
+
```
|
41
|
+
bundle exec rails server
|
42
|
+
```
|
data/README.md
CHANGED
@@ -1,62 +1,40 @@
|
|
1
1
|
# Europeana::Blacklight
|
2
2
|
|
3
|
-
[](https://travis-ci.org/europeana/europeana-blacklight) [](https://coveralls.io/github/europeana/europeana-blacklight?branch=master) [](https://hakiri.io/github/europeana/europeana-blacklight/master)
|
3
|
+
[](https://travis-ci.org/europeana/europeana-blacklight) [](https://coveralls.io/github/europeana/europeana-blacklight?branch=master) [](https://hakiri.io/github/europeana/europeana-blacklight/master) [](https://gemnasium.com/europeana/europeana-blacklight)
|
4
4
|
|
5
5
|
Ruby gem providing an adapter to use the
|
6
6
|
[Europeana REST API](http://labs.europeana.eu/api/introduction/) as a data
|
7
7
|
source for [Blacklight](http://projectblacklight.org/).
|
8
8
|
|
9
|
-
##
|
9
|
+
## Usage
|
10
10
|
|
11
|
-
|
11
|
+
See the [Quick Start Guide](QUICKSTART.md).
|
12
12
|
|
13
|
-
|
14
|
-
gem 'europeana-blacklight',
|
15
|
-
github: 'europeana/europeana-blacklight',
|
16
|
-
require: 'europeana/blacklight'
|
17
|
-
```
|
13
|
+
## Features
|
18
14
|
|
19
|
-
|
15
|
+
### Supported Blacklight features
|
20
16
|
|
21
|
-
|
17
|
+
* Search
|
18
|
+
* View record
|
19
|
+
* Pagination of search results
|
20
|
+
* Field facets
|
21
|
+
* [Query facets](#query-facets)
|
22
|
+
* Facet limits
|
23
|
+
* Fielded search
|
24
|
+
* Bookmarks
|
25
|
+
* Range queries
|
22
26
|
|
23
|
-
|
27
|
+
### Unsupported Blacklight features
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
```ruby
|
36
|
-
class CatalogController < ApplicationController
|
37
|
-
self.search_params_logic = Europeana::Blacklight::SearchBuilder.default_processor_chain
|
38
|
-
|
39
|
-
configure_blacklight do |config|
|
40
|
-
config.repository_class = Europeana::Blacklight::ApiRepository
|
41
|
-
config.search_builder_class = Europeana::Blacklight::SearchBuilder
|
42
|
-
config.response_model = Europeana::Blacklight::Response
|
43
|
-
config.document_model = Europeana::Blacklight::Document
|
44
|
-
config.document_presenter_class = Europeana::Blacklight::DocumentPresenter
|
45
|
-
config.facet_paginator_class = Europeana::Blacklight::FacetPaginator
|
46
|
-
end
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
4. Caching (optional)
|
51
|
-
|
52
|
-
To enable caching of API responses:
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
configure_blacklight do |config|
|
56
|
-
config.europeana_api_cache = Rails.cache # or any {ActiveSupport::Cache} instance
|
57
|
-
config.europeana_api_cache_expires_in = 60.minutes # defaults to 24.hours
|
58
|
-
end
|
59
|
-
```
|
29
|
+
* Result sorting :(
|
30
|
+
* "Did you mean" spellcheck
|
31
|
+
* MLT Solr-style (but see custom features)
|
32
|
+
|
33
|
+
### Custom features
|
34
|
+
|
35
|
+
* Nested EDM field names
|
36
|
+
* MLT by record ID in :mlt URL parameter
|
37
|
+
* Query facets with arbitrary API parameters
|
60
38
|
|
61
39
|
## Query facets
|
62
40
|
|
@@ -65,13 +43,14 @@ permit specification of multiple parameters to be passed to the API:
|
|
65
43
|
|
66
44
|
```ruby
|
67
45
|
configure_blacklight do |config|
|
68
|
-
config.add_facet_field 'Cities (reusable content)', query:
|
69
|
-
{ label: 'Paris', fq: { qf: 'paris', reusability: 'open' } },
|
70
|
-
{ label: 'Berlin', fq: { qf: 'berlin', reusability: 'open' } }
|
71
|
-
|
46
|
+
config.add_facet_field 'Cities (reusable content)', query: {
|
47
|
+
paris: { label: 'Paris', fq: { qf: 'paris', reusability: 'open' } },
|
48
|
+
berlin: { label: 'Berlin', fq: { qf: 'berlin', reusability: 'open' } }
|
49
|
+
}
|
72
50
|
end
|
73
51
|
```
|
74
52
|
|
75
53
|
*Warning:* query facets are achieved by sending additional queries to the
|
76
|
-
API. If you configure
|
77
|
-
|
54
|
+
API. If you configure 2 query facets each with 10 facet values, this will result
|
55
|
+
in an additional 20 queries being sent to the API.
|
56
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Europeana
|
2
|
+
module Blacklight
|
3
|
+
module Catalog
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
include ::Blacklight::Catalog
|
7
|
+
include Europeana::Blacklight::SearchHelper
|
8
|
+
|
9
|
+
included do
|
10
|
+
self.search_params_logic = Europeana::Blacklight::SearchBuilder.default_processor_chain
|
11
|
+
|
12
|
+
configure_blacklight do |config|
|
13
|
+
# Adapter classes
|
14
|
+
config.repository_class = Europeana::Blacklight::ApiRepository
|
15
|
+
config.search_builder_class = Europeana::Blacklight::SearchBuilder
|
16
|
+
config.response_model = Europeana::Blacklight::Response
|
17
|
+
config.document_model = Europeana::Blacklight::Document
|
18
|
+
config.document_presenter_class = Europeana::Blacklight::DocumentPresenter
|
19
|
+
# config.facet_paginator_class = Europeana::Blacklight::FacetPaginator
|
20
|
+
|
21
|
+
# Prevent BL's "did you mean" spellcheck feature kicking in
|
22
|
+
config.spell_max = -1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Empty search returns all records
|
27
|
+
def has_search_parameters?
|
28
|
+
super || params.key?(:q) || params.key?(:mlt)
|
29
|
+
end
|
30
|
+
|
31
|
+
def search_results(user_params, _search_params_logic)
|
32
|
+
super.tap do |results|
|
33
|
+
if has_search_parameters?
|
34
|
+
results.first[:facet_queries] = europeana_api_query_facet_counts(user_params)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def blacklight_query_facets
|
42
|
+
blacklight_config.facet_fields.select do |_, facet|
|
43
|
+
facet.query &&
|
44
|
+
(facet.include_in_request ||
|
45
|
+
(facet.include_in_request.nil? &&
|
46
|
+
blacklight_config.add_facet_fields_to_solr_request))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def europeana_api_query_facet_counts(user_params)
|
51
|
+
qf_counts = []
|
52
|
+
|
53
|
+
blacklight_query_facets.each_pair do |_facet_name, query_facet|
|
54
|
+
query_facet.query.each_pair do |_field_name, query_field|
|
55
|
+
count = europeana_api_query_facet_count(query_field[:fq], user_params)
|
56
|
+
qf_counts.push([query_field[:fq], count])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
qf_counts.sort_by(&:last).reverse.each_with_object({}) do |qf, hash|
|
61
|
+
hash[qf.first] = qf.last
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def europeana_api_query_facet_count(query_field_fq, user_params)
|
66
|
+
query = search_builder_class.new(search_params_logic, self).
|
67
|
+
with(user_params).with_overlay_params(query_field_fq || {}).query.
|
68
|
+
merge(rows: 0, start: 1, profile: 'minimal')
|
69
|
+
repository.search(query).total
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -20,12 +20,15 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
|
+
spec.add_dependency 'activesupport', '>= 4.0', '< 5.0'
|
23
24
|
spec.add_dependency 'blacklight', '>= 5.12.0', '< 6.0.0'
|
24
|
-
spec.add_dependency 'europeana-api', '~> 0.
|
25
|
+
spec.add_dependency 'europeana-api', '~> 0.4.0'
|
25
26
|
spec.add_dependency 'iso-639', '~> 0.2.5'
|
26
27
|
spec.add_dependency 'kaminari', '~> 0.16'
|
27
28
|
|
28
29
|
spec.add_development_dependency 'bundler', '~> 1.8'
|
29
30
|
spec.add_development_dependency 'rake', '~> 10.0'
|
30
31
|
spec.add_development_dependency 'rspec', '~> 3.2'
|
32
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 2.8'
|
33
|
+
spec.add_development_dependency 'webmock', '~> 1.21'
|
31
34
|
end
|
data/lib/europeana/blacklight.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
3
3
|
require 'blacklight'
|
4
|
+
require 'europeana/api'
|
5
|
+
require 'europeana/blacklight/engine' if defined?(Rails)
|
6
|
+
require 'europeana/blacklight/version'
|
4
7
|
|
5
8
|
module Europeana
|
6
9
|
##
|
@@ -9,7 +12,10 @@ module Europeana
|
|
9
12
|
autoload :ApiRepository, 'europeana/blacklight/api_repository'
|
10
13
|
autoload :Document, 'europeana/blacklight/document'
|
11
14
|
autoload :DocumentPresenter, 'europeana/blacklight/document_presenter'
|
15
|
+
# autoload :FacetPaginator, 'europeana/blacklight/facet_paginator'
|
12
16
|
autoload :Response, 'europeana/blacklight/response'
|
17
|
+
autoload :Routes, 'europeana/blacklight/routes'
|
13
18
|
autoload :SearchBuilder, 'europeana/blacklight/search_builder'
|
19
|
+
autoload :SearchHelper, 'europeana/blacklight/search_helper'
|
14
20
|
end
|
15
21
|
end
|
@@ -13,11 +13,7 @@ module Europeana
|
|
13
13
|
# @return (see blacklight_config.response_model)
|
14
14
|
def find(id, params = {})
|
15
15
|
id = "/#{id}" unless id[0] == '/'
|
16
|
-
|
17
|
-
cache_key << ':' + params.to_query unless params.blank?
|
18
|
-
res = cached(cache_key) do
|
19
|
-
connection.record(id, auth_params(params))
|
20
|
-
end
|
16
|
+
res = connection.record(id, params)
|
21
17
|
|
22
18
|
blacklight_config.response_model.new(
|
23
19
|
res, params, document_model: blacklight_config.document_model,
|
@@ -26,10 +22,7 @@ module Europeana
|
|
26
22
|
end
|
27
23
|
|
28
24
|
def search(params = {})
|
29
|
-
|
30
|
-
res = cached(cache_key) do
|
31
|
-
connection.search(auth_params(params))
|
32
|
-
end
|
25
|
+
res = connection.search(params)
|
33
26
|
|
34
27
|
blacklight_config.response_model.new(
|
35
28
|
res, params, document_model: blacklight_config.document_model,
|
@@ -37,46 +30,6 @@ module Europeana
|
|
37
30
|
)
|
38
31
|
end
|
39
32
|
|
40
|
-
##
|
41
|
-
# Fetches the hierarchy data for a Europeana record
|
42
|
-
#
|
43
|
-
# If the hierarchy data for the requested record is cached, that will be
|
44
|
-
# returned, otherwise it will be obtained from the Europeana REST API.
|
45
|
-
#
|
46
|
-
# @param id [String] Europeana record ID, with leading slash
|
47
|
-
# @return [Hash] Record's hierarchy data, or false if it has none
|
48
|
-
def fetch_document_hierarchy(id)
|
49
|
-
cached("Europeana:API:Record:hierarchy:#{id}") do
|
50
|
-
begin
|
51
|
-
europeana_api_document_hierarchy(id)
|
52
|
-
rescue Europeana::API::Errors::RequestError => error
|
53
|
-
unless error.message == 'This record has no hierarchical structure!'
|
54
|
-
raise
|
55
|
-
end
|
56
|
-
false
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
##
|
62
|
-
# Requests hierarchy data for a Europeana record from the REST API
|
63
|
-
#
|
64
|
-
# The return value will contain a combination of the responses from the
|
65
|
-
# ancestor-self-siblings and children API endpoints.
|
66
|
-
#
|
67
|
-
# @param id [String] Europeana record ID, with leading slash
|
68
|
-
# @return [Hash] Record's hierarchy data
|
69
|
-
def europeana_api_document_hierarchy(id)
|
70
|
-
record = Europeana::API::Record.new(id, auth_params)
|
71
|
-
hierarchy = record.hierarchy('ancestor-self-siblings')
|
72
|
-
|
73
|
-
if hierarchy['self']['hasChildren']
|
74
|
-
hierarchy = record.hierarchy('ancestor-self-siblings', :children)
|
75
|
-
end
|
76
|
-
|
77
|
-
hierarchy
|
78
|
-
end
|
79
|
-
|
80
33
|
##
|
81
34
|
# Queries the API for items similar to a given document
|
82
35
|
def more_like_this(doc, field = nil, params = {})
|
@@ -88,19 +41,17 @@ module Europeana
|
|
88
41
|
end
|
89
42
|
|
90
43
|
def build_connection
|
91
|
-
Europeana::API
|
44
|
+
Europeana::API.tap do |api|
|
45
|
+
api.api_key = blacklight_config.connection_config[:europeana_api_key]
|
46
|
+
api.cache_store = cache_store
|
47
|
+
api.cache_expires_in = cache_expires_in
|
48
|
+
end
|
92
49
|
end
|
93
50
|
|
94
51
|
protected
|
95
52
|
|
96
|
-
def
|
97
|
-
|
98
|
-
wskey: blacklight_config.connection_config[:europeana_api_key]
|
99
|
-
}.merge(params)
|
100
|
-
end
|
101
|
-
|
102
|
-
def cache
|
103
|
-
@cache ||= begin
|
53
|
+
def cache_store
|
54
|
+
@cache_store ||= begin
|
104
55
|
blacklight_config.europeana_api_cache || ActiveSupport::Cache::NullStore.new
|
105
56
|
end
|
106
57
|
end
|
@@ -110,12 +61,6 @@ module Europeana
|
|
110
61
|
blacklight_config.europeana_api_cache_expires_in || 24.hours
|
111
62
|
end
|
112
63
|
end
|
113
|
-
|
114
|
-
def cached(key)
|
115
|
-
cache.fetch(key, expires_in: cache_expires_in) do
|
116
|
-
yield
|
117
|
-
end
|
118
|
-
end
|
119
64
|
end
|
120
65
|
end
|
121
66
|
end
|
@@ -12,11 +12,11 @@ module Europeana
|
|
12
12
|
|
13
13
|
include ActiveModel::Conversion
|
14
14
|
include ::Blacklight::Document
|
15
|
+
include ::Blacklight::Document::ActiveModelShim
|
15
16
|
include MoreLikeThis
|
16
17
|
include Relations
|
17
18
|
|
18
19
|
attr_writer :provider_id, :record_id
|
19
|
-
attr_accessor :hierarchy
|
20
20
|
|
21
21
|
class << self
|
22
22
|
# @todo Are three-letter language codes valid in EDM?
|
@@ -24,7 +24,12 @@ module Europeana
|
|
24
24
|
# output; remove when fixed at source
|
25
25
|
def lang_map?(obj)
|
26
26
|
return false unless obj.is_a?(Hash)
|
27
|
-
obj.keys.all? { |
|
27
|
+
obj.keys.map(&:to_s).all? { |key| known_lang_map_key?(key) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def known_lang_map_key?(key)
|
31
|
+
key = key.dup.downcase
|
32
|
+
['def', '', 'sh'].include?(key) || (!ISO_639.find(key.split('-').first).nil?)
|
28
33
|
end
|
29
34
|
|
30
35
|
def localize_lang_map(lang_map)
|
@@ -49,6 +54,8 @@ module Europeana
|
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
57
|
+
delegate :lang_map?, :localize_lang_map, to: :class
|
58
|
+
|
52
59
|
def initialize(source_doc = {}, response = nil)
|
53
60
|
fields, @relations = extract_relations(source_doc)
|
54
61
|
super(fields, response)
|
@@ -86,11 +93,11 @@ module Europeana
|
|
86
93
|
true
|
87
94
|
end
|
88
95
|
|
89
|
-
def private?(
|
90
|
-
|
96
|
+
def private?(_exhibit)
|
97
|
+
false
|
91
98
|
end
|
92
99
|
|
93
|
-
def public?(
|
100
|
+
def public?(_exhibit)
|
94
101
|
true
|
95
102
|
end
|
96
103
|
|
@@ -102,25 +109,13 @@ module Europeana
|
|
102
109
|
@record_id ||= id.to_s.split('/')[2]
|
103
110
|
end
|
104
111
|
|
105
|
-
def as_json(options =
|
106
|
-
|
107
|
-
unless @hierarchy.nil?
|
108
|
-
json.merge!('hierarchy' => @hierarchy.as_json(options))
|
109
|
-
end
|
110
|
-
json.tap do |j|
|
112
|
+
def as_json(options = {})
|
113
|
+
super.tap do |json|
|
111
114
|
relations.each do |k, v|
|
112
|
-
|
115
|
+
json[k] = v.as_json
|
113
116
|
end
|
114
117
|
end
|
115
118
|
end
|
116
|
-
|
117
|
-
def lang_map?(obj)
|
118
|
-
self.class.lang_map?(obj)
|
119
|
-
end
|
120
|
-
|
121
|
-
def localize_lang_map(lang_map)
|
122
|
-
self.class.localize_lang_map(lang_map)
|
123
|
-
end
|
124
119
|
end
|
125
120
|
end
|
126
121
|
end
|
@@ -68,6 +68,31 @@ module Europeana
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def has?(k, *values)
|
72
|
+
if !key?(k)
|
73
|
+
false
|
74
|
+
elsif values.empty?
|
75
|
+
fetch(k, nil).present?
|
76
|
+
else
|
77
|
+
Array(values).any? do |expected|
|
78
|
+
Array(fetch(k, nil)).any? do |actual|
|
79
|
+
case expected
|
80
|
+
when Regexp
|
81
|
+
actual =~ expected
|
82
|
+
else
|
83
|
+
actual == expected
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def key?(k)
|
91
|
+
[nested_field_container(k)].flatten.any? do |container|
|
92
|
+
container._source.key?(nested_field_key(k))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
71
96
|
def has_relation?(name)
|
72
97
|
relations.key?(name.to_s)
|
73
98
|
end
|
@@ -3,7 +3,7 @@ module Europeana
|
|
3
3
|
##
|
4
4
|
# Blacklight document presenter for Europeana documents
|
5
5
|
class DocumentPresenter < ::Blacklight::DocumentPresenter
|
6
|
-
include ActionView::Helpers::AssetTagHelper
|
6
|
+
include ActionView::Helpers::AssetTagHelper # ?
|
7
7
|
|
8
8
|
def render_document_show_field_value(field, options = {})
|
9
9
|
render_nested_field_value(field, :show, options)
|
@@ -10,6 +10,7 @@ module Europeana
|
|
10
10
|
module Pagination
|
11
11
|
include Kaminari::PageScopeMethods
|
12
12
|
include Kaminari::ConfigurationMethods::ClassMethods
|
13
|
+
extend ActiveSupport::Concern
|
13
14
|
|
14
15
|
def limit_value
|
15
16
|
rows
|
@@ -28,6 +29,15 @@ module Europeana
|
|
28
29
|
docs.first.model_name
|
29
30
|
end
|
30
31
|
|
32
|
+
def max_pages
|
33
|
+
(defined?(@_max_pages) && @_max_pages) || (1000 / limit_value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def total_pages
|
37
|
+
total = super
|
38
|
+
total > max_pages ? max_pages : total
|
39
|
+
end
|
40
|
+
|
31
41
|
def next_page
|
32
42
|
current_page + 1 unless last_page?
|
33
43
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Europeana
|
2
|
+
module Blacklight
|
3
|
+
##
|
4
|
+
# URL routing for Blacklight
|
5
|
+
module Routes
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do |klass|
|
9
|
+
klass.default_route_sets -= [:solr_document]
|
10
|
+
unless klass.default_route_sets.include?(:europeana_document)
|
11
|
+
klass.default_route_sets += [:europeana_document]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def europeana_document(primary_resource)
|
16
|
+
add_routes do |options|
|
17
|
+
args = { only: [:show] }
|
18
|
+
args[:constraints] = options[:constraints] if options[:constraints]
|
19
|
+
|
20
|
+
post 'record/*id/track', args.merge(to: "#{primary_resource}#track", as: 'track_document')
|
21
|
+
get 'record/*id', args.merge(to: "#{primary_resource}#show", as: 'document')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -5,21 +5,26 @@ module Europeana
|
|
5
5
|
class SearchBuilder < ::Blacklight::SearchBuilder
|
6
6
|
require 'europeana/blacklight/search_builder/facet_pagination'
|
7
7
|
require 'europeana/blacklight/search_builder/more_like_this'
|
8
|
+
require 'europeana/blacklight/search_builder/overlay_params'
|
8
9
|
require 'europeana/blacklight/search_builder/ranges'
|
9
10
|
|
11
|
+
attr_accessor :default_processor_chain
|
10
12
|
self.default_processor_chain = [
|
11
13
|
:default_api_parameters, :add_profile_to_api,
|
12
|
-
:add_query_to_api, :add_qf_to_api, :add_facet_qf_to_api,
|
13
|
-
:
|
14
|
+
:add_query_to_api, :add_qf_to_api, :add_facet_qf_to_api, :add_query_facet_to_api,
|
15
|
+
:add_standalone_facets_to_api, :add_facetting_to_api, :add_paging_to_api,
|
14
16
|
:add_sorting_to_api
|
15
17
|
]
|
16
18
|
|
17
19
|
include FacetPagination
|
18
20
|
include MoreLikeThis
|
19
21
|
include Ranges
|
22
|
+
include OverlayParams
|
20
23
|
|
21
24
|
delegate :to_query, to: :to_hash
|
22
25
|
|
26
|
+
STANDALONE_FACETS = %w(COLOURPALETTE MEDIA REUSABILITY)
|
27
|
+
|
23
28
|
##
|
24
29
|
# Start with general defaults from BL config. Need to use custom
|
25
30
|
# merge to dup values, to avoid later mutating the original by mistake.
|
@@ -87,23 +92,47 @@ module Europeana
|
|
87
92
|
def add_facet_qf_to_api(api_parameters)
|
88
93
|
return unless blacklight_params[:f]
|
89
94
|
|
90
|
-
salient_facets = blacklight_params[:f].
|
91
|
-
k
|
95
|
+
salient_facets = blacklight_params[:f].select do |k, _v|
|
96
|
+
!STANDALONE_FACETS.include?(k) && api_request_facet_fields.keys.include?(k)
|
92
97
|
end
|
93
98
|
|
94
99
|
salient_facets.each_pair do |facet_field, value_list|
|
95
100
|
Array(value_list).reject(&:blank?).each do |value|
|
96
101
|
api_parameters[:qf] ||= []
|
97
|
-
|
102
|
+
if Europeana::API::Search::Fields::MEDIA.include?(facet_field)
|
103
|
+
api_parameters[:qf] << "#{facet_field}:#{value}"
|
104
|
+
else
|
105
|
+
api_parameters[:qf] << "#{facet_field}:\"#{value}\""
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Filter results by a query facet
|
113
|
+
def add_query_facet_to_api(_api_parameters)
|
114
|
+
return unless blacklight_params[:f]
|
115
|
+
|
116
|
+
salient_facets = blacklight_params[:f].select do |k, _v|
|
117
|
+
facet = blacklight_config.facet_fields[k]
|
118
|
+
facet.query && (facet.include_in_request || (facet.include_in_request.nil? && blacklight_config.add_facet_fields_to_solr_request))
|
119
|
+
end
|
120
|
+
|
121
|
+
salient_facets.each_pair do |facet_field, value_list|
|
122
|
+
Array(value_list).reject(&:blank?).each do |value|
|
123
|
+
with_overlay_params(blacklight_config.facet_fields[facet_field].query[value][:fq])
|
98
124
|
end
|
99
125
|
end
|
100
126
|
end
|
101
127
|
|
102
|
-
|
103
|
-
#
|
104
|
-
|
105
|
-
|
106
|
-
|
128
|
+
##
|
129
|
+
# Some facets need to be filtered as distinct API params, even though
|
130
|
+
# they are returned with the facets in a search response
|
131
|
+
def add_standalone_facets_to_api(api_parameters)
|
132
|
+
STANDALONE_FACETS.each do |field|
|
133
|
+
if blacklight_params[:f] && blacklight_params[:f][field]
|
134
|
+
api_parameters[field.downcase.to_sym] = blacklight_params[:f][field].join(',')
|
135
|
+
end
|
107
136
|
end
|
108
137
|
end
|
109
138
|
|
@@ -115,7 +144,9 @@ module Europeana
|
|
115
144
|
# @see http://labs.europeana.eu/api/search/#individual-facets
|
116
145
|
# @see http://labs.europeana.eu/api/search/#offset-and-limit-of-facets
|
117
146
|
def add_facetting_to_api(api_parameters)
|
118
|
-
api_parameters[:facet] = api_request_facet_fields.keys.
|
147
|
+
api_parameters[:facet] = api_request_facet_fields.keys.map do |field|
|
148
|
+
Europeana::API::Search::Fields::MEDIA.include?(field) ? 'DEFAULT' : field
|
149
|
+
end.uniq.join(',')
|
119
150
|
|
120
151
|
api_request_facet_fields.each do |field_name, facet|
|
121
152
|
api_parameters[:"f.#{facet.field}.facet.limit"] = (facet_limit_for(field_name) + 1) if facet_limit_for(field_name)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Europeana
|
2
|
+
module Blacklight
|
3
|
+
class SearchBuilder
|
4
|
+
##
|
5
|
+
# "Overlay" params do not replace others, but are combined with them, into
|
6
|
+
# multiple values for those param keys
|
7
|
+
module OverlayParams
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
default_processor_chain << :add_overlay_params_to_api
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_overlay_params(overlay_params = {})
|
15
|
+
@overlay_params ||= []
|
16
|
+
@overlay_params << overlay_params
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_overlay_params_to_api(api_parameters)
|
21
|
+
return unless @overlay_params
|
22
|
+
|
23
|
+
@overlay_params.each do |param_set|
|
24
|
+
param_set.each_pair do |k, v|
|
25
|
+
k = k.to_sym
|
26
|
+
if api_parameters.key?(k)
|
27
|
+
api_parameters[k] = [api_parameters[k]].flatten # in case it's not an Array
|
28
|
+
else
|
29
|
+
api_parameters[k] = []
|
30
|
+
end
|
31
|
+
api_parameters[k] += [v]
|
32
|
+
api_parameters[k] = api_parameters[k].flatten.uniq
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Europeana
|
2
|
+
module Blacklight
|
3
|
+
##
|
4
|
+
# Local overrides for {Blacklight::SearchHelper}
|
5
|
+
module SearchHelper
|
6
|
+
def previous_and_next_document_params(index, window = 1)
|
7
|
+
api_params = {}
|
8
|
+
|
9
|
+
if index > 1
|
10
|
+
api_params[:start] = index - window # get one before
|
11
|
+
api_params[:rows] = 2 * window + 1 # and one after
|
12
|
+
else
|
13
|
+
api_params[:start] = 1 # there is no previous doc
|
14
|
+
api_params[:rows] = 2 * window # but there should be one after
|
15
|
+
end
|
16
|
+
|
17
|
+
api_params
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def fetch_many(ids = [], *args)
|
23
|
+
if args.length == 1
|
24
|
+
user_params = params
|
25
|
+
extra_controller_params = args.first || {}
|
26
|
+
else
|
27
|
+
user_params, extra_controller_params = args
|
28
|
+
user_params ||= params
|
29
|
+
extra_controller_params ||= {}
|
30
|
+
end
|
31
|
+
|
32
|
+
id_query = ids.map { |id| "europeana_id:\"/#{id}\"" }.join(' OR ')
|
33
|
+
|
34
|
+
query = search_builder.with(user_params).where(id_query)
|
35
|
+
api_response = repository.search(query.merge(extra_controller_params))
|
36
|
+
|
37
|
+
[api_response, api_response.documents]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Europeana
|
2
|
+
module Blacklight
|
3
|
+
class Install < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
argument :europeana_api_key, type: :string
|
7
|
+
argument :controller_name, type: :string, default: 'catalog'
|
8
|
+
|
9
|
+
def disable_rsolr_gem
|
10
|
+
comment_lines('Gemfile', /gem 'rsolr'/)
|
11
|
+
end
|
12
|
+
|
13
|
+
def bundle_install
|
14
|
+
Bundler.with_clean_env do
|
15
|
+
run 'bundle install'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_configuration_files
|
20
|
+
template 'config/blacklight.yml', 'config/blacklight.yml'
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_controller
|
24
|
+
template 'catalog_controller.rb', "app/controllers/#{controller_name}_controller.rb"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class <%= controller_name.classify %>Controller < ApplicationController
|
3
|
+
include Europeana::Blacklight::Catalog
|
4
|
+
|
5
|
+
configure_blacklight do |config|
|
6
|
+
# Europeana API caching
|
7
|
+
config.europeana_api_cache = Rails.cache
|
8
|
+
config.europeana_api_cache_expires_in = 24.hours
|
9
|
+
|
10
|
+
# Default parameters to send to Europeana for all search-like requests.
|
11
|
+
# @see SolrHelper#solr_search_params
|
12
|
+
config.default_solr_params = {
|
13
|
+
rows: 24
|
14
|
+
}
|
15
|
+
|
16
|
+
# items to show per page, each number in the array represents another
|
17
|
+
# option to choose from.
|
18
|
+
config.per_page = [12, 24, 48, 96]
|
19
|
+
|
20
|
+
# Field configuration for search results/index views
|
21
|
+
config.index.title_field = 'title'
|
22
|
+
config.index.display_type_field = 'type'
|
23
|
+
config.index.timestamp_field = nil # Europeana's is in microseconds
|
24
|
+
config.index.thumbnail_field = 'edmPreview'
|
25
|
+
|
26
|
+
# Fields to be displayed in the index (search results) view
|
27
|
+
# The ordering of the field names is the order of the display
|
28
|
+
# @see http://labs.europeana.eu/api/data-fields
|
29
|
+
config.add_index_field 'edmAgentLabelLangAware', label: 'Creator'
|
30
|
+
config.add_index_field 'dcDescription', label: 'Description'
|
31
|
+
config.add_index_field 'edmConceptPrefLabelLangAware',
|
32
|
+
separator: '; ', limit: 4, label: 'Subject'
|
33
|
+
config.add_index_field 'year', label: 'Year'
|
34
|
+
config.add_index_field 'dataProvider', label: 'Data provider'
|
35
|
+
|
36
|
+
# Facet fields in the order they should be displayed.
|
37
|
+
# @see http://labs.europeana.eu/api/search#individual-facets
|
38
|
+
config.add_facet_field 'TYPE'
|
39
|
+
config.add_facet_field 'REUSABILITY'
|
40
|
+
config.add_facet_field 'COUNTRY'
|
41
|
+
config.add_facet_field 'LANGUAGE'
|
42
|
+
config.add_facet_field 'PROVIDER'
|
43
|
+
config.add_facet_field 'DATA_PROVIDER'
|
44
|
+
config.add_facet_field 'YEAR'
|
45
|
+
config.add_facet_field 'RIGHTS'
|
46
|
+
|
47
|
+
# Send all facet field names to the API.
|
48
|
+
config.add_facet_fields_to_solr_request!
|
49
|
+
|
50
|
+
# Fields to be displayed in the object view, in the order of display.
|
51
|
+
config.add_show_field 'agents.prefLabel', label: 'Agents'
|
52
|
+
config.add_show_field 'agents.begin', label: 'Start date'
|
53
|
+
config.add_show_field 'agents.end', label: 'End date'
|
54
|
+
config.add_show_field 'proxies.dcType', label: 'Type'
|
55
|
+
config.add_show_field 'proxies.dcCreator', label: 'Creator'
|
56
|
+
config.add_show_field 'proxies.dcFormat', label: 'Format'
|
57
|
+
config.add_show_field 'proxies.dcIdentifier', label: 'Identifier'
|
58
|
+
config.add_show_field 'proxies.dctermsCreated', label: 'Created'
|
59
|
+
config.add_show_field 'aggregations.webResources.dctermsCreated', label: 'Created'
|
60
|
+
config.add_show_field 'proxies.dctermsExtent', label: 'Extent'
|
61
|
+
config.add_show_field 'europeanaAggregation.edmCountry', label: 'Country'
|
62
|
+
config.add_show_field 'edmDatasetName', label: 'Dataset name'
|
63
|
+
config.add_show_field 'aggregations.edmIsShownAt', label: 'Is shown at'
|
64
|
+
config.add_show_field 'aggregations.edmIsShownBy', label: 'Is shown by'
|
65
|
+
config.add_show_field 'europeanaAggregation.edmLanguage', label: 'Language'
|
66
|
+
config.add_show_field 'europeanaAggregation.edmPreview', label: 'Preview'
|
67
|
+
config.add_show_field 'aggregations.edmProvider', label: 'Provider'
|
68
|
+
config.add_show_field 'aggregations.edmDataProvider', label: 'Data provider'
|
69
|
+
config.add_show_field 'aggregations.edmRights', label: 'Rights'
|
70
|
+
config.add_show_field 'places.latitude', label: 'Latitude'
|
71
|
+
config.add_show_field 'places.longitude', label: 'Longitude'
|
72
|
+
config.add_show_field 'type', label: 'Type'
|
73
|
+
config.add_show_field 'year', label: 'Year'
|
74
|
+
|
75
|
+
# "fielded" search configuration.
|
76
|
+
config.add_search_field('', label: 'All Fields')
|
77
|
+
%w(title who what when where subject).each do |field_name|
|
78
|
+
config.add_search_field(field_name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: europeana-blacklight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Doe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
name: blacklight
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -36,14 +56,14 @@ dependencies:
|
|
36
56
|
requirements:
|
37
57
|
- - "~>"
|
38
58
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
59
|
+
version: 0.4.0
|
40
60
|
type: :runtime
|
41
61
|
prerelease: false
|
42
62
|
version_requirements: !ruby/object:Gem::Requirement
|
43
63
|
requirements:
|
44
64
|
- - "~>"
|
45
65
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
66
|
+
version: 0.4.0
|
47
67
|
- !ruby/object:Gem::Dependency
|
48
68
|
name: iso-639
|
49
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,6 +134,34 @@ dependencies:
|
|
114
134
|
- - "~>"
|
115
135
|
- !ruby/object:Gem::Version
|
116
136
|
version: '3.2'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: shoulda-matchers
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '2.8'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - "~>"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '2.8'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: webmock
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '1.21'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - "~>"
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '1.21'
|
117
165
|
description:
|
118
166
|
email:
|
119
167
|
- richard.doe@rwdit.net
|
@@ -129,8 +177,10 @@ files:
|
|
129
177
|
- ".travis.yml"
|
130
178
|
- Gemfile
|
131
179
|
- LICENSE.md
|
180
|
+
- QUICKSTART.md
|
132
181
|
- README.md
|
133
182
|
- Rakefile
|
183
|
+
- app/controllers/concerns/europeana/blacklight/catalog.rb
|
134
184
|
- bin/console
|
135
185
|
- bin/setup
|
136
186
|
- europeana-blacklight.gemspec
|
@@ -140,16 +190,23 @@ files:
|
|
140
190
|
- lib/europeana/blacklight/document/more_like_this.rb
|
141
191
|
- lib/europeana/blacklight/document/relations.rb
|
142
192
|
- lib/europeana/blacklight/document_presenter.rb
|
193
|
+
- lib/europeana/blacklight/engine.rb
|
143
194
|
- lib/europeana/blacklight/facet_paginator.rb
|
144
195
|
- lib/europeana/blacklight/response.rb
|
145
196
|
- lib/europeana/blacklight/response/facets.rb
|
146
197
|
- lib/europeana/blacklight/response/more_like_this.rb
|
147
198
|
- lib/europeana/blacklight/response/pagination.rb
|
199
|
+
- lib/europeana/blacklight/routes.rb
|
148
200
|
- lib/europeana/blacklight/search_builder.rb
|
149
201
|
- lib/europeana/blacklight/search_builder/facet_pagination.rb
|
150
202
|
- lib/europeana/blacklight/search_builder/more_like_this.rb
|
203
|
+
- lib/europeana/blacklight/search_builder/overlay_params.rb
|
151
204
|
- lib/europeana/blacklight/search_builder/ranges.rb
|
205
|
+
- lib/europeana/blacklight/search_helper.rb
|
152
206
|
- lib/europeana/blacklight/version.rb
|
207
|
+
- lib/generators/europeana/blacklight/install_generator.rb
|
208
|
+
- lib/generators/europeana/blacklight/templates/catalog_controller.rb
|
209
|
+
- lib/generators/europeana/blacklight/templates/config/blacklight.yml
|
153
210
|
homepage: https://github.com/europeana/europeana-blacklight
|
154
211
|
licenses:
|
155
212
|
- EUPL 1.1
|