geoblacklight_sidecar_images 1.1.2 → 2.0.0.pre.alpha.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +60 -58
  3. data/Gemfile +5 -23
  4. data/README.md +66 -58
  5. data/Rakefile +13 -1
  6. data/app/controllers/geoblacklight_sidecar_images/application_controller.rb +0 -1
  7. data/app/helpers/geoblacklight_sidecar_images/application_helper.rb +15 -0
  8. data/app/jobs/geoblacklight_sidecar_images/store_image_job.rb +11 -4
  9. data/app/models/concerns/geoblacklight_sidecar_images/solr_document_behavior.rb +24 -0
  10. data/app/models/concerns/wms_rewrite_concern.rb +13 -4
  11. data/app/models/sidecar_image_transition.rb +3 -1
  12. data/app/models/solr_document_sidecar.rb +8 -3
  13. data/app/services/geoblacklight_sidecar_images/image_service/dynamic_map_layer.rb +2 -6
  14. data/app/services/geoblacklight_sidecar_images/image_service/esri_thumbnail.rb +11 -0
  15. data/app/services/geoblacklight_sidecar_images/image_service/image_map_layer.rb +2 -8
  16. data/app/services/geoblacklight_sidecar_images/image_service/tiled_map_layer.rb +2 -6
  17. data/app/services/geoblacklight_sidecar_images/image_service/wms.rb +13 -13
  18. data/app/services/geoblacklight_sidecar_images/image_service.rb +105 -57
  19. data/db/migrate/20180118203155_create_solr_document_sidecars.rb +3 -1
  20. data/db/migrate/20180118203519_create_sidecar_image_transitions.rb +3 -6
  21. data/geoblacklight_sidecar_images.gemspec +8 -11
  22. data/lib/generators/geoblacklight_sidecar_images/config_generator.rb +1 -11
  23. data/lib/generators/geoblacklight_sidecar_images/install_generator.rb +63 -12
  24. data/lib/generators/geoblacklight_sidecar_images/models_generator.rb +2 -36
  25. data/lib/generators/geoblacklight_sidecar_images/templates/views/catalog/_index_split_default.html.erb +5 -12
  26. data/lib/geoblacklight_sidecar_images/engine.rb +21 -0
  27. data/lib/geoblacklight_sidecar_images/field_map.rb +50 -0
  28. data/lib/geoblacklight_sidecar_images/ogm_thumbnail.rb +35 -0
  29. data/lib/geoblacklight_sidecar_images/version.rb +1 -1
  30. data/lib/geoblacklight_sidecar_images.rb +3 -1
  31. data/lib/tasks/geoblacklight_sidecar_images_tasks.rake +75 -58
  32. data/spec/helpers/application_helper_spec.rb +32 -0
  33. data/spec/jobs/store_image_job_spec.rb +4 -3
  34. data/spec/lib/geoblacklight_sidecar_images/field_map_spec.rb +25 -0
  35. data/spec/lib/geoblacklight_sidecar_images/ogm_thumbnail_spec.rb +27 -0
  36. data/spec/lib/tasks/geoblacklight_sidecar_images_spec.rb +16 -15
  37. data/spec/models/solr_document_sidecar_spec.rb +16 -0
  38. data/spec/services/image_service_protocol_spec.rb +30 -0
  39. data/spec/services/image_service_spec.rb +23 -24
  40. data/spec/spec_helper.rb +24 -24
  41. data/spec/test_app_templates/Gemfile.extra +4 -2
  42. data/spec/test_app_templates/lib/generators/test_app_generator.rb +52 -9
  43. data/template.rb +7 -5
  44. metadata +65 -83
  45. data/app/mailers/geoblacklight_sidecar_images/application_mailer.rb +0 -8
  46. data/app/views/layouts/geoblacklight_sidecar_images/application.html.erb +0 -14
  47. data/lib/generators/geoblacklight_sidecar_images/helpers_generator.rb +0 -21
  48. data/lib/generators/geoblacklight_sidecar_images/templates/helpers/blacklight/layout_helper_behavior.rb +0 -110
  49. /data/app/models/{application_record.rb → geoblacklight_sidecar_images/application_record.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f74fdd81e5f08c824eba396159f470b729ee1647a0b20d75801f05fd697d71a
4
- data.tar.gz: 230beb9912150c2a54ed91f2e2af0381edbaef85040d2e6b6f84d5ac735585f2
3
+ metadata.gz: ab3fbb4fea06b510373aacfcac11b0a9941c088140939a0f58f5cfbd5e7617a2
4
+ data.tar.gz: 969301942ddb0601b14e2cc05d2d59708a71abda75dd2349f705c918d4007fe2
5
5
  SHA512:
6
- metadata.gz: a41f54bddf89f1090f161c1138ac6f43216a28240bb95152de1c2d2688cc24e6030bad2b873ce1a801e6efc3ebb8d51c39c38d8f84234e649f55f1a07207e51a
7
- data.tar.gz: dcf8b061b2c66f8c3ae772f3a33f5b479cffd991cb0d906a7004dfc9affa0c966395c7469ab89daae038dffe199931761ca818d39107d7b27505176545f13def
6
+ metadata.gz: d2577da5f702ede9ac232880d3f9d3114aea42c57c34a256c345db46bd075dc6c4729fc10a25dc4f37f4618cb262b139c859ef1142f8b3b62caed497a64f652c
7
+ data.tar.gz: ab4297ae1e5c68b9adc5fdb81831f2d415c480b52f67baeb33bd65006fcd38fb34b9ce7e103646361eb504b58e6d6c39801cad67042f9474c04c208d3c554263
@@ -4,74 +4,76 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
- - feature/github-actions
7
+ - develop
8
8
  pull_request:
9
9
 
10
10
  jobs:
11
11
  linter:
12
12
  runs-on: ubuntu-latest
13
- strategy:
14
- matrix:
15
- bundler_version: [2.2.8]
16
- faraday_version: ['~> 2.0']
17
13
  steps:
18
- - uses: actions/checkout@v2
19
- - name: Set up Ruby
20
- uses: ruby/setup-ruby@v1
21
- with:
22
- ruby-version: 3.3.1
23
- - name: Install bundler
24
- run: gem install bundler -v ${{ matrix.bundler_version }}
25
- - name: Install dependencies
26
- run: bundle _${{ matrix.bundler_version }}_ install
27
- env:
28
- FARADAY_VERSION: ${{ matrix.faraday_version }}
29
- - name: Run linter
30
- run: bundle exec standardrb
14
+ - uses: actions/checkout@v4
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: "3.3"
19
+ bundler-cache: true
20
+ - name: Run linter
21
+ run: bundle exec standardrb
31
22
 
32
23
  test:
33
24
  runs-on: ubuntu-latest
34
25
  strategy:
26
+ fail-fast: false
35
27
  matrix:
36
- ruby_version: [3.3.1]
37
- rails_version: [7.1.3.2, 7.0.8.1]
38
- bundler_version: [2.2.8]
39
- faraday_version: ['~> 2.0']
28
+ include:
29
+ - ruby_version: "3.3"
30
+ rails_version: "7.2.2"
31
+ geoblacklight_version: "~> 4.4"
32
+ engine_cart_options: "--skip-git --skip-listen --skip-spring --skip-keeps --skip-action-cable --skip-test --skip-docker --skip-rubocop --skip-brakeman --skip-kamal --skip-solid --skip-bundle"
33
+ - ruby_version: "3.4"
34
+ rails_version: "8.1.3"
35
+ geoblacklight_version: "~> 5.3"
36
+ engine_cart_options: "--skip-docker --skip-action-cable --skip-rubocop --skip-brakeman --skip-kamal --skip-solid --skip-thruster --skip-bundle -a propshaft --css bootstrap --js importmap"
37
+ - ruby_version: "4.0"
38
+ rails_version: "8.1.3"
39
+ geoblacklight_version: "6.0.0.pre.alpha.7"
40
+ engine_cart_options: "--skip-docker --skip-action-cable --skip-rubocop --skip-brakeman --skip-kamal --skip-solid --skip-thruster --skip-bundle -a propshaft --css bootstrap --js importmap"
40
41
 
41
- name: test ruby ${{ matrix.ruby_version }} / rails ${{ matrix.rails_version }} / faraday ${{ matrix.faraday_version }}
42
+ name: ruby ${{ matrix.ruby_version }} / rails ${{ matrix.rails_version }} / gbl ${{ matrix.geoblacklight_version }}
42
43
  steps:
43
- - uses: actions/checkout@v2
44
- - name: Set up Ruby
45
- uses: ruby/setup-ruby@v1
46
- with:
47
- ruby-version: ${{ matrix.ruby_version }}
48
- - name: Create Solr container
49
- run: docker run -d -p 8983:8983 geoblacklight/solr:8.9-v1.0.0 server/scripts/ci-start.sh
50
- - name: Install bundler
51
- run: gem install bundler -v ${{ matrix.bundler_version }}
52
- - name: Install dependencies
53
- run: bundle _${{ matrix.bundler_version }}_ install
54
- env:
55
- RAILS_VERSION: ${{ matrix.rails_version }}
56
- FARADAY_VERSION: ${{ matrix.faraday_version }}
57
- - name: Setup Yarn
58
- run: exec "yarnpkg"
59
- - name: Load config into solr
60
- run: |
61
- cd solr/conf
62
- zip -1 -r solr_config.zip ./*
63
- curl -H "Content-type:application/octet-stream" --data-binary @solr_config.zip "http://solr:SolrRocks@127.0.0.1:8983/solr/admin/configs?action=UPLOAD&name=blacklight"
64
- curl -H 'Content-type: application/json' http://solr:SolrRocks@127.0.0.1:8983/api/collections/ -d '{create: {name: blacklight-core, config: blacklight, numShards: 1}}'
65
- - name: Run tests
66
- run: bundle exec rake ci
67
- env:
68
- RAILS_VERSION: ${{ matrix.rails_version }}
69
- FARADAY_VERSION: ${{ matrix.faraday_version }}
70
- ENGINE_CART_RAILS_OPTIONS: '--skip-git --skip-listen --skip-spring --skip-keeps --skip-action-cable --skip-coffee --skip-test'
71
- SOLR_URL: http://solr:SolrRocks@localhost:8983/solr/blacklight-core
72
- - name: Upload coverage artifacts
73
- uses: actions/upload-artifact@v4
74
- if: always()
75
- with:
76
- name: coverage
77
- path: coverage/
44
+ - uses: actions/checkout@v4
45
+ - name: Set up Ruby
46
+ uses: ruby/setup-ruby@v1
47
+ with:
48
+ ruby-version: ${{ matrix.ruby_version }}
49
+ - name: Install libvips and ImageMagick
50
+ run: sudo apt-get update && sudo apt-get install -y libvips42 imagemagick
51
+ - name: Create Solr container
52
+ run: docker run -d -p 8983:8983 geoblacklight/solr:8.9-v1.0.0 server/scripts/ci-start.sh
53
+ - name: Install dependencies
54
+ run: bundle install
55
+ env:
56
+ RAILS_VERSION: ${{ matrix.rails_version }}
57
+ GEOBLACKLIGHT_VERSION: ${{ matrix.geoblacklight_version }}
58
+ - name: Setup Yarn
59
+ run: exec "yarnpkg"
60
+ - name: Load config into solr
61
+ run: |
62
+ cd solr/conf
63
+ zip -1 -r solr_config.zip ./*
64
+ curl -H "Content-type:application/octet-stream" --data-binary @solr_config.zip "http://solr:SolrRocks@127.0.0.1:8983/solr/admin/configs?action=UPLOAD&name=blacklight"
65
+ curl -H 'Content-type: application/json' http://solr:SolrRocks@127.0.0.1:8983/api/collections/ -d '{create: {name: blacklight-core, config: blacklight, numShards: 1}}'
66
+ - name: Run tests
67
+ run: bundle exec rake ci
68
+ env:
69
+ RAILS_VERSION: ${{ matrix.rails_version }}
70
+ GEOBLACKLIGHT_VERSION: ${{ matrix.geoblacklight_version }}
71
+ ENGINE_CART_RAILS_OPTIONS: ${{ matrix.engine_cart_options }}
72
+ SOLR_URL: http://solr:SolrRocks@localhost:8983/solr/blacklight-core
73
+ BUNDLE_SPECIFIC_PLATFORM: "true"
74
+ - name: Upload coverage artifacts
75
+ uses: actions/upload-artifact@v4
76
+ if: always()
77
+ with:
78
+ name: coverage-ruby${{ matrix.ruby_version }}-rails${{ matrix.rails_version }}
79
+ path: coverage/
data/Gemfile CHANGED
@@ -1,27 +1,13 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Declare your gem's dependencies in geoblacklight_sidecar_images.gemspec.
4
- # Bundler will treat runtime dependencies like base dependencies, and
5
- # development dependencies will be added by default to the :development group.
6
-
7
- # Please see geoblacklight_sidecar_images.gemspec for dependency information.
8
3
  gemspec
9
4
 
10
- # Declare any dependencies that are still in development here instead of in
11
- # your gemspec. These might include edge Rails or gems from your path or
12
- # Git. Remember to move these dependencies to your gemspec before releasing
13
- # your gem to rubygems.org.
14
-
15
- group :development, :test do
16
- end
17
-
18
- # To use a debugger
19
- # gem 'byebug', group: [:development, :test]
5
+ # Ruby 4 removed cgi from default gems
6
+ gem "cgi" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("4.0.0")
20
7
 
21
8
  # BEGIN ENGINE_CART BLOCK
22
9
  # engine_cart: 1.2.0
23
10
  # engine_cart stanza: 0.10.0
24
- # the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
25
11
  file = File.expand_path("Gemfile", ENV["ENGINE_CART_DESTINATION"] || ENV["RAILS_ROOT"] || File.expand_path(".internal_test_app", File.dirname(__FILE__)))
26
12
 
27
13
  if File.exist?(file)
@@ -33,8 +19,7 @@ if File.exist?(file)
33
19
  end
34
20
  else
35
21
  Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
36
- gem "geoblacklight", ">= 2.0"
37
- gem "mini_magick", "~> 4.9.4"
22
+ gem "geoblacklight", ENV["GEOBLACKLIGHT_VERSION"] || ">= 4.0"
38
23
  gem "image_processing", "~> 1.6"
39
24
  gem "statesman", ">= 3.4"
40
25
  gem "marcel", ">= 1.0"
@@ -48,9 +33,6 @@ else
48
33
  end
49
34
  end
50
35
 
51
- if File.exist?("spec/test_app_templates/Gemfile.extra")
52
- # rubocop:disable Security/Eval
53
- eval File.read("spec/test_app_templates/Gemfile.extra"), nil, "spec/test_app_templates/Gemfile.extra"
54
- # rubocop:enable Security/Eval
55
- end
36
+ extra = File.expand_path("spec/test_app_templates/Gemfile.extra", File.dirname(__FILE__))
37
+ eval_gemfile extra if File.exist?(extra)
56
38
  # END ENGINE_CART BLOCK
data/README.md CHANGED
@@ -12,34 +12,34 @@ Store local copies of remote imagery in GeoBlacklight.
12
12
  * [Development](#development)
13
13
 
14
14
  ## Description
15
+
15
16
  This GeoBlacklight plugin captures remote images from geographic web services and saves them locally. It borrows the concept of a [SolrDocumentSidecar](https://github.com/projectblacklight/spotlight/blob/master/app/models/spotlight/solr_document_sidecar.rb) from [Spotlight](https://github.com/projectblacklight/spotlight), to have an ActiveRecord-based "sidecar" to match each non-AR SolrDocument. This allows us to use [ActiveStorage](https://github.com/rails/rails/tree/master/activestorage) to attach images to our solr documents.
16
17
 
17
18
  ### Example Screenshot
19
+
18
20
  ![Screenshot](screenshot.png)
19
21
 
20
22
  ## Requirements
21
23
 
22
- * [Ruby on Rails >= 5.2, < 8.0](https://weblog.rubyonrails.org/releases/)
23
- * [GeoBlacklight v4 or v3](https://github.com/geoblacklight/geoblacklight)
24
- * [ImageMagick](https://github.com/ImageMagick/ImageMagick)
24
+ * Ruby >= 3.3 (CI also runs on 3.4 and 4.0)
25
+ * Rails >= 7.2, < 9 (tested on 7.2 with GeoBlacklight 4 and 8.1 with GeoBlacklight 5/6)
26
+ * GeoBlacklight 4.x, 5.x, or 6.x
27
+ * [libvips](https://www.libvips.org/) (Rails default) or [ImageMagick](https://github.com/ImageMagick/ImageMagick)
25
28
 
26
29
  ### Suggested
27
30
 
28
- * Background Job Processor
29
-
30
- [Sidekiq](https://github.com/mperham/sidekiq) is an excellent choice if you need an opinion.
31
+ * Background job processor — [Solid Queue](https://github.com/rails/solid_queue) (Rails 8) or [Sidekiq](https://github.com/sidekiq/sidekiq)
31
32
 
32
33
  ## Installation
33
34
 
34
- ### Existing GeoBlacklight Instance
35
-
36
- GeoBlacklight v4 with Aardvark metadata / Add the gem to your Gemfile.
35
+ ### Existing GeoBlacklight instance
37
36
 
38
37
  ```ruby
39
- gem "geoblacklight_sidecar_images", "~> 1.0"
38
+ gem "geoblacklight_sidecar_images", "~> 2.0"
40
39
  ```
41
40
 
42
- GeoBlacklight v3 with GBL v1.0 metadata / Add the gem to your Gemfile.
41
+ GeoBlacklight v3 with GBL 1.0 metadata still uses the 0.9.x series:
42
+
43
43
  ```ruby
44
44
  gem "geoblacklight_sidecar_images", "~> 0.9.1", "< 1.0"
45
45
  ```
@@ -50,13 +50,15 @@ Run the generator.
50
50
  $ bin/rails generate geoblacklight_sidecar_images:install
51
51
  ```
52
52
 
53
+ Use `--skip-views` on GeoBlacklight 5/6 apps that render results with ViewComponents rather than the GBL 4 split catalog partial. Use `--skip-assets` when the host is not using Sprockets.
54
+
53
55
  Run the database migration.
54
56
 
55
57
  ```bash
56
58
  $ bin/rails db:migrate
57
59
  ```
58
60
 
59
- Complete any necessary [Active Storage setup](https://edgeguides.rubyonrails.org/active_storage_overview.html#setup) steps, for example:
61
+ Complete any necessary [Active Storage setup](https://guides.rubyonrails.org/active_storage_overview.html#setup) steps, for example:
60
62
 
61
63
  1. Add a config/storage.yml file
62
64
 
@@ -66,23 +68,24 @@ local:
66
68
  root: <%= Rails.root.join("storage") %>
67
69
  ```
68
70
 
69
- 2. Add config/environments declarations, development.rb for example:
71
+ 2. Add config/environments declarations, development.rb for example:
70
72
 
71
73
  ```
72
74
  # Store uploaded files on the local file system (see config/storage.yml for options)
73
75
  config.active_storage.service = :local
74
76
  ```
75
77
 
76
- ### New GeoBlacklight Instance
78
+ The install generator appends Sidecar Images settings to `config/settings.yml` (`GBLSI_THUMBNAIL_FIELD`, optional GeoServer proxy keys, and optional `GBLSI_OGM_API_URL`). Leave the GeoServer URLs blank unless you need authenticated local WMS harvesting. Leave `GBLSI_OGM_API_URL` blank unless you want to skip harvest and render OpenGeoMetadata API thumbnails instead.
77
79
 
78
- Create a new GeoBlacklight instance with the GBLSI code
80
+ `SolrDocument#sidecar` is included by the engine. You do not need to copy a method into `app/models/solr_document.rb`. If you are upgrading from 1.x, you can remove the generator-injected `sidecar` method from that file.
81
+
82
+ ### New GeoBlacklight instance
79
83
 
80
84
  ```bash
81
85
  $ rails new app-name -m https://raw.githubusercontent.com/geoblacklight/geoblacklight_sidecar_images/develop/template.rb
82
-
83
86
  ```
84
87
 
85
- ### Ingest Test Documents
88
+ ### Ingest test documents
86
89
 
87
90
  ```bash
88
91
  # Run your GBL instance
@@ -98,9 +101,11 @@ bundle exec rake gblsci:sample_data:seed
98
101
 
99
102
  ### Harvest images
100
103
 
104
+ Harvest is only needed when you store thumbnails in Active Storage. If `GBLSI_OGM_API_URL` is set, skip these tasks and see [OpenGeoMetadata API thumbnails](#opengeometadata-api-thumbnails).
105
+
101
106
  #### Harvest all images
102
107
 
103
- Spawns background jobs to harvest images for all documents in your Solr index.
108
+ Spawns background jobs to harvest images for all documents in your Solr index (paginated with Solr cursorMarks).
104
109
 
105
110
  ```bash
106
111
  bundle exec rake gblsci:images:harvest_all
@@ -141,40 +146,38 @@ We use a state machine library to track success/failure of our harvest tasks. Th
141
146
  SolrDocumentSidecar.in_state(:succeeded) => [#<SolrDocumentSidecar:0x0000000170697960 ... ]
142
147
  SolrDocumentSidecar.image.attached? => false
143
148
  SolrDocumentSidecar.image_state.current_state => "placeheld"
144
- SolrDocumentSidecar.image_state.last_transition => #<SidecarImageTransition id: 207, to_state: "placeheld", metadata: {"solr_doc_id"=>"stanford-cg357zz0321", "solr_version"=>1616509329754554368, "placeheld"=>true, "viewer_protocol"=>"wms", "image_url"=>"http://geowebservices-restricted.stanford.edu/geoserver/wms/reflect?&FORMAT=image%2Fpng&TRANSPARENT=TRUE&LAYERS=druid:cg357zz0321&WIDTH=300&HEIGHT=300", "service_url"=>"http://geowebservices-restricted.stanford.edu/geoserver/wms/reflect?&FORMAT=image%2Fpng&TRANSPARENT=TRUE&LAYERS=druid:cg357zz0321&WIDTH=300&HEIGHT=300", "gblsi_thumbnail_uri"=>false, "error"=>"Faraday::Error::ConnectionFailed"},...>
149
+ SolrDocumentSidecar.image_state.last_transition => #<SidecarImageTransition id: 207, to_state: "placeheld", metadata: {"solr_doc_id"=>"stanford-cg357zz0321", ...>
145
150
  ```
146
151
 
147
152
  ### Destroy images
148
153
 
149
- #### Remove everything
154
+ Destructive tasks require `CONFIRM=1`.
150
155
 
151
- Remove all sidecar objects and attached images
156
+ #### Remove everything
152
157
 
153
158
  ```bash
154
- bundle exec rake gblsci:images:harvest_purge_all
159
+ CONFIRM=1 bundle exec rake gblsci:images:harvest_purge_all
155
160
  ```
156
161
 
157
162
  #### Remove orphaned AR objects
158
163
 
159
- Remove all sidecar objects and attached images for AR objects without a corresponding Solr document
160
-
161
164
  ```bash
162
- bundle exec rake gblsci:images:harvest_purge_orphans
165
+ CONFIRM=1 bundle exec rake gblsci:images:harvest_purge_orphans
163
166
  ```
164
167
 
165
168
  #### Remove a batch
166
169
 
167
- Remove sidecar objects and attached images via a CSV file of document ids
170
+ Remove sidecar objects and attached images via a CSV file of document ids at `tmp/destroy_batch.csv`.
168
171
 
169
172
  ```bash
170
- bundle exec rake gblsci:images:harvest_destroy_batch
173
+ CONFIRM=1 bundle exec rake gblsci:images:harvest_destroy_batch
171
174
  ```
172
175
 
173
176
  ### Troubleshooting
174
177
 
175
178
  #### Harvest report
176
179
 
177
- Generate a CSV file of sidecar objects and associated image state. Useful for debugging problem items.
180
+ Generate a CSV file of sidecar objects and associated image state under `tmp/`.
178
181
 
179
182
  ```bash
180
183
  bundle exec rake gblsci:images:harvest_report
@@ -197,63 +200,64 @@ If you add a thumbnail uri to your geoblacklight solr documents...
197
200
  ```json
198
201
  {
199
202
  ...
200
- "dc_format_s":"TIFF",
201
- "dc_creator_sm":["Minnesota. Department of Highways."],
202
- "thumbnail_path_ss":"https://umedia.lib.umn.edu/sites/default/files/imagecache/square300/reference/562/image/jpeg/1089695.jpg",
203
- "dc_type_s":"Still image",
203
+ "dct_format_s": "TIFF",
204
+ "dct_creator_sm": ["Minnesota. Department of Highways."],
205
+ "thumbnail_path_ss": "https://umedia.lib.umn.edu/sites/default/files/imagecache/square300/reference/562/image/jpeg/1089695.jpg",
206
+ "gbl_resourceClass_sm": ["Imagery"],
204
207
  ...
205
208
  }
206
209
  ```
207
210
 
208
- Then you can edit your GeoBlacklight settings.yml file to point at that solr field (Settings.GBLSI_THUMBNAIL_FIELD). Any docs in your index that have a value for that field will harvest the image at that URI instead of trying to retrieve an image via IIIF or the other web services.
211
+ Then you can edit your GeoBlacklight settings.yml file to point at that solr field (`Settings.GBLSI_THUMBNAIL_FIELD`). Any docs in your index that have a value for that field will harvest the image at that URI instead of trying to retrieve an image via IIIF or the other web services.
212
+
213
+ ## OpenGeoMetadata API thumbnails
214
+
215
+ To skip harvest, Active Storage, and the sidecar state machine entirely, point views at the OpenGeoMetadata API. Thumbnails are loaded in the browser from:
216
+
217
+ `https://ogm.geo4lib.app/api/v1/resources/{id}/thumbnail`
218
+
219
+ Set the API root in `config/settings.yml`:
220
+
221
+ ```yaml
222
+ GBLSI_OGM_API_URL: 'https://ogm.geo4lib.app/api/v1'
223
+ ```
224
+
225
+ `sidecar_thumbnail_tag document` then renders an `img` for that URL (for example `stanford-mp692kw6192` → `/resources/stanford-mp692kw6192/thumbnail`). No sidecar row is created. Harvest rake tasks are unused in this mode.
226
+
227
+ The harvest/Active Storage path remains the default when `GBLSI_OGM_API_URL` is blank.
209
228
 
210
229
  ## View customization
211
230
 
212
- Use basic Active Storage patterns to display imagery in your application.
231
+ Use basic Active Storage patterns, or the engine helper, to display imagery in your application.
213
232
 
214
- ### Example Methods
233
+ ### Example methods
215
234
 
216
235
  ```ruby
217
- # Is there an image?
218
- document.sidecar.image.attached?
236
+ # Helper (available in host views). Uses the OGM API when GBLSI_OGM_API_URL is
237
+ # set; otherwise uses a harvested Active Storage attachment.
238
+ <%= sidecar_thumbnail_tag document, size: [200, 200] %>
219
239
 
220
- # Can the image size be manipulated?
240
+ # Harvested Active Storage (only when OGM API thumbnails are not enabled)
241
+ document.sidecar.image.attached?
221
242
  document.sidecar.image.variable?
222
-
223
- # Example image_tag with resize
224
243
  <%= image_tag document.sidecar.image.variant(resize_to_fit: [100, 100]), {class: 'media-object'} %>
225
-
226
244
  ```
227
245
 
228
246
  ### Search results
229
247
 
230
- This GBL plugin includes a custom [catalog/_index_split_default.html.erb file](https://github.com/geoblacklight/geoblacklight_sidecar_images/blob/develop/lib/generators/geoblacklight_sidecar_images/templates/views/catalog/_index_split_default.html.erb). Look there for examples on calling the image method.
248
+ On GeoBlacklight 4, the install generator can copy a catalog `_index_split_default.html.erb` partial. GeoBlacklight 5/6 apps should call `sidecar_thumbnail_tag` (or `document.sidecar.image`) from their result component instead of replacing Blacklight helpers.
231
249
 
232
250
  ### Show pages
233
251
 
234
252
  Example for adding a thumbnail to the show page sidebar.
235
253
 
236
- *catalog/_show_sidebar.html.erb*
237
-
238
254
  ```ruby
239
- # Add to end of file
240
- <% if @document.sidecar.image.attached? %>
241
- <% if @document.sidecar.image.variable? %>
242
- <div class="card">
243
- <div class="card-header">Thumbnail</div>
244
- <div class="card-body">
245
- <%= image_tag @document.sidecar.image.variant(resize_to_fit: [200, 200]), {class: 'mr-3'} %>
246
- </div>
247
- </div>
248
- <% end %>
249
- <% end %>
250
-
255
+ <%= sidecar_thumbnail_tag @document, size: [200, 200], class: "mr-3" %>
251
256
  ```
252
257
 
253
258
  ## Development
254
259
 
255
260
  ```bash
256
-
257
261
  # Run test suite
258
262
  bundle exec rake ci
259
263
 
@@ -269,8 +273,12 @@ bundle exec rake gblsci:images:harvest_all
269
273
 
270
274
  # Tail image service log file
271
275
  tail -f log/image_service_development.log
276
+ ```
272
277
 
278
+ Test against a specific stack with environment variables:
279
+
280
+ ```bash
281
+ RAILS_VERSION=8.1.3 GEOBLACKLIGHT_VERSION="~> 5.3" bundle exec rake ci
273
282
  ```
274
283
 
275
284
  [See Localhost Results](http://localhost:3000/?per_page=50&q=&search_field=all_fields)
276
-
data/Rakefile CHANGED
@@ -22,11 +22,23 @@ RuboCop::RakeTask.new(:rubocop)
22
22
  require "solr_wrapper/rake_task"
23
23
  require "engine_cart/rake_task"
24
24
  require "geoblacklight_sidecar_images/version"
25
+ require "fileutils"
26
+
27
+ # EngineCart bundles the test app before TestAppGenerator runs. Copy Bundler
28
+ # platform settings so Nokogiri uses the precompiled native gem.
29
+ Rake::Task["engine_cart:inject_gemfile_extras"].enhance do
30
+ dest = File.join(EngineCart.destination, ".bundle")
31
+ FileUtils.mkdir_p(dest)
32
+ File.write(File.join(dest, "config"), <<~YAML)
33
+ ---
34
+ BUNDLE_FORCE_RUBY_PLATFORM: "false"
35
+ BUNDLE_SPECIFIC_PLATFORM: "true"
36
+ YAML
37
+ end
25
38
 
26
39
  desc "Run test suite"
27
40
  task ci: ["engine_cart:generate"] do
28
41
  ENV["environment"] = "test"
29
- # run the tests
30
42
  Rake::Task["spec"].invoke
31
43
  end
32
44
 
@@ -2,6 +2,5 @@
2
2
 
3
3
  module GeoblacklightSidecarImages
4
4
  class ApplicationController < ActionController::Base
5
- protect_from_forgery with: :exception
6
5
  end
7
6
  end
@@ -2,5 +2,20 @@
2
2
 
3
3
  module GeoblacklightSidecarImages
4
4
  module ApplicationHelper
5
+ def sidecar_thumbnail_tag(document, size: [200, 200], **options)
6
+ options = {alt: "", role: "presentation"}.merge(options)
7
+
8
+ ogm_url = document.try(:ogm_thumbnail_url)
9
+ return image_tag(ogm_url, options) if ogm_url.present?
10
+
11
+ sidecar = document.sidecar
12
+ return unless sidecar.image.attached?
13
+
14
+ if sidecar.image.variable?
15
+ image_tag sidecar.image.variant(resize_to_fit: size), options
16
+ else
17
+ image_tag sidecar.image, options
18
+ end
19
+ end
5
20
  end
6
21
  end
@@ -1,15 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "faraday"
4
+
3
5
  module GeoblacklightSidecarImages
4
6
  class StoreImageJob < ApplicationJob
5
- queue_as :default
7
+ queue_as :gblsci
8
+
9
+ retry_on Faraday::TimeoutError, wait: :polynomially_longer, attempts: 5
10
+ retry_on Faraday::ConnectionFailed, wait: :polynomially_longer, attempts: 3
11
+ discard_on Blacklight::Exceptions::RecordNotFound
6
12
 
7
13
  def perform(solr_document_id)
8
14
  document = Geoblacklight::SolrDocument.find(solr_document_id)
9
15
 
10
- metadata = {}
11
- metadata["solr_doc_id"] = document.id
12
- metadata["solr_version"] = document.sidecar.version
16
+ metadata = {
17
+ "solr_doc_id" => document.id,
18
+ "solr_version" => document.sidecar.version
19
+ }
13
20
 
14
21
  document.sidecar.image_state.transition_to!(:queued, metadata)
15
22
  GeoblacklightSidecarImages::ImageService.new(document).store
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoblacklightSidecarImages
4
+ module SolrDocumentBehavior
5
+ extend ActiveSupport::Concern
6
+
7
+ def ogm_thumbnail_url
8
+ GeoblacklightSidecarImages::OgmThumbnail.url_for(self)
9
+ end
10
+
11
+ def sidecar
12
+ record = SolrDocumentSidecar.find_or_initialize_by(
13
+ document_id: id,
14
+ document_type: self.class.to_s
15
+ )
16
+ version = _source["_version_"]
17
+ if record.new_record? || record.version != version
18
+ record.version = version
19
+ record.save!
20
+ end
21
+ record
22
+ end
23
+ end
24
+ end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WmsRewriteConcern
4
- extend Geoblacklight::SolrDocument
4
+ extend ActiveSupport::Concern
5
5
 
6
6
  def viewer_endpoint
7
- if local_restricted?
8
- # replace wms prefix with cas authed proxy
7
+ if local_restricted? && geoserver_proxy_configured?
9
8
  super.gsub(Settings.INSTITUTION_GEOSERVER_URL, Settings.PROXY_GEOSERVER_URL)
10
9
  else
11
10
  super
@@ -17,6 +16,16 @@ module WmsRewriteConcern
17
16
  end
18
17
 
19
18
  def local?
20
- fetch(Settings.FIELDS.PROVIDER, "").casecmp(Settings.INSTITUTION_LOCAL_NAME).zero?
19
+ name = Settings.INSTITUTION_LOCAL_NAME.to_s
20
+ return false if name.blank?
21
+
22
+ fetch(GeoblacklightSidecarImages::FieldMap[:provider], "").casecmp(name).zero?
23
+ end
24
+
25
+ private
26
+
27
+ def geoserver_proxy_configured?
28
+ Settings.INSTITUTION_GEOSERVER_URL.to_s.present? &&
29
+ Settings.PROXY_GEOSERVER_URL.to_s.present?
21
30
  end
22
31
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class SidecarImageTransition < ApplicationRecord
3
+ class SidecarImageTransition < GeoblacklightSidecarImages::ApplicationRecord
4
+ self.table_name = "sidecar_image_transitions"
5
+
4
6
  include Statesman::Adapters::ActiveRecordTransition
5
7
 
6
8
  validates :to_state, inclusion: {in: SidecarImageStateMachine.states}
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ##
4
- # Metadata for indexed documents
5
- class SolrDocumentSidecar < ApplicationRecord
4
+ # ActiveRecord sidecar for a Solr document, with an attached thumbnail image.
5
+ class SolrDocumentSidecar < GeoblacklightSidecarImages::ApplicationRecord
6
+ self.table_name = "solr_document_sidecars"
7
+
6
8
  include Statesman::Adapters::ActiveRecordQueries[
7
9
  transition_class: SidecarImageTransition,
8
10
  initial_state: :initialized
@@ -12,6 +14,7 @@ class SolrDocumentSidecar < ApplicationRecord
12
14
  has_many :sidecar_image_transitions, autosave: false, dependent: :destroy
13
15
  has_one_attached :image
14
16
 
17
+ # SolrDocument is not an ActiveRecord model. Reconstruct from the stored id.
15
18
  def document
16
19
  document_type.new document_type.unique_key => document_id
17
20
  end
@@ -35,7 +38,9 @@ class SolrDocumentSidecar < ApplicationRecord
35
38
  :initialized
36
39
  end
37
40
 
38
- def self.image_url
41
+ def image_url
42
+ return unless image.attached?
43
+
39
44
  Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true)
40
45
  end
41
46