geoblacklight 4.5.1 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/download_controller.rb +5 -0
  3. data/app/helpers/arcgis_helper.rb +3 -0
  4. data/app/helpers/blacklight_helper.rb +4 -0
  5. data/app/helpers/carto_helper.rb +5 -0
  6. data/app/helpers/geoblacklight/geoblacklight_helper_behavior.rb +7 -1
  7. data/app/helpers/geoblacklight_helper.rb +74 -21
  8. data/app/models/concerns/geoblacklight/solr_document/carto.rb +7 -0
  9. data/app/models/concerns/geoblacklight/solr_document/citation.rb +7 -0
  10. data/app/models/concerns/geoblacklight/solr_document/inspection.rb +1 -1
  11. data/app/models/concerns/geoblacklight/solr_document.rb +30 -2
  12. data/app/presenters/geoblacklight/document_presenter.rb +8 -0
  13. data/app/views/catalog/_arcgis.html.erb +1 -1
  14. data/app/views/catalog/_carto.html.erb +1 -1
  15. data/app/views/catalog/_downloads_collapse.html.erb +3 -0
  16. data/app/views/catalog/_index_split_default.html.erb +1 -1
  17. data/app/views/catalog/_show_default_attribute_table.html.erb +1 -1
  18. data/app/views/catalog/_show_default_viewer_container.html.erb +3 -3
  19. data/app/views/catalog/_show_downloads.html.erb +3 -0
  20. data/app/views/catalog/_show_sidebar.html.erb +1 -1
  21. data/app/views/catalog/_show_sidebar_static_map.html.erb +3 -0
  22. data/app/views/catalog/_web_services.html.erb +1 -1
  23. data/lib/geoblacklight/deprecated_configuration.rb +519 -0
  24. data/lib/geoblacklight/download/hgl_download.rb +5 -0
  25. data/lib/geoblacklight/engine.rb +14 -0
  26. data/lib/geoblacklight/geometry.rb +7 -0
  27. data/lib/geoblacklight/item_viewer.rb +8 -1
  28. data/lib/geoblacklight/references.rb +15 -0
  29. data/lib/geoblacklight/version.rb +1 -1
  30. data/lib/geoblacklight/view_helper_override.rb +12 -1
  31. data/lib/geoblacklight.rb +17 -0
  32. data/lib/tasks/geoblacklight.rake +17 -0
  33. data/package.json +3 -2
  34. data/spec/lib/geoblacklight/deprecated_configuration_spec.rb +597 -0
  35. data/spec/lib/geoblacklight/geometry_spec.rb +15 -0
  36. data/spec/lib/geoblacklight/references_spec.rb +24 -0
  37. data/spec/models/concerns/geoblacklight/solr_document/citation_spec.rb +16 -0
  38. data/spec/models/concerns/geoblacklight/solr_document_spec.rb +48 -0
  39. metadata +5 -6
@@ -0,0 +1,519 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "yaml"
5
+
6
+ module Geoblacklight
7
+ ##
8
+ # Boot time checks for application configuration that GeoBlacklight 5 removes.
9
+ #
10
+ # These cases cannot be caught by deprecating a method, because nothing in
11
+ # GeoBlacklight calls them:
12
+ #
13
+ # * An overridden template keeps working on 4.x and is simply never rendered
14
+ # again on 5.x, so the customization disappears silently.
15
+ # * A removed setting is only ever read by JavaScript, or by code that 5.x
16
+ # deletes outright.
17
+ #
18
+ # So we look at the application's own files and settings once, at boot.
19
+ module DeprecatedConfiguration
20
+ ##
21
+ # Templates GeoBlacklight 5 no longer ships, mapped to their replacement.
22
+ # An application that has copied one of these into app/views will keep the
23
+ # file after upgrading, but GeoBlacklight 5 will not render it.
24
+ TEMPLATES = {
25
+ "catalog/_arcgis" => "use Geoblacklight::ArcgisComponent instead",
26
+ "catalog/_carto" => "the Carto OneClick integration is removed without replacement",
27
+ "catalog/_data_dictionary" => "use Geoblacklight::DataDictionaryDownloadComponent instead",
28
+ "catalog/_downloads_collapse" => "use Geoblacklight::DownloadLinksComponent instead",
29
+ "catalog/_header_icons" => "use Geoblacklight::HeaderIconsComponent instead",
30
+ "catalog/_index_split_default" => "use Geoblacklight::SearchResultComponent instead",
31
+ "catalog/_results_pagination" => "GeoBlacklight no longer overrides this template; override Blacklight's copy instead",
32
+ "catalog/_show_default_attribute_table" => "use Geoblacklight::AttributeTableComponent instead",
33
+ "catalog/_show_default_display_note" => "use Geoblacklight::DisplayNoteComponent instead",
34
+ "catalog/_show_default_viewer_container" => "use Geoblacklight::ItemMapViewerComponent instead",
35
+ "catalog/_show_default_viewer_information" => "it is removed without replacement",
36
+ "catalog/_show_downloads" => "use Geoblacklight::DownloadLinksComponent instead",
37
+ "catalog/_show_header_default" => "use the title slot of Geoblacklight::DocumentComponent instead",
38
+ "catalog/_show_sidebar" => "use Geoblacklight::Document::SidebarComponent instead",
39
+ "catalog/_show_sidebar_static_map" => "use Geoblacklight::StaticMapComponent instead",
40
+ "catalog/_show_web_services" => "use Geoblacklight::WebServicesLinkComponent instead",
41
+ "catalog/_web_services" => "use Geoblacklight::WebServicesComponent instead",
42
+ "catalog/_web_services_default" => "use Geoblacklight::WebServicesDefaultComponent instead",
43
+ "catalog/_web_services_wfs" => "use Geoblacklight::WebServicesWfsComponent instead",
44
+ "catalog/_web_services_wms" => "use Geoblacklight::WebServicesWmsComponent instead",
45
+ "download/hgl" => "the Harvard Geospatial Library download integration is removed without replacement",
46
+ "relation/_relations" => "use Geoblacklight::RelationsComponent instead",
47
+ "shared/_header_navbar" => "set config.header_component to a subclass of Geoblacklight::HeaderComponent instead"
48
+ }.freeze
49
+
50
+ ##
51
+ # Settings keys GeoBlacklight 5 no longer reads, mapped to their replacement.
52
+ # Each entry is the dotted path to check, e.g. "LEAFLET.VIEWERS".
53
+ SETTINGS = {
54
+ "APPLICATION_LOGO_URL" => "it was only used by the Carto OneClick integration, which is removed without replacement",
55
+ "CARTO_ONECLICK_LINK" => "the Carto OneClick integration is removed without replacement",
56
+ "LEAFLET.VIEWERS" => "viewer controls are no longer configurable per protocol"
57
+ }.freeze
58
+
59
+ ##
60
+ # Settings whose default GeoBlacklight 5 changes. The installer only writes
61
+ # config/settings.yml once, so an application upgrading from 4.x carries its
62
+ # old value forward silently. We warn only when the value is still the 4.x
63
+ # default, so an application that has deliberately chosen a value is left alone.
64
+ CHANGED_SETTINGS = {
65
+ "ARCGIS_BASE_URL" => {
66
+ from: "https://www.arcgis.com/home/webmap/viewer.html",
67
+ to: "https://www.arcgis.com/apps/mapviewer/index.html",
68
+ because: "Esri retired the classic map viewer. The old URL still redirects and keeps the urls= " \
69
+ "parameter, so \"Open in ArcGIS\" works today; update the setting so you stop relying " \
70
+ "on that redirect"
71
+ },
72
+ "TIMEOUT_DOWNLOAD" => {
73
+ from: 16,
74
+ to: 180,
75
+ because: "16 seconds is too short for many generated downloads"
76
+ },
77
+ "WMS_PARAMS.INFO_FORMAT" => {
78
+ from: "text/html",
79
+ to: "application/json",
80
+ because: "GeoBlacklight 5 asks GetFeatureInfo for JSON. It still builds an attribute table from " \
81
+ "an HTML response, but marks it isHTML, so it cannot highlight the clicked feature on " \
82
+ "the map and cannot tell an empty result from a real one"
83
+ }
84
+ }.freeze
85
+
86
+ ##
87
+ # Individual setting values that stop matching anything in GeoBlacklight 5. These
88
+ # are only present when an application configured them deliberately, so the check
89
+ # is silent for a stock application.
90
+ STALE_SETTING_VALUES = {
91
+ "SIDEBAR_STATIC_MAP" => {
92
+ value: "map",
93
+ because: "Geoblacklight::StaticMapComponent will stop rendering the sidebar map for those documents"
94
+ },
95
+ "HELP_TEXT.viewer_protocol" => {
96
+ value: "map",
97
+ because: "Geoblacklight::ViewerHelpTextComponent will stop rendering help text for those documents"
98
+ }
99
+ }.freeze
100
+
101
+ ##
102
+ # Provider icon slugs that GeoBlacklight 5 renames, and routes through
103
+ # Settings.ICON_MAPPING. It ships no label for the new name.
104
+ ICON_RENAMES = {
105
+ "chicago" => "university-of-chicago",
106
+ "illinois" => "university-of-illinois-urbana-champaign",
107
+ "iowa" => "university-of-iowa",
108
+ "maryland" => "university-of-maryland",
109
+ "michigan" => "university-of-michigan",
110
+ "michigan-state" => "michigan-state-university",
111
+ "minnesota" => "university-of-minnesota",
112
+ "nebraska" => "university-of-nebraska-lincoln",
113
+ "ohio-state" => "the-ohio-state-university",
114
+ "penn-state" => "pennsylvania-state-university",
115
+ "purdue" => "purdue-university",
116
+ "wisconsin" => "university-of-wisconsin-madison"
117
+ }.freeze
118
+
119
+ ##
120
+ # Translation keys GeoBlacklight 5 stops looking up, mapped to what happens
121
+ # instead. An application that translated or reworded one of these keeps the
122
+ # translation in its own locale file, where GeoBlacklight 5 never reads it again,
123
+ # so the customization disappears with no error.
124
+ LOCALE_KEYS = {
125
+ "geoblacklight.citation.retrieved_from" =>
126
+ "GeoBlacklight 5 ends a citation with the document's identifier URL, its schema.org/url reference " \
127
+ "or the catalog URL, rather than with a translated suffix",
128
+ "geoblacklight.tools.open_carto" =>
129
+ "the Carto OneClick integration is removed without replacement",
130
+ "geoblacklight.references.services_close" =>
131
+ "GeoBlacklight 5 uses blacklight.modal.close"
132
+ }.merge(
133
+ %w[hgl_success hgl_request hgl_request_button hgl_close hgl_instructions hgl_email].to_h do |key|
134
+ ["geoblacklight.download.#{key}",
135
+ "the Harvard Geospatial Library download integration is removed without replacement"]
136
+ end
137
+ ).merge(
138
+ ICON_RENAMES.to_h do |short, long|
139
+ ["blacklight.icon.#{short}",
140
+ "GeoBlacklight 5 routes this provider through Settings.ICON_MAPPING and looks up " \
141
+ "blacklight.icon.#{long} instead"]
142
+ end
143
+ ).freeze
144
+
145
+ ##
146
+ # Readers that GeoBlacklight 5 declares with Blacklight's `attribute`. Those are
147
+ # defined directly on the SolrDocument class, and a method on the class wins over
148
+ # one from an included module, so an application concern that overrides any of
149
+ # these silently stops taking effect and `super` no longer reaches GeoBlacklight.
150
+ DOCUMENT_ATTRIBUTE_READERS = %w[
151
+ display_note geom_field wxs_identifier file_format rights_field_data provider
152
+ resource_type resource_class title creator publisher identifiers issued format
153
+ ].freeze
154
+
155
+ ##
156
+ # Settings that do not exist in 4.x but that GeoBlacklight 5 requires.
157
+ REQUIRED_SETTINGS = {
158
+ "DOWNLOAD_FORMATS.VECTOR" => "GeoBlacklight 5 builds the vector download list from this setting instead " \
159
+ "of hardcoding Shapefile, KMZ and GeoJSON, and Geoblacklight::References#vector_download_formats " \
160
+ "raises NoMethodError without it"
161
+ }.freeze
162
+
163
+ ##
164
+ # RELATIONSHIPS_SHOWN keys that GeoBlacklight 4.1 replaced with an
165
+ # _ANCESTORS/_DESCENDANTS pair, mapped to the key that took over the same
166
+ # query_type. GeoBlacklight 5 does not read the old names, so a relationship
167
+ # configured under one is simply not displayed any more.
168
+ #
169
+ # config/settings.yml is only written when GeoBlacklight is first installed, so an
170
+ # application generated by GeoBlacklight 4.0 still has the old shape unless somebody
171
+ # reconciled the block by hand. GeoBlacklight 3.x had no RELATIONSHIPS_SHOWN at all,
172
+ # so 4.0 is the only generation this applies to.
173
+ RELATIONSHIP_RENAMES = {
174
+ "MEMBER_OF" => "MEMBER_OF_ANCESTORS",
175
+ "RELATION" => "RELATION_ANCESTORS",
176
+ "REPLACED_BY" => "REPLACES_DESCENDANTS",
177
+ "REPLACES" => "REPLACES_ANCESTORS",
178
+ "VERSION_OF" => "VERSION_OF_DESCENDANTS"
179
+ }.freeze
180
+
181
+ ##
182
+ # The GeoBlacklight 4 install generator injected
183
+ # `<%= javascript_tag '$.fx.off = true;' if Rails.env.test? %>` into the
184
+ # application layout. GeoBlacklight 5 does not ship jQuery, so the line raises
185
+ # "$ is not defined" once the application's tests run. Nothing else reports it: the
186
+ # layout is not one of the TEMPLATES GeoBlacklight removes, so the application keeps
187
+ # the file and only finds out when the suite breaks.
188
+ JQUERY_ANIMATIONS = /\$\.fx\.off/
189
+
190
+ ##
191
+ # Warn about every deprecated template and setting we can see.
192
+ # @param root [Pathname] the application root to inspect
193
+ def self.warn!(root = Rails.root)
194
+ if root
195
+ warn_about_templates(root)
196
+ warn_about_helper_override(root)
197
+ warn_about_locale_keys(root)
198
+ warn_about_jquery_animations(root)
199
+ end
200
+ warn_about_settings
201
+ warn_about_changed_settings
202
+ warn_about_required_settings
203
+ warn_about_stale_setting_values
204
+ warn_about_relationship_keys
205
+ warn_about_document_overrides
206
+ warn_about_catalog_controller
207
+ end
208
+
209
+ ##
210
+ # GeoBlacklight 5 changes GeoblacklightHelper substantially: about twenty methods
211
+ # are removed, document_available? takes an argument, and viewer_protocol can be
212
+ # nil. An application that has copied the helper into app/helpers shadows
213
+ # GeoBlacklight's own, which also suppresses every method level deprecation in it,
214
+ # so this is the only warning such an application gets.
215
+ # @param root [Pathname] the application root to inspect
216
+ def self.warn_about_helper_override(root)
217
+ override = File.join(root, "app", "helpers", "geoblacklight_helper.rb")
218
+ return unless File.exist?(override)
219
+
220
+ Geoblacklight.deprecation.warn(
221
+ "#{relative_to(override, root)} overrides GeoblacklightHelper, which shadows GeoBlacklight's own " \
222
+ "copy and hides the deprecations for the helper methods GeoBlacklight 5 removes. Before upgrading: " \
223
+ "document_available? has to accept an optional document, and viewer_protocol can return nil, so " \
224
+ "viewer_protocol.camelize raises for a document with no viewer reference"
225
+ )
226
+ end
227
+
228
+ ##
229
+ # Show partials the 4.x install generator lists in the application's own
230
+ # CatalogController, all of which GeoBlacklight 5 removes.
231
+ SHOW_PARTIALS = %w[
232
+ show_default_display_note show_default_viewer_container
233
+ show_default_attribute_table show_default_viewer_information
234
+ ].freeze
235
+
236
+ ##
237
+ # Show tools the 4.x install generator registers with `partial:`. GeoBlacklight 5
238
+ # removes all three partials, and Blacklight 8 wants a `component:` instead.
239
+ SHOW_TOOL_PARTIALS = %w[arcgis carto data_dictionary].freeze
240
+
241
+ ##
242
+ # Everything the application's own CatalogController needs before GeoBlacklight 5,
243
+ # reported as a single to-do list. One warning per file the application has to
244
+ # edit keeps the boot output readable: a stock 4.x app trips every one of these
245
+ # checks, and warning separately would mean six lines on every rails, rake and
246
+ # rspec invocation. It is also why none of this is reported from the partials
247
+ # themselves, which would warn several times per request instead.
248
+ def self.warn_about_catalog_controller
249
+ return unless defined?(::CatalogController)
250
+
251
+ problems = catalog_controller_problems(::CatalogController)
252
+ return if problems.empty?
253
+
254
+ Geoblacklight.deprecation.warn(
255
+ "app/controllers/catalog_controller.rb needs these changes before GeoBlacklight 5: " +
256
+ problems.join("; ")
257
+ )
258
+ rescue
259
+ # A boot time diagnostic must never be the reason an application fails to start.
260
+ nil
261
+ end
262
+
263
+ ##
264
+ # @param controller [Class]
265
+ # @return [Array<String>]
266
+ def self.catalog_controller_problems(controller)
267
+ config = controller.blacklight_config
268
+ problems = []
269
+
270
+ if config.index.document_presenter_class.to_s == "Geoblacklight::DocumentPresenter"
271
+ problems << "remove `config.index.document_presenter_class = Geoblacklight::DocumentPresenter`, " \
272
+ "because GeoBlacklight 5 removes that class and the reference will not resolve"
273
+ end
274
+
275
+ stale = SHOW_PARTIALS & config.show.partials.map(&:to_s)
276
+ if stale.any?
277
+ problems << "remove #{stale.join(", ")} from `config.show.partials`, because GeoBlacklight 5 " \
278
+ "ships none of those partials"
279
+ end
280
+
281
+ if config.show.document_component.nil?
282
+ problems << "set `config.show.document_component = Geoblacklight::DocumentComponent`, or the record " \
283
+ "page loses the map viewer and the attribute table"
284
+ end
285
+ if config.index.document_component.nil?
286
+ problems << "set `config.index.document_component = Geoblacklight::SearchResultComponent`, or search " \
287
+ "results lose the map data attributes and the icons"
288
+ end
289
+ if config.header_component.to_s.start_with?("Blacklight::")
290
+ problems << "set `config.header_component = Geoblacklight::HeaderComponent`, because GeoBlacklight 5 " \
291
+ "renders the masthead there rather than from shared/_header_navbar"
292
+ end
293
+
294
+ config.show.document_actions.each do |key, action|
295
+ next unless action.component.nil?
296
+ next unless SHOW_TOOL_PARTIALS.include?(action.partial.to_s)
297
+ problems << "register the #{key.inspect} show tool with a `component:` rather than " \
298
+ "`partial: #{action.partial.to_s.inspect}`, because GeoBlacklight 5 removes that partial"
299
+ end
300
+
301
+ problems << web_services_problem(controller)
302
+ problems.compact
303
+ end
304
+
305
+ ##
306
+ # Blacklight 8's action_documents returns only the documents, so the 4.x
307
+ # destructuring leaves @documents nil.
308
+ # @param controller [Class]
309
+ # @return [String, nil]
310
+ def self.web_services_problem(controller)
311
+ source = controller.instance_method(:web_services).source_location&.first
312
+ return unless source && File.exist?(source)
313
+ return unless File.read(source).match?(/@response\s*,\s*@documents\s*=\s*action_documents/)
314
+
315
+ "replace `@response, @documents = action_documents` in #web_services with `@docs = action_documents`, " \
316
+ "because Blacklight 8 returns only the documents"
317
+ rescue
318
+ nil
319
+ end
320
+
321
+ ##
322
+ # Warn about application modules whose overrides of a SolrDocument reader stop
323
+ # winning in GeoBlacklight 5. Only module overrides are reported: a definition in
324
+ # the SolrDocument class body still takes precedence over the `attribute` reader.
325
+ def self.warn_about_document_overrides
326
+ return unless defined?(::SolrDocument)
327
+
328
+ document = ::SolrDocument
329
+ DOCUMENT_ATTRIBUTE_READERS.each do |reader|
330
+ next unless document.method_defined?(reader) || document.private_method_defined?(reader)
331
+
332
+ method = document.instance_method(reader)
333
+ # A C implemented method is Ruby's, not the application's: Kernel#format, for
334
+ # one, answers private_method_defined?("format") on any document class.
335
+ next if method.source_location.nil?
336
+
337
+ owner = method.owner
338
+ next if owner.is_a?(Class)
339
+ next if owner.name.to_s.start_with?("Geoblacklight", "Blacklight")
340
+
341
+ Geoblacklight.deprecation.warn(
342
+ "#{owner}##{reader} overrides Geoblacklight::SolrDocument##{reader}; GeoBlacklight 5 defines " \
343
+ "that reader directly on #{document} with Blacklight's `attribute`, so an override in an " \
344
+ "included module is ignored. Move it into the #{document} class body, after " \
345
+ "`include Geoblacklight::SolrDocument`"
346
+ )
347
+ end
348
+ rescue NameError
349
+ nil
350
+ end
351
+
352
+ def self.warn_about_stale_setting_values
353
+ return unless defined?(::Settings)
354
+
355
+ STALE_SETTING_VALUES.each do |setting, stale|
356
+ next unless Array(setting_value(setting)).include?(stale[:value])
357
+ Geoblacklight.deprecation.warn(
358
+ "Settings.#{setting} lists #{stale[:value].inspect}, which never matches in GeoBlacklight 5 " \
359
+ "because SolrDocument#viewer_protocol returns nil rather than #{stale[:value].inspect} for a " \
360
+ "document with no viewer reference; #{stale[:because]}"
361
+ )
362
+ end
363
+ end
364
+
365
+ ##
366
+ # @param root [Pathname] the application root to inspect
367
+ def self.warn_about_templates(root)
368
+ TEMPLATES.each do |template, advice|
369
+ Dir.glob(File.join(root, "app", "views", "#{template}.*")).sort.each do |override|
370
+ Geoblacklight.deprecation.warn(
371
+ "#{relative_to(override, root)} overrides #{template}, which is removed in " \
372
+ "GeoBlacklight 5; #{advice}"
373
+ )
374
+ end
375
+ end
376
+ end
377
+
378
+ ##
379
+ # @param root [Pathname] the application root to inspect
380
+ def self.warn_about_locale_keys(root)
381
+ Dir.glob(File.join(root, "config", "locales", "**", "*.{yml,yaml}")).sort.each do |path|
382
+ defined_keys = locale_keys(path)
383
+
384
+ LOCALE_KEYS.each do |key, advice|
385
+ next unless defined_keys.include?(key)
386
+ Geoblacklight.deprecation.warn(
387
+ "#{relative_to(path, root)} defines #{key}, which GeoBlacklight 5 no longer looks up; #{advice}"
388
+ )
389
+ end
390
+ end
391
+ end
392
+
393
+ ##
394
+ # @param root [Pathname] the application root to inspect
395
+ def self.warn_about_jquery_animations(root)
396
+ Dir.glob(File.join(root, "app", "views", "layouts", "**", "*.{erb,haml}")).sort.each do |layout|
397
+ next unless disables_jquery_animations?(layout)
398
+
399
+ Geoblacklight.deprecation.warn(
400
+ "#{relative_to(layout, root)} turns jQuery animations off with $.fx.off, which the " \
401
+ "GeoBlacklight 4 install generator added; GeoBlacklight 5 does not ship jQuery, so remove that " \
402
+ "javascript_tag line or the test environment raises \"$ is not defined\""
403
+ )
404
+ end
405
+ end
406
+
407
+ ##
408
+ # @param path [String]
409
+ # @return [Boolean]
410
+ def self.disables_jquery_animations?(path)
411
+ File.file?(path) && File.read(path).match?(JQUERY_ANIMATIONS)
412
+ rescue SystemCallError
413
+ # An unreadable layout is somebody else's problem; a boot time diagnostic
414
+ # must never be the reason an application fails to start.
415
+ false
416
+ end
417
+
418
+ ##
419
+ # Reported as a single warning rather than one per key. An application still on the
420
+ # GeoBlacklight 4.0 shape trips every entry, and all of them are fixed by replacing
421
+ # the same block of the same file.
422
+ def self.warn_about_relationship_keys
423
+ return unless defined?(::Settings)
424
+
425
+ stale = RELATIONSHIP_RENAMES.select { |old, _| setting_present?("RELATIONSHIPS_SHOWN.#{old}") }
426
+ return if stale.empty?
427
+
428
+ Geoblacklight.deprecation.warn(
429
+ "Settings.RELATIONSHIPS_SHOWN defines #{stale.keys.join(", ")}, which GeoBlacklight 4.1 replaced " \
430
+ "with _ANCESTORS and _DESCENDANTS pairs; GeoBlacklight 5 does not read the old names, so those " \
431
+ "relationships stop being displayed. Rename to #{stale.values.join(", ")}, and note that each pair's " \
432
+ "other half is new configuration rather than a rename"
433
+ )
434
+ end
435
+
436
+ ##
437
+ # The dotted keys a locale file defines, with the leading locale dropped so that a
438
+ # translation into any locale matches.
439
+ # @param path [String]
440
+ # @return [Array<String>]
441
+ def self.locale_keys(path)
442
+ loaded = YAML.load_file(path, aliases: true)
443
+ return [] unless loaded.is_a?(Hash)
444
+
445
+ loaded.each_value.flat_map { |tree| tree.is_a?(Hash) ? dotted_keys(tree) : [] }
446
+ rescue
447
+ # A locale file we cannot parse is not ours to complain about.
448
+ []
449
+ end
450
+
451
+ ##
452
+ # @param tree [Hash]
453
+ # @return [Array<String>]
454
+ def self.dotted_keys(tree, prefix = [])
455
+ tree.flat_map do |key, value|
456
+ path = prefix + [key.to_s]
457
+ value.is_a?(Hash) ? dotted_keys(value, path) : [path.join(".")]
458
+ end
459
+ end
460
+ private_class_method :dotted_keys
461
+
462
+ def self.warn_about_settings
463
+ return unless defined?(::Settings)
464
+
465
+ SETTINGS.each do |setting, advice|
466
+ next unless setting_present?(setting)
467
+ Geoblacklight.deprecation.warn(
468
+ "Settings.#{setting} is deprecated and will be removed in GeoBlacklight 5; #{advice}"
469
+ )
470
+ end
471
+ end
472
+
473
+ def self.warn_about_changed_settings
474
+ return unless defined?(::Settings)
475
+
476
+ CHANGED_SETTINGS.each do |setting, change|
477
+ next unless setting_value(setting) == change[:from]
478
+ Geoblacklight.deprecation.warn(
479
+ "Settings.#{setting} is set to the GeoBlacklight 4 default #{change[:from].inspect}, which is " \
480
+ "deprecated; GeoBlacklight 5 uses #{change[:to].inspect} because #{change[:because]}"
481
+ )
482
+ end
483
+ end
484
+
485
+ def self.warn_about_required_settings
486
+ return unless defined?(::Settings)
487
+
488
+ REQUIRED_SETTINGS.each do |setting, advice|
489
+ next unless setting_value(setting).nil?
490
+ Geoblacklight.deprecation.warn(
491
+ "Settings.#{setting} is not set; GeoBlacklight 5 requires it because #{advice}"
492
+ )
493
+ end
494
+ end
495
+
496
+ ##
497
+ # Walk a dotted settings path without raising when an ancestor is missing.
498
+ # @param setting [String] e.g. "LEAFLET.VIEWERS"
499
+ # @return [Object, nil] the value, or nil if any step of the path is missing
500
+ def self.setting_value(setting)
501
+ setting.split(".").reduce(::Settings) do |node, key|
502
+ return nil unless node.respond_to?(key)
503
+ node.public_send(key)
504
+ end
505
+ end
506
+
507
+ ##
508
+ # @param setting [String] e.g. "LEAFLET.VIEWERS"
509
+ # @return [Boolean]
510
+ def self.setting_present?(setting)
511
+ setting_value(setting).present?
512
+ end
513
+
514
+ def self.relative_to(path, root)
515
+ Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
516
+ end
517
+ private_class_method :relative_to
518
+ end
519
+ end
@@ -1,8 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geoblacklight
4
+ # @deprecated The Harvard Geospatial Library download integration is removed
5
+ # without replacement in GeoBlacklight 5.
4
6
  class HglDownload < Geoblacklight::Download
5
7
  def initialize(document, email, options = {})
8
+ Geoblacklight.deprecation.warn(
9
+ "Geoblacklight::HglDownload is deprecated without replacement and will be removed in GeoBlacklight 5"
10
+ )
6
11
  request_params = {
7
12
  "LayerName" => document[Settings.FIELDS.WXS_IDENTIFIER].sub(/^cite:/, ""),
8
13
  "UserEmail" => email
@@ -11,6 +11,20 @@ require "handlebars_assets"
11
11
 
12
12
  module Geoblacklight
13
13
  class Engine < ::Rails::Engine
14
+ # Register GeoBlacklight's deprecator so that applications can configure it
15
+ # alongside Rails' own, e.g. `config.active_support.deprecation = :raise`.
16
+ initializer "geoblacklight.deprecator" do |app|
17
+ app.deprecators[:geoblacklight] = Geoblacklight.deprecation if app.respond_to?(:deprecators)
18
+ end
19
+
20
+ # Warn about application configuration that GeoBlacklight 5 removes. This
21
+ # runs once per boot rather than per request, because nothing in
22
+ # GeoBlacklight calls the deprecated templates or settings on the
23
+ # application's behalf.
24
+ config.after_initialize do
25
+ Geoblacklight::DeprecatedConfiguration.warn!
26
+ end
27
+
14
28
  # GeoblacklightHelper is needed by all helpers, so we inject it
15
29
  # into action view base here.
16
30
  initializer "geoblacklight.helpers" do
@@ -26,6 +26,13 @@ module Geoblacklight
26
26
  # Generate a wsen bounding box from the geometry
27
27
  # @return [String] bounding box as comma delimited wsen "w, s, e, n"
28
28
  def bounding_box
29
+ if geom.blank?
30
+ Geoblacklight.deprecation.warn(
31
+ "Geoblacklight::Geometry#bounding_box falls back to the whole world extent for a document with " \
32
+ "no geometry; in GeoBlacklight 5 SolrDocument#geom_field returns nil rather than \"\", so this " \
33
+ "raises NoMethodError instead"
34
+ )
35
+ end
29
36
  obj = factory.parse_wkt(geometry_as_wkt)
30
37
 
31
38
  # Get the minimum bounding box for the geometry as a Polygon
@@ -7,7 +7,14 @@ module Geoblacklight
7
7
  end
8
8
 
9
9
  def viewer_protocol
10
- return "map" if viewer_preference.nil?
10
+ if viewer_preference.nil?
11
+ Geoblacklight.deprecation.warn(
12
+ "Geoblacklight::ItemViewer#viewer_protocol returns \"map\" for a document with no viewer " \
13
+ "reference; GeoBlacklight 5 returns nil instead, so calls like viewer_protocol.camelize will " \
14
+ "raise and comparisons against \"map\" will stop matching"
15
+ )
16
+ return "map"
17
+ end
11
18
  viewer_preference.keys.first.to_s
12
19
  end
13
20
 
@@ -31,6 +31,14 @@ module Geoblacklight
31
31
  # Accessor for a document's file format
32
32
  # @return [String] file format for the document
33
33
  def format
34
+ unless @document.respond_to?(:file_format)
35
+ Geoblacklight.deprecation.warn(
36
+ "Geoblacklight::References reads the format with @document[#{Settings.FIELDS.FORMAT}] in " \
37
+ "GeoBlacklight 4 and @document.file_format in GeoBlacklight 5, but the document you passed " \
38
+ "(#{@document.class}) does not respond to #file_format; pass an object that includes " \
39
+ "Geoblacklight::SolrDocument, or define #file_format on it"
40
+ )
41
+ end
34
42
  @document[Settings.FIELDS.FORMAT]
35
43
  end
36
44
 
@@ -128,6 +136,13 @@ module Geoblacklight
128
136
  # Adds a call to references for defined URI keys
129
137
  def method_missing(m, *args, &b)
130
138
  if Geoblacklight::Constants::URI.key?(m)
139
+ if m == :hgl
140
+ Geoblacklight.deprecation.warn(
141
+ "Geoblacklight::References#hgl and Geoblacklight::Constants::URI[:hgl] are " \
142
+ "deprecated; the Harvard Geospatial Library download integration is removed " \
143
+ "without replacement in GeoBlacklight 5"
144
+ )
145
+ end
131
146
  references m
132
147
  else
133
148
  super
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geoblacklight
4
- VERSION = "4.5.1"
4
+ VERSION = "4.6.0"
5
5
  end
@@ -2,15 +2,26 @@
2
2
 
3
3
  module Geoblacklight
4
4
  # Override Blacklight helpers to inject behavior
5
+ #
6
+ # @deprecated This module is removed in GeoBlacklight 5. Blacklight renders
7
+ # saved search constraints through Blacklight::ConstraintsComponent, and the
8
+ # bbox constraint is supplied by Geoblacklight::BboxItemPresenter.
5
9
  module ViewHelperOverride
10
+ # This overrides Blacklight's own helper, so Blacklight calls it on every
11
+ # search history page even in an unmodified application. Warning here would
12
+ # be noise, so only the GeoBlacklight-specific method below is deprecated,
13
+ # and this call to it is silenced.
6
14
  def render_search_to_s(params)
7
- super + render_search_to_s_bbox(params)
15
+ super + Geoblacklight.deprecation.silence { render_search_to_s_bbox(params) }
8
16
  end
9
17
 
18
+ # @deprecated
10
19
  def render_search_to_s_bbox(params)
11
20
  return "".html_safe if params["bbox"].blank?
12
21
 
13
22
  render_search_to_s_element(t("geoblacklight.bbox_label"), render_filter_value(params["bbox"]))
14
23
  end
24
+ Geoblacklight.deprecation.deprecate_methods(Geoblacklight::ViewHelperOverride,
25
+ render_search_to_s_bbox: "use Blacklight::ConstraintsComponent instead")
15
26
  end
16
27
  end