diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index b05c9807c9..0a9756355d 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -20,9 +20,5 @@ jobs: - name: 'Yarn Install' run: yarn install - # Run the ES Lint checks on javascript files - # https://github.com/marketplace/actions/run-eslint - - name: 'ES Lint checks' - uses: stefanoeb/eslint-action@1.0.0 - with: - args: './app/javascript/**/*.js' + - name: 'Run ESLint' + run: yarn run eslint app/javascript/**/*.js --ext .js diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index b8db0ec031..6cc54855ec 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -19,7 +19,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.6.3 + ruby-version: 2.7.6 bundler-cache: true # Install Node @@ -48,28 +48,27 @@ jobs: # Start the DB server and initialize the DB - name: 'Start MySQL' + run: sudo systemctl start mysql + + - name: 'Build out the test database' run: | - sudo systemctl start mysql - bin/rails db:setup RAILS_ENV=test - bin/rails db:migrate RAILS_ENV=test + bundle exec rails db:create RAILS_ENV=test + bundle exec rails db:schema:load RAILS_ENV=test + + - name: 'Run any pending database migrations' + run: bin/rails db:migrate RAILS_ENV=test # Prebuild the CSS, JS and image assets - name: 'Precompile all of the Assets' - run: bin/rails assets:precompile - - # briley - comment out Karma tests due to issues with dependencies. We should - # replace these with RSpec feature tests - # Run the JS tests - # - name: 'Run Karma Tests' - # run: yarn test + run: bundle exec rails assets:precompile # Run the unit and functional tests - name: 'Run Rspec Unit and Functional Tests' run: | - bin/bundle exec rspec spec/models/ spec/policies/ spec/services/ spec/helpers/ - bin/bundle exec rspec spec/controllers/ spec/presenters/ spec/requests/ spec/views - bin/bundle exec rspec spec/mixins/ + bundle exec rspec spec/models/ spec/policies/ spec/services/ spec/helpers/ + bundle exec rspec spec/controllers/ spec/presenters/ spec/requests/ spec/views + bundle exec rspec spec/mixins/ # Run the time consuming integration tests (using Chrome headless browser) - name: 'Run Rspec Integration Tests' - run: bin/bundle exec rspec spec/features/ + run: bundle exec rspec spec/features/ diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml index 2159c8d10e..7d5c3978a1 100644 --- a/.github/workflows/postgres.yml +++ b/.github/workflows/postgres.yml @@ -35,7 +35,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.6.3 + ruby-version: 2.7.6 bundler-cache: true # Install Node @@ -74,26 +74,20 @@ jobs: # Initialize the DB - name: 'Setup Test DB' run: | - bin/rails db:setup RAILS_ENV=test - bin/rails db:migrate RAILS_ENV=test + bundle exec rails db:setup RAILS_ENV=test + bundle exec rails db:migrate RAILS_ENV=test # Prebuild the CSS, JS and image assets - name: 'Compile Assets' - run: bin/rails assets:precompile - - # briley - comment out Karma tests due to issues with dependencies. We should - # replace these with RSpec feature tests - # Run the JS tests - # - name: 'Run Karma Tests' - # run: yarn test + run: bundle exec rails assets:precompile # Run the unit and functional tests - name: 'Run Rspec Unit and Functional Tests' run: | - bin/rspec spec/models/ spec/policies/ spec/services/ spec/helpers/ - bin/rspec spec/controllers/ spec/presenters/ spec/requests/ spec/views - bin/rspec spec/mixins/ + bundle exec rspec spec/models/ spec/policies/ spec/services/ spec/helpers/ + bundle exec rspec spec/controllers/ spec/presenters/ spec/requests/ spec/views + bundle exec rspec spec/mixins/ # Run the time consuming integration tests (using Chrome headless browser) - name: 'Run Integration Tests' - run: bin/rspec spec/features/ + run: bundle exec rspec spec/features/ diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 0fd54b1cc4..57e84481cc 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -13,7 +13,7 @@ jobs: # Install Ruby and run bundler - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.6.3 + ruby-version: 2.7.6 bundler-cache: true # Run the Rubocop linter checks diff --git a/.gitignore b/.gitignore index af0d767c65..4cdd5fee27 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ yarn-debug.log* /yarn-error.log yarn-debug.log* .yarn-integrity + +# Ignore briley AWS cloud9 script to start the application +cloud9-start.sh \ No newline at end of file diff --git a/Gemfile b/Gemfile index d25c86bd0c..4406242641 100644 --- a/Gemfile +++ b/Gemfile @@ -2,20 +2,20 @@ source 'https://rubygems.org' -ruby '>= 2.6.3' +ruby '>= 2.7' # ===========# # CORE RAILS # # ===========# # Full-stack web application framework. (http://rubyonrails.org) -gem 'rails', '~> 5.2' +gem 'rails', '~> 6.1' # TODO: Remove this once Rails addresses the issue with its dependency on mimemagic. Mimemagic had # an MIT license but was using some incompatible GPL license code. # Versions of mimemagic that were yanked: https://rubygems.org/gems/mimemagic/versions # Analysis of the issue: https://www.theregister.com/2021/03/25/ruby_rails_code/ -gem 'mimemagic', '~> 0.3.7' +gem 'mimemagic' # Use sqlite3 as the database for Active Record # gem 'sqlite3', '~> 1.4' @@ -24,13 +24,17 @@ gem 'mimemagic', '~> 0.3.7' gem 'puma', group: :puma, require: false # Use SCSS for stylesheets +# TODO : might need to move to cssbundling-rails +# SEE: https://dev.to/kolide/how-to-migrate-a-rails-6-app-from-sass-rails-to-cssbundling-rails-4l41 gem 'sass-rails' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker' -# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks -gem 'turbolinks' +# Turbo gives you the speed of a single-page web application without having to write any JavaScript.. +# Read more: https://github.com/hotwired/turbo-rails +# https://github.com/hotwired/turbo-rails/blob/main/UPGRADING.md +gem 'turbo-rails' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder' @@ -60,6 +64,7 @@ gem 'bootsnap', require: false # Rollbar-gem is the SDK for Ruby apps and includes support for apps using # Rails, Sinatra, Rack, plain Ruby, and other frameworks. +# https://github.com/rollbar/rollbar-gem gem 'rollbar', group: :rollbar, require: false # ======== # @@ -93,6 +98,7 @@ gem 'devise_invitable' gem 'omniauth' # OmniAuth Shibboleth strategies for OmniAuth 1.x +# https://github.com/toyokazu/omniauth-shibboleth gem 'omniauth-shibboleth' # ORCID OAuth 2.0 Strategy for OmniAuth 1.0 @@ -148,6 +154,7 @@ gem 'kaminari' # Paginate in your headers, not in your response body. This follows the # proposed RFC-8288 standard for Web linking. +# https://github.com/davidcelis/api-pagination gem 'api-pagination' # =========== # @@ -158,7 +165,7 @@ gem 'api-pagination' gem 'sassc-rails' # Font-Awesome SASS (https://github.com/FortAwesome/font-awesome-sass) -gem 'font-awesome-sass', '~> 5.13.0' +gem 'font-awesome-sass', '~> 5' # Use webpack to manage app-like JavaScript modules in Rails # (https://github.com/rails/webpacker) @@ -188,10 +195,6 @@ gem 'wicked_pdf' # (http://github.com/karnov/htmltoword) gem 'htmltoword' -# Filename sanitization for Ruby. This is useful when you generate filenames for -# downloads from user input -gem 'zaru' - # ==================== # # INTERNATIONALIZATION # # ==================== # @@ -239,11 +242,11 @@ group :test do # (https://github.com/thekompanee/fuubar) gem 'fuubar' - # Guard keeps an eye on your file modifications (http://guardgem.org) + # Guard keeps an eye on your file modifications (https://github.com/guard/guard) gem 'guard' # Guard gem for RSpec (https://github.com/guard/guard-rspec) - gem 'guard-rspec' + # gem 'guard-rspec' # Library for stubbing HTTP requests in Ruby. # (http://github.com/bblimke/webmock) @@ -273,11 +276,11 @@ group :test do # Automatically create snapshots when Cucumber steps fail with Capybara # and Rails (http://github.com/mattheworiordan/capybara-screenshot) - gem 'capybara-screenshot' + # gem 'capybara-screenshot' # Browser integration tests are expensive. We can mock external requests # in our tests, but once a browser is involved, we lose control. - gem 'capybara-webmock', '~> 0.6' + gem 'capybara-webmock' # RSpec::CollectionMatchers lets you express expected outcomes on # collections of an object in an example. @@ -309,22 +312,22 @@ group :ci, :development do gem 'rubocop-i18n' # A collection of RuboCop cops to check for performance optimizations in Ruby code. - gem 'rubocop-performance' + # gem 'rubocop-performance' # Automatic Rails code style checking tool. A RuboCop extension focused on enforcing # Rails best practices and coding conventions. - gem 'rubocop-rails' + # gem 'rubocop-rails' # A RuboCop plugin for Rake tasks - gem 'rubocop-rake' + # gem 'rubocop-rake' # Code style checking for RSpec files. A plugin for the RuboCop code style enforcing # & linting tool. - gem 'rubocop-rspec' + # gem 'rubocop-rspec' # Thread-safety checks via static analysis. A plugin for the RuboCop code style # enforcing & linting tool. - gem 'rubocop-thread_safety' + # gem 'rubocop-thread_safety' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index f4d60c19ff..575e507936 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,59 +1,76 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.2.8.1) - actionpack (= 5.2.8.1) + actioncable (6.1.7) + actionpack (= 6.1.7) + activesupport (= 6.1.7) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) + actionmailbox (6.1.7) + actionpack (= 6.1.7) + activejob (= 6.1.7) + activerecord (= 6.1.7) + activestorage (= 6.1.7) + activesupport (= 6.1.7) + mail (>= 2.7.1) + actionmailer (6.1.7) + actionpack (= 6.1.7) + actionview (= 6.1.7) + activejob (= 6.1.7) + activesupport (= 6.1.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.8.1) - actionview (= 5.2.8.1) - activesupport (= 5.2.8.1) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.7) + actionview (= 6.1.7) + activesupport (= 6.1.7) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7) + actionpack (= 6.1.7) + activerecord (= 6.1.7) + activestorage (= 6.1.7) + activesupport (= 6.1.7) + nokogiri (>= 1.8.5) + actionview (6.1.7) + activesupport (= 6.1.7) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7) + activesupport (= 6.1.7) globalid (>= 0.3.6) - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) + activemodel (6.1.7) + activesupport (= 6.1.7) + activerecord (6.1.7) + activemodel (= 6.1.7) + activesupport (= 6.1.7) activerecord_json_validator (2.1.1) activerecord (>= 4.2.0, < 8) json_schemer (~> 0.2.18) - activestorage (5.2.8.1) - actionpack (= 5.2.8.1) - activerecord (= 5.2.8.1) - marcel (~> 1.0.0) - activesupport (5.2.8.1) + activestorage (6.1.7) + actionpack (= 6.1.7) + activejob (= 6.1.7) + activerecord (= 6.1.7) + activesupport (= 6.1.7) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) annotate (3.2.0) activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) annotate_gem (0.0.14) bundler (>= 1.1) - api-pagination (4.8.2) - arel (9.0.0) + api-pagination (5.0.0) ast (2.4.2) autoprefixer-rails (10.4.7.0) execjs (~> 2) @@ -69,7 +86,7 @@ GEM msgpack (~> 1.2) brakeman (5.3.1) builder (3.2.4) - bullet (7.0.2) + bullet (7.0.3) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundle-audit (0.1.0) @@ -78,7 +95,7 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 1.0) byebug (11.1.3) - capybara (3.36.0) + capybara (3.37.1) addressable matrix mini_mime (>= 0.1.3) @@ -87,9 +104,6 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - capybara-screenshot (1.0.26) - capybara (>= 1.0, < 4) - launchy capybara-webmock (0.6.0) capybara (>= 2.4, < 4) rack (>= 1.4) @@ -136,22 +150,22 @@ GEM ecma-re-validator (0.4.0) regexp_parser (~> 2.2) erubi (1.11.0) - excon (0.92.4) + excon (0.93.1) execjs (2.8.1) factory_bot (6.2.1) activesupport (>= 5.0.0) factory_bot_rails (6.2.0) factory_bot (~> 6.2.0) railties (>= 5.0.0) - faker (2.22.0) + faker (2.23.0) i18n (>= 1.8.11, < 2) - faraday (2.5.1) + faraday (2.6.0) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.0) + faraday-net_http (3.0.1) ffi (1.15.5) flag_shih_tzu (0.3.23) - fog-aws (3.14.0) + fog-aws (3.15.0) fog-core (~> 2.1) fog-json (~> 1.1) fog-xml (~> 0.1) @@ -166,7 +180,7 @@ GEM fog-xml (0.1.4) fog-core nokogiri (>= 1.5.11, < 2.0.0) - font-awesome-sass (5.13.1) + font-awesome-sass (5.15.1) sassc (>= 1.11) formatador (1.1.0) forwardable (1.3.2) @@ -189,11 +203,6 @@ GEM pry (>= 0.13.0) shellany (~> 0.0) thor (>= 0.18.1) - guard-compat (1.2.1) - guard-rspec (4.7.3) - guard (~> 2.1) - guard-compat (~> 1.1) - rspec (>= 2.99.0, < 4.0) hana (1.3.7) hashdiff (1.0.1) hashie (5.0.0) @@ -216,7 +225,7 @@ GEM hana (~> 1.3) regexp_parser (~> 2.0) uri_template (~> 0.7) - jwt (2.4.1) + jwt (2.5.0) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -229,15 +238,13 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - launchy (2.5.0) - addressable (~> 2.7) ledermann-rails-settings (2.5.0) activerecord (>= 4.2) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) locale (2.1.3) - loofah (2.18.0) + loofah (2.19.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) lumberjack (1.2.8) @@ -249,31 +256,29 @@ GEM mime-types (3.4.1) mime-types-data (~> 3.2015) mime-types-data (3.2022.0105) - mimemagic (0.3.10) + mimemagic (0.4.3) nokogiri (~> 1) rake mini_mime (1.1.2) - mini_portile2 (2.8.0) - minitest (5.16.2) - mocha (1.14.0) - msgpack (1.5.4) + minitest (5.16.3) + mocha (1.16.0) + msgpack (1.6.0) multi_json (1.15.0) multi_xml (0.6.0) mysql2 (0.5.4) nenv (0.3.0) nio4r (2.5.8) - nokogiri (1.13.8) - mini_portile2 (~> 2.8.0) + nokogiri (1.13.9-x86_64-linux) racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) shellany (~> 0.0) - oauth2 (2.0.6) + oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) multi_xml (~> 0.5) - rack (>= 1.2, < 3) - rash_alt (>= 0.4, < 1) + rack (>= 1.2, < 4) + snaky_hash (~> 2.0) version_gem (~> 1.1) omniauth (2.1.0) hashie (>= 3.4.6) @@ -295,7 +300,7 @@ GEM parallel (1.22.1) parser (3.1.2.1) ast (~> 2.4.1) - pg (1.4.3) + pg (1.4.4) prime (0.1.2) forwardable singleton @@ -305,8 +310,8 @@ GEM pry (0.14.1) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (4.0.7) - puma (5.6.4) + public_suffix (5.0.0) + puma (6.0.0) nio4r (~> 2.0) pundit (2.2.0) activesupport (>= 3.0.0) @@ -316,24 +321,26 @@ GEM rack (2.2.4) rack-mini-profiler (3.0.0) rack (>= 1.2.0) - rack-protection (2.2.2) + rack-protection (3.0.2) rack - rack-proxy (0.7.2) + rack-proxy (0.7.4) rack rack-test (2.0.2) rack (>= 1.3) - rails (5.2.8.1) - actioncable (= 5.2.8.1) - actionmailer (= 5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) - activemodel (= 5.2.8.1) - activerecord (= 5.2.8.1) - activestorage (= 5.2.8.1) - activesupport (= 5.2.8.1) - bundler (>= 1.3.0) - railties (= 5.2.8.1) + rails (6.1.7) + actioncable (= 6.1.7) + actionmailbox (= 6.1.7) + actionmailer (= 6.1.7) + actionpack (= 6.1.7) + actiontext (= 6.1.7) + actionview (= 6.1.7) + activejob (= 6.1.7) + activemodel (= 6.1.7) + activerecord (= 6.1.7) + activestorage (= 6.1.7) + activesupport (= 6.1.7) + bundler (>= 1.15.0) + railties (= 6.1.7) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) @@ -344,77 +351,58 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (5.2.8.1) - actionpack (= 5.2.8.1) - activesupport (= 5.2.8.1) + railties (6.1.7) + actionpack (= 6.1.7) + activesupport (= 6.1.7) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) rake (13.0.6) - rash_alt (0.4.12) - hashie (>= 3.4) - rb-fsevent (0.11.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - recaptcha (5.9.0) + recaptcha (5.12.3) json - regexp_parser (2.5.0) + regexp_parser (2.6.0) responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.5) - rollbar (3.3.1) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) + rollbar (3.3.2) rspec-collection_matchers (1.2.0) rspec-expectations (>= 2.99.0.beta1) rspec-core (3.11.0) rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) + rspec-expectations (3.11.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.11.0) rspec-mocks (3.11.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.11.0) - rspec-rails (5.1.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - railties (>= 5.2) - rspec-core (~> 3.10) - rspec-expectations (~> 3.10) - rspec-mocks (~> 3.10) - rspec-support (~> 3.10) - rspec-support (3.11.0) - rubocop (1.34.1) + rspec-rails (6.0.1) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.11) + rspec-expectations (~> 3.11) + rspec-mocks (~> 3.11) + rspec-support (~> 3.11) + rspec-support (3.11.1) + rubocop (1.37.1) json (~> 2.3) parallel (~> 1.10) parser (>= 3.1.2.1) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.20.0, < 2.0) + rubocop-ast (>= 1.23.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.21.0) + rubocop-ast (1.23.0) parser (>= 3.1.1.0) rubocop-i18n (3.0.0) rubocop (~> 1.0) - rubocop-performance (1.14.3) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) - rubocop-rails (2.15.2) - activesupport (>= 4.2.0) - rack (>= 1.1) - rubocop (>= 1.7.0, < 2.0) - rubocop-rake (0.6.0) - rubocop (~> 1.0) - rubocop-rspec (2.12.1) - rubocop (~> 1.31) - rubocop-thread_safety (0.4.4) - rubocop (>= 0.53.0) ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) ruby_dig (0.0.2) @@ -441,12 +429,15 @@ GEM shoulda-matchers (4.5.1) activesupport (>= 4.2.0) singleton (0.1.1) - spring (2.1.1) + snaky_hash (2.0.1) + hashie + version_gem (~> 1.1, >= 1.1.1) + spring (4.1.0) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - spring-watcher-listen (2.0.1) + spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) + spring (>= 4) sprockets (4.1.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -456,32 +447,32 @@ GEM sprockets (>= 3.0.0) text (1.3.1) thor (1.2.1) - thread_safe (0.3.6) tilt (2.0.11) tomparse (0.4.2) translation (1.32) gettext (~> 3.2, >= 3.2.5, <= 3.4.3) - turbolinks (5.2.1) - turbolinks-source (~> 5.2) - turbolinks-source (5.2.0) - tzinfo (1.2.10) - thread_safe (~> 0.1) - unicode-display_width (2.2.0) + turbo-rails (1.3.2) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + unicode-display_width (2.3.0) uniform_notifier (1.16.0) uri_template (0.7.0) - version_gem (1.1.0) + version_gem (1.1.1) warden (1.2.9) rack (>= 2.0.9) - web-console (3.7.0) - actionview (>= 5.0) - activemodel (>= 5.0) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) bindex (>= 0.4.0) - railties (>= 5.0) + railties (>= 6.0.0) webdrivers (4.7.0) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (> 3.141, < 5.0) - webmock (3.17.1) + webmock (3.18.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -504,10 +495,10 @@ GEM yard-tomdoc (0.7.1) tomparse (>= 0.4.0) yard - zaru (0.3.0) + zeitwerk (2.6.1) PLATFORMS - ruby + x86_64-linux DEPENDENCIES activerecord_json_validator @@ -523,8 +514,7 @@ DEPENDENCIES bundle-audit byebug capybara - capybara-screenshot - capybara-webmock (~> 0.6) + capybara-webmock contact_us database_cleaner devise @@ -535,10 +525,9 @@ DEPENDENCIES factory_bot_rails faker flag_shih_tzu - font-awesome-sass (~> 5.13.0) + font-awesome-sass (~> 5) fuubar guard - guard-rspec htmltoword httparty jbuilder @@ -546,7 +535,7 @@ DEPENDENCIES kaminari ledermann-rails-settings listen - mimemagic (~> 0.3.7) + mimemagic mocha mysql2 omniauth @@ -560,7 +549,7 @@ DEPENDENCIES pundit pundit-matchers rack-mini-profiler - rails (~> 5.2) + rails (~> 6.1) rails-controller-testing recaptcha rollbar @@ -568,11 +557,6 @@ DEPENDENCIES rspec-rails rubocop rubocop-i18n - rubocop-performance - rubocop-rails - rubocop-rake - rubocop-rspec - rubocop-thread_safety sass-rails sassc-rails selenium-webdriver @@ -582,7 +566,7 @@ DEPENDENCIES spring-watcher-listen text translation - turbolinks + turbo-rails web-console webdrivers webmock @@ -591,10 +575,9 @@ DEPENDENCIES wkhtmltopdf-binary yard yard-tomdoc - zaru RUBY VERSION - ruby 2.6.3p62 + ruby 2.7.6p219 BUNDLED WITH - 2.2.33 + 2.3.15 diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 4e5640a461..58ceda63b6 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -14,4 +14,4 @@ @import "../../../node_modules/jquery-ui-sass/assets/sass/jquery-ui.scss"; @import "font-awesome-sprockets"; -@import "font-awesome"; +@import "font-awesome"; \ No newline at end of file diff --git a/app/controllers/api/v0/departments_controller.rb b/app/controllers/api/v0/departments_controller.rb index e573522b78..8048ac28a8 100644 --- a/app/controllers/api/v0/departments_controller.rb +++ b/app/controllers/api/v0/departments_controller.rb @@ -48,9 +48,8 @@ def assign_users assign_users_to(@department.id) - # Added "status: :see_other" to redirect_to (as we require rediect to be a GET). - # See https://makandracards.com/makandra/38347-redirecting-responses-for-patch-or-delete-will-not-redirect-with-get - redirect_to users_api_v0_departments_path, status: :see_other + @users = @user.org.users.includes(:department) + render users_api_v0_departments_path end ## @@ -62,9 +61,8 @@ def unassign_users assign_users_to(nil) - # Added "status: :see_other" to redirect_to (as we require rediect to be a GET). - # See https://makandracards.com/makandra/38347-redirecting-responses-for-patch-or-delete-will-not-redirect-with-get - redirect_to users_api_v0_departments_path, status: :see_other + @users = @user.org.users.includes(:department) + render users_api_v0_departments_path end private diff --git a/app/controllers/contacts_controller.rb b/app/controllers/contact_us/contacts_controller.rb similarity index 100% rename from app/controllers/contacts_controller.rb rename to app/controllers/contact_us/contacts_controller.rb diff --git a/app/controllers/contributors_controller.rb b/app/controllers/contributors_controller.rb index 3c210b63d4..410b95fd37 100644 --- a/app/controllers/contributors_controller.rb +++ b/app/controllers/contributors_controller.rb @@ -155,7 +155,7 @@ def process_orcid_for_update(hash:) # = Callbacks = # ============= def fetch_plan - @plan = Plan.includes(:contributors).find_by(id: params[:plan_id]) + @plan = Plan.find_by(id: params[:plan_id]) return true if @plan.present? redirect_to root_path, alert: _('plan not found') diff --git a/app/controllers/guidance_groups_controller.rb b/app/controllers/guidance_groups_controller.rb index 611d5ef4d4..9871a4d886 100644 --- a/app/controllers/guidance_groups_controller.rb +++ b/app/controllers/guidance_groups_controller.rb @@ -13,6 +13,7 @@ class GuidanceGroupsController < ApplicationController # GET /org/admin/guidancegroup/:id/admin_new def admin_new + @guidance_groups = GuidanceGroup.where(org_id: current_user.org.id) @guidance_group = GuidanceGroup.new(org_id: current_user.org.id) authorize @guidance_group end @@ -22,6 +23,7 @@ def admin_new def admin_create # Ensure that the user can only create GuidanceGroups for their Org args = guidance_group_params.to_h.merge({ org_id: current_user.org.id }) + @guidance_groups = GuidanceGroup.where(org_id: current_user.org.id) @guidance_group = GuidanceGroup.new(args) authorize @guidance_group @@ -37,6 +39,7 @@ def admin_create # GET /org/admin/guidancegroup/:id/admin_edit def admin_edit + @guidance_groups = GuidanceGroup.where(org_id: current_user.org.id) @guidance_group = GuidanceGroup.find(params[:id]) authorize @guidance_group end @@ -44,6 +47,7 @@ def admin_edit # PUT /org/admin/guidancegroup/:id/admin_update # rubocop:disable Metrics/AbcSize def admin_update + @guidance_groups = GuidanceGroup.where(org_id: current_user.org.id) @guidance_group = GuidanceGroup.find(params[:id]) authorize @guidance_group diff --git a/app/controllers/guidances_controller.rb b/app/controllers/guidances_controller.rb index d3a193a12e..7b6dc5e4c6 100644 --- a/app/controllers/guidances_controller.rb +++ b/app/controllers/guidances_controller.rb @@ -14,10 +14,11 @@ class GuidancesController < ApplicationController # GET /org/admin/guidance/:id/admin_index def admin_index authorize Guidance - @guidances = Guidance.by_org(current_user.org) - .includes(:guidance_group, :themes).page(1) + @guidances = Guidance.includes(:guidance_group, :themes) + .by_org(current_user.org).page(1) ensure_default_group(current_user.org) - @guidance_groups = GuidanceGroup.by_org(current_user.org).page(1) + @guidance_groups = GuidanceGroup.includes(:org) + .by_org(current_user.org).page(1) end # GET /org/admin/guidance/:id/admin_new @@ -63,7 +64,7 @@ def admin_update @guidance = Guidance.find(params[:id]) authorize @guidance - if @guidance.update_attributes(guidance_params) + if @guidance.update(guidance_params) if @guidance.published? guidance_group = GuidanceGroup.find(@guidance.guidance_group_id) if !guidance_group.published? || guidance_group.published.nil? @@ -103,7 +104,7 @@ def admin_destroy def admin_publish @guidance = Guidance.find(params[:id]) authorize @guidance - if @guidance.update_attributes(published: true) + if @guidance.update(published: true) guidance_group = GuidanceGroup.find(@guidance.guidance_group_id) guidance_group.update(published: true) if !guidance_group.published? || guidance_group.published.nil? flash[:notice] = _('Your guidance has been published and is now available to users.') @@ -120,7 +121,7 @@ def admin_publish def admin_unpublish @guidance = Guidance.find(params[:id]) authorize @guidance - if @guidance.update_attributes(published: false) + if @guidance.update(published: false) guidance_group = GuidanceGroup.find(@guidance.guidance_group_id) guidance_group.update(published: false) unless guidance_group.guidances.where(published: true).exists? flash[:notice] = _('Your guidance is no longer published and will not be available to users.') diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index ae863c5eff..bba42c8bd8 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -3,7 +3,6 @@ # Controller for the Comments section of the Write Plan page class NotesController < ApplicationController include ConditionalUserMailer - require 'pp' after_action :verify_authorized respond_to :html diff --git a/app/controllers/org_admin/departments_controller.rb b/app/controllers/org_admin/departments_controller.rb index 8613a484c6..b77ae38503 100644 --- a/app/controllers/org_admin/departments_controller.rb +++ b/app/controllers/org_admin/departments_controller.rb @@ -60,7 +60,7 @@ def destroy @department = Department.find(params[:id]) @org_id = org_id authorize @department - url = "#{admin_edit_org_path(@org_id)}\#departments" + url = "#{admin_edit_org_path(@org_id)}#departments" if @department.destroy flash[:notice] = success_message(@department, _('deleted')) diff --git a/app/controllers/org_admin/templates_controller.rb b/app/controllers/org_admin/templates_controller.rb index 537ea4c5e4..aed9d383dc 100644 --- a/app/controllers/org_admin/templates_controller.rb +++ b/app/controllers/org_admin/templates_controller.rb @@ -17,7 +17,7 @@ def index templates = Template.latest_version.where(customization_of: nil) published = templates.select { |t| t.published? || t.draft? }.length - @orgs = Org.managed + @orgs = Org.includes(:identifiers).managed @title = _('All Templates') @templates = templates.includes(:org).page(1) @query_params = { sort_field: 'templates.title', sort_direction: 'asc' } @@ -42,7 +42,7 @@ def organisational .where(customization_of: nil, org_id: current_user.org.id) published = templates.select { |t| t.published? || t.draft? }.length - @orgs = current_user.can_super_admin? ? Org.all : nil + @orgs = current_user.can_super_admin? ? Org.includes(:identifiers).all : nil @title = if current_user.can_super_admin? format(_('%{org_name} Templates'), org_name: current_user.org.name) else @@ -80,7 +80,7 @@ def customisable end published = customizations.select { |t| t.published? || t.draft? }.length - @orgs = current_user.can_super_admin? ? Org.all : [] + @orgs = current_user.can_super_admin? ? Org.includes(:identifiers).all : [] @title = _('Customizable Templates') @templates = funder_templates @customizations = customizations @@ -108,8 +108,8 @@ def show .includes(sections: { questions: :question_options }) .order('phases.number', 'sections.number', 'questions.number', 'question_options.number') - .select('phases.title', 'phases.description', 'sections.title', - 'questions.text', 'question_options.text') + .select('phases.title', 'phases.description', 'phases.modifiable', + 'sections.title', 'questions.text', 'question_options.text') unless template.latest? # rubocop:disable Layout/LineLength flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') @@ -136,6 +136,7 @@ def edit 'question_options.number') .select('phases.title', 'phases.description', + 'phases.modifiable', 'sections.title', 'questions.text', 'question_options.text') diff --git a/app/controllers/org_admin/users_controller.rb b/app/controllers/org_admin/users_controller.rb index 6138ddb18b..9474a9ffd7 100644 --- a/app/controllers/org_admin/users_controller.rb +++ b/app/controllers/org_admin/users_controller.rb @@ -26,7 +26,7 @@ def update authorize @user @departments = @user.org.departments.order(:name) @plans = Plan.active(@user).page(1) - if @user.update_attributes(user_params) + if @user.update(user_params) flash.now[:notice] = success_message(@user, _('updated')) else flash.now[:alert] = failure_message(@user, _('update')) diff --git a/app/controllers/orgs_controller.rb b/app/controllers/orgs_controller.rb index e2d8129f8f..ed0e3f78df 100644 --- a/app/controllers/orgs_controller.rb +++ b/app/controllers/orgs_controller.rb @@ -88,11 +88,11 @@ def admin_update end @org.save end - redirect_to "#{admin_edit_org_path(@org)}\##{tab}", + redirect_to "#{admin_edit_org_path(@org)}##{tab}", notice: success_message(@org, _('saved')) else failure = failure_message(@org, _('save')) if failure.blank? - redirect_to "#{admin_edit_org_path(@org)}\##{tab}", alert: failure + redirect_to "#{admin_edit_org_path(@org)}##{tab}", alert: failure end end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength diff --git a/app/controllers/paginable/guidance_groups_controller.rb b/app/controllers/paginable/guidance_groups_controller.rb index d001ecc68a..0eb68c02ff 100644 --- a/app/controllers/paginable/guidance_groups_controller.rb +++ b/app/controllers/paginable/guidance_groups_controller.rb @@ -10,7 +10,7 @@ def index authorize(Guidance) paginable_renderise( partial: 'index', - scope: GuidanceGroup.by_org(current_user.org), + scope: GuidanceGroup.includes(:org).by_org(current_user.org), query_params: { sort_field: 'guidance_groups.name', sort_direction: :asc }, format: :json ) diff --git a/app/controllers/paginable/guidances_controller.rb b/app/controllers/paginable/guidances_controller.rb index d97e00826a..ecbb718c08 100644 --- a/app/controllers/paginable/guidances_controller.rb +++ b/app/controllers/paginable/guidances_controller.rb @@ -10,8 +10,7 @@ def index authorize(Guidance) paginable_renderise( partial: 'index', - scope: Guidance.by_org(current_user.org) - .includes(:guidance_group, :themes), + scope: Guidance.includes(:guidance_group, :themes).by_org(current_user.org), query_params: { sort_field: 'guidances.text', sort_direction: :asc }, format: :json ) diff --git a/app/controllers/paginable/plans_controller.rb b/app/controllers/paginable/plans_controller.rb index b4ddbae87f..acdf1ae1af 100644 --- a/app/controllers/paginable/plans_controller.rb +++ b/app/controllers/paginable/plans_controller.rb @@ -11,7 +11,7 @@ def privately_visible paginable_renderise( partial: 'privately_visible', - scope: Plan.active(current_user), + scope: Plan.includes(:roles).active(current_user), query_params: { sort_field: 'plans.updated_at', sort_direction: :desc }, format: :json ) diff --git a/app/controllers/paginable/templates_controller.rb b/app/controllers/paginable/templates_controller.rb index 4456ffa00b..8e691519ca 100644 --- a/app/controllers/paginable/templates_controller.rb +++ b/app/controllers/paginable/templates_controller.rb @@ -13,18 +13,18 @@ class TemplatesController < ApplicationController # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity def index authorize Template - templates = Template.latest_version.where(customization_of: nil) + templates = Template.includes(:org).latest_version.where(customization_of: nil) case params[:f] when 'published' template_ids = templates.select { |t| t.published? || t.draft? }.collect(&:family_id) - templates = Template.latest_version(template_ids).where(customization_of: nil) + templates = Template.includes(:org).latest_version(template_ids).where(customization_of: nil) when 'unpublished' template_ids = templates.select { |t| !t.published? && !t.draft? }.collect(&:family_id) - templates = Template.latest_version(template_ids).where(customization_of: nil) + templates = Template.includes(:org).latest_version(template_ids).where(customization_of: nil) end paginable_renderise( partial: 'index', - scope: templates.includes(:org), + scope: templates, query_params: { sort_field: 'templates.title', sort_direction: :asc }, locals: { action: 'index' }, format: :json diff --git a/app/controllers/paginable/users_controller.rb b/app/controllers/paginable/users_controller.rb index 3da69b12cc..288fd08215 100644 --- a/app/controllers/paginable/users_controller.rb +++ b/app/controllers/paginable/users_controller.rb @@ -15,9 +15,9 @@ def index @filter_admin = params[:filter_admin] == '1' scope = if current_user.can_super_admin? - User.includes(:roles) + User.includes(:department, :org, :perms, :roles, :identifiers) else - current_user.org.users.includes(:roles) + current_user.org.users.includes(:department, :org, :perms, :roles, :identifiers) end scope = scope.joins(:perms).distinct if @filter_admin diff --git a/app/controllers/plan_exports_controller.rb b/app/controllers/plan_exports_controller.rb index 5684fd6521..edb15b3843 100644 --- a/app/controllers/plan_exports_controller.rb +++ b/app/controllers/plan_exports_controller.rb @@ -43,6 +43,13 @@ def show .detect { |p| p.visibility_allowed?(@plan) } end + # Added contributors to coverage of plans. + # Users will see both roles and contributor names if the role is filled + @hash[:data_curation] = Contributor.where(plan_id: @plan.id).data_curation + @hash[:investigation] = Contributor.where(plan_id: @plan.id).investigation + @hash[:pa] = Contributor.where(plan_id: @plan.id).project_administration + @hash[:other] = Contributor.where(plan_id: @plan.id).other + respond_to do |format| format.html { show_html } format.csv { show_csv } @@ -107,9 +114,9 @@ def show_json def file_name # Sanitize bad characters and replace spaces with underscores ret = @plan.title - Zaru.sanitize! ret ret = ret.strip.gsub(/\s+/, '_') ret = ret.gsub(/"/, '') + ret = ActiveStorage::Filename.new(ret).sanitized # limit the filename length to 100 chars. Windows systems have a MAX_PATH allowance # of 255 characters, so this should provide enough of the title to allow the user # to understand which DMP it is and still allow for the file to be saved to a deeply diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 404a6a782f..623cf2477f 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -15,7 +15,7 @@ class PlansController < ApplicationController # rubocop:disable Metrics/AbcSize def index authorize Plan - @plans = Plan.includes(:roles, :org).active(current_user).page(1) + @plans = Plan.includes(:roles).active(current_user).page(1) @organisationally_or_publicly_visible = if current_user.org.is_other? [] else @@ -162,8 +162,7 @@ def create # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def show @plan = Plan.includes( - template: { phases: { sections: { questions: :answers } } }, - plans_guidance_groups: { guidance_group: :guidances } + :guidance_groups, template: [:phases] ).find(params[:id]) authorize @plan @@ -174,7 +173,6 @@ def show end # Get all of the available funders @funders = Org.funder - .includes(identifiers: :identifier_scheme) .joins(:templates) .where(templates: { published: true }).uniq.sort_by(&:name) # TODO: Seems strange to do this. Why are we just not using an `edit` route? @@ -192,8 +190,9 @@ def show if @all_ggs_grouped_by_org.include?(current_user.org) @important_ggs << [current_user.org, @all_ggs_grouped_by_org[current_user.org]] end + @default_orgs = Org.default_orgs @all_ggs_grouped_by_org.each do |org, ggs| - @important_ggs << [org, ggs] if Org.default_orgs.include?(org) + @important_ggs << [org, ggs] if @default_orgs.include?(org) # If this is one of the already selected guidance groups its important! @important_ggs << [org, ggs] if !(ggs & @selected_guidance_groups).empty? && !@important_ggs.include?([org, ggs]) @@ -229,7 +228,7 @@ def edit { template: { phases: { sections: { - questions: %i[question_format question_options annotations themes] + questions: %i[question_format annotations] } } } }, diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index a3fbb757d5..53492a3f9e 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -234,7 +234,7 @@ def do_update(require_password = true, confirm = false) end # unlink shibboleth from user's details - current_user.update_attributes(shibboleth_id: '') if params[:unlink_flag] == 'true' + current_user.update(shibboleth_id: '') if params[:unlink_flag] == 'true' # render the correct page if successfully_updated @@ -249,7 +249,7 @@ def do_update(require_password = true, confirm = false) set_flash_message :notice, success_message(current_user, _('saved')) # Sign in the user bypassing validation in case his password changed sign_in current_user, bypass: true - redirect_to "#{edit_user_registration_path}\#personal-details", + redirect_to "#{edit_user_registration_path}#personal-details", notice: success_message(current_user, _('saved')) else @@ -280,12 +280,12 @@ def do_update_password(current_user, args) set_flash_message :notice, success_message(current_user, _('saved')) # TODO: this method is deprecated sign_in current_user, bypass: true - redirect_to "#{edit_user_registration_path}\#password-details", + redirect_to "#{edit_user_registration_path}#password-details", notice: success_message(current_user, _('saved')) else flash[:alert] = message.blank? ? failure_message(current_user, _('save')) : message - redirect_to "#{edit_user_registration_path}\#password-details" + redirect_to "#{edit_user_registration_path}#password-details" end end # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index bf0fe082df..b40c559f61 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -81,7 +81,7 @@ def update @role = Role.find(params[:id]) authorize @role - if @role.update_attributes(access: role_params[:access]) + if @role.update(access: role_params[:access]) deliver_if(recipients: @role.user, key: 'users.added_as_coowner') do |_r| UserMailer.permissions_change_notification(@role, current_user).deliver_now end diff --git a/app/controllers/super_admin/orgs_controller.rb b/app/controllers/super_admin/orgs_controller.rb index 50ff0b421b..18fc1fa4b9 100644 --- a/app/controllers/super_admin/orgs_controller.rb +++ b/app/controllers/super_admin/orgs_controller.rb @@ -11,7 +11,7 @@ class OrgsController < ApplicationController def index authorize Org render 'index', locals: { - orgs: Org.includes(:contributors, :plans).with_template_and_user_counts.page(1) + orgs: Org.with_template_and_user_counts.page(1) } end diff --git a/app/controllers/super_admin/themes_controller.rb b/app/controllers/super_admin/themes_controller.rb index 6be6852c59..ccd80dbfb8 100644 --- a/app/controllers/super_admin/themes_controller.rb +++ b/app/controllers/super_admin/themes_controller.rb @@ -35,7 +35,7 @@ def edit def update authorize(Theme) @theme = Theme.find(params[:id]) - if @theme.update_attributes(permitted_params) + if @theme.update(permitted_params) flash.now[:notice] = success_message(@theme, _('updated')) else flash.now[:alert] = failure_message(@theme, _('update')) diff --git a/app/controllers/super_admin/users_controller.rb b/app/controllers/super_admin/users_controller.rb index 4c67446d60..a27f528adb 100644 --- a/app/controllers/super_admin/users_controller.rb +++ b/app/controllers/super_admin/users_controller.rb @@ -39,7 +39,7 @@ def update # Remove the extraneous Org Selector hidden fields attrs = remove_org_selection_params(params_in: attrs) - if @user.update_attributes(attrs) + if @user.update(attrs) # If its a new Org create it if lookup.present? && lookup.new_record? lookup.save diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index eca0e89eca..def9e66356 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -21,9 +21,11 @@ def admin_index @filter_admin = false @users = if current_user.can_super_admin? - User.includes(:roles).page(1) + User.includes(:department, :org, :perms, :roles, :identifiers).page(1) else - current_user.org.users.includes(:roles).page(1) + current_user.org.users + .includes(:department, :org, :perms, :roles, :identifiers) + .page(1) end end @@ -125,7 +127,7 @@ def update_email_preferences pref.save # Include active tab in redirect path - redirect_to "#{edit_user_registration_path}\#notification-preferences", + redirect_to "#{edit_user_registration_path}#notification-preferences", notice: success_message(pref, _('saved')) end # rubocop:enable Metrics/AbcSize diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index f61459d552..802f33f005 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -86,14 +86,14 @@ import '../src/superAdmin/themes/newEdit'; import '../src/superAdmin/users/edit'; // Since we're using Webpacker to manage JS we need to startup Rails' Unobtrusive JS -// and Turbolinks. ActiveStorage and ActionCable would also need to be in here +// and Turbo. ActiveStorage and ActionCable would also need to be in here // if we decide to implement either before Rails 6 require('@rails/ujs').start(); -// TODO: Disabled turbolinks for the time being because our custom JS is not +// TODO: Disabled turbo for the time being because our custom JS is not // properly setup to work with it. We should review the docs: -// https://github.com/turbolinks/turbolinks -// require('turbolinks').start(); +// https://github.com/hotwired/turbo-rails +// import "@hotwired/turbo-rails". // require("@rails/activestorage").start() // require("@rails/actioncable").start() diff --git a/app/javascript/src/utils/autoComplete.js b/app/javascript/src/utils/autoComplete.js index f181a17f38..2021a47444 100644 --- a/app/javascript/src/utils/autoComplete.js +++ b/app/javascript/src/utils/autoComplete.js @@ -218,3 +218,4 @@ export const initAutocomplete = (selector) => { } } }; +export default initAutocomplete; diff --git a/app/javascript/src/utils/charts.js b/app/javascript/src/utils/charts.js index 63e8088a59..364d15cd1e 100644 --- a/app/javascript/src/utils/charts.js +++ b/app/javascript/src/utils/charts.js @@ -1,4 +1,4 @@ -import Chart from 'chart.js'; +import Chart from 'chart.js/auto'; // Set Aspect Rate (width of X-axis/height of Y-axis) based on // choice of selectedLastDayOfMonth in Time picker string value. Note aspect @@ -40,13 +40,14 @@ export const getAspectRatio = (diffInMonths) => { // Register a plugin for displaying a message for no data export const initializeCharts = () => { - Chart.plugins.register({ + Chart.register({ + id: 'no_data_label', afterDraw: (chart) => { if (chart.data.datasets.length === 0) { const { ctx, width, height } = { - ctx: chart.chart.ctx, - width: chart.chart.width, - height: chart.chart.height, + ctx: chart.ctx, + width: chart.width, + height: chart.height, }; chart.clear(); ctx.save(); @@ -72,8 +73,10 @@ export const createChart = (selector, data, appendTolabel = '', onClickHandler = }], }, options: { - legend: { - display: false, + plugins: { + legend: { + display: false, + }, }, tooltips: { callbacks: { @@ -81,9 +84,9 @@ export const createChart = (selector, data, appendTolabel = '', onClickHandler = }, }, scales: { - yAxes: [{ + y: { ticks: { min: 0, suggestedMax: 50 }, - }], + }, }, onClick: onClickHandler, }, @@ -94,20 +97,21 @@ export const createChart = (selector, data, appendTolabel = '', onClickHandler = export const drawHorizontalBar = (canvasSelector, data) => { const aspectRatio = getAspectRatio(data.labels.length); const chart = new Chart(canvasSelector, { // eslint-disable-line no-new - type: 'horizontalBar', + type: 'bar', data, options: { + indexAxis: 'y', responsive: true, maintainAspectRatio: true, aspectRatio, scales: { - xAxes: [{ + x: { ticks: { beginAtZero: true, stepSize: 10 }, stacked: true, - }], - yAxes: [{ + }, + y: { stacked: true, - }], + }, }, }, }); diff --git a/app/javascript/src/utils/tinymce.js.erb b/app/javascript/src/utils/tinymce.js.erb index 6e523855b4..0d0ad822b1 100644 --- a/app/javascript/src/utils/tinymce.js.erb +++ b/app/javascript/src/utils/tinymce.js.erb @@ -1,7 +1,8 @@ // Import TinyMCE import tinymce from 'tinymce/tinymce'; // Import TinyMCE theme -import 'tinymce/themes/modern/theme'; +import 'tinymce/themes/silver/theme'; +import 'tinymce/icons/default'; // Plugins import 'tinymce/plugins/table'; import 'tinymce/plugins/lists'; @@ -29,13 +30,12 @@ export const defaultOptions = { target_list: false, elementpath: false, resize: true, - autoresize_min_height: 230, + min_height: 230, autoresize_bottom_margin: 10, branding: false, extended_valid_elements: 'iframe[tooltip] , a[href|target=_blank]', paste_auto_cleanup_on_paste: true, paste_remove_styles: true, - paste_retain_style_properties: 'none', paste_convert_middot_lists: true, paste_remove_styles_if_webkit: true, paste_remove_spans: true, @@ -45,7 +45,7 @@ export const defaultOptions = { }, // editorManager.baseURL is not resolved properly for IE since document.currentScript // is not supported, see issue https://github.com/tinymce/tinymce/issues/358 - skin_url: '/tinymce/skins/lightgray', + skin_url: '/tinymce/skins/oxide', content_css: ['/tinymce/tinymce.css'], }; /* diff --git a/app/models/application_record.rb b/app/models/application_record.rb index fc9717e959..ecde6e7ebf 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -11,11 +11,11 @@ class ApplicationRecord < ActiveRecord::Base class << self # Indicates whether the underlying DB is MySQL def mysql_db? - ActiveRecord::Base.connection.adapter_name == 'Mysql2' + connection.adapter_name == 'Mysql2' end def postgres_db? - ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' + connection.adapter_name == 'PostgreSQL' end # Generates the appropriate where clause for a JSON field based on the DB type diff --git a/app/models/concerns/exportable_plan.rb b/app/models/concerns/exportable_plan.rb index b106db3a7a..7936eaffd3 100644 --- a/app/models/concerns/exportable_plan.rb +++ b/app/models/concerns/exportable_plan.rb @@ -97,10 +97,9 @@ def prepare(user, coversheet = false) hash end - # rubocop:enable Metrics/MethodLength, Metrics/AbcSize + # rubocop:enable Style/OptionalBooleanParameter - # rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def prepare_coversheet hash = {} @@ -110,6 +109,13 @@ def prepare_coversheet roles.administrator.not_creator.first&.user&.name(false) unless attribution.present? hash[:attribution] = attribution + # Added contributors to coverage of plans. + # Users will see both roles and contributor names if the role is filled + hash[:data_curation] = Contributor.where(plan_id: id).data_curation + hash[:investigation] = Contributor.where(plan_id: id).investigation + hash[:pa] = Contributor.where(plan_id: id).project_administration + hash[:other] = Contributor.where(plan_id: id).other + # Org name of plan owner's org hash[:affiliation] = owner.present? ? owner.org.name : '' @@ -132,13 +138,29 @@ def prepare_coversheet end # rubocop:enable Metrics/AbcSize - # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + # rubocop:disable Metrics/AbcSize def prepare_coversheet_for_csv(csv, _headings, hash) + csv << [_('Title: '), format(_('%{title}'), title: title)] csv << if Array(hash[:attribution]).many? [_('Creators: '), format(_('%{authors}'), authors: Array(hash[:attribution]).join(', '))] else [_('Creator:'), format(_('%{authors}'), authors: hash[:attribution])] end + if hash[:investigation].present? + csv << [_('Principal Investigator: '), + format(_('%{investigation}'), investigation: hash[:investigation].map(&:name).join(', '))] + end + if hash[:data_curation].present? + csv << [_('Date Manager: '), + format(_('%{data_curation}'), data_curation: hash[:data_curation].map(&:name).join(', '))] + end + if hash[:pa].present? + csv << [_('Project Administrator: '), format(_('%{pa}'), pa: hash[:pa].map(&:name).join(', '))] + end + if hash[:other].present? + csv << [_('Contributor: '), format(_('%{other}'), other: hash[:other].map(&:name).join(', '))] + end + csv << [_('Affiliation: '), format(_('%{affiliation}'), affiliation: hash[:affiliation])] csv << ['Affiliation: ', format(_('%{affiliation}'), affiliation: hash[:affiliation])] csv << if hash[:funder].present? [_('Template: '), format(_('%{funder}'), funder: hash[:funder])] diff --git a/app/models/concerns/json_link_validator.rb b/app/models/concerns/json_link_validator.rb index 2e0e037e33..544f0e22ff 100644 --- a/app/models/concerns/json_link_validator.rb +++ b/app/models/concerns/json_link_validator.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Module that helps validate Template and Org links -module JSONLinkValidator +module JsonLinkValidator # Validates whether or not the value passed is conforming to # [{ link: String, text: String}, ...] def valid_links?(value) diff --git a/app/models/contributor.rb b/app/models/contributor.rb index 5cb2d9094d..b462efc610 100644 --- a/app/models/contributor.rb +++ b/app/models/contributor.rb @@ -68,7 +68,8 @@ class Contributor < ApplicationRecord 2 => :investigation, 3 => :project_administration, 4 => :other, - column: 'roles' + column: 'roles', + check_for_column: !Rails.env.test? # ========== # = Scopes = @@ -87,12 +88,8 @@ class Contributor < ApplicationRecord # ======================== # = Static Class Methods = # ======================== - - class << self - # returns the default role - def default_role - 'other' - end + def self.role_default + 'other' end # Check for equality by matching on Plan, ORCID, email or name diff --git a/app/models/department.rb b/app/models/department.rb index a3c2a189a3..31d84bd755 100644 --- a/app/models/department.rb +++ b/app/models/department.rb @@ -30,7 +30,7 @@ class Department < ApplicationRecord validates :name, presence: { message: PRESENCE_MESSAGE }, uniqueness: { message: UNIQUENESS_MESSAGE, - scope: :org_id } + scope: :org_id, case_sensitive: false } validates :name, uniqueness: { message: UNIQUENESS_MESSAGE, scope: :org_id } diff --git a/app/models/identifier.rb b/app/models/identifier.rb index 0ee44592b1..8d8a6221ca 100644 --- a/app/models/identifier.rb +++ b/app/models/identifier.rb @@ -77,7 +77,7 @@ def value=(val) base = identifier_scheme.identifier_prefix base += '/' unless base.ends_with?('/') - super("#{base}#{val}") + super("#{base}#{val.to_s.strip}") else super(val) end diff --git a/app/models/identifier_scheme.rb b/app/models/identifier_scheme.rb index ea712e3901..da664144eb 100644 --- a/app/models/identifier_scheme.rb +++ b/app/models/identifier_scheme.rb @@ -51,7 +51,8 @@ class IdentifierScheme < ApplicationRecord 3 => :for_plans, 4 => :for_users, 5 => :for_contributors, - column: 'context' + column: 'context', + check_for_column: !Rails.env.test? # ========================= # = Custom Accessor Logic = diff --git a/app/models/org.rb b/app/models/org.rb index 6b2a48525c..b56a40e0b1 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -48,12 +48,12 @@ class Org < ApplicationRecord attribute :feedback_msg, :text, default: feedback_confirmation_default_message attribute :language_id, :integer, default: -> { Language.default&.id } - attribute :links, :text, default: { org: [] } # Stores links as an JSON object: # { org: [{"link":"www.example.com","text":"foo"}, ...] } # The links are validated against custom validator allocated at # validators/template_links_validator.rb + attribute :links, :text, default: { org: [] } serialize :links, JSON # ================ @@ -93,7 +93,8 @@ class Org < ApplicationRecord # =============== validates :name, presence: { message: PRESENCE_MESSAGE }, - uniqueness: { message: UNIQUENESS_MESSAGE } + uniqueness: { message: UNIQUENESS_MESSAGE, + case_sensitive: false } validates :is_other, inclusion: { in: BOOLEAN_VALUES, message: PRESENCE_MESSAGE } @@ -172,7 +173,8 @@ def check_for_missing_logo_file 4 => :research_institute, 5 => :project, 6 => :school, - column: 'org_type' + column: 'org_type', + check_for_column: !Rails.env.test? # The default Org is the one whose guidance is auto-attached to # plans when a plan is created diff --git a/app/models/perm.rb b/app/models/perm.rb index a95f6e6543..e30cd7705e 100644 --- a/app/models/perm.rb +++ b/app/models/perm.rb @@ -35,7 +35,8 @@ def lazy_load(name) # =============== validates :name, presence: { message: PRESENCE_MESSAGE }, - uniqueness: { message: UNIQUENESS_MESSAGE } + uniqueness: { message: UNIQUENESS_MESSAGE, + case_sensitive: false } # ================= # = Class methods = diff --git a/app/models/plan.rb b/app/models/plan.rb index 0bf4e69a58..0cf221887b 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -75,8 +75,6 @@ class Plan < ApplicationRecord alias_attribute :name, :title - attribute :visibility, :integer, default: 3 - # ================ # = Associations = # ================ @@ -101,7 +99,7 @@ class Plan < ApplicationRecord has_many :guidances, through: :themes - has_many :guidance_group_options, -> { distinct.published.reorder('id') }, + has_many :guidance_group_options, -> { distinct.includes(:org).published.reorder('id') }, through: :guidances, source: :guidance_group, class_name: 'GuidanceGroup' diff --git a/app/models/question_format.rb b/app/models/question_format.rb index 360da0e67e..803e5725f4 100644 --- a/app/models/question_format.rb +++ b/app/models/question_format.rb @@ -41,7 +41,8 @@ class QuestionFormat < ApplicationRecord # =============== validates :title, presence: { message: PRESENCE_MESSAGE }, - uniqueness: { message: UNIQUENESS_MESSAGE } + uniqueness: { message: UNIQUENESS_MESSAGE, + case_sensitive: false } validates :description, presence: { message: PRESENCE_MESSAGE } diff --git a/app/models/region.rb b/app/models/region.rb index e091e3721b..514671e44d 100644 --- a/app/models/region.rb +++ b/app/models/region.rb @@ -27,10 +27,12 @@ class Region < ApplicationRecord # =============== validates :name, presence: { message: PRESENCE_MESSAGE }, - uniqueness: { message: UNIQUENESS_MESSAGE } + uniqueness: { message: UNIQUENESS_MESSAGE, + case_sensitive: false } validates :description, presence: true validates :abbreviation, presence: { message: PRESENCE_MESSAGE }, - uniqueness: { message: UNIQUENESS_MESSAGE } + uniqueness: { message: UNIQUENESS_MESSAGE, + case_sensitive: false } end diff --git a/app/models/role.rb b/app/models/role.rb index d6df1e10e0..d062c15f3a 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -45,7 +45,8 @@ class Role < ApplicationRecord 3 => :editor, # 4 4 => :commenter, # 8 5 => :reviewer, # 16 - column: 'access' + column: 'access', + check_for_column: !Rails.env.test? # =============== # = Validations = diff --git a/app/models/template.rb b/app/models/template.rb index 6dae89c083..175235d0b3 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -52,6 +52,7 @@ class Template < ApplicationRecord # # The links is validated against custom validator allocated at # validators/template_links_validator.rb + attribute :links, :text, default: { funder: [], sample_plan: [] } serialize :links, JSON attribute :published, :boolean, default: false @@ -60,10 +61,7 @@ class Template < ApplicationRecord attribute :version, :integer, default: 0 attribute :customization_of, :integer, default: nil attribute :family_id, :integer, default: -> { Template.new_family_id } - attribute :links, :text, default: { funder: [], sample_plan: [] } - # TODO: re-add visibility setting? (this is handled in org_admin/create and - # relies on the org_id in the current callback-form) - attribute :visibility, :integer, default: 0 + attribute :visibility, default: Template.visibilities[:organisationally_visible] # ================ # = Associations = @@ -205,12 +203,16 @@ class Template < ApplicationRecord } # Retrieves unarchived templates whose title or org.name includes the term - # passed + # passed(We use search_term_orgs as alias for orgs to avoid issues with + # any orgs table join already present in loaded unarchived.) scope :search, lambda { |term| - unarchived.joins(:org) - .where('lower(templates.title) LIKE lower(:term) OR ' \ - 'lower(orgs.name) LIKE lower(:term)', - term: "%#{term}%") + unarchived + .joins(<<~SQL) + JOIN orgs AS search_term_orgs ON search_term_orgs.id = templates.org_id + SQL + .where('lower(templates.title) LIKE lower(:term)' \ + 'OR lower(search_term_orgs.name) LIKE lower(:term)', + term: "%#{term}%") } # defines the export setting for a template object diff --git a/app/policies/api/v1/plans_policy.rb b/app/policies/api/v1/plans_policy.rb index 005bf9a2c0..96d1cfc4b5 100644 --- a/app/policies/api/v1/plans_policy.rb +++ b/app/policies/api/v1/plans_policy.rb @@ -25,8 +25,8 @@ def resolve def plans_for_client return [] unless @user.present? - ids = @user.plans.pluck(&:id) - ids += @user.org.plans.pluck(&:id) if @user.org.present? + ids = @user.plans.pluck(:id) + ids += @user.org.plans.pluck(:id) if @user.org.present? ids.uniq end diff --git a/app/services/api/v1/deserialization_service.rb b/app/services/api/v1/deserialization_service.rb index 383cab77ad..1fe53510e0 100644 --- a/app/services/api/v1/deserialization_service.rb +++ b/app/services/api/v1/deserialization_service.rb @@ -41,7 +41,7 @@ def attach_identifier(object:, json:) # Translates the role in the json to a Contributor role def translate_role(role:) - default = ::Contributor.default_role + default = ::Contributor.role_default return default unless role.present? role = role.to_s unless role.is_a?(String) diff --git a/app/services/api/v1/persistence_service.rb b/app/services/api/v1/persistence_service.rb index 3a92230256..68c83f79da 100644 --- a/app/services/api/v1/persistence_service.rb +++ b/app/services/api/v1/persistence_service.rb @@ -38,32 +38,31 @@ def safe_save_identifier(identifier:) Identifier.transaction do identifier.save if identifier.valid? - return identifier unless identifier.new_record? end + return identifier if identifier.valid? && !identifier.new_record? Identifier.where(identifier_scheme: identifier.identifier_scheme, value: identifier.value, identifiable: identifier.identifiable).first end + # rubocop:disable Metrics/AbcSize def safe_save_org(org:) return nil unless org.is_a?(Org) Org.transaction do organization = Org.find_or_initialize_by(name: org.name) - if organization.new_record? - # Now that we know its a new record make sure its valid first - return nil unless org.valid? - + if organization.new_record? && org.valid? organization.update(saveable_attributes(attrs: org.attributes)) org.identifiers.each do |id| id.identifiable = organization.reload safe_save_identifier(identifier: id) end end - organization.reload + organization.reload if organization.valid? end end + # rubocop:enable Metrics/AbcSize # rubocop:disable Metrics/AbcSize def safe_save_contributor(contributor:) diff --git a/app/validators/answer_for_correct_template_validator.rb b/app/validators/answer_for_correct_template_validator.rb index 20723a8eb5..b76cc31a56 100644 --- a/app/validators/answer_for_correct_template_validator.rb +++ b/app/validators/answer_for_correct_template_validator.rb @@ -7,6 +7,6 @@ def validate(record) # Make sure that the question and plan belong to the same template! return unless record.plan.template == record.question.section.phase.template - record.errors[:question] << I18n.t('helpers.answer.question_must_belong_to_correct_template') + record.errors.add(:question, I18n.t('helpers.answer.question_must_belong_to_correct_template')) end end diff --git a/app/validators/email_validator.rb b/app/validators/email_validator.rb index 05e46d9efb..6a3709a13b 100644 --- a/app/validators/email_validator.rb +++ b/app/validators/email_validator.rb @@ -5,6 +5,6 @@ class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return if value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i - record.errors[attribute] << (options[:message] || 'is not a valid email address') + record.errors.add(attribute, options.fetch(:message, 'is not a valid email address')) end end diff --git a/app/validators/org_links_validator.rb b/app/validators/org_links_validator.rb index 1f720e6458..29c3a32fcf 100644 --- a/app/validators/org_links_validator.rb +++ b/app/validators/org_links_validator.rb @@ -2,15 +2,16 @@ # Validation for the format of the JSON for Org links class OrgLinksValidator < ActiveModel::Validator - include JSONLinkValidator + include JsonLinkValidator + def validate(record) links = record.links if links.is_a?(Hash) unless links.with_indifferent_access.key?('org') - record.errors[:links] << (format(_('A key "org" is expected for links hash'), key: k)) + record.errors.add(:links, format(_('A key "org" is expected for links hash'), key: k)) end else - record.errors[:links] << _('A hash is expected for links') + record.errors.add(:links, _('A hash is expected for links')) end end end diff --git a/app/validators/template_links_validator.rb b/app/validators/template_links_validator.rb index 5127a92e17..5a60216b8d 100644 --- a/app/validators/template_links_validator.rb +++ b/app/validators/template_links_validator.rb @@ -2,7 +2,7 @@ # Validation for the format of the JSON for Template links class TemplateLinksValidator < ActiveModel::Validator - include JSONLinkValidator + include JsonLinkValidator # rubocop:disable Metrics/AbcSize def validate(record) @@ -13,14 +13,14 @@ def validate(record) if links.key?(k) unless valid_links?(links[k]) msg = _('The key %{key} does not have a valid set of object links') - record.errors[:links] << (format(msg, key: k)) + record.errors.add(:links, format(msg, key: k)) end else - record.errors[:links] << (format(_('A key %{key} is expected for links hash'), key: k)) + record.errors.add(:links, format(_('A key %{key} is expected for links hash'), key: k)) end end else - record.errors[:links] << _('A hash is expected for links') + record.errors.add(:links, _('A hash is expected for links')) end end # rubocop:enable Metrics/AbcSize diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb index cdaed9416f..3f344b6ce7 100644 --- a/app/validators/url_validator.rb +++ b/app/validators/url_validator.rb @@ -6,6 +6,6 @@ def validate_each(record, attribute, value) reg = %r{https?://[-a-zA-Z0-9@:%_+.~#?&/=]{2,256}\.[a-z]{2,4}\b(/[-a-zA-Z0-9@:%_+.~#?&/=]*)?} return unless value =~ reg - record.errors[attribute] << (options[:message] || 'is not a valid URL') + record.errors.add(attribute, options.fetch(:message, 'is not a valid URL')) end end diff --git a/app/views/guidance_groups/_guidance_group_form.html.erb b/app/views/guidance_groups/_guidance_group_form.html.erb index 9b192bab28..a0384f0095 100644 --- a/app/views/guidance_groups/_guidance_group_form.html.erb +++ b/app/views/guidance_groups/_guidance_group_form.html.erb @@ -1,4 +1,4 @@ -<%# locals: form %> +<%# locals: form, allow_subset_flag %> <% name_tip = _('Add an appropriate name for your guidance group. This name will tell the end user where the guidance has come from. We suggest you use the organisation or department name e.g. "OU" or "Maths & Stats"') published_tip = _("Check this box when you are ready for guidance associated with this group to appear on user's plans.") @@ -14,10 +14,15 @@ subset_tip = _("If the guidance is only meant for a subset of users e.g. those i <%= form.check_box :published, data: { toggle: 'tooltip' }, title: published_tip %> <%= form.label :published, class: "control-label" %> -
- <%= form.check_box :optional_subset, data: { toggle: 'tooltip' }, title: subset_tip %> - <%= form.label :optional_subset, class: "control-label" %><%= _(' (e.g. School/ Department) ') %> -
+<%# Only display the optional subset flag if allowed. Otherwise default to 'false' %> +<% if allow_subset_flag %> +
+ <%= form.check_box :optional_subset, data: { toggle: 'tooltip' }, title: subset_tip %> + <%= form.label :optional_subset, class: "control-label" %><%= _(' (e.g. School/ Department) ') %> +
+<% else %> + <%= form.hidden_field :optional_subset, value: "0" %> +<% end %>
<%= form.hidden_field :org_id %> <%= form.submit _('Save'), class: "btn btn-primary" %> diff --git a/app/views/guidance_groups/admin_edit.html.erb b/app/views/guidance_groups/admin_edit.html.erb index cbd3728464..6a1413d984 100644 --- a/app/views/guidance_groups/admin_edit.html.erb +++ b/app/views/guidance_groups/admin_edit.html.erb @@ -11,7 +11,17 @@
<%= form_for(@guidance_group, url: admin_update_guidance_group_path(@guidance_group), html: { method: :put, id: "admin_update_guidance_group_form" }) do |f| %> - <%= render partial: "guidance_groups/guidance_group_form", locals: { form: f } %> + <% + allow_subset = @guidance_group.optional_subset? + allow_subset = @guidance_groups.reject { |gg| gg.optional_subset? }.length > 1 unless allow_subset + %> + <%= render partial: "guidance_groups/guidance_group_form", + locals: { + form: f, + # Don't display the optional subset if there are no GuidanceGroups that are + # not an optional subset + allow_subset_flag: allow_subset + } %> <% end %>
diff --git a/app/views/guidance_groups/admin_new.html.erb b/app/views/guidance_groups/admin_new.html.erb index be2be02205..1f99bb0a19 100644 --- a/app/views/guidance_groups/admin_new.html.erb +++ b/app/views/guidance_groups/admin_new.html.erb @@ -11,7 +11,12 @@
<%= form_for :guidance_group, url: { action: "admin_create" }, html: { id: 'admin_create_guidance_group_form' } do |f| %> - <%= render partial: "guidance_groups/guidance_group_form", locals: { form: f } %> + <%= render partial: "guidance_groups/guidance_group_form", + locals: { + form: f, + # Don't display the optional subset if there is only one GuidanceGroup + allow_subset_flag: @guidance_groups.length > 1 + } %> <% end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 079d6e3b34..889b85f939 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -61,7 +61,7 @@ <%= stylesheet_link_tag(stylesheet_manifest_file) %> - <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> + <%= javascript_pack_tag 'application', 'data-turbo-track': 'reload' %> <%= csrf_meta_tags %> diff --git a/app/views/layouts/modal_search/_form.html.erb b/app/views/layouts/modal_search/_form.html.erb index a9b469c7bf..a6a15e59cd 100644 --- a/app/views/layouts/modal_search/_form.html.erb +++ b/app/views/layouts/modal_search/_form.html.erb @@ -47,7 +47,7 @@ no_results_msg = _("No results matched your filter criteria.")