--- loncom/homework/grades.pm 2003/03/24 21:03:54 1.76 +++ loncom/homework/grades.pm 2003/07/15 20:59:53 1.116 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.76 2003/03/24 21:03:54 ng Exp $ +# $Id: grades.pm,v 1.116 2003/07/15 20:59:53 ng Exp $ # # Copyright Michigan State University Board of Trustees # @@ -41,11 +41,16 @@ use Apache::style; use Apache::lonxml; use Apache::lonnet; use Apache::loncommon; +use Apache::lonhtmlcommon; use Apache::lonnavmaps; use Apache::lonhomework; use Apache::loncoursedata; use Apache::lonmsg qw(:user_normal_msg); use Apache::Constants qw(:common); +use String::Similarity; + +my %oldessays=(); +my %perm=(); # ----- These first few routines are general use routines.---- # @@ -125,60 +130,67 @@ sub getclasslist { my (undef,undef,$end,$start,$id,$section,$fullname,$status)= @{$classlist->{$_}}; # filter students according to status selected - if ($filterlist && $ENV{'form.saveStatus'} ne 'Any') { - if ($ENV{'form.saveStatus'} ne $status) { + if ($filterlist && $ENV{'form.Status'} ne 'Any') { + if ($ENV{'form.Status'} ne $status) { delete ($classlist->{$_}); next; } } $section = ($section ne '' ? $section : 'no'); - if ($getsec eq 'all' || $getsec eq $section) { - $sections{$section}++; - $fullnames{$_}=$fullname; - } else { - delete($classlist->{$_}); - } + if (&canview($section)) { + if ($getsec eq 'all' || $getsec eq $section) { + $sections{$section}++; + $fullnames{$_}=$fullname; + } else { + delete($classlist->{$_}); + } + } else { + delete($classlist->{$_}); + } } my %seen = (); my @sections = sort(keys(%sections)); return ($classlist,\@sections,\%fullnames); } -#find user domain -sub finduser { - my ($name) = @_; - my $domain = ''; - if ( $Apache::grades::viewgrades eq 'F' ) { - my %classlist=&Apache::lonnet::dump('classlist', - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - my (@fields) = grep /^$name:/, keys %classlist; - ($name, $domain) = split(/:/,$fields[0]); - return ($name,$domain); - } else { - return ($ENV{'user.name'},$ENV{'user.domain'}); +sub canmodify { + my ($sec)=@_; + if ($perm{'mgr'}) { + if (!defined($perm{'mgr_section'})) { + # can modify whole class + return 1; + } else { + if ($sec eq $perm{'mgr_section'}) { + #can modify the requested section + return 1; + } else { + # can't modify the request section + return 0; + } + } } + #can't modify + return 0; } -#--- Prompts a user to enter a username. -sub moreinfo { - my ($request,$reason) = @_; - $request->print("Unable to process request: $reason"); - if ( $Apache::grades::viewgrades eq 'F' ) { - $request->print('<form action="/adm/grades" method="post">'."\n"); - if ($ENV{'form.url'}) { - $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n"); - } - if ($ENV{'form.symb'}) { - $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n"); - } - $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n"); - $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n"); - $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n"); - $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n"); - $request->print('</form>'); +sub canview { + my ($sec)=@_; + if ($perm{'vgr'}) { + if (!defined($perm{'vgr_section'})) { + # can modify whole class + return 1; + } else { + if ($sec eq $perm{'vgr_section'}) { + #can modify the requested section + return 1; + } else { + # can't modify the request section + return 0; + } + } } - return ''; + #can't modify + return 0; } #--- Retrieve the grade status of a student for all the parts @@ -211,10 +223,7 @@ sub jscriptNform { $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n". '<input type="hidden" name="command" value="submission" />'."\n". '<input type="hidden" name="student" value="" />'."\n". @@ -224,6 +233,50 @@ sub jscriptNform { } #------------------ End of general use routines -------------------- + +# +# Find most similar essay +# + +sub most_similar { + my ($uname,$udom,$uessay)=@_; + +# ignore spaces and punctuation + + $uessay=~s/\W+/ /gs; + +# these will be returned. Do not care if not at least 50 percent similar + my $limit=0.6; + my $sname=''; + my $sdom=''; + my $scrsid=''; + my $sessay=''; +# go through all essays ... + foreach my $tkey (keys %oldessays) { + my ($tname,$tdom,$tcrsid)=split(/\./,$tkey); +# ... except the same student + if (($tname ne $uname) || ($tdom ne $udom)) { + my $tessay=$oldessays{$tkey}; + $tessay=~s/\W+/ /gs; +# String similarity gives up if not even limit + my $tsimilar=&String::Similarity::similarity($uessay,$tessay,$limit); +# Found one + if ($tsimilar>$limit) { + $limit=$tsimilar; + $sname=$tname; + $sdom=$tdom; + $scrsid=$tcrsid; + $sessay=$oldessays{$tkey}; + } + } + } + if ($limit>0.6) { + return ($sname,$sdom,$scrsid,$sessay,$limit); + } else { + return ('','','','',0); + } +} + #------------------------------------------------------------------- #------------------------------------ Receipt Verification Routines @@ -301,7 +354,7 @@ sub listStudents { '<td><b>Type: </b>'.$responsetype.'</td>'. '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>'; } - $result.='</table>'; + $result.='</table>'."\n"; my $viewgrade = $ENV{'form.handgrade'} eq 'yes' ? 'View/Grade' : 'View'; $ENV{'form.probTitle'} = $ENV{'form.probTitle'} eq '' ? @@ -315,28 +368,47 @@ sub listStudents { $request->print(<<LISTJAVASCRIPT); <script type="text/javascript" language="javascript"> - function checkSelect(checkBox) { - var ctr=0; - var sense=""; - if (checkBox.length > 1) { - for (var i=0; i<checkBox.length; i++) { - if (checkBox[i].checked) { - ctr++; - } - } - sense = "a student or group of students"; - } else { - if (checkBox.checked) { - ctr = 1; - } - sense = "the student"; + function checkSelect(checkBox) { + var ctr=0; + var sense=""; + if (checkBox.length > 1) { + for (var i=0; i<checkBox.length; i++) { + if (checkBox[i].checked) { + ctr++; + } + } + sense = "a student or group of students"; + } else { + if (checkBox.checked) { + ctr = 1; + } + sense = "the student"; + } + if (ctr == 0) { + alert("Please select "+sense+" before clicking on the $viewgrade button."); + return false; + } + document.gradesub.submit(); } - if (ctr == 0) { - alert("Please select "+sense+" before clicking on the $viewgrade button."); - return false; + + function reLoadList(formname) { + if (formname.saveStatusOld.value == pullDownSelection(formname.Status)) {return;} + formname.command.value = 'submission'; + formname.submit(); + } + + function pullDownSelection(selectOne) { + var selection=""; + if (selectOne.length > 1) { + for (var i=0; i<selectOne.length; i++) { + if (selectOne[i].selected) { + return selectOne[i].value; + } + } + } else { + if (selectOne.selected) return selectOne.value; + } } - document.gradesub.submit(); - } </script> LISTJAVASCRIPT @@ -346,13 +418,17 @@ LISTJAVASCRIPT my $checklastsub = $ENV{'form.handgrade'} eq 'yes' ? '' : 'checked'; my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'."\n". - ' <b>View Problem: </b><input type="radio" name="vProb" value="no" /> no '."\n". - '<input type="radio" name="vProb" value="yes" checked /> one student '."\n". + ' <b>View Problem Text: </b><input type="radio" name="vProb" value="no" checked /> no '."\n". + '<input type="radio" name="vProb" value="yes" /> one student '."\n". '<input type="radio" name="vProb" value="all" /> all students <br />'."\n". ' <b>Submissions: </b>'."\n"; if ($ENV{'form.handgrade'} eq 'yes') { $gradeTable.='<input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> handgrade only'."\n"; } + + my $saveStatus = $ENV{'form.Status'} eq '' ? 'Active' : $ENV{'form.Status'}; + $ENV{'form.Status'} = $saveStatus; + $gradeTable.='<input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last sub only'."\n". '<input type="radio" name="lastSub" value="last" /> last sub & parts info'."\n". '<input type="radio" name="lastSub" value="all" /> all details'."\n". @@ -361,72 +437,99 @@ LISTJAVASCRIPT '<input type="hidden" name="response" value="'.$ENV{'form.response'}.'" />'."\n". '<input type="hidden" name="handgrade" value="'.$ENV{'form.handgrade'}.'" /><br />'."\n". '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" /><br />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". - 'To '.lc($viewgrade).' a submission, click on the check box next to the student\'s name. Then '."\n". + '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n"; + + $gradeTable.='<b>Student Status:</b> '. + &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);').'<br />'; + + $gradeTable.='To '.lc($viewgrade).' a submission, click on the check box next to the student\'s name. Then '."\n". 'click on the '.$viewgrade.' button. To view the submissions for a group of students, click'."\n". ' on the check boxes for the group of students.<br />'."\n". - '<input type="hidden" name="command" value="processGroup" />'."\n". - '<input type="button" '."\n". + '<input type="hidden" name="command" value="processGroup" />'."\n"; + $gradeTable.='<input type="button" '."\n". 'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n". 'value="'.$viewgrade.'" />'."\n"; - - my (undef,undef,$fullname) = &getclasslist($getsec,$ENV{'form.showgrading'} eq 'yes' ? '1' : '0'); - + + my (undef, undef, $fullname) = &getclasslist($getsec,'1'); $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'. - '<table border="0"><tr bgcolor="#e6ffff">'. - '<td><b> Select </b></td><td><b> Fullname </b></td>'. - '<td><b> Username </b></td><td><b> Domain </b></td>'; - foreach (sort(@$partlist)) { - $gradeTable.='<td><b> Part '.(split(/_/))[0].' Status </b></td>'; + '<table border="0"><tr bgcolor="#e6ffff">'; + my $loop = 0; + while ($loop < 2) { + $gradeTable.='<td><b> Select </b></td><td><b> Fullname </b>'. + '<font color="#999999">(Username)</font> </td>'; + if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + foreach (sort(@$partlist)) { + $gradeTable.='<td><b> Part '.(split(/_/))[0].' Status </b></td>'; + } + } + $loop++; } $gradeTable.='</tr>'."\n"; my $ctr = 0; foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom) = split(/:/,$student); - my (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist); - my $statusflg = ''; - foreach (keys(%status)) { - $statusflg = 1 if ($status{$_} ne 'nothing'); - my ($foo,$partid,$foo1) = split(/\./,$_); - if ($status{'resource.'.$partid.'.submitted_by'} ne '') { - $statusflg = ''; - $gradeTable.='<input type="hidden" name="'. - $student.':submitted_by" value="'. - $status{'resource.'.$partid.'.submitted_by'}.'" />'; + my %status = (); + if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist); + my $statusflg = ''; + foreach (keys(%status)) { + $statusflg = 1 if ($status{$_} ne 'nothing'); + my ($foo,$partid,$foo1) = split(/\./,$_); + if ($status{'resource.'.$partid.'.submitted_by'} ne '') { + $statusflg = ''; + $gradeTable.='<input type="hidden" name="'. + $student.':submitted_by" value="'. + $status{'resource.'.$partid.'.submitted_by'}.'" />'; + } } + next if ($statusflg eq '' && $submitonly eq 'yes'); } - next if ($statusflg eq '' && $submitonly eq 'yes'); $ctr++; - if ( $Apache::grades::viewgrades eq 'F' ) { - $gradeTable.='<tr bgcolor="#ffffe6">'. - '<td align="center"><input type=checkbox name="stuinfo" value="'. - $student.':'.$$fullname{$student}.'"></td>'."\n". - '<td> '.$$fullname{$student}.' </td>'."\n". - '<td> '.$uname.' </td>'."\n". - '<td align="middle"> '.$udom.' </td>'."\n"; - - foreach (sort keys(%status)) { - next if (/^resource.*?submitted_by$/); - $gradeTable.='<td align="middle"> '.$status{$_}.' </td>'."\n"; + if ( $perm{'vgr'} eq 'F' ) { + $gradeTable.='<tr bgcolor="#ffffe6">' if ($ctr%2 ==1); + $gradeTable.='<td align="center"><input type=checkbox name="stuinfo" value="'. + $student.':'.$$fullname{$student}.' "></td>'."\n". + '<td> '.$$fullname{$student}.' '."\n". + '<font color="#999999">('.$uname.')</font></td>'."\n"; + + if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + foreach (sort keys(%status)) { + next if (/^resource.*?submitted_by$/); + $gradeTable.='<td align="middle"> '.$status{$_}.' </td>'."\n"; + } } - $gradeTable.='</tr>'."\n"; + $gradeTable.='</tr>'."\n" if ($ctr%2 ==0); } } + if ($ctr%2 ==1) { + $gradeTable.='<td> </td><td> </td>'; + if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') { + foreach (@$partlist) { + $gradeTable.='<td> </td>'; + } + } + $gradeTable.='</tr>'; + } + $gradeTable.='</table></td></tr></table>'. '<input type="button" '. 'onClick="javascript:checkSelect(this.form.stuinfo);" '. 'value="'.$viewgrade.'" /></form>'."\n"; if ($ctr == 0) { - $gradeTable='<br /> <font color="red">'. - 'No submission found for this resource.</font><br />'; + my $num_students=(scalar(keys(%$fullname))); + if ($num_students eq 0) { + $gradeTable='<br /> <font color="red">There are no students currently enrolled.</font>'; + } else { + $gradeTable='<br /> <font color="red">'. + 'No submissions found for this resource for any students. ('.$num_students. + ' checked for submissions</font><br />'; + } } elsif ($ctr == 1) { $gradeTable =~ s/type=checkbox/type=checkbox checked/; } @@ -634,6 +737,7 @@ SUBJAVASCRIPT #--- javascript for essay type problem -- sub sub_page_kw_js { my $request = shift; + my $iconpath = $request->dir_config('lonIconsURL'); $request->print(<<SUBJAVASCRIPT); <script type="text/javascript" language="javascript"> @@ -681,6 +785,12 @@ sub sub_page_kw_js { } //====================== Script for composing message ============== + // preload images + img1 = new Image(); + img1.src = "$iconpath/mailbkgrd.gif"; + img2 = new Image(); + img2.src = "$iconpath/mailto.gif"; + function msgCenter(msgform,usrctr,fullname) { var Nmsg = msgform.savemsgN.value; savedMsgHeader(Nmsg,usrctr,fullname); @@ -716,7 +826,7 @@ sub sub_page_kw_js { height = 600; scrollbar = "yes"; } -// if (window.pWin) window.pWin.close(); +// if (window.pWin) {window.pWin.close(); window.pWin=null} pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx=70,screeny=75,width=600,height='+height); pWin.focus(); pDoc = pWin.document; @@ -735,18 +845,23 @@ sub sub_page_kw_js { pDoc.write(" if (document.msgcenter.subchk.checked) {"); pDoc.write(" msgchk = \\"msgsub,\\";"); pDoc.write(" }"); - pDoc.write( "for (var i=1; i<=nmsg; i++) {"); + pDoc.write(" var includemsg = 0;"); + pDoc.write(" for (var i=1; i<=nmsg; i++) {"); pDoc.write(" var opnmsg = eval(\\"opener.document.SCORE.savemsg\\"+i);"); pDoc.write(" var frmmsg = eval(\\"document.msgcenter.msg\\"+i);"); pDoc.write(" opnmsg.value = frmmsg.value;"); pDoc.write(" var chkbox = eval(\\"document.msgcenter.msgn\\"+i);"); pDoc.write(" if (chkbox.checked) {"); pDoc.write(" msgchk += \\"savemsg\\"+i+\\",\\";"); + pDoc.write(" includemsg = 1;"); pDoc.write(" }"); pDoc.write(" }"); pDoc.write(" if (document.msgcenter.newmsgchk.checked) {"); pDoc.write(" msgchk += \\"newmsg\\"+usrctr;"); + pDoc.write(" includemsg = 1;"); pDoc.write(" }"); + pDoc.write(" imgformname = eval(\\"opener.document.SCORE.mailicon\\"+usrctr);"); + pDoc.write(" imgformname.src = \\"$iconpath/\\"+((includemsg) ? \\"mailto.gif\\" : \\"mailbkgrd.gif\\");"); pDoc.write(" var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);"); pDoc.write(" includemsg.value = msgchk;"); @@ -992,11 +1107,19 @@ sub submission { (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; my ($uname,$udom) = ($ENV{'form.student'},$ENV{'form.userdom'}); - ($uname,$udom) = &finduser($uname) if $udom eq ''; + my $usec = &Apache::lonnet::getsection($udom,$uname,$ENV{'request.course.id'}); $ENV{'form.fullname'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq ''; my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url))); if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; } + + if (!&canview($usec)) { + $request->print('<font color="red">Unable to view requested student.('. + $uname.$udom.$usec.$ENV{'request.course.id'}.')</font>'); + $request->print(&show_grading_menu_form($symb,$url)); + return; + } + my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : ''); # header info @@ -1036,10 +1159,7 @@ sub submission { $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n". '<input type="hidden" name="command" value="handgrade" />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n". '<input type="hidden" name="refresh" value="off" />'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". @@ -1063,13 +1183,18 @@ sub submission { my ($cts,$prnmsg) = (1,''); while ($cts <= $ENV{'form.savemsgN'}) { $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'. - ($keyhash{$symb.'_savemsg'.$cts} eq '' ? $ENV{'form.savemsg'.$cts} : $keyhash{$symb.'_savemsg'.$cts}). + ($keyhash{$symb.'_savemsg'.$cts} eq '' ? + &Apache::lonfeedback::clear_out_html($ENV{'form.savemsg'.$cts}) : + &Apache::lonfeedback::clear_out_html($keyhash{$symb.'_savemsg'.$cts})). '" />'."\n"; $cts++; } $request->print($prnmsg); if ($ENV{'form.handgrade'} eq 'yes' && $ENV{'form.showgrading'} eq 'yes') { +# +# Print out the keyword options line +# $request->print(<<KEYWORDS); <b>Keyword Options:</b> <a href="javascript:keywords(document.SCORE.keywords)"; TARGET=_self>List</a> @@ -1077,6 +1202,14 @@ sub submission { CLASS="page">Paste Selection to List</a> <a href="javascript:kwhighlight()"; TARGET=_self>Highlight Attribute</a><br /><br /> KEYWORDS +# +# Load the other essays for similarity check +# + my $essayurl=&Apache::lonnet::declutter($url); + my ($adom,$aname,$apath)=($essayurl=~/^(\w+)\/(\w+)\/(.*)$/); + $apath=&Apache::lonnet::escape($apath); + $apath=~s/\W/\_/gs; + %oldessays=&Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); } } @@ -1094,17 +1227,17 @@ KEYWORDS '<table border="0" width=100%><tr bgcolor="#edffff"><td>'."\n"; $result.='<b>Fullname: </b>'.$ENV{'form.fullname'}. - '<font color="#999999"> Username: '.$uname.'</font>'. - '<font color="#999999"> Domain: '.$udom.'</font><br />'."\n"; + '<font color="#999999"> Username: '.$uname. + ($ENV{'user.domain'} eq $udom ? '' : ' ('.$udom.')').'</font><br />'."\n"; +# '<font color="#999999"> Domain: '.$udom.'</font><br />'."\n"; $result.='<input type="hidden" name="name'.$counter. '" value="'.$ENV{'form.fullname'}.'" />'."\n"; - # If this is handgraded, then check for collaborators + # If this is an essay-response part(handgraded), then check for collaborators my @col_fullnames; my ($classlist,$fullname); if ($ENV{'form.handgrade'} eq 'yes') { - my @col_list; - ($classlist,undef,$fullname) = &getclasslist('all',$ENV{'form.showgrading'} eq 'yes' ? '1' : '0'); + ($classlist,undef,$fullname) = &getclasslist('all','0'); for (keys (%$handgrade)) { my $ncol = &Apache::lonnet::EXT('resource.'.$_. '.maxcollaborators', @@ -1112,50 +1245,46 @@ KEYWORDS next if ($ncol <= 0); s/\_/\./g; next if ($record{'resource.'.$_.'.collaborators'} eq ''); - my (@collaborators) = split(/,?\s+/, - $record{'resource.'.$_.'.collaborators'}); - my (@badcollaborators); - if (scalar(@collaborators) != 0) { + my @goodcollaborators = (); + my @badcollaborators = (); + foreach (split(/,?\s+/,$record{'resource.'.$_.'.collaborators'})) { + $_ =~ s/[\$\^\(\)]//g; + next if ($_ eq ''); + my ($co_name,$co_dom) = split /\@|:/,$_; + $co_dom = $udom if (! defined($co_dom) || $co_dom =~ /^domain$/i); + next if ($co_name eq $uname && $co_dom eq $udom); + # Doing this grep allows 'fuzzy' specification + my @Matches = grep /^$co_name:$co_dom$/i,keys %$classlist; + if (! scalar(@Matches)) { + push @badcollaborators,$_; + } else { + push @goodcollaborators, @Matches; + } + } + if (scalar(@goodcollaborators) != 0) { $result.='<b>Collaborators: </b>'; - foreach my $collaborator (@collaborators) { - my ($co_name,$co_dom) = split /\@|:/,$collaborator; - $co_dom = $udom if (! defined($co_dom)); - next if ($co_name eq $uname && $co_dom eq $udom); - # Doing this grep allows 'fuzzy' specification - my @Matches = grep /^$co_name:$co_dom/i, - keys %$classlist; - if (! scalar(@Matches)) { - push @badcollaborators,$collaborator; - next; - } - push @col_list, @Matches; - foreach (@Matches) { - my ($lastname,$givenn) = split(/,/,$$fullname{$_}); - push @col_fullnames, $givenn.' '.$lastname; - $result.=$$fullname{$_}.' '; - } - } + foreach (@goodcollaborators) { + my ($lastname,$givenn) = split(/,/,$$fullname{$_}); + push @col_fullnames, $givenn.' '.$lastname; + $result.=$$fullname{$_}.' '; + } $result.='<br />'."\n"; - if (scalar(@badcollaborators) > 0) { - $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'; - $result.='This student has submitted '; - if (scalar(@badcollaborators) == 1) { - $result .= 'an invalid collaborator'; - } else { - $result .= 'invalid collaborators'; - } - $result .= ': '.join(', ',@badcollaborators); - - } - if (scalar(@collaborators > $ncol)) { - $result .= '<table border="0"><tr bgcolor="#ffbbbb"><td>'; - $result .= 'This student has submitted too many '. - 'collaborators. Maximum is '.$ncol; - $result .= '</td></tr></table>'; - } - $result.='<input type="hidden" name="collaborator'.$counter. - '" value="'.(join ':',@col_list).'" />'."\n"; - } + $result.='<input type="hidden" name="collaborator'.$counter. + '" value="'.(join ':',@goodcollaborators).'" />'."\n"; + } + if (scalar(@badcollaborators) > 0) { + $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'; + $result.='This student has submitted '; + $result.=(scalar(@badcollaborators) == 1) ? 'an invalid collaborator' : 'invalid collaborators'; + $result .= ': '.join(', ',@badcollaborators); + $result .= '</td></tr></table>'; + } + if (scalar(@badcollaborators > $ncol)) { + $result .= '<table border="0"><tr bgcolor="#ffbbbb"><td>'; + $result .= 'This student has submitted too many '. + 'collaborators. Maximum is '.$ncol.'.'; + $result .= '</td></tr></table>'; + } } } $request->print($result."\n"); @@ -1186,18 +1315,30 @@ KEYWORDS } else { for my $part (sort keys(%$handgrade)) { foreach (@$string) { - my ($partid,$respid) = /^resource\.(\d+)\.(\d+)\.submission/; + my ($partid,$respid) = /^resource\.(\w+)\.(\w+)\.submission/; if ($part eq ($partid.'_'.$respid)) { my ($ressub,$subval) = split(/:/,$_,2); +# Similarity check + my $similar=''; + my ($oname,$odom,$ocrsid,$oessay,$osim)=&most_similar($uname,$udom,$subval); + if ($osim) { + $osim=int($osim*100.0); + $similar='<hr /><h3><font color="#FF0000">Essay is '.$osim. + '% similar to an essay by '.&Apache::loncommon::plainname($oname,$odom). + '</font></h3><blockquote><i>'. + &keywords_highlight($oessay).'</i></blockquote><hr />'; + } $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '. $partid.'</b> <font color="#999999">( ID '.$respid. ' )</font> '. ($record{"resource.$partid.$respid.uploadedurl"}? '<a href="'. &Apache::lonnet::tokenwrapper($record{"resource.$partid.$respid.uploadedurl"}). - '"><img src="/adm/lonIcons/unknown.gif" border=0"> File uploaded by student</a> <font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />':''). - '<b>Answer: </b>'. - &keywords_highlight($subval).'</td></tr>'."\n" + '"><img src="/adm/lonIcons/unknown.gif" border=0"> File uploaded by student</a> '. + '<font color="red" size="1">Like all files provided by users, '. + 'this file may contain virusses</font><br />':''). + '<b>Answer: </b><blockquote>'. + &keywords_highlight($subval).'</blockquote><br /> '.$similar.'</td></tr>'."\n" if ($ENV{'form.lastSub'} eq 'lastonly' || ($ENV{'form.lastSub'} eq 'hdgrade' && $$handgrade{$part} =~ /:yes$/)); @@ -1216,7 +1357,8 @@ KEYWORDS } # return if view submission with no grading option - if ($ENV{'form.showgrading'} eq '') { +# if ($ENV{'form.showgrading'} eq '' || (!&canmodify($usec))) { + if (!&canmodify($usec)) { $request->print('</td></tr></table></td></tr></table></form>'."\n"); $request->print(&show_grading_menu_form($symb,$url)) if (($ENV{'form.command'} eq 'submission') || @@ -1235,10 +1377,13 @@ KEYWORDS my $lastone = pop @col_fullnames; $msgfor .= ', '.(join ', ',@col_fullnames).' and '.$lastone.'.'; } + $msgfor =~ s/\'/\\'/g; #' stupid emacs - no! javascript $result.='<tr><td bgcolor="#ffffff">'."\n". ' <a href="javascript:msgCenter(document.SCORE,'.$counter. ',\''.$msgfor.'\')"; TARGET=_self>'. - 'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a>'. + 'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> '. + '<img src="'.$request->dir_config('lonIconsURL'). + '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n". '<br /> (Message will be sent when you click on Save & Next below.)'."\n" if ($ENV{'form.handgrade'} eq 'yes'); $request->print($result); @@ -1249,7 +1394,7 @@ KEYWORDS my ($partid,$respid) = split(/_/); next if ($seen{$partid} > 0); $seen{$partid}++; - next if ($$handgrade{$_} =~ /:no$/); +# next if ($$handgrade{$_} =~ /:no$/); push @partlist,$partid; $request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record)); @@ -1352,12 +1497,16 @@ sub processHandGrade { my $ctr = 0; while ($ctr < $ngrade) { my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr}); - my ($errorflag) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr); + my ($errorflag,$pts,$wgt) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr); if ($errorflag eq 'no_score') { $ctr++; next; } - + if ($errorflag eq 'not_allowed') { + $request->print("<font color=\"red\">Not allowed to modify grades for $uname:$udom</font>"); + $ctr++; + next; + } my $includemsg = $ENV{'form.includemsg'.$ctr}; my ($subject,$message,$msgstatus) = ('','',''); if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { @@ -1366,19 +1515,27 @@ sub processHandGrade { foreach (@msgnum) { $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne ''); } - #$message =~ s/\s+/ /g; + $message =&Apache::lonfeedback::clear_out_html($message); + $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); } if ($ENV{'form.collaborator'.$ctr}) { my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr}); foreach (@collaborators) { - &saveHandGrade($request,$url,$symb,$_,$udom,$ctr, - $ENV{'form.unamedom'.$ctr}); - if ($message ne '') { - $msgstatus = &Apache::lonmsg::user_normal_msg ($_,$udom, - $ENV{'form.msgsub'}, - $message); + my ($errorflag,$pts,$wgt) = &saveHandGrade($request,$url,$symb,$_,$udom,$ctr,$ENV{'form.unamedom'.$ctr}); + if ($errorflag eq 'not_allowed') { + $request->print("<font color=\"red\">Not allowed to modify grades for $_:$udom</font>"); + next; + } else { + if ($message ne '') { + $msgstatus = &Apache::lonmsg::user_normal_msg ($_,$udom, + $ENV{'form.msgsub'}, + $message); + } } } } @@ -1427,12 +1584,20 @@ sub processHandGrade { $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); # Called by Save & Refresh from Highlight Attribute Window + my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'0'); if ($ENV{'form.refresh'} eq 'on') { - my $ctr = 0; - $ENV{'form.NTSTU'}=$ngrade; + my ($ctr,$total) = (0,0); while ($ctr < $ngrade) { - ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$ENV{'form.unamedom'.$ctr}); - &submission($request,$ctr,$ngrade-1); + $total++ if $ENV{'form.unamedom'.$ctr} ne ''; + $ctr++; + } + $ENV{'form.NTSTU'}=$ngrade; + $ctr = 0; + while ($ctr < $total) { + my $processUser = $ENV{'form.unamedom'.$ctr}; + ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$processUser); + $ENV{'form.fullname'} = $$fullname{$processUser}; + &submission($request,$ctr,$total-1); $ctr++; } return ''; @@ -1448,7 +1613,6 @@ sub processHandGrade { $laststu = $firststu if ($ctr > $ngrade); } - my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'0'); my (@parsedlist,@nextlist); my ($nextflg) = 0; foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { @@ -1504,8 +1668,12 @@ sub processHandGrade { #---- Save the score and award for each student, if changed sub saveHandGrade { my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_; - my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname); - my %newrecord; + my $usec = &Apache::lonnet::getsection($domain,$stuname, + $ENV{'request.course.id'}); + if (!&canmodify($usec)) { return('not_allowed'); } + my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname); + my %newrecord = (); + my ($pts,$wgt) = ('',''); foreach (split(/:/,$ENV{'form.partlist'.$newflg})) { if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') { if ($record{'resource.'.$_.'.solved'} ne 'excused') { @@ -1515,11 +1683,11 @@ sub saveHandGrade { } } } else { - my $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? - $ENV{'form.GD_BOX'.$newflg.'_'.$_} : - $ENV{'form.RADVAL'.$newflg.'_'.$_}); + $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? + $ENV{'form.GD_BOX'.$newflg.'_'.$_} : + $ENV{'form.RADVAL'.$newflg.'_'.$_}); return 'no_score' if ($pts eq '' && $ENV{'form.GD_SEL'.$newflg.'_'.$_} eq ''); - my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : + $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_}; my $partial= $pts/$wgt; $newrecord{'resource.'.$_.'.awarded'} = $partial @@ -1542,7 +1710,7 @@ sub saveHandGrade { &Apache::lonnet::cstore(\%newrecord,$symb, $ENV{'request.course.id'},$domain,$stuname); } - return ''; + return '',$pts,$wgt; } #-------------------------------------------------------------------------------------- @@ -1560,8 +1728,8 @@ sub viewgrades_js { var textbox = eval("document.classgrade.TEXTVAL_"+partid); if (point == "textval") { var point = eval("document.classgrade.TEXTVAL_"+partid+".value"); - if (isNaN(point) || point < 0) { - alert("A number equal or greater than 0 is expected. Entered value = "+point); + if (isNaN(point) || parseFloat(point) < 0) { + alert("A number equal or greater than 0 is expected. Entered value = "+parseFloat(point)); var resetbox = false; for (var i=0; i<radioButton.length; i++) { if (radioButton[i].checked) { @@ -1574,8 +1742,8 @@ sub viewgrades_js { } return; } - if (point > weight) { - var resp = confirm("You entered a value ("+point+ + if (parseFloat(point) > parseFloat(weight)) { + var resp = confirm("You entered a value ("+parseFloat(point)+ ") greater than the weight for the part. Accept?"); if (resp == false) { textbox.value = ""; @@ -1584,7 +1752,7 @@ sub viewgrades_js { } for (var i=0; i<radioButton.length; i++) { radioButton[i].checked=false; - if (point == i) { + if (parseFloat(point) == i) { radioButton[i].checked=true; } } @@ -1658,13 +1826,13 @@ sub viewgrades_js { var point = textbox.value; var weight = eval("document.classgrade.weight_"+partid+".value"); - if (isNaN(point) || point < 0) { - alert("A number equal or greater than 0 is expected. Entered value = "+point); + if (isNaN(point) || parseFloat(point) < 0) { + alert("A number equal or greater than 0 is expected. Entered value = "+parseFloat(point)); textbox.value = ""; return; } - if (point > weight) { - var resp = confirm("You entered a value ("+point+ + if (parseFloat(point) > parseFloat(weight)) { + var resp = confirm("You entered a value ("+parseFloat(point)+ ") greater than the weight of the part. Accept?"); if (resp == false) { textbox.value = ""; @@ -1738,10 +1906,7 @@ sub viewgrades { '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="command" value="editgrades" />'."\n". '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'" />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n"; $result.='<h3>Assign Common Grade To '; @@ -1798,9 +1963,9 @@ sub viewgrades { $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n". '<input type="hidden" name="totalparts" value="'.$ctsparts.'" />'; $result.='<input type="button" value="Reset" '. - 'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> '; - $result.='<input type="button" value="Submit Changes" '. - 'onClick="javascript:submit();" TARGET=_self />'."\n"; + 'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self>'; +# $result.=' <input type="button" value="Submit Changes" name="subButton1'. +# 'onClick="javascript:submit();" TARGET=_self />'."\n"; #table listing all the students in a section/class #header of table @@ -1814,10 +1979,11 @@ sub viewgrades { } $result.= '<table border=0><tr><td bgcolor="#777777">'."\n". '<table border=0><tr bgcolor="#deffff">'. - '<td><b>Fullname</b></td><td><b>Username</b></td><td><b>Domain</b></td>'."\n"; + '<td><b>Fullname</b> <font color="#999999">(Username)</font></td>'."\n"; my (@parts) = sort(&getpartlist($url)); foreach my $part (@parts) { my $display=&Apache::lonnet::metadata($url,$part.'.display'); + next if ($display =~ /Number of Attempts/); if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); } if ($display =~ /^Partial Credit Factor/) { my ($partid) = &split_part_type($part); @@ -1835,7 +2001,8 @@ sub viewgrades { my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'1'); my $ctr = 0; foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { - my ($uname,$udom) = split(/:/); + my $uname = $_; + $uname=~s/:/_/; $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$uname.'" />'."\n"; $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'}, $_,$$fullname{$_},\@parts,\%weight); @@ -1845,6 +2012,11 @@ sub viewgrades { $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n"; $result.='<input type="button" value="Submit Changes" '. 'onClick="javascript:submit();" TARGET=_self /></form>'."\n"; + if (scalar(%$fullname) eq 0) { + my $colspan=3+scalar(@parts); + $result='<font color="red">There are no students in section "'.$ENV{'form.section'}. + '" with enrollment status "'.$ENV{'form.Status'}.'" to modify or grade.</font>'; + } $result.=&show_grading_menu_form($symb,$url); return $result; } @@ -1853,42 +2025,43 @@ sub viewgrades { sub viewstudentgrade { my ($url,$symb,$courseid,$student,$fullname,$parts,$weight) = @_; my ($uname,$udom) = split(/:/,$student); + $student=~s/:/_/; my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname); my $result='<tr bgcolor="#ffffdd"><td>'. '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom. - '\')"; TARGET=_self>'.$fullname.'</a>'. - '</td><td>'.$uname.'</td><td align="middle">'.$udom.'</td>'."\n"; + '\')"; TARGET=_self>'.$fullname.'</a> '. + '<font color="#999999">('.$uname.($ENV{'user.domain'} eq $udom ? '' : ':'.$udom).')</font></td>'."\n"; foreach my $apart (@$parts) { my ($part,$type) = &split_part_type($apart); my $score=$record{"resource.$part.$type"}; if ($type eq 'awarded') { my $pts = $score eq '' ? '' : $score*$$weight{$part}; $result.='<input type="hidden" name="'. - 'GD_'.$uname.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n"; + 'GD_'.$student.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n"; $result.='<td align="middle"><input type="text" name="'. - 'GD_'.$uname.'_'.$part.'_awarded" '. - 'onChange="javascript:changeSelect(\''.$part.'\',\''.$uname. + 'GD_'.$student.'_'.$part.'_awarded" '. + 'onChange="javascript:changeSelect(\''.$part.'\',\''.$student. '\')" value="'.$pts.'" size="4" /></td>'."\n"; } elsif ($type eq 'solved') { my ($status,$foo)=split(/_/,$score,2); $status = 'nothing' if ($status eq ''); - $result.='<input type="hidden" name="'.'GD_'.$uname.'_'. + $result.='<input type="hidden" name="'.'GD_'.$student.'_'. $part.'_solved_s" value="'.$status.'" />'."\n"; $result.='<td align="middle"><select name="'. - 'GD_'.$uname.'_'.$part.'_solved" '. - 'onChange="javascript:changeOneScore(\''.$part.'\',\''.$uname.'\')" >'."\n"; + 'GD_'.$student.'_'.$part.'_solved" '. + 'onChange="javascript:changeOneScore(\''.$part.'\',\''.$student.'\')" >'."\n"; my $optsel = '<option selected="on"> </option><option>excused</option>'."\n"; $optsel = '<option> </option><option selected="on">excused</option>'."\n" if ($status eq 'excused'); $result.=$optsel; $result.="</select></td>\n"; - } else { - $result.='<input type="hidden" name="'. - 'GD_'.$uname.'_'.$part.'_'.$type.'_s" value="'.$score.'" />'. - "\n"; - $result.='<td align="middle"><input type="text" name="'. - 'GD_'.$uname.'_'.$part.'_'.$type.'" '. - 'value="'.$score.'" size="4" /></td>'."\n"; +# } else { +# $result.='<input type="hidden" name="'. +# 'GD_'.$student.'_'.$part.'_'.$type.'_s" value="'.$score.'" />'. +# "\n"; +# $result.='<td align="middle"><input type="text" name="'. +# 'GD_'.$student.'_'.$part.'_'.$type.'" '. +# 'value="'.$score.'" size="4" /></td>'."\n"; } } $result.='</tr>'; @@ -1907,7 +2080,7 @@ sub editgrades { $title.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n"; my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n"; $result.= '<table border="0"><tr bgcolor="#deffff">'. - '<td rowspan=2><b>Username</b></td><td rowspan=2><b>Fullname</b></td>'."\n"; + '<td rowspan=2><b>Username</b></td><td rowspan=2><b>Domain</b></td><td rowspan=2><b>Fullname</b></td>'."\n"; my %scoreptr = ( 'correct' =>'correct_by_override', @@ -1955,16 +2128,24 @@ sub editgrades { $result .= '</tr><tr bgcolor="#deffff">'; $result .= $header; $result .= '</tr>'."\n"; - + my $noupdate; for ($i=0; $i<$ENV{'form.total'}; $i++) { + my $line; my $user = $ENV{'form.ctr'.$i}; + my $usercolon = $user; + $usercolon =~s/_/:/; + my ($uname,$udom)=split(/_/,$user); my %newrecord; my $updateflag = 0; - my @userdom = grep /^$user:/,keys %$classlist; - my (undef,$udom) = split(/:/,$userdom[0]); - - $result .= '<tr bgcolor="#ffffde"><td>'.$user.' </td><td>'. - $$fullname{$userdom[0]}.' </td>'; + $line .= '<tr bgcolor="#ffffde"><td>'.$uname.' </td><td>'. + $udom.' </td><td>'. + $$fullname{$usercolon}.' </td>'; + my $usec=$classlist->{"$uname:$udom"}[5]; + if (!&canmodify($usec)) { + my $numcols=scalar(@partid)*(scalar(@parts)-1)*2; + $noupdate.=$line."<td colspan=\"$numcols\"><font color=\"red\">Not allowed to modify student</font></td></tr>"; + next; + } foreach (@partid) { my $old_aw = $ENV{'form.GD_'.$user.'_'.$_.'_awarded_s'}; my $old_part_pcr = $old_aw/($weight{$_} ne '0' ? $weight{$_}:1); @@ -1984,7 +2165,7 @@ sub editgrades { } $score = 'excused' if (($ENV{'form.GD_'.$user.'_'.$_.'_solved'} eq 'excused') && ($score ne 'excused')); - $result .= '<td align="center">'.$old_aw.' </td>'. + $line .= '<td align="center">'.$old_aw.' </td>'. '<td align="center">'.$awarded. ($score eq 'excused' ? $score : '').' </td>'; @@ -2007,17 +2188,24 @@ sub editgrades { $newrecord{'resource.'.$part.'regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}"; $updateflag=1; } - $result .= '<td align="center">'.$old_aw.' </td>'. + $line .= '<td align="center">'.$old_aw.' </td>'. '<td align="center">'.$awarded.' </td>'; } } - $result .= '</tr>'."\n"; + $line.='</tr>'."\n"; if ($updateflag) { $count++; &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'}, - $udom,$user); + $udom,$uname); + $result.=$line; + } else { + $noupdate.=$line; } } + if ($noupdate) { + my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3; + $result .= '<tr bgcolor="#ffffff"><td align="center" colspan="'.$numcols.'">No Changes Occured For the Students Below</td></tr>'.$noupdate; + } $result .= '</table></td></tr></table>'."\n". &show_grading_menu_form ($symb,$url); my $msg = '<b>Number of records updated = '.$rec_update. @@ -2158,10 +2346,7 @@ to this page if the data selected is ins value="$ENV{'form.upfile_associate'}" /> <input type="hidden" name="symb" value="$symb" /> <input type="hidden" name="url" value="$url" /> -<input type="hidden" name="saveCmd" value="$ENV{'form.saveCmd'}" /> -<input type="hidden" name="saveSec" value="$ENV{'form.saveSec'}" /> -<input type="hidden" name="saveSub" value="$ENV{'form.saveSub'}" /> -<input type="hidden" name="saveStatus" value="$ENV{'form.saveStatus'}" /> +<input type="hidden" name="saveState" value="$ENV{'form.saveState'}" /> <input type="hidden" name="probTitle" value="$ENV{'form.probTitle'}" /> <input type="hidden" name="command" value="csvuploadassign" /> <hr /> @@ -2199,6 +2384,48 @@ sub csvuploadmap_footer { ENDPICK } +sub upcsvScores_form { + my ($request) = shift; + my ($symb,$url)=&get_symb_and_url($request); + if (!$symb) {return '';} + my $result =<<CSVFORMJS; +<script type="text/javascript" language="javascript"> + function checkUpload(formname) { + if (formname.upfile.value == "") { + alert("Please use the browse button to select a file from your local directory."); + return false; + } + formname.submit(); + } + </script> +CSVFORMJS + $ENV{'form.probTitle'} = &Apache::lonnet::gettitle($symb); + $result.='<br /><table width=100% border=0><tr><td bgcolor="#777777">'."\n"; + $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n"; + $result.=' <b>Specify a file containing the class scores for problem - '.$ENV{'form.probTitle'}. + '.</b></td></tr>'."\n"; + $result.='<tr bgcolor=#ffffe6><td>'."\n"; + my $upfile_select=&Apache::loncommon::upfile_select_html(); + $result.=<<ENDUPFORM; +<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> +<input type="hidden" name="symb" value="$symb" /> +<input type="hidden" name="url" value="$url" /> +<input type="hidden" name="command" value="csvuploadmap" /> +<input type="hidden" name="probTitle" value="$ENV{'form.probTitle'}" /> +<input type="hidden" name="saveState" value="$ENV{'form.saveState'}" /> +$upfile_select +<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Scores" /> + +</form> +ENDUPFORM + $result.='</td></tr></table>'."\n"; + $result.='</td></tr></table><br /><br />'."\n"; + $result.=&show_grading_menu_form($symb,$url); + + return $result; +} + + sub csvuploadmap { my ($request)= @_; my ($symb,$url)=&get_symb_and_url($request); @@ -2258,7 +2485,8 @@ sub csvuploadassign { } $request->print('<h3>Assigning Grades</h3>'); my $courseid=$ENV{'request.course.id'}; - my ($classlist) = &getclasslist('all','1'); + my ($classlist) = &getclasslist('all',0); + my @notallowed; my @skipped; my $countdone=0; foreach my $grade (@gradedata) { @@ -2269,6 +2497,11 @@ sub csvuploadassign { push(@skipped,"$username:$domain"); next; } + my $usec=$classlist->{"$username:$domain"}[5]; + if (!&canmodify($usec)) { + push(@notallowed,"$username:$domain"); + next; + } my %grades; foreach my $dest (keys(%fields)) { if ($dest eq 'username' || $dest eq 'domain') { next; } @@ -2287,10 +2520,14 @@ sub csvuploadassign { } $request->print("<br />Stored $countdone students\n"); if (@skipped) { - $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />'); - foreach my $student (@skipped) { $request->print("<br />$student"); } + $request->print('<p<font size="+1"><b>Skipped Students</b></font></p>'); + foreach my $student (@skipped) { $request->print("$student<br />\n"); } } - $request->print(&view_edit_entire_class_form($symb,$url)); + if (@notallowed) { + $request->print('<p><font size="+1" color="red"><b>Students Not Allowed to Modify</b></font></p>'); + foreach my $student (@notallowed) { $request->print("$student<br />\n"); } + } + $request->print("<br />\n"); $request->print(&show_grading_menu_form($symb,$url)); return ''; } @@ -2355,7 +2592,7 @@ LISTJAVASCRIPT my $result='<h3><font color="#339933"> '. 'Manual Grading by Page or Sequence</font></h3>'; - $result.='<form action="/adm/grades" method="post" name="displayPage">'."<br>\n"; + $result.='<form action="/adm/grades" method="post" name="displayPage">'."\n"; $result.=' <b>Problems from:</b> <select name="selectpage">'."\n"; my ($titles,$symbx) = &getSymbMap($request); my ($curpage,$type,$mapId) = ($symb =~ /(.*?\.(page|sequence))___(\d+)___/); @@ -2378,7 +2615,7 @@ LISTJAVASCRIPT $result.='<input type="hidden" name="page" />'."\n". '<input type="hidden" name="title" />'."\n"; - $result.=' <b>View Problems: </b><input type="radio" name="vProb" value="no" checked /> no '."\n". + $result.=' <b>View Problems Text: </b><input type="radio" name="vProb" value="no" checked /> no '."\n". '<input type="radio" name="vProb" value="yes" /> yes '."<br>\n"; $result.=' <b>Submission Details: </b>'. @@ -2387,15 +2624,13 @@ LISTJAVASCRIPT '<input type="radio" name="lastSub" value="all" /> all details'."\n"; $result.='<input type="hidden" name="section" value="'.$getsec.'" />'."\n". + '<input type="hidden" name="Status" value="'.$ENV{'form.Status'}.'" />'."\n". '<input type="hidden" name="command" value="displayPage" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". - '<input type="hidden" name="symb" value="'.$symb.'" />'."<br><br>\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n"; + '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."<br />\n"; - $result.='<br /> <input type="button" '. + $result.=' <input type="button" '. 'onClick="javascript:checkPickOne(this.form);"value="Submit" /><br />'."\n"; $request->print($result); @@ -2433,25 +2668,22 @@ LISTJAVASCRIPT sub getSymbMap { my ($request) = @_; - my $navmap = Apache::lonnavmaps::navmap-> new($request, - $ENV{'request.course.fn'}.'.db', + my $navmap = Apache::lonnavmaps::navmap-> new($ENV{'request.course.fn'}.'.db', $ENV{'request.course.fn'}.'_parms.db',1, 1); - - my $res = $navmap->firstResource(); # temp resource to access constants $navmap->init(); # End navmap using boilerplate - my $iterator = $navmap->getIterator(undef, undef, undef, 1); + my $iterator = Apache::lonnavmaps::iterator->new($navmap, undef, undef, undef, undef, 1, undef, 1); my $depth = 1; - $iterator->next(); # ignore first BEGIN_MAP my $curRes = $iterator->next(); my %symbx = (); my @titles = (); my $minder=0; - while ($depth > 0) { - if ($curRes == $iterator->BEGIN_MAP()) {$depth++;} + my $seenBeginMap = 0; + while ($depth > 0 || !$seenBeginMap) { + if ($curRes == $iterator->BEGIN_MAP()) {$depth++; $seenBeginMap = 1; } if ($curRes == $iterator->END_MAP()) { $depth--; } if (ref($curRes) && $curRes->is_map()) { @@ -2465,15 +2697,14 @@ sub getSymbMap { my $countProblems = 0; $mapiterator->next(); # skip the first BEGIN_MAP my $mapcurRes = $mapiterator->next(); # for "current resource" - my $ctr=0; - while ($mapdepth > 0 && $ctr < 100) { + while ($mapdepth > 0) { if($mapcurRes == $mapiterator->BEGIN_MAP) { $mapdepth++; } - if($mapcurRes == $mapiterator->END_MAP) { $mapdepth++; } + if($mapcurRes == $mapiterator->END_MAP) { $mapdepth--; } if (ref($mapcurRes) && $mapcurRes->is_problem() && !$mapcurRes->randomout) { $countProblems++; } - $ctr++; + $mapcurRes = $mapiterator->next(); } if ($countProblems > 0) { my $title = $curRes->compTitle(); @@ -2499,9 +2730,14 @@ sub displayPage { my $cnum = $ENV{"course.$ENV{'request.course.id'}.num"}; my $getsec = $ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'}; my $pageTitle = $ENV{'form.page'}; - my (undef,undef,$fullname) = &getclasslist($getsec,'1'); + my ($classlist,undef,$fullname) = &getclasslist($getsec,'1'); my ($uname,$udom) = split(/:/,$ENV{'form.student'}); - + my $usec=$classlist->{$ENV{'form.student'}}[5]; + if (!&canview($usec)) { + $request->print('<font color="red">Unable to view requested student.('.$ENV{'form.student'}.')</font>'); + $request->print(&show_grading_menu_form($symb,$url)); + return; + } my $result='<h3><font color="#339933"> '.$ENV{'form.title'}.'</font></h3>'; $result.='<h3> Student: '.$$fullname{$ENV{'form.student'}}. '<font color="#999999"> ('.$uname.($udom eq $cdom ? '':':'.$udom).')</font></h3>'."\n"; @@ -2509,8 +2745,7 @@ sub displayPage { &sub_page_js($request); $request->print($result); - my $navmap = Apache::lonnavmaps::navmap-> new($request, - $ENV{'request.course.fn'}.'.db', + my $navmap = Apache::lonnavmaps::navmap-> new($ENV{'request.course.fn'}.'.db', $ENV{'request.course.fn'}.'_parms.db',1, 1); my ($mapUrl, $id, $resUrl) = split(/___/, $ENV{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps @@ -2525,10 +2760,7 @@ sub displayPage { '<input type="hidden" name="title" value="'.$ENV{'form.title'}.'" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n"; + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n"; my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL'). '/check.gif" height="16" border="0" />'; @@ -2540,16 +2772,15 @@ sub displayPage { '<td align="center"><b> No </b></td>'. '<td><b> '.($ENV{'form.vProb'} eq 'no' ? 'Title' : 'Problem View').'/Grade</b></td></tr>'; - my ($depth,$ctr,$question) = (1,0,1); + my ($depth,$question) = (1,1); $iterator->next(); # skip the first BEGIN_MAP my $curRes = $iterator->next(); # for "current resource" - while ($depth > 0 && $ctr < 100) { # ctr, just in case it never gets out of loop + while ($depth > 0) { if($curRes == $iterator->BEGIN_MAP) { $depth++; } - if($curRes == $iterator->END_MAP) { $depth++; } + if($curRes == $iterator->END_MAP) { $depth--; } if (ref($curRes) && $curRes->is_problem() && !$curRes->randomout) { my $parts = $curRes->parts(); - $parts = &temp_parts_fix($parts); # remove line when lonnavmap is fixed my $title = $curRes->compTitle(); my $symbx = $curRes->symb(); $studentTable.='<tr bgcolor="#ffffe6"><td align="center" valign="top" >'.$question. @@ -2558,21 +2789,18 @@ sub displayPage { if ($ENV{'form.vProb'} eq 'yes') { $studentTable.=&show_problem($request,$symbx,$uname,$udom,1); } else { - my $companswer = &Apache::loncommon::get_student_answers( - $symbx,$uname,$udom,$ENV{'request.course.id'}); - $companswer=~s|<form(.*?)>||g; - $companswer=~s|</form>||g; - + my $companswer = &Apache::loncommon::get_student_answers($symbx,$uname,$udom,$ENV{'request.course.id'}); + $companswer =~ s|<form(.*?)>||g; + $companswer =~ s|</form>||g; # while ($companswer =~ /(<a href\=\"javascript:newWindow.*?Script Vars<\/a>)/s) { #<a href="javascript:newWindow</a> -# $request->print('match='.$1.'<br>'); -# $companswer =~ s/$1/ /s; +# $companswer =~ s/$1/ /ms; +# $request->print('match='.$1."<br>\n"); # } -# $companswer =~ s/<table border=\"1\">/<table border=\"0\">/g; +# $companswer =~ s|<table border=\"1\">|<table border=\"0\">|g; $studentTable.=' <b>'.$title.'</b> <br> <b>Correct answer:</b><br>'.$companswer; } my %record = &Apache::lonnet::restore($symbx,$ENV{'request.course.id'},$udom,$uname); - if ($ENV{'form.lastSub'} eq 'datesub') { if ($record{'version'} eq '') { $studentTable.='<br /> <font color="red">No recorded submission for this problem</font><br />'; @@ -2582,6 +2810,10 @@ sub displayPage { '<td><b>Date/Time</b></td>'. '<td><b>Submission</b></td>'. '<td><b>Status </b></td></tr>'; + my %responseType = (); + foreach my $partid (@{$parts}) { + $responseType{$partid} = $curRes->responseType($partid); + } my ($version); for ($version=1;$version<=$record{'version'};$version++) { my $timestamp = scalar(localtime($record{$version.':timestamp'})); @@ -2590,13 +2822,14 @@ sub displayPage { my @displaySub = (); foreach my $partid (@{$parts}) { my @matchKey = grep /^resource\.$partid\..*?\.submission$/,@versionKeys; - next if ($record{"$version:resource.$partid.award"} eq 'APPROX_ANS' && - $record{"$version:resource.$partid.solved"} eq ''); + next if ($record{"$version:resource.$partid.solved"} eq ''); $displaySub[0].=(exists $record{$version.':'.$matchKey[0]}) ? - '<b>Part:</b> '.$partid.' <b>Submission:</b> ' - .$record{$version.':'.$matchKey[0]}.'<br />' : ''; + '<b>Part '.$partid.' '. + ($record{"$version:resource.$partid.tries"} eq '' ? 'Trial not counted' : + 'Trial '.$record{"$version:resource.$partid.tries"}).'</b> '. + &cleanRecord($record{$version.':'.$matchKey[0]},$responseType{$partid}).'<br />' : ''; $displaySub[1].=(exists $record{"$version:resource.$partid.award"}) ? - '<b>Part:</b> '.$partid.' '. + '<b>Part '.$partid.'</b> '. $record{"$version:resource.$partid.award"}.'/'. $record{"$version:resource.$partid.solved"}.'<br />' : ''; $displaySub[2].=(exists $record{"$version:resource.$partid.regrader"}) ? @@ -2616,19 +2849,21 @@ sub displayPage { '','.submission'); } - - foreach my $partid (@{$parts}) { - $studentTable.=&gradeBox($request,$symbx,$uname,$udom,$question,$partid,\%record); - $studentTable.='<input type="hidden" name="q_'.$question.'" value="'.$partid.'" />'."\n"; - $question++; + if (&canmodify($usec)) { + foreach my $partid (@{$parts}) { + $studentTable.=&gradeBox($request,$symbx,$uname,$udom,$question,$partid,\%record); + $studentTable.='<input type="hidden" name="q_'.$question.'" value="'.$partid.'" />'."\n"; + $question++; + } } $studentTable.='</td></tr>'; - } + } $curRes = $iterator->next(); - $ctr++; } + $navmap->untieHashes(); + $studentTable.='</td></tr></table></td></tr></table>'."\n". ' <input type="button" value="Save" '. 'onClick="javascript:checkSubmitPage(this.form,'.$question.');" TARGET=_self />'. @@ -2639,16 +2874,24 @@ sub displayPage { return ''; } -sub temp_parts_fix { #remove sub once lonnavmap is fixed - my $parts = shift; - my %seen = (); - my @correctParts = (); - foreach (@{$parts}) { - next if ($seen{$_} > 0); - $seen{$_}++; - push @correctParts,$_; +sub cleanRecord { + my ($answer,$response) = @_; + if ($response eq 'option') { + my (@IDs,@ans); + foreach (split(/\&/,&Apache::lonnet::unescape($answer))) { + my ($optionID,$ans) = split(/=/); + push @IDs,$optionID.'</font>'; + push @ans,$ans; + } + my $grayFont = '<font color="#999999">'; + return '<table border="1">'. + '<tr valign="top"><td>Answer</td><td>'. + (join '</td><td>',@ans).'</td></tr>'. + '<tr><td>'.$grayFont.'Option ID</font></td><td>'.$grayFont. + (join '</td><td>'.$grayFont,@IDs).'</font></td></tr>'. + '</table>'; } - return \@correctParts; + return $answer; } sub updateGradeByPage { @@ -2658,17 +2901,21 @@ sub updateGradeByPage { my $cnum = $ENV{"course.$ENV{'request.course.id'}.num"}; my $getsec = $ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'}; my $pageTitle = $ENV{'form.page'}; - my (undef,undef,$fullname) = &getclasslist($getsec,'1'); + my ($classlist,undef,$fullname) = &getclasslist($getsec,'1'); my ($uname,$udom) = split(/:/,$ENV{'form.student'}); - + my $usec=$classlist->{$ENV{'form.student'}}[5]; + if (!&canmodify($usec)) { + $request->print('<font color="red">Unable to modify requested student.('.$ENV{'form.student'}.'</font>'); + $request->print(&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'})); + return; + } my $result='<h3><font color="#339933"> '.$ENV{'form.title'}.'</font></h3>'; $result.='<h3> Student: '.$$fullname{$ENV{'form.student'}}. '<font color="#999999"> ('.$uname.($udom eq $cdom ? '':':'.$udom).')</font></h3>'."\n"; $request->print($result); - my $navmap = Apache::lonnavmaps::navmap-> new($request, - $ENV{'request.course.fn'}.'.db', + my $navmap = Apache::lonnavmaps::navmap-> new($ENV{'request.course.fn'}.'.db', $ENV{'request.course.fn'}.'_parms.db',1, 1); my ($mapUrl, $id, $resUrl) = split(/___/, $ENV{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps @@ -2685,14 +2932,13 @@ sub updateGradeByPage { $iterator->next(); # skip the first BEGIN_MAP my $curRes = $iterator->next(); # for "current resource" - my ($depth,$ctr,$question,$changeflag)= (1,0,1,0); - while ($depth > 0 && $ctr < 100) { # ctr, just in case it never gets out of loop + my ($depth,$question,$changeflag)= (1,1,0); + while ($depth > 0) { if($curRes == $iterator->BEGIN_MAP) { $depth++; } - if($curRes == $iterator->END_MAP) { $depth++; } + if($curRes == $iterator->END_MAP) { $depth--; } if (ref($curRes) && $curRes->is_problem() && !$curRes->randomout) { my $parts = $curRes->parts(); - $parts = &temp_parts_fix($parts); # remove line when lonnavmap is fixed my $title = $curRes->compTitle(); my $symbx = $curRes->symb(); $studentTable.='<tr bgcolor="#ffffe6"><td align="center" valign="top" >'.$question. @@ -2749,9 +2995,10 @@ sub updateGradeByPage { } $curRes = $iterator->next(); - $ctr++; } + $navmap->untieHashes(); + $studentTable.='</td></tr></table></td></tr></table>'; $studentTable.=&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'}); my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' : @@ -2770,6 +3017,15 @@ sub updateGradeByPage { # #------ start of section for handling grading by page/sequence --------- +sub defaultFormData { + my ($symb,$url)=@_; + return ' + <input type="hidden" name="symb" value="'.$symb.'" />'."\n". + '<input type="hidden" name="url" value="'.$url.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". + '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n"; +} + sub getSequenceDropDown { my ($request,$symb)=@_; my $result='<select name="selectpage">'."\n"; @@ -2787,17 +3043,47 @@ sub getSequenceDropDown { return $result; } +sub scantron_uploads { + if (!-e $Apache::lonnet::perlvar{'lonScansDir'}) { return ''}; + my $result= '<select name="scantron_selectfile">'; + opendir(DIR,$Apache::lonnet::perlvar{'lonScansDir'}); + my @files=sort(readdir(DIR)); + foreach my $filename (@files) { + if ($filename eq '.' or $filename eq '..') { next; } + $result.="<option>$filename</option>\n"; + } + closedir(DIR); + $result.="</select>"; + return $result; +} + +sub scantron_scantab { + my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); + my $result='<select name="scantron_format">'."\n"; + foreach my $line (<$fh>) { + my ($name,$descrip)=split(/:/,$line); + if ($name =~ /^\#/) { next; } + $result.='<option value="'.$name.'">'.$descrip.'</option>'."\n"; + } + $result.='</select>'."\n"; + + return $result; +} + sub scantron_selectphase { my ($r) = @_; my ($symb,$url)=&get_symb_and_url($r); if (!$symb) {return '';} my $sequence_selector=&getSequenceDropDown($r,$symb); + my $default_form_data=&defaultFormData($symb,$url); + my $grading_menu_button=&show_grading_menu_form($symb,$url); + my $file_selector=&scantron_uploads(); + my $format_selector=&scantron_scantab(); my $result; $result.= <<SCANTRONFORM; -<form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantronupload"> - <input type="hidden" name="symb" value="$symb" /> - <input type="hidden" name="url" value="$url" /> - <input type="hidden" name="command" value="scantron_configphase" /> +<form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantro_process"> + <input type="hidden" name="command" value="scantron_process" /> + $default_form_data <table width="100%" border="0"> <tr> <td bgcolor="#777777"> @@ -2814,12 +3100,12 @@ sub scantron_selectphase { </tr> <tr bgcolor="#ffffe6"> <td> - <!-- FIXME I need to present a list of files from a specfic directory that has been configured, or any existing delay queues --> - Filename of scoring office file: - <select name="selectfile"> - <option value="filname1">filename1</option> - <option value="filname2">filename2</option> - </select> + Filename of scoring office file: $file_selector + </td> + </tr> + <tr bgcolor="#ffffe6"> + <td> + Format of data file: $format_selector </td> </tr> </table> @@ -2828,42 +3114,211 @@ sub scantron_selectphase { </table> <input type="submit" value="Submit" /> </form> +$grading_menu_button SCANTRONFORM return $result; } -sub scantron_configphase { - my ($r) = @_; - my $sequence=$ENV{'form.selectpage'}; - my $result; - $result.="got page $sequence"; - $Apache::lonxml::debug=1; - &Apache::lonhomework::showhash(%ENV); - $Apache::lonxml::debug=0; - #FIXME Needs to present some lines from the file and allow the instructor to specify which columns represent what data, possibly have some nice defaults setup, probably should do a pass through all problems for a student to get an idea of how many questions there are, and homw many lines we'll have, - return $result; +sub get_scantron_config { + my ($which) = @_; + my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); + my %config; + foreach my $line (<$fh>) { + my ($name,$descrip)=split(/:/,$line); + if ($name ne $which ) { next; } + chomp($line); + my @config=split(/:/,$line); + $config{'name'}=$config[0]; + $config{'description'}=$config[1]; + $config{'CODElocation'}=$config[2]; + $config{'CODEstart'}=$config[3]; + $config{'CODElength'}=$config[4]; + $config{'IDstart'}=$config[5]; + $config{'IDlength'}=$config[6]; + $config{'Qstart'}=$config[7]; + $config{'Qlength'}=$config[8]; + $config{'Qoff'}=$config[9]; + $config{'Qon'}=$config[10]; + last; + } + return %config; +} + +sub username_to_idmap { + my ($classlist)= @_; + my %idmap; + foreach my $student (keys(%$classlist)) { + $idmap{$classlist->{$student}->[&Apache::loncoursedata::CL_ID]}= + $student; + } + return %idmap; +} + +sub scantron_parse_scanline { + my ($line,$scantron_config)=@_; + my %record; + my $questions=substr($line,$$scantron_config{'Qstart'}-1); + my $data=substr($line,0,$$scantron_config{'Qstart'}-1); + if ($$scantron_config{'CODElocation'} ne 0) { + if ($$scantron_config{'CODElocation'} < 0) { + $record{'scantron.CODE'}=substr($data,$$scantron_config{'CODEstart'}-1, + $$scantron_config{'CODElength'}); + } else { + #FIXME interpret first N questions + } + } + $record{'scantron.ID'}=substr($data,$$scantron_config{'IDstart'}-1, + $$scantron_config{'IDlength'}); + my @alphabet=('A'..'Z'); + my $questnum=0; + while ($questions) { + $questnum++; + my $currentquest=substr($questions,0,$$scantron_config{'Qlength'}); + substr($questions,0,$$scantron_config{'Qlength'})=''; + if (length($currentquest) < $$scantron_config{'Qlength'}) { next; } + my (@array)=split(/$$scantron_config{'Qon'}/,$currentquest); + if (scalar(@array) gt 2) { + #FIXME do something intelligent with double bubbles + Apache->request->print("<br ><b>Wha!!!</b> <pre>".scalar(@array). + '-'.$currentquest.'-'.$questnum.'</pre><br />'); + } + if (length($array[0]) eq $$scantron_config{'Qlength'}) { + $record{"scantron.$questnum.answer"}=''; + } else { + $record{"scantron.$questnum.answer"}=$alphabet[length($array[0])]; + } + } + $record{'scantron.maxquest'}=$questnum; + return \%record; +} + +sub scantron_add_delay { +} + +sub scantron_find_student { + my ($scantron_record,$idmap)=@_; + my $scanID=$$scantron_record{'scantron.ID'}; + foreach my $id (keys(%$idmap)) { + Apache->request->print('<pre>checking studnet -'.$id.'- againt -'.$scanID.'- </pre>'); + if (lc($id) eq lc($scanID)) { Apache->request->print('success');return $$idmap{$id}; } + } + return undef; +} + +sub scantron_filter { + my ($curres)=@_; + if (ref($curres) && $curres->is_problem() && !$curres->randomout) { + return 1; + } + return 0; } sub scantron_process_students { + my ($r) = @_; + my (undef,undef,$sequence)=split(/___/,$ENV{'form.selectpage'}); + my ($symb,$url)=&get_symb_and_url($r); + if (!$symb) {return '';} + my $default_form_data=&defaultFormData($symb,$url); + + my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'}); + my $scanlines=Apache::File->new($Apache::lonnet::perlvar{'lonScansDir'}."/$ENV{'form.scantron_selectfile'}"); + my @scanlines=<$scanlines>; + my $classlist=&Apache::loncoursedata::get_classlist(); + my %idmap=&username_to_idmap($classlist); + my $navmap=Apache::lonnavmaps::navmap->new($ENV{'request.course.fn'}.'.db',$ENV{'request.course.fn'}.'_parms.db',1, 1); + my $map=$navmap->getResourceByUrl($sequence); + my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); + $r->print("geto ".scalar(@resources)."<br />"); + my $result= <<SCANTRONFORM; +<form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantronupload"> + <input type="hidden" name="command" value="scantron_configphase" /> + $default_form_data +SCANTRONFORM + $r->print($result); + + my @delayqueue; + my $totalcorrect; + my $totalincorrect; + + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r, + 'Scantron Status','Scantron Progress',scalar(@scanlines)); + foreach my $line (@scanlines) { + my $studentcorrect; + my $studentincorrect; + + chomp($line); + my $scan_record=&scantron_parse_scanline($line,\%scantron_config); + my ($uname,$udom); + if ($uname=&scantron_find_student($scan_record,\%idmap)) { + &scantron_add_delay(\@delayqueue,$line, + 'Unable to find a student that matches'); + } + $r->print('<pre>doing studnet'.$uname.'</pre>'); + ($uname,$udom)=split(/:/,$uname); + &Apache::lonnet::delenv('form.counter'); + &Apache::lonnet::appenv(%$scan_record); +# &Apache::lonhomework::showhash(%ENV); + $Apache::lonxml::debug=1; + &Apache::lonxml::debug("line is $line"); + + my $i=0; + foreach my $resource (@resources) { + $i++; + my $result=&Apache::lonnet::ssi($resource->src(), + ('submitted' =>'scantron', + 'grade_target' =>'grade', + 'grade_username'=>$uname, + 'grade_domain' =>$udom, + 'grade_courseid'=>$ENV{'request.course.id'}, + 'grade_symb' =>$resource->symb())); + my %score=&Apache::lonnet::restore($resource->symb(), + $ENV{'request.course.id'}, + $udom,$uname); + foreach my $part ($resource->{PARTS}) { + if ($score{'resource.'.$part.'.solved'} =~ /^correct/) { + $studentcorrect++; + $totalcorrect++; + } else { + $studentincorrect++; + $totalincorrect++; + } + } + $r->print('<pre>'. + $resource->symb().'-'. + $resource->src().'-'.'</pre>result is'.$result); + &Apache::lonhomework::showhash(%score); + # if ($i eq 3) {last;} + } + &Apache::lonnet::delenv('form.counter'); + &Apache::lonnet::delenv('scantron\.'); + &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state, + 'last student Who got a '.$studentcorrect.' correct and '. + $studentincorrect.' incorrect. The class has gotten '. + $totalcorrect.' correct and '.$totalincorrect.' incorrect'); + last; + #FIXME + #get iterator for $sequence + #foreach question 'submit' the students answer to the server + # through grade target { + # generate data to pass back that includes grade recevied + #} + } + $Apache::lonxml::debug=0; + foreach my $delay (@delayqueue) { + #FIXME + #print out each delayed student with interface to select how + # to repair student provided info + #Expected errors include + # 1 bad/no stuid/username + # 2 invalid bubblings + + } #FIXME - # loop through students, { - # Check if studnet info valid, if not add line to delay queue - # foreach question 'submit' the students answer to the server - # through grade target { - # generate data to pass back that includes grade recevied - # } - # } - # loop through delay queue { - # print out each delayed student with interface to select how - # to repair student provided info - # Expected errors include - # 1 bad/no stuid/username - # 2 invalid bubblings - # } # if delay queue exists 2 submits one to process delayed students one # to ignore delayed students, possibly saving the delay queue for later - + + $navmap->untieHashes(); } #-------- end of section for handling grading scantron forms ------- # @@ -2878,16 +3333,24 @@ sub show_grading_menu_form { my $result.='<form action="/adm/grades" method="post">'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". - '<input type="hidden" name="saveCmd" value="'.$ENV{'form.saveCmd'}.'" />'."\n". - '<input type="hidden" name="saveSec" value="'.$ENV{'form.saveSec'}.'" />'."\n". - '<input type="hidden" name="saveSub" value="'.$ENV{'form.saveSub'}.'" />'."\n". - '<input type="hidden" name="saveStatus" value="'.$ENV{'form.saveStatus'}.'" />'."\n". + '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n". '<input type="hidden" name="command" value="gradingmenu" />'."\n". '<input type="submit" name="submit" value="Grading Menu" />'."\n". '</form>'."\n"; return $result; } +# -- Retrieve choices for grading form +sub savedState { + my %savedState = (); + if ($ENV{'form.saveState'}) { + foreach (split(/:/,$ENV{'form.saveState'})) { + my ($key,$value) = split(/=/,$_,2); + $savedState{$key} = $value; + } + } + return \%savedState; +} #--- Displays the main menu page ------- sub gradingmenu { @@ -2895,24 +3358,20 @@ sub gradingmenu { my ($symb,$url)=&get_symb_and_url($request); if (!$symb) {return '';} my $probTitle = &Apache::lonnet::gettitle($symb); - my $saveCmd = ($ENV{'form.saveCmd'} eq '' ? 'pickStudentPage' : $ENV{'form.saveCmd'}); - my $saveSec = ($ENV{'form.saveSec'} eq '' ? 'all' : $ENV{'form.saveSec'}); - my $saveSub = ($ENV{'form.saveSub'} eq '' ? 'yes' : $ENV{'form.saveSub'}); - my $saveStatus = ($ENV{'form.saveStatus'} eq '' ? 'Active' : $ENV{'form.saveStatus'}); $request->print(<<GRADINGMENUJS); <script type="text/javascript" language="javascript"> - function checkChoice(formname) { - var cmd = formname.command; - formname.saveCmd.value = radioSelection(cmd); - formname.saveSec.value = pullDownSelection(formname.section); - formname.saveSub.value = radioSelection(formname.submitonly); - formname.saveStatus.value = pullDownSelection(formname.status); - if (cmd[0].checked || cmd[1].checked || cmd[2].checked || cmd[4].checked) formname.submit(); - - if (cmd[3].checked) browseAndUpload(); - - if (cmd[5].checked) { + function checkChoice(formname,val,cmdx) { + if (val <= 2) { + var cmd = radioSelection(formname.radioChoice); + } else { + cmd = cmdx; + } + formname.command.value = cmd; + formname.saveState.value = "saveCmd="+cmd+":saveSec="+pullDownSelection(formname.section)+ + ":saveSub="+radioSelection(formname.submitonly)+":saveStatus="+pullDownSelection(formname.Status); + if (val < 5) formname.submit(); + if (val == 5) { if (!checkReceiptNo(formname,'notOK')) { return false;} formname.submit(); } @@ -2929,7 +3388,6 @@ sub gradingmenu { formname.receipt.focus(); return false; } - formname.command[5].checked = true; return true; } @@ -2960,57 +3418,6 @@ sub gradingmenu { } } - function browseAndUpload() { - bNLoad = window.open('', 'BrowseAndUpload', 'toolbar=no,location=no,scrollbars=no,width=550,height=200,screenx=100,screeny=75'); - bNLoad.focus(); - var lDoc = bNLoad.document; - lDoc.write("<html><head>"); - lDoc.write("<title>Browse And Upload</title>"); - - lDoc.write("<script language=javascript>"); - lDoc.write("function checkUpload(formname) {"); - - lDoc.write(" if (formname.upfile.value == \\"\\") {"); - lDoc.write(" alert(\\"Please use the browse button to select a file from your local directory.\\");"); - lDoc.write(" return false;"); - lDoc.write(" }"); - lDoc.write(" document.gradesupload.submit();"); - lDoc.write(" setTimeout('self.close()',750)"); - lDoc.write("}"); - - lDoc.write("<"); - lDoc.write("/script>"); - - lDoc.write("</head><body bgcolor=white>"); - lDoc.write("<form method=\\"post\\" enctype=\\"multipart/form-data\\" action=\\"/adm/grades\\" name=\\"gradesupload\\" target=\\"LONcatInfo\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"symb\\" value=\\"$symb\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"url\\" value=\\"$url\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"probTitle\\" value=\\"$probTitle\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"saveCmd\\" value=\\"csvupload\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"saveSec\\" value=\\"$saveSec\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"saveSub\\" value=\\"$saveSub\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"saveStatus\\" value=\\"$saveStatus\\">"); - lDoc.write("<input type=\\"hidden\\" name=\\"command\\" value=\\"csvuploadmap\\">"); - - lDoc.write("<font color=\\"green\\" size=+1><b>Specify a file containing the class scores for problem - $probTitle</b></font><br><br>"); - - lDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">"); - lDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">"); - lDoc.write("<td>"); - lDoc.write("<input type=\\"file\\" name=\\"upfile\\" size=\\"50\\" />"); - lDoc.write("<br />Type: <select name=\\"upfiletype\\">"); - lDoc.write("<option value=\\"csv\\">CSV (comma separated values, spreadsheet)</option>"); - lDoc.write("<option value=\\"space\\">Space separated</option>"); - lDoc.write("<option value=\\"tab\\">Tabulator separated</option>"); - lDoc.write("<option value=\\"xml\\">HTML/XML</option>"); - lDoc.write("</select>"); - lDoc.write("</td></tr></table>"); - lDoc.write("</td></tr></table> "); - lDoc.write("<input type=\\"button\\" value=\\"Upload Scores\\" onClick=\\"javascript:checkUpload(this.form)\\"> "); - lDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>"); - lDoc.write("</form>"); - lDoc.write("</body></html>"); - } </script> GRADINGMENUJS @@ -3024,12 +3431,17 @@ GRADINGMENUJS $resptype = $responsetype; $hdgrade = $handgrade if ($handgrade eq 'yes'); $result.='<tr><td><b>Part </b>'.(split(/_/))[0].'</td>'. - '<td><b>Type: </b>'.$responsetype.'</td>'. - '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>'; + '<td><b>Type: </b>'.$responsetype.'</td></tr>'; +# '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>'; } $result.='</table>'."\n"; my (undef,$sections) = &getclasslist('all','0'); + my $savedState = &savedState(); + my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'pickStudentPage' : $$savedState{'saveCmd'}); + my $saveSec = ($$savedState{'saveSec'} eq '' ? 'all' : $$savedState{'saveSec'}); + my $saveSub = ($$savedState{'saveSub'} eq '' ? 'yes' : $$savedState{'saveSub'}); + my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'}); $result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". @@ -3037,82 +3449,75 @@ GRADINGMENUJS '<input type="hidden" name="response" value="'.$resptype.'" />'."\n". '<input type="hidden" name="handgrade" value="'.$hdgrade.'" />'."\n". '<input type="hidden" name="probTitle" value="'.$probTitle.'" />'."\n". - '<input type="hidden" name="saveCmd" value="" />'."\n". - '<input type="hidden" name="saveSec" value="" />'."\n". - '<input type="hidden" name="saveSub" value="" />'."\n". - '<input type="hidden" name="saveStatus" value="" />'."\n". + '<input type="hidden" name="command" value="" />'."\n". + '<input type="hidden" name="saveState" value="" />'."\n". '<input type="hidden" name="showgrading" value="yes" />'."\n"; - $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n". - '<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n". + $result.='<table width="100%" border=0><tr><td bgcolor=#777777>'."\n". + '<table width=100% border=0><tr bgcolor="#e6ffff"><td colspan="2">'."\n". ' <b>Select a Grading/Viewing Option</b></td></tr>'."\n". - '<tr bgcolor=#ffffe6><td>'."\n"; + '<tr bgcolor="#ffffe6" valign="top"><td>'."\n"; + + $result.='<table width="100%" border=0>'; + $result.='<tr bgcolor="#ffffe6" valign="top"><td>'."\n". + ' Section: <select name="section">'."\n"; + if (ref($sections)) { + foreach (sort (@$sections)) {$result.='<option value="'.$_.'" '. + ($saveSec eq $_ ? 'selected="on"' : '').'>'.$_.'</option>'."\n";} + } + $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</select> '; - $result.='<table width=100% border=0>'. - '<tr bgcolor="#ffffe6" valign="top"><td colspan="2">'. - '<input type="radio" name="command" value="pickStudentPage" '. + $result.='Student Status:</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef); + + if (ref($sections)) { + $result.=' (Section "no" implies the students were not assigned a section.)<br />' + if (grep /no/,@$sections); + } + $result.='</td></tr>'; + + $result.='<tr bgcolor="#ffffe6" valign="top"><td>'. + '<input type="radio" name="radioChoice" value="pickStudentPage" '. ($saveCmd eq 'pickStudentPage' ? 'checked' : '').'> '. - 'Handgrade/View Submission for a student by page/sequence</td></tr>'."\n". + 'One student for whole page/sequence/folder</td></tr>'."\n"; - '<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'. - '<input type="radio" name="command" value="viewgrades" '. + $result.='<tr bgcolor="#ffffe6"valign="top"><td>'. + '<input type="radio" name="radioChoice" value="viewgrades" '. ($saveCmd eq 'viewgrades' ? 'checked' : '').'> '. - 'Grade by section or class</td></tr>'."\n". + 'All students in section/course for current resource</td></tr>'."\n"; - '<tr bgcolor="#ffffe6"valign="top"><td><input type="radio" name="command" value="submission" '. - ($saveCmd eq 'submission' ? 'checked' : '').'> '. - ($hdgrade eq 'yes' ? 'View/Grade essay response of' : 'View'). - ' an individual student </td>'."\n". - '<td>--> For students who has: '. + $result.='<tr bgcolor="#ffffe6"valign="top"><td>'. + '<input type="radio" name="radioChoice" value="submission" '. + ($saveCmd eq 'submission' ? 'checked' : '').'> '.'One or more students for current resource'. + '<br /> -->For students who has: '. '<input type="radio" name="submitonly" value="yes" '. ($saveSub eq 'yes' ? 'checked' : '').' /> submitted'. '<input type="radio" name="submitonly" value="all" '. - ($saveSub eq 'all' ? 'checked' : '').' /> everybody</td></tr>'."\n". + ($saveSub eq 'all' ? 'checked' : '').' /> everybody</td></tr>'."\n"; + + $result.='<tr bgcolor="#ffffe6"><td><br />'. + '<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="View/Grade/Regrade" />'. + '</td></tr></table>'."\n"; - '<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'. - '<input type="radio" name="command" value="csvupload" '. - ($saveCmd eq 'csvupload' ? 'checked' : '').'> '. - 'Upload scores from file</td></tr>'."\n"; + $result.='</td><td valign="top">'; + + $result.='<table width="100%" border=0>'; + $result.='<tr bgcolor="#ffffe6"><td>'. + '<input type="button" onClick="javascript:checkChoice(this.form,\'3\',\'csvform\');" value="Upload" />'. + ' scores from file </td></tr>'."\n"; $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'. - '<input type="radio" name="command" value="scantron_selectphase" /> '. - 'Grade scantron forms</td></tr>'."\n"; + '<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'. + '" value="Grade" /> scantron forms</td></tr>'."\n"; if ((&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) && ($symb)) { $result.='<tr bgcolor="#ffffe6"valign="top"><td>'. - '<input type="radio" name="command" value="verify" onChecked="javascript:this.form.receipt.focus()" '. - ($saveCmd eq 'verify' ? 'checked' : '').'> '. - 'Verify a submission receipt issued by this server</td>'. - '<td>--> Receipt no: '.unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}). + '<input type="button" onClick="javascript:checkChoice(this.form,\'5\',\'verify\');" value="Verify" />'. + ' submission Receipt no: '.unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}). '-<input type="text" name="receipt" size="4" onChange="javascript:checkReceiptNo(this.form,\'OK\')">'. '</td></tr>'."\n"; } - $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2"><br />'."\n". - ' Select section: <select name="section">'."\n"; - if (ref($sections)) { - foreach (sort (@$sections)) {$result.='<option value="'.$_.'" '. - ($saveSec eq $_ ? 'selected="on"' : '').'>'.$_.'</option>'."\n";} - } - $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</select> '; - - $result.='Student Status:</b><select name="status">'. - '<option value="Active" '.($saveStatus eq 'Active' ? 'selected' : '').'>Active</option>'. - '<option value="Expired" '.($saveStatus eq 'Expired' ? 'selected' : '').'>Expired</option>'. - '<option value="Any" '.($saveStatus eq 'Any' ? 'selected' : '').'>Any</option>'. - '</select>'; - - $result.=' <font color="red">(Applies to the first three options only.)</font>'."\n"; - - if (ref($sections)) { - $result.=' (Section "no" implies the students were not assigned a section.)<br />' - if (grep /no/,@$sections); - } - $result.='</td></tr>'; - - $result.='<tr bgcolor="#ffffe6"><td colspan="2"><br />'. - '<input type="button" onClick="javascript:checkChoice(this.form);" value="View/Grade" />'."\n". - '</form></td></tr></table>'."\n". + $result.='</form></td></tr></table>'."\n". '</td></tr></table>'."\n". '</td></tr></table>'."\n"; return $result; @@ -3120,7 +3525,8 @@ GRADINGMENUJS sub handler { my $request=$_[0]; - + + undef(%perm); if ($ENV{'browser.mathml'}) { $request->content_type('text/xml'); } else { @@ -3149,15 +3555,14 @@ sub handler { if ($tsymb) { my ($map,$id,$url)=split(/\_\_\_/,$tsymb); if (&Apache::lonnet::allowed('mgr',$tcrsid)) { - $request->print( - &Apache::lonnet::ssi('/res/'.$url, - ('grade_username' => $tuname, - 'grade_domain' => $tudom, - 'grade_courseid' => $tcrsid, - 'grade_symb' => $tsymb))); + $request->print(&Apache::lonnet::ssi_body('/res/'.$url, + ('grade_username' => $tuname, + 'grade_domain' => $tudom, + 'grade_courseid' => $tcrsid, + 'grade_symb' => $tsymb))); } else { $request->print('<h3>Not authorized: '.$token.'</h3>'); - } + } } else { $request->print('<h3>Not a valid DocID: '.$token.'</h3>'); } @@ -3166,36 +3571,48 @@ sub handler { } } } else { - $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}); - if ($command eq 'submission') { + 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'}); + } + } + + if ($command eq 'submission' && $perm{'vgr'}) { ($ENV{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0)); - } elsif ($command eq 'pickStudentPage') { + } elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) { &pickStudentPage($request); - } elsif ($command eq 'displayPage') { + } elsif ($command eq 'displayPage' && $perm{'vgr'}) { &displayPage($request); - } elsif ($command eq 'gradeByPage') { + } elsif ($command eq 'gradeByPage' && $perm{'mgr'}) { &updateGradeByPage($request); - } elsif ($command eq 'processGroup') { + } elsif ($command eq 'processGroup' && $perm{'vgr'}) { &processGroup($request); - } elsif ($command eq 'gradingmenu') { + } elsif ($command eq 'gradingmenu' && $perm{'vgr'}) { $request->print(&gradingmenu($request)); - } elsif ($command eq 'viewgrades') { + } elsif ($command eq 'viewgrades' && $perm{'vgr'}) { $request->print(&viewgrades($request)); - } elsif ($command eq 'handgrade') { + } elsif ($command eq 'handgrade' && $perm{'mgr'}) { $request->print(&processHandGrade($request)); - } elsif ($command eq 'editgrades') { + } elsif ($command eq 'editgrades' && $perm{'mgr'}) { $request->print(&editgrades($request)); - } elsif ($command eq 'verify') { + } elsif ($command eq 'verify' && $perm{'vgr'}) { $request->print(&verifyreceipt($request)); - } elsif ($command eq 'csvform') { + } elsif ($command eq 'csvform' && $perm{'mgr'}) { $request->print(&upcsvScores_form($request)); - } elsif ($command eq 'csvupload') { + } elsif ($command eq 'csvupload' && $perm{'mgr'}) { $request->print(&csvupload($request)); - } elsif ($command eq 'viewclasslist') { - $request->print(&viewclasslist($request)); - } elsif ($command eq 'csvuploadmap') { + } elsif ($command eq 'csvuploadmap' && $perm{'mgr'} ) { $request->print(&csvuploadmap($request)); - } elsif ($command eq 'csvuploadassign') { + } elsif ($command eq 'csvuploadassign' && $perm{'mgr'}) { if ($ENV{'form.associate'} ne 'Reverse Association') { $request->print(&csvuploadassign($request)); } else { @@ -3206,12 +3623,12 @@ sub handler { } $request->print(&csvuploadmap($request)); } - } elsif ($command eq 'scantron_selectphase') { + } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) { $request->print(&scantron_selectphase($request)); - } elsif ($command eq 'scantron_configphase') { - $request->print(&scantron_configphase($request)); - } else { - $request->print("Unknown action: $command:"); + } elsif ($command eq 'scantron_process' && $perm{'mgr'}) { + $request->print(&scantron_process_students($request)); + } elsif ($command) { + $request->print("Access Denied"); } } &send_footer($request);