diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8544b80..8dd7ebc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,7 +68,7 @@ jobs: - name: Install system requirements run: | sudo apt update - sudo apt install -y postgresql-client + sudo apt install -y postgresql-client libvips42 - name: Bundle Install run: | diff --git a/.ruby-version b/.ruby-version index a0891f5..84d6c67 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.4 +3.4.10 diff --git a/Dockerfile b/Dockerfile index 64a860f..acf172b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3.4 +FROM ruby:3.4.10 ARG RAILS_MASTER_KEY ARG REDIS_URL @@ -6,6 +6,7 @@ ARG REDIS_URL RUN apt-get update \ && apt-get install -y --no-install-recommends \ postgresql-client \ + libvips42 \ && rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/app diff --git a/Gemfile b/Gemfile index b667cf6..e00eeee 100644 --- a/Gemfile +++ b/Gemfile @@ -3,13 +3,19 @@ source 'https://rubygems.org' git_source(:github) {|_repo| "https://github.com/#{repo}.git" } -ruby '3.3.4' +ruby '3.4.10' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' -gem 'rails', '~> 7.2.1' +gem 'rails', '~> 8.1.3' +# csv stopped being a Ruby default gem in 3.4+; httparty requires it internally +# without declaring it as a dependency, so it must be explicit here. gem 'csv' +# benchmark won't be a default gem starting in Ruby 4.0; mini_magick requires it +# internally without declaring it as a dependency. +gem 'benchmark' + # Use postgresql as the database for Active Record gem 'pg', '~> 1.1' @@ -20,18 +26,6 @@ gem 'searchkick' # Use the Puma web server [https://github.com/puma/puma] gem 'puma', '~> 5.0' -# Build JSON APIs with ease [https://github.com/rails/jbuilder] -# gem 'jbuilder' - -# Use Redis adapter to run Action Cable in production -# gem 'redis', '~> 4.0' - -# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] -# gem 'kredis' - -# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] -# gem 'bcrypt', '~> 3.1.7' - # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] @@ -48,6 +42,12 @@ gem 'administrate' gem 'administrate-field-jsonb' gem 'trix-rails', require: 'trix' +# administrate < 1.0 pulled these in transitively via sassc-rails; administrate 1.0 +# bundles its own assets and dropped that dependency, but the app's own asset +# pipeline (app/assets/config/manifest.js) still relies on Sprockets/Sass directly. +gem 'sassc-rails' +gem 'sprockets-rails' + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem 'debug', platforms: %i[mri mingw x64_mingw] @@ -67,19 +67,20 @@ group :test do # chromedriver binary itself (Selenium Manager) - no separate webdriver gem needed. gem 'capybara' gem 'selenium-webdriver' + # CDP support, needed for Selenium's driver.register(username:, password:) - used to + # authenticate admin system specs without embedding credentials in the visited URL. + gem 'selenium-devtools' end -gem 'pundit', '~> 2.2' - gem 'kaminari', '~> 1.2' gem 'jbuilder', '~> 2.11' -gem 'rspec_api_documentation', '~> 6.1' - -gem 'acts-as-taggable-on', '~> 11.0.0' - -gem 'administrate-field-acts_as_taggable' +# 11.0.0 hard-pins activerecord < 8.0, which makes it impossible to install +# alongside Rails 8 at all - not a discretionary bump, a forced one. 12->13 has +# no breaking changes to the tag_list/for_context API ActsAsTaggableField uses +# (see CHANGELOG.md), only dropped-Ruby-version and added-Rails-version support. +gem 'acts-as-taggable-on', '~> 13.0' gem 'administrate-field-list', '~> 0.0.6' @@ -95,9 +96,7 @@ gem 'active_record_doctor', '~> 1.10' gem 'sidekiq', '>=7.2.2', '<8' -gem 'uuid', '~> 2.3' - -gem 'addressable', '~> 2.8' +gem 'addressable', '~> 2.9' gem 'importmap-rails', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 609e992..3b4bc5b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,104 +1,102 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.1) - actionpack (= 7.2.1) - activesupport (= 7.2.1) + action_text-trix (2.1.19) + railties + actioncable (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.1) - actionpack (= 7.2.1) - activejob (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + actionmailbox (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) mail (>= 2.8.0) - actionmailer (7.2.1) - actionpack (= 7.2.1) - actionview (= 7.2.1) - activejob (= 7.2.1) - activesupport (= 7.2.1) + actionmailer (8.1.3.1) + actionpack (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activesupport (= 8.1.3.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.1) - actionview (= 7.2.1) - activesupport (= 7.2.1) + actionpack (8.1.3.1) + actionview (= 8.1.3.1) + activesupport (= 8.1.3.1) nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.1) - actionpack (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + actiontext (8.1.3.1) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.1) - activesupport (= 7.2.1) + actionview (8.1.3.1) + activesupport (= 8.1.3.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_record_doctor (1.14.0) activerecord (>= 4.2.0) - activejob (7.2.1) - activesupport (= 7.2.1) + activejob (8.1.3.1) + activesupport (= 8.1.3.1) globalid (>= 0.3.6) - activemodel (7.2.1) - activesupport (= 7.2.1) - activerecord (7.2.1) - activemodel (= 7.2.1) - activesupport (= 7.2.1) + activemodel (8.1.3.1) + activesupport (= 8.1.3.1) + activerecord (8.1.3.1) + activemodel (= 8.1.3.1) + activesupport (= 8.1.3.1) timeout (>= 0.4.0) - activestorage (7.2.1) - actionpack (= 7.2.1) - activejob (= 7.2.1) - activerecord (= 7.2.1) - activesupport (= 7.2.1) + activestorage (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activesupport (= 8.1.3.1) marcel (~> 1.0) - activesupport (7.2.1) + activesupport (8.1.3.1) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - acts-as-taggable-on (11.0.0) - activerecord (>= 7.0, < 8.0) + uri (>= 0.13.1) + acts-as-taggable-on (13.0.0) + activerecord (>= 7.1, < 8.2) zeitwerk (>= 2.4, < 3.0) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - administrate (0.20.1) - actionpack (>= 6.0, < 8.0) - actionview (>= 6.0, < 8.0) - activerecord (>= 6.0, < 8.0) - jquery-rails (~> 4.6.0) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + administrate (1.0.0) + actionpack (>= 6.0, < 9.0) + actionview (>= 6.0, < 9.0) + activerecord (>= 6.0, < 9.0) kaminari (~> 1.2.2) - sassc-rails (~> 2.1) - selectize-rails (~> 0.6) administrate-field-active_storage (0.4.2) administrate (>= 0.2.2) rails (>= 7.0) - administrate-field-acts_as_taggable (0.0.4) - acts-as-taggable-on (>= 6.0) - administrate (< 1.0.0) - administrate-field-jsonb (0.4.6) - administrate (< 1.0.0) + administrate-field-jsonb (0.4.8) + administrate (< 2.0) rails (>= 4.2) administrate-field-list (0.0.6) administrate rails (>= 5.0) - ast (2.4.2) + ast (2.4.3) aws-eventstream (1.4.0) aws-partitions (1.1278.0) aws-sdk-core (3.254.1) @@ -117,9 +115,10 @@ GEM aws-sigv4 (~> 1.5) aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) - base64 (0.2.0) - bigdecimal (3.1.8) - bootsnap (1.18.4) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (3.1.9) + bootsnap (1.18.6) msgpack (~> 1.2) builder (3.3.0) capybara (3.40.0) @@ -131,20 +130,20 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - concurrent-ruby (1.3.4) + concurrent-ruby (1.3.8) connection_pool (2.4.1) - crass (1.0.6) + crass (1.0.7) cronex (0.15.0) tzinfo unicode (>= 0.4.4.5) - csv (3.3.0) - date (3.3.4) + csv (3.3.6) + date (3.5.1) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) diff-lcs (1.5.1) - drb (2.2.1) - elastic-transport (8.5.2) + drb (2.2.3) + elastic-transport (8.5.3) faraday (< 3) multi_json elasticsearch (8.19.3) @@ -153,33 +152,33 @@ GEM ostruct elasticsearch-api (8.19.3) multi_json - erubi (1.13.0) - et-orbi (1.4.0) + erubi (1.13.1) + et-orbi (1.4.1) tzinfo - factory_bot (6.4.6) - activesupport (>= 5.0.0) - factory_bot_rails (6.4.3) - factory_bot (~> 6.4) + factory_bot (6.5.6) + activesupport (>= 6.1.0) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) railties (>= 5.0.0) faker (3.4.2) i18n (>= 1.8.11, < 2) - faraday (2.14.2) + faraday (2.14.3) faraday-net_http (>= 2.0, < 3.5) json logger faraday-net_http (3.4.4) net-http (~> 0.5) - ffi (1.17.0-aarch64-linux-gnu) - ffi (1.17.0-aarch64-linux-musl) - ffi (1.17.0-arm-linux-gnu) - ffi (1.17.0-arm-linux-musl) - ffi (1.17.0-arm64-darwin) - ffi (1.17.0-x86-linux-gnu) - ffi (1.17.0-x86-linux-musl) - ffi (1.17.0-x86_64-darwin) - ffi (1.17.0-x86_64-linux-gnu) - ffi (1.17.0-x86_64-linux-musl) - fugit (1.12.2) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + fugit (1.12.3) et-orbi (~> 1.4) raabro (~> 1.4) globalid (1.2.1) @@ -188,28 +187,24 @@ GEM httparty (0.20.0) mime-types (~> 3.0) multi_xml (>= 0.5.2) - i18n (1.14.5) + 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) - importmap-rails (2.0.1) + importmap-rails (2.0.3) actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) io-console (0.7.2) - irb (1.14.0) + irb (1.14.3) rdoc (>= 4.0.0) reline (>= 0.4.2) jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) jmespath (1.6.2) - jquery-rails (4.6.0) - rails-dom-testing (>= 1, < 3) - railties (>= 4.2.0) - thor (>= 0.14, < 2.0) - json (2.7.2) + json (2.7.6) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -222,110 +217,115 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - language_server-protocol (3.17.0.3) - logger (1.6.0) - loofah (2.22.0) + language_server-protocol (3.17.0.6) + logger (1.6.6) + loofah (2.25.2) crass (~> 1.0.2) nokogiri (>= 1.12.0) - macaddr (1.7.2) - systemu (~> 2.6.5) - mail (2.8.1) + mail (2.9.1) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) + marcel (1.2.1) matrix (0.4.3) mime-types (3.5.2) mime-types-data (~> 3.2015) - mime-types-data (3.2024.0820) + mime-types-data (3.2024.1203) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.1) - msgpack (1.7.2) + mini_portile2 (2.8.9) + minitest (5.25.5) + msgpack (1.8.4) multi_json (1.21.1) - multi_xml (0.7.1) + multi_xml (0.7.2) bigdecimal (~> 3.1) - mustache (1.1.1) namae (1.2.0) racc (~> 1.7) net-http (0.9.1) uri (>= 0.11.1) - net-imap (0.4.14) + net-imap (0.6.6) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol - nio4r (2.7.3) - nokogiri (1.16.7-aarch64-linux) + nio4r (2.7.5) + nokogiri (1.19.4) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + nokogiri (1.19.4-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.16.7-arm-linux) + nokogiri (1.19.4-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.16.7-arm64-darwin) + nokogiri (1.19.4-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.16.7-x86-linux) + nokogiri (1.19.4-arm-linux-musl) racc (~> 1.4) - nokogiri (1.16.7-x86_64-darwin) + nokogiri (1.19.4-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) + nokogiri (1.19.4-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-musl) racc (~> 1.4) ostruct (0.6.3) parallel (1.26.3) - parser (3.3.4.2) + parser (3.3.12.0) ast (~> 2.4.1) racc - pg (1.5.7) + pg (1.5.9) psych (5.1.2) stringio - public_suffix (6.0.1) - puma (5.6.8) + public_suffix (7.0.5) + puma (5.6.9) nio4r (~> 2.0) - pundit (2.4.0) - activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) - rack (2.2.9) + rack (2.2.23) rack-cors (2.0.2) rack (>= 2.0.0) rack-session (1.0.2) rack (< 3) rack-test (2.1.0) rack (>= 1.3) - rackup (1.0.0) + rackup (1.0.1) rack (< 3) webrick - rails (7.2.1) - actioncable (= 7.2.1) - actionmailbox (= 7.2.1) - actionmailer (= 7.2.1) - actionpack (= 7.2.1) - actiontext (= 7.2.1) - actionview (= 7.2.1) - activejob (= 7.2.1) - activemodel (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + rails (8.1.3.1) + actioncable (= 8.1.3.1) + actionmailbox (= 8.1.3.1) + actionmailer (= 8.1.3.1) + actionpack (= 8.1.3.1) + actiontext (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activemodel (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) bundler (>= 1.15.0) - railties (= 7.2.1) + railties (= 8.1.3.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.2.1) - actionpack (= 7.2.1) - activesupport (= 7.2.1) + rails-html-sanitizer (1.7.1) + loofah (~> 2.25, >= 2.25.2) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) @@ -333,27 +333,22 @@ GEM psych (>= 4.0.0) redis-client (0.23.2) connection_pool - regexp_parser (2.9.2) - reline (0.5.9) + regexp_parser (2.9.3) + reline (0.5.12) io-console (~> 0.5) - rexml (3.3.6) - strscan + rexml (3.4.4) roo (2.10.1) nokogiri (~> 1) rubyzip (>= 1.3.0, < 3.0.0) - rspec (3.13.0) - rspec-core (~> 3.13.0) - rspec-expectations (~> 3.13.0) - rspec-mocks (~> 3.13.0) - rspec-core (3.13.0) + rspec-core (3.13.6) rspec-support (~> 3.13.0) - rspec-expectations (3.13.2) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.1) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.4) + rspec-rails (6.1.5) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -361,11 +356,7 @@ GEM rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) - rspec-support (3.13.1) - rspec_api_documentation (6.1.0) - activesupport (>= 3.0.0) - mustache (~> 1.0, >= 0.99.4) - rspec (~> 3.0) + rspec-support (3.13.7) rubocop (1.65.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -377,22 +368,22 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.1) + rubocop-ast (1.32.3) parser (>= 3.3.1.0) rubocop-factory_bot (2.26.1) rubocop (~> 1.61) - rubocop-rails (2.26.0) + rubocop-rails (2.26.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.4) + rubocop-rspec (3.0.5) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) rubocop-rspec (~> 3, >= 3.0.1) ruby-progressbar (1.13.0) - ruby-vips (2.2.2) + ruby-vips (2.2.5) ffi (~> 1.12) logger rubyzip (2.3.2) @@ -407,8 +398,9 @@ GEM searchkick (5.3.1) activemodel (>= 6.1) hashie - securerandom (0.3.1) - selectize-rails (0.12.6) + securerandom (0.3.2) + selenium-devtools (0.151.0) + selenium-webdriver (~> 4.2) selenium-webdriver (4.46.0) base64 (~> 0.2) logger (~> 1.4) @@ -417,48 +409,47 @@ GEM websocket (~> 1.0) shoulda-matchers (6.4.0) activesupport (>= 5.2.0) - sidekiq (7.3.8) + sidekiq (7.3.10) base64 - connection_pool (>= 2.3.0) + connection_pool (>= 2.3.0, < 3) logger - rack (>= 2.2.4) - redis-client (>= 0.22.2) + rack (>= 2.2.4, < 3.3) + redis-client (>= 0.23.0, < 1) sidekiq-cron (2.4.0) cronex (>= 0.13.0) fugit (~> 1.8, >= 1.11.1) globalid (>= 1.0.1) sidekiq (>= 6.5.0) - sprockets (4.2.1) + sprockets (4.2.2) concurrent-ruby (~> 1.0) + logger rack (>= 2.2.4, < 4) sprockets-rails (3.5.2) actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - stringio (3.1.1) - strscan (3.1.0) - systemu (2.6.5) - thor (1.3.1) - tilt (2.4.0) - timeout (0.4.1) + stringio (3.1.9) + thor (1.3.2) + tilt (2.8.0) + timeout (0.6.1) trix-rails (2.4.0) rails (> 4.1) + tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode (0.4.4.5) unicode-display_width (2.5.0) uri (1.1.1) - useragent (0.16.10) - uuid (2.3.9) - macaddr (~> 1.0) - webrick (1.8.1) + useragent (0.16.11) + webrick (1.8.2) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.8.2) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.17) + zeitwerk (2.6.18) PLATFORMS aarch64-linux @@ -477,15 +468,15 @@ PLATFORMS DEPENDENCIES active_record_doctor (~> 1.10) - acts-as-taggable-on (~> 11.0.0) - addressable (~> 2.8) + acts-as-taggable-on (~> 13.0) + addressable (~> 2.9) administrate administrate-field-active_storage (~> 0.4.1) - administrate-field-acts_as_taggable administrate-field-jsonb administrate-field-list (~> 0.0.6) aws-sdk-rails (~> 5.0) aws-sdk-ses (~> 1.0) + benchmark bootsnap capybara csv @@ -501,28 +492,28 @@ DEPENDENCIES namae (~> 1.1) pg (~> 1.1) puma (~> 5.0) - pundit (~> 2.2) rack-cors - rails (~> 7.2.1) + rails (~> 8.1.3) roo (~> 2.9) rspec-rails - rspec_api_documentation (~> 6.1) rubocop rubocop-factory_bot rubocop-rails rubocop-rspec rubocop-rspec_rails + sassc-rails searchkick + selenium-devtools selenium-webdriver shoulda-matchers sidekiq (>= 7.2.2, < 8) sidekiq-cron (~> 2.4.0) + sprockets-rails trix-rails tzinfo-data - uuid (~> 2.3) RUBY VERSION - ruby 3.3.4p94 + ruby 3.4.10p104 BUNDLED WITH 2.5.11 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 41bd56d..7dc11fe 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -4,10 +4,8 @@ //= link_tree ../../../vendor/javascript .js //= link administrate-field-jsonb/application.css //= link administrate-field-jsonb/application.js -//= link administrate-field-taggable/application.js -//= link administrate-field-taggable/application.css +//= link acts_as_taggable_field.js //= link administrate-field-active_storage/application.css -//= require selectize //= require trix // application.js // application.css diff --git a/app/assets/javascripts/acts_as_taggable_field.js b/app/assets/javascripts/acts_as_taggable_field.js new file mode 100644 index 0000000..bf7e5cb --- /dev/null +++ b/app/assets/javascripts/acts_as_taggable_field.js @@ -0,0 +1,20 @@ +// Selectize init for ActsAsTaggableField's text input, ported from the +// unmaintained administrate-field-acts_as_taggable gem's application.js. +$(function() { + $(".field-unit--acts-as-taggable-field .field-unit__field > input").each(function(elem) { + var $this = $(this); + var opts = $this.data('tag-options'); + + $this.selectize({ + delimiter: ", ", + persist: false, + options: opts, + create: function(input) { + return { + value: input, + text: input + }; + } + }); + }) +}); diff --git a/app/assets/stylesheets/acts_as_taggable_field.css b/app/assets/stylesheets/acts_as_taggable_field.css new file mode 100644 index 0000000..6867434 --- /dev/null +++ b/app/assets/stylesheets/acts_as_taggable_field.css @@ -0,0 +1,9 @@ +.taggable_field .tag { + text-align: center; + font-size: 0.85em; + margin: 0 3px 3px 0; + padding: 2px 6px; + background: #f2f2f2; + color: #303030; + border: 0 solid #d0d0d0; +} diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb index 40afcd6..cba7fbe 100644 --- a/app/controllers/admin/application_controller.rb +++ b/app/controllers/admin/application_controller.rb @@ -8,8 +8,6 @@ # you're free to overwrite the RESTful controller actions. module Admin class ApplicationController < Administrate::ApplicationController - # include Administrate::Punditize - before_action :authenticate_admin before_action do diff --git a/app/dashboards/mention_dashboard.rb b/app/dashboards/mention_dashboard.rb index b3283c4..abae96a 100644 --- a/app/dashboards/mention_dashboard.rb +++ b/app/dashboards/mention_dashboard.rb @@ -18,7 +18,7 @@ class MentionDashboard < Administrate::BaseDashboard id: Field::Number, created_at: Field::DateTime, updated_at: Field::DateTime, - tags: Field::ActsAsTaggable + tags: ActsAsTaggableField }.freeze # COLLECTION_ATTRIBUTES diff --git a/app/fields/acts_as_taggable_field.rb b/app/fields/acts_as_taggable_field.rb new file mode 100644 index 0000000..ca78488 --- /dev/null +++ b/app/fields/acts_as_taggable_field.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'administrate/field/text' +require 'administrate/engine' + +# In-house replacement for the unmaintained administrate-field-acts_as_taggable gem +# (last released 2021, hard-pins `administrate < 1.0.0`). Behavior is ported as-is +# from that gem's lib/administrate/field/acts_as_taggable.rb. +class ActsAsTaggableField < Administrate::Field::Text + class Engine < ::Rails::Engine + if defined?(Administrate::Engine) + Administrate::Engine.add_javascript 'acts_as_taggable_field' + Administrate::Engine.add_stylesheet 'acts_as_taggable_field' + end + end + + def context + options.fetch(:context, @attribute) + end + + # Administrate::Field::Base#read_value (called from #initialize, before + # #attribute is overridden below has a chance to matter) lazily fetches data via + # `resource.try(attribute)` - and that `attribute` call is polymorphic, so it hits + # our own override below instead of the raw `:tags` attribute key, fetching + # `resource.tag_list` (an array of tag-name strings) instead of `resource.tags` + # (real ActsAsTaggableOn::Tag records). #tags/#delimited/#truncate all expect the + # latter, so this re-derives the same logic using @attribute (the raw ivar) rather + # than the overridden #attribute method. + def read_value(data) + if options.key?(:getter) + return options[:getter].respond_to?(:call) ? options[:getter].call(self) : resource.try(options[:getter]) + end + + data.nil? ? resource.try(@attribute) : data + end + + # acts_as_taggable_on exposes a `_list` virtual attribute + # (e.g. `tag_list` for the `:tags` context) for reading/writing a comma-delimited + # tag string - this field operates on that attribute rather than the raw `tags` + # association. + def attribute + "#{super.to_s.singularize}_list" + end + + def self.permitted_attribute(attr, **_opts) + "#{attr.to_s.singularize}_list" + end + + def tags + data + end + + def name + context.to_s + end + + def delimited + tags.join(', ').to_s + end + + def truncate + delimited[0...truncation_length] + end + + def tag_options + return [] unless defined?(ActsAsTaggableOn::Tag) + + ActsAsTaggableOn::Tag.for_context(context).order(:name).map do |t| + { text: t.name, value: t.name } + end + end +end diff --git a/app/models/concerns/letter_common.rb b/app/models/concerns/letter_common.rb index 8cb701d..cb0ff27 100644 --- a/app/models/concerns/letter_common.rb +++ b/app/models/concerns/letter_common.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -# rubocop:disable Metrics/BlockLength - # Common stuff for indexing module LetterCommon extend ActiveSupport::Concern @@ -9,18 +7,34 @@ module LetterCommon included do attr_accessor :tags - # attr_readonly :content + has_many :mentions, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :entities, -> { distinct }, through: :mentions + + has_many :letter_destinations, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :destinations, -> { distinct }, through: :letter_destinations, source: :entity + + has_many :letter_senders, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :senders, -> { distinct }, through: :letter_senders, source: :entity + + has_many :letter_origins, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :origins, -> { distinct }, through: :letter_origins, source: :entity + + has_many :letter_recipients, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :recipients, -> { distinct }, through: :letter_recipients, source: :entity - # scope :published, lambda { - # includes(:repositories) - # .references(:repositories) - # .where( - # repositories: { - # published: true - # } - # ) - # # .where('letters.date BETWEEN ? AND ?', DateTime.new(1957), DateTime.new(1965, 12).at_end_of_month) - # } + has_many :letter_repositories, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :repositories, -> { distinct }, through: :letter_repositories + + has_many :letter_collections, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :collections, -> { distinct }, through: :letter_collections + + has_many :letter_languages, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy + has_many :languages, -> { distinct }, through: :letter_languages + + belongs_to :letter_file, inverse_of: :letters, optional: true + belongs_to :file_folder, inverse_of: :letters, optional: true + belongs_to :letter_owner, inverse_of: :letters, optional: true + belongs_to :letter_publisher, inverse_of: :letters, optional: true scope :published, -> { where(published: true) } @@ -100,5 +114,3 @@ def volume_title end end end - -# rubocop:enable Metrics/BlockLength diff --git a/app/models/letter.rb b/app/models/letter.rb index f4c780d..6fa0fcb 100644 --- a/app/models/letter.rb +++ b/app/models/letter.rb @@ -8,35 +8,6 @@ class Letter < ApplicationRecord before_destroy :remove_published after_save :reindex_published - has_many :mentions, dependent: :destroy - has_many :entities, -> { distinct }, through: :mentions - - has_many :letter_destinations, dependent: :destroy - has_many :destinations, -> { distinct }, through: :letter_destinations, source: :entity - - has_many :letter_senders, dependent: :destroy - has_many :senders, -> { distinct }, through: :letter_senders, source: :entity - - has_many :letter_origins, dependent: :destroy - has_many :origins, -> { distinct }, through: :letter_origins, source: :entity - - has_many :letter_recipients, dependent: :destroy - has_many :recipients, -> { distinct }, through: :letter_recipients, source: :entity - - has_many :letter_repositories, dependent: :destroy - has_many :repositories, -> { distinct }, through: :letter_repositories - - has_many :letter_collections, dependent: :destroy - has_many :collections, -> { distinct }, through: :letter_collections - - has_many :letter_languages, dependent: :destroy - has_many :languages, -> { distinct }, through: :letter_languages - - belongs_to :letter_file, optional: true - belongs_to :file_folder, optional: true - belongs_to :letter_owner, optional: true - belongs_to :letter_publisher, optional: true - def search_data { id_path: url_path, @@ -51,7 +22,8 @@ def search_data repositories: repositories.map(&:label), languages: languages.map(&:label), published:, - volume: volume.to_s + volume: volume.to_s, + fuck: 'me' } end diff --git a/app/models/published_letter.rb b/app/models/published_letter.rb index 69ec01b..9f1936a 100644 --- a/app/models/published_letter.rb +++ b/app/models/published_letter.rb @@ -6,35 +6,6 @@ class PublishedLetter < ApplicationRecord self.table_name = 'letters' - has_many :mentions, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :entities, -> { distinct }, through: :mentions - - has_many :letter_destinations, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :destinations, -> { distinct }, through: :letter_destinations, source: :entity - - has_many :letter_senders, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :senders, -> { distinct }, through: :letter_senders, source: :entity - - has_many :letter_origins, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :origins, -> { distinct }, through: :letter_origins, source: :entity - - has_many :letter_recipients, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :recipients, -> { distinct }, through: :letter_recipients, source: :entity - - has_many :letter_repositories, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :repositories, -> { distinct }, through: :letter_repositories - - has_many :letter_collections, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :collections, -> { distinct }, through: :letter_collections - - has_many :letter_languages, foreign_key: 'letter_id', inverse_of: :letter, dependent: :destroy - has_many :languages, -> { distinct }, through: :letter_languages - - belongs_to :letter_file, foreign_key: 'letter_id', inverse_of: :letter, optional: true - belongs_to :file_folder, foreign_key: 'letter_id', inverse_of: :letter, optional: true - belongs_to :letter_owner, foreign_key: 'letter_id', inverse_of: :letter, optional: true - belongs_to :letter_publisher, foreign_key: 'letter_id', inverse_of: :letter, optional: true - def self.default_scope where(published: true) end @@ -53,11 +24,20 @@ def search_data repositories: repositories.select(&:published).map(&:label), languages: languages.map(&:label), published:, - volume: volume.to_s + volume: volume.to_s, + other_publishers: } end def should_index? published end + + def other_publishers + return if letter_publisher.nil? + + doc = Nokogiri::HTML(letter_publisher.label) + text = doc.css('i').map(&:text) + text ? text.map(&:strip) : [letter_publisher.label] + end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb deleted file mode 100644 index d91c019..0000000 --- a/app/policies/application_policy.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -class ApplicationPolicy - attr_reader :user, :record - - def initialize(user, record) - @user = user - @record = record - end - - def index? - true - end - - def show? - true - end - - def create? - true - end - - def new? - true - end - - def update? - true - end - - def edit? - true - end - - def destroy? - true - end - - class Scope - def initialize(user, scope) - @user = user - @scope = scope - end - - def resolve - raise NotImplementedError, "You must define #resolve in #{self.class}" - end - - private - - attr_reader :user, :scope - end -end diff --git a/app/views/admin/media/show.html.erb b/app/views/admin/media/show.html.erb index 17a3432..a2435a1 100644 --- a/app/views/admin/media/show.html.erb +++ b/app/views/admin/media/show.html.erb @@ -25,12 +25,13 @@ as well as a link to its edit page. t("administrate.actions.edit_resource", name: page.page_title), [:edit, namespace, page.resource], class: "button", - ) if accessible_action?(:edit) && accessible_action?(:edit, page.resource) %> + ) if accessible_action?(page.resource, :edit) %>
- <%= page.resource.alt_text %> + <% media_url = page.resource.image.attached? ? url_for(page.resource.image) : page.resource.link %> + <%= page.resource.alt_text %>
<%= page.resource.caption %>
<% page.attributes.each do |title, attributes| %> diff --git a/app/views/admin/mentions/_form.html.erb b/app/views/admin/mentions/_form.html.erb index 5d798ea..3ee5e47 100644 --- a/app/views/admin/mentions/_form.html.erb +++ b/app/views/admin/mentions/_form.html.erb @@ -33,10 +33,12 @@ and renders all form fields for a resource's editable attributes. <% end %> - <% page.attributes(controller.action_name).each do |attribute| -%> -
- <%= render_field attribute, f: f %> -
+ <% page.attributes(controller.action_name).each do |title, attributes| -%> + <% attributes.each do |attribute| %> +
+ <%= render_field attribute, f: f %> +
+ <% end -%> <% end -%>
diff --git a/app/views/admin/mentions/edit.html.erb b/app/views/admin/mentions/edit.html.erb index 62e2be2..f443901 100644 --- a/app/views/admin/mentions/edit.html.erb +++ b/app/views/admin/mentions/edit.html.erb @@ -34,7 +34,7 @@ It displays a header, and renders the `_form` partial to do the heavy lifting. t("administrate.actions.show_resource", name: page.page_title), [namespace, page.resource], class: "button", - ) if accessible_action?(:show) && accessible_action?(:show, page.resource) %> + ) if accessible_action?(page.resource, :show) %>
diff --git a/app/views/fields/acts_as_taggable_field/_form.html.erb b/app/views/fields/acts_as_taggable_field/_form.html.erb new file mode 100644 index 0000000..f84fb00 --- /dev/null +++ b/app/views/fields/acts_as_taggable_field/_form.html.erb @@ -0,0 +1,6 @@ +
+ <%= f.label field.attribute %> +
+
+ <%= f.text_field field.attribute, value: field.delimited, data: { tag_options: field.tag_options } %> +
diff --git a/app/views/fields/acts_as_taggable_field/_index.html.erb b/app/views/fields/acts_as_taggable_field/_index.html.erb new file mode 100644 index 0000000..d683ccc --- /dev/null +++ b/app/views/fields/acts_as_taggable_field/_index.html.erb @@ -0,0 +1 @@ +<%= field.truncate %> diff --git a/app/views/fields/acts_as_taggable_field/_show.html.erb b/app/views/fields/acts_as_taggable_field/_show.html.erb new file mode 100644 index 0000000..0651443 --- /dev/null +++ b/app/views/fields/acts_as_taggable_field/_show.html.erb @@ -0,0 +1,5 @@ +
+ <% field.tags.each do |tag| %> + <%= tag.name -%> + <% end %> +
diff --git a/app/workers/resave_all_letters_worker.rb b/app/workers/resave_all_letters_worker.rb index a84ef58..5d95750 100644 --- a/app/workers/resave_all_letters_worker.rb +++ b/app/workers/resave_all_letters_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ResaveAllLettersWorker include Sidekiq::Job diff --git a/bin/dev b/bin/dev new file mode 100644 index 0000000..5f91c20 --- /dev/null +++ b/bin/dev @@ -0,0 +1,2 @@ +#!/usr/bin/env ruby +exec "./bin/rails", "server", *ARGV diff --git a/bin/rubocop b/bin/rubocop new file mode 100644 index 0000000..5a20504 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +# Explicit RuboCop config increases performance slightly while avoiding config confusion. +ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) + +load Gem.bin_path("rubocop", "rubocop") diff --git a/config/importmap.rb b/config/importmap.rb index 7fdb198..7c2f1f5 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Pin npm packages by running ./bin/importmap pin 'application' pin 'moment' # @2.30.1 -pin "js-datepicker" # @5.18.3 +pin 'js-datepicker' # @5.18.3 diff --git a/config/initializers/new_framework_defaults_8_1.rb b/config/initializers/new_framework_defaults_8_1.rb new file mode 100644 index 0000000..8f20895 --- /dev/null +++ b/config/initializers/new_framework_defaults_8_1.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Be sure to restart your server when you modify this file. +# +# This file eases your Rails 8.1 framework defaults upgrade. +# +# Uncomment each configuration one by one to switch to the new default. +# Once your application is ready to run with all new defaults, you can remove +# this file and set the `config.load_defaults` to `8.1`. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. +# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html + +### +# Skips escaping HTML entities and line separators. When set to `false`, the +# JSON renderer no longer escapes these to improve performance. +# +# Example: +# class PostsController < ApplicationController +# def index +# render json: { key: "\u2028\u2029<>&" } +# end +# end +# +# Renders `{"key":"\u2028\u2029\u003c\u003e\u0026"}` with the previous default, but `{"key":"

<>&"}` with the config +# set to `false`. +# +# Applications that want to keep the escaping behavior can set the config to `true`. +#++ +# Rails.configuration.action_controller.escape_json_responses = false + +### +# Skips escaping LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) in JSON. +# +# Historically these characters were not valid inside JavaScript literal strings but that changed in ECMAScript 2019. +# As such it's no longer a concern in modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset. +#++ +# Rails.configuration.active_support.escape_js_separators_in_json = false + +### +# Raises an error when order dependent finder methods (e.g. `#first`, `#second`) are called without `order` values +# on the relation, and the model does not have any order columns (`implicit_order_column`, `query_constraints`, or +# `primary_key`) to fall back on. +# +# The current behavior of not raising an error has been deprecated, and this configuration option will be removed in +# Rails 8.2. +#++ +# Rails.configuration.active_record.raise_on_missing_required_finder_order_columns = true + +### +# Controls how Rails handles path relative URL redirects. +# When set to `:raise`, Rails will raise an `ActionController::Redirecting::UnsafeRedirectError` +# for relative URLs without a leading slash, which can help prevent open redirect vulnerabilities. +# +# Example: +# redirect_to "example.com" # Raises UnsafeRedirectError +# redirect_to "@attacker.com" # Raises UnsafeRedirectError +# redirect_to "/safe/path" # Works correctly +# +# Applications that want to allow these redirects can set the config to `:log` (previous default) +# to only log warnings, or `:notify` to send ActiveSupport notifications. +#++ +# Rails.configuration.action_controller.action_on_path_relative_redirect = :raise + +### +# Use a Ruby parser to track dependencies between Action View templates +#++ +# Rails.configuration.action_view.render_tracker = :ruby + +### +# When enabled, hidden inputs generated by `form_tag`, `token_tag`, `method_tag`, and the hidden parameter fields +# included in `button_to` forms will omit the `autocomplete="off"` attribute. +# +# Applications that want to keep generating the `autocomplete` attribute for those tags can set it to `false`. +#++ +# Rails.configuration.action_view.remove_hidden_field_autocomplete = true diff --git a/config/initializers/rspec_api_documention.rb b/config/initializers/rspec_api_documention.rb deleted file mode 100644 index da707a1..0000000 --- a/config/initializers/rspec_api_documention.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -# Monkey patch to properly display json :( -# https://github.com/zipmark/rspec_api_documentation/issues/456 -module RspecApiDocumentation - class RackTestClient < ClientBase - def response_body - if last_response.headers['Content-Type'].include?('json') - last_response.body.encode('utf-8') - else - '[binary data]' - end - end - end -end diff --git a/spec/acceptance_helper.rb b/spec/acceptance_helper.rb deleted file mode 100644 index 53dba02..0000000 --- a/spec/acceptance_helper.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'rspec_api_documentation/dsl' - -RspecApiDocumentation.configure do |config| - config.format = %i[html markdown] - config.template_path = Rails.root.join('templates', 'rspec_api_documentation') - config.keep_source_order = true - config.docs_dir = Rails.public_path.join('docs') - config.api_name = 'Beckett Data API Documentation' -end diff --git a/spec/fields/acts_as_taggable_field_spec.rb b/spec/fields/acts_as_taggable_field_spec.rb new file mode 100644 index 0000000..d82b9bd --- /dev/null +++ b/spec/fields/acts_as_taggable_field_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'administrate/field/text' + +RSpec.describe ActsAsTaggableField do + describe '#attribute' do + it 'singularizes the underlying attribute and appends _list' do + field = described_class.new(:tags, [], nil) + expect(field.attribute).to eq('tag_list') + end + end + + describe '.permitted_attribute' do + it 'singularizes the attribute and appends _list' do + expect(described_class.permitted_attribute(:tags)).to eq('tag_list') + end + end + + describe '#tags' do + it 'returns the raw data' do + field = described_class.new(:tags, %w[a b], nil) + expect(field.tags).to eq(%w[a b]) + end + + it 'fetches real Tag records from the resource when constructed the way Administrate ' \ + 'actually builds fields (data: nil, resource: given), not tag_list name strings' do + # Administrate::Field::Base#read_value calls `resource.try(attribute)` when data is + # nil - and that `attribute` call is polymorphic, landing on this class's own + # #attribute override (returns "tag_list") rather than the raw :tags attribute this + # field was constructed with. A prior version of #read_value used that overridden + # #attribute directly, so this fetched mention.tag_list (tag-name strings) instead of + # mention.tags (real Tag records), and _show.html.erb's `tag.name` raised + # NoMethodError on a String. Only reproducible by exercising the real construction + # path (data: nil) - constructing with data already populated skips read_value + # entirely, which is why this went undetected until manual browser verification. + mention = create(:mention, tag_list: 'battle, correspondence') + field = described_class.new(:tags, nil, nil, resource: mention) + + expect(field.tags).to all(be_a(ActsAsTaggableOn::Tag)) + expect(field.tags.map(&:name)).to contain_exactly('battle', 'correspondence') + end + end + + describe '#delimited' do + it 'joins tag names with a comma and space' do + mention = create(:mention, tag_list: 'foo, bar') + field = described_class.new(:tags, mention.tags, nil) + + expect(field.delimited).to eq('foo, bar') + end + + it 'returns an empty string when there are no tags' do + field = described_class.new(:tags, [], nil) + expect(field.delimited).to eq('') + end + end + + describe '#truncate' do + it 'truncates the delimited tag list to the default length' do + mention = create(:mention, tag_list: 'a' * 60) + field = described_class.new(:tags, mention.tags, nil) + + expect(field.truncate.length).to eq(50) + end + end + + describe '#tag_options' do + it 'lists tags used in the tags context, sorted by name' do + create(:mention, tag_list: 'zebra, apple') + field = described_class.new(:tags, [], nil) + + expect(field.tag_options).to eq( + [{ text: 'apple', value: 'apple' }, { text: 'zebra', value: 'zebra' }] + ) + end + end +end diff --git a/spec/jobs/import_data_job_spec.rb b/spec/jobs/import_data_job_spec.rb deleted file mode 100644 index b858132..0000000 --- a/spec/jobs/import_data_job_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ImportDataJob do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/jobs/load_big_sam_job_spec.rb b/spec/jobs/load_big_sam_job_spec.rb index 4271655..aaf26b0 100644 --- a/spec/jobs/load_big_sam_job_spec.rb +++ b/spec/jobs/load_big_sam_job_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' require 'fileutils' diff --git a/spec/models/big_sam_spec.rb b/spec/models/big_sam_spec.rb deleted file mode 100644 index 8cb2214..0000000 --- a/spec/models/big_sam_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BigSam do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb deleted file mode 100644 index c6bfd2c..0000000 --- a/spec/models/collection_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Collection do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/event_type_spec.rb b/spec/models/event_type_spec.rb deleted file mode 100644 index 042fcf6..0000000 --- a/spec/models/event_type_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe EventType do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/file_folder_spec.rb b/spec/models/file_folder_spec.rb deleted file mode 100644 index 751e941..0000000 --- a/spec/models/file_folder_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FileFolder do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_collection_spec.rb b/spec/models/letter_collection_spec.rb deleted file mode 100644 index 33ff10f..0000000 --- a/spec/models/letter_collection_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterCollection do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_destination_spec.rb b/spec/models/letter_destination_spec.rb deleted file mode 100644 index 61fd41f..0000000 --- a/spec/models/letter_destination_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterDestination do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_file_spec.rb b/spec/models/letter_file_spec.rb deleted file mode 100644 index 5db75d9..0000000 --- a/spec/models/letter_file_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterFile do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_origin_spec.rb b/spec/models/letter_origin_spec.rb deleted file mode 100644 index 69658c6..0000000 --- a/spec/models/letter_origin_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterOrigin do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_owner_spec.rb b/spec/models/letter_owner_spec.rb deleted file mode 100644 index bbab35d..0000000 --- a/spec/models/letter_owner_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterOwner do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_publisher_spec.rb b/spec/models/letter_publisher_spec.rb deleted file mode 100644 index b136a6c..0000000 --- a/spec/models/letter_publisher_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterPublisher do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_recipient_spec.rb b/spec/models/letter_recipient_spec.rb deleted file mode 100644 index 356335d..0000000 --- a/spec/models/letter_recipient_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterRecipient do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/letter_sender_spec.rb b/spec/models/letter_sender_spec.rb deleted file mode 100644 index 29a3ed8..0000000 --- a/spec/models/letter_sender_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LetterSender do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/mention_spec.rb b/spec/models/mention_spec.rb deleted file mode 100644 index a302cff..0000000 --- a/spec/models/mention_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Mention do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/published_letter_spec.rb b/spec/models/published_letter_spec.rb index 6fc8e53..80176cc 100644 --- a/spec/models/published_letter_spec.rb +++ b/spec/models/published_letter_spec.rb @@ -42,4 +42,13 @@ expect(published_letter.repositories.count).to eq(2) expect(published_letter.search_data[:repositories].count).to eq(1) end + + it 'represents previous publisher' do + publisher = create(:letter_publisher, + label: 'Alan, "Letters" Endgame , Voice Ed. Maurice. (1998) 37.') + letter = create(:published_letter, letter_publisher: publisher) + published_letter = described_class.find(letter.id) + expect(published_letter.search_data[:other_publishers]).to(include('Endgame')) + expect(published_letter.search_data[:other_publishers]).to(include('Voice')) + end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index a9bc56b..4c3b332 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -49,7 +49,7 @@ # ActiveStorage::Current is a CurrentAttributes subclass — its values are # reset by ActiveSupport::Executor after each inline job. Setting url_options # in before(:each) ensures it's present whenever a spec calls .url. - config.before { ActiveStorage::Current.url_options = { host: ENV['RAILS_HOST'] } } + config.before { ActiveStorage::Current.url_options = { host: ENV.fetch('RAILS_HOST', nil) } } # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_paths = [Rails.root.join('spec', 'fixtures'), Rails.root.join('spec', 'fixtures', 'files')] diff --git a/spec/requests/admin/about_pages_spec.rb b/spec/requests/admin/about_pages_spec.rb index 716a164..d3159e9 100644 --- a/spec/requests/admin/about_pages_spec.rb +++ b/spec/requests/admin/about_pages_spec.rb @@ -46,10 +46,10 @@ expect(response.body).to include(%(href="#{new_admin_about_page_path}")) end - it 'still renders the "destroy" link on the show page' do + it 'still renders the "destroy" button on the show page' do about_page = create(:about_page) get admin_about_page_path(about_page), headers: admin_auth_headers - expect(response.body).to include(%(href="#{admin_about_page_path(about_page)}")) + expect(response.body).to include(%(action="#{admin_about_page_path(about_page)}")) .and include('button--danger') end end diff --git a/spec/requests/admin/media_spec.rb b/spec/requests/admin/media_spec.rb index 164afbd..96a15c7 100644 --- a/spec/requests/admin/media_spec.rb +++ b/spec/requests/admin/media_spec.rb @@ -18,13 +18,6 @@ describe 'GET show' do it 'renders successfully when authenticated' do - pending( - 'known bug: admin/media/show.html.erb:28 calls accessible_action?(:edit) with one ' \ - 'argument before the correct two-argument call - Administrate::ApplicationHelper#' \ - 'accessible_action? requires (target, action_name), so this raises ArgumentError ' \ - "before the &&'d correct call, or page.resource.url (line 33, Medium has no #url " \ - 'method), is ever reached' - ) medium = create(:medium) get admin_medium_path(medium), headers: admin_auth_headers expect(response).to have_http_status(:ok) diff --git a/spec/requests/admin/mentions_spec.rb b/spec/requests/admin/mentions_spec.rb index d071911..10363c3 100644 --- a/spec/requests/admin/mentions_spec.rb +++ b/spec/requests/admin/mentions_spec.rb @@ -14,6 +14,16 @@ get admin_mentions_path, headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + # Regression test: ActsAsTaggableField's #tags previously blew up on a real tagged + # mention outside of a bare smoke test, since the untagged factory default never + # exercised the field's actual data-fetching path (see acts_as_taggable_field_spec.rb). + it 'renders the tags of a tagged mention' do + create(:mention, tag_list: 'battle, correspondence') + get admin_mentions_path, headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('battle').and include('correspondence') + end end describe 'GET show' do @@ -22,16 +32,17 @@ get admin_mention_path(mention), headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + it 'renders the tags of a tagged mention' do + mention = create(:mention, tag_list: 'battle, correspondence') + get admin_mention_path(mention), headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('battle').and include('correspondence') + end end describe 'GET new' do it 'renders successfully when authenticated' do - pending( - 'known bug: admin/mentions/_form.html.erb:36 iterates page.attributes(...) as a ' \ - 'flat list of fields, but it actually yields [title, attributes] pairs (see ' \ - 'admin/letters/_form.html.erb for the correct nested form), so `attribute.html_class` ' \ - 'raises NoMethodError on the Array' - ) get new_admin_mention_path, headers: admin_auth_headers expect(response).to have_http_status(:ok) end @@ -39,15 +50,16 @@ describe 'GET edit' do it 'renders successfully when authenticated' do - pending( - 'known bug: admin/mentions/edit.html.erb:37 calls ' \ - 'accessible_action?(:show) with one argument before the correct two-argument call - ' \ - 'Administrate::ApplicationHelper#accessible_action? requires (target, action_name), so ' \ - 'this raises ArgumentError before the &&\'d correct call is ever reached' - ) mention = create(:mention) get edit_admin_mention_path(mention), headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + it 'pre-populates the tag list input of a tagged mention' do + mention = create(:mention, tag_list: 'battle, correspondence') + get edit_admin_mention_path(mention), headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('value="battle, correspondence"') + end end end diff --git a/spec/requests/repositories_spec.rb b/spec/requests/repositories_spec.rb index 4f3cd24..a3db5f5 100644 --- a/spec/requests/repositories_spec.rb +++ b/spec/requests/repositories_spec.rb @@ -2,128 +2,58 @@ require 'rails_helper' -# This spec was generated by rspec-rails when you ran the scaffold generator. -# It demonstrates how one might use RSpec to test the controller code that -# was generated by Rails when you ran the scaffold generator. -# -# It assumes that the implementation code is generated by the rails scaffold -# generator. If you are using any extension libraries to generate different -# controller code, this generated spec may or may not pass. -# -# It only uses APIs available in rails and/or rspec-rails. There are a number -# of tools you can use to make these specs even more expressive, but we're -# sticking to rails and rspec-rails APIs to keep things simple and stable. - RSpec.describe '/repositories' do - # This should return the minimal set of attributes required to create a valid - # Repository. As you add validations to Repository, be sure to - # adjust the attributes here as well. - let(:valid_attributes) { - skip('Add a hash of attributes valid for your model') - } - - let(:invalid_attributes) { - skip('Add a hash of attributes invalid for your model') - } - - # This should return the minimal set of values that should be in the headers - # in order to pass any filters (e.g. authentication) defined in - # RepositoriesController, or in your router and rack - # middleware. Be sure to keep this updated too. - let(:valid_headers) { - {} - } - describe 'GET /index' do - it 'renders a successful response' do - Repository.create! valid_attributes - get repositories_url, headers: valid_headers, as: :json + it 'renders a successful response with all repositories' do + create_list(:repository, 3) + get repositories_url, as: :json expect(response).to be_successful + expect(json.count).to eq(3) end end describe 'GET /show' do - it 'renders a successful response' do - repository = Repository.create! valid_attributes + it 'renders the requested repository' do + repository = create(:repository) get repository_url(repository), as: :json expect(response).to be_successful + expect(json[:id]).to eq(repository.id) + expect(json[:label]).to eq(repository.label) end - end - - describe 'POST /create' do - context 'with valid parameters' do - it 'creates a new Repository' do - expect { - post repositories_url, - params: { repository: valid_attributes }, headers: valid_headers, as: :json - }.to change(Repository, :count).by(1) - end - it 'renders a JSON response with the new repository' do - post repositories_url, - params: { repository: valid_attributes }, headers: valid_headers, as: :json - expect(response).to have_http_status(:created) - expect(response.content_type).to match(a_string_including('application/json')) - end + it 'renders a not_found response for an unknown id' do + get repository_url(SecureRandom.uuid), as: :json + expect(response).to have_http_status(:not_found) end + end - context 'with invalid parameters' do - it 'does not create a new Repository' do - expect { - post repositories_url, - params: { repository: invalid_attributes }, as: :json - }.not_to change(Repository, :count) - end - - it 'renders a JSON response with errors for the new repository' do - post repositories_url, - params: { repository: invalid_attributes }, headers: valid_headers, as: :json - expect(response).to have_http_status(:unprocessable_entity) - expect(response.content_type).to match(a_string_including('application/json')) - end + # RepositoriesController only overrides index/show - create/update/destroy fall + # through to ApplicationController's defaults, which all `head :not_implemented`. + describe 'POST /create' do + it 'does not create a new Repository' do + expect { + post repositories_url, params: { repository: { label: 'New Repository' } }, as: :json + }.not_to change(Repository, :count) + expect(response).to have_http_status(:not_implemented) end end describe 'PATCH /update' do - context 'with valid parameters' do - let(:new_attributes) { - skip('Add a hash of attributes valid for your model') - } - - it 'updates the requested repository' do - repository = Repository.create! valid_attributes - patch repository_url(repository), - params: { repository: new_attributes }, headers: valid_headers, as: :json - repository.reload - skip('Add assertions for updated state') - end - - it 'renders a JSON response with the repository' do - repository = Repository.create! valid_attributes - patch repository_url(repository), - params: { repository: new_attributes }, headers: valid_headers, as: :json - expect(response).to have_http_status(:ok) - expect(response.content_type).to match(a_string_including('application/json')) - end - end - - context 'with invalid parameters' do - it 'renders a JSON response with errors for the repository' do - repository = Repository.create! valid_attributes - patch repository_url(repository), - params: { repository: invalid_attributes }, headers: valid_headers, as: :json - expect(response).to have_http_status(:unprocessable_entity) - expect(response.content_type).to match(a_string_including('application/json')) - end + it 'does not update the requested repository' do + repository = create(:repository, label: 'Original') + patch repository_url(repository), params: { repository: { label: 'Changed' } }, as: :json + expect(response).to have_http_status(:not_implemented) + expect(repository.reload.label).to eq('Original') end end describe 'DELETE /destroy' do - it 'destroys the requested repository' do - repository = Repository.create! valid_attributes + it 'does not destroy the requested repository' do + repository = create(:repository) expect { - delete repository_url(repository), headers: valid_headers, as: :json - }.to change(Repository, :count).by(-1) + delete repository_url(repository), as: :json + }.not_to change(Repository, :count) + expect(response).to have_http_status(:not_implemented) end end end diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index dfddde6..0346da3 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -24,5 +24,16 @@ config.before(:each, :js, type: :system) do driven_by Capybara.javascript_driver + + # Admin::ApplicationController gates every admin route behind HTTP Basic Auth, and + # this app has no session-based login to drive instead. Visiting with credentials + # embedded in the URL (http://user:pass@host/path) used to work, but Administrate + # 1.0 bundles Turbo, which calls history.replaceState on every page load - Chrome + # rejects replaceState targets that carry userinfo, and since Administrate's JS is + # one bundled IIFE, that uncaught exception aborts everything after it, including + # selectize's own setup. Real admin users never hit this (their location.href never + # carries credentials - Chrome only uses them for the auth handshake). Registering + # credentials via CDP instead keeps the visited URL clean and sidesteps it entirely. + Capybara.current_session.driver.browser.register(username: 'test', password: 'test') end end diff --git a/spec/system/admin/letters_spec.rb b/spec/system/admin/letters_spec.rb index 03b77fd..1b865bb 100644 --- a/spec/system/admin/letters_spec.rb +++ b/spec/system/admin/letters_spec.rb @@ -9,11 +9,6 @@ # break (jquery-ujs -> Turbo/Stimulus, changed asset bundling in 1.0) - and the only # way to actually verify it is a real browser, since no request spec executes JS. RSpec.describe 'Admin::Letters entity picker', :js do - def visit_with_basic_auth(path) - server = Capybara.current_session.server - visit "http://test:test@#{server.host}:#{server.port}#{path}" - end - def selectize "jQuery('.field-unit--has-many-through-field select')[0].selectize" end @@ -21,7 +16,7 @@ def selectize it 'initializes jQuery and the selectize widget on the entities field' do letter = create(:letter) - visit_with_basic_auth(edit_admin_letter_path(letter)) + visit edit_admin_letter_path(letter) expect(page.execute_script('return window.jQuery !== undefined')).to be true expect(page).to have_css('.selectize-control') @@ -33,7 +28,7 @@ def selectize entity = create(:person_entity, label: 'Zzz System Spec Findable Entity') Entity.reindex - visit_with_basic_auth(edit_admin_letter_path(letter)) + visit edit_admin_letter_path(letter) expect(page).to have_css('.selectize-control') page.execute_script("#{selectize}.addItem('#{entity.id}')") @@ -49,7 +44,7 @@ def selectize letter.save! Entity.reindex - visit_with_basic_auth(edit_admin_letter_path(letter)) + visit edit_admin_letter_path(letter) expect(page).to have_css(".item[data-value='#{entity.id}']") find(".item[data-value='#{entity.id}']").click @@ -68,7 +63,7 @@ def selectize letter.save! Entity.reindex - visit_with_basic_auth(edit_admin_letter_path(letter)) + visit edit_admin_letter_path(letter) expect(page).to have_css(".item[data-value='#{entity.id}']") find(".item[data-value='#{entity.id}']").click diff --git a/templates/rspec_api_documentation/markdow_example.mustache b/templates/rspec_api_documentation/markdow_example.mustache deleted file mode 100644 index 16263d0..0000000 --- a/templates/rspec_api_documentation/markdow_example.mustache +++ /dev/null @@ -1,85 +0,0 @@ -# {{ resource_name }} API -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} - -## {{ description }} - -### {{ http_method }} {{ route }} -{{# explanation }} - -{{ explanation }} -{{/ explanation }} -{{# has_parameters? }} - -### Parameters - -| Name | Description | Required | Scope | Default | -|------|-------------|----------|-------|---------| -{{# parameters }} -| {{ name }} | {{ description }} | {{ required }} | {{ scope }} | | {{ default }} -{{/ parameters }} - -{{/ has_parameters? }} -{{# has_response_fields? }} - -### Response Fields - -| Name | Description | Scope | -|------|-------------|-------| -{{# response_fields }} -| {{ name }} | {{ description }} | {{ scope }} | -{{/ response_fields }} - -{{/ has_response_fields? }} -{{# requests }} -### Request - -#### Headers - -
{{ request_headers_text }}
- -#### Route - -
{{ request_method }} {{ request_path }}
-{{# request_query_parameters_text }} - -#### Query Parameters - -
{{ request_query_parameters_text }}
-{{/ request_query_parameters_text }} -{{# request_body }} - -#### Body - -
{{{ request_body }}}
-{{/ request_body }} -{{# curl }} - -#### cURL - -
{{ curl }}
-{{/ curl }} - -{{# response_status }} -### Response - -#### Headers - -
{{ response_headers_text }}
- -#### Status - -
{{ response_status }} {{ response_status_text}}
- -{{# response_body }} -#### Body - -~~~ -{{{ response_body }}} -~~~ - -{{/ response_body }} -{{/ response_status }} -{{/ requests }} \ No newline at end of file diff --git a/templates/rspec_api_documentation/rspec_api_documentation/api_blueprint_index.mustache b/templates/rspec_api_documentation/rspec_api_documentation/api_blueprint_index.mustache deleted file mode 100644 index 865f24a..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/api_blueprint_index.mustache +++ /dev/null @@ -1,80 +0,0 @@ -FORMAT: 1A -# {{ api_name }} -{{# sections }} - -# Group {{ resource_name }} -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} -{{# description }} - -{{ description }} -{{/ description }} -{{# routes }} - -## {{ route_name }} [{{ route }}] -{{# description }} - -description: {{ description }} -{{/ description }} -{{# explanation }} - -explanation: {{ explanation }} -{{/ explanation }} -{{# has_parameters? }} - -+ Parameters -{{# parameters }} - + {{ name }}{{# example }}: {{ example }}{{/ example }}{{# properties_description }} ({{ properties_description }}){{/ properties_description }}{{# description }} - {{ description }}{{/ description }} -{{/ parameters }} -{{/ has_parameters? }} -{{# has_attributes? }} - -+ Attributes (object) -{{# attributes }} - + {{ name }}{{# example }}: {{ example }}{{/ example }}{{# properties_description }} ({{ properties_description }}){{/ properties_description }}{{# description }} - {{ description }}{{/ description }} -{{/ attributes }} -{{/ has_attributes? }} -{{# http_methods }} - -### {{ description }} [{{ http_method }}] -{{# examples }} -{{# requests }} -{{# has_request? }} - -+ Request {{ description }}{{# request_content_type }} ({{ request_content_type }}){{/ request_content_type }} -{{/ has_request? }} -{{# request_headers_text }} - - + Headers - - {{{ request_headers_text }}} -{{/ request_headers_text }} -{{# request_body }} - - + Body - - {{{ request_body }}} -{{/ request_body }} -{{# has_response? }} - -+ Response {{ response_status }} ({{ response_content_type }}) -{{/ has_response? }} -{{# response_headers_text }} - - + Headers - - {{{ response_headers_text }}} -{{/ response_headers_text }} -{{# response_body }} - - + Body - - {{{ response_body }}} -{{/ response_body }} -{{/ requests }} -{{/ examples }} -{{/ http_methods }} -{{/ routes }} -{{/ sections }} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/html_example.mustache b/templates/rspec_api_documentation/rspec_api_documentation/html_example.mustache deleted file mode 100644 index 47474e0..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/html_example.mustache +++ /dev/null @@ -1,140 +0,0 @@ - - - - {{resource_name}} API - - - - -
-

{{resource_name}} API

- {{# resource_explanation }} - -

{{{ resource_explanation }}}

- {{/ resource_explanation }} - -
-

{{ description }}

-

{{ http_method }} {{ route }}

- {{# explanation }} -

- {{{ explanation }}} -

- {{/ explanation }} - - {{# has_parameters? }} -

Parameters

- - - - - - - - - - {{# parameters }} - - - {{# scope }} - {{ scope }}[{{ name }}] - {{/ scope }} - {{^ scope }} - {{ name }} - {{/ scope }} - - - - - {{/ parameters }} - -
NameDescriptionDefault
- {{ description }} - - {{ default }} -
- {{/ has_parameters? }} - - {{# has_response_fields? }} -

Response Fields

- - - - - - - - - - - {{# response_fields }} - - - - - - - {{/ response_fields }} - -
NameDefaultDescriptionNot Null
- {{# scope }} - {{ scope }}[{{ name }}] - {{/ scope }} - {{^ scope }} - {{ name }} - {{/ scope }} - - {{ default }} - - {{ description }} - - {{ not_null }} -
- {{/ has_response_fields? }} - - {{# requests }} -

Request

- - {{# request_headers_text }} -

Headers

-
{{ request_headers_text }}
- {{/ request_headers_text }} - -

Route

-
{{ request_method }} {{ request_path }}
- - {{# request_query_parameters_text }} -

Query Parameters

-
{{ request_query_parameters_text }}
- {{/ request_query_parameters_text }} - - {{# request_body }} -

Body

-
{{{ request_body }}}
- {{/ request_body }} - - {{# curl }} -

cURL

-
{{ curl }}
- {{/ curl }} - - {{# response_status }} -

Response

- {{# response_headers_text }} -

Headers

-
{{ response_headers_text }}
- {{/ response_headers_text }} -

Status

-
{{ response_status }} {{ response_status_text}}
- {{# response_body }} -

Body

-
{{ response_body }}
- {{/ response_body }} - {{/ response_status }} - {{/ requests }} -
-
- - diff --git a/templates/rspec_api_documentation/rspec_api_documentation/html_index.mustache b/templates/rspec_api_documentation/rspec_api_documentation/html_index.mustache deleted file mode 100644 index aaedde2..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/html_index.mustache +++ /dev/null @@ -1,33 +0,0 @@ - - - - {{ api_name }} - - - - -
-

{{ api_name }}

- {{{ api_explanation }}} - {{# sections }} -
-

{{ resource_name }}

- {{# resource_explanation }} - -

{{{ resource_explanation }}}

- {{/ resource_explanation }} - - -
- {{/ sections }} -
- - diff --git a/templates/rspec_api_documentation/rspec_api_documentation/markdown_example.mustache b/templates/rspec_api_documentation/rspec_api_documentation/markdown_example.mustache deleted file mode 100644 index 474ab56..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/markdown_example.mustache +++ /dev/null @@ -1,85 +0,0 @@ -# {{ resource_name }} API -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} - -## {{ description }} - -### {{ http_method }} {{ route }} -{{# explanation }} - -{{ explanation }} -{{/ explanation }} -{{# has_parameters? }} - -### Parameters - -| Name | Description | Required | Default | -|------|-------------|----------|---------| -{{# parameters }} -| {{ name }} | {{ description }} | {{ required }} | {{ default }} -{{/ parameters }} - -{{/ has_parameters? }} -{{# has_response_fields? }} - -### Response Fields - -| Name | Default | Description | Not Null | -|------|---------|-------------|----------| -{{# response_fields }} -| {{ name }} | {{ default }} | {{ description }} | {{ not_null }} | -{{/ response_fields }} - -{{/ has_response_fields? }} -{{# requests }} -### Request - -#### Headers - -
{{ request_headers_text }}
- -#### Route - -
{{ request_method }} {{ request_path }}
-{{# request_query_parameters_text }} - -#### Query Parameters - -
{{ request_query_parameters_text }}
-{{/ request_query_parameters_text }} -{{# request_body }} - -#### Body - -
{{{ request_body }}}
-{{/ request_body }} -{{# curl }} - -#### cURL - -
{{ curl }}
-{{/ curl }} - -{{# response_status }} -### Response - -#### Headers - -
{{ response_headers_text }}
- -#### Status - -
{{ response_status }} {{ response_status_text}}
- -{{# response_body }} -#### Body - -~~~ -{{{ response_body }}} -~~~ - -{{/ response_body }} -{{/ response_status }} -{{/ requests }} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/markdown_index.mustache b/templates/rspec_api_documentation/rspec_api_documentation/markdown_index.mustache deleted file mode 100644 index c88754d..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/markdown_index.mustache +++ /dev/null @@ -1,15 +0,0 @@ -# {{ api_name }} -{{{ api_explanation }}} - -{{# sections }} -## {{ resource_name }} -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} - -{{# examples }} -* [{{ description }}]({{ dirname }}/{{ filename }}) -{{/ examples }} - -{{/ sections }} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/slate_example.mustache b/templates/rspec_api_documentation/rspec_api_documentation/slate_example.mustache deleted file mode 100644 index 01fafb9..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/slate_example.mustache +++ /dev/null @@ -1,84 +0,0 @@ -## {{ description }} - -{{# explanation }} -{{{ explanation }}} -{{/ explanation }} - -### Request - -#### Endpoint - -{{# requests}} -```plaintext -{{ request_method }} {{ request_path }} -{{ request_headers_text }} -``` -{{/ requests}} - -`{{ http_method }} {{ route }}` - -#### Parameters - -{{# requests}} -{{# request_query_parameters_text }} - -```json -{{ request_query_parameters_text }} -``` -{{/ request_query_parameters_text }} -{{# request_body }} - -```json -{{{ request_body }}} -``` -{{/ request_body }} - -{{# has_parameters? }} - -| Name | Description | -|:-----|:------------| -{{# parameters }} -| {{#scope}}{{scope}}[{{/scope}}{{ name }}{{#scope}}]{{/scope}} {{# required }}*required*{{/ required }} | {{{ description }}} | -{{/ parameters }} - -{{/ has_parameters? }} -{{^ has_parameters? }} -None known. -{{/ has_parameters? }} - -{{# response_status}} - -### Response - -```plaintext -{{ response_headers_text }} -{{ response_status }} {{ response_status_text}} -``` - -{{# response_body}} - -```json -{{{ response_body }}} -``` -{{/response_body}} - -{{/ response_status}} - -{{# has_response_fields? }} - -#### Fields - -| Name | Description | -|:-----------|:--------------------| -{{# response_fields }} -| {{#scope}}{{scope}}[{{/scope}}{{ name }}{{#scope}}]{{/scope}} | {{{ description }}} | -{{/ response_fields }} - -{{/ has_response_fields? }} - -{{# curl }} -```shell -{{{ curl }}} -``` -{{/ curl }} -{{/ requests}} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/slate_index.mustache b/templates/rspec_api_documentation/rspec_api_documentation/slate_index.mustache deleted file mode 100644 index be0e5ae..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/slate_index.mustache +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: {{ api_name }} -language_tabs: - - json: JSON - - shell: cURL ---- - -{{{ api_explanation }}} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/textile_example.mustache b/templates/rspec_api_documentation/rspec_api_documentation/textile_example.mustache deleted file mode 100644 index a7e022b..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/textile_example.mustache +++ /dev/null @@ -1,80 +0,0 @@ -h1. {{ resource_name }} API -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} - -h2. {{ description }} - -h3. {{ http_method }} {{ route }} - -{{# explanation }} -{{ explanation }} - -{{/ explanation }} -{{# has_parameters? }} -h3. Parameters -{{# parameters }} - -Name : {{ name }} {{# required }} *- required -*{{/ required }} -Description : {{ description }} -{{/ parameters }} - -{{/ has_parameters? }} -{{# has_response_fields? }} -h3. Response Fields -{{# response_fields }} - -Name : {{ name }} -Description : {{ description }} -{{/ response_fields }} - -{{/ has_response_fields? }} -{{# requests }} -h3. Request - -h4. Headers - -
{{ request_headers_text }}
- -h4. Route - -
{{ request_method }} {{ request_path }}
- -{{# request_query_parameters_text }} -h4. Query Parameters - -
{{ request_query_parameters_text }}
- -{{/ request_query_parameters_text }} -{{# request_body }} -h4. Body - -
{{{ request_body }}}
- -{{/ request_body }} -{{# curl }} -h4. cURL - -
{{ curl }}
- -{{/ curl }} -{{# response_status }} -h3. Response - -h4. Headers - -
{{ response_headers_text }}
- -h4. Status - -
{{ response_status }} {{ response_status_text}}
- -{{# response_body }} -h4. Body - -
{{{ response_body }}}
- -{{/ response_body }} -{{/ response_status }} -{{/ requests }} diff --git a/templates/rspec_api_documentation/rspec_api_documentation/textile_index.mustache b/templates/rspec_api_documentation/rspec_api_documentation/textile_index.mustache deleted file mode 100644 index 564b410..0000000 --- a/templates/rspec_api_documentation/rspec_api_documentation/textile_index.mustache +++ /dev/null @@ -1,15 +0,0 @@ -h1. {{ api_name }} -{{{ api_explanation }}} - -{{# sections }} -h2. {{ resource_name }} -{{# resource_explanation }} - -{{{ resource_explanation }}} -{{/ resource_explanation }} - -{{# examples }} -* "{{ description }}":{{ dirname }}/{{ filename }} -{{/ examples }} - -{{/ sections }}