diff --git a/.dockerfiles/Dockerfile b/.dockerfiles/Dockerfile index 0c9e85dfd2..ec6483b142 100644 --- a/.dockerfiles/Dockerfile +++ b/.dockerfiles/Dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:jammy AS base ARG NODE_MAJOR=20 ARG BUNDLER_VERSION='2.4.13' +ARG RUBY_VERSION='3.3.4' ARG USER=markus # Required in order to ensure bind-mounts are owned by the correct user inside the container @@ -20,10 +21,19 @@ RUN sh /tmp/setup_node.sh COPY markus_1.0_all.deb / # Install basic system dependencies -RUN apt-get update -qq && \ +RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends /markus_1.0_all.deb && \ rm /tmp/setup_node.sh /markus_1.0_all.deb +# Install Ruby (we use ruby-install to configure the installed ruby version). +RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends wget ca-certificates sudo && \ + wget https://github.com/postmodern/ruby-install/releases/download/v0.9.3/ruby-install-0.9.3.tar.gz && \ + tar -xzvf ruby-install-0.9.3.tar.gz && \ + cd ruby-install-0.9.3/ && \ + make install && \ + ruby-install --update && \ + ruby-install --system ruby $RUBY_VERSION + # Enable reading of PDF files with imagemagick RUN sed -ri 's/(rights=")none("\s+pattern="PDF")/\1read\2/' /etc/ImageMagick-6/policy.xml @@ -71,7 +81,8 @@ RUN apt-get update -qq && \ python3 \ python3-dev \ python3-venv \ - equivs + equivs \ + libjemalloc2 # pre-create mount-points for volumes and set ownership of these mountpoints RUN mkdir -p /bundle \ @@ -110,7 +121,7 @@ COPY --chown=${USER}:${USER} .dockerfiles/database.yml.postgresql /app/config/da COPY --chown=${USER}:${USER} .dockerfiles/git-ssh.rc /home/${USER}/.ssh/rc # Install bundler -RUN gem install bundler -v $BUNDLER_VERSION +RUN gem install bundler -v $BUNDLER_VERSION && bundle config set --local without 'development test offline production_test' USER $USER @@ -121,7 +132,7 @@ ENV RAILS_ENV=production ENV NODE_ENV=production # Install gems -RUN SECRET_KEY_BASE=1 bundle install --deployment --without development test offline production_test +RUN SECRET_KEY_BASE=1 bundle install --deployment # Precompile assets RUN SECRET_KEY_BASE=1 NO_SCHEMA_VALIDATE=true NO_INIT_SCHEDULER=true PGDATABASE=dummy bundle exec rails assets:precompile diff --git a/.dockerfiles/entrypoint-dev-rails.sh b/.dockerfiles/entrypoint-dev-rails.sh index b7a5b9bfc1..ca9e946f71 100755 --- a/.dockerfiles/entrypoint-dev-rails.sh +++ b/.dockerfiles/entrypoint-dev-rails.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash +# Enable jemalloc for reduced memory usage and latency. +if [ -z "${LD_PRELOAD+x}" ] && [ -f /usr/lib/*/libjemalloc.so.2 ]; then + export LD_PRELOAD="$(echo /usr/lib/*/libjemalloc.so.2)" +fi + # install bundle gems if not up to date with the Gemfile.lock file -bundle check 2>/dev/null || bundle install --without unicorn +bundle check 2>/dev/null || bundle install # install node packages npm list &> /dev/null || npm ci diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index ae24d080b9..96c5c9fedd 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -49,7 +49,7 @@ jobs: - name: Set up ruby and cache gems uses: ruby/setup-ruby@v1 with: - ruby-version: ruby-3.0 + ruby-version: ruby-3.3 bundler-cache: true - name: Set up node and cache packages uses: actions/setup-node@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 72a408511d..d7b0b4ed8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,14 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: + - id: check-illegal-windows-names + - id: check-json + exclude: | + (?x)^( + spec/fixtures/files/.* + )$ + - id: check-merge-conflict - id: check-yaml exclude: | (?x)^( @@ -15,7 +22,7 @@ repos: - id: prettier types_or: [javascript, jsx, css, scss, html] - repo: https://github.com/thibaudcolas/pre-commit-stylelint - rev: v16.6.1 + rev: v16.10.0 hooks: - id: stylelint additional_dependencies: [ @@ -32,7 +39,7 @@ repos: app/assets/stylesheets/common/_reset.scss )$ - repo: https://github.com/rubocop/rubocop - rev: v1.64.1 + rev: v1.68.0 hooks: - id: rubocop args: ["--autocorrect"] @@ -45,11 +52,12 @@ repos: Vagrantfile )$ additional_dependencies: - - rubocop-rails:2.24.1 - - rubocop-performance:1.21.0 - - rubocop-factory_bot:2.25.1 - - rubocop-rspec:2.28.0 - - rubocop-rspec_rails:2.28.2 + - rubocop-rails:2.26.1 + - rubocop-performance:1.22.1 + - rubocop-factory_bot:2.26.1 + - rubocop-rspec:3.0.5 + - rubocop-rspec_rails:2.30.0 + - rubocop-capybara:2.21.0 exclude: vendor diff --git a/.rubocop.yml b/.rubocop.yml index 06188e0ba1..90a8a1e378 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,6 +4,7 @@ require: - rubocop-factory_bot - rubocop-rspec - rubocop-rspec_rails + - rubocop-capybara AllCops: Exclude: @@ -209,9 +210,6 @@ RSpec/ExampleWording: RSpec/ExpectChange: EnforcedStyle: block -RSpec/FactoryBot: # Extracted into rubocop-factory_bot gem - Enabled: false - RSpec/IndexedLet: Enabled: false @@ -242,9 +240,6 @@ RSpec/NestedGroups: RSpec/PendingWithoutReason: Enabled: false -RSpec/Rails: # Extracted into rubocop-factory_bot gem - Enabled: false - RSpec/ScatteredLet: Exclude: - spec/policies/**/*.rb @@ -364,6 +359,9 @@ Style/RedundantSelfAssignmentBranch: Style/ReturnNil: Enabled: true +Style/SafeNavigationChainLength: + Enabled: false + Style/SelectByRegexp: Enabled: true diff --git a/Changelog.md b/Changelog.md index c897bec2cd..35e84309ad 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,9 +1,44 @@ # Changelog -## [v2.5.3] +## [v2.6.0] + +### ✨ New features and improvements + +- Prevent instructors from unassigning peer reviewers who have existing peer review data (#7263) +- Add visual indicator on a per-assignment basis for used grace credits (#7226) +- Change default disabled text area colour to ligher grey on light mode (#7269) +- Implement a limit on the file size rendered by the submission viewer (#7273) +- Add an option to retain old grading data when recollecting graded submissions (#7256) ### 🐛 Bug fixes +- Fix incorrect calculation of token penalties when submissions are on time (#7216) +- Ensured submissions that have been released cannot be recollected from the repo browser (#7254) +- Fix bug where renaming a group to an existing group in a different assignment resulted in incorrect repository mapping (#7224) +- Disable editable fields in assignment criterion when criterion is released (#7264) +- Fixed Download One Time Annotation 'Not Found' error (#7302) + +### 🔧 Internal changes + +- Fix test coverage for ExamTemplate.create_with_file method (#7213) +- Upgrade Docker environment to use Ruby v3.3 (#7185) +- Upgrade to Rails v7.2 (#7185) +- Move Exception message in student model to a localization file (#7218) +- Add test cases for the student model to cover Group or Grouping save method failure (#7218) +- Create tests for overtime messages of the submission rule classes (#7216) +- Fix flaky `check_repo_permissions` test (#7223) +- Move model validation error messages to respective localization files (#7229) +- Replace time-warp gem with newer, maintained timecop gem (#7234) +- Update pre-commit-hooks to v5.0 and add checks `check-illegal-windows-names`, `check-json`, and `check-merge-conflict` (#7259) +- Merge result.js and result_main.css build files into application.js/application.css (#7260) +- Simplify pdf.js configuration (#7260) +- Improve descriptions of the Group and Grouping models (#7262) +- Disable Rubocop Style/SafeNavigationChainLength check (#7301) +- Ignore faker translations in i18n-js compilation (#7305) + +## [v2.5.3] + +### 🐛 Bug fixes - Fix Marks Spreadsheet csv bug of showing incorrect marks (#7257) - Fix incorrect inclusion of course parameter in LtiSyncJob (#7258) - Fix Google Colab Jupyter Notebooks rendering by excluding widgets (#7271) diff --git a/Gemfile b/Gemfile index bb62bc0e7a..b9ef976c48 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ source 'https://rubygems.org' # Bundler requires these gems in all environments gem 'puma' -gem 'rails', '~> 7.1.3' +gem 'rails', '~> 7.2.2' gem 'sprockets' gem 'sprockets-rails' @@ -40,7 +40,7 @@ gem 'i18n-js' gem 'rails-i18n', '~> 7.0.0' # Redis -gem 'redis', '~> 4.8.1' +gem 'redis', '~> 5.3.0' # Exam template requirements gem 'combine_pdf' @@ -50,6 +50,7 @@ gem 'rmagick', '~> 6.0.1' gem 'rtesseract' # Ruby miscellany +gem 'csv' gem 'json' gem 'mini_mime' gem 'redcarpet' @@ -90,11 +91,12 @@ group :test do gem 'fuubar' gem 'machinist', '< 3' gem 'rails-controller-testing' - gem 'shoulda' gem 'shoulda-callback-matchers', '~> 1.1.1' + gem 'shoulda-context', '~> 3.0.0.rc1' + gem 'shoulda-matchers', '~> 6.0' gem 'simplecov', require: false gem 'simplecov-lcov', require: false - gem 'time-warp' + gem 'timecop' gem 'webmock' end @@ -105,7 +107,7 @@ group :development, :test do gem 'capybara' gem 'debug', '>= 1.0.0' gem 'i18n-tasks', require: false - gem 'rspec-rails', '~> 6.1.3' + gem 'rspec-rails', '~> 7.0.1' gem 'selenium-webdriver' end diff --git a/Gemfile.lock b/Gemfile.lock index a4ba3e3ea1..6ad23284f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,70 +3,65 @@ GEM specs: action_policy (0.7.1) ruby-next-core (>= 1.0) - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (7.2.2) + actionpack (= 7.2.2) + activesupport (= 7.2.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3.4) - actionpack (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (7.2.2) + actionpack (= 7.2.2) + activejob (= 7.2.2) + activerecord (= 7.2.2) + activestorage (= 7.2.2) + activesupport (= 7.2.2) + mail (>= 2.8.0) + actionmailer (7.2.2) + actionpack (= 7.2.2) + actionview (= 7.2.2) + activejob (= 7.2.2) + activesupport (= 7.2.2) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.3.4) - actionview (= 7.1.3.4) - activesupport (= 7.1.3.4) + actionpack (7.2.2) + actionview (= 7.2.2) + activesupport (= 7.2.2) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.2) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.4) - actionpack (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + useragent (~> 0.16) + actiontext (7.2.2) + actionpack (= 7.2.2) + activerecord (= 7.2.2) + activestorage (= 7.2.2) + activesupport (= 7.2.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (7.2.2) + activesupport (= 7.2.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.4) - activesupport (= 7.1.3.4) + activejob (7.2.2) + activesupport (= 7.2.2) globalid (>= 0.3.6) activejob-status (1.0.1) activejob (>= 6.0) activesupport (>= 6.0) - activemodel (7.1.3.4) - activesupport (= 7.1.3.4) - activemodel-serializers-xml (1.0.2) - activemodel (> 5.x) - activesupport (> 5.x) + activemodel (7.2.2) + activesupport (= 7.2.2) + activemodel-serializers-xml (1.0.3) + activemodel (>= 5.0.0.a) + activesupport (>= 5.0.0.a) builder (~> 3.1) - activerecord (7.1.3.4) - activemodel (= 7.1.3.4) - activesupport (= 7.1.3.4) + activerecord (7.2.2) + activemodel (= 7.2.2) + activesupport (= 7.2.2) timeout (>= 0.4.0) activerecord-session_store (2.1.0) actionpack (>= 6.1) @@ -75,29 +70,32 @@ GEM multi_json (~> 1.11, >= 1.11.2) rack (>= 2.0.8, < 4) railties (>= 6.1) - activestorage (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activesupport (= 7.1.3.4) + activestorage (7.2.2) + actionpack (= 7.2.2) + activejob (= 7.2.2) + activerecord (= 7.2.2) + activesupport (= 7.2.2) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (7.2.2) base64 + benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) - autoprefixer-rails (10.4.16.0) + autoprefixer-rails (10.4.19.0) execjs (~> 2) awesome_print (1.9.2) base64 (0.2.0) + benchmark (0.4.0) better_errors (2.10.1) erubi (>= 1.0.0) rack (>= 0.9.0) @@ -105,11 +103,11 @@ GEM bigdecimal (3.1.8) binding_of_caller (1.0.1) debug_inspector (>= 1.2.0) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (6.1.2) + brakeman (6.2.2) racc - browser (5.3.1) + browser (6.0.0) builder (3.3.0) bullet (7.2.0) activesupport (>= 3.0.0) @@ -123,14 +121,15 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - cgi (0.3.6) + cgi (0.4.1) chunky_png (1.4.0) combine_pdf (1.0.26) matrix ruby-rc4 (>= 0.1.5) concurrent-ruby (1.3.4) - config (5.5.1) + config (5.5.2) deep_merge (~> 1.2, >= 1.2.1) + ostruct connection_pool (2.4.1) cookies_eu (1.7.8) js_cookie_rails (~> 2.2.0) @@ -140,7 +139,8 @@ GEM crass (1.0.6) cssbundling-rails (1.4.1) railties (>= 6.0.0) - date (3.3.4) + csv (3.3.0) + date (3.4.0) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) @@ -188,13 +188,13 @@ GEM exception_notification (4.5.0) actionmailer (>= 5.2, < 8) activesupport (>= 5.2, < 8) - execjs (2.9.1) - factory_bot (6.4.5) + execjs (2.10.0) + factory_bot (6.5.0) activesupport (>= 5.0.0) - factory_bot_rails (6.4.3) - factory_bot (~> 6.4) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) railties (>= 5.0.0) - faker (3.4.2) + faker (3.5.1) i18n (>= 1.8.11, < 2) ffi (1.16.3) fugit (1.11.1) @@ -206,10 +206,10 @@ GEM glob (0.4.0) globalid (1.2.1) activesupport (>= 6.1) - hashdiff (1.1.0) + hashdiff (1.1.1) highline (3.0.1) histogram (0.2.4.1) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) i18n-js (4.2.3) glob (>= 0.4.0) @@ -225,7 +225,7 @@ GEM rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) io-console (0.7.2) - irb (1.14.0) + irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) js-routes (2.2.8) @@ -234,15 +234,15 @@ GEM railties (>= 3.1) jsbundling-rails (1.3.1) railties (>= 6.0.0) - json (2.7.2) - jwt (2.8.2) + json (2.7.5) + jwt (2.9.3) base64 kgio (2.11.4) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.0) - loofah (2.22.0) + logger (1.6.1) + loofah (2.23.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) machinist (2.0) @@ -255,14 +255,13 @@ GEM matrix (0.4.2) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.24.1) + minitest (5.25.1) mono_logger (1.1.2) msgpack (1.7.2) multi_json (1.15.0) mustermann (3.0.0) ruby2_keywords (~> 0.0.1) - mutex_m (0.2.0) - net-imap (0.4.12) + net-imap (0.5.1) date net-protocol net-pop (0.1.2) @@ -271,16 +270,17 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.3) + nio4r (2.7.4) nokogiri (1.16.7) mini_portile2 (~> 2.8.2) racc (~> 1.4) observer (0.1.2) + ostruct (0.6.0) parser (3.3.2.0) ast (~> 2.4.1) racc pdf-core (0.10.0) - pg (1.5.7) + pg (1.5.9) pkg-config (1.5.6) pluck_to_hash (1.0.2) activerecord (>= 4.0.2) @@ -292,14 +292,14 @@ GEM prawn-qrcode (0.5.2) prawn (>= 1) rqrcode (>= 1.0.0) - psych (5.1.2) + psych (5.2.0) stringio - public_suffix (5.0.5) + public_suffix (6.0.1) puma (6.4.3) nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) - rack (2.2.9) + rack (2.2.10) rack-cors (2.0.2) rack (>= 2.0.0) rack-protection (3.1.0) @@ -311,20 +311,20 @@ GEM rackup (1.0.0) rack (< 3) webrick - rails (7.1.3.4) - actioncable (= 7.1.3.4) - actionmailbox (= 7.1.3.4) - actionmailer (= 7.1.3.4) - actionpack (= 7.1.3.4) - actiontext (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activemodel (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + rails (7.2.2) + actioncable (= 7.2.2) + actionmailbox (= 7.2.2) + actionmailer (= 7.2.2) + actionpack (= 7.2.2) + actiontext (= 7.2.2) + actionview (= 7.2.2) + activejob (= 7.2.2) + activemodel (= 7.2.2) + activerecord (= 7.2.2) + activestorage (= 7.2.2) + activesupport (= 7.2.2) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 7.2.2) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -339,15 +339,15 @@ GEM rails-i18n (7.0.3) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - rails_performance (1.2.2) + rails_performance (1.2.3) browser railties redis redis-namespace - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + railties (7.2.2) + actionpack (= 7.2.2) + activesupport (= 7.2.2) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) @@ -361,11 +361,14 @@ GEM rdoc (6.7.0) psych (>= 4.0.0) redcarpet (3.6.0) - redis (4.8.1) + redis (5.3.0) + redis-client (>= 0.22.0) + redis-client (0.22.2) + connection_pool redis-namespace (1.11.0) redis (>= 4) regexp_parser (2.9.0) - reline (0.5.9) + reline (0.5.11) io-console (~> 0.5) responders (3.1.1) actionpack (>= 5.2) @@ -380,8 +383,7 @@ GEM redis (>= 3.3) resque (>= 1.27) rufus-scheduler (~> 3.2, != 3.3) - rexml (3.3.6) - strscan + rexml (3.3.9) rmagick (6.0.1) observer (~> 0.1) pkg-config (~> 1.4) @@ -390,18 +392,18 @@ GEM chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) - rspec-core (3.13.0) + rspec-core (3.13.1) rspec-support (~> 3.13.0) - rspec-expectations (3.13.1) + rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.3) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) + rspec-rails (7.0.1) + actionpack (>= 7.0) + activesupport (>= 7.0) + railties (>= 7.0) rspec-core (~> 3.13) rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) @@ -416,20 +418,18 @@ GEM rufus-scheduler (3.9.1) fugit (~> 1.1, >= 1.1.6) rugged (1.7.2) - selenium-webdriver (4.23.0) + securerandom (0.3.1) + selenium-webdriver (4.25.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - shoulda (4.0.0) - shoulda-context (~> 2.0) - shoulda-matchers (~> 4.0) shoulda-callback-matchers (1.1.4) activesupport (>= 3) - shoulda-context (2.0.0) - shoulda-matchers (4.3.0) - activesupport (>= 4.2.0) + shoulda-context (3.0.0.rc1) + shoulda-matchers (6.4.0) + activesupport (>= 5.2.0) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -449,16 +449,15 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - stringio (3.1.1) - strscan (3.1.0) + stringio (3.1.2) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - terser (1.2.3) + terser (1.2.4) execjs (>= 0.3.0, < 3) - thor (1.3.1) + thor (1.3.2) tilt (2.3.0) - time-warp (1.0.15) - timeout (0.4.1) + timecop (0.9.10) + timeout (0.4.2) ttfunk (1.8.0) bigdecimal (~> 3.1) tzinfo (2.0.6) @@ -468,18 +467,19 @@ GEM kgio (~> 2.6) raindrops (~> 0.7) uniform_notifier (1.16.0) - webmock (3.23.1) + useragent (0.16.10) + webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.8.2) + webrick (1.9.0) websocket (1.2.11) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.17) + zeitwerk (2.7.1) PLATFORMS ruby @@ -501,6 +501,7 @@ DEPENDENCIES config cookies_eu cssbundling-rails (~> 1.4) + csv debug (>= 1.0.0) descriptive_statistics dry-validation @@ -526,32 +527,33 @@ DEPENDENCIES prawn-qrcode puma rack-cors - rails (~> 7.1.3) + rails (~> 7.2.2) rails-controller-testing rails-html-sanitizer rails-i18n (~> 7.0.0) rails_performance redcarpet - redis (~> 4.8.1) + redis (~> 5.3.0) responders resque resque-scheduler rmagick (~> 6.0.1) - rspec-rails (~> 6.1.3) + rspec-rails (~> 7.0.1) rtesseract rubyzip rugged selenium-webdriver - shoulda shoulda-callback-matchers (~> 1.1.1) + shoulda-context (~> 3.0.0.rc1) + shoulda-matchers (~> 6.0) simplecov simplecov-lcov sprockets sprockets-rails terser - time-warp + timecop unicorn webmock BUNDLED WITH - 2.4.13 + 2.5.17 diff --git a/app/MARKUS_VERSION b/app/MARKUS_VERSION index 834f068caf..f8c2d0c7ec 100644 --- a/app/MARKUS_VERSION +++ b/app/MARKUS_VERSION @@ -1 +1 @@ -VERSION=v2.5.3,PATCH_LEVEL=DEV +VERSION=v2.6.0,PATCH_LEVEL=DEV diff --git a/app/assets/javascripts/Components/Helpers/tag_modal.jsx b/app/assets/javascripts/Components/Helpers/tag_modal.jsx index 829d98f59d..310268eb11 100644 --- a/app/assets/javascripts/Components/Helpers/tag_modal.jsx +++ b/app/assets/javascripts/Components/Helpers/tag_modal.jsx @@ -11,7 +11,7 @@ export default class TagModal extends React.Component { render() { return ( { + this.setState({retain_existing_grading: event.target.checked}); + }; + handleCollectTimeChange = event => { this.setState({collect_time: event.target.value}); }; @@ -55,7 +61,7 @@ class CollectSubmissionsModal extends React.Component { render() { return ( @@ -96,15 +102,47 @@ class CollectSubmissionsModal extends React.Component { {I18n.t("submissions.collect.collection_options")}

+ {this.state.override && ( +

+ +   + + {!this.state.retain_existing_grading && ( +

+ {I18n.t("submissions.collect.grading_data_will_be_lost")} +
+ )} +

+ )} {this.state.collect_time === "collect_current" && !this.props.isScannedExam && (

- +
diff --git a/app/assets/javascripts/Components/Modals/create_modify_annotation_panel_modal.jsx b/app/assets/javascripts/Components/Modals/create_modify_annotation_panel_modal.jsx index 6fb5e8b8b6..097a0c442b 100644 --- a/app/assets/javascripts/Components/Modals/create_modify_annotation_panel_modal.jsx +++ b/app/assets/javascripts/Components/Modals/create_modify_annotation_panel_modal.jsx @@ -191,7 +191,7 @@ class CreateModifyAnnotationPanel extends React.Component { return ( diff --git a/app/assets/javascripts/Components/Modals/extension_modal.jsx b/app/assets/javascripts/Components/Modals/extension_modal.jsx index 225600a0cf..e54387fad5 100644 --- a/app/assets/javascripts/Components/Modals/extension_modal.jsx +++ b/app/assets/javascripts/Components/Modals/extension_modal.jsx @@ -127,7 +127,7 @@ class ExtensionModal extends React.Component { render() { return ( diff --git a/app/assets/javascripts/Components/Modals/filter_modal.jsx b/app/assets/javascripts/Components/Modals/filter_modal.jsx index fb06902d22..18b0b7aaa4 100644 --- a/app/assets/javascripts/Components/Modals/filter_modal.jsx +++ b/app/assets/javascripts/Components/Modals/filter_modal.jsx @@ -199,7 +199,7 @@ export class FilterModal extends React.Component { } return ( { this.props.onRequestClose(); diff --git a/app/assets/javascripts/Components/Modals/graders_distribution_modal.jsx b/app/assets/javascripts/Components/Modals/graders_distribution_modal.jsx index 6843a64290..76b5a21b15 100644 --- a/app/assets/javascripts/Components/Modals/graders_distribution_modal.jsx +++ b/app/assets/javascripts/Components/Modals/graders_distribution_modal.jsx @@ -45,7 +45,7 @@ export class GraderDistributionModal extends React.Component { render() { return ( diff --git a/app/assets/javascripts/Components/Modals/roster_sync_modal.jsx b/app/assets/javascripts/Components/Modals/roster_sync_modal.jsx index b59194196f..a8162f9f20 100644 --- a/app/assets/javascripts/Components/Modals/roster_sync_modal.jsx +++ b/app/assets/javascripts/Components/Modals/roster_sync_modal.jsx @@ -47,7 +47,7 @@ class LtiRosterModal extends React.Component { return (
diff --git a/app/assets/javascripts/Components/Modals/section_distribution_modal.js b/app/assets/javascripts/Components/Modals/section_distribution_modal.js index 3ea46e9ec0..ba93dc0396 100644 --- a/app/assets/javascripts/Components/Modals/section_distribution_modal.js +++ b/app/assets/javascripts/Components/Modals/section_distribution_modal.js @@ -53,7 +53,7 @@ export class SectionDistributionModal extends React.Component { render() { return ( diff --git a/app/assets/javascripts/Components/Modals/send_lti_grades_modal.jsx b/app/assets/javascripts/Components/Modals/send_lti_grades_modal.jsx index 4cacc01a68..cff431ef15 100644 --- a/app/assets/javascripts/Components/Modals/send_lti_grades_modal.jsx +++ b/app/assets/javascripts/Components/Modals/send_lti_grades_modal.jsx @@ -49,7 +49,7 @@ class LtiGradeModal extends React.Component { render() { return ( diff --git a/app/assets/javascripts/Components/Result/feedback_file_panel.jsx b/app/assets/javascripts/Components/Result/feedback_file_panel.jsx index 80c10944c9..ed560a6df1 100644 --- a/app/assets/javascripts/Components/Result/feedback_file_panel.jsx +++ b/app/assets/javascripts/Components/Result/feedback_file_panel.jsx @@ -80,7 +80,11 @@ export class FeedbackFilePanel extends React.Component { {feedbackSelector} {download_feedback_file}
-
+
{ + if (file_type in MAX_FILE_SIZES) { + return file_size > MAX_FILE_SIZES[file_type]; + } else { + return file_size > MAX_FILE_SIZES._default; + } +}; + export class FileViewer extends React.Component { // this.props.result_id is used as a flag for the component to // know whether it is displaying within the result view. @@ -18,6 +38,7 @@ export class FileViewer extends React.Component { content: "", type: "", url: "", + size: 0, loading: true, }; } @@ -101,7 +122,7 @@ export class FileViewer extends React.Component { (!this.props.result_id && this.props.selectedFile === null) || submission_file_id === null ) { - this.setState({loading: false, type: ""}); + this.setState({loading: false, size: 0, type: ""}); return; } force_text = !!force_text; @@ -111,17 +132,25 @@ export class FileViewer extends React.Component { this.remove(); }); - this.setState({loading: true, url: null}, () => { + this.setState({loading: true, size: 0, url: null}, () => { if (!this.props.selectedFileURL) { fetch( Routes.get_file_course_submission_path(this.props.course_id, this.props.submission_id, { submission_file_id: submission_file_id, force_text: force_text, + max_content_size: MAX_FILE_SIZES.text, }), {credentials: "include"} ) .then(res => res.json()) .then(body => { + this.setState({size: body.size, type: body.type}); + + if (isFileTooLarge(body.size, body.type)) { + this.setState({loading: false}); + return; + } + if (body.type === "image" || body.type === "pdf" || this.isNotebook(body.type)) { this.setState({type: body.type}, () => { this.setFileUrl(submission_file_id); @@ -190,6 +219,8 @@ export class FileViewer extends React.Component { } if (this.state.loading) { return I18n.t("working"); + } else if (isFileTooLarge(this.state.size, this.state.type)) { + return I18n.t("submissions.oversize_submission_file"); } else if (this.state.type === "image") { return ; } else if (this.state.type === "pdf") { diff --git a/app/assets/javascripts/Components/Result/submission_file_panel.jsx b/app/assets/javascripts/Components/Result/submission_file_panel.jsx index 3ac61c136d..c34c3fd53b 100644 --- a/app/assets/javascripts/Components/Result/submission_file_panel.jsx +++ b/app/assets/javascripts/Components/Result/submission_file_panel.jsx @@ -180,7 +180,7 @@ export class SubmissionFilePanel extends React.Component { /> )}
-
+

-