geoblacklight 6.0.0.pre.alpha.7 → 6.0.0.pre.beta.2

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.
Files changed (231) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +14 -3
  3. data/README.md +2 -2
  4. data/Rakefile +1 -17
  5. data/app/assets/images/geoblacklight/logo-dark.svg +31 -0
  6. data/app/assets/images/geoblacklight/logo.svg +10 -10
  7. data/app/assets/stylesheets/geoblacklight/global.css +44 -7
  8. data/app/assets/stylesheets/geoblacklight/index_maps.css +0 -7
  9. data/app/assets/stylesheets/geoblacklight/record.css +33 -9
  10. data/app/assets/stylesheets/geoblacklight/search.css +66 -17
  11. data/app/assets/stylesheets/geoblacklight/viewers.css +18 -111
  12. data/app/assets/stylesheets/geoblacklight.css +0 -5
  13. data/app/components/blacklight/icons/georeferenced_component.rb +23 -0
  14. data/app/components/geoblacklight/document/download_link_component.html.erb +1 -1
  15. data/app/components/geoblacklight/document/preview_component.html.erb +0 -2
  16. data/app/components/geoblacklight/document_component.html.erb +0 -4
  17. data/app/components/geoblacklight/facets/bbox_field_component.html.erb +2 -1
  18. data/app/components/geoblacklight/georeferenced_header_badge_component.rb +16 -0
  19. data/app/components/geoblacklight/header_badge_component.html.erb +4 -2
  20. data/app/components/geoblacklight/header_badge_component.rb +1 -1
  21. data/app/components/geoblacklight/header_badges_component.html.erb +5 -0
  22. data/app/components/geoblacklight/header_badges_component.rb +34 -0
  23. data/app/components/geoblacklight/iiif_drag_drop_component.html.erb +1 -1
  24. data/app/components/geoblacklight/item_map_viewer_component.html.erb +0 -58
  25. data/app/components/geoblacklight/item_map_viewer_component.rb +19 -70
  26. data/app/components/geoblacklight/locator_map_component.rb +31 -0
  27. data/app/components/geoblacklight/login_link_component.html.erb +1 -1
  28. data/app/components/geoblacklight/login_link_component.rb +17 -1
  29. data/app/components/geoblacklight/metadata_description_markdown_component.rb +3 -9
  30. data/app/components/geoblacklight/overview_map_component.html.erb +2 -0
  31. data/app/components/geoblacklight/overview_map_component.rb +86 -0
  32. data/app/components/geoblacklight/relations/relation_component.html.erb +12 -0
  33. data/app/components/geoblacklight/relations/relation_component.rb +30 -0
  34. data/app/components/geoblacklight/relations/relations_component.html.erb +15 -0
  35. data/app/components/geoblacklight/relations/relations_component.rb +59 -0
  36. data/app/components/geoblacklight/resource_header_badge_component.rb +1 -1
  37. data/app/components/geoblacklight/search_result_component.html.erb +14 -33
  38. data/app/components/geoblacklight/search_result_component.rb +2 -14
  39. data/app/components/geoblacklight/static_map_component.rb +3 -14
  40. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.html.erb +7 -0
  41. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.rb +45 -0
  42. data/app/controllers/{relation_controller.rb → relations_controller.rb} +4 -2
  43. data/app/controllers/viewer_record_controller.rb +28 -0
  44. data/app/helpers/geoblacklight_helper.rb +57 -6
  45. data/app/javascript/geoblacklight/controllers/overview_map_controller.js +143 -0
  46. data/app/javascript/geoblacklight/core.js +8 -10
  47. data/app/javascript/geoblacklight/index.js +9 -12
  48. data/app/javascript/geoblacklight/initializers/field_truncation.js +62 -0
  49. data/app/javascript/geoblacklight/initializers/metadata_download.js +3 -8
  50. data/app/javascript/geoblacklight/initializers/truncation.js +7 -3
  51. data/app/javascript/geoblacklight/initializers/viewer_requests.js +61 -0
  52. data/app/javascript/geoblacklight/initializers/viewer_theme.js +28 -0
  53. data/app/models/concerns/geoblacklight/solr_document/thumbnail.rb +38 -0
  54. data/app/models/concerns/geoblacklight/solr_document.rb +2 -0
  55. data/app/models/concerns/geoblacklight/suppressed_records_search_behavior.rb +1 -1
  56. data/app/views/catalog/_document_split.html.erb +10 -10
  57. data/app/views/catalog/_home_text.html.erb +1 -1
  58. data/app/views/catalog/metadata.html.erb +1 -1
  59. data/app/views/{relation → relations}/index.html.erb +1 -1
  60. data/app/views/relations/index.json.jbuilder +9 -0
  61. data/config/importmap.rb +8 -8
  62. data/config/locales/geoblacklight.en.yml +48 -99
  63. data/geoblacklight.gemspec +3 -3
  64. data/lib/generators/geoblacklight/assets_generator.rb +2 -2
  65. data/lib/generators/geoblacklight/install_generator.rb +3 -6
  66. data/lib/generators/geoblacklight/templates/assets/customizations.css +5 -1
  67. data/lib/generators/geoblacklight/templates/catalog_controller.rb +17 -27
  68. data/lib/generators/geoblacklight/templates/settings.yml +15 -95
  69. data/lib/geoblacklight/configuration/display_note_shown_config.rb +3 -0
  70. data/lib/geoblacklight/configuration/relationship_config.rb +7 -1
  71. data/lib/geoblacklight/configuration/relationships_config.rb +15 -15
  72. data/lib/geoblacklight/configuration/settings_attributes.rb +85 -0
  73. data/lib/geoblacklight/configuration/settings_builder.rb +3 -14
  74. data/lib/geoblacklight/configuration.rb +23 -62
  75. data/lib/geoblacklight/exceptions.rb +4 -0
  76. data/lib/geoblacklight/reference.rb +0 -2
  77. data/lib/geoblacklight/references.rb +17 -5
  78. data/lib/geoblacklight/relations/ancestors.rb +12 -0
  79. data/lib/geoblacklight/relations/descendants.rb +11 -0
  80. data/lib/geoblacklight/relations/query.rb +39 -0
  81. data/lib/geoblacklight/{relation → relations}/relation_response.rb +5 -4
  82. data/lib/geoblacklight/routes/exportable.rb +2 -1
  83. data/lib/geoblacklight/version.rb +1 -1
  84. data/lib/geoblacklight/viewer_record.rb +39 -0
  85. data/lib/geoblacklight.rb +1 -1
  86. data/lib/tasks/geoblacklight.rake +1 -17
  87. data/lib/tasks/solr.rb +37 -0
  88. data/schema/readme.md +1 -1
  89. data/script/wait-for-solr +36 -0
  90. data/solr/conf/solrconfig.xml +10 -16
  91. data/spec/components/geoblacklight/document/sidebar_component_spec.rb +3 -3
  92. data/spec/components/geoblacklight/document_component_spec.rb +8 -34
  93. data/spec/components/geoblacklight/{header_icons_component_spec.rb → header_badges_component_spec.rb} +20 -2
  94. data/spec/components/geoblacklight/item_map_viewer_component_spec.rb +65 -15
  95. data/spec/components/geoblacklight/locator_map_component_spec.rb +54 -0
  96. data/spec/components/geoblacklight/login_link_component_spec.rb +20 -12
  97. data/spec/components/geoblacklight/metadata_description_markdown_component_spec.rb +1 -6
  98. data/spec/components/geoblacklight/overview_map_component_spec.rb +136 -0
  99. data/spec/components/geoblacklight/relations/relation_component_spec.rb +98 -0
  100. data/spec/components/geoblacklight/relations/relations_component_spec.rb +146 -0
  101. data/spec/components/geoblacklight/search_result_component_spec.rb +66 -39
  102. data/spec/components/geoblacklight/static_map_component_spec.rb +8 -2
  103. data/spec/components/geoblacklight/truncatable_metadata_field_layout_component_spec.rb +83 -0
  104. data/spec/controllers/catalog_controller_spec.rb +22 -7
  105. data/spec/controllers/{relation_controller_spec.rb → relations_controller_spec.rb} +1 -1
  106. data/spec/factories/user.rb +6 -1
  107. data/spec/features/axe_spec.rb +5 -3
  108. data/spec/features/home_page_spec.rb +8 -7
  109. data/spec/features/index_view_spec.rb +6 -20
  110. data/spec/features/layer_preview_spec.rb +4 -11
  111. data/spec/features/locator_map_spec.rb +31 -0
  112. data/spec/features/relations_spec.rb +22 -11
  113. data/spec/features/restricted_viewer_spec.rb +14 -0
  114. data/spec/features/search_results_map_spec.rb +89 -13
  115. data/spec/features/search_spec.rb +6 -2
  116. data/spec/features/sign_in_spec.rb +26 -0
  117. data/spec/features/tilejson_spec.rb +1 -3
  118. data/spec/features/tms_spec.rb +2 -2
  119. data/spec/features/truncated_metadata_spec.rb +77 -0
  120. data/spec/features/viewer_requests_spec.rb +40 -0
  121. data/spec/features/viewer_theme_spec.rb +51 -0
  122. data/spec/features/wmts_spec.rb +6 -6
  123. data/spec/features/xyz_spec.rb +3 -3
  124. data/spec/fixtures/solr_documents/README.md +18 -14
  125. data/spec/fixtures/solr_documents/actual-polygon1.json +22 -18
  126. data/spec/fixtures/solr_documents/b1g_wabash_child_15.json +14 -15
  127. data/spec/fixtures/solr_documents/b1g_wabash_child_16.json +14 -15
  128. data/spec/fixtures/solr_documents/b1g_wabash_child_17.json +14 -15
  129. data/spec/fixtures/solr_documents/b1g_wabash_child_18.json +14 -15
  130. data/spec/fixtures/solr_documents/b1g_wabash_parent.json +14 -15
  131. data/spec/fixtures/solr_documents/esri-dynamic-layer-single-layer.json +2 -2
  132. data/spec/fixtures/solr_documents/esri-feature-layer.json +1 -1
  133. data/spec/fixtures/solr_documents/esri-image-map-layer.json +20 -20
  134. data/spec/fixtures/solr_documents/esri-wms-layer.json +22 -24
  135. data/spec/fixtures/solr_documents/index_map_point.json +3 -3
  136. data/spec/fixtures/solr_documents/public_polygon.json +28 -0
  137. data/spec/helpers/geoblacklight_helper_spec.rb +103 -25
  138. data/spec/lib/geoblacklight/bounding_box_spec.rb +16 -0
  139. data/spec/lib/geoblacklight/configuration/relationships_config_spec.rb +121 -0
  140. data/spec/lib/geoblacklight/configuration/settings_attributes_spec.rb +113 -0
  141. data/spec/lib/geoblacklight/configuration/settings_builder_spec.rb +33 -4
  142. data/spec/lib/geoblacklight/references_spec.rb +35 -0
  143. data/spec/lib/geoblacklight/{relation → relations}/ancestors_spec.rb +17 -6
  144. data/spec/lib/geoblacklight/{relation → relations}/descendants_spec.rb +14 -7
  145. data/spec/lib/geoblacklight/{relation → relations}/relation_response_spec.rb +31 -17
  146. data/spec/lib/geoblacklight/viewer_record_spec.rb +69 -0
  147. data/spec/models/concerns/geoblacklight/solr_document/thumbnail_spec.rb +149 -0
  148. data/spec/models/concerns/geoblacklight/solr_document_spec.rb +1 -1
  149. data/spec/requests/bookmarks_spec.rb +2 -1
  150. data/spec/requests/catalog_show_spec.rb +24 -2
  151. data/spec/requests/index_view_spec.rb +50 -2
  152. data/spec/requests/missing_metadata_spec.rb +1 -1
  153. data/spec/requests/relations_spec.rb +9 -2
  154. data/spec/requests/search_results_spec.rb +6 -6
  155. data/spec/requests/viewer_record_spec.rb +37 -0
  156. data/spec/requests/viewer_requests_spec.rb +52 -0
  157. data/spec/solr_config_spec.rb +41 -0
  158. data/spec/solr_fixtures_spec.rb +23 -0
  159. data/spec/spec_helper.rb +13 -3
  160. data/spec/support/authentication.rb +37 -0
  161. data/spec/support/features/map_helpers.rb +68 -0
  162. data/spec/support/features/session_helpers.rb +18 -13
  163. data/spec/support/features/viewer_helpers.rb +20 -0
  164. data/spec/support/features.rb +4 -0
  165. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  166. data/template.rb +1 -1
  167. metadata +72 -84
  168. data/app/components/geoblacklight/accordion_component.html.erb +0 -16
  169. data/app/components/geoblacklight/accordion_component.rb +0 -15
  170. data/app/components/geoblacklight/attribute_table_component.html.erb +0 -15
  171. data/app/components/geoblacklight/attribute_table_component.rb +0 -17
  172. data/app/components/geoblacklight/header_icons_component.html.erb +0 -3
  173. data/app/components/geoblacklight/header_icons_component.rb +0 -27
  174. data/app/components/geoblacklight/index_map_inspect_component.html.erb +0 -12
  175. data/app/components/geoblacklight/index_map_inspect_component.rb +0 -15
  176. data/app/components/geoblacklight/index_map_legend_component.html.erb +0 -14
  177. data/app/components/geoblacklight/index_map_legend_component.rb +0 -24
  178. data/app/components/geoblacklight/location_leaflet_map_component.rb +0 -68
  179. data/app/components/geoblacklight/relations_component.html.erb +0 -23
  180. data/app/components/geoblacklight/relations_component.rb +0 -25
  181. data/app/components/geoblacklight/viewer_help_text_component.html.erb +0 -1
  182. data/app/components/geoblacklight/viewer_help_text_component.rb +0 -46
  183. data/app/controllers/wms_controller.rb +0 -17
  184. data/app/javascript/geoblacklight/controllers/leaflet_viewer_controller.js +0 -240
  185. data/app/javascript/geoblacklight/controllers/openlayers_viewer_controller.js +0 -74
  186. data/app/javascript/geoblacklight/controllers/search_results_controller.js +0 -50
  187. data/app/javascript/geoblacklight/initializers/popovers.js +0 -11
  188. data/app/javascript/geoblacklight/initializers/tooltips.js +0 -51
  189. data/app/javascript/geoblacklight/leaflet/basemaps.js +0 -73
  190. data/app/javascript/geoblacklight/leaflet/constants.js +0 -18
  191. data/app/javascript/geoblacklight/leaflet/controls/geosearch.js +0 -168
  192. data/app/javascript/geoblacklight/leaflet/controls/layer_opacity.js +0 -121
  193. data/app/javascript/geoblacklight/leaflet/controls/sidebar.js +0 -49
  194. data/app/javascript/geoblacklight/leaflet/controls/sleep.js +0 -101
  195. data/app/javascript/geoblacklight/leaflet/inspection.js +0 -210
  196. data/app/javascript/geoblacklight/leaflet/layer_index_map.js +0 -128
  197. data/app/javascript/geoblacklight/leaflet/layer_wmts.js +0 -57
  198. data/app/javascript/geoblacklight/leaflet/layers.js +0 -146
  199. data/app/javascript/geoblacklight/leaflet/utils.js +0 -83
  200. data/app/javascript/geoblacklight/openlayers/basemaps.js +0 -55
  201. data/app/javascript/geoblacklight/openlayers/inspection.js +0 -42
  202. data/app/javascript/geoblacklight/openlayers/layers.js +0 -44
  203. data/app/views/relation/index.json.jbuilder +0 -8
  204. data/lib/geoblacklight/configuration/layer_config.rb +0 -28
  205. data/lib/geoblacklight/configuration/leaflet_config.rb +0 -73
  206. data/lib/geoblacklight/configuration/leaflet_layers_config.rb +0 -33
  207. data/lib/geoblacklight/configuration/leaflet_sleep_config.rb +0 -20
  208. data/lib/geoblacklight/relation/ancestors.rb +0 -31
  209. data/lib/geoblacklight/relation/descendants.rb +0 -31
  210. data/lib/geoblacklight/routes/wms.rb +0 -15
  211. data/lib/geoblacklight/wms_layer/feature_info_response.rb +0 -37
  212. data/lib/geoblacklight/wms_layer.rb +0 -34
  213. data/spec/components/geoblacklight/attribute_table_component_spec.rb +0 -36
  214. data/spec/components/geoblacklight/index_map_legend_component_spec.rb +0 -29
  215. data/spec/components/geoblacklight/viewer_help_text_component_spec.rb +0 -27
  216. data/spec/controllers/wms_controller_spec.rb +0 -34
  217. data/spec/features/configurable_basemap_spec.rb +0 -40
  218. data/spec/features/full_screen_control_spec.rb +0 -15
  219. data/spec/features/layer_inspection_spec.rb +0 -12
  220. data/spec/features/layer_opacity_spec.rb +0 -16
  221. data/spec/fixtures/solr_documents/harvard_raster.json +0 -39
  222. data/spec/fixtures/solr_documents/public_polygon_mit.json +0 -23
  223. data/spec/fixtures/solr_documents/uva_slug_colon.json +0 -29
  224. data/spec/javascripts/geoblacklight_spec.js +0 -11
  225. data/spec/lib/geoblacklight/configuration/layer_config_spec.rb +0 -71
  226. data/spec/lib/geoblacklight/configuration/leaflet_config_spec.rb +0 -129
  227. data/spec/lib/geoblacklight/configuration/leaflet_layers_config_spec.rb +0 -63
  228. data/spec/lib/geoblacklight/configuration_spec.rb +0 -48
  229. data/spec/lib/geoblacklight/wms_layer/feature_info_response_spec.rb +0 -54
  230. data/spec/lib/geoblacklight/wms_layer_spec.rb +0 -115
  231. /data/app/components/geoblacklight/{location_leaflet_map_component.html.erb → locator_map_component.html.erb} +0 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geoblacklight
4
+ module Relations
5
+ # Shared Solr query machinery for finding documents related to a given id via a
6
+ # single field. Subclasses only need to supply the `fq` that expresses their
7
+ # direction (ancestors vs. descendants); everything else - the fields fetched,
8
+ # how many rows, and how the query is executed - is identical either way.
9
+ class Query
10
+ MAX_ROWS = 3
11
+
12
+ def initialize(id, field, repository)
13
+ @search_id = id
14
+ @field = field
15
+ @repository = repository
16
+ end
17
+
18
+ def execute_query
19
+ @repository.connection.send_and_receive(
20
+ @repository.blacklight_config.solr_path,
21
+ params: create_search_params
22
+ )
23
+ end
24
+
25
+ def results
26
+ execute_query["response"]
27
+ end
28
+
29
+ private
30
+
31
+ def shared_search_params
32
+ {rows: MAX_ROWS,
33
+ fl: [Geoblacklight.configuration.fields.title, Geoblacklight.configuration.fields.id,
34
+ Geoblacklight.configuration.fields.resource_type, Geoblacklight.configuration.fields.description,
35
+ Geoblacklight.configuration.fields.resource_class, Geoblacklight.configuration.fields.access_rights]}
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geoblacklight
4
- module Relation
4
+ module Relations
5
5
  class RelationResponse
6
- attr_reader :search_id, :link_id
6
+ attr_reader :search_id, :link_id, :repository
7
+
7
8
  def initialize(id, repository)
8
9
  @link_id = id
9
10
  @search_id = RSolr.solr_escape(id)
@@ -29,9 +30,9 @@ module Geoblacklight
29
30
  def query_type(option)
30
31
  case option.query_type
31
32
  when "ancestors"
32
- Geoblacklight::Relation::Ancestors
33
+ Geoblacklight::Relations::Ancestors
33
34
  when "descendants"
34
- Geoblacklight::Relation::Descendants
35
+ Geoblacklight::Relations::Descendants
35
36
  else
36
37
  fail ArgumentError, "Bad RelationResponse query_type: #{option.query_type}. Only 'ancestors' or 'descendants' is allowed."
37
38
  end
@@ -11,7 +11,8 @@ module Geoblacklight
11
11
  mapper.member do
12
12
  mapper.get "web_services"
13
13
  mapper.get "metadata"
14
- mapper.get "relations" => "relation#index"
14
+ mapper.get "relations" => "relations#index"
15
+ mapper.get "viewer" => "viewer_record#show"
15
16
  end
16
17
  end
17
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geoblacklight
4
- VERSION = "6.0.0-alpha.7"
4
+ VERSION = "6.0.0-beta.2"
5
5
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geoblacklight
4
+ # A record as the item viewer is allowed to see it
5
+ class ViewerRecord
6
+ # These references aren't previewable data, so we don't need to restrict them
7
+ METADATA_REFERENCES = %i[mods fgdc iso19139 html url data_dictionary].freeze
8
+
9
+ # @param document [SolrDocument] the record as indexed
10
+ # @param available [Boolean] see the document_available? helper
11
+ def initialize(document, available:)
12
+ @document = document
13
+ @available = available
14
+ end
15
+
16
+ # If the record is available (public, or restricted and we're authed), return
17
+ # as-is; otherwise strip out references that are previewable data
18
+ # @return [Hash]
19
+ def as_json(options = nil)
20
+ record = @document.as_json(options)
21
+ return record if @available || !record.key?(reference_field)
22
+
23
+ record.merge(reference_field => metadata_references.to_json)
24
+ end
25
+
26
+ private
27
+
28
+ def reference_field
29
+ @document.references.reference_field.to_s
30
+ end
31
+
32
+ # The references we're keeping
33
+ def metadata_references
34
+ @document.references.refs
35
+ .select { |reference| METADATA_REFERENCES.include?(reference.type) }
36
+ .to_h { |reference| reference.reference }
37
+ end
38
+ end
39
+ end
data/lib/geoblacklight.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "zeitwerk"
4
4
  loader = Zeitwerk::Loader.for_gem
5
5
  loader.ignore("#{__dir__}/generators")
6
- loader.collapse("#{__dir__}/geoblacklight/wms_layer")
6
+ loader.ignore("#{__dir__}/tasks")
7
7
  loader.setup
8
8
  require "geoblacklight/engine"
9
9
 
@@ -2,23 +2,7 @@
2
2
 
3
3
  require "rails/generators"
4
4
  require "generators/geoblacklight/install_generator"
5
-
6
- def system_with_error_handling(*args)
7
- Open3.popen3(*args) do |_stdin, stdout, stderr, thread|
8
- puts stdout.read
9
- raise "Unable to run #{args.inspect}: #{stderr.read}" unless thread.value.success?
10
- end
11
- end
12
-
13
- def with_solr(&block)
14
- puts "Starting Solr"
15
- system_with_error_handling "docker compose up -d solr"
16
- sleep 5 # give solr a few seconds to load the core config and be ready
17
- yield
18
- ensure
19
- puts "Stopping Solr"
20
- system_with_error_handling "docker compose stop solr"
21
- end
5
+ require "tasks/solr"
22
6
 
23
7
  namespace :geoblacklight do
24
8
  desc "Run Solr and GeoBlacklight for interactive development"
data/lib/tasks/solr.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helpers for interacting with Solr via docker compose
4
+
5
+ require "open3"
6
+
7
+ # Run in a thread with error handling, so we can ensure Solr gets stopped on failure
8
+ def system_with_error_handling(*args)
9
+ Open3.popen3(*args) do |_stdin, stdout, stderr, thread|
10
+ puts stdout.read
11
+ raise "Unable to run #{args.inspect}: #{stderr.read}" unless thread.value.success?
12
+ end
13
+ end
14
+
15
+ # Downstream applications can create their own compose.yml which will shadow
16
+ # ours; in that case they can change the name of the solr service and set it here.
17
+ def solr_service
18
+ ENV.fetch("SOLR_SERVICE", "solr")
19
+ end
20
+
21
+ def wait_for_solr
22
+ script = File.expand_path("../../script/wait-for-solr", __dir__)
23
+ # Not system_with_error_handling: that buffers stdout until the process exits, so the
24
+ # progress lines would only appear once the wait was already over.
25
+ raise "Unable to run #{script}" unless system(script)
26
+ end
27
+
28
+ # Replacement for solr_wrapper.
29
+ def with_solr(&block)
30
+ puts "Starting Solr"
31
+ system_with_error_handling "docker compose up -d #{solr_service}"
32
+ wait_for_solr
33
+ yield
34
+ ensure
35
+ puts "Stopping Solr"
36
+ system_with_error_handling "docker compose stop #{solr_service}"
37
+ end
data/schema/readme.md CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  This directory contains a [JSON schema vocabulary](http://json-schema.org) file. It is provided for documentation and testing purposes.
4
4
 
5
- - geoblacklight-schema-aardvark.json : This document is formatted in the [OpenGeoMetadata, version Aardvark schema](https://opengeometadata.org/docs/ogm-aardvark), compatible with Geoblacklight version 4.0+.
5
+ - geoblacklight-schema-aardvark.json : This document is formatted in the [OpenGeoMetadata, version Aardvark schema](https://opengeometadata.org/ogm-aardvark), compatible with Geoblacklight version 4.0+.
6
6
 
7
7
  For more information on the metadata schema for GeoBlacklight, see [opengeometadata.org](https://opengeometadata.org)
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Wait until Solr is serving the core, not merely running.
4
+ #
5
+ # `docker compose up -d` returns as soon as the container starts, which is well before Solr
6
+ # has created and loaded its core. It also returns successfully when the host port fails to
7
+ # publish, leaving a container that is healthy inside but unreachable from the host. Both
8
+ # cases used to sail past a `sleep 5` and fail on the first Solr request.
9
+ #
10
+ # The check is deliberately core-scoped. A node-level endpoint such as
11
+ # /solr/admin/info/system answers 200 while the core is still being created, which is the
12
+ # window this is here to close; the core's ping handler answers 404 until the core is there.
13
+ #
14
+ # Usage: script/wait-for-solr
15
+ # SOLR_URL full core URL to poll (default http://127.0.0.1:8983/solr/blacklight-core)
16
+ # SOLR_WAIT_ATTEMPTS give up after this many 2s attempts (default 30)
17
+ # SOLR_SERVICE name of the Solr service in docker-compose.yml (default solr)
18
+ set -uo pipefail
19
+
20
+ url="${SOLR_URL:-http://127.0.0.1:8983/solr/blacklight-core}"
21
+ url="${url%/}"
22
+ attempts="${SOLR_WAIT_ATTEMPTS:-30}"
23
+
24
+ until [ "$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$url/admin/ping")" = "200" ]; do
25
+ attempts=$((attempts - 1))
26
+ if [ "$attempts" -le 0 ]; then
27
+ echo "Solr never became ready at $url/admin/ping" >&2
28
+ echo "Check \`docker compose port ${SOLR_SERVICE:-solr} 8983\`; if it prints nothing, run" >&2
29
+ echo "\`docker compose up -d --force-recreate ${SOLR_SERVICE:-solr}\`" >&2
30
+ exit 1
31
+ fi
32
+ echo "Waiting for Solr to be ready..."
33
+ sleep 2
34
+ done
35
+
36
+ echo "Solr is up and running!"
@@ -117,9 +117,9 @@
117
117
  <str name="q.alt">*:*</str>
118
118
  <str name="qf">
119
119
  text^1
120
- dct_description_ti^2
120
+ dct_description_tmi^2
121
121
  dct_creator_tmi^3
122
- dct_publisher_ti^3
122
+ dct_publisher_tmi^3
123
123
  dct_isPartOf_tmi^4
124
124
  dct_subject_tmi^5
125
125
  dct_spatial_tmi^5
@@ -127,16 +127,16 @@
127
127
  dct_title_ti^6
128
128
  dct_accessRights_ti^7
129
129
  dct_provider_ti^8
130
- gbl_resourceClass_ti^9
131
- gbl_resourceType_ti^9
132
- dct_identifier_ti^10
130
+ gbl_resourceClass_tmi^9
131
+ gbl_resourceType_tmi^9
132
+ dct_identifier_tmi^10
133
133
  id_ti^10
134
134
  </str>
135
135
  <str name="pf"><!-- phrase boost within result set -->
136
136
  text^1
137
- dct_description_ti^2
137
+ dct_description_tmi^2
138
138
  dct_creator_tmi^3
139
- dct_publisher_ti^3
139
+ dct_publisher_tmi^3
140
140
  dct_isPartOf_tmi^4
141
141
  dct_subject_tmi^5
142
142
  dct_spatial_tmi^5
@@ -144,9 +144,9 @@
144
144
  dct_title_ti^6
145
145
  dct_accessRights_ti^7
146
146
  dct_provider_ti^8
147
- gbl_resourceClass_ti^9
148
- gbl_resourceType_ti^9
149
- dct_identifier_ti^10
147
+ gbl_resourceClass_tmi^9
148
+ gbl_resourceType_tmi^9
149
+ dct_identifier_tmi^10
150
150
  id_ti^10
151
151
  </str>
152
152
  <bool name="facet">true</bool>
@@ -179,12 +179,6 @@
179
179
  <lst name="defaults">
180
180
  <str name="echoParams">all</str>
181
181
  </lst>
182
- <!-- An optional feature of the PingRequestHandler is to configure the
183
- handler with a "healthcheckFile" which can be used to enable/disable
184
- the PingRequestHandler.
185
- relative paths are resolved against the data dir
186
- -->
187
- <str name="healthcheckFile">server-enabled.txt</str>
188
182
  </requestHandler>
189
183
 
190
184
  <requestHandler name="/analysis/field"
@@ -17,7 +17,7 @@ RSpec.describe Geoblacklight::Document::SidebarComponent, type: :component do
17
17
  allow_any_instance_of(Blacklight::DocumentHelperBehavior).to receive(:current_bookmarks).and_return([])
18
18
 
19
19
  with_controller_class(CatalogController) do
20
- allow(vc_test_controller).to receive_messages(current_or_guest_user: User.new)
20
+ allow(vc_test_controller).to receive_messages(current_or_guest_user: nil)
21
21
  render_inline(component)
22
22
  end
23
23
  end
@@ -26,7 +26,7 @@ RSpec.describe Geoblacklight::Document::SidebarComponent, type: :component do
26
26
  let(:fixture) { "solr_documents/public_iiif_princeton.json" }
27
27
 
28
28
  it "renders the static map" do
29
- expect(page).to have_css("#static-map")
29
+ expect(page).to have_css("#locator-map")
30
30
  end
31
31
 
32
32
  it "renders the Location label" do
@@ -38,7 +38,7 @@ RSpec.describe Geoblacklight::Document::SidebarComponent, type: :component do
38
38
  let(:fixture) { "solr_documents/restricted-line.json" }
39
39
 
40
40
  it "does not render the static map" do
41
- expect(page).to have_no_css("#static-map")
41
+ expect(page).to have_no_css("#locator-map")
42
42
  end
43
43
 
44
44
  it "does not render the Location label" do
@@ -20,7 +20,7 @@ RSpec.describe Geoblacklight::DocumentComponent, type: :component do
20
20
 
21
21
  before do
22
22
  vc_test_controller.action_name = "show"
23
- allow(vc_test_controller).to receive_messages(view_context: view_context, current_or_guest_user: User.new, blacklight_config: blacklight_config)
23
+ allow(vc_test_controller).to receive_messages(view_context: view_context, current_or_guest_user: nil, blacklight_config: blacklight_config)
24
24
  allow(view_context).to receive_messages(search_session: {}, current_search_session: nil, current_bookmarks: [])
25
25
  render_inline(component)
26
26
  end
@@ -42,51 +42,27 @@ RSpec.describe Geoblacklight::DocumentComponent, type: :component do
42
42
  end
43
43
  end
44
44
 
45
- context "when the document is an index map" do
46
- let(:fixture) { "solr_documents/index-map-stanford.json" }
47
-
48
- it "renders the index map legend" do
49
- expect(page).to have_css(".index-map-legend")
50
- end
51
-
52
- it "renders the index map inspection area" do
53
- expect(page).to have_css(".viewer-information")
54
- end
55
- end
56
-
57
45
  context "when the document has a IIIF manifest" do
58
46
  let(:fixture) { "solr_documents/b1g_iiif_manifest.json" }
59
47
 
60
- it "displays the IIIF help text" do
61
- expect(page).to have_text(I18n.t("geoblacklight.help_text.viewer_protocol.iiif.title"))
62
- end
63
-
64
- it "uses the IIIF tag for the container" do
65
- expect(page).to have_css("div#mirador")
48
+ it "uses the viewer for the container" do
49
+ expect(page).to have_css(".viewer")
66
50
  end
67
51
  end
68
52
 
69
53
  context "when the document has a pmtiles layer" do
70
54
  let(:fixture) { "solr_documents/public_pmtiles_princeton.json" }
71
55
 
72
- it "displays the PM Tiles help text" do
73
- expect(page).to have_text(I18n.t("geoblacklight.help_text.viewer_protocol.pmtiles.title"))
74
- end
75
-
76
- it "uses the Open Layers tag for the container" do
77
- expect(page).to have_css("div#openlayers-viewer")
56
+ it "uses the viewer for the container" do
57
+ expect(page).to have_css(".viewer")
78
58
  end
79
59
  end
80
60
 
81
61
  context "when the document has a WMS layer" do
82
62
  let(:fixture) { "solr_documents/actual-polygon1.json" }
83
63
 
84
- it "displays wms help text" do
85
- expect(page).to have_text(I18n.t("geoblacklight.help_text.viewer_protocol.wms.title"))
86
- end
87
-
88
- it "uses the Leaflet tag for the container" do
89
- expect(page).to have_css("div#leaflet-viewer")
64
+ it "uses the viewer for the container" do
65
+ expect(page).to have_css(".viewer")
90
66
  end
91
67
  end
92
68
 
@@ -94,9 +70,7 @@ RSpec.describe Geoblacklight::DocumentComponent, type: :component do
94
70
  let(:fixture) { "solr_documents/actual-papermap1.json" }
95
71
 
96
72
  it "does not render the viewer" do
97
- expect(page).not_to have_css("div#leaflet-viewer")
98
- expect(page).not_to have_css("div#openlayers-viewer")
99
- expect(page).not_to have_css("div#mirador")
73
+ expect(page).not_to have_css(".viewer")
100
74
  end
101
75
  end
102
76
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "spec_helper"
4
4
 
5
- RSpec.describe Geoblacklight::HeaderIconsComponent, type: :component do
5
+ RSpec.describe Geoblacklight::HeaderBadgesComponent, type: :component do
6
6
  before do
7
7
  render_inline(described_class.new(document: document))
8
8
  end
@@ -10,11 +10,13 @@ RSpec.describe Geoblacklight::HeaderIconsComponent, type: :component do
10
10
  let(:document) { SolrDocument.new(document_attributes) }
11
11
  let(:resource_class) { [] }
12
12
  let(:resource_type) { [] }
13
+ let(:georeferenced) { nil }
13
14
  let(:document_attributes) do
14
15
  {
15
16
  "gbl_resourceClass_sm" => resource_class,
16
17
  "gbl_resourceType_sm" => resource_type,
17
- "dct_accessRights_s" => "Public"
18
+ "dct_accessRights_s" => "Public",
19
+ "gbl_georeferenced_b" => georeferenced
18
20
  }
19
21
  end
20
22
 
@@ -48,4 +50,20 @@ RSpec.describe Geoblacklight::HeaderIconsComponent, type: :component do
48
50
  expect(page).to have_css(".blacklight-icons-raster")
49
51
  end
50
52
  end
53
+
54
+ context "when georeferenced" do
55
+ let(:georeferenced) { true }
56
+
57
+ it "renders the georeferenced icon" do
58
+ expect(page).to have_css(".blacklight-icons-georeferenced")
59
+ end
60
+ end
61
+
62
+ context "when not georeferenced" do
63
+ let(:georeferenced) { false }
64
+
65
+ it "does not render the georeferenced icon" do
66
+ expect(page).not_to have_css(".blacklight-icons-georeferenced")
67
+ end
68
+ end
51
69
  end
@@ -7,30 +7,80 @@ RSpec.describe Geoblacklight::ItemMapViewerComponent, type: :component do
7
7
  render_inline(described_class.new(document: document))
8
8
  end
9
9
 
10
- context "IIIF viewer" do
11
- let(:fixture) { JSON.parse(read_fixture("solr_documents/iiif-eastern-hemisphere.json")) }
12
- let(:document) { SolrDocument.new(fixture) }
10
+ # One viewer for every protocol it can preview: what to show is the viewer's own decision, taken
11
+ # from the references in the record it fetches
12
+ ["solr_documents/iiif-eastern-hemisphere.json",
13
+ "solr_documents/public_pmtiles_princeton.json",
14
+ "solr_documents/actual-polygon1.json"].each do |fixture_path|
15
+ context "with #{File.basename(fixture_path, ".json")}" do
16
+ let(:document) { SolrDocument.new(JSON.parse(read_fixture(fixture_path))) }
13
17
 
14
- it "uses the IIIF tag" do
15
- expect(page).to have_css("div#mirador")
18
+ it "uses the viewer" do
19
+ expect(page).to have_css("ogm-viewer")
20
+ end
21
+
22
+ it "leaves the theme to the page's color mode" do
23
+ expect(page).to have_css("ogm-viewer:not([theme])")
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "the basemap" do
29
+ let(:document) { SolrDocument.new(JSON.parse(read_fixture("solr_documents/actual-polygon1.json"))) }
30
+
31
+ it "is left to the viewer's own default when none is configured" do
32
+ expect(page).to have_css("ogm-viewer:not([light-basemap]):not([dark-basemap])")
33
+ end
34
+
35
+ context "when the application configures its own" do
36
+ before do
37
+ allow(Geoblacklight.configuration).to receive(:light_basemap_url)
38
+ .and_return("https://tiles.example.edu/styles/light/style.json")
39
+ render_inline(described_class.new(document: document))
40
+ end
41
+
42
+ it "names the style document on the viewer" do
43
+ expect(page).to have_css('ogm-viewer[light-basemap="https://tiles.example.edu/styles/light/style.json"]')
44
+ end
16
45
  end
17
46
  end
18
47
 
19
- context "Open layers viewer" do
20
- let(:fixture) { JSON.parse(read_fixture("solr_documents/public_pmtiles_princeton.json")) }
21
- let(:document) { SolrDocument.new(fixture) }
48
+ describe "restricted origins in reference URLs" do
49
+ # Restricted, and provided by this app's own institution
50
+ let(:document) { SolrDocument.new(JSON.parse(read_fixture("solr_documents/actual-raster1.json"))) }
51
+
52
+ before do
53
+ allow(Geoblacklight.configuration).to receive(:restricted_origins).and_return(["https://stacks.stanford.edu/"])
54
+ end
55
+
56
+ context "when signed in" do
57
+ before do
58
+ allow(vc_test_controller).to receive(:current_user).and_return(instance_double(ActiveRecord::Base))
59
+ render_inline(described_class.new(document: document))
60
+ end
61
+
62
+ it "sends them to the viewer as a separate data param" do
63
+ expect(page).to have_css('ogm-viewer[data-restricted-origins=\'["https://stacks.stanford.edu/"]\']')
64
+ end
65
+ end
66
+
67
+ context "when not signed in" do
68
+ before do
69
+ allow(vc_test_controller).to receive(:current_user).and_return(nil)
70
+ render_inline(described_class.new(document: document))
71
+ end
22
72
 
23
- it "uses the open layers tag" do
24
- expect(page).to have_css("div#openlayers-viewer")
73
+ it "does not send them to the viewer" do
74
+ expect(page).to have_css("ogm-viewer:not([data-restricted-origins])")
75
+ end
25
76
  end
26
77
  end
27
78
 
28
- context "Base or leaflet viewer" do
29
- let(:fixture) { JSON.parse(read_fixture("solr_documents/actual-polygon1.json")) }
30
- let(:document) { SolrDocument.new(fixture) }
79
+ context "with an oembed record" do
80
+ let(:document) { SolrDocument.new(JSON.parse(read_fixture("solr_documents/oembed.json"))) }
31
81
 
32
- it "uses the IIIF tag" do
33
- expect(page).to have_css("div#leaflet-viewer")
82
+ it "uses the oembed viewer instead" do
83
+ expect(page).to have_css("div#oembed-viewer")
34
84
  end
35
85
  end
36
86
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Geoblacklight::LocatorMapComponent, type: :component do
6
+ let(:document) { SolrDocument.new(JSON.parse(read_fixture("solr_documents/actual-polygon1.json"))) }
7
+
8
+ subject(:map) { page.find("ogm-locator") }
9
+
10
+ before { render_inline(described_class.new(document: document)) }
11
+
12
+ it "renders a locator the stylesheet can size" do
13
+ expect(map[:id]).to eq "locator-map"
14
+ expect(map[:class]).to eq "viewer locator-map"
15
+ end
16
+
17
+ it "points at the same record endpoint the item viewer reads" do
18
+ expect(map["record-url"]).to be_present
19
+ end
20
+
21
+ it "leaves the theme to the page's color mode" do
22
+ expect(map[:theme]).to be_nil
23
+ end
24
+
25
+ context "when the application turns Blacklight's dark mode support off" do
26
+ before do
27
+ allow_any_instance_of(GeoblacklightHelper).to receive(:geoblacklight_viewer_theme).and_return("light")
28
+ render_inline(described_class.new(document: document))
29
+ end
30
+
31
+ it "passes the light default the helper states through to the viewer" do
32
+ expect(map[:theme]).to eq "light"
33
+ end
34
+ end
35
+
36
+ describe "the basemap" do
37
+ it "is left to the viewer's own default when none is configured" do
38
+ expect(map["light-basemap"]).to be_nil
39
+ expect(map["dark-basemap"]).to be_nil
40
+ end
41
+
42
+ context "when the application configures its own" do
43
+ before do
44
+ allow(Geoblacklight.configuration).to receive(:dark_basemap_url)
45
+ .and_return("https://tiles.example.edu/styles/dark/style.json")
46
+ render_inline(described_class.new(document: document))
47
+ end
48
+
49
+ it "names the style document on the locator too, so every map on the page matches" do
50
+ expect(map["dark-basemap"]).to eq "https://tiles.example.edu/styles/dark/style.json"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -3,26 +3,34 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.describe Geoblacklight::LoginLinkComponent, type: :component do
6
- let(:document) { instance_double(SolrDocument, id: 123) }
6
+ let(:document) { instance_double(SolrDocument, id: 123, restricted?: true, same_institution?: true) }
7
+ let(:login_path) { "/login" }
7
8
 
8
- context "when rendering is required" do
9
- before do
10
- allow(vc_test_controller).to receive(:user_signed_in?).and_return(false)
11
- allow(document).to receive(:restricted?).and_return(true)
12
- allow(document).to receive(:same_institution?).and_return(true)
13
- end
9
+ before do
10
+ allow(vc_test_controller).to receive(:blacklight_login_path).and_return(login_path)
11
+ allow(vc_test_controller).to receive(:current_user).and_return(nil)
12
+ end
14
13
 
15
- it "shows download link" do
14
+ context "when the document is restricted to this institution and no one is signed in" do
15
+ it "links to the sign-in page" do
16
16
  render_inline(described_class.new(document: document))
17
- expect(page).to have_text(I18n.t("geoblacklight.tools.login_to_view"))
17
+ expect(page).to have_link(I18n.t("geoblacklight.tools.login_to_view"), href: login_path)
18
18
  end
19
19
  end
20
20
 
21
- context "when rendering is not required" do
21
+ context "when signed in" do
22
22
  before do
23
- allow(document).to receive(:restricted?).and_return(false)
24
- allow(document).to receive(:same_institution?).and_return(false)
23
+ allow(vc_test_controller).to receive(:current_user).and_return(instance_double(ActiveRecord::Base))
24
+ end
25
+
26
+ it "does not render anything" do
27
+ render_inline(described_class.new(document: document))
28
+ expect(page).not_to have_text(I18n.t("geoblacklight.tools.login_to_view"))
25
29
  end
30
+ end
31
+
32
+ context "when the app has no authentication" do
33
+ let(:login_path) { nil }
26
34
 
27
35
  it "does not render anything" do
28
36
  render_inline(described_class.new(document: document))