geoblacklight 4.0.0.pre.alpha.3 → 4.0.0.pre.rc3

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 (209) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +1 -1
  3. data/.github/workflows/ruby.yml +32 -103
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +12 -6
  6. data/.rubocop_todo.yml +0 -3
  7. data/.solr_wrapper +2 -0
  8. data/README.md +1 -4
  9. data/Rakefile +0 -1
  10. data/app/assets/images/blacklight/child-item.svg +3 -0
  11. data/app/assets/images/blacklight/collections.svg +4 -0
  12. data/app/assets/images/blacklight/datasets.svg +7 -0
  13. data/app/assets/images/blacklight/geoblacklight-icons.json +363 -332
  14. data/app/assets/images/blacklight/imagery.svg +4 -0
  15. data/app/assets/images/blacklight/maps.svg +4 -0
  16. data/app/assets/images/blacklight/parent-item.svg +3 -0
  17. data/app/assets/images/blacklight/university-of-colorado-boulder.svg +6 -0
  18. data/app/assets/images/blacklight/websites.svg +4 -0
  19. data/app/assets/javascripts/geoblacklight/controls/fullscreen.js +8 -0
  20. data/app/assets/javascripts/geoblacklight/geoblacklight.js +2 -1
  21. data/app/assets/javascripts/geoblacklight/viewers/esri.js +1 -0
  22. data/app/assets/javascripts/geoblacklight/viewers/index_map.js +1 -0
  23. data/app/assets/javascripts/geoblacklight/viewers/tilejson.js +33 -0
  24. data/app/assets/javascripts/geoblacklight/viewers/tms.js +2 -2
  25. data/app/assets/javascripts/geoblacklight/viewers/viewer.js +3 -0
  26. data/app/assets/javascripts/geoblacklight/viewers/wms.js +2 -2
  27. data/app/assets/javascripts/geoblacklight/viewers/wmts.js +85 -0
  28. data/app/assets/javascripts/geoblacklight/viewers/xyz.js +10 -0
  29. data/app/assets/stylesheets/geoblacklight/geoblacklight.scss +1 -0
  30. data/app/assets/stylesheets/geoblacklight/modules/_base.scss +0 -1
  31. data/app/assets/stylesheets/geoblacklight/modules/_styles.scss +5 -1
  32. data/app/assets/stylesheets/geoblacklight/modules/downloads.scss +20 -47
  33. data/app/assets/stylesheets/geoblacklight/modules/index_maps.scss +68 -0
  34. data/app/assets/stylesheets/geoblacklight/modules/item.scss +16 -0
  35. data/app/assets/stylesheets/geoblacklight/modules/modal.scss +6 -0
  36. data/app/assets/stylesheets/geoblacklight/modules/sidebar.scss +4 -0
  37. data/app/components/geoblacklight/icon_facet_item_component.rb +33 -0
  38. data/app/controllers/wms_controller.rb +1 -1
  39. data/app/helpers/geoblacklight_helper.rb +6 -45
  40. data/app/models/concerns/geoblacklight/bbox_filter_field.rb +64 -0
  41. data/app/models/concerns/geoblacklight/bbox_filter_query.rb +50 -0
  42. data/app/models/concerns/geoblacklight/solr_document.rb +1 -1
  43. data/app/models/concerns/geoblacklight/suppressed_records_search_behavior.rb +31 -0
  44. data/app/presenters/geoblacklight/bbox_item_presenter.rb +9 -0
  45. data/app/views/catalog/_downloads_collapse.html.erb +27 -0
  46. data/app/views/catalog/_header_icons.html.erb +2 -2
  47. data/app/views/catalog/_index_split_default.html.erb +2 -2
  48. data/app/views/catalog/_show_default_viewer_container.html.erb +17 -0
  49. data/app/views/catalog/_show_downloads.html.erb +10 -21
  50. data/app/views/catalog/_show_sidebar.html.erb +3 -0
  51. data/app/views/catalog/_show_web_services.html.erb +11 -0
  52. data/app/views/catalog/_web_services.html.erb +3 -2
  53. data/app/views/catalog/web_services.html.erb +1 -1
  54. data/app/views/shared/_header_navbar.html.erb +13 -3
  55. data/config/locales/geoblacklight.en.yml +6 -1
  56. data/geoblacklight.gemspec +7 -7
  57. data/lib/generators/geoblacklight/assets_generator.rb +1 -1
  58. data/lib/generators/geoblacklight/install_generator.rb +18 -1
  59. data/lib/generators/geoblacklight/templates/assets/_customizations.scss +5 -4
  60. data/lib/generators/geoblacklight/templates/assets/application.scss +0 -3
  61. data/lib/generators/geoblacklight/templates/catalog_controller.rb +86 -57
  62. data/lib/generators/geoblacklight/templates/settings.gbl_v1.yml +5 -5
  63. data/lib/generators/geoblacklight/templates/settings.yml +62 -25
  64. data/lib/geoblacklight/bounding_box.rb +5 -1
  65. data/lib/geoblacklight/constants.rb +3 -0
  66. data/lib/geoblacklight/download.rb +1 -1
  67. data/lib/geoblacklight/engine.rb +7 -4
  68. data/lib/geoblacklight/faraday_middleware/follow_redirects.rb +176 -0
  69. data/lib/geoblacklight/item_viewer.rb +13 -1
  70. data/lib/geoblacklight/metadata/base.rb +2 -1
  71. data/lib/geoblacklight/metadata_transformer/base.rb +1 -1
  72. data/lib/geoblacklight/version.rb +1 -1
  73. data/lib/geoblacklight/view_helper_override.rb +2 -28
  74. data/lib/geoblacklight.rb +0 -10
  75. data/lib/tasks/geoblacklight.rake +1 -1
  76. data/schema/geoblacklight-schema-aardvark.json +3 -23
  77. data/solr/conf/schema.xml +37 -43
  78. data/solr/conf/solrconfig.xml +17 -17
  79. data/spec/components/geoblacklight/icon_facet_item_component_spec.rb +17 -0
  80. data/spec/config/initializers/rails_config_spec.rb +1 -1
  81. data/spec/controllers/catalog_controller_spec.rb +8 -8
  82. data/spec/controllers/download_controller_spec.rb +4 -4
  83. data/spec/controllers/relation_controller_spec.rb +1 -1
  84. data/spec/controllers/wms_controller_spec.rb +2 -4
  85. data/spec/features/download_layer_spec.rb +31 -14
  86. data/spec/features/esri_viewer_spec.rb +5 -1
  87. data/spec/features/full_screen_controll_spec.rb +15 -0
  88. data/spec/features/home_page_spec.rb +2 -2
  89. data/spec/features/index_map_spec.rb +2 -2
  90. data/spec/features/missing_metadata_spec.rb +1 -1
  91. data/spec/features/multiple_downloads_spec.rb +2 -1
  92. data/spec/features/relations_spec.rb +12 -1
  93. data/spec/features/saved_searches_spec.rb +1 -1
  94. data/spec/features/search_results_complex_geometry_spec.rb +24 -0
  95. data/spec/features/search_results_icons_spec.rb +16 -0
  96. data/spec/features/search_results_map_spec.rb +2 -2
  97. data/spec/features/search_spec.rb +17 -0
  98. data/spec/features/show_page_download_spec.rb +6 -3
  99. data/spec/features/show_page_metadata_spec.rb +2 -2
  100. data/spec/features/split_view.html.erb_spec.rb +12 -1
  101. data/spec/features/tilejson_spec.rb +22 -0
  102. data/spec/features/tms_spec.rb +2 -2
  103. data/spec/features/web_services_modal_spec.rb +35 -2
  104. data/spec/features/wmts_spec.rb +34 -0
  105. data/spec/features/xyz_spec.rb +10 -0
  106. data/spec/fixtures/manifests/tilejson.json +21 -0
  107. data/spec/fixtures/manifests/wmts-multiple.xml +813 -0
  108. data/spec/fixtures/manifests/wmts-single.xml +126 -0
  109. data/spec/fixtures/solr_documents/README.md +46 -43
  110. data/spec/fixtures/solr_documents/actual-papermap1.json +2 -1
  111. data/spec/fixtures/solr_documents/actual-point1.json +2 -1
  112. data/spec/fixtures/solr_documents/actual-polygon1.json +2 -1
  113. data/spec/fixtures/solr_documents/actual-raster1.json +3 -2
  114. data/spec/fixtures/solr_documents/b1g_wabash_child_15.json +62 -0
  115. data/spec/fixtures/solr_documents/b1g_wabash_child_16.json +64 -0
  116. data/spec/fixtures/solr_documents/b1g_wabash_child_17.json +62 -0
  117. data/spec/fixtures/solr_documents/b1g_wabash_child_18.json +62 -0
  118. data/spec/fixtures/solr_documents/b1g_wabash_parent.json +59 -0
  119. data/spec/fixtures/solr_documents/baruch_ancestor1.json +2 -1
  120. data/spec/fixtures/solr_documents/baruch_ancestor2.json +2 -1
  121. data/spec/fixtures/solr_documents/baruch_documentation_download.json +1 -1
  122. data/spec/fixtures/solr_documents/bbox-spans-180.json +2 -1
  123. data/spec/fixtures/solr_documents/cornell_html_metadata.json +4 -3
  124. data/spec/fixtures/solr_documents/esri-dynamic-layer-all-layers.json +3 -2
  125. data/spec/fixtures/solr_documents/esri-dynamic-layer-single-layer.json +3 -2
  126. data/spec/fixtures/solr_documents/esri-feature-layer.json +2 -1
  127. data/spec/fixtures/solr_documents/esri-image-map-layer.json +3 -2
  128. data/spec/fixtures/solr_documents/esri-tiled_map_layer.json +2 -1
  129. data/spec/fixtures/solr_documents/esri-wms-layer.json +2 -1
  130. data/spec/fixtures/solr_documents/harvard_raster.json +3 -2
  131. data/spec/fixtures/solr_documents/iiif-eastern-hemisphere.json +3 -2
  132. data/spec/fixtures/solr_documents/index-map-polygon-no-downloadurl.json +2 -1
  133. data/spec/fixtures/solr_documents/index-map-polygon.json +2 -1
  134. data/spec/fixtures/solr_documents/index-map-stanford.json +2 -1
  135. data/spec/fixtures/solr_documents/index_map_point.json +3 -2
  136. data/spec/fixtures/solr_documents/metadata_no_provider.json +2 -1
  137. data/spec/fixtures/solr_documents/multiple-downloads.json +3 -2
  138. data/spec/fixtures/solr_documents/no_spatial.json +1 -4
  139. data/spec/fixtures/solr_documents/oembed.json +2 -1
  140. data/spec/fixtures/solr_documents/princeton-child1.json +3 -2
  141. data/spec/fixtures/solr_documents/princeton-child2.json +3 -2
  142. data/spec/fixtures/solr_documents/princeton-child3.json +2 -1
  143. data/spec/fixtures/solr_documents/princeton-child4.json +3 -2
  144. data/spec/fixtures/solr_documents/princeton-parent.json +5 -3
  145. data/spec/fixtures/solr_documents/public_direct_download.json +2 -1
  146. data/spec/fixtures/solr_documents/public_iiif_princeton.json +3 -2
  147. data/spec/fixtures/solr_documents/public_polygon_mit.json +2 -1
  148. data/spec/fixtures/solr_documents/restricted-line.json +2 -1
  149. data/spec/fixtures/solr_documents/tilejson.json +48 -0
  150. data/spec/fixtures/solr_documents/tms.json +15 -18
  151. data/spec/fixtures/solr_documents/umn_metro_result1.json +5 -3
  152. data/spec/fixtures/solr_documents/umn_state_result1.json +3 -2
  153. data/spec/fixtures/solr_documents/umn_state_result2.json +3 -5
  154. data/spec/fixtures/solr_documents/uva_slug_colon.json +2 -1
  155. data/spec/fixtures/solr_documents/wmts-multiple.json +41 -0
  156. data/spec/fixtures/solr_documents/wmts-single-layer.json +48 -0
  157. data/spec/fixtures/solr_documents/xyz.json +46 -0
  158. data/spec/helpers/geoblacklight_helper_spec.rb +14 -37
  159. data/spec/lib/geoblacklight/document_presenter_spec.rb +3 -3
  160. data/spec/lib/geoblacklight/download/geojson_download_spec.rb +1 -1
  161. data/spec/lib/geoblacklight/download/geotiff_download_spec.rb +1 -1
  162. data/spec/lib/geoblacklight/download/kmz_download_spec.rb +1 -1
  163. data/spec/lib/geoblacklight/download/shapefile_download_spec.rb +1 -1
  164. data/spec/lib/geoblacklight/download_spec.rb +2 -2
  165. data/spec/lib/geoblacklight/metadata/base_spec.rb +19 -1
  166. data/spec/lib/geoblacklight/metadata_transformer/fgdc_spec.rb +1 -1
  167. data/spec/lib/geoblacklight/metadata_transformer/iso19139_spec.rb +1 -1
  168. data/spec/lib/geoblacklight/references_spec.rb +5 -3
  169. data/spec/lib/geoblacklight/relation/relation_response_spec.rb +5 -0
  170. data/spec/lib/geoblacklight/view_helper_override_spec.rb +0 -10
  171. data/spec/lib/geoblacklight/wms_layer_spec.rb +1 -1
  172. data/spec/models/concerns/geoblacklight/bbox_filter_field_spec.rb +96 -0
  173. data/spec/models/concerns/geoblacklight/bbox_filter_query_spec.rb +105 -0
  174. data/spec/models/concerns/geoblacklight/solr_document/inspection_spec.rb +2 -1
  175. data/spec/models/concerns/geoblacklight/suppressed_records_search_behavior_spec.rb +31 -0
  176. data/spec/presenters/geoblacklight/bbox_item_presenter_spec.rb +36 -0
  177. data/spec/spec_helper.rb +8 -3
  178. data/spec/test_app_templates/Gemfile.extra +1 -0
  179. data/spec/test_app_templates/lib/generators/test_app_generator.rb +4 -4
  180. data/spec/views/catalog/_results_pagination.html.erb_spec.rb +1 -1
  181. data/spec/views/catalog/_show_downloads.html.erb_spec.rb +6 -6
  182. data/template.rb +2 -4
  183. data/vendor/assets/images/fullscreen.png +0 -0
  184. data/vendor/assets/images/fullscreen@2x.png +0 -0
  185. data/vendor/assets/javascripts/Leaflet.fullscreen.js +152 -0
  186. data/vendor/assets/javascripts/esri-leaflet.js +10 -3
  187. data/vendor/assets/javascripts/esri-leaflet.js.map +1 -1
  188. data/vendor/assets/javascripts/leaflet-iiif.js +39 -18
  189. data/vendor/assets/javascripts/leaflet-src.js.erb +14126 -0
  190. data/vendor/assets/javascripts/leaflet-src.js.map +1 -1
  191. data/vendor/assets/stylesheets/leaflet.css +640 -634
  192. data/vendor/assets/stylesheets/leaflet.fullscreen.css +40 -0
  193. metadata +102 -49
  194. data/app/models/concerns/geoblacklight/spatial_search_behavior.rb +0 -71
  195. data/app/views/catalog/_download_generated_link.html.erb +0 -4
  196. data/app/views/catalog/_download_link.html.erb +0 -3
  197. data/app/views/catalog/_downloads_generated.html.erb +0 -6
  198. data/app/views/catalog/_downloads_primary.html.erb +0 -21
  199. data/app/views/catalog/_downloads_secondary.html.erb +0 -39
  200. data/app/views/catalog/_icon_facet.html.erb +0 -16
  201. data/bin/coverage.rb +0 -36
  202. data/lib/generators/geoblacklight/templates/Procfile +0 -3
  203. data/lib/generators/geoblacklight/templates/package.json +0 -14
  204. data/lib/generators/geoblacklight/templates/webpacker.yml +0 -67
  205. data/lib/generators/geoblacklight/webpacker_generator.rb +0 -36
  206. data/lib/geoblacklight/catalog_helper_override.rb +0 -14
  207. data/spec/models/concerns/geoblacklight/spatial_search_behavior_spec.rb +0 -97
  208. data/vendor/assets/javascripts/leaflet.js.erb +0 -13922
  209. data/vendor/assets/stylesheets/leaflet-label.css +0 -54
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+ # :nocov:
3
+ require 'faraday'
4
+ require 'set'
5
+
6
+ module Geoblacklight
7
+ # NOTE: We copied this class from faraday_middleware in order to support
8
+ # both Faraday 1 & 2. If this middleware is ever extracted from
9
+ # faraday_middleware into its own gem we should remove this and use that
10
+ # instead.
11
+ module FaradayMiddleware
12
+ # Exception thrown when the maximum amount of requests is
13
+ # exceeded.
14
+ class RedirectLimitReached < ::Faraday::ClientError
15
+ attr_reader :response
16
+
17
+ def initialize(response)
18
+ super "too many redirects; last one to: #{response['location']}"
19
+ @response = response
20
+ end
21
+ end
22
+
23
+ # Public: Follow HTTP 301, 302, 303, 307, and 308 redirects.
24
+ #
25
+ # For HTTP 301, 302, and 303, the original GET, POST, PUT, DELETE, or PATCH
26
+ # request gets converted into a GET. With `:standards_compliant => true`,
27
+ # however, the HTTP method after 301/302 remains unchanged. This allows you
28
+ # to opt into HTTP/1.1 compliance and act unlike the major web browsers.
29
+ #
30
+ # This middleware currently only works with synchronous requests; i.e. it
31
+ # doesn't support parallelism.
32
+ #
33
+ # If you wish to persist cookies across redirects, you could use
34
+ # the faraday-cookie_jar gem:
35
+ #
36
+ # Faraday.new(:url => url) do |faraday|
37
+ # faraday.use FaradayMiddleware::FollowRedirects
38
+ # faraday.use :cookie_jar
39
+ # faraday.adapter Faraday.default_adapter
40
+ # end
41
+ #
42
+ class FollowRedirects < ::Faraday::Middleware
43
+ # HTTP methods for which 30x redirects can be followed
44
+ ALLOWED_METHODS = Set.new [:head, :options, :get, :post, :put, :patch, :delete]
45
+ # HTTP redirect status codes that this middleware implements
46
+ REDIRECT_CODES = Set.new [301, 302, 303, 307, 308]
47
+ # Keys in env hash which will get cleared between requests
48
+ ENV_TO_CLEAR = Set.new [:status, :response, :response_headers]
49
+
50
+ # Default value for max redirects followed
51
+ FOLLOW_LIMIT = 3
52
+
53
+ # Regex that matches characters that need to be escaped in URLs, sans
54
+ # the "%" character which we assume already represents an escaped sequence.
55
+ URI_UNSAFE = %r{[^\-_.!~*'()a-zA-Z\d;/?:@&=+$,\[\]%]}.freeze
56
+
57
+ AUTH_HEADER = 'Authorization'
58
+
59
+ # Public: Initialize the middleware.
60
+ #
61
+ # options - An options Hash (default: {}):
62
+ # :limit - A Numeric redirect limit (default: 3)
63
+ # :standards_compliant - A Boolean indicating whether to respect
64
+ # the HTTP spec when following 301/302
65
+ # (default: false)
66
+ # :callback - A callable used on redirects
67
+ # with the old and new envs
68
+ # :cookies - An Array of Strings (e.g.
69
+ # ['cookie1', 'cookie2']) to choose
70
+ # cookies to be kept, or :all to keep
71
+ # all cookies (default: []).
72
+ # :clear_authorization_header - A Boolean indicating whether the request
73
+ # Authorization header should be cleared on
74
+ # redirects (default: true)
75
+ def initialize(app, options = {})
76
+ super(app)
77
+ @options = options
78
+
79
+ @convert_to_get = Set.new [303]
80
+ @convert_to_get << 301 << 302 unless standards_compliant?
81
+ end
82
+
83
+ def call(env)
84
+ perform_with_redirection(env, follow_limit)
85
+ end
86
+
87
+ private
88
+
89
+ def convert_to_get?(response)
90
+ [:head, :options].exclude?(response.env[:method]) &&
91
+ @convert_to_get.include?(response.status)
92
+ end
93
+
94
+ def perform_with_redirection(env, follows)
95
+ request_body = env[:body]
96
+ response = @app.call(env)
97
+
98
+ response.on_complete do |response_env|
99
+ if follow_redirect?(response_env, response)
100
+ fail RedirectLimitReached, response if follows.zero?
101
+
102
+ new_request_env = update_env(response_env.dup, request_body, response)
103
+ callback&.call(response_env, new_request_env)
104
+ response = perform_with_redirection(new_request_env, follows - 1)
105
+ end
106
+ end
107
+ response
108
+ end
109
+
110
+ def update_env(env, request_body, response)
111
+ redirect_from_url = env[:url].to_s
112
+ redirect_to_url = safe_escape(response['location'] || '')
113
+ env[:url] += redirect_to_url
114
+
115
+ ENV_TO_CLEAR.each { |key| env.delete key }
116
+
117
+ if convert_to_get?(response)
118
+ env[:method] = :get
119
+ env[:body] = nil
120
+ else
121
+ env[:body] = request_body
122
+ end
123
+
124
+ clear_authorization_header(env, redirect_from_url, redirect_to_url)
125
+
126
+ env
127
+ end
128
+
129
+ def follow_redirect?(env, response)
130
+ ALLOWED_METHODS.include?(env[:method]) &&
131
+ REDIRECT_CODES.include?(response.status)
132
+ end
133
+
134
+ def follow_limit
135
+ @options.fetch(:limit, FOLLOW_LIMIT)
136
+ end
137
+
138
+ def standards_compliant?
139
+ @options.fetch(:standards_compliant, false)
140
+ end
141
+
142
+ def callback
143
+ @options[:callback]
144
+ end
145
+
146
+ # Internal: escapes unsafe characters from an URL which might be a path
147
+ # component only or a fully qualified URI so that it can be joined onto an
148
+ # URI:HTTP using the `+` operator. Doesn't escape "%" characters so to not
149
+ # risk double-escaping.
150
+ def safe_escape(uri)
151
+ uri = uri.split('#')[0] # we want to remove the fragment if present
152
+ uri.to_s.gsub(URI_UNSAFE) do |match|
153
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
154
+ end
155
+ end
156
+
157
+ def clear_authorization_header(env, from_url, to_url)
158
+ return env if redirect_to_same_host?(from_url, to_url)
159
+ return env unless @options.fetch(:clear_authorization_header, true)
160
+
161
+ env[:request_headers].delete(AUTH_HEADER)
162
+ end
163
+
164
+ def redirect_to_same_host?(from_url, to_url)
165
+ return true if to_url.start_with?('/')
166
+
167
+ from_uri = URI.parse(from_url)
168
+ to_uri = URI.parse(to_url)
169
+
170
+ [from_uri.scheme, from_uri.host, from_uri.port] ==
171
+ [to_uri.scheme, to_uri.host, to_uri.port]
172
+ end
173
+ end
174
+ end
175
+ end
176
+ # :nocov:
@@ -51,8 +51,20 @@ module Geoblacklight
51
51
  @references.tms
52
52
  end
53
53
 
54
+ def xyz
55
+ @references.xyz
56
+ end
57
+
58
+ def tilejson
59
+ @references.tilejson
60
+ end
61
+
62
+ def wmts
63
+ @references.wmts
64
+ end
65
+
54
66
  def viewer_preference
55
- [oembed, index_map, tms, wms, iiif, tiled_map_layer, dynamic_map_layer,
67
+ [oembed, index_map, tilejson, xyz, wmts, tms, wms, iiif, tiled_map_layer, dynamic_map_layer,
56
68
  image_map_layer, feature_layer].compact.map(&:to_hash).first
57
69
  end
58
70
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'geoblacklight/faraday_middleware/follow_redirects'
2
3
  module Geoblacklight
3
4
  module Metadata
4
5
  ##
@@ -47,7 +48,7 @@ module Geoblacklight
47
48
  # connection error
48
49
  def retrieve_metadata
49
50
  connection = Faraday.new(url: @reference.endpoint) do |conn|
50
- conn.use FaradayMiddleware::FollowRedirects
51
+ conn.use Geoblacklight::FaradayMiddleware::FollowRedirects
51
52
  conn.adapter Faraday.default_adapter
52
53
  end
53
54
  begin
@@ -31,7 +31,7 @@ module Geoblacklight
31
31
  def cleaned_metadata
32
32
  transformed_doc = Nokogiri::XML(@metadata.to_html)
33
33
  if transformed_doc.xpath('//body').children.empty?
34
- fail TransformError,\
34
+ fail TransformError, \
35
35
  'Failed to extract the <body> child elements from the transformed metadata'
36
36
  end
37
37
  transformed_doc.xpath('//body').children
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Geoblacklight
3
- VERSION = '4.0.0-alpha.3'
3
+ VERSION = '4.0.0-rc3'
4
4
  end
@@ -1,41 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
  module Geoblacklight
3
+ # Override Blacklight helpers to inject behavior
3
4
  module ViewHelperOverride
4
- include CatalogHelperOverride
5
-
6
- def spatial_parameters?
7
- params[:bbox]
8
- end
9
-
10
- # Overrides BL method to enable results for spatial only params
11
- def has_search_parameters?
12
- spatial_parameters? || super
13
- end
14
-
15
- def query_has_constraints?(localized_params = params)
16
- has_search_parameters? || super(localized_params)
17
- end
18
-
19
5
  def render_search_to_s(params)
20
6
  super + render_search_to_s_bbox(params)
21
7
  end
22
8
 
23
9
  def render_search_to_s_bbox(params)
24
10
  return ''.html_safe if params['bbox'].blank?
25
- render_search_to_s_element(t('geoblacklight.bbox_label'), render_filter_value(params['bbox']))
26
- end
27
11
 
28
- def render_constraints_filters(localized_params = params)
29
- content = super(localized_params)
30
- localized_params = localized_params.to_h if localized_params.respond_to?(:to_h)
31
-
32
- if localized_params[:bbox]
33
- path = search_action_path(remove_spatial_filter_group(:bbox, localized_params))
34
- content << render_constraint_element(t('geoblacklight.bbox_label'),
35
- localized_params[:bbox], remove: path)
36
- end
37
-
38
- content
12
+ render_search_to_s_element(t('geoblacklight.bbox_label'), render_filter_value(params['bbox']))
39
13
  end
40
14
  end
41
15
  end
data/lib/geoblacklight.rb CHANGED
@@ -4,7 +4,6 @@ require 'geoblacklight/engine'
4
4
 
5
5
  module Geoblacklight
6
6
  require 'geoblacklight/bounding_box'
7
- require 'geoblacklight/catalog_helper_override'
8
7
  require 'geoblacklight/constants'
9
8
  require 'geoblacklight/exceptions'
10
9
  require 'geoblacklight/geometry'
@@ -34,15 +33,6 @@ module Geoblacklight
34
33
  require 'geoblacklight/relation/ancestors'
35
34
  require 'geoblacklight/relation/relation_response'
36
35
 
37
- def self.inject!
38
- CatalogController.send(:include, Geoblacklight::CatalogHelperOverride)
39
- CatalogController.send(:include, Geoblacklight::ViewHelperOverride)
40
- CatalogController.send(:helper, Geoblacklight::ViewHelperOverride) unless
41
- CatalogController.helpers.is_a?(Geoblacklight::ViewHelperOverride)
42
- SearchHistoryController.send(:helper, Geoblacklight::ViewHelperOverride) unless
43
- SearchHistoryController.helpers.is_a?(Geoblacklight::ViewHelperOverride)
44
- end
45
-
46
36
  def self.logger
47
37
  ::Rails.logger
48
38
  end
@@ -87,7 +87,7 @@ namespace :geoblacklight do
87
87
  fail 'Please supply required arguments [document_id, download_type and timeout]'
88
88
  end
89
89
  document = Geoblacklight::SolrDocument.find(args[:doc_id])
90
- fail Blacklight::Exceptions::RecordNotFound if document[:layer_slug_s] != args[:doc_id]
90
+ fail Blacklight::Exceptions::RecordNotFound if document[:id] != args[:doc_id]
91
91
  download = "Geoblacklight::#{args[:download_type].capitalize}Download"
92
92
  .constantize.new(document, timeout: args[:timeout].to_i)
93
93
  download.get
@@ -67,28 +67,7 @@
67
67
  "dcat_theme_sm": {
68
68
  "type": "array",
69
69
  "items": {
70
- "type": "string",
71
- "enum": [
72
- "Farming",
73
- "Biota",
74
- "Boundaries",
75
- "Climatology, Meteorology and Atmosphere",
76
- "Economy",
77
- "Elevation",
78
- "Environment",
79
- "Geoscientific Information",
80
- "Health",
81
- "Imagery and Base Maps",
82
- "Intelligence and Military",
83
- "Inland Waters",
84
- "Location",
85
- "Oceans",
86
- "Planning and Cadastral",
87
- "Society",
88
- "Structure",
89
- "Transportation",
90
- "Utilities and Communications"
91
- ]
70
+ "type": "string"
92
71
  }
93
72
  },
94
73
  "dcat_keyword_sm": {
@@ -123,7 +102,8 @@
123
102
  }
124
103
  },
125
104
  "locn_geometry": { "type": "string" },
126
- "dcat_centroid_ss": { "type": "string" },
105
+ "dcat_bbox": { "type": "string" },
106
+ "dcat_centroid": { "type": "string" },
127
107
  "dct_relation_sm": {
128
108
  "type": "array",
129
109
  "items": {
data/solr/conf/schema.xml CHANGED
@@ -4,20 +4,36 @@
4
4
  <fields>
5
5
  <field name="_version_" type="long" stored="true" indexed="true"/>
6
6
  <field name="timestamp" type="date" stored="true" indexed="true" default="NOW"/>
7
- <field name="geoblacklight_version" type="string" stored="true" indexed="true"/>
8
- <field name="id" type="string" stored="true" indexed="true" required="true"/>
7
+ <field name="id" type="string" stored="true" indexed="true" required="true"/>
9
8
 
10
9
  <!-- core generated fields -->
11
10
  <field name="text" type="text_en" stored="false" indexed="true" multiValued="true"
12
11
  termVectors="true" termPositions="true" termOffsets="true" />
13
12
 
13
+ <!-- Spatial Field Type: Represents the exent of the resource and powers map search functionality.
14
+ Value can be any valid WKT or ENVELOPE String:
15
+ <field name="locn_geometry">POLYGON((1 8, 1 9, 2 9, 2 8, 1 8))</field>
16
+ <field name="locn_geometry">ENVELOPE(-117.312, -115.39, 84.31, 83.1)</field> -->
17
+ <field name="locn_geometry" type="location_geo3d" stored="true" indexed="true"/>
18
+
19
+ <!-- Spatial Field Type: The bounding box of the resource. Used in overlap ratio boosting.
20
+ Value must be an ENVELOPE String:
21
+ <field name="dcat_bbox">ENVELOPE(-117.312, -115.39, 84.31, 83.1)</field> -->
22
+ <field name="dcat_bbox" type="location_rpt" stored="true" indexed="true"/>
23
+
24
+ <!-- Spatial Field Type: Used to display the center point of a resource. -->
25
+ <field name="dcat_centroid" type="location" stored="true" indexed="true"/>
26
+
27
+ <!-- Spatial Field Type: Internal field used for overlap ratio boosting. -->
28
+ <field name="solr_bboxtype" type="bbox" stored="true" indexed="true"/>
29
+
14
30
  <!-- dynamic field with simple types by suffix -->
15
31
  <dynamicField name="*_b" type="boolean" stored="true" indexed="true"/>
16
32
  <dynamicField name="*_d" type="double" stored="true" indexed="true"/>
17
33
  <dynamicField name="*_dt" type="date" stored="true" indexed="true"/>
18
34
  <dynamicField name="*_f" type="float" stored="true" indexed="true"/>
19
35
  <dynamicField name="*_i" type="int" stored="true" indexed="true"/>
20
- <dynamicField name="*_im" type="int" stored="true" indexed="true" multiValued="true" />
36
+ <dynamicField name="*_im" type="int" stored="true" indexed="true" multiValued="true" sortMissingLast="true" />
21
37
  <dynamicField name="*_l" type="long" stored="true" indexed="true"/>
22
38
  <dynamicField name="*_s" type="string" stored="true" indexed="true"/>
23
39
  <dynamicField name="*_ss" type="string" stored="true" indexed="false"/>
@@ -44,31 +60,6 @@
44
60
 
45
61
  <!-- date range (_drsim) -->
46
62
  <dynamicField name="*_drsim" type="dateRange" stored="true" indexed="true" multiValued="true"/>
47
-
48
- <!-- Spatial field types:
49
-
50
- Solr3:
51
- <field name="my_pt">83.1,-117.312</field>
52
- as (y,x)
53
-
54
- Solr4:
55
-
56
- <field name="my_bbox">-117.312 83.1 -115.39 84.31</field>
57
- as (W S E N)
58
-
59
- <field name="my_geom">ENVELOPE(-117.312, -115.39, 84.31, 83.1)</field>
60
- as (W E N S)
61
-
62
- <field name="my_jts">POLYGON((1 8, 1 9, 2 9, 2 8, 1 8))</field>
63
- as WKT for point, linestring, polygon
64
-
65
- -->
66
- <dynamicField name="*_pt" type="location" stored="true" indexed="true"/>
67
- <dynamicField name="*_bbox" type="location_rpt" stored="true" indexed="true"/><!-- deprecated -->
68
- <dynamicField name="*_geom" type="location_rpt" stored="true" indexed="true"/>
69
- <dynamicField name="*_geometry" type="location_rpt" stored="true" indexed="true"/>
70
- <dynamicField name="*_bboxtype" type="bbox" stored="true" indexed="true"/>
71
-
72
63
  </fields>
73
64
 
74
65
  <types>
@@ -146,32 +137,36 @@
146
137
  </fieldType>
147
138
 
148
139
  <!-- Spatial field types -->
149
- <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_d"/>
150
-
140
+ <fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/>
151
141
  <fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
152
142
  geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers"/>
143
+ <fieldType name="location_geo3d"
144
+ class="solr.SpatialRecursivePrefixTreeFieldType"
145
+ spatialContextFactory="Geo3D"
146
+ prefixTree="s2"
147
+ geo="true"
148
+ maxDistErr="0.001"
149
+ planetModel="WGS84"/>
150
+
153
151
  <!-- Adding field type for bboxField that enables, among other things, overlap ratio calculations -->
154
152
  <fieldType name="bbox" class="solr.BBoxField"
155
153
  geo="true" distanceUnits="kilometers" numberType="pdouble" />
156
154
  <fieldType name="pdouble" class="solr.DoublePointField" docValues="true"/>
157
-
158
-
159
155
  </types>
160
156
 
161
157
  <!-- for scoring formula -->
162
158
  <copyField source="dct_spatial_sm" dest="dct_spatial_tmi" maxChars="10000"/>
163
159
  <copyField source="dct_temporal_sm" dest="dct_temporal_tmi" maxChars="10000"/>
164
- <copyField source="dct_creator_sm" dest="dc_creator_tmi" maxChars="1000"/>
165
- <copyField source="dct_description_sm" dest="dc_description_tmi" maxChars="10000"/>
166
- <copyField source="dct_format_s" dest="dc_format_ti" maxChars="100"/>
167
- <copyField source="dct_identifier_sm" dest="dc_identifier_tmi" maxChars="100"/>
168
- <copyField source="dct_publisher_sm" dest="dc_publisher_tmi" maxChars="1000"/>
169
- <copyField source="dct_accessRights_s" dest="dc_rights_ti" maxChars="100"/>
160
+ <copyField source="dct_creator_sm" dest="dct_creator_tmi" maxChars="1000"/>
161
+ <copyField source="dct_description_sm" dest="dct_description_tmi" maxChars="10000"/>
162
+ <copyField source="dct_format_s" dest="dct_format_ti" maxChars="100"/>
163
+ <copyField source="dct_identifier_sm" dest="dct_identifier_tmi" maxChars="100"/>
164
+ <copyField source="dct_publisher_sm" dest="dct_publisher_tmi" maxChars="1000"/>
165
+ <copyField source="dct_accessRights_s" dest="dct_accessRights_ti" maxChars="100"/>
170
166
  <copyField source="schema_provider_s" dest="dct_provider_ti" maxChars="1000"/>
171
- <copyField source="dct_subject_sm" dest="dc_subject_tmi" maxChars="10000"/>
172
- <copyField source="dct_title_s" dest="dc_title_ti" maxChars="1000"/>
167
+ <copyField source="dct_subject_sm" dest="dct_subject_tmi" maxChars="10000"/>
168
+ <copyField source="dct_title_s" dest="dct_title_ti" maxChars="1000"/>
173
169
  <copyField source="dct_isPartOf_sm" dest="dct_isPartOf_tmi" maxChars="1000"/>
174
- <copyField source="locn_geometry_s" dest="layer_geom_type_ti" maxChars="100"/>
175
170
  <copyField source="id" dest="layer_slug_ti" maxChars="100"/>
176
171
 
177
172
  <!-- core text search -->
@@ -180,7 +175,6 @@
180
175
 
181
176
  <!-- for sorting text fields -->
182
177
  <copyField source="schema_provider_s" dest="schema_provider_sort"/>
183
- <copyField source="dct_publisher_sm" dest="dc_publisher_sort"/>
184
178
  <copyField source="dct_title_s" dest="dct_title_sort"/>
185
179
 
186
180
  <!-- for spell checking -->
@@ -200,5 +194,5 @@
200
194
  <copyField source="dct_spatial_sm" dest="suggest"/>
201
195
 
202
196
  <!-- for bbox value -->
203
- <copyField source="locn_geometry" dest="solr_bboxtype"/>
197
+ <copyField source="dcat_bbox" dest="solr_bboxtype"/>
204
198
  </schema>
@@ -70,9 +70,9 @@
70
70
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
71
71
  <query>
72
72
  <maxBooleanClauses>1024</maxBooleanClauses>
73
- <filterCache class="solr.FastLRUCache" size="512" initialSize="512" autowarmCount="0"/>
74
- <queryResultCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/>
75
- <documentCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/>
73
+ <filterCache class="solr.CaffeineCache" size="512" initialSize="512" autowarmCount="0" async="true"/>
74
+ <queryResultCache class="solr.CaffeineCache" size="512" initialSize="512" autowarmCount="0" async="true"/>
75
+ <documentCache class="solr.CaffeineCache" size="512" initialSize="512" autowarmCount="0" async="true"/>
76
76
  <enableLazyFieldLoading>true</enableLazyFieldLoading>
77
77
  <queryResultWindowSize>20</queryResultWindowSize>
78
78
  <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
@@ -117,35 +117,35 @@
117
117
  <str name="q.alt">*:*</str>
118
118
  <str name="qf">
119
119
  text^1
120
- dc_description_ti^2
121
- dc_creator_tmi^3
122
- dc_publisher_ti^3
120
+ dct_description_ti^2
121
+ dct_creator_tmi^3
122
+ dct_publisher_ti^3
123
123
  dct_isPartOf_tmi^4
124
- dc_subject_tmi^5
124
+ dct_subject_tmi^5
125
125
  dct_spatial_tmi^5
126
126
  dct_temporal_tmi^5
127
- dc_title_ti^6
128
- dc_rights_ti^7
127
+ dct_title_ti^6
128
+ dct_accessRights_ti^7
129
129
  dct_provider_ti^8
130
130
  layer_geom_type_ti^9
131
131
  layer_slug_ti^10
132
- dc_identifier_ti^10
132
+ dct_identifier_ti^10
133
133
  </str>
134
134
  <str name="pf"><!-- phrase boost within result set -->
135
135
  text^1
136
- dc_description_ti^2
137
- dc_creator_tmi^3
138
- dc_publisher_ti^3
136
+ dct_description_ti^2
137
+ dct_creator_tmi^3
138
+ dct_publisher_ti^3
139
139
  dct_isPartOf_tmi^4
140
- dc_subject_tmi^5
140
+ dct_subject_tmi^5
141
141
  dct_spatial_tmi^5
142
142
  dct_temporal_tmi^5
143
- dc_title_ti^6
144
- dc_rights_ti^7
143
+ dct_title_ti^6
144
+ dct_accessRights_ti^7
145
145
  dct_provider_ti^8
146
146
  layer_geom_type_ti^9
147
147
  layer_slug_ti^10
148
- dc_identifier_ti^10
148
+ dct_identifier_ti^10
149
149
  </str>
150
150
  <bool name="facet">true</bool>
151
151
  <int name="facet.mincount">1</int>
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe Geoblacklight::IconFacetItemComponent, type: :component do
5
+ subject(:rendered) do
6
+ render_inline_to_capybara_node(described_class.new(suppress_link: true, **kwargs))
7
+ end
8
+
9
+ let(:kwargs) { { facet_item: facet_item } }
10
+ let(:facet_item) { instance_double(Blacklight::FacetItemPresenter, label: 'Stanford', value: 'stanford', hits: 5, href: nil, selected?: false, facet_config: facet_config) }
11
+ let(:facet_config) { Blacklight::Configuration::FacetField.new(field: 'provider_facet', label: 'Provider') }
12
+
13
+ it 'prepends the icon to the facet item label' do
14
+ expect(rendered).to have_selector('span.facet-label', text: 'Stanford')
15
+ expect(rendered).to have_selector('span.facet-label svg title', text: 'Stanford University')
16
+ end
17
+ end
@@ -10,6 +10,6 @@ describe 'Config' do
10
10
  end
11
11
 
12
12
  it 'Loads new v3.4 Settings.FIELDS defaults' do
13
- expect(Settings.HOMEPAGE_MAP_GEOM).to eq nil
13
+ expect(Settings.HOMEPAGE_MAP_GEOM).to be_nil
14
14
  end
15
15
  end
@@ -5,7 +5,7 @@ describe CatalogController, type: :controller do
5
5
  describe '#web_services' do
6
6
  it 'returns a document based off an id' do
7
7
  get :web_services, params: { id: 'mit-f6rqs4ucovjk2' }
8
- expect(response.status).to eq 200
8
+ expect(response).to have_http_status :ok
9
9
  expect(assigns(:documents)).not_to be_nil
10
10
  end
11
11
  end
@@ -13,14 +13,14 @@ describe CatalogController, type: :controller do
13
13
  describe '.default_solr_params' do
14
14
  it 'sets the number of rows returned by Solr to 10 and does not filter the results' do
15
15
  get :index
16
- expect(response.status).to eq 200
16
+ expect(response).to have_http_status :ok
17
17
  expect(assigns(:response).docs).not_to be_empty
18
18
  expect(assigns(:response).docs.length).to eq 10
19
19
  end
20
20
 
21
21
  it 'sets the starting document index to 0' do
22
22
  get :index
23
- expect(response.status).to eq 200
23
+ expect(response).to have_http_status :ok
24
24
  expect(assigns(:response).docs).not_to be_empty
25
25
  expect(assigns(:response).docs.first.id).to eq 'stanford-cg357zz0321'
26
26
  end
@@ -35,7 +35,7 @@ describe CatalogController, type: :controller do
35
35
  it 'sets the starting document index' do
36
36
  blacklight_config.default_solr_params = { start: 2, 'q.alt' => '*:*' }
37
37
  get :index
38
- expect(response.status).to eq 200
38
+ expect(response).to have_http_status :ok
39
39
  expect(assigns(:response).docs).not_to be_empty
40
40
  expect(assigns(:response).docs.first.id).to eq 'mit-001145244'
41
41
  end
@@ -43,7 +43,7 @@ describe CatalogController, type: :controller do
43
43
  it 'filters using a default DisMax query when no query is provided by the client' do
44
44
  blacklight_config.default_solr_params = { start: 10, 'q.alt' => '{!dismax}id:nyu' }
45
45
  get :index
46
- expect(response.status).to eq 200
46
+ expect(response).to have_http_status :ok
47
47
  expect(assigns(:response).docs).to be_empty
48
48
  end
49
49
  end
@@ -58,7 +58,7 @@ describe CatalogController, type: :controller do
58
58
  it 'alters the number of documents returned from Solr' do
59
59
  blacklight_config.default_per_page = 20
60
60
  get :index
61
- expect(response.status).to eq 200
61
+ expect(response).to have_http_status :ok
62
62
  expect(assigns(:response).docs).not_to be_empty
63
63
  expect(assigns(:response).docs.length).to eq 20
64
64
  end
@@ -68,7 +68,7 @@ describe CatalogController, type: :controller do
68
68
  describe '#raw' do
69
69
  it 'returns a JSON representation of a Solr Document' do
70
70
  get :raw, params: { id: 'tufts-cambridgegrid100-04' }
71
- expect(response.status).to eq 200
71
+ expect(response).to have_http_status :ok
72
72
  expect(response.body).not_to be_empty
73
73
  response_values = JSON.parse(response.body)
74
74
  expect(response_values).to include 'gbl_mdVersion_s' => 'Aardvark'
@@ -77,7 +77,7 @@ describe CatalogController, type: :controller do
77
77
  expect(response_values).to include Settings.FIELDS.ACCESS_RIGHTS => 'Public'
78
78
  expect(response_values).to include Settings.FIELDS.PROVIDER => 'Tufts'
79
79
  expect(response_values).to include Settings.FIELDS.ID => 'tufts-cambridgegrid100-04'
80
- expect(response_values).to include Settings.FIELDS.SPATIAL_EXTENT => 'ENVELOPE(-71.163984,-71.052581,42.408316,42.34757)'
80
+ expect(response_values).to include Settings.FIELDS.GEOMETRY => 'ENVELOPE(-71.163984,-71.052581,42.408316,42.34757)'
81
81
  end
82
82
  end
83
83
  end