Skip to content

Commit 6765f5f

Browse files
authored
Merge branch 'master' into ec2-testing
2 parents 5a93401 + 9cc857f commit 6765f5f

File tree

11 files changed

+263
-95
lines changed

11 files changed

+263
-95
lines changed

Gemfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ GEM
205205
libv8-node (16.19.0.1-x86_64-darwin)
206206
libv8-node (16.19.0.1-x86_64-linux)
207207
lockbox (1.3.0)
208-
loofah (2.22.0)
208+
loofah (2.23.1)
209209
crass (~> 1.0.2)
210210
nokogiri (>= 1.12.0)
211211
mail (2.8.1)
@@ -247,11 +247,11 @@ GEM
247247
newrelic_rpm (9.6.0)
248248
base64
249249
nio4r (2.7.0)
250-
nokogiri (1.16.5-arm64-darwin)
250+
nokogiri (1.16.8-arm64-darwin)
251251
racc (~> 1.4)
252-
nokogiri (1.16.5-x86_64-darwin)
252+
nokogiri (1.16.8-x86_64-darwin)
253253
racc (~> 1.4)
254-
nokogiri (1.16.5-x86_64-linux)
254+
nokogiri (1.16.8-x86_64-linux)
255255
racc (~> 1.4)
256256
oauth2 (2.0.9)
257257
faraday (>= 0.17.3, < 3.0)
@@ -306,7 +306,7 @@ GEM
306306
psych (5.1.2)
307307
stringio
308308
public_suffix (5.0.4)
309-
racc (1.7.3)
309+
racc (1.8.1)
310310
rack (2.2.9)
311311
rack-attack (6.7.0)
312312
rack (>= 1.0, < 4)
@@ -335,9 +335,9 @@ GEM
335335
activesupport (>= 5.0.0)
336336
minitest
337337
nokogiri (>= 1.6)
338-
rails-html-sanitizer (1.6.0)
338+
rails-html-sanitizer (1.6.1)
339339
loofah (~> 2.21)
340-
nokogiri (~> 1.14)
340+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
341341
railties (6.1.7.6)
342342
actionpack (= 6.1.7.6)
343343
activesupport (= 6.1.7.6)

app/assets/javascripts/manage_submissions.js

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
const manage_submissions_endpoints = {
22
'regrade-selected': 'regradeBatch',
3+
'delete-selected': 'submissions/destroy_batch',
4+
'download-selected': 'submissions/download_batch',
5+
'excuse-selected': 'submissions/excuse_batch',
36
'score_details': 'submissions/score_details',
47
};
58

@@ -303,6 +306,7 @@ $(document).ready(function() {
303306

304307
if (!is_autograded) {
305308
$('#regrade-selected').hide();
309+
$('#regrade-all-html').hide();
306310
}
307311

308312
// base URLs for selected buttons
@@ -311,23 +315,90 @@ $(document).ready(function() {
311315
baseURLs[id] = $(id).prop('href');
312316
});
313317

314-
function changeButtonStates(state) {
315-
state ? buttonIDs.forEach((id) => $(id).addClass('disabled')) : buttonIDs.forEach((id) => $(id).removeClass('disabled'));
316-
317-
// prop each selected button with selected submissions
318-
if (!state) {
319-
var urlParam = $.param({'submission_ids': selectedSubmissions});
320-
buttonIDs.forEach(function(id) {
321-
var newHref = baseURLs[id] + '?' + urlParam;
322-
$(id).prop('href', newHref);
323-
});
324-
} else {
325-
buttonIDs.forEach(function(id) {
326-
$(id).prop('href', baseURLs[id]);
327-
});
318+
function updateSelectedCount(numericSubmissions) {
319+
const allBoxes = $('#submissions tbody .cbox').length;
320+
const selectedCountElement = document.getElementById("selected-count-html");
321+
const placeholder = document.querySelector(".selected-count-placeholder");
322+
if (selectedCountElement) {
323+
selectedCountElement.innerText = `All ${numericSubmissions.length} submissions on this page selected.`;
324+
if (numericSubmissions.length === allBoxes) {
325+
placeholder.style.display = "block";
326+
} else if (numericSubmissions.length <= allBoxes) {
327+
placeholder.style.display = "none";
328+
}
328329
}
329330
}
330331

332+
function changeButtonStates(state) {
333+
buttonIDs.forEach((id) => {
334+
const button = $(id);
335+
if (state) {
336+
if (id === "#download-selected") {
337+
$(id).prop('href', baseURLs[id]);
338+
}
339+
button.addClass("disabled");
340+
button.off("click").prop("disabled", true);
341+
} else {
342+
button.removeClass("disabled").prop("disabled", false);
343+
if (id == "#download-selected") {
344+
var urlParam = $.param({'submission_ids': selectedSubmissions});
345+
buttonIDs.forEach(function(id) {
346+
var newHref = baseURLs[id] + '?' + urlParam;
347+
$(id).prop('href', newHref);
348+
});
349+
return;
350+
}
351+
$(document).off("click", id).on("click", id, function (event) {
352+
console.log(`${id} button clicked`);
353+
event.preventDefault();
354+
if (selectedSubmissions.length === 0) {
355+
alert("No submissions selected.");
356+
return;
357+
}
358+
const endpoint = manage_submissions_endpoints[id.replace("#", "")];
359+
const requestData = { submission_ids: selectedSubmissions };
360+
if (id === "#delete-selected") {
361+
if (!confirm("Deleting will delete all checked submissions and cannot be undone. Are you sure you want to delete these submissions?")) {
362+
return;
363+
}
364+
}
365+
let refreshInterval = setInterval(() => {
366+
location.reload();
367+
}, 5000);
368+
$.ajax({
369+
url: endpoint,
370+
type: "POST",
371+
contentType: "application/json",
372+
data: JSON.stringify(requestData),
373+
dataType: "json",
374+
headers: {
375+
"X-CSRF-Token": $('meta[name="csrf-token"]').attr("content"),
376+
},
377+
success: function (response) {
378+
clearInterval(refreshInterval);
379+
if (response.redirect) {
380+
window.location.href = response.redirect;
381+
return;
382+
}
383+
if (response.error) {
384+
alert(response.error);
385+
}
386+
if (response.success) {
387+
alert(response.success);
388+
}
389+
selectedSubmissions = [];
390+
changeButtonStates(true);
391+
},
392+
error: function (error) {
393+
clearInterval(refreshInterval);
394+
alert("An error occurred while processing the request.");
395+
},
396+
});
397+
});
398+
}
399+
});
400+
}
401+
331402
changeButtonStates(true); // disable all buttons by default
332403

333404
// SELECTING STUDENT CHECKBOXES
@@ -362,6 +433,7 @@ $(document).ready(function() {
362433
const numericSelectedSubmissions = selectedSubmissions.filter(submissionId => typeof submissionId === 'number');
363434
// Update the "Select All" checkbox based on filtered numeric submissions
364435
$('#cbox-select-all').prop('checked', numericSelectedSubmissions.length === $('#submissions tbody .cbox').length);
436+
updateSelectedCount(numericSelectedSubmissions);
365437
changeButtonStates(disableButtons);
366438
}
367439

app/assets/stylesheets/style.css.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,21 @@ table.sub td, th {
16281628
align-items: center;
16291629
}
16301630

1631+
.selected-count-placeholder {
1632+
display: flex;
1633+
flex-direction: row;
1634+
justify-content: center;
1635+
text-align: center;
1636+
background-color: $autolab-submissions-background;
1637+
padding-top: 10px;
1638+
padding-bottom: 10px;
1639+
border-radius: 4px;
1640+
}
1641+
1642+
.selected-count-red {
1643+
color: $autolab-red;
1644+
}
1645+
16311646
.excused-popover {
16321647
background-color: $autolab-submissions-background;
16331648
border-radius: 11px;

app/controllers/assessment/autograde.rb

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ def autograde_done
2828

2929
extend_config_module(@assessment, submissions[0], @cud)
3030

31-
if (@assessment.use_unique_module_name)
31+
if @assessment.use_unique_module_name
3232
require_relative(@assessment.unique_config_file_path)
3333
else
34-
require_relative(Rails.root.join("assessmentConfig", "#{@course.name}-#{@assessment.name}.rb"))
34+
require_relative(Rails.root.join("assessmentConfig",
35+
"#{@course.name}-#{@assessment.name}.rb"))
3536
end
3637

3738
if @assessment.overwrites_method?(:autogradeDone)
@@ -86,7 +87,19 @@ def regrade
8687
#
8788
# action_auth_level :regradeBatch, :instructor
8889
def regradeBatch
89-
submission_ids = params[:submission_ids]
90+
request_body = request.body.read
91+
submission_ids = begin if request_body.present?
92+
parsed_data = JSON.parse(request_body)
93+
Array(parsed_data['submission_ids'])
94+
else
95+
params[:submission_ids]
96+
end
97+
rescue JSON::ParserError => e
98+
params[:submission_ids] || []
99+
end
100+
101+
# Ensure submission_ids is an array
102+
submission_ids = Array(submission_ids)
90103

91104
# Now regrade only the most recent submissions. Keep track of
92105
# any handins that fail.
@@ -106,26 +119,32 @@ def regradeBatch
106119

107120
failure_jobs = failed_list.length
108121
if failure_jobs > 0
109-
flash[:error] = "Warning: Could not regrade #{ActionController::Base.helpers.pluralize(failure_jobs, "submission")}:<br>"
122+
flash[:error] =
123+
"Warning: Could not regrade #{ActionController::Base.helpers.pluralize(failure_jobs,
124+
"submission")}:<br>"
110125
failed_list.each do |failure|
111-
if failure[:error].error_code == :nil_submission
112-
flash[:error] += "Unrecognized submission ID<br>"
113-
else
114-
flash[:error] += "#{failure[:submission].filename}: #{failure[:error].message}<br>"
115-
end
126+
flash[:error] += if failure[:error].error_code == :nil_submission
127+
"Unrecognized submission ID<br>"
128+
else
129+
"#{failure[:submission].filename}: #{failure[:error].message}<br>"
130+
end
116131
end
117132
end
118133

119134
success_jobs = submissions.size - failure_jobs
120135
if success_jobs > 0
121-
link = "<a href=\"#{url_for(controller: 'jobs')}\">#{ActionController::Base.helpers.pluralize(success_jobs, "submission")}</a>"
122-
flash[:success] = ("Regrading #{link}")
136+
link = "<a href=\"#{url_for(controller: 'jobs')}\">#{ActionController::Base.helpers.pluralize(
137+
success_jobs, "submission")}</a>"
138+
flash[:success] = "Regrading #{link}"
123139
end
124140

125141
# For both :success and :error
126142
flash[:html_safe] = true
127143

128-
redirect_to([@course, @assessment, :submissions]) && return
144+
respond_to do |format|
145+
format.html { redirect_to [@course, @assessment, :submissions] }
146+
format.json { render json: { redirect: url_for([@course, @assessment, :submissions]) } }
147+
end
129148
end
130149

131150
#
@@ -136,7 +155,7 @@ def regradeBatch
136155
# action_auth_level :regradeAll, :instructor
137156
def regradeAll
138157
# Grab all of the submissions for this assessment
139-
@submissions = @assessment.submissions.where(special_type: Submission::NORMAL)
158+
@submissions = @assessment.submissions.where(special_type: [Submission::NORMAL, nil])
140159
.order("version DESC")
141160

142161
last_submissions = @submissions.latest
@@ -153,20 +172,22 @@ def regradeAll
153172

154173
failure_jobs = failed_list.length
155174
if failure_jobs > 0
156-
flash[:error] = "Warning: Could not regrade #{ActionController::Base.helpers.pluralize(failure_jobs, "submission")}:<br>"
175+
flash[:error] =
176+
"Warning: Could not regrade #{ActionController::Base.helpers.pluralize(failure_jobs, "submission")}"
177+
178+
@failure_messages = []
157179
failed_list.each do |failure|
158-
if failure[:error].error_code == :nil_submission
159-
flash[:error] += "Unrecognized submission ID<br>"
160-
else
161-
flash[:error] += "#{failure[:submission].filename}: #{failure[:error].message}<br>"
162-
end
180+
@failure_messages << if failure[:error].error_code == :nil_submission
181+
"Unrecognized submission ID"
182+
else
183+
"#{failure[:submission].filename}: #{failure[:error].message}"
184+
end
163185
end
164186
end
165187

166188
success_jobs = last_submissions.size - failure_jobs
167189
if success_jobs > 0
168-
link = "<a href=\"#{url_for(controller: 'jobs')}\">#{ActionController::Base.helpers.pluralize(success_jobs, "student")}</a>"
169-
flash[:success] = ("Regrading the most recent submissions from #{link}")
190+
flash[:success] = "Regrading #{success_jobs} recent submissions"
170191
end
171192

172193
# For both :success and :error
@@ -189,7 +210,8 @@ def regradeAll
189210
#
190211
def sendJob_AddHTMLMessages(course, assessment, submissions)
191212
# Check for nil first, since students should know about this
192-
flash[:error] = "Submission could not be autograded due to an error in creation" && return if submissions.blank?
213+
flash[:error] =
214+
"Submission could not be autograded due to an error in creation" && return if submissions.blank?
193215

194216
begin
195217
job = sendJob(course, assessment, submissions, @cud)
@@ -198,36 +220,42 @@ def sendJob_AddHTMLMessages(course, assessment, submissions)
198220
when :missing_autograding_props
199221
flash[:error] = "Autograding failed because there are no autograding properties."
200222
if @cud.instructor?
201-
link = (view_context.link_to "Autograder Settings", [:edit, course, assessment, :autograder])
223+
link = (view_context.link_to "Autograder Settings",
224+
[:edit, course, assessment, :autograder])
202225
flash[:error] += " Visit #{link} to set the autograding properties."
203226
flash[:html_safe] = true
204227
else
205228
flash[:error] += " Please contact your instructor."
206229
end
207230
when :tango_open
208-
flash[:error] = "There was an error submitting your autograding job. We are likely down for maintenance if issues persist, please contact #{Rails.configuration.school['support_email']}"
231+
flash[:error] =
232+
"There was an error submitting your autograding job. We are likely down for maintenance if issues persist, please contact #{Rails.configuration.school['support_email']}"
209233
when :tango_upload
210234
flash[:error] = "There was an error uploading the submission file."
211235
when :tango_add_job
212236
flash[:error] = "Submission was rejected by autograder."
213237
if @cud.instructor?
214-
link = (view_context.link_to "Autograder Settings", [:edit, course, assessment, :autograder])
238+
link = (view_context.link_to "Autograder Settings",
239+
[:edit, course, assessment, :autograder])
215240
flash[:error] += " Verify the autograding properties at #{link}.<br>ErrorMsg: " + e.additional_data
216241
flash[:html_safe] = true
217242
end
218243
when :missing_autograder_file
219-
flash[:error] = "One or more files are missing in the server. Please contact the instructor. The missing files are: " + e.additional_data
244+
flash[:error] =
245+
"One or more files are missing in the server. Please contact the instructor. The missing files are: " + e.additional_data
220246
else
221247
flash[:error] = "Autograding failed because of an unexpected exception in the system."
222248
end
223249

224250
raise e # pass it on
225251
end
226252

227-
link = "<a href=\"#{url_for(controller: 'jobs', action: 'getjob', id: job)}\">Job ID = #{job}</a>"
228-
viewFeedbackLink = "<a href=\"#{url_for(controller: 'assessments', action: 'viewFeedback', submission_id: submissions[0].id, feedback: assessment.problems[0].id)}\">View autograding progress.</a>"
229-
flash[:success] = ("Submitted file #{submissions[0].filename} (#{link}) for autograding." \
230-
" #{viewFeedbackLink}")
253+
link = "<a href=\"#{url_for(controller: 'jobs', action: 'getjob',
254+
id: job)}\">Job ID = #{job}</a>"
255+
viewFeedbackLink = "<a href=\"#{url_for(controller: 'assessments', action: 'viewFeedback',
256+
submission_id: submissions[0].id, feedback: assessment.problems[0].id)}\">View autograding progress.</a>"
257+
flash[:success] = "Submitted file #{submissions[0].filename} (#{link}) for autograding." \
258+
" #{viewFeedbackLink}"
231259
flash[:html_safe] = true
232260
job
233261
end

app/controllers/assessment/handin.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def handin
2727
return false
2828
end
2929

30+
# Clear cache since new submission made, need to remake cache
31+
Rails.cache.delete(["submission_ids", @assessment.id])
32+
Rails.cache.delete(["submissions_to_cud", @assessment.id])
33+
3034
if @assessment.embedded_quiz
3135
contents = params[:submission]["embedded_quiz_form_answer"].to_s
3236
out_file = Tempfile.new('out.txt-')

0 commit comments

Comments
 (0)