--- loncom/homework/grades.pm 2005/09/23 15:19:05 1.288 +++ loncom/homework/grades.pm 2006/01/25 22:56:25 1.304 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.288 2005/09/23 15:19:05 albertel Exp $ +# $Id: grades.pm,v 1.304 2006/01/25 22:56:25 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -334,7 +334,16 @@ COMMONJSFUNCTIONS #--- section, ids and fullnames for each user. sub getclasslist { my ($getsec,$filterlist) = @_; - $getsec = $getsec eq '' ? 'all' : $getsec; + my @getsec; + if (!ref($getsec)) { + if ($getsec ne '' && $getsec ne 'all') { + @getsec=($getsec); + } + } else { + @getsec=@{$getsec}; + } + if (grep(/^all$/,@getsec)) { undef(@getsec); } + my $classlist=&Apache::loncoursedata::get_classlist(); # Bail out if we were unable to get the classlist return if (! defined($classlist)); @@ -363,7 +372,7 @@ sub getclasslist { } $section = ($section ne '' ? $section : 'none'); if (&canview($section)) { - if ($getsec eq 'all' || $getsec eq $section) { + if (!@getsec || grep(/^\Q$section\E$/,@getsec)) { $sections{$section}++; $fullnames{$student}=$fullname; } else { @@ -536,7 +545,13 @@ sub verifyreceipt { if ($env{"course.$courseid.receiptalg"} eq 'receipt2') { $receiptparts=1; } my $parts=['0']; if ($receiptparts) { ($parts)=&response_type($url,$symb); } - foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { + foreach (sort + { + if (lc($$fullname{$a}) ne lc($$fullname{$b})) { + return (lc($$fullname{$a}) cmp lc($$fullname{$b})); + } + return $a cmp $b; + } (keys(%$fullname))) { my ($uname,$udom)=split(/\:/); foreach my $part (@$parts) { if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) { @@ -689,12 +704,16 @@ LISTJAVASCRIPT while ($loop < 2) { $gradeTable.=' No.  Select '. ''.&nameUserString('header').' Section/Group'; - if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + if ($env{'form.showgrading'} eq 'yes' + && $submitonly ne 'queued' + && $submitonly ne 'all') { foreach (sort(@$partlist)) { my $display_part=&get_display_part((split(/_/))[0],$url,$symb); $gradeTable.=' Part: '.$display_part. ' Status '; } + } elsif ($submitonly eq 'queued') { + $gradeTable.=' '.&mt('Queue Status').' '; } $loop++; # $gradeTable.='' if ($loop%2 ==1); @@ -702,10 +721,29 @@ LISTJAVASCRIPT $gradeTable.=''."\n"; my $ctr = 0; - foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { + foreach my $student (sort + { + if (lc($$fullname{$a}) ne lc($$fullname{$b})) { + return (lc($$fullname{$a}) cmp lc($$fullname{$b})); + } + return $a cmp $b; + } + (keys(%$fullname))) { my ($uname,$udom) = split(/:/,$student); + my %status = (); - if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + + if ($submitonly eq 'queued') { + my %queue_status = + &Apache::bridgetask::get_student_status($symb,$cdom,$cnum, + $udom,$uname); + next if (!defined($queue_status{'gradingqueue'})); + $status{'gradingqueue'} = $queue_status{'gradingqueue'}; + } + + if ($env{'form.showgrading'} eq 'yes' + && $submitonly ne 'queued' + && $submitonly ne 'all') { (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist); my $submitted = 0; my $graded = 0; @@ -756,10 +794,14 @@ LISTJAVASCRIPT } if ($ctr%2 ==1) { $gradeTable.='   '; - if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + if ($env{'form.showgrading'} eq 'yes' + && $submitonly ne 'queued' + && $submitonly ne 'all') { foreach (@$partlist) { $gradeTable.=' '; } + } elsif ($submitonly eq 'queued') { + $gradeTable.=' '; } $gradeTable.=''; } @@ -776,6 +818,7 @@ LISTJAVASCRIPT my $submissions='submissions'; if ($submitonly eq 'incorrect') { $submissions = 'incorrect submissions'; } if ($submitonly eq 'graded' ) { $submissions = 'ungraded submissions'; } + if ($submitonly eq 'queued' ) { $submissions = 'queued submissions'; } $gradeTable='
 '. 'No '.$submissions.' found for this resource for any students. ('.$num_students. ' students checked for '.$submissions.')
'; @@ -1534,7 +1577,7 @@ sub submission { } my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'}; - $request->print('
'."\n". + $request->print(''."\n". ''."\n". ''."\n". ''."\n". @@ -1764,9 +1807,14 @@ KEYWORDS } if (@files) { $lastsubonly.='
Like all files provided by users, this file may contain virusses
'; + my $file_counter = 0; foreach my $file (@files) { + $file_counter ++; &Apache::lonnet::allowuploaded('/adm/grades',$file); $lastsubonly.='
'.$file.''; + $lastsubonly.='Return commented document to student. '."\n"; + $lastsubonly.=''; + } $lastsubonly.='
'; } @@ -1822,13 +1870,24 @@ KEYWORDS ''."\n"; $result.=' '. - 'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'  '. + &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').' ('. + &mt('incl. grades').' )'. ''."\n". - '
 (Message will be sent when you click on Save & Next below.)'."\n" - if ($env{'form.handgrade'} eq 'yes'); + '
 ('. + &mt('Message will be sent when you click on Save & Next below.').")\n"; $request->print($result); } + if ($perm{'vgr'}) { + $request->print('
'. + &Apache::loncommon::track_student_link(&mt('View recent activity'), + $uname,$udom,'check')); + } + if ($perm{'opa'}) { + $request->print('
'. + &Apache::loncommon::pprmlink(&mt('Set/Change parameters'), + $uname,$udom,$symb,'check')); + } my %seen = (); my @partlist; @@ -1927,6 +1986,9 @@ sub processHandGrade { my $button = $env{'form.gradeOpt'}; my $ngrade = $env{'form.NCT'}; my $ntstu = $env{'form.NTSTU'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if ($button eq 'Save & Next') { my $ctr = 0; while ($ctr < $ngrade) { @@ -1944,18 +2006,24 @@ sub processHandGrade { my $includemsg = $env{'form.includemsg'.$ctr}; my ($subject,$message,$msgstatus) = ('','',''); if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { - $subject = $env{'form.msgsub'} if ($includemsg =~ /^msgsub/); + $subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/); + unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); } my (@msgnum) = split(/,/,$includemsg); foreach (@msgnum) { $message.=$env{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne ''); } $message =&Apache::lonfeedback::clear_out_html($message); - $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt; - $message.=" for 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt; + $message.=" for $env{'form.probTitle'}"; + } $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom, - $env{'form.msgsub'},$message); + $subject.' ['. + &Apache::lonnet::declutter($url).']',$message); + $request->print('
'.&mt('Sending message to [_1]@[_2]',$uname,$udom).': '. + $msgstatus); } if ($env{'form.collaborator'.$ctr}) { my @collabstrs=&Apache::loncommon::get_env_multiple("form.collaborator$ctr"); @@ -1977,6 +2045,14 @@ sub processHandGrade { } } } + if ($env{'form.returndoc1'}) { + # if multiple files are uploaded names will be 'returndoc2', 'returndoc3' + my $file_counter = 1; + while ($env{'form.returndoc'.$file_counter}) { + $request->print("Will upload document".$env{'form.returndocorig'.$file_counter}); + $file_counter ++; + } + } $ctr++; } } @@ -2018,9 +2094,7 @@ sub processHandGrade { $env{'form.savemsgN'} = --$idx; $keyhash{$symb.'_savemsgN'} = $env{'form.savemsgN'}; my $putresult = &Apache::lonnet::put - ('nohist_handgrade',\%keyhash, - $env{'course.'.$env{'request.course.id'}.'.domain'}, - $env{'course.'.$env{'request.course.id'}.'.num'}); + ('nohist_handgrade',\%keyhash,$cdom,$cnum); } # Called by Save & Refresh from Highlight Attribute Window my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1'); @@ -2064,7 +2138,13 @@ sub processHandGrade { my (@parsedlist,@nextlist); my ($nextflg) = 0; - foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { + foreach (sort + { + if (lc($$fullname{$a}) ne lc($$fullname{$b})) { + return (lc($$fullname{$a}) cmp lc($$fullname{$b})); + } + return $a cmp $b; + } (keys(%$fullname))) { if ($nextflg == 1 && $button =~ /Next$/) { push @parsedlist,$_; } @@ -2080,6 +2160,14 @@ sub processHandGrade { foreach my $student (@parsedlist) { my $submitonly=$env{'form.submitonly'}; my ($uname,$udom) = split(/:/,$student); + + if ($submitonly eq 'queued') { + my %queue_status = + &Apache::bridgetask::get_student_status($symb,$cdom,$cnum, + $udom,$uname); + next if (!defined($queue_status{'gradingqueue'})); + } + if ($submitonly =~ /^(yes|graded|incorrect)$/) { # my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname); my %status=&student_gradeStatus($url,$symb,$udom,$uname,$partlist); @@ -2121,7 +2209,7 @@ sub processHandGrade { my $the_end = '

LON-CAPA User Message


'."\n"; $the_end.='Message: No more students for this section or class.

'."\n"; $the_end.='Click on the button below to return to the grading menu.

'."\n"; - $the_end.=&show_grading_menu_form ($symb,$url); + $the_end.=&show_grading_menu_form($symb,$url); $request->print($the_end); } return ''; @@ -2140,7 +2228,9 @@ sub saveHandGrade { my ($pts,$wgt) = ('',''); my %aggregate = (); my $aggregateflag = 0; - foreach my $new_part (split(/:/,$env{'form.partlist'.$newflg})) { + + my @parts = split(/:/,$env{'form.partlist'.$newflg}); + foreach my $new_part (@parts) { #collaborator may vary for different parts if ($submitter && $new_part ne $part) { next; } my $dropMenu = $env{'form.GD_SEL'.$newflg.'_'.$new_part}; @@ -2215,19 +2305,33 @@ sub saveHandGrade { push (@v_flag,$new_part); } } + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if (scalar(keys(%newrecord)) > 0) { if (scalar(@v_flag)) { &version_portfiles(\%record, \@parts_graded, $env{'request.course.id'}, $symb, $domain, $stuname, \@v_flag); } &Apache::lonnet::cstore(\%newrecord,$symb, $env{'request.course.id'},$domain,$stuname); + + my @ungraded_parts; + foreach my $part (@parts) { + if ( !defined($record{'resource.'.$part.'.awarded'}) + && !defined($newrecord{'resource.'.$part.'.awarded'}) ) { + push(@ungraded_parts, $part); + } + } + if ( !@ungraded_parts ) { + &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,$cdom, + $cnum,$domain,$stuname); + } } if ($aggregateflag) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, - $env{'course.'.$env{'request.course.id'}.'.domain'}, - $env{'course.'.$env{'request.course.id'}.'.num'}); + $cdom,$cnum); } - return '',$pts,$wgt; + return ('',$pts,$wgt); } # ----------- Provides number of tries since last reset. @@ -2306,22 +2410,23 @@ sub version_portfiles { &Apache::lonnet::logthis("should be unmarking and remarking $key",@portfiles); foreach my $file (@portfiles) { &Apache::lonnet::unmark_as_readonly($domain,$stuname,[$symb,$env{'request.course.id'}],$file); - my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*$)/); + my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/); my $version = 0; - my @answer_file_parts = split(/\./, $answer_file); + my ($answer_name,$answer_ver,$answer_ext) = + &file_name_version_ext($answer_file); my @dir_list = &Apache::lonnet::dirlist($directory,$domain,$stuname,$portfolio_root); - my @file_names; - my @file_name_parts; foreach my $row (@dir_list) { - @file_names = split(/\&/,$row,2); - @file_name_parts = split(/\./, $file_names[0]); - # ($file_name_parts[scalar @file_name_parts] eq $answer_file_parts[scalar @answer_file_parts]) - if (($file_name_parts[0] eq $answer_file_parts[0]) && - ($file_name_parts[-1] eq $answer_file_parts[-1])) { + my ($file) = split(/\&/,$row,2); + my ($file_name,$file_version,$file_ext) = + &file_name_version_ext($file); + if (($file_name eq $answer_name) && + ($file_ext eq $answer_ext)) { # gets here if filename and extension match, regardless of version - if (scalar @file_name_parts == 3) { # a versioned file is found - # so save it for later - if ($file_name_parts[1] > $version) {$version = $file_name_parts[1]}; + if ($file_version ne '') { + # a versioned file is found so save it for later + if ($file_version > $version) { + $version = $file_version; + } } } } @@ -2330,11 +2435,13 @@ sub version_portfiles { if($env{'form.copy'} eq '-1') { &Apache::lonnet::logthis('problem getting file '.$directory.$answer_file); } else { - my $copy_result = &Apache::lonnet::finishuserfileupload($stuname,$domain,'copy', - '/portfolio'.$directory.$answer_file_parts[0].'.'.$version.'.'.$answer_file_parts[-1]); - push(@v_portfiles, $directory.$answer_file_parts[0].'.'.$version.'.'.$answer_file_parts[-1]); + my $new_answer = $answer_name.'.'.$version.'.'.$answer_ext; + my $copy_result = &Apache::lonnet::finishuserfileupload( + $stuname,$domain,'copy', + '/portfolio'.$directory.$new_answer); + push(@v_portfiles, $directory.$new_answer); &Apache::lonnet::mark_as_readonly($domain,$stuname, - ['/portfolio'.$directory.$answer_file_parts[0].'.'.$version.'.'.$answer_file_parts[-1]], + ['/portfolio'.$directory.$new_answer], [$symb,$env{'request.course.id'},'graded']); } } @@ -2345,6 +2452,22 @@ sub version_portfiles { } +sub file_name_version_ext { + my ($file)=@_; + my @file_parts = split(/\./, $file); + my ($name,$version,$ext); + if (@file_parts > 1) { + $ext=pop(@file_parts); + if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) { + $version=pop(@file_parts); + } + $name=join('.',@file_parts); + } else { + $name=join('.',@file_parts); + } + return($name,$version,$ext); +} + #-------------------------------------------------------------------------------------- # #-------------------------- Next few routines handles grading by section or whole class @@ -2394,6 +2517,7 @@ sub viewgrades_js { } for (i=0;i nothing to reset - $newrecord{'resource.'.$_.'.tries'} = 0; + $newrecord{'resource.'.$_.'.tries'} = ''; $newrecord{'resource.'.$_.'.solved'} = ''; $newrecord{'resource.'.$_.'.award'} = ''; - $newrecord{'resource.'.$_.'.awarded'} = 0; - $newrecord{'resource.'.$_.'.regrader'}="$env{'user.name'}:$env{'user.domain'}"; + $newrecord{'resource.'.$_.'.awarded'} = ''; $updateflag = 1; if ($env{'form.GD_'.$user.'_'.$_.'_aggtries'} > 0) { my $aggtries = $env{'form.GD_'.$user.'_'.$_.'_aggtries'}; @@ -2866,10 +3000,38 @@ sub editgrades { } } $line.=''."\n"; + + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if ($updateflag) { $count++; &Apache::lonnet::cstore(\%newrecord,$symb,$env{'request.course.id'}, $udom,$uname); + + if (&Apache::bridgetask::in_queue('gradingqueue',$symb,$cdom, + $cnum,$udom,$uname)) { + # need to figure out if should be in queue. + my %record = + &Apache::lonnet::restore($symb,$env{'request.course.id'}, + $udom,$uname); + my $all_graded = 1; + my $none_graded = 1; + foreach my $part (@parts) { + 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, + $udom,$uname); + } + } + $result.=' '.$updateCtr.' '.$line; $updateCtr++; } else { @@ -2878,8 +3040,7 @@ sub editgrades { } if ($aggregateflag) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, - $env{'course.'.$env{'request.course.id'}.'.domain'}, - $env{'course.'.$env{'request.course.id'}.'.num'}); + $cdom,$cnum); } } if ($noupdate) { @@ -3162,13 +3323,14 @@ sub csvuploadoptions {

Uploading Class Grade Options

-
+


\n"); + $request->print('
+
'."\n"); $request->print(&show_grading_menu_form($symb,$url)); return ''; } @@ -3286,9 +3449,19 @@ sub csvuploadassign { if (! %grades) { push(@skipped,"$username:$domain no data to store"); } $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}"; # &Apache::lonnet::logthis(" storing ".(join('-',%grades))); - &Apache::lonnet::cstore(\%grades,$symb,$env{'request.course.id'}, - $domain,$username); - $request->print('.'); + my $result=&Apache::lonnet::cstore(\%grades,$symb, + $env{'request.course.id'}, + $domain,$username); + if ($result eq 'ok') { + $request->print('.'); + } else { + $request->print("

+ + Failed to store student $username\@$domain. + Message when trying to store was ($result) + +

" ); + } $request->rflush(); $countdone++; } @@ -3395,7 +3568,13 @@ LISTJAVASCRIPT my (undef,undef,$fullname) = &getclasslist($getsec,'1'); my $ptr = 1; - foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { + foreach my $student (sort + { + if (lc($$fullname{$a}) ne lc($$fullname{$b})) { + return (lc($$fullname{$a}) cmp lc($$fullname{$b})); + } + return $a cmp $b; + } (keys(%$fullname))) { my ($uname,$udom) = split(/:/,$student); $studentTable.=($ptr%2 == 1 ? '' : ''); $studentTable.=''.$ptr.' '; @@ -4027,7 +4206,7 @@ SCANTRONFORM - + @@ -5404,13 +5583,15 @@ GRADINGMENUJS ($saveCmd eq 'submission' ? 'checked' : '').'> '.''.&mt('Current Resource').': '.&mt('For one or more students'). ' '."\n"; + ($saveSub eq 'all' ? 'selected="on"' : '').'>'.&mt('with any status').''."\n"; $result.=''. '