supplejack_api 1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +80 -0
- data/Rakefile +42 -0
- data/app/assets/javascripts/supplejack_api/application.js +26 -0
- data/app/assets/stylesheets/supplejack_api/application.css +30 -0
- data/app/controllers/supplejack_api/admin/base_controller.rb +24 -0
- data/app/controllers/supplejack_api/admin/sessions_controller.rb +25 -0
- data/app/controllers/supplejack_api/admin/site_activities_controller.rb +21 -0
- data/app/controllers/supplejack_api/admin/users_controller.rb +55 -0
- data/app/controllers/supplejack_api/application_controller.rb +70 -0
- data/app/controllers/supplejack_api/concepts_controller.rb +52 -0
- data/app/controllers/supplejack_api/concerns/ignore_metrics.rb +14 -0
- data/app/controllers/supplejack_api/concerns/records_controller_metrics.rb +26 -0
- data/app/controllers/supplejack_api/concerns/set_items_controller_metrics.rb +20 -0
- data/app/controllers/supplejack_api/concerns/user_sets_controller_metrics.rb +26 -0
- data/app/controllers/supplejack_api/harvester/concepts_controller.rb +41 -0
- data/app/controllers/supplejack_api/harvester/fragments_controller.rb +30 -0
- data/app/controllers/supplejack_api/harvester/records_controller.rb +68 -0
- data/app/controllers/supplejack_api/metrics_api_controller.rb +44 -0
- data/app/controllers/supplejack_api/partners_controller.rb +39 -0
- data/app/controllers/supplejack_api/records_controller.rb +71 -0
- data/app/controllers/supplejack_api/schema_controller.rb +19 -0
- data/app/controllers/supplejack_api/set_items_controller.rb +38 -0
- data/app/controllers/supplejack_api/sources_controller.rb +67 -0
- data/app/controllers/supplejack_api/status_controller.rb +67 -0
- data/app/controllers/supplejack_api/user_sets_controller.rb +97 -0
- data/app/controllers/supplejack_api/users_controller.rb +49 -0
- data/app/helpers/supplejack_api/application_helper.rb +39 -0
- data/app/helpers/supplejack_api/facets_helper.rb +30 -0
- data/app/mailers/supplejack_api/request_limit_mailer.rb +43 -0
- data/app/models/supplejack_api/api_concept/concept_fragment.rb +31 -0
- data/app/models/supplejack_api/api_record/record_fragment.rb +15 -0
- data/app/models/supplejack_api/concept.rb +46 -0
- data/app/models/supplejack_api/concept_search.rb +86 -0
- data/app/models/supplejack_api/concerns/queryable_by_date.rb +31 -0
- data/app/models/supplejack_api/concerns/record.rb +108 -0
- data/app/models/supplejack_api/concerns/record_fragmentable.rb +24 -0
- data/app/models/supplejack_api/concerns/searchable.rb +430 -0
- data/app/models/supplejack_api/concerns/user_set.rb +219 -0
- data/app/models/supplejack_api/daily_metrics.rb +20 -0
- data/app/models/supplejack_api/faceted_metrics.rb +55 -0
- data/app/models/supplejack_api/fragment.rb +82 -0
- data/app/models/supplejack_api/interaction_models/record.rb +60 -0
- data/app/models/supplejack_api/interaction_models/set.rb +13 -0
- data/app/models/supplejack_api/interaction_updaters/all_usage_metric.rb +41 -0
- data/app/models/supplejack_api/interaction_updaters/set_metrics.rb +32 -0
- data/app/models/supplejack_api/interaction_updaters/usage_metrics.rb +73 -0
- data/app/models/supplejack_api/partner.rb +24 -0
- data/app/models/supplejack_api/preview_record.rb +30 -0
- data/app/models/supplejack_api/record.rb +18 -0
- data/app/models/supplejack_api/record_search.rb +12 -0
- data/app/models/supplejack_api/schema_definition.rb +147 -0
- data/app/models/supplejack_api/search.rb +14 -0
- data/app/models/supplejack_api/set_item.rb +57 -0
- data/app/models/supplejack_api/site_activity.rb +59 -0
- data/app/models/supplejack_api/source.rb +28 -0
- data/app/models/supplejack_api/source_activity.rb +36 -0
- data/app/models/supplejack_api/source_authority.rb +42 -0
- data/app/models/supplejack_api/supplejack_schema.rb +37 -0
- data/app/models/supplejack_api/support/concept/searchable.rb +79 -0
- data/app/models/supplejack_api/support/concept/storable.rb +59 -0
- data/app/models/supplejack_api/support/fragment_helpers.rb +96 -0
- data/app/models/supplejack_api/support/harvestable.rb +105 -0
- data/app/models/supplejack_api/support/searchable.rb +115 -0
- data/app/models/supplejack_api/support/status_logger.rb +23 -0
- data/app/models/supplejack_api/support/storable.rb +49 -0
- data/app/models/supplejack_api/support/validation_logger.rb +23 -0
- data/app/models/supplejack_api/usage_metrics.rb +25 -0
- data/app/models/supplejack_api/user.rb +211 -0
- data/app/models/supplejack_api/user_activity.rb +65 -0
- data/app/models/supplejack_api/user_set.rb +17 -0
- data/app/serializers/supplejack_api/application_serializer.rb +12 -0
- data/app/serializers/supplejack_api/concept_record_serializer.rb +23 -0
- data/app/serializers/supplejack_api/concept_search_serializer.rb +12 -0
- data/app/serializers/supplejack_api/concept_serializer.rb +100 -0
- data/app/serializers/supplejack_api/concerns/record_serializable.rb +119 -0
- data/app/serializers/supplejack_api/concerns/search_serializable.rb +24 -0
- data/app/serializers/supplejack_api/record_search_serializer.rb +64 -0
- data/app/serializers/supplejack_api/record_serializer.rb +13 -0
- data/app/serializers/supplejack_api/search_serializer.rb +13 -0
- data/app/serializers/supplejack_api/source_authority_serializer.rb +23 -0
- data/app/serializers/supplejack_api/user_serializer.rb +13 -0
- data/app/serializers/supplejack_api/user_set_record_serializer.rb +14 -0
- data/app/serializers/supplejack_api/user_set_serializer.rb +77 -0
- data/app/services/metrics_api/v3/api.rb +30 -0
- data/app/services/metrics_api/v3/endpoints/facets.rb +23 -0
- data/app/services/metrics_api/v3/endpoints/global.rb +26 -0
- data/app/services/metrics_api/v3/endpoints/helpers.rb +14 -0
- data/app/services/metrics_api/v3/endpoints/root.rb +97 -0
- data/app/services/metrics_api/v3/presenters/daily_metric.rb +23 -0
- data/app/services/metrics_api/v3/presenters/extended_metadata.rb +41 -0
- data/app/services/metrics_api/v3/presenters/record.rb +26 -0
- data/app/services/metrics_api/v3/presenters/view.rb +28 -0
- data/app/views/layouts/supplejack_api/_head.html.erb +17 -0
- data/app/views/layouts/supplejack_api/_top_nav.html.erb +33 -0
- data/app/views/layouts/supplejack_api/application.html.erb +33 -0
- data/app/views/supplejack_api/admin/sessions/new.html.erb +25 -0
- data/app/views/supplejack_api/admin/shared/_links.erb +34 -0
- data/app/views/supplejack_api/admin/site_activities/index.csv.erb +22 -0
- data/app/views/supplejack_api/admin/site_activities/index.html.erb +54 -0
- data/app/views/supplejack_api/admin/users/edit.html.erb +16 -0
- data/app/views/supplejack_api/admin/users/index.csv.erb +22 -0
- data/app/views/supplejack_api/admin/users/index.html.erb +57 -0
- data/app/views/supplejack_api/admin/users/show.html.erb +33 -0
- data/app/views/supplejack_api/request_limit_mailer/at100percent.text.erb +13 -0
- data/app/views/supplejack_api/request_limit_mailer/at100percent_admin.text.erb +1 -0
- data/app/views/supplejack_api/request_limit_mailer/at90percent.text.erb +13 -0
- data/app/views/supplejack_api/request_limit_mailer/at90percent_admin.text.erb +1 -0
- data/app/workers/supplejack_api/daily_metrics_worker.rb +112 -0
- data/app/workers/supplejack_api/interaction_metrics_worker.rb +45 -0
- data/config/cucumber.yml +16 -0
- data/config/initializers/force_eagerload.rb +11 -0
- data/config/initializers/interaction_updaters.rb +7 -0
- data/config/routes.rb +81 -0
- data/db/binding_records.development.json +7 -0
- data/db/binding_records.staging.json +7 -0
- data/db/concepts.json +33 -0
- data/db/concepts_data.json +569745 -0
- data/db/source_authorities.json +119 -0
- data/lib/generators/supplejack_api/install_generator.rb +124 -0
- data/lib/mongoid/paperclip.rb +53 -0
- data/lib/mongoid/string.rb +20 -0
- data/lib/sunspot/mongoid.rb +51 -0
- data/lib/sunspot/resque_session_proxy.rb +72 -0
- data/lib/sunspot/sunspot_spellcheck.rb +98 -0
- data/lib/supplejack_api.rb +13 -0
- data/lib/supplejack_api/admin/sortable.rb +40 -0
- data/lib/supplejack_api/engine.rb +46 -0
- data/lib/supplejack_api/harvester_constraint.rb +28 -0
- data/lib/supplejack_api/stylesheets.rb +36 -0
- data/lib/supplejack_api/utils.rb +75 -0
- data/lib/supplejack_api/version.rb +11 -0
- data/lib/tasks/resque.rake +22 -0
- data/lib/url_validator.rb +38 -0
- data/spec/controllers/supplejack_api/admin/base_controller_spec.rb +55 -0
- data/spec/controllers/supplejack_api/admin/site_activities_controller_spec.rb +43 -0
- data/spec/controllers/supplejack_api/admin/users_controller_spec.rb +79 -0
- data/spec/controllers/supplejack_api/application_controller_spec.rb +133 -0
- data/spec/controllers/supplejack_api/concepts_controller_spec.rb +83 -0
- data/spec/controllers/supplejack_api/concerns/records_controller_metrics_spec.rb +60 -0
- data/spec/controllers/supplejack_api/harvester/concepts_controller_spec.rb +57 -0
- data/spec/controllers/supplejack_api/harvester/records_controller_spec.rb +138 -0
- data/spec/controllers/supplejack_api/metrics_api_controller_spec.rb +71 -0
- data/spec/controllers/supplejack_api/partners_controller_spec.rb +77 -0
- data/spec/controllers/supplejack_api/records_controller_spec.rb +143 -0
- data/spec/controllers/supplejack_api/set_items_controller_spec.rb +78 -0
- data/spec/controllers/supplejack_api/sources_controller_spec.rb +161 -0
- data/spec/controllers/supplejack_api/status_controller_spec.rb +120 -0
- data/spec/controllers/supplejack_api/user_sets_controller_spec.rb +233 -0
- data/spec/controllers/supplejack_api/users_controller_spec.rb +61 -0
- data/spec/dummy/README.rdoc +268 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +23 -0
- data/spec/dummy/app/assets/stylesheets/application.css +22 -0
- data/spec/dummy/app/controllers/application_controller.rb +10 -0
- data/spec/dummy/app/helpers/application_helper.rb +9 -0
- data/spec/dummy/app/supplejack_api/concept_schema.rb +83 -0
- data/spec/dummy/app/supplejack_api/record_schema.rb +64 -0
- data/spec/dummy/app/supplejack_api/record_schema.txt +66 -0
- data/spec/dummy/app/views/layouts/application.html.erb +23 -0
- data/spec/dummy/app/workers/supplejack_api/clear_index_buffer.rb +32 -0
- data/spec/dummy/app/workers/supplejack_api/flush_old_records_worker.rb +17 -0
- data/spec/dummy/app/workers/supplejack_api/index_buffer.rb +49 -0
- data/spec/dummy/app/workers/supplejack_api/index_source_worker.rb +39 -0
- data/spec/dummy/app/workers/supplejack_api/index_worker.rb +82 -0
- data/spec/dummy/app/workers/supplejack_api/store_user_activity_worker.rb +24 -0
- data/spec/dummy/config.ru +11 -0
- data/spec/dummy/config/application.rb +76 -0
- data/spec/dummy/config/application.yml +31 -0
- data/spec/dummy/config/application.yml.example +36 -0
- data/spec/dummy/config/boot.rb +17 -0
- data/spec/dummy/config/environment.rb +12 -0
- data/spec/dummy/config/environments/development.rb +42 -0
- data/spec/dummy/config/environments/production.rb +76 -0
- data/spec/dummy/config/environments/test.rb +46 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +14 -0
- data/spec/dummy/config/initializers/devise.rb +214 -0
- data/spec/dummy/config/initializers/inflections.rb +22 -0
- data/spec/dummy/config/initializers/kaminari_config.rb +17 -0
- data/spec/dummy/config/initializers/mime_types.rb +12 -0
- data/spec/dummy/config/initializers/mongoid.rb +9 -0
- data/spec/dummy/config/initializers/quiet_logger.rb +23 -0
- data/spec/dummy/config/initializers/resque.rb +18 -0
- data/spec/dummy/config/initializers/secret_token.rb +14 -0
- data/spec/dummy/config/initializers/session_store.rb +15 -0
- data/spec/dummy/config/initializers/simple_form.rb +149 -0
- data/spec/dummy/config/initializers/simple_form_foundation.rb +33 -0
- data/spec/dummy/config/initializers/state_machine.rb +8 -0
- data/spec/dummy/config/initializers/sunspot.rb +32 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +17 -0
- data/spec/dummy/config/locales/devise.en.yml +63 -0
- data/spec/dummy/config/locales/en.yml +66 -0
- data/spec/dummy/config/locales/simple_form.en.yml +33 -0
- data/spec/dummy/config/mongoid.travis.yml +34 -0
- data/spec/dummy/config/mongoid.yml +36 -0
- data/spec/dummy/config/resque-pool.yml +18 -0
- data/spec/dummy/config/resque_schedule.yml +12 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/config/secrets.yml +8 -0
- data/spec/dummy/config/sunspot.yml +38 -0
- data/spec/dummy/db/concepts.json +37 -0
- data/spec/dummy/db/source_authorities.json +116 -0
- data/spec/dummy/public/404.html +35 -0
- data/spec/dummy/public/422.html +35 -0
- data/spec/dummy/public/500.html +34 -0
- data/spec/dummy/public/favicon.ico +8 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/solr/collection1/conf/elevate.xml +36 -0
- data/spec/dummy/solr/collection1/conf/mapping-FoldToASCII.txt +3813 -0
- data/spec/dummy/solr/collection1/conf/schema.xml +292 -0
- data/spec/dummy/solr/collection1/conf/solrconfig.xml +1780 -0
- data/spec/dummy/solr/collection1/conf/spellings.txt +2 -0
- data/spec/dummy/solr/collection1/conf/stopwords.txt +58 -0
- data/spec/dummy/solr/collection1/conf/synonyms.txt +31 -0
- data/spec/factories/concepts.rb +16 -0
- data/spec/factories/daily_metrics.rb +10 -0
- data/spec/factories/faceted_metrics.rb +25 -0
- data/spec/factories/fragment.rb +14 -0
- data/spec/factories/partners.rb +14 -0
- data/spec/factories/record_interaction.rb +17 -0
- data/spec/factories/records.rb +47 -0
- data/spec/factories/set_interaction.rb +15 -0
- data/spec/factories/source_authorities.rb +19 -0
- data/spec/factories/sources.rb +16 -0
- data/spec/factories/usage_metrics.rb +20 -0
- data/spec/factories/user_activities.rb +14 -0
- data/spec/factories/user_sets.rb +27 -0
- data/spec/factories/users.rb +23 -0
- data/spec/helpers/application_helper_spec.rb +35 -0
- data/spec/models/concept_spec.rb +163 -0
- data/spec/models/fragment_spec.rb +15 -0
- data/spec/models/site_activity_spec.rb +103 -0
- data/spec/models/source_activity_spec.rb +56 -0
- data/spec/models/source_authority_spec.rb +42 -0
- data/spec/models/supplejack_api/api_concept/concept_fragment_spec.rb +189 -0
- data/spec/models/supplejack_api/api_record/record_fragment_spec.rb +189 -0
- data/spec/models/supplejack_api/concept_spec.rb +0 -0
- data/spec/models/supplejack_api/interaction_updaters/all_usage_metric_spec.rb +41 -0
- data/spec/models/supplejack_api/interaction_updaters/set_metrics_spec.rb +32 -0
- data/spec/models/supplejack_api/interaction_updaters/usage_metrics_spec.rb +44 -0
- data/spec/models/supplejack_api/partner_spec.rb +20 -0
- data/spec/models/supplejack_api/record_search_spec.rb +429 -0
- data/spec/models/supplejack_api/record_spec.rb +280 -0
- data/spec/models/supplejack_api/schema_definition_spec.rb +272 -0
- data/spec/models/supplejack_api/search_spec.rb +243 -0
- data/spec/models/supplejack_api/set_item_spec.rb +123 -0
- data/spec/models/supplejack_api/source_spec.rb +22 -0
- data/spec/models/supplejack_api/support/fragment_helpers_spec.rb +216 -0
- data/spec/models/supplejack_api/support/harvestable_spec.rb +177 -0
- data/spec/models/supplejack_api/support/searchable_spec.rb +85 -0
- data/spec/models/supplejack_api/support/storable_spec.rb +18 -0
- data/spec/models/supplejack_api/user_activity_spec.rb +88 -0
- data/spec/models/supplejack_api/user_set_spec.rb +559 -0
- data/spec/models/supplejack_api/user_spec.rb +348 -0
- data/spec/routing/concepts_routing_spec.rb +22 -0
- data/spec/routing/harvester_constraint_spec.rb +66 -0
- data/spec/routing/harvester_routing_spec.rb +51 -0
- data/spec/routing/partner_routing_spec.rb +34 -0
- data/spec/routing/records_routing_spec.rb +26 -0
- data/spec/routing/sets_routing_spec.rb +44 -0
- data/spec/routing/source_routing_spec.rb +38 -0
- data/spec/routing/users_routing_spec.rb +18 -0
- data/spec/serializers/concept_record_serializer_spec.rb +30 -0
- data/spec/serializers/supplejack_api/application_serializer_spec.rb +14 -0
- data/spec/serializers/supplejack_api/concept_search_serializer_spec.rb +34 -0
- data/spec/serializers/supplejack_api/concept_serializer_spec.rb +92 -0
- data/spec/serializers/supplejack_api/record_search_serializer_spec.rb +34 -0
- data/spec/serializers/supplejack_api/record_serializer_spec.rb +271 -0
- data/spec/serializers/supplejack_api/search_serializer_spec.rb +90 -0
- data/spec/serializers/supplejack_api/user_serializer_spec.rb +22 -0
- data/spec/serializers/supplejack_api/user_set_serializer_spec.rb +96 -0
- data/spec/services/metrics_api/v3/api_spec.rb +23 -0
- data/spec/services/metrics_api/v3/endpoints/facets_spec.rb +25 -0
- data/spec/services/metrics_api/v3/endpoints/global_spec.rb +22 -0
- data/spec/services/metrics_api/v3/endpoints/root_spec.rb +49 -0
- data/spec/services/metrics_api/v3/presenters/extended_metadata_spec.rb +49 -0
- data/spec/spec_helper.rb +70 -0
- data/spec/support/api/schemas/metrics/daily_metrics_metadata.json +24 -0
- data/spec/support/api/schemas/metrics/extended_metrics.json +26 -0
- data/spec/support/api/schemas/metrics/extended_response.json +6 -0
- data/spec/support/api/schemas/metrics/facets_response.json +6 -0
- data/spec/support/api/schemas/metrics/record_metadata.json +33 -0
- data/spec/support/api/schemas/metrics/top_level_response.json +6 -0
- data/spec/support/api/schemas/metrics/view_metadata.json +33 -0
- data/spec/support/api_schema_matcher.rb +14 -0
- data/spec/support/devise.rb +10 -0
- data/spec/workers/supplejack_api/daily_metrics_worker_spec.rb +140 -0
- data/spec/workers/supplejack_api/flush_old_records_worker_spec.rb +20 -0
- data/spec/workers/supplejack_api/index_worker_spec.rb +52 -0
- data/spec/workers/supplejack_api/source_index_worker_spec.rb +61 -0
- metadata +1231 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The majority of the Supplejack API code is Crown copyright (C) 2014, New Zealand Government,
|
3
|
+
# and is licensed under the GNU General Public License, version 3.
|
4
|
+
# One component is a third party component. See https://github.com/DigitalNZ/supplejack_api for details.
|
5
|
+
#
|
6
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ and
|
7
|
+
# the Department of Internal Affairs. http://digitalnz.org/supplejack
|
8
|
+
|
9
|
+
module SupplejackApi
|
10
|
+
class Concept
|
11
|
+
include Support::Concept::Storable
|
12
|
+
include Support::Concept::Searchable
|
13
|
+
include ActiveModel::SerializerSupport
|
14
|
+
|
15
|
+
def self.build_context(fields)
|
16
|
+
context = {}
|
17
|
+
namespaces = []
|
18
|
+
|
19
|
+
fields.each do |field|
|
20
|
+
namespaces << ConceptSchema.model_fields[field].try(:namespace)
|
21
|
+
end
|
22
|
+
|
23
|
+
namespaces.compact.uniq.each do |namespace|
|
24
|
+
context[namespace] = ConceptSchema.namespaces[namespace].url
|
25
|
+
namespaced_fields = ConceptSchema.fields.select { |_key, field| field.namespace == namespace }
|
26
|
+
namespaced_fields.each do |name, field|
|
27
|
+
if fields.include?(name) && name != field.namespace
|
28
|
+
context[name] = "#{field.namespace}:#{field.namespace_field}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Manually build context for concept_id
|
34
|
+
context[:dcterms] = ConceptSchema.namespaces[:dcterms].url
|
35
|
+
context[:concept_id] = {}
|
36
|
+
context[:concept_id]['@id'] = 'dcterms:identifier'
|
37
|
+
|
38
|
+
fields.each do |field|
|
39
|
+
context[field] = {}
|
40
|
+
namespace = ConceptSchema.model_fields[field].try(:namespace)
|
41
|
+
context[field]['@id'] = "#{namespace}:#{field}"
|
42
|
+
end
|
43
|
+
context
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The majority of the Supplejack API code is Crown copyright (C) 2014, New Zealand Government,
|
3
|
+
# and is licensed under the GNU General Public License, version 3.
|
4
|
+
# One component is a third party component. See https://github.com/DigitalNZ/supplejack_api for details.
|
5
|
+
#
|
6
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ and
|
7
|
+
# the Department of Internal Affairs. http://digitalnz.org/supplejack
|
8
|
+
|
9
|
+
module SupplejackApi
|
10
|
+
class ConceptSearch < Search
|
11
|
+
def initialize(options = {})
|
12
|
+
@options = options.dup
|
13
|
+
@options.reverse_merge!(
|
14
|
+
and: {},
|
15
|
+
or: {},
|
16
|
+
without: {},
|
17
|
+
page: 1,
|
18
|
+
per_page: 20,
|
19
|
+
sort: nil,
|
20
|
+
direction: 'desc',
|
21
|
+
fields: ConceptSchema.model_fields.keys.join(','),
|
22
|
+
debug: nil
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
# FIXME: make me smaller!
|
27
|
+
def search_builder
|
28
|
+
@search_builder ||= Sunspot.new_search(SupplejackApi::Concept) do
|
29
|
+
spellcheck collate: true, only_more_popular: true if options[:suggest]
|
30
|
+
|
31
|
+
options[:without].each do |name, values|
|
32
|
+
values = values.split(',')
|
33
|
+
values.each do |value|
|
34
|
+
without(name, to_proper_value(name, value))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if options[:geo_bbox]
|
39
|
+
coords = options[:geo_bbox].split(',').map(&:to_f)
|
40
|
+
with(:lat_lng).in_bounding_box([coords[2], coords[1]], [coords[0], coords[3]])
|
41
|
+
end
|
42
|
+
|
43
|
+
adjust_solr_params do |params|
|
44
|
+
if options[:solr_query].present?
|
45
|
+
params[:q] ||= ''
|
46
|
+
params['q.alt'] = options[:solr_query]
|
47
|
+
params[:defType] = 'dismax'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
order_by(sort, direction) if options[:sort].present?
|
52
|
+
|
53
|
+
paginate page: page, per_page: per_page
|
54
|
+
end
|
55
|
+
|
56
|
+
@search_builder.build(&build_conditions)
|
57
|
+
@search_builder
|
58
|
+
end
|
59
|
+
# rubocop:enable Metrics/MethodLength
|
60
|
+
|
61
|
+
def query_fields
|
62
|
+
query_fields_list = super
|
63
|
+
query_fields_list += [:name, :label] if (query_fields_list && [:name, :label]).present?
|
64
|
+
end
|
65
|
+
|
66
|
+
def field_list
|
67
|
+
return @field_list if @field_list
|
68
|
+
model_fields = ConceptSchema.model_fields.dup
|
69
|
+
valid_fields = model_fields.keep_if { |_key, field| field.try(:store).nil? }
|
70
|
+
|
71
|
+
@field_list = options[:fields].split(',').map { |f| f.strip.tr(':', '_').to_sym }
|
72
|
+
@field_list.keep_if do |f|
|
73
|
+
valid_fields.include?(f)
|
74
|
+
end
|
75
|
+
|
76
|
+
@field_list
|
77
|
+
end
|
78
|
+
|
79
|
+
def group_list
|
80
|
+
return @group_list if @group_list
|
81
|
+
@group_list = options[:fields].split(',').map { |f| f.strip.to_sym }
|
82
|
+
@group_list.keep_if { |f| ConceptSchema.groups.keys.include?(f) }
|
83
|
+
@group_list
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The majority of the Supplejack API code is Crown copyright (C) 2014, New Zealand Government,
|
3
|
+
# and is licensed under the GNU General Public License, version 3.
|
4
|
+
# One component is a third party component. See https://github.com/DigitalNZ/supplejack_api for details.
|
5
|
+
#
|
6
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ and
|
7
|
+
# the Department of Internal Affairs. http://digitalnz.org/supplejack
|
8
|
+
|
9
|
+
module SupplejackApi
|
10
|
+
module Concerns
|
11
|
+
# Contains convenience methods for querying documents by their day field
|
12
|
+
# This concern assumes documents have the field 'day' of type +Date+
|
13
|
+
module QueryableByDate
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
index date: 1
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def created_on(date)
|
22
|
+
where(:date.gte => date.at_beginning_of_day, :date.lte => date.at_end_of_day)
|
23
|
+
end
|
24
|
+
|
25
|
+
def created_between(start_date, end_date)
|
26
|
+
where(:date.gte => start_date, :date.lte => end_date)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module SupplejackApi::Concerns::Record
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attr_accessor :next_record, :previous_record, :next_page, :previous_page
|
7
|
+
attr_accessor :should_index_flag
|
8
|
+
|
9
|
+
# Associations
|
10
|
+
embeds_many :fragments, cascade_callbacks: true, class_name: 'SupplejackApi::ApiRecord::RecordFragment'
|
11
|
+
embeds_one :merged_fragment, class_name: 'SupplejackApi::ApiRecord::RecordFragment'
|
12
|
+
has_and_belongs_to_many :concepts, class_name: 'SupplejackApi::Concept'
|
13
|
+
|
14
|
+
# From storable
|
15
|
+
store_in collection: 'records'
|
16
|
+
index(concept_ids: 1)
|
17
|
+
index({ record_id: 1 }, unique: true)
|
18
|
+
auto_increment :record_id, session: 'strong'
|
19
|
+
|
20
|
+
# Callbacks
|
21
|
+
before_save :merge_fragments
|
22
|
+
|
23
|
+
# Scopes
|
24
|
+
scope :active, -> { where(status: 'active') }
|
25
|
+
scope :deleted, -> { where(status: 'deleted') }
|
26
|
+
scope :suppressed, -> { where(status: 'suppressed') }
|
27
|
+
scope :solr_rejected, -> { where(status: 'solr_rejected') }
|
28
|
+
|
29
|
+
build_model_fields
|
30
|
+
|
31
|
+
def self.created_on(date)
|
32
|
+
where(:created_at.gte => date.at_beginning_of_day, :created_at.lte => date.at_end_of_day)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.find_multiple(ids)
|
36
|
+
return [] unless ids.try(:any?)
|
37
|
+
string_ids = ids.find_all { |id| id.to_s.length > 10 }
|
38
|
+
integer_ids = ids.find_all { |id| id.to_s.length <= 10 }
|
39
|
+
|
40
|
+
records = []
|
41
|
+
records += active.find(string_ids) if string_ids.present?
|
42
|
+
records += active.where(:record_id.in => integer_ids)
|
43
|
+
records = records.sort_by { |r| ids.find_index(r.record_id) || 100 }
|
44
|
+
end
|
45
|
+
|
46
|
+
# rubocop:disable Metrics/MethodLength
|
47
|
+
# FIXME: make me smaller!
|
48
|
+
def find_next_and_previous_records(scope, options = {})
|
49
|
+
return unless options.try(:any?)
|
50
|
+
|
51
|
+
search = ::SupplejackApi::RecordSearch.new(options)
|
52
|
+
search.scope = scope
|
53
|
+
|
54
|
+
return nil unless search.valid?
|
55
|
+
|
56
|
+
# Find the index in the array for the current record
|
57
|
+
record_index = search.hits.find_index { |i| i.primary_key == id.to_s }
|
58
|
+
total_pages = (search.total.to_f / search.per_page).ceil
|
59
|
+
|
60
|
+
self.next_page = search.page
|
61
|
+
self.previous_page = search.page
|
62
|
+
|
63
|
+
return unless record_index
|
64
|
+
|
65
|
+
if record_index.zero?
|
66
|
+
unless search.page == 1
|
67
|
+
previous_page_search = ::SupplejackApi::RecordSearch.new(options.merge(page: search.page - 1))
|
68
|
+
previous_primary_key = previous_page_search.hits[-1].try(:primary_key)
|
69
|
+
self.previous_page = search.page - 1
|
70
|
+
end
|
71
|
+
else
|
72
|
+
previous_primary_key = search.hits[record_index - 1].try(:primary_key)
|
73
|
+
end
|
74
|
+
|
75
|
+
if previous_primary_key.present?
|
76
|
+
self.previous_record = SupplejackApi::Record.find(previous_primary_key).try(:record_id) rescue nil
|
77
|
+
end
|
78
|
+
|
79
|
+
if record_index == search.hits.size - 1
|
80
|
+
unless search.page >= total_pages
|
81
|
+
next_page_search = ::SupplejackApi::RecordSearch.new(options.merge(page: search.page + 1))
|
82
|
+
next_primary_key = next_page_search.hits[0].try(:primary_key)
|
83
|
+
self.next_page = search.page + 1
|
84
|
+
end
|
85
|
+
else
|
86
|
+
next_primary_key = search.hits[record_index + 1].try(:primary_key)
|
87
|
+
end
|
88
|
+
|
89
|
+
return unless next_primary_key.present?
|
90
|
+
|
91
|
+
self.next_record = ::SupplejackApi::Record.find(next_primary_key).try(:record_id) rescue nil
|
92
|
+
end
|
93
|
+
# rubocop:enable Metrics/MethodLength
|
94
|
+
|
95
|
+
def active?
|
96
|
+
status == 'active'
|
97
|
+
end
|
98
|
+
|
99
|
+
def should_index?
|
100
|
+
return should_index_flag unless should_index_flag.nil?
|
101
|
+
active?
|
102
|
+
end
|
103
|
+
|
104
|
+
def fragment_class
|
105
|
+
SupplejackApi::ApiRecord::RecordFragment
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module SupplejackApi::Concerns::RecordFragmentable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
embedded_in :record
|
7
|
+
|
8
|
+
delegate :record_id, to: :record
|
9
|
+
|
10
|
+
def self.schema_class
|
11
|
+
RecordSchema
|
12
|
+
end
|
13
|
+
|
14
|
+
build_mongoid_schema
|
15
|
+
|
16
|
+
def self.mutable_fields
|
17
|
+
@@mutable_fields ||= begin
|
18
|
+
immutable_fields = %w(_id _type source_id created_at updated_at)
|
19
|
+
mutable_fields = fields.keys - immutable_fields
|
20
|
+
Hash[mutable_fields.map { |name| [name, fields[name].type] }]
|
21
|
+
end.freeze
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,430 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rubocop:disable Metrics/ModuleLength
|
3
|
+
module SupplejackApi::Concerns::Searchable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
INTEGER_ATTRIBUTES ||= [:page, :per_page, :facets_per_page, :facets_page, :record_type].freeze
|
8
|
+
|
9
|
+
attr_accessor :options, :request_url, :scope, :solr_request_params, :errors, :warnings
|
10
|
+
|
11
|
+
class_attribute :max_values
|
12
|
+
|
13
|
+
self.max_values = {
|
14
|
+
page: 100_000,
|
15
|
+
per_page: 100,
|
16
|
+
facets_per_page: 150,
|
17
|
+
facets_page: 5000
|
18
|
+
}
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
@options = options.dup
|
22
|
+
@options.reverse_merge!(
|
23
|
+
facets: '',
|
24
|
+
and: {},
|
25
|
+
or: {},
|
26
|
+
without: {},
|
27
|
+
page: 1,
|
28
|
+
per_page: 20,
|
29
|
+
record_type: 0,
|
30
|
+
facets_per_page: 10,
|
31
|
+
facets_page: 1,
|
32
|
+
sort: nil,
|
33
|
+
direction: 'desc',
|
34
|
+
fields: 'default',
|
35
|
+
facet_query: {},
|
36
|
+
debug: nil
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.model_class
|
41
|
+
to_s.gsub(/Search/, '').constantize
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.schema_class
|
45
|
+
"#{model_class.to_s.demodulize}Schema".constantize
|
46
|
+
end
|
47
|
+
|
48
|
+
# The records that match the criteria within each role will be removed
|
49
|
+
# from the search results
|
50
|
+
#
|
51
|
+
def self.role_collection_restrictions(scope)
|
52
|
+
restrictions = []
|
53
|
+
|
54
|
+
if scope
|
55
|
+
role = scope.role.try(:to_sym)
|
56
|
+
if schema_class.roles[role].record_restrictions
|
57
|
+
restrictions = schema_class.roles[role].record_restrictions
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
restrictions
|
62
|
+
end
|
63
|
+
|
64
|
+
# rubocop:disable Metrics/MethodLength
|
65
|
+
# rubocop:disable Metrics/AbcSize
|
66
|
+
# FIXME: Make this method smaller, it's triple the max method length
|
67
|
+
def search_builder
|
68
|
+
search_model = self
|
69
|
+
|
70
|
+
@search_builder ||= Sunspot.new_search(search_model.class.model_class) do
|
71
|
+
with(:record_type, record_type) unless options[:record_type] == 'all'
|
72
|
+
|
73
|
+
search_model.facet_list.each do |facet_name|
|
74
|
+
facet(facet_name, limit: facets_per_page, offset: facets_offset)
|
75
|
+
end
|
76
|
+
|
77
|
+
spellcheck collate: true, only_more_popular: true if options[:suggest]
|
78
|
+
|
79
|
+
options[:without].each do |name, values|
|
80
|
+
values = values.split(',')
|
81
|
+
values.each do |value|
|
82
|
+
without(name, to_proper_value(name, value))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if options[:geo_bbox]
|
87
|
+
coords = options[:geo_bbox].split(',').map(&:to_f)
|
88
|
+
with(:lat_lng).in_bounding_box([coords[2], coords[1]], [coords[0], coords[3]])
|
89
|
+
end
|
90
|
+
|
91
|
+
adjust_solr_params do |params|
|
92
|
+
if options[:solr_query].present?
|
93
|
+
params[:q] ||= ''
|
94
|
+
params['q.alt'] = options[:solr_query]
|
95
|
+
params[:defType] = 'dismax'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Facet Queries
|
100
|
+
#
|
101
|
+
# The facet query parameter should have the following format:
|
102
|
+
#
|
103
|
+
# facet_query: {images: {"creator" => "all"}, headings: {"record_type" => 1}}
|
104
|
+
#
|
105
|
+
# - Each key in the top level hash will be the name of each facet row returned.
|
106
|
+
# - Each value in the top level hash is a hash similar with all the restrictions
|
107
|
+
#
|
108
|
+
|
109
|
+
if options[:facet_query].any?
|
110
|
+
facet(:counts) do
|
111
|
+
options[:facet_query].each_pair do |row_name, filters_hash|
|
112
|
+
row(row_name.to_s) do
|
113
|
+
filters_hash.each_pair do |filter, value|
|
114
|
+
if value == 'all'
|
115
|
+
without(filter.to_sym, nil)
|
116
|
+
elsif filter =~ /-(.+)/
|
117
|
+
without(Regexp.last_match(1).to_sym, to_proper_value(filter, value))
|
118
|
+
else
|
119
|
+
if value.is_a?(Array)
|
120
|
+
with(filter.to_sym).all_of(value)
|
121
|
+
else
|
122
|
+
with(filter.to_sym, to_proper_value(filter, value))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
order_by(sort, direction) if options[:sort].present?
|
132
|
+
|
133
|
+
search_model.class.role_collection_restrictions(search_model.scope).each do |field, values|
|
134
|
+
without(field.to_sym, values)
|
135
|
+
end
|
136
|
+
|
137
|
+
SupplejackApi::Source.suppressed.each do |source|
|
138
|
+
without(:source_id, source.source_id)
|
139
|
+
end
|
140
|
+
|
141
|
+
paginate page: page, per_page: per_page
|
142
|
+
end
|
143
|
+
|
144
|
+
@search_builder.build(&build_conditions)
|
145
|
+
|
146
|
+
@search_builder
|
147
|
+
end
|
148
|
+
# rubocop:enable Metrics/AbcSize
|
149
|
+
# rubocop:enable Metrics/MethodLength
|
150
|
+
|
151
|
+
# Return an array of valid facets
|
152
|
+
# It will remove any invalid facets in order to avoid Solr errors
|
153
|
+
#
|
154
|
+
def facet_list
|
155
|
+
return @facet_list if @facet_list
|
156
|
+
|
157
|
+
@facet_list = options[:facets].split(',').map { |f| f.strip.to_sym }
|
158
|
+
@facet_list.keep_if { |f| self.class.model_class.valid_facets.include?(f) }
|
159
|
+
@facet_list
|
160
|
+
end
|
161
|
+
|
162
|
+
def field_list
|
163
|
+
return @field_list if @field_list
|
164
|
+
valid_fields = self.class.schema_class.fields.keys.dup
|
165
|
+
|
166
|
+
@field_list = options[:fields].split(',').map { |f| f.strip.tr(':', '_').to_sym }
|
167
|
+
@field_list.delete_if do |f|
|
168
|
+
!valid_fields.include?(f)
|
169
|
+
end
|
170
|
+
|
171
|
+
@field_list
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns the facets part of the search results converted to a hash
|
175
|
+
#
|
176
|
+
# @return [Hash] facets in hash form, each facet is respresented as +facet_name => facet_values+
|
177
|
+
def facets_hash
|
178
|
+
facets = {}
|
179
|
+
|
180
|
+
self.facets.each do |facet|
|
181
|
+
rows = {}
|
182
|
+
facet.rows.each do |row|
|
183
|
+
rows[row.value] = row.count
|
184
|
+
end
|
185
|
+
|
186
|
+
facets.merge!(facet.name => rows)
|
187
|
+
end
|
188
|
+
|
189
|
+
facets
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns all valid groups of fields
|
193
|
+
# The groups are extracted from the "fields" parameter
|
194
|
+
#
|
195
|
+
def group_list
|
196
|
+
return @group_list if @group_list
|
197
|
+
@group_list = options[:fields].split(',').map { |f| f.strip.to_sym }
|
198
|
+
@group_list.keep_if { |f| self.class.model_class.valid_groups.include?(f) }
|
199
|
+
@group_list
|
200
|
+
end
|
201
|
+
|
202
|
+
def query_fields
|
203
|
+
query_field_list = nil
|
204
|
+
|
205
|
+
if options[:query_fields].is_a?(String)
|
206
|
+
query_field_list = options[:query_fields].split(',').map(&:strip).map(&:to_sym)
|
207
|
+
elsif options[:query_fields].is_a?(Array)
|
208
|
+
query_field_list = options[:query_fields].map(&:to_sym)
|
209
|
+
end
|
210
|
+
|
211
|
+
return nil if query_field_list.try(:empty?)
|
212
|
+
query_field_list
|
213
|
+
end
|
214
|
+
|
215
|
+
def extract_range(value)
|
216
|
+
if value =~ /^\[(\d+)\sTO\s(\d+)\]$/
|
217
|
+
Regexp.last_match(1).to_i..Regexp.last_match(2).to_i
|
218
|
+
else
|
219
|
+
value.to_i.positive? ? value.to_i : value.strip
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def to_proper_value(_name, value)
|
224
|
+
return false if value == 'false'
|
225
|
+
return true if value == 'true'
|
226
|
+
return nil if %w(nil null).include?(value)
|
227
|
+
|
228
|
+
value = value.strip if value.is_a?(String)
|
229
|
+
value
|
230
|
+
end
|
231
|
+
|
232
|
+
# Downcase all queries before sending to SOLR, except queries
|
233
|
+
# which have specific lucene syntax.
|
234
|
+
#
|
235
|
+
def text
|
236
|
+
@text = options[:text]
|
237
|
+
if @text.present? && !@text.match(/:\"/)
|
238
|
+
@text.downcase!
|
239
|
+
@text.gsub!(/ and | or | not /, &:upcase)
|
240
|
+
end
|
241
|
+
@text
|
242
|
+
end
|
243
|
+
|
244
|
+
def offset
|
245
|
+
(page * per_page) - per_page
|
246
|
+
end
|
247
|
+
|
248
|
+
def facets_offset
|
249
|
+
offset = (facets_page * facets_per_page) - facets_per_page
|
250
|
+
offset.negative? ? 0 : offset
|
251
|
+
end
|
252
|
+
|
253
|
+
def valid?
|
254
|
+
self.errors ||= []
|
255
|
+
self.warnings ||= []
|
256
|
+
self.class.max_values.each do |attribute, max_value|
|
257
|
+
max_value = self.class.max_values[attribute]
|
258
|
+
if @options[attribute].to_i > max_value
|
259
|
+
self.warnings << "The #{attribute} parameter can not exceed #{max_value}"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
solr_search_object
|
264
|
+
self.errors.empty?
|
265
|
+
end
|
266
|
+
|
267
|
+
def records
|
268
|
+
solr_search_object.results
|
269
|
+
end
|
270
|
+
|
271
|
+
def jsonp
|
272
|
+
@options[:jsonp].present? ? @options[:jsonp] : nil
|
273
|
+
end
|
274
|
+
|
275
|
+
# It's currently required to make the active_model_serializers gem to work with XML
|
276
|
+
# The XML Serialization is handled by the respective serializer
|
277
|
+
#
|
278
|
+
def to_xml; end
|
279
|
+
|
280
|
+
# IMPORTANT !!!!
|
281
|
+
#
|
282
|
+
# Try to make this a bit prettier
|
283
|
+
#
|
284
|
+
INTEGER_ATTRIBUTES.each do |method|
|
285
|
+
define_method(method) do
|
286
|
+
value = @options[:"#{method.to_sym}"].to_i
|
287
|
+
value = [value, self.class.max_values[method]].min if self.class.max_values[method]
|
288
|
+
value
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def sort
|
293
|
+
value = @options[:sort].to_sym
|
294
|
+
|
295
|
+
begin
|
296
|
+
field = Sunspot::Setup.for(self.class.model_class).field(value)
|
297
|
+
return value
|
298
|
+
rescue Sunspot::UnrecognizedFieldError => e
|
299
|
+
return 'score'
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def direction
|
304
|
+
if %w(asc desc).include?(@options[:direction])
|
305
|
+
@options[:direction].to_sym
|
306
|
+
else
|
307
|
+
:desc
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def solr_search_object
|
312
|
+
return @solr_search_object if @solr_search_object
|
313
|
+
@solr_search_object = execute_solr_search
|
314
|
+
|
315
|
+
if options[:debug] == 'true' && @solr_search_object.respond_to?(:query)
|
316
|
+
self.solr_request_params = @solr_search_object.query.to_params
|
317
|
+
end
|
318
|
+
|
319
|
+
@solr_search_object
|
320
|
+
end
|
321
|
+
|
322
|
+
def solr_error_message(exception)
|
323
|
+
{
|
324
|
+
title: "#{exception.response[:status]} #{RSolr::Error::Http::STATUS_CODES[exception.response[:status].to_i]}",
|
325
|
+
body: exception.send(:parse_solr_error_response, exception.response[:body])
|
326
|
+
}
|
327
|
+
end
|
328
|
+
|
329
|
+
# rubocop:disable Style/MethodMissing
|
330
|
+
def method_missing(symbol, *args)
|
331
|
+
return nil unless solr_search_object.respond_to?(:hits)
|
332
|
+
solr_search_object.send(symbol, *args)
|
333
|
+
end
|
334
|
+
# rubocop:enable Style/MethodMissing
|
335
|
+
|
336
|
+
def execute_solr_search
|
337
|
+
search = search_builder
|
338
|
+
|
339
|
+
search.build do
|
340
|
+
keywords text, fields: query_fields
|
341
|
+
end
|
342
|
+
|
343
|
+
execute_solr_search_and_handle_errors(search)
|
344
|
+
end
|
345
|
+
|
346
|
+
def execute_solr_search_and_handle_errors(search)
|
347
|
+
self.errors ||= []
|
348
|
+
sunspot = search.execute
|
349
|
+
rescue RSolr::Error::Http => e
|
350
|
+
self.errors << solr_error_message(e)
|
351
|
+
Rails.logger.info e.message
|
352
|
+
sunspot = {}
|
353
|
+
rescue Timeout::Error, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
354
|
+
self.errors << 'Solr is temporarily unavailable please try again in a few seconds.'
|
355
|
+
Rails.logger.info e.message
|
356
|
+
sunspot = {}
|
357
|
+
ensure
|
358
|
+
return sunspot
|
359
|
+
end
|
360
|
+
|
361
|
+
private
|
362
|
+
|
363
|
+
# Generates the :and and :or conditions for a search object
|
364
|
+
#
|
365
|
+
def build_conditions
|
366
|
+
proc do
|
367
|
+
{ and: options[:and], or: options[:or] }.each do |operator, value|
|
368
|
+
Utils.call_block(self, &recurse_conditions(operator, value))
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
# Detects when the key is a operator (:and, :or) and calls itself
|
374
|
+
# recursively until it finds facets defined in Sunspot.
|
375
|
+
#
|
376
|
+
def recurse_conditions(key, conditions, current_operator = :and)
|
377
|
+
proc do
|
378
|
+
case key.to_sym
|
379
|
+
when :and
|
380
|
+
all_of do
|
381
|
+
conditions.each do |filter, value|
|
382
|
+
Utils.call_block(self, &recurse_conditions(filter, value, :and))
|
383
|
+
end
|
384
|
+
end
|
385
|
+
when :or
|
386
|
+
any_of do
|
387
|
+
conditions.each do |filter, value|
|
388
|
+
Utils.call_block(self, &recurse_conditions(filter, value, :or))
|
389
|
+
end
|
390
|
+
end
|
391
|
+
else
|
392
|
+
Utils.call_block(self, &filter_values(key, conditions, current_operator))
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Generates a single condition. It can take a operator to
|
398
|
+
# determine how the values within the filter are going to be
|
399
|
+
# joined.
|
400
|
+
#
|
401
|
+
def filter_values(key, conditions, current_operator = :and)
|
402
|
+
proc do
|
403
|
+
if conditions.is_a? Hash
|
404
|
+
operator, values = conditions.first
|
405
|
+
else
|
406
|
+
operator = current_operator
|
407
|
+
values = conditions
|
408
|
+
end
|
409
|
+
|
410
|
+
if values.is_a?(Array)
|
411
|
+
case operator.to_sym
|
412
|
+
when :or
|
413
|
+
with(key).any_of(values)
|
414
|
+
when :and
|
415
|
+
with(key).all_of(values)
|
416
|
+
else
|
417
|
+
raise Exception, 'Expected operator (:and, :or)'
|
418
|
+
end
|
419
|
+
else
|
420
|
+
if values =~ /(.+)\*$/
|
421
|
+
with(key).starting_with(Regexp.last_match(1))
|
422
|
+
else
|
423
|
+
with(key, to_proper_value(key, values))
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
# rubocop:enable Metrics/ModuleLength
|