--- loncom/homework/grades.pm	2005/09/21 21:44:55	1.286
+++ loncom/homework/grades.pm	2006/02/14 19:41:06	1.314
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.286 2005/09/21 21:44:55 albertel Exp $
+# $Id: grades.pm,v 1.314 2006/02/14 19:41:06 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.='<td><b>&nbsp;No.</b>&nbsp;</td><td><b>&nbsp;Select&nbsp;</b></td>'.
 	    '<td>'.&nameUserString('header').'&nbsp;Section/Group</td>';
-	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.='<td><b>&nbsp;Part: '.$display_part.
 		    ' Status&nbsp;</b></td>';
 	    }
+	} elsif ($submitonly eq 'queued') {
+	    $gradeTable.='<td><b>&nbsp;'.&mt('Queue Status').'&nbsp;</b></td>';
 	}
 	$loop++;
 #	$gradeTable.='<td></td>' if ($loop%2 ==1);
@@ -702,10 +721,29 @@ LISTJAVASCRIPT
     $gradeTable.='</tr>'."\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.='<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';
-	    if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
+	    if ($env{'form.showgrading'} eq 'yes' 
+		&& $submitonly ne 'queued'
+		&& $submitonly ne 'all') {
 		foreach (@$partlist) {
 		    $gradeTable.='<td>&nbsp;</td>';
 		}
+	    } elsif ($submitonly eq 'queued') {
+		$gradeTable.='<td>&nbsp;</td>';
 	    }
 	$gradeTable.='</tr>';
     }
@@ -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='<br />&nbsp;<font color="red">'.
 		'No '.$submissions.' found for this resource for any students. ('.$num_students.
 		' students checked for '.$submissions.')</font><br />';
@@ -1343,10 +1386,8 @@ SUBJAVASCRIPT
 #--- displays the grading box, used in essay type problem and grading by page/sequence
 sub gradeBox {
     my ($request,$symb,$uname,$udom,$counter,$partid,$record) = @_;
-
     my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').
 	'/check.gif" height="16" border="0" />';
-
     my $wgt    = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
     my $wgtmsg = ($wgt > 0 ? '(problem weight)' : 
 		  '<font color="red">problem weight assigned by computer</font>');
@@ -1354,31 +1395,26 @@ sub gradeBox {
     my $score  = ($$record{'resource.'.$partid.'.awarded'} eq '' ?
 		  '' : $$record{'resource.'.$partid.'.awarded'}*$wgt);
     my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";
-
     my $display_part=&get_display_part($partid,undef,$symb);
-
     my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
 				       [$partid]);
     my $aggtries = $$record{'resource.'.$partid.'.tries'};
     if ($last_resets{$partid}) {
         $aggtries = &get_num_tries($record,$last_resets{$partid},$partid);
     }
-
     $result.='<table border="0"><tr><td>'.
 	'<b>Part: </b>'.$display_part.' <b>Points: </b></td><td>'."\n";
-
     my $ctr = 0;
     $result.='<table border="0"><tr>'."\n";  # display radio buttons in a nice table 10 across
     while ($ctr<=$wgt) {
-	$result.= '<td><nobr><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
+	$result.= '<td><nobr><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
 	    'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','.
 	    $ctr.')" value="'.$ctr.'" '.
-	    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</nobr></td>\n";
+	    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</label></nobr></td>\n";
 	$result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
 	$ctr++;
     }
     $result.='</tr></table>';
-
     $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>'."\n";
     $result.='<td><input type="text" name="GD_BOX'.$counter.'_'.$partid.'"'.
 	($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
@@ -1387,7 +1423,6 @@ sub gradeBox {
     $result.='<td>/'.$wgt.' '.$wgtmsg.
 	($$record{'resource.'.$partid.'.solved'} eq 'correct_by_student' ? '&nbsp;'.$checkIcon : '').
 	' </td><td>'."\n";
-
     $result.='<select name="GD_SEL'.$counter.'_'.$partid.'" '.
 	'onChange="javascript:clearRadBox(this.form,\''.$counter.'_'.$partid.'\')" >'."\n";
     if ($$record{'resource.'.$partid.'.solved'} eq 'excused') {
@@ -1408,6 +1443,18 @@ sub gradeBox {
         '<input type="hidden" name="aggtries'.$counter.'_'.$partid.'" value="'.
         $aggtries.'" />'."\n";
     $result.='</td></tr></table>'."\n";
+    my $files=&get_submitted_files($udom,$uname,$partid,$counter,$record);
+    if (@$files) {
+        my $file_counter = 0;
+	foreach my $file (@$files) {
+            $result.=' Return commented document to student. <input type="file" name="part'.$partid.'_returndoc';
+            $result.=$file_counter.'" />'."\n";
+            $result.='<input type="hidden" name="respid" value="'.$counter.'" />';
+            $result.='<input type="hidden" name="returndocorig'.$file_counter.'" value="'.$file.'" />';
+        }
+    }
+
+    
     return $result;
 }
 
@@ -1534,7 +1581,7 @@ sub submission {
 	}
 	my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};
 
-	$request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".
+	$request->print('<form action="/adm/grades" method="post" name="SCORE" enctype="multipart/form-data">'."\n".
 			'<input type="hidden" name="command"    value="handgrade" />'."\n".
 			'<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
 			'<input type="hidden" name="Status"     value="'.$env{'form.Status'}.'" />'."\n".
@@ -1749,24 +1796,23 @@ KEYWORDS
 			$lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.
 			    $display_part.' <font color="#999999">( ID '.$respid.
 			    ' )</font>&nbsp; &nbsp;';
-			my @files;
-			if ($record{"resource.$partid.$respid.portfiles"}) {
-			    my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
-			    foreach my $file (split(',',$record{"resource.$partid.$respid.portfiles"})) {
-				push(@files,$file_url.$file);
-			    
-				&Apache::lonnet::logthis("found a portfolio file".$record{"resource.$partid.$respid.portfiles"});
-				&Apache::lonnet::logthis("uploaded URL file".$record{"resource.$partid.$respid.uploadedurl"});
-			    }
-			}
-			if ($record{"resource.$partid.$respid.uploadedurl"}) {
-			    push(@files,$record{"resource.$partid.$respid.uploadedurl"});
-			}
-			if (@files) {
+			my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
+#			if ($record{"resource.$partid.$respid.portfiles"}) {
+#			    my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
+#			    foreach my $file (split(',',$record{"resource.$partid.$respid.portfiles"})) {
+#				push(@files,$file_url.$file);
+#			    }
+#			}
+#			if ($record{"resource.$partid.$respid.uploadedurl"}) {
+#			    push(@files,$record{"resource.$partid.$respid.uploadedurl"});
+#			}
+			if (@$files) {
 			    $lastsubonly.='<br /><font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';
-			    foreach my $file (@files) {
+			    my $file_counter = 0;
+			    foreach my $file (@$files) {
+			        $file_counter ++;
 				&Apache::lonnet::allowuploaded('/adm/grades',$file);
-				$lastsubonly.='<br /><a href="'.$file.'" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>';
+				$lastsubonly.='<br /><a href="'.$file.'" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border="0"> '.$file.'</a>';
 			    }
 			    $lastsubonly.='<br />';
 			}
@@ -1822,13 +1868,24 @@ KEYWORDS
 	    '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";
 	$result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
 	    ',\''.$msgfor.'\')"; TARGET=_self>'.
-	    'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> &nbsp;'.
+	    &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> ('.
+	    &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" />)'.
 	    '<img src="'.$request->dir_config('lonIconsURL').
 	    '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".
-	    '<br />&nbsp;(Message will be sent when you click on Save & Next below.)'."\n" 
-	    if ($env{'form.handgrade'} eq 'yes');
+	    '<br />&nbsp;('.
+	    &mt('Message will be sent when you click on Save & Next below.').")\n";
 	$request->print($result);
     }
+    if ($perm{'vgr'}) {
+	$request->print('<br />'.
+	    &Apache::loncommon::track_student_link(&mt('View recent activity'),
+						   $uname,$udom,'check'));
+    }
+    if ($perm{'opa'}) {
+	$request->print('<br />'.
+	    &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
+					 $uname,$udom,$symb,'check'));
+    }
 
     my %seen = ();
     my @partlist;
@@ -1927,6 +1984,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,35 +2004,40 @@ 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 <a href=\"".
+		if ($env{'form.withgrades'.$ctr}) {
+		    $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
+		    $message.=" for <a href=\"".
 		    &Apache::lonnet::clutter($url).
 		    "?symb=$symb\">$env{'form.probTitle'}</a>";
+		}
 		$msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,
-							       $env{'form.msgsub'},$message);
+							       $subject.' ['.
+							       &Apache::lonnet::declutter($url).']',$message);
+		$request->print('<br />'.&mt('Sending message to [_1]@[_2]',$uname,$udom).': '.
+				$msgstatus);
 	    }
 	    if ($env{'form.collaborator'.$ctr}) {
 		my @collabstrs=&Apache::loncommon::get_env_multiple("form.collaborator$ctr");
 		foreach my $collabstr (@collabstrs) {
 		    my ($part,@collaborators) = split(/:/,$collabstr);
-		    foreach (@collaborators) {
+		    foreach my $collaborator (@collaborators) {
 			my ($errorflag,$pts,$wgt) = 
-			    &saveHandGrade($request,$url,$symb,$_,$udom,$ctr,
+			    &saveHandGrade($request,$url,$symb,$collaborator,$udom,$ctr,
 					   $env{'form.unamedom'.$ctr},$part);
 			if ($errorflag eq 'not_allowed') {
-			    $request->print("<font color=\"red\">Not allowed to modify grades for $_:$udom</font>");
+			    $request->print("<font color=\"red\">Not allowed to modify grades for $collaborator:$udom</font>");
 			    next;
 			} else {
 			    if ($message ne '') {
-				$msgstatus = &Apache::lonmsg::user_normal_msg($_,$udom,$env{'form.msgsub'},$message);
+				$msgstatus = &Apache::lonmsg::user_normal_msg($collaborator,$udom,$env{'form.msgsub'},$message);
 			    }
-			    
 			}
 		    }
 		}
@@ -2018,9 +2083,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 +2127,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 +2149,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 +2198,7 @@ sub processHandGrade {
 	my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";
 	$the_end.='<b>Message: </b> No more students for this section or class.<br /><br />'."\n";
 	$the_end.='Click on the button below to return to the grading menu.<br /><br />'."\n";
-	$the_end.=&show_grading_menu_form ($symb,$url);
+	$the_end.=&show_grading_menu_form($symb,$url);
 	$request->print($the_end);
     }
     return '';
@@ -2140,7 +2217,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};
@@ -2210,26 +2289,78 @@ sub saveHandGrade {
 	    $newrecord{'resource.'.$new_part.'.regrader'}=
 		"$env{'user.name'}:$env{'user.domain'}";
 	}
+        if ($env{'form.part'.$new_part.'_returndoc1'}) {
+            # if multiple files are uploaded names will be 'returndoc2','returndoc3'
+           
+            my $portfolio_root = &Apache::loncommon::propath($domain,
+    					 $stuname).
+    					'/userfiles/portfolio';
+                $request->print('<br>'.$portfolio_root.'<br>');
+                
+    #                my $result=&Apache::lonnet::userfileupload('uploaddoc','',
+    #	        	 'portfolio'.$env{'form.currentpath'});
+    
+            my $file_counter = 1;
+            my $respid = $env{'form.respid'};
+            while ($env{'form.part'.$new_part.'_returndoc'.$file_counter}) {
+                my $fname=$env{'form.returndoc'.$file_counter.'.filename'};
+                $newrecord{"resource.$new_part.$respid.handback"} = $env{'form.returndocorig'.$file_counter};
+                $request->print("<br />".$fname." will be the uploaded file name");
+                $request->print("<font color=\"red\">Will upload document</font>".$env{'form.returndocorig'.$file_counter});
+                $file_counter++;
+            }
+        }
+	
 	# unless problem has been graded, set flag to version the submitted files
-	unless ($record{'resource.'.$new_part.'.solved'} =~ /^correct_/  || $record{'resource.'.$new_part.'.solved'} eq 'incorrect_by_override') {
+	unless ($record{'resource.'.$new_part.'.solved'} =~ /^correct_/  || 
+	        $record{'resource.'.$new_part.'.solved'} eq 'incorrect_by_override' ||
+	        $dropMenu eq 'reset status')
+	   {
 	    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);
+}
+sub get_submitted_files {
+    my ($udom,$uname,$partid,$respid,$record) = @_;
+    my @files;
+    if ($$record{"resource.$partid.$respid.portfiles"}) {
+        my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
+        foreach my $file (split(',',$$record{"resource.$partid.$respid.portfiles"})) {
+    	    push(@files,$file_url.$file);
+        }
+    }
+    if ($$record{"resource.$partid.$respid.uploadedurl"}) {
+        push(@files,$$record{"resource.$partid.$respid.uploadedurl"});
+    }
+    return (\@files);
 }
-
 # ----------- Provides number of tries since last reset.
 sub get_num_tries {
     my ($record,$last_reset,$part) = @_;
@@ -2291,58 +2422,94 @@ sub get_last_resets {
 
 # ----------- Handles creating versions for portfolio files as answers
 sub version_portfiles {
-    my ($record, $parts_graded, $courseid, $symb, $domain, $stuname, $v_flag) = @_;
+    my ($record, $parts_graded, $courseid, $symb, $domain, $stu_name, $v_flag) = @_;
     my $version_parts = join('|',@$v_flag);
     my $parts = join('|', @$parts_graded);
     my $portfolio_root = &Apache::loncommon::propath($domain,
-						 $stuname).
+						 $stu_name).
 						'/userfiles/portfolio';
     foreach my $key (keys(%$record)) {
         my $new_portfiles;
-	
         if ($key =~ /^resource\.($version_parts)\./ && $key =~ /\.portfiles$/ ) {
             my @v_portfiles;
             my @portfiles = split(/,/,$$record{$key});
-            &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 =~ /^(.*?)([^\/]*$)/);
+                &Apache::lonnet::unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file);
+                my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/);
                 my $version = 0;
-                my @answer_file_parts = split(/\./, $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])) {
-                        # 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]};
-                        }
-                    }
-                }
-                $version++;
-                $env{'form.copy'} = &Apache::lonnet::getfile("/uploaded/$domain/$stuname/portfolio$directory$answer_file");
-                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]);
-                    &Apache::lonnet::mark_as_readonly($domain,$stuname,
-                                ['/portfolio'.$directory.$answer_file_parts[0].'.'.$version.'.'.$answer_file_parts[-1]],
-                                [$symb,$env{'request.course.id'},'graded']);
+		my ($answer_name,$answer_ver,$answer_ext) =
+		    &file_name_version_ext($answer_file);
+                my @dir_list = &Apache::lonnet::dirlist($directory,$domain,$stu_name,$portfolio_root);
+                $version = &get_next_version($answer_name, $answer_ext, \@dir_list);
+                my $new_answer = &version_selected_portfile($domain, $stu_name, $directory, $answer_file, $version);
+                if ($new_answer ne 'problem getting file') {
+                    push(@v_portfiles, $directory.$new_answer);
+                    &Apache::lonnet::mark_as_readonly($domain,$stu_name,
+                        ['/portfolio'.$directory.$new_answer],
+                        [$symb,$env{'request.course.id'},'graded']);
                 }
+                
             }
             $$record{$key} = join(',',@v_portfiles);
         }
     } 
     return 'ok';   
-    
+}
+
+sub get_next_version {
+    my ($answer_name, $answer_ext, $dir_list);
+    my $version;
+    foreach my $row (@$dir_list) {
+        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 ($file_version ne '') {
+                # a versioned file is found  so save it for later
+                if ($file_version > $version) {
+		    $version = $file_version;
+	        }
+            }
+        }
+    } 
+    $version ++;
+    return($version);
+}
+
+sub version_selected_portfile {
+    my ($domain,$stu_name,$directory,$file_name,$version) = @_;
+    my ($answer_name,$answer_ver,$answer_ext) =
+        &file_name_version_ext($file_name);
+    my $new_answer;
+    $env{'form.copy'} = &Apache::lonnet::getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name");
+    if($env{'form.copy'} eq '-1') {
+        &Apache::lonnet::logthis('problem getting file '.$file_name);
+        $new_answer = 'problem getting file';
+    } else {
+        $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;
+        my $copy_result = &Apache::lonnet::finishuserfileupload(
+                            $stu_name,$domain,'copy',
+		        '/portfolio'.$directory.$new_answer);
+    }    
+    return ($new_answer);
+}
+
+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);
 }
 
 #--------------------------------------------------------------------------------------
@@ -2394,6 +2561,7 @@ sub viewgrades_js {
 	}
 	for (i=0;i<document.classgrade.total.value;i++) {
 	    var user = document.classgrade["ctr"+i].value;
+	    user = user.replace(new RegExp(':', 'g'),"_");
 	    var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 	    var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 	    var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2421,6 +2589,7 @@ sub viewgrades_js {
 
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 		var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2438,6 +2607,7 @@ sub viewgrades_js {
 	} else {
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 		var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2496,6 +2666,7 @@ sub viewgrades_js {
 
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var resetscore = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		resetscore.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;
 		var resettries = document.classgrade["GD_"+user+"_"+partid+"_tries"];
@@ -2579,9 +2750,9 @@ sub viewgrades {
 	$result.='<table border="0"><tr>';  
 	my $ctr = 0;
 	while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
-	    $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.
+	    $result.= '<td><label><input type="radio" name="RADVAL_'.$partid.'" '.
 		'onclick="javascript:writePoint(\''.$partid.'\','.$weight{$partid}.
-		','.$ctr.')" />'.$ctr."</td>\n";
+		','.$ctr.')" />'.$ctr."</label></td>\n";
 	    $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
 	    $ctr++;
 	}
@@ -2638,7 +2809,13 @@ sub viewgrades {
     #list all the students - with points and grade status
     my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1');
     my $ctr = 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))) {
 	$ctr++;
 	$result.=&viewstudentgrade($url,$symb,$env{'request.course.id'},
 				   $_,$$fullname{$_},\@parts,\%weight,$ctr,\%last_resets);
@@ -2822,13 +2999,14 @@ sub editgrades {
 	    my $dropMenu = $env{'form.GD_'.$user.'_'.$_.'_solved'};
 	    $score = 'excused' if (($dropMenu eq 'excused') && ($score ne 'excused'));
 
+	    $newrecord{'resource.'.$_.'.regrader'}=
+		"$env{'user.name'}:$env{'user.domain'}";
 	    if ($dropMenu eq 'reset status' &&
 		$old_score ne '') { # ignore if no previous attempts => 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 +3044,38 @@ sub editgrades {
 	    }
 	}
 	$line.='</tr>'."\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.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$updateCtr.'&nbsp;</td>'.$line;
 	    $updateCtr++;
 	} else {
@@ -2878,8 +3084,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) {
@@ -3143,8 +3348,13 @@ sub csvuploadmap {
 	    unshift(@fields,['none','']);
 	    $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
 							    \@fields);
-	    my %sone=&Apache::loncommon::record_sep($records[0]);
-	    $keyfields=join(',',sort(keys(%sone)));
+            foreach my $rec (@records) {
+                my %temp = &Apache::loncommon::record_sep($rec);
+                if (%temp) {
+                    $keyfields=join(',',sort(keys(%temp)));
+                    last;
+                }
+            }
 	}
     }
     &csvuploadmap_footer($request,$i,$keyfields);
@@ -3162,13 +3372,14 @@ sub csvuploadoptions {
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <h3><font color="#339933">Uploading Class Grade Options</font></h3>
 <input type="hidden" name="command"    value="csvuploadassign" />
-<input type="submit" value="Assign Grades" /><br />
+<!--
 <p>
 <label>
    <input type="checkbox" name="show_full_results" />
    Show a table of all changes
 </label>
 </p>
+-->
 <p>
 <label>
    <input type="checkbox" name="overwite_scores" checked="checked" />
@@ -3190,7 +3401,8 @@ ENDPICK
     }
     # FIXME do a check for any duplicated user ids...
     # FIXME do a check for any invalid user ids?...
-    $request->print("<hr /></form>\n");
+    $request->print('<input type="submit" value="Assign Grades" /><br />
+<hr /></form>'."\n");
     $request->print(&show_grading_menu_form($symb,$url));
     return '';
 }
@@ -3286,9 +3498,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("<p>
+                              <font color='red'>
+                                 Failed to store student $username\@$domain.
+                                 Message when trying to store was ($result)
+                              </font>
+                             </p>" );
+	}
 	$request->rflush();
 	$countdone++;
     }
@@ -3365,13 +3587,13 @@ LISTJAVASCRIPT
     $result.='<input type="hidden" name="page" />'."\n".
 	'<input type="hidden" name="title" />'."\n";
 
-    $result.='&nbsp;<b>View Problems Text: </b><input type="radio" name="vProb" value="no" checked="on" /> no '."\n".
-	'<input type="radio" name="vProb" value="yes" /> yes '."<br>\n";
+    $result.='&nbsp;<b>View Problems Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
+	'<label><input type="radio" name="vProb" value="yes" /> yes </label>'."<br />\n";
 
     $result.='&nbsp;<b>Submission Details: </b>'.
-	'<input type="radio" name="lastSub" value="none" /> none'."\n".
-	'<input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions'."\n".
-	'<input type="radio" name="lastSub" value="all" /> all details'."\n";
+	'<label><input type="radio" name="lastSub" value="none" /> none</label>'."\n".
+	'<label><input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions</label>'."\n".
+	'<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
 
     $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
 	'<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
@@ -3395,12 +3617,18 @@ 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 ? '<tr bgcolor="#ffffe6">' : '</td>');
 	$studentTable.='<td align="right">'.$ptr.'&nbsp;</td>';
-	$studentTable.='<td>&nbsp;<input type="radio" name="student" value="'.$student.'" /> '
-	    .&nameUserString(undef,$$fullname{$student},$uname,$udom)."\n";
+	$studentTable.='<td>&nbsp;<label><input type="radio" name="student" value="'.$student.'" /> '
+	    .&nameUserString(undef,$$fullname{$student},$uname,$udom)."</label>\n";
 	$studentTable.=($ptr%2 == 0 ? '</td></tr>' : '');
 	$ptr++;
     }
@@ -3472,7 +3700,11 @@ sub displayPage {
     my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
-
+    if (!$map) {
+	$request->print('<font color="red">Unable to view requested sequence. ('.$resUrl.')</font>');
+	$request->print(&show_grading_menu_form($symb,$url));
+	return; 
+    }
     my $iterator = $navmap->getIterator($map->map_start(),
 					$map->map_finish());
 
@@ -3678,7 +3910,12 @@ sub updateGradeByPage {
     my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
-
+    if (!$map) {
+	$request->print('<font color="red">Unable to grade requested sequence. ('.$resUrl.')</font>');
+	my ($symb,$url)=&get_symb_and_url($request);
+	$request->print(&show_grading_menu_form($symb,$url));
+	return; 
+    }
     my $iterator = $navmap->getIterator($map->map_start(),
 					$map->map_finish());
 
@@ -3883,11 +4120,11 @@ sub scantron_CODElist {
 sub scantron_CODEunique {
     my $result='<nobr>
                  <label><input type="radio" name="scantron_CODEunique"
-                        value="Yes" checked="on" /> Yes </label>
+                        value="yes" checked="checked" /> Yes </label>
                 </nobr>
                 <nobr>
                  <label><input type="radio" name="scantron_CODEunique"
-                        value="No" /> No </label>
+                        value="no" /> No </label>
                 </nobr>';
     return $result;
 }
@@ -4018,7 +4255,7 @@ SCANTRONFORM
             </tr>
             <tr bgcolor="#ffffe6">
               <td colspan="2">
-                <input type="submit" value="Show List of Files" />
+                <input type="submit" value="Download: Show List of Associated Files" />
               </td>
             </tr>
           </table>
@@ -4324,7 +4561,7 @@ sub scantron_process_corrections {
 	}
     }
     if ($err) {
-	$r->print("Unable to accept last correction, an error occurred :$errmsg:");
+	$r->print("<font color='red'>Unable to accept last correction, an error occurred :$errmsg:</font>");
     } else {
 	&scantron_put_line($scanlines,$scan_data,$which,$line,$skip);
 	&scantron_putfile($scanlines,$scan_data);
@@ -5390,28 +5627,30 @@ GRADINGMENUJS
 
     $result.='</td></tr>';
 
-    $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
+    $result.='<tr bgcolor="#ffffe6"valign="top"><td><label>'.
 	'<input type="radio" name="radioChoice" value="submission" '.
 	($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
-	' <select name="submitonly">'.
+	'</label> <select name="submitonly">'.
 	'<option value="yes" '.
-	($saveSub eq 'yes' ? 'selected="on"' : '').'>with submissions</option>'.
+	($saveSub eq 'yes' ? 'selected="on"' : '').'>'.&mt('with submissions').'</option>'.
+	'<option value="queued" '.
+	($saveSub eq 'queued' ? 'selected="on"' : '').'>'.&mt('in grading queue').'</option>'.
 	'<option value="graded" '.
-	($saveSub eq 'graded' ? 'selected="on"' : '').'>with ungraded submissions</option>'.
+	($saveSub eq 'graded' ? 'selected="on"' : '').'>'.&mt('with ungraded submissions').'</option>'.
 	'<option value="incorrect" '.
-	($saveSub eq 'incorrect' ? 'selected="on"' : '').'>with incorrect submissions</option>'.
+	($saveSub eq 'incorrect' ? 'selected="on"' : '').'>'.&mt('with incorrect submissions').'</option>'.
 	'<option value="all" '.
-	($saveSub eq 'all' ? 'selected="on"' : '').'>with any status</option></select></td></tr>'."\n";
+	($saveSub eq 'all' ? 'selected="on"' : '').'>'.&mt('with any status').'</option></select></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
-	'<input type="radio" name="radioChoice" value="viewgrades" '.
+	'<label><input type="radio" name="radioChoice" value="viewgrades" '.
 	($saveCmd eq 'viewgrades' ? 'checked' : '').'> '.
-	'<b>Current Resource:</b> For all students in selected section or course</td></tr>'."\n";
+	'<b>Current Resource:</b> For all students in selected section or course</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.
-	'<input type="radio" name="radioChoice" value="pickStudentPage" '.
+	'<label><input type="radio" name="radioChoice" value="pickStudentPage" '.
 	($saveCmd eq 'pickStudentPage' ? 'checked' : '').'> '.
-	'The <b>complete</b> set/page/sequence: For one student</td></tr>'."\n";
+	'The <b>complete</b> set/page/sequence: For one student</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"><td><br />'.
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="Next->" />'.
@@ -5455,18 +5694,18 @@ sub reset_perm {
 
 sub init_perm {
     &reset_perm();
-    if (!($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}))) {
-	if ($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
-	    $perm{'vgr_section'}=$env{'request.course.sec'};
-	} else {
-	    delete($perm{'vgr'});
-	}
-    }
-    if (!($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}))) {
-	if ($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
-	    $perm{'mgr_section'}=$env{'request.course.sec'};
-	} else {
-	    delete($perm{'mgr'});
+    foreach my $test_perm ('vgr','mgr','opa') {
+
+	my $scope = $env{'request.course.id'};
+	if (!($perm{$test_perm}=&Apache::lonnet::allowed($test_perm,$scope))) {
+
+	    $scope .= '/'.$env{'request.course.sec'};
+	    if ( $perm{$test_perm}=
+		 &Apache::lonnet::allowed($test_perm,$scope)) {
+		$perm{$test_perm.'_section'}=$env{'request.course.sec'};
+	    } else {
+		delete($perm{$test_perm});
+	    }
 	}
     }
 }