--- loncom/homework/grades.pm 2002/10/16 19:13:57 1.55 +++ loncom/homework/grades.pm 2002/11/27 16:39:37 1.62 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.55 2002/10/16 19:13:57 matthew Exp $ +# $Id: grades.pm,v 1.62 2002/11/27 16:39:37 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -111,62 +111,32 @@ sub response_type { #--- section, ids and fullnames for each user. sub getclasslist { my ($getsec,$hideexpired) = @_; - my $now = time; - my %classlist=&Apache::lonnet::dump('classlist', - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - my ($tmp) = keys(%classlist); + my $classlist=&Apache::loncoursedata::get_classlist(); # Bail out if we were unable to get the classlist - return if ($tmp =~ /^(con_lost|error|no_such_host)/i); - - # codes to check for fields in the classlist - # should contain end:start:id:section:fullname - for (keys %classlist) { - my (@fields) = split(/:/,$classlist{$_}); - %classlist = &reformat_classlist(\%classlist) if (scalar(@fields) <= 2); - last; - } - - my (@holdsec,@sections,%allids,%stusec,%fullname); - foreach (keys(%classlist)) { - my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_}); + return if (! defined($classlist)); + # + my %sections; + my %fullnames; + foreach (keys(%$classlist)) { + # the following undefs are for 'domain', and 'username' respectively. + my (undef,undef,$end,$start,$id,$section,$fullname,$status)= + @{$classlist->{$_}}; # still a student? - if (($hideexpired) && ($end) && ($end < $now)) { - next; - } + if (($hideexpired) && ($status ne 'Active')) { + delete ($classlist->{$_}); + next; + } $section = ($section ne '' ? $section : 'no'); - push @holdsec,$section; if ($getsec eq 'all' || $getsec eq $section) { - push (@{ $classlist{$getsec} }, $_); - $allids{$_} =$id; - $stusec{$_} =$section; - $fullname{$_}=$fullname; - } + $sections{$section}++; + $fullnames{$_}=$fullname; + } else { + delete($classlist->{$_}); + } } my %seen = (); - foreach my $item (@holdsec) { - push (@sections, $item) unless $seen{$item}++; - } - return (\%classlist,\@sections,\%allids,\%stusec,\%fullname); -} - -# add id, section and fullname to the classlist.db -# done to maintain backward compatibility with older versions -sub reformat_classlist { - my ($classlist) = shift; - foreach (sort keys(%$classlist)) { - my ($unam,$udom) = split(/:/); - my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'}); - my $fullname = &get_fullname ($unam,$udom); - my %userid = &Apache::lonnet::idrget($udom,($unam)); - $$classlist{$_} = $$classlist{$_}.':'.$userid{$unam}.':'.$section.':'.$fullname; - } - my $putresult = &Apache::lonnet::put - ('classlist',\%$classlist, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - - return %$classlist; + my @sections = sort(keys(%sections)); + return ($classlist,\@sections,\%fullnames); } #find user domain @@ -267,8 +237,8 @@ sub verifyreceipt { '<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br><br>'."\n"; my ($string,$contents,$matches) = ('','',0); - my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0'); - + my (undef,undef,$fullname) = &getclasslist('all','0'); + foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom)=split(/\:/); if ($receipt eq @@ -369,8 +339,9 @@ 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" checked> no '."\n". - '<input type="radio" name="vProb" value="yes"> yes <br />'."\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". + '<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"; @@ -381,7 +352,7 @@ LISTJAVASCRIPT '<input type="hidden" name="section" value="'.$getsec.'" />'."\n". '<input type="hidden" name="submitonly" value="'.$submitonly.'" />'."\n". '<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="handgrade": #falue="'.$ENV{'form.handgrade'}.'" /><br />'."\n". '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" /><br />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". @@ -393,7 +364,7 @@ LISTJAVASCRIPT 'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n". 'value="'.$viewgrade.'" />'."\n"; - my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0'); + my (undef,undef,$fullname) = &getclasslist($getsec,'0'); $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'. '<table border="0"><tr bgcolor="#e6ffff">'. @@ -701,21 +672,21 @@ sub sub_page_js { pWin.document.write("<tr bgcolor=\\"#ffffdd\\">"); pWin.document.write("<td>Subject</td>"); pWin.document.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"></td>"); - pWin.document.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+" \\"size=\\"60\\" maxlength=\\"80\\"></td></tr>"); + pWin.document.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+"\\"size=\\"60\\" maxlength=\\"80\\"></td></tr>"); } function displaySavedMsg(ctr,msg,shwsel) { pWin.document.write("<tr bgcolor=\\"#ffffdd\\">"); pWin.document.write("<td align=\\"center\\">"+ctr+"</td>"); pWin.document.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"></td>"); - pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>"); + pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+"\\" size=\\"60\\" maxlength=\\"80\\"></td></tr>"); } function newMsg(newmsg,shwsel) { pWin.document.write("<tr bgcolor=\\"#ffffdd\\">"); pWin.document.write("<td align=\\"center\\">New</td>"); pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>"); - pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>"); + pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+"\\" size=\\"60\\" maxlength=\\"80\\"></td></tr>"); } function msgTail() { @@ -825,6 +796,32 @@ SUBJAVASCRIPT } +sub show_problem { + my ($request,$symb,$uname,$udom,$removeform) = @_; + my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom, + $ENV{'request.course.id'}); + if ($removeform) { + $rendered=~s|<form(.*?)>||g; + $rendered=~s|</form>||g; + $rendered=~s|name="submit"|name="would_have_been_submit"|g; + } + my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom, + $ENV{'request.course.id'}); + if ($removeform) { + $companswer=~s|<form(.*?)>||g; + $companswer=~s|</form>||g; + $rendered=~s|name="submit"|name="would_have_been_submit"|g; + } + my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">'; + $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">'; + $result.='<b> View of the problem - '.$ENV{'form.fullname'}. + '</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />'; + $result.='<b>Correct answer:</b><br />'.$companswer; + $result.='</td></tr></table>'; + $result.='</td></tr></table><br />'; + $request->print($result); +} + # --------------------------- show submissions of a student, option to grade sub submission { my ($request,$counter,$total) = @_; @@ -839,8 +836,7 @@ sub submission { 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 ''; } my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : ''); - $ENV{'form.vProb'} = $ENV{'form.vProb'} ne '' ? $ENV{'form.vProb'} : 'yes'; - my ($classlist,$seclist,$ids,$stusec,$fullname); +# $ENV{'form.vProb'} = $ENV{'form.vProb'} ne '' ? $ENV{'form.vProb'} : 'yes'; # header info if ($counter == 0) { @@ -851,18 +847,7 @@ sub submission { # option to display problem, only once else it cause problems # with the form later since the problem has a form. if ($ENV{'form.vProb'} eq 'yes') { - my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom, - $ENV{'request.course.id'}); - my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom, - $ENV{'request.course.id'}); - my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">'; - $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">'; - $result.='<b> View of the problem - '.$ENV{'form.fullname'}. - '</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />'; - $result.='<b>Correct answer:</b><br />'.$companswer; - $result.='</td></tr></table>'; - $result.='</td></tr></table><br />'; - $request->print($result); + &show_problem($request,$symb,$uname,$udom,0); } # kwclr is the only variable that is guaranteed to be non blank @@ -925,6 +910,11 @@ KEYWORDS } } + if ($ENV{'form.vProb'} eq 'all') { + $request->print('<br /><br /><br />'); + &show_problem($request,$symb,$uname,$udom,1); + } + my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname); my ($partlist,$handgrade) = &response_type($url); @@ -941,49 +931,61 @@ KEYWORDS # If this is handgraded, then check for collaborators my @col_fullnames; + my ($classlist,$fullname); if ($ENV{'form.handgrade'} eq 'yes') { my @col_list; - ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0'); + ($classlist,undef,$fullname) = &getclasslist('all','0'); for (keys (%$handgrade)) { my $ncol = &Apache::lonnet::EXT('resource.'.$_. - '.maxcollaborators',$symb,$udom,$uname); - if ($ncol > 0) { - s/\_/\./g; - if ($record{'resource.'.$_.'.collaborators'} ne '') { - my (@collaborators) = split(/,?\s+/, - $record{'resource.'.$_.'.collaborators'}); - my (@badcollaborators); - if (scalar(@collaborators) != 0) { - $result.='<b>Collaborators: </b>'; - foreach my $collaborator (@collaborators) { - $collaborator = $collaborator =~ /\@|:/ ? - (split(/@|:/,$collaborator))[0] : $collaborator; - next if ($collaborator eq $uname); - if (!grep /^$collaborator:/i,keys %$classlist) { - push @badcollaborators,$collaborator; - next; - } - push @col_list, $collaborator; - my ($lastname,$givenn) = split(/,/,$$fullname{$collaborator.':'.$udom}); - push @col_fullnames, $givenn.' '.$lastname; - $result.=$$fullname{$collaborator.':'.$udom}.' '; - } - $result.='<br />'."\n"; - $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'. - 'This student has submitted '. - (scalar (@badcollaborators) > 1 ? '' : 'an'). - ' invalid collaborator'.(scalar (@badcollaborators) > 1 ? 's. ' : '. '). - (join ', ',@badcollaborators).'</td></tr></table>' - if (scalar(@badcollaborators) > 0); - - $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'. - 'This student has submitted too many collaborators. Maximum is '. - $ncol.'.</td></tr></table>' if (scalar(@collaborators) > $ncol); - $result.='<input type="hidden" name="collaborator'.$counter. - '" value="'.(join ':',@col_list).'" />'."\n"; - } - } - } + '.maxcollaborators', + $symb,$udom,$uname); + 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) { + $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{$_}.' '; + } + } + $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 sumbitted too many '. + 'collaborators. Maximum is '.$ncol; + $result .= '</td></tr></table>'; + } + $result.='<input type="hidden" name="collaborator'.$counter. + '" value="'.(join ':',@col_list).'" />'."\n"; + } } } $request->print($result."\n"); @@ -1107,9 +1109,15 @@ KEYWORDS 'onChange="javascript:clearRadBox(this.form.RADVAL'.$counter.'_'.$partid. ',this.form.GD_BOX'.$counter.'_'.$partid. ',this.form.GD_SEL'.$counter.'_'.$partid. - ',this.form.stores'.$counter.'_'.$partid.')" />'."\n". - '<option selected="on"> </option>'. - '<option>excused</option></select>'."  \n"; + ',this.form.stores'.$counter.'_'.$partid.')" >'."\n"; + if ($record{'resource.'.$partid.'.solved'} eq 'excused') { + $result.='<option> </option>'. + '<option selected="on">excused</option></select>'; + } else { + $result.='<option selected="on"> </option>'. + '<option>excused</option></select>'; + } + $result.="  \n"; $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="0" />'; $result.='</td></tr></table>'."\n"; $request->print($result); @@ -1165,9 +1173,9 @@ sub get_last_submission { for ($version=1;$version<=$returnhash{'version'};$version++) { foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) { $lasthash{$_}=$returnhash{$version.':'.$_}; - if ($returnhash{$version.':'.$_} =~ /(SUBMITTED|DRAFT)$/) { +# if ($returnhash{$version.':'.$_} =~ /(SUBMITTED|DRAFT)$/) { $timestamp = scalar(localtime($returnhash{$version.':timestamp'})); - } +# } } } foreach ((keys %lasthash)) { @@ -1191,8 +1199,13 @@ sub keywords_highlight { (my $styleoff = $styleon) =~ s/\</\<\//; my @keylist = split(/[,\s+]/,$ENV{'form.keywords'}); foreach (@keylist) { - $string =~ s/\b$_(\b|\.)/\<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff\<\/font\>/gi; + $string =~ s/\b\Q$_\E(\b|\.)/\<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff\<\/font\>/gi; } + # This is not really the right place to do this, but I cannot find a + # better one at this time. So here we go - the m in the s:::mg causes + # ^ to match the beginning of a new line. So we replace(???) the beginning + # of the line with <br /> to make things formatted a little better. + $string =~ s:^:<br />:mg; return $string; } @@ -1213,7 +1226,7 @@ sub processHandGrade { my $includemsg = $ENV{'form.includemsg'.$ctr}; my ($subject,$message,$msgstatus) = ('','',''); - if ($includemsg =~ /savemsg|new$ctr/) { + if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/); my (@msgnum) = split(/,/,$includemsg); foreach (@msgnum) { @@ -1301,7 +1314,7 @@ sub processHandGrade { $laststu = $firststu if ($ctr > $ngrade); } - my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0'); + 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) { @@ -1363,8 +1376,12 @@ sub saveHandGrade { my %newrecord; foreach (split(/:/,$ENV{'form.partlist'.$newflg})) { if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') { - $newrecord{'resource.'.$_.'.solved'} = 'excused' - if ($record{'resource.'.$_.'.solved'} ne 'excused'); + if ($record{'resource.'.$_.'.solved'} ne 'excused') { + $newrecord{'resource.'.$_.'.solved'} = 'excused'; + if (exists($record{'resource.'.$_.'.awarded'})) { + $newrecord{'resource.'.$_.'.awarded'} = ''; + } + } } else { my $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? $ENV{'form.GD_BOX'.$newflg.'_'.$_} : @@ -1640,7 +1657,7 @@ sub viewgrades { $weight{$partid}.' (problem weight)</td>'."\n"; $result.= '</td><td><select name="SELVAL_'.$partid.'"'. 'onChange="javascript:writeRadText(\''.$partid.'\','. - $weight{$partid}.')" /> '. + $weight{$partid}.')"> '. '<option selected="on"> </option>'. '<option>excused</option></select></td></tr>'."\n"; $ctsparts++; @@ -1682,7 +1699,7 @@ sub viewgrades { #get info for each student #list all the students - with points and grade status - my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0'); + my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'0'); my $ctr = 0; foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom) = split(/:/); @@ -1767,7 +1784,7 @@ sub editgrades { 'ungraded' =>'ungraded_attempted', 'nothing' => '', ); - my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0'); + my ($classlist,undef,$fullname) = &getclasslist($ENV{'form.section'},'0'); my (@partid); my %weight = (); @@ -2185,7 +2202,7 @@ sub gradingmenu { #--- Menu for grading a section or the whole class --- sub view_edit_entire_class_form { my ($symb,$url)=@_; - my ($classlist,$sections) = &getclasslist('all','0'); + my ($classlist,$sections,undef) = &getclasslist('all','0'); my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n"; $result.=' <b>Grade Entire Section or Class</b></td></tr>'."\n";