diff --git a/Gemfile b/Gemfile index e00eeee..f75148a 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'elasticsearch', '~> 8' gem 'searchkick' # Use the Puma web server [https://github.com/puma/puma] -gem 'puma', '~> 5.0' +gem 'puma', '~> 8.0' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] @@ -33,7 +33,13 @@ gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] gem 'bootsnap', require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] -gem 'image_processing', '~> 1.2' +gem 'image_processing', '~> 2.0' +# mini_magick/ruby-vips became soft dependencies of image_processing in 2.0 and must be +# added explicitly. This app's config.load_defaults 7.0 (config/application.rb) sets +# config.active_storage.variant_processor = :vips - vips is the actually-active processor, +# not mini_magick (previously present only as an unused transitive dependency of +# image_processing 1.x's gemspec, which required both backends unconditionally). +gem 'ruby-vips', '~> 2.0' # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible gem 'rack-cors' @@ -84,9 +90,9 @@ gem 'acts-as-taggable-on', '~> 13.0' gem 'administrate-field-list', '~> 0.0.6' -gem 'httparty', '~> 0.20.0' +gem 'httparty', '~> 0.24.0' -gem 'roo', '~> 2.9' +gem 'roo', '~> 3.0' gem 'namae', '~> 1.1' diff --git a/Gemfile.lock b/Gemfile.lock index 3b4bc5b..c7357ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -183,15 +183,13 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) - hashie (5.0.0) - httparty (0.20.0) - mime-types (~> 3.0) + httparty (0.24.2) + csv + mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.14.8) concurrent-ruby (~> 1.0) - image_processing (1.13.0) - mini_magick (>= 4.9.5, < 5) - ruby-vips (>= 2.0.17, < 3) + image_processing (2.0.3) importmap-rails (2.0.3) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -218,6 +216,7 @@ GEM kaminari-core (= 1.2.2) kaminari-core (1.2.2) language_server-protocol (3.17.0.6) + lint_roller (1.1.0) logger (1.6.6) loofah (2.25.2) crass (~> 1.0.2) @@ -230,17 +229,13 @@ GEM net-smtp marcel (1.2.1) matrix (0.4.3) - mime-types (3.5.2) - mime-types-data (~> 3.2015) - mime-types-data (3.2024.1203) - mini_magick (4.13.2) mini_mime (1.1.5) mini_portile2 (2.8.9) minitest (5.25.5) msgpack (1.8.4) multi_json (1.21.1) - multi_xml (0.7.2) - bigdecimal (~> 3.1) + multi_xml (0.9.1) + bigdecimal (>= 3.1, < 5) namae (1.2.0) racc (~> 1.7) net-http (0.9.1) @@ -280,10 +275,11 @@ GEM ast (~> 2.4.1) racc pg (1.5.9) + prism (1.9.0) psych (5.1.2) stringio public_suffix (7.0.5) - puma (5.6.9) + puma (8.0.2) nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) @@ -337,9 +333,12 @@ GEM reline (0.5.12) io-console (~> 0.5) rexml (3.4.4) - roo (2.10.1) + roo (3.0.0) + base64 (~> 0.2) + csv (~> 3) + logger (~> 1) nokogiri (~> 1) - rubyzip (>= 1.3.0, < 3.0.0) + rubyzip (>= 3.0.0, < 4.0.0) rspec-core (3.13.6) rspec-support (~> 3.13.0) rspec-expectations (3.13.5) @@ -348,45 +347,51 @@ GEM rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.5) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-rails (8.0.4) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (>= 3.13.0, < 5.0.0) + rspec-expectations (>= 3.13.0, < 5.0.0) + rspec-mocks (>= 3.13.0, < 5.0.0) + rspec-support (>= 3.13.0, < 5.0.0) rspec-support (3.13.7) - rubocop (1.65.1) + rubocop (1.89.0) json (~> 2.3) - language_server-protocol (>= 3.17.0) - parallel (~> 1.10) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (>= 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) - parser (>= 3.3.1.0) - rubocop-factory_bot (2.26.1) - rubocop (~> 1.61) - rubocop-rails (2.26.2) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.50.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-factory_bot (2.28.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rails (2.36.0) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.52.0, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.5) - rubocop (~> 1.61) - rubocop-rspec_rails (2.30.0) - rubocop (~> 1.61) - rubocop-rspec (~> 3, >= 3.0.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rspec (3.10.2) + lint_roller (~> 1.1) + regexp_parser (>= 2.0) + rubocop (~> 1.86, >= 1.86.2) + rubocop-rspec_rails (2.32.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rspec (~> 3.5) ruby-progressbar (1.13.0) - ruby-vips (2.2.5) + ruby-vips (2.3.0) ffi (~> 1.12) logger - rubyzip (2.3.2) + rubyzip (3.4.1) sassc (2.4.0) ffi (~> 1.9) sassc-rails (2.1.2) @@ -395,9 +400,8 @@ GEM sprockets (> 3.0) sprockets-rails tilt - searchkick (5.3.1) - activemodel (>= 6.1) - hashie + searchkick (6.1.2) + activemodel (>= 7.2) securerandom (0.3.2) selenium-devtools (0.151.0) selenium-webdriver (~> 4.2) @@ -407,8 +411,8 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) - shoulda-matchers (6.4.0) - activesupport (>= 5.2.0) + shoulda-matchers (8.0.1) + activesupport (>= 7.2) sidekiq (7.3.10) base64 connection_pool (>= 2.3.0, < 3) @@ -484,23 +488,24 @@ DEPENDENCIES elasticsearch (~> 8) factory_bot_rails faker - httparty (~> 0.20.0) - image_processing (~> 1.2) + httparty (~> 0.24.0) + image_processing (~> 2.0) importmap-rails (~> 2.0) jbuilder (~> 2.11) kaminari (~> 1.2) namae (~> 1.1) pg (~> 1.1) - puma (~> 5.0) + puma (~> 8.0) rack-cors rails (~> 8.1.3) - roo (~> 2.9) + roo (~> 3.0) rspec-rails rubocop rubocop-factory_bot rubocop-rails rubocop-rspec rubocop-rspec_rails + ruby-vips (~> 2.0) sassc-rails searchkick selenium-devtools diff --git a/app/controllers/entities_controller.rb b/app/controllers/entities_controller.rb index 6ffd2c7..073cd32 100644 --- a/app/controllers/entities_controller.rb +++ b/app/controllers/entities_controller.rb @@ -69,8 +69,12 @@ def letters private def reindex - Entity.reindex if ENV['RAILS_ENV'] == 'test' - PublishedEntity.reindex if ENV['RAILS_ENV'] == 'test' + # mode: :inline forces a synchronous reindex regardless of Searchable's + # `callbacks: :async` option - searchkick's default mode resolution falls back to + # the model's callbacks option (see Searchkick::Index#reindex_records), so without + # this the search immediately below could run against a not-yet-indexed record. + Entity.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' + PublishedEntity.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' rescue Searchkick::Error end diff --git a/app/controllers/letters_controller.rb b/app/controllers/letters_controller.rb index 94434e9..96f1ed8 100644 --- a/app/controllers/letters_controller.rb +++ b/app/controllers/letters_controller.rb @@ -55,7 +55,7 @@ def letters_from_results(results) volume: letter.volume, recipients: letter.recipients, destinations: letter.destinations, - origins: letter.orgins, + origins: letter.origins, mentions: letter.mentions } end @@ -134,8 +134,12 @@ def set_filters # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity def reindex - Letter.reindex if ENV['RAILS_ENV'] == 'test' - PublishedLetter.reindex if ENV['RAILS_ENV'] == 'test' + # mode: :inline forces a synchronous reindex regardless of Searchable's + # `callbacks: :async` option - searchkick's default mode resolution falls back to + # the model's callbacks option (see Searchkick::Index#reindex_records), so without + # this the search immediately below could run against a not-yet-indexed record. + Letter.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' + PublishedLetter.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' end # Only allow a list of trusted parameters through. diff --git a/app/dashboards/entity_dashboard.rb b/app/dashboards/entity_dashboard.rb index 2c6101d..d55f8aa 100644 --- a/app/dashboards/entity_dashboard.rb +++ b/app/dashboards/entity_dashboard.rb @@ -4,6 +4,7 @@ class EntityDashboard < Administrate::BaseDashboard include ActionView::Helpers::SanitizeHelper + # ATTRIBUTE_TYPES # a hash that describes the type of each of the model's fields. # diff --git a/app/jobs/load_big_sam_job.rb b/app/jobs/load_big_sam_job.rb index e033577..191f072 100644 --- a/app/jobs/load_big_sam_job.rb +++ b/app/jobs/load_big_sam_job.rb @@ -5,6 +5,7 @@ class LoadBigSamJob < ApplicationJob include ActionView::Helpers::SanitizeHelper + queue_as :default # Raised to abandon a single row (e.g. an unparseable date) without treating it as a @@ -372,7 +373,7 @@ def get_entity(label: nil, type: nil, return_nil: false) def get_person(name) entity = nil names = Namae.parse(name).first - if names&.given && names&.family + if names&.given && names.family names.family = "Van #{names.family}" if names.particle&.downcase == 'van' names.family = "von #{names.family}" if names.particle&.downcase == 'von' names = mc_or_mac?(names) diff --git a/app/models/concerns/entity_common.rb b/app/models/concerns/entity_common.rb index 86adf35..1416591 100644 --- a/app/models/concerns/entity_common.rb +++ b/app/models/concerns/entity_common.rb @@ -198,7 +198,7 @@ def short_display lines.push("Date #{date_str}") if date_str.present? end - paragraphs = lines.map {|line| "
#{line}
" }.flatten.join.strip + paragraphs = lines.map {|line| "#{line}
" }.join.strip Loofah.fragment("