--- loncom/homework/grades.pm 2021/01/23 20:24:53 1.782
+++ loncom/homework/grades.pm 2022/06/11 14:38:28 1.790
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.782 2021/01/23 20:24:53 raeburn Exp $
+# $Id: grades.pm,v 1.790 2022/06/11 14:38:28 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1173,6 +1173,8 @@ LISTJAVASCRIPT
my @sections;
if ($env{'request.course.sec'} ne '') {
@sections = ($env{'request.course.sec'});
+ } elsif ($env{'form.section'} eq '') {
+ @sections = ('all');
} else {
@sections = &Apache::loncommon::get_env_multiple('form.section');
}
@@ -1214,7 +1216,7 @@ LISTJAVASCRIPT
''."\n".
''."\n";
if (exists($env{'form.Status'})) {
- $gradeTable .= ''."\n";
+ $gradeTable .= ''."\n";
} else {
$gradeTable .= &Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title(&mt('Student Status'))
@@ -3182,13 +3184,31 @@ sub processHandGrade {
my $ntstu = $env{'form.NTSTU'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my ($res_error,%queueable);
+ my ($partlist,$handgrade,$responseType,$numresp,$numessay) = &response_type($symb,\$res_error);
+ if ($res_error) {
+ $request->print(&navmap_errormsg());
+ return;
+ } else {
+ foreach my $part (@{$partlist}) {
+ if (ref($responseType->{$part}) eq 'HASH') {
+ foreach my $id (keys(%{$responseType->{$part}})) {
+ if (($responseType->{$part}->{$id} eq 'essay') ||
+ (lc($handgrade->{$part.'_'.$id}) eq 'yes')) {
+ $queueable{$part} = 1;
+ last;
+ }
+ }
+ }
+ }
+ }
if ($button eq 'Save & Next') {
my $ctr = 0;
while ($ctr < $ngrade) {
my ($uname,$udom) = split(/:/,$env{'form.unamedom'.$ctr});
my ($errorflag,$pts,$wgt,$numhidden) =
- &saveHandGrade($request,$symb,$uname,$udom,$ctr);
+ &saveHandGrade($request,$symb,$uname,$udom,$ctr,undef,undef,\%queueable);
if ($errorflag eq 'no_score') {
$ctr++;
next;
@@ -3243,7 +3263,7 @@ sub processHandGrade {
foreach my $collaborator (@collaborators) {
my ($errorflag,$pts,$wgt) =
&saveHandGrade($request,$symb,$collaborator,$udom,$ctr,
- $env{'form.unamedom'.$ctr},$part);
+ $env{'form.unamedom'.$ctr},$part,\%queueable);
if ($errorflag eq 'not_allowed') {
$request->print("".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")."");
next;
@@ -3265,13 +3285,6 @@ sub processHandGrade {
}
}
- my $res_error;
- my ($partlist,$handgrade,$responseType,$numresp,$numessay) = &response_type($symb,\$res_error);
- if ($res_error) {
- $request->print(&navmap_errormsg());
- return;
- }
-
my %keyhash = ();
if ($numessay) {
# Keywords sorted in alphabatical order
@@ -3423,7 +3436,7 @@ sub processHandGrade {
#---- Save the score and award for each student, if changed
sub saveHandGrade {
- my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part) = @_;
+ my ($request,$symb,$stuname,$domain,$newflg,$submitter,$part,$queueable) = @_;
my @version_parts;
my $usec = &Apache::lonnet::getsection($domain,$stuname,
$env{'request.course.id'});
@@ -3535,7 +3548,7 @@ sub saveHandGrade {
&Apache::lonnet::cstore(\%newrecord,$symb,
$env{'request.course.id'},$domain,$stuname);
&check_and_remove_from_queue(\@parts,\%record,\%newrecord,$symb,
- $cdom,$cnum,$domain,$stuname);
+ $cdom,$cnum,$domain,$stuname,$queueable);
}
if ($aggregateflag) {
&Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
@@ -3575,7 +3588,7 @@ sub makehidden {
}
sub check_and_remove_from_queue {
- my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname) = @_;
+ my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname,$queueable) = @_;
my @ungraded_parts;
foreach my $part (@{$parts}) {
if ( $record->{ 'resource.'.$part.'.awarded'} eq ''
@@ -3583,7 +3596,9 @@ sub check_and_remove_from_queue {
&& $newrecord->{'resource.'.$part.'.awarded'} eq ''
&& $newrecord->{'resource.'.$part.'.solved' } ne 'excused'
) {
- push(@ungraded_parts, $part);
+ if ($queueable->{$part}) {
+ push(@ungraded_parts, $part);
+ }
}
}
if ( !@ungraded_parts ) {
@@ -4476,6 +4491,7 @@ sub editgrades {
&Apache::loncommon::end_data_table_header_row();
my @noupdate;
my ($updateCtr,$noupdateCtr) = (1,1);
+ my ($got_types,%queueable);
for ($i=0; $i<$env{'form.total'}; $i++) {
my $user = $env{'form.ctr'.$i};
my ($uname,$udom)=split(/:/,$user);
@@ -4575,14 +4591,33 @@ sub editgrades {
$udom,$uname);
my $all_graded = 1;
my $none_graded = 1;
+ unless ($got_types) {
+ my $error;
+ my ($plist,$handgrd,$resptype) = &response_type($symb,\$error);
+ unless ($error) {
+ foreach my $part (@parts) {
+ if (ref($resptype->{$part}) eq 'HASH') {
+ foreach my $id (keys(%{$resptype->{$part}})) {
+ if (($resptype->{$part}->{$id} eq 'essay') ||
+ (lc($handgrd->{$part.'_'.$id}) eq 'yes')) {
+ $queueable{$part} = 1;
+ last;
+ }
+ }
+ }
+ }
+ }
+ $got_types = 1;
+ }
foreach my $part (@parts) {
- if ( $record{'resource.'.$part.'.awarded'} eq '' ) {
- $all_graded = 0;
- } else {
- $none_graded = 0;
+ if ($queueable{$part}) {
+ if ( $record{'resource.'.$part.'.awarded'} eq '' ) {
+ $all_graded = 0;
+ } else {
+ $none_graded = 0;
+ }
}
- }
-
+ }
if ($all_graded || $none_graded) {
&Apache::bridgetask::remove_from_queue('gradingqueue',
$symb,$cdom,$cnum,
@@ -5696,6 +5731,7 @@ sub updateGradeByPage {
my @displayPts=();
my %aggregate = ();
my $aggregateflag = 0;
+ my %queueable;
if ($env{'form.HIDE'.$prob}) {
my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname);
my ($version,$parts) = split(/:/,$env{'form.HIDE'.$prob},2);
@@ -5705,7 +5741,20 @@ sub updateGradeByPage {
foreach my $partid (@{$parts}) {
my $newpts = $env{'form.GD_BOX'.$question.'_'.$partid};
my $oldpts = $env{'form.oldpts'.$question.'_'.$partid};
-
+ my @types = $curRes->responseType($partid);
+ if (grep(/^essay$/,@types)) {
+ $queueable{$partid} = 1;
+ } else {
+ my @ids = $curRes->responseIds($partid);
+ for (my $i=0; $i < scalar(@ids); $i++) {
+ my $hndgrd = &Apache::lonnet::EXT('resource.'.$partid.'_'.$ids[$i].
+ '.handgrade',$symb);
+ if (lc($hndgrd) eq 'yes') {
+ $queueable{$partid} = 1;
+ last;
+ }
+ }
+ }
my $wgt = $env{'form.WGT'.$question.'_'.$partid} != 0 ?
$env{'form.WGT'.$question.'_'.$partid} : 1;
my $partial = $newpts/$wgt;
@@ -5771,7 +5820,7 @@ sub updateGradeByPage {
$env{'request.course.id'},
$udom,$uname);
&check_and_remove_from_queue($parts,\%record,undef,$symbx,
- $cdom,$cnum,$udom,$uname);
+ $cdom,$cnum,$udom,$uname,\%queueable);
}
if ($aggregateflag) {
@@ -6683,9 +6732,12 @@ sub scantron_parse_scanline {
}
sub get_master_seq {
- my ($resources,$master_seq,$symb_to_resource) = @_;
+ my ($resources,$master_seq,$symb_to_resource,$need_symb_in_map,$symb_for_examcode) = @_;
return unless ((ref($resources) eq 'ARRAY') && (ref($master_seq) eq 'ARRAY') &&
(ref($symb_to_resource) eq 'HASH'));
+ if ($need_symb_in_map) {
+ return unless (ref($symb_for_examcode) eq 'HASH');
+ }
my $resource_error;
foreach my $resource (@{$resources}) {
my $ressymb;
@@ -6693,6 +6745,14 @@ sub get_master_seq {
$ressymb = $resource->symb();
push(@{$master_seq},$ressymb);
$symb_to_resource->{$ressymb} = $resource;
+ if ($need_symb_in_map) {
+ unless ($resource->is_map()) {
+ my $map=(&Apache::lonnet::decode_symb($ressymb))[0];
+ unless (exists($symb_for_examcode->{$map})) {
+ $symb_for_examcode->{$map} = $ressymb;
+ }
+ }
+ }
} else {
$resource_error = 1;
last;
@@ -8704,6 +8764,17 @@ sub scantron_validate_doublebubble {
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
if ($randomorder || $randompick) {
$nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
if ($nav_error) {
@@ -8887,6 +8958,17 @@ sub scantron_validate_missingbubbles {
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
if ($randomorder || $randompick) {
$nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
if ($nav_error) {
@@ -9028,10 +9110,21 @@ sub scantron_process_students {
}
my $map=$navmap->getResourceByUrl($sequence);
my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
- %grader_randomlists_by_symb);
+ %grader_randomlists_by_symb,%symb_for_examcode);
if (ref($map)) {
$randomorder = $map->randomorder();
$randompick = $map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
} else {
$r->print(&navmap_errormsg());
return '';
@@ -9039,7 +9132,7 @@ sub scantron_process_students {
my $nav_error;
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
if ($randomorder || $randompick) {
- $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource,1,\%symb_for_examcode);
if ($nav_error) {
$r->print(&navmap_errormsg());
return '';
@@ -9194,11 +9287,16 @@ SCANTRONFORM
}
if (($scancode) && ($randomorder || $randompick)) {
- my $parmresult =
- &Apache::lonparmset::storeparm_by_symb($symb,
- '0_examcode',2,$scancode,
- 'string_examcode',$uname,
- $udom);
+ foreach my $key (keys(%symb_for_examcode)) {
+ my $symb_in_map = $symb_for_examcode{$key};
+ if ($symb_in_map ne '') {
+ my $parmresult =
+ &Apache::lonparmset::storeparm_by_symb($symb_in_map,
+ '0_examcode',2,$scancode,
+ 'string_examcode',$uname,
+ $udom);
+ }
+ }
}
$completedstudents{$uname}={'line'=>$line};
if ($env{'form.verifyrecord'}) {
@@ -9513,7 +9611,7 @@ END
my @lines = &Apache::lonnet::get_scantronformat_file();
my $count = 0;
foreach my $line (@lines) {
- next if ($line =~ /^#/);
+ next if (($line =~ /^\#/) || ($line eq ''));
$singleline = $line;
$count ++;
}
@@ -9707,7 +9805,7 @@ sub validate_uploaded_scantron_file {
my %unique_formats;
my @formatlines = &Apache::lonnet::get_scantronformat_file();
foreach my $line (@formatlines) {
- chomp($line);
+ next if (($line =~ /^\#/) || ($line eq ''));
my @config = split(/:/,$line);
my $idstart = $config[5];
my $idlength = $config[6];
@@ -10077,6 +10175,17 @@ sub checkscantron_results {
if (ref($map)) {
$randomorder=$map->randomorder();
$randompick=$map->randompick();
+ unless ($randomorder || $randompick) {
+ foreach my $res ($navmap->retrieveResources($map,sub { $_[0]->is_map() },1,0,1)) {
+ if ($res->randomorder()) {
+ $randomorder = 1;
+ }
+ if ($res->randompick()) {
+ $randompick = 1;
+ }
+ last if ($randomorder || $randompick);
+ }
+ }
}
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
my $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
@@ -11383,7 +11492,9 @@ sub startpage {
$args{'only_body'} = 1;
$r->print(&Apache::loncommon::start_page("Student's Version",$head_extra,\%args));
} else {
- unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
+ if ($env{'request.course.id'}) {
+ unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
+ }
$args{'bread_crumbs'} = $crumbs;
$r->print(&Apache::loncommon::start_page('Grading',$head_extra,\%args));
if ($env{'request.course.id'}) {
@@ -11829,8 +11940,8 @@ Side Effects: None.
- missingbubble - array ref of the bubble lines that have missing
bubble errors
- $randomorder - True if exam folder has randomorder set
- $randompick - True if exam folder has randompick set
+ $randomorder - True if exam folder (or a sub-folder) has randomorder set
+ $randompick - True if exam folder (or a sub-folder) has randompick set
$respnumlookup - Reference to HASH mapping question numbers in bubble lines
for current line to question number used for same question
in "Master Seqence" (as seen by Course Coordinator).