diff --git a/htdocs/js/SendMail/sendmail.js b/htdocs/js/SendMail/sendmail.js index 48dfb2110e..2e6472e4c1 100644 --- a/htdocs/js/SendMail/sendmail.js +++ b/htdocs/js/SendMail/sendmail.js @@ -1,6 +1,6 @@ (() => { const previewUserNameSpan = document.getElementById('preview-user'); - const classListSelect = document.getElementById('classList'); + const classListSelect = document.getElementById('selected_users'); if (previewUserNameSpan && classListSelect) { const setPreviewUser = () => { if (classListSelect.selectedIndex !== -1) diff --git a/lib/WeBWorK/ContentGenerator/Instructor/Index.pm b/lib/WeBWorK/ContentGenerator/Instructor/Index.pm index 4ed3a2a6ba..7e699577ed 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/Index.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/Index.pm @@ -23,7 +23,7 @@ pages =cut -use WeBWorK::Utils qw(x format_set_name_internal); +use WeBWorK::Utils qw(x format_set_name_internal jitar_id_to_seq prob_id_sort); use constant E_MAX_ONE_SET => x('Please select at most one set.'); use constant E_ONE_USER => x('Please select exactly one user.'); @@ -152,6 +152,19 @@ sub pre_header_initialize ($c) { } else { push @error, E_ONE_SET unless $nsets == 1; } + } elsif (defined $c->param('show_answers')) { + my %all_problems; + for my $setID (@selectedSetIDs) { + my @problems = $db->listGlobalProblems($setID); + if ($db->getGlobalSet($setID)->assignment_type && $db->getGlobalSet($setID)->assignment_type eq 'jitar') { + @problems = map { join('.', jitar_id_to_seq($_)) } @problems; + } + @all_problems{@problems} = (1) x @problems; + } + $route = 'answer_log'; + $params{selected_users} = \@selectedUserIDs; + $params{selected_sets} = \@selectedSetIDs; + $params{selected_problems} = [ prob_id_sort keys %all_problems ]; } elsif (defined $c->param('create_set')) { my $setname = format_set_name_internal($c->param('new_set_name') // ''); if ($setname) { @@ -169,10 +182,6 @@ sub pre_header_initialize ($c) { } elsif (defined $c->param('add_users')) { $route = 'instructor_add_users'; $params{number_of_students} = $c->param('number_of_students') // 1; - } elsif (defined $c->param('email_users')) { - $route = 'instructor_mail_merge'; - } elsif (defined $c->param('transfer_files')) { - $route = 'instructor_file_manager'; } push @error, x('You are not allowed to act as a student.') diff --git a/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm b/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm index e4792cccd4..0c9272ef1c 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm @@ -96,7 +96,7 @@ sub initialize ($c) { $c->{defaultSubject} = $c->stash('courseID') . ' notice'; $c->{merge_file} = $mergefile // ''; - my @classList = $c->param('classList') // ($user); + my @classList = $c->param('selected_users') // ($user); $c->{preview_user} = $c->db->getUser($classList[0] || $user); # Gather database data @@ -129,7 +129,7 @@ sub initialize ($c) { if ($recipients eq 'all_students') { @send_to = map { $_->user_id } @Users; } elsif ($recipients eq 'studentID') { - @send_to = $c->param('classList'); + @send_to = $c->param('selected_users'); } $c->{ra_send_to} = \@send_to; diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm b/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm index 51b3523911..b38155c311 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm @@ -25,7 +25,7 @@ WeBWorK::ContentGenerator::Instructor::ShowAnswers.pm -- display past answers o use Text::CSV; use Mojo::File; -use WeBWorK::Utils qw(sortByName jitar_id_to_seq); +use WeBWorK::Utils qw(sortByName jitar_id_to_seq prob_id_sort); use WeBWorK::Utils::Rendering qw(renderPG); use constant PAST_ANSWERS_FILENAME => 'past_answers'; @@ -312,47 +312,9 @@ sub getInstructorData ($c) { return ( users => \@users, expandedGlobalSetIDs => \@expandedGlobalSetIDs, - globalProblemIDs => [ sort prob_id_sort keys %all_problems ], + globalProblemIDs => [ prob_id_sort keys %all_problems ], filename => PAST_ANSWERS_FILENAME . '.csv' ); } -sub byData { - my ($A, $B) = ($a, $b); - $A =~ s/\|[01]*\t([^\t]+)\t.*/|$1/; # remove answers and correct/incorrect status - $B =~ s/\|[01]*\t([^\t]+)\t.*/|$1/; - return $A cmp $B; -} - -# Sorts problem ID's so that all just-in-time like ids are at the bottom -# of the list in order and other problems -sub prob_id_sort { - - my @seqa = split(/\./, $a); - my @seqb = split(/\./, $b); - - # go through problem number sequence - for (my $i = 0; $i <= $#seqa; $i++) { - # if at some point two numbers are different return the comparison. - # e.g. 2.1.3 vs 1.2.6 - if ($seqa[$i] != $seqb[$i]) { - return $seqa[$i] <=> $seqb[$i]; - } - - # if all of the values are equal but b is shorter then it comes first - # i.e. 2.1.3 vs 2.1 - if ($i == $#seqb) { - return 1; - } - } - - # if all of the values are equal and a and b are the same length then equal - # otherwise a was shorter than b so a comes first. - if ($#seqa == $#seqb) { - return 0; - } else { - return -1; - } -} - 1; diff --git a/lib/WeBWorK/Utils.pm b/lib/WeBWorK/Utils.pm index fce6c3d51c..7853654c70 100644 --- a/lib/WeBWorK/Utils.pm +++ b/lib/WeBWorK/Utils.pm @@ -96,6 +96,7 @@ our @EXPORT_OK = qw( runtime_use sortAchievements sortByName + prob_id_sort surePathToFile textDateTime timeToSec @@ -1256,6 +1257,43 @@ sub sortAchievements { } +################################################################################ +# Sorts problem ID's so that all just-in-time like ids are at the bottom +# of the list in order and other problems +################################################################################ +sub prob_id_sort_comparator { + + my @seqa = split(/\./, $a); + my @seqb = split(/\./, $b); + + # go through problem number sequence + for (my $i = 0; $i <= $#seqa; $i++) { + # if at some point two numbers are different return the comparison. + # e.g. 2.1.3 vs 1.2.6 + if ($seqa[$i] != $seqb[$i]) { + return $seqa[$i] <=> $seqb[$i]; + } + + # if all of the values are equal but b is shorter then it comes first + # i.e. 2.1.3 vs 2.1 + if ($i == $#seqb) { + return 1; + } + } + + # if all of the values are equal and a and b are the same length then equal + # otherwise a was shorter than b so a comes first. + if ($#seqa == $#seqb) { + return 0; + } else { + return -1; + } +} + +sub prob_id_sort { + return sort prob_id_sort_comparator @_; +} + ################################################################################ # Validate strings and labels ################################################################################ diff --git a/templates/ContentGenerator/Instructor/Index.html.ep b/templates/ContentGenerator/Instructor/Index.html.ep index 31e261601e..ac9fc79b5c 100644 --- a/templates/ContentGenerator/Instructor/Index.html.ep +++ b/templates/ContentGenerator/Instructor/Index.html.ep @@ -62,7 +62,7 @@
% # TODO: When bootstrap is upgraded to 5.3 switch the "column-gap" style to the "column-gap-3" class.
-
+

<%= submit_button maketext('Edit'), @@ -80,7 +80,7 @@ formaction => $c->systemLink(url_for 'instructor_user_list'), data => { users_needed => 'at least one', error_users => maketext($E_MIN_ONE_USER) } =%> \ - <%== maketext('account data for all selected users') =%>\ + <%== maketext('account data for selected users') =%>\
@@ -101,6 +101,15 @@ <%== maketext('progress for one user') =%>\
+
+ <%= submit_button maketext('Email'), + name => 'email_users', + class => 'btn btn-sm btn-secondary w-25', + formaction => $c->systemLink(url_for 'instructor_mail_merge') =%> + \ + <%== maketext('selected users') =%>\ + +
<%= submit_button maketext('Add'), name => 'add_users', class => 'btn btn-sm btn-secondary w-25' =%> <%= number_field number_of_students => 1, min => 1, max => 100, @@ -110,7 +119,7 @@
-
+

<%= submit_button maketext('Assign'), @@ -126,7 +135,7 @@ error_sets => maketext($E_MIN_ONE_SET) } =%> \ - <%== maketext('all selected users to all selected sets') =%>\ + <%== maketext('selected users to selected sets') =%>\
@@ -155,6 +164,23 @@ <%== maketext(q{one set's details for some or all users}) =%>\
+
+ <%= submit_button maketext('View'), + name => 'show_answers', + class => 'btn btn-sm btn-secondary w-25' =%> + \ + <%== maketext('answers for selected users, for selected sets') =%>\ + +
+
+ <%= submit_button maketext('Generate'), + name => 'hardcopy', + class => 'btn btn-sm btn-secondary w-25', + formaction => $c->systemLink(url_for 'hardcopy') =%> + \ + <%== maketext('PDF for selected users, for selected sets') =%>\ + +
<%= submit_button maketext('Score'), name => 'score_sets', @@ -162,11 +188,11 @@ formaction => $c->systemLink(url_for 'instructor_scoring'), data => { sets_needed => 'at least one', error_sets => maketext($E_MIN_ONE_SET) } =%> \ - <%== maketext('all selected sets for all users') =%>\ + <%== maketext('selected sets for all users') =%>\
-
+

<%= submit_button maketext('Edit'), diff --git a/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep b/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep index aa0b86d1a1..149943a6a2 100644 --- a/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep +++ b/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep @@ -126,7 +126,7 @@
<%= scrollingRecordList( { - name => 'classList', + name => 'selected_users', controller => $c, default_sort => 'lnfn', default_format => 'lnfn_uid',