Skip to content
Merged

v2.10.3 #8165

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1248ceb
build(deps-dev): bump ruby-lsp from 0.26.9 to 0.26.11 (#8141)
dependabot[bot] Sep 6, 2026
f021d99
build(deps): bump i18n-js from 4.5.1 to 4.5.3 (#8140)
dependabot[bot] Sep 6, 2026
ce0dcdb
build(deps): bump fast-uri (#8146)
dependabot[bot] Sep 6, 2026
2ba5ae4
build(deps): bump mail from 2.9.0 to 2.9.1 (#8149)
dependabot[bot] Sep 6, 2026
1427b80
build(deps-dev): bump selenium-webdriver from 4.46.0 to 4.48.0 (#8143)
dependabot[bot] Sep 6, 2026
49a9953
build(deps-dev): bump annotaterb from 4.22.0 to 4.24.0 (#8144)
dependabot[bot] Sep 6, 2026
feb8b6e
build(deps): bump pghero from 3.8.0 to 4.0.1 (#8137)
dependabot[bot] Sep 6, 2026
7ca98eb
build(deps): bump js-routes from 2.3.7 to 2.4.1 (#8145)
dependabot[bot] Sep 6, 2026
06fb69f
Upgraded jest and jest-environment-jsdom to v30.5.1 (#8151)
david-yz-liu Sep 6, 2026
e25107f
build(deps-dev): bump jekyll-relative-links from 0.7.0 to 0.8.0 (#8152)
dependabot[bot] Sep 7, 2026
561d92a
build(deps): bump dompurify from 3.4.13 to 3.4.14 (#8159)
dependabot[bot] Sep 7, 2026
e9ce1b6
build(deps-dev): bump bootsnap from 1.24.6 to 1.25.0 (#8158)
dependabot[bot] Sep 7, 2026
9373026
build(deps): bump i18n-js from 4.2.3 to 4.2.4 (#8157)
dependabot[bot] Sep 7, 2026
64f7cd4
build(deps): bump rugged from 1.9.0 to 1.9.6 (#8156)
dependabot[bot] Sep 7, 2026
a024815
build(deps): bump jquery-ui from 1.14.1 to 1.14.2 (#8155)
dependabot[bot] Sep 7, 2026
0f49a6a
build(deps): bump playwright from 1.61.0 to 1.62.0 (#8117)
dependabot[bot] Sep 7, 2026
e3f3424
build(deps): bump katex from 0.16.33 to 0.18.5 (#8154)
dependabot[bot] Sep 7, 2026
f0d604c
Enforced privileged LTI launch role for course linking and creation (…
donny-wong Sep 9, 2026
a4999b8
Extended API assignment routes to support multiple submission periods…
sophia-huynh Sep 9, 2026
c07143e
Fixed scanned exam PDFs rendering blank by configuring pdf.js wasmUrl…
donny-wong Sep 14, 2026
5c29d77
v2.10.3
Naragod Sep 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ updates:
fortawesome:
patterns:
- "@fortawesome*"
jest:
patterns:
- "jest"
- "jest-environment-jsdom"
rails:
patterns:
- "@rails*"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dump.rdb
/public/packs
/public/packs-test
/public/javascripts
/public/wasm
/app/assets/builds/*
!/app/assets/builds/.keep
/node_modules
Expand Down
12 changes: 11 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@
### ✨ New features and improvements

### 🐛 Bug fixes
- Fixed production webpack builds compiling JSX in development mode (#8150)

### 📚 Documentation changes

### 🔧 Internal changes

## [v2.10.3]

### ✨ New features and improvements
- Updated POST and PUT assignment API routes to allow for multiple submission rule periods (#8128)

### 🐛 Bug fixes
- Fixed scanned exam PDFs rendering as blank pages by pointing pdf.js at its wasm image decoders (#8164)
- Enforce privileged LTI launch role for course linking and creation (#8130)

## [v2.10.2]

### 🛡️ Security
Expand Down
54 changes: 27 additions & 27 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ GEM
uri (>= 0.13.1)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
annotaterb (4.22.0)
annotaterb (4.24.0)
activerecord (>= 6.0.0)
activesupport (>= 6.0.0)
ast (2.4.3)
Expand All @@ -101,8 +101,8 @@ GEM
bigdecimal (3.3.1)
binding_of_caller (2.0.0)
debug_inspector (>= 1.2.0)
bootsnap (1.24.6)
msgpack (~> 1.2)
bootsnap (1.25.0)
msgpack (~> 1.5)
brakeman (8.0.5)
racc
browser (6.2.0)
Expand Down Expand Up @@ -184,7 +184,7 @@ GEM
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
erb (6.0.4)
erb (6.0.7)
erubi (1.13.1)
et-orbi (1.4.1)
tzinfo
Expand All @@ -199,18 +199,18 @@ GEM
railties (>= 6.1.0)
faker (3.8.0)
i18n (>= 1.8.11, < 2)
ffi (1.16.3)
ffi (1.17.4)
forwardable-extended (2.6.0)
fugit (1.13.0)
et-orbi (~> 1.4)
raabro (~> 1.4)
fuubar (2.5.1)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
glob (0.4.0)
glob (0.5.0)
globalid (1.3.0)
activesupport (>= 6.1)
google-protobuf (4.35.1)
google-protobuf (4.36.1)
bigdecimal
rake (~> 13.3)
hashdiff (1.2.1)
Expand All @@ -220,7 +220,7 @@ GEM
http_parser.rb (0.8.1)
i18n (1.15.2)
concurrent-ruby (~> 1.0)
i18n-js (4.2.3)
i18n-js (4.2.4)
glob (>= 0.4.0)
i18n
i18n-tasks (1.1.2)
Expand All @@ -235,7 +235,7 @@ GEM
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.8, >= 1.8.1)
terminal-table (>= 1.5.1)
io-console (0.8.2)
io-console (0.9.2)
irb (1.18.0)
pp (>= 0.6.0)
prism (>= 1.3.0)
Expand All @@ -262,15 +262,15 @@ GEM
webrick (~> 1.7)
jekyll-include-cache (0.2.1)
jekyll (>= 3.7, < 5.0)
jekyll-relative-links (0.7.0)
jekyll-relative-links (0.8.0)
jekyll (>= 3.3, < 5.0)
jekyll-sass-converter (3.1.0)
sass-embedded (~> 1.75)
jekyll-seo-tag (2.9.0)
jekyll (>= 3.8, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
js-routes (2.3.7)
js-routes (2.4.1)
railties (>= 5)
sorbet-runtime
js_cookie_rails (2.2.0)
Expand All @@ -290,7 +290,7 @@ GEM
rexml (>= 3.4.4)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
language_server-protocol (3.17.0.5)
language_server-protocol (3.17.0.6)
liquid (4.0.4)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
Expand All @@ -300,7 +300,7 @@ GEM
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
machinist (2.0)
mail (2.9.0)
mail (2.9.1)
logger
mini_mime (>= 0.1.1)
net-imap
Expand All @@ -318,12 +318,12 @@ GEM
msgpack (1.8.4)
multi_json (1.21.1)
mustermann (3.1.1)
net-imap (0.6.4.1)
net-imap (0.6.6)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
net-protocol (0.3.0)
timeout
net-smtp (0.5.1)
net-protocol
Expand All @@ -340,7 +340,7 @@ GEM
forwardable-extended (~> 2.6)
pdf-core (0.10.0)
pg (1.6.3)
pghero (3.8.0)
pghero (4.0.1)
activerecord (>= 7.2)
pkg-config (1.6.5)
pluck_to_hash (1.0.2)
Expand All @@ -366,7 +366,7 @@ GEM
nio4r (~> 2.0)
raabro (1.5.0)
racc (1.8.1)
rack (3.2.6)
rack (3.2.7)
rack-cors (3.0.0)
logger
rack (>= 3.0.14)
Expand Down Expand Up @@ -426,9 +426,9 @@ GEM
raindrops (0.20.0)
rake (13.4.2)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
rb-inotify (0.11.1)
ffi (~> 1.0)
rbs (4.0.2)
rbs (4.2.0)
logger
prism (>= 1.6.0)
tsort
Expand All @@ -445,7 +445,7 @@ GEM
redis-namespace (1.11.0)
redis (>= 4)
regexp_parser (2.9.0)
reline (0.6.3)
reline (0.7.0)
io-console (~> 0.5)
responders (3.1.1)
actionpack (>= 5.2)
Expand All @@ -469,7 +469,7 @@ GEM
rmagick (7.0.5)
observer (~> 0.1)
pkg-config (~> 1.4)
rouge (4.1.3)
rouge (4.7.0)
rqrcode (2.2.0)
chunky_png (~> 1.0)
rqrcode_core (~> 1.0)
Expand All @@ -492,7 +492,7 @@ GEM
rspec-support (>= 3.13.0, < 5.0.0)
rspec-support (3.13.7)
rtesseract (3.1.4)
ruby-lsp (0.26.9)
ruby-lsp (0.26.11)
language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0)
rbs (>= 3, < 5)
Expand All @@ -502,13 +502,13 @@ GEM
rubyzip (3.4.1)
rufus-scheduler (3.9.2)
fugit (~> 1.1, >= 1.11.1)
rugged (1.9.0)
rugged (1.9.6)
safe_yaml (1.0.5)
sass-embedded (1.101.0)
sass-embedded (1.104.0)
google-protobuf (~> 4.31)
rake (>= 13)
securerandom (0.4.1)
selenium-webdriver (4.46.0)
selenium-webdriver (4.48.0)
base64 (~> 0.2)
logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5)
Expand All @@ -533,7 +533,7 @@ GEM
rack-protection (= 4.2.1)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
sorbet-runtime (0.6.13266)
sorbet-runtime (0.6.13459)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
thor (1.5.0)
Expand Down Expand Up @@ -564,7 +564,7 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.8.2)
zeitwerk (2.8.3)

PLATFORMS
ruby
Expand Down
2 changes: 1 addition & 1 deletion app/MARKUS_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION=v2.10.2,PATCH_LEVEL=DEV
VERSION=v2.10.3,PATCH_LEVEL=DEV
64 changes: 37 additions & 27 deletions app/controllers/api/assignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ def show
# Creates a new assignment
# Requires: short_identifier, due_date, description
# Optional: repository_folder, group_min, group_max, tokens_per_period,
# submission_rule_type, allow_web_submits,
# submission_rule_type, submission_rule_periods, allow_web_submits,
# display_grader_names_to_students, enable_test, assign_graders_to_criteria,
# message, allow_remarks, remark_due_date, remark_message, student_form_groups,
# group_name_autogenerated, submission_rule_deduction, submission_rule_hours,
# submission_rule_interval
# group_name_autogenerated
def create
if has_missing_params?([:short_identifier, :due_date, :description])
# incomplete/invalid HTTP params
Expand Down Expand Up @@ -101,11 +100,10 @@ def create
# Updates an existing assignment
# Requires: id
# Optional: short_identifier, due_date,repository_folder, group_min, group_max,
# tokens_per_period, submission_rule_type, allow_web_submits,
# tokens_per_period, submission_rule_type, submission_rule_periods, allow_web_submits,
# display_grader_names_to_students, enable_test, assign_graders_to_criteria,
# description, message, allow_remarks, remark_due_date, remark_message,
# student_form_groups, group_name_autogenerated, submission_rule_deduction,
# submission_rule_hours, submission_rule_interval, starter_file_type,
# student_form_groups, group_name_autogenerated, starter_file_type,
# default_starter_file_group_id
def update
# If no assignment is found, render an error.
Expand Down Expand Up @@ -142,11 +140,16 @@ def update
render 'shared/http_status', locals: { code: '500', message:
HttpStatusHelper::ERROR_CODE['message']['500'] }, status: :internal_server_error
return
elsif submission_rule.valid?
# If it's a valid submission rule, replace the existing one
assignment.submission_rule.destroy
assignment.submission_rule = submission_rule
end

original_submission_rule = assignment.submission_rule
unless assignment.update(submission_rule: submission_rule)
render 'shared/http_status', locals: { code: '500', message:
HttpStatusHelper::ERROR_CODE['message']['500'] }, status: :internal_server_error
return
end
original_submission_rule.destroy

end

unless assignment.save
Expand Down Expand Up @@ -230,28 +233,35 @@ def update_test_specs
# Defaults to NoLateSubmissionRule
def get_submission_rule(params)
if params[:submission_rule_type] == 'GracePeriod'
submission_rule = GracePeriodSubmissionRule.new
period = Period.new(hours: params[:submission_rule_hours])
submission_rule.periods << period

rule_type = 'GracePeriodSubmissionRule'
required = [:hours]
elsif params[:submission_rule_type] == 'PenaltyDecayPeriod'
submission_rule = PenaltyDecayPeriodSubmissionRule.new
period = Period.new(hours: params[:submission_rule_hours],
deduction: params[:submission_rule_deduction],
interval: params[:submission_rule_interval])
submission_rule.periods << period

rule_type = 'PenaltyDecayPeriodSubmissionRule'
required = [:hours, :deduction, :interval]
elsif params[:submission_rule_type] == 'PenaltyPeriod'
submission_rule = PenaltyPeriodSubmissionRule.new
period = Period.new(hours: params[:submission_rule_hours],
deduction: params[:submission_rule_deduction])
submission_rule.periods << period

rule_type = 'PenaltyPeriodSubmissionRule'
required = [:hours, :deduction]
else
submission_rule = NoLateSubmissionRule.new
return NoLateSubmissionRule.new
end

if params[:submission_rule_periods].nil?
return
end

permitted_params = params.permit(
submission_rule_periods: [:hours, :deduction, :interval, :_destroy]
)
permitted_params[:submission_rule_periods].each do |period|
if required.any? { |key| !period.key?(key) }
return
end
end

submission_rule
SubmissionRule.new(
{ type: rule_type,
periods_attributes: permitted_params[:submission_rule_periods] }
)
end

def grades_summary
Expand Down
15 changes: 14 additions & 1 deletion app/controllers/lti_deployments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
class LtiDeploymentsController < ApplicationController
skip_verify_authorized except: [:choose_course]
skip_forgery_protection except: [:choose_course]
skip_forgery_protection except: [:choose_course, :create_course]

before_action :authenticate, :check_course_switch, :check_record,
except: [:get_config, :launch, :public_jwk, :redirect_login]
before_action(except: [:get_config, :launch, :public_jwk, :redirect_login]) { authorize! }
before_action :check_host, only: [:launch, :redirect_login]
before_action :check_lti_launch_role, only: [:choose_course, :create_course]

USE_SECURE_COOKIES = !Rails.env.local?

Expand Down Expand Up @@ -151,6 +152,7 @@ def redirect_login
has_privileged_role = lti_data[:user_roles].intersect?(LtiDeployment::LTI_PRIVILEGED_ROLES)
has_ta_role = lti_data[:user_roles].include?(LtiDeployment::LTI_ROLES[:ta])
if has_privileged_role && !has_ta_role
session[:lti_privileged_deployments] = Array(session[:lti_privileged_deployments]) | [lti_deployment.id]
redirect_to choose_course_lti_deployment_path(lti_deployment)
else
redirect_to course_not_set_up_lti_deployment_path(lti_deployment)
Expand Down Expand Up @@ -256,4 +258,15 @@ def construct_redirect_with_port(url, endpoint: nil)
referer_host = referer_host_with_port if referer.to_s.start_with?(referer_host_with_port)
URI("#{referer_host}#{endpoint}")
end

# Only allow linking or creating a course for LTI deployments that the current
# user launched from the LMS with a privileged (non-TA) role. The launch role
# is recorded in the session by #redirect_login.
def check_lti_launch_role
return if Array(session[:lti_privileged_deployments]).include?(record&.id)

@title = I18n.t('lti.launch_required_title')
@message = I18n.t('lti.launch_required')
render 'message', status: :forbidden
end
end
Loading