version 1.404, 2007/06/14 21:36:12
|
version 1.431, 2007/08/21 18:48:18
|
Line 41 use Apache::Constants qw(:common);
|
Line 41 use Apache::Constants qw(:common);
|
use Apache::lonlocal; |
use Apache::lonlocal; |
use Apache::lonenc; |
use Apache::lonenc; |
use String::Similarity; |
use String::Similarity; |
use lib '/home/httpd/lib/perl'; |
|
use LONCAPA; |
use LONCAPA; |
|
|
use POSIX qw(floor); |
use POSIX qw(floor); |
|
|
my %oldessays=(); |
|
my %perm=(); |
my %perm=(); |
|
|
# ----- These first few routines are general use routines.---- |
# ----- These first few routines are general use routines.---- |
Line 94 sub get_symb {
|
Line 92 sub get_symb {
|
return (); |
return (); |
} |
} |
} |
} |
|
&Apache::lonenc::check_decrypt(\$symb); |
return ($symb); |
return ($symb); |
} |
} |
|
|
Line 493 sub jscriptNform {
|
Line 492 sub jscriptNform {
|
' }'."\n". |
' }'."\n". |
'</script>'."\n"; |
'</script>'."\n"; |
$jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". |
$jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\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="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n". |
'<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n". |
'<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n". |
Line 538 sub compute_points {
|
Line 537 sub compute_points {
|
# |
# |
|
|
sub most_similar { |
sub most_similar { |
my ($uname,$udom,$uessay)=@_; |
my ($uname,$udom,$uessay,$old_essays)=@_; |
|
|
# ignore spaces and punctuation |
# ignore spaces and punctuation |
|
|
Line 555 sub most_similar {
|
Line 554 sub most_similar {
|
my $scrsid=''; |
my $scrsid=''; |
my $sessay=''; |
my $sessay=''; |
# go through all essays ... |
# go through all essays ... |
foreach my $tkey (keys %oldessays) { |
foreach my $tkey (keys(%$old_essays)) { |
my ($tname,$tdom,$tcrsid)=split(/\./,$tkey); |
my ($tname,$tdom,$tcrsid)=map {&unescape($_)} (split(/\./,$tkey)); |
# ... except the same student |
# ... except the same student |
if (($tname ne $uname) || ($tdom ne $udom)) { |
next if (($tname eq $uname) && ($tdom eq $udom)); |
my $tessay=$oldessays{$tkey}; |
my $tessay=$old_essays->{$tkey}; |
$tessay=~s/\W+/ /gs; |
$tessay=~s/\W+/ /gs; |
# String similarity gives up if not even limit |
# String similarity gives up if not even limit |
my $tsimilar=&String::Similarity::similarity($uessay,$tessay,$limit); |
my $tsimilar=&String::Similarity::similarity($uessay,$tessay,$limit); |
# Found one |
# Found one |
if ($tsimilar>$limit) { |
if ($tsimilar>$limit) { |
$limit=$tsimilar; |
$limit=$tsimilar; |
$sname=$tname; |
$sname=$tname; |
$sdom=$tdom; |
$sdom=$tdom; |
$scrsid=$tcrsid; |
$scrsid=$tcrsid; |
$sessay=$oldessays{$tkey}; |
$sessay=$old_essays->{$tkey}; |
} |
} |
} |
|
} |
} |
if ($limit>0.6) { |
if ($limit>0.6) { |
return ($sname,$sdom,$scrsid,$sessay,$limit); |
return ($sname,$sdom,$scrsid,$sessay,$limit); |
Line 618 sub verifyreceipt {
|
Line 616 sub verifyreceipt {
|
if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) { |
if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) { |
$contents.='<tr bgcolor="#ffffe6"><td> '."\n". |
$contents.='<tr bgcolor="#ffffe6"><td> '."\n". |
'<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom. |
'<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom. |
'\')"; TARGET=_self>'.$$fullname{$_}.'</a> </td>'."\n". |
'\');" target="_self">'.$$fullname{$_}.'</a> </td>'."\n". |
'<td> '.$uname.' </td>'. |
'<td> '.$uname.' </td>'. |
'<td> '.$udom.' </td>'; |
'<td> '.$udom.' </td>'; |
if ($receiptparts) { |
if ($receiptparts) { |
Line 743 LISTJAVASCRIPT
|
Line 741 LISTJAVASCRIPT
|
'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" /><br />'."\n". |
'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" /><br />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\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="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n"; |
'<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n"; |
|
|
if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) { |
if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) { |
Line 1691 sub submission {
|
Line 1689 sub submission {
|
'" src="'.$request->dir_config('lonIconsURL'). |
'" src="'.$request->dir_config('lonIconsURL'). |
'/check.gif" height="16" border="0" />'; |
'/check.gif" height="16" border="0" />'; |
|
|
|
my %old_essays; |
# header info |
# header info |
if ($counter == 0) { |
if ($counter == 0) { |
&sub_page_js($request); |
&sub_page_js($request); |
Line 1752 sub submission {
|
Line 1751 sub submission {
|
'<input type="hidden" name="refresh" value="off" />'."\n". |
'<input type="hidden" name="refresh" value="off" />'."\n". |
'<input type="hidden" name="studentNo" value="" />'."\n". |
'<input type="hidden" name="studentNo" value="" />'."\n". |
'<input type="hidden" name="gradeOpt" value="" />'."\n". |
'<input type="hidden" name="gradeOpt" value="" />'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" />'."\n". |
'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" />'."\n". |
'<input type="hidden" name="vProb" value="'.$env{'form.vProb'}.'" />'."\n". |
'<input type="hidden" name="vProb" value="'.$env{'form.vProb'}.'" />'."\n". |
'<input type="hidden" name="vAns" value="'.$env{'form.vAns'}.'" />'."\n". |
'<input type="hidden" name="vAns" value="'.$env{'form.vAns'}.'" />'."\n". |
Line 1793 sub submission {
|
Line 1792 sub submission {
|
# |
# |
$request->print(<<KEYWORDS); |
$request->print(<<KEYWORDS); |
<b>Keyword Options:</b> |
<b>Keyword Options:</b> |
<a href="javascript:keywords(document.SCORE)"; TARGET=_self>List</a> |
<a href="javascript:keywords(document.SCORE);" target="_self">List</a> |
<a href="#" onMouseDown="javascript:getSel(); return false" |
<a href="#" onMouseDown="javascript:getSel(); return false" |
CLASS="page">Paste Selection to List</a> |
CLASS="page">Paste Selection to List</a> |
<a href="javascript:kwhighlight()"; TARGET=_self>Highlight Attribute</a><br /><br /> |
<a href="javascript:kwhighlight();" target="_self">Highlight Attribute</a><br /><br /> |
KEYWORDS |
KEYWORDS |
# |
# |
# Load the other essays for similarity check |
# Load the other essays for similarity check |
Line 1805 KEYWORDS
|
Line 1804 KEYWORDS
|
my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/); |
my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/); |
$apath=&escape($apath); |
$apath=&escape($apath); |
$apath=~s/\W/\_/gs; |
$apath=~s/\W/\_/gs; |
%oldessays=&Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); |
%old_essays=&Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); |
} |
} |
} |
} |
|
|
Line 1922 KEYWORDS
|
Line 1921 KEYWORDS
|
' <b>Collaborative submission by:</b> '. |
' <b>Collaborative submission by:</b> '. |
'<a href="javascript:viewSubmitter(\''. |
'<a href="javascript:viewSubmitter(\''. |
$env{"form.$uname:$udom:$partid:submitted_by"}. |
$env{"form.$uname:$udom:$partid:submitted_by"}. |
'\')"; TARGET=_self>'. |
'\');" target="_self">'. |
$$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a><br />'; |
$$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a><br />'; |
$request->print($submitby); |
$request->print($submitby); |
next; |
next; |
Line 1943 KEYWORDS
|
Line 1942 KEYWORDS
|
my $similar=''; |
my $similar=''; |
if($env{'form.checkPlag'}){ |
if($env{'form.checkPlag'}){ |
my ($oname,$odom,$ocrsid,$oessay,$osim)= |
my ($oname,$odom,$ocrsid,$oessay,$osim)= |
&most_similar($uname,$udom,$subval); |
&most_similar($uname,$udom,$subval,\%old_essays); |
if ($osim) { |
if ($osim) { |
$osim=int($osim*100.0); |
$osim=int($osim*100.0); |
$similar="<hr /><h3><span class=\"LC_warning\">Essay". |
my %old_course_desc = |
" is $osim% similar to an essay by ". |
&Apache::lonnet::coursedescription($ocrsid, |
&Apache::loncommon::plainname($oname,$odom). |
{'one_time' => 1}); |
|
|
|
$similar="<hr /><h3><span class=\"LC_warning\">". |
|
&mt('Essay is [_1]% similar to an essay by [_2] ([_3]:[_4]) in course [_5] (course id [_6]:[_7])', |
|
$osim, |
|
&Apache::loncommon::plainname($oname,$odom), |
|
$oname,$odom, |
|
$old_course_desc{'description'}, |
|
$old_course_desc{'num'}, |
|
$old_course_desc{'domain'}). |
'</span></h3><blockquote><i>'. |
'</span></h3><blockquote><i>'. |
&keywords_highlight($oessay). |
&keywords_highlight($oessay). |
'</i></blockquote><hr />'; |
'</i></blockquote><hr />'; |
Line 2000 KEYWORDS
|
Line 2008 KEYWORDS
|
if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) { |
if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) { |
my $toGrade.='<input type="button" value="Grade Student" '. |
my $toGrade.='<input type="button" value="Grade Student" '. |
'onClick="javascript:checksubmit(this.form,\'Grade Student\',\'' |
'onClick="javascript:checksubmit(this.form,\'Grade Student\',\'' |
.$counter.'\');" TARGET=_self> '."\n" if (&canmodify($usec)); |
.$counter.'\');" target="_self" /> '."\n" if (&canmodify($usec)); |
$toGrade.='</td></tr></table></td></tr></table>'."\n"; |
$toGrade.='</td></tr></table></td></tr></table>'."\n"; |
if (($env{'form.command'} eq 'submission') || |
if (($env{'form.command'} eq 'submission') || |
($env{'form.command'} eq 'processGroup' && $counter == $total)) { |
($env{'form.command'} eq 'processGroup' && $counter == $total)) { |
Line 2024 KEYWORDS
|
Line 2032 KEYWORDS
|
$result='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n". |
$result='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n". |
'<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n"; |
'<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n"; |
$result.=' <a href="javascript:msgCenter(document.SCORE,'.$counter. |
$result.=' <a href="javascript:msgCenter(document.SCORE,'.$counter. |
',\''.$msgfor.'\')"; TARGET=_self>'. |
',\''.$msgfor.'\');" target="_self">'. |
&mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a><label> ('. |
&mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a><label> ('. |
&mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'. |
&mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'. |
'<img src="'.$request->dir_config('lonIconsURL'). |
'<img src="'.$request->dir_config('lonIconsURL'). |
Line 2076 KEYWORDS
|
Line 2084 KEYWORDS
|
my $endform='<table border="0"><tr><td>'."\n"; |
my $endform='<table border="0"><tr><td>'."\n"; |
$endform.='<input type="button" value="Save & Next" '. |
$endform.='<input type="button" value="Save & Next" '. |
'onClick="javascript:checksubmit(this.form,\'Save & Next\','. |
'onClick="javascript:checksubmit(this.form,\'Save & Next\','. |
$total.','.scalar(@partlist).');" TARGET=_self> '."\n"; |
$total.','.scalar(@partlist).');" target="_self" /> '."\n"; |
my $ntstu ='<select name="NTSTU">'. |
my $ntstu ='<select name="NTSTU">'. |
'<option>1</option><option>2</option>'. |
'<option>1</option><option>2</option>'. |
'<option>3</option><option>5</option>'. |
'<option>3</option><option>5</option>'. |
Line 2085 KEYWORDS
|
Line 2093 KEYWORDS
|
$ntstu =~ s/<option>$nsel</<option selected="selected">$nsel</; |
$ntstu =~ s/<option>$nsel</<option selected="selected">$nsel</; |
$endform.=$ntstu.'student(s) '; |
$endform.=$ntstu.'student(s) '; |
$endform.='<input type="button" value="Previous" '. |
$endform.='<input type="button" value="Previous" '. |
'onClick="javascript:checksubmit(this.form,\'Previous\');" TARGET=_self> '."\n". |
'onClick="javascript:checksubmit(this.form,\'Previous\');" target="_self" /> '."\n". |
'<input type="button" value="Next" '. |
'<input type="button" value="Next" '. |
'onClick="javascript:checksubmit(this.form,\'Next\');" TARGET=_self> '; |
'onClick="javascript:checksubmit(this.form,\'Next\');" target="_self" /> '; |
$endform.='(Next and Previous (student) do not save the scores.)'."\n" ; |
$endform.='(Next and Previous (student) do not save the scores.)'."\n" ; |
$endform.="<input type='hidden' value='".&get_increment(). |
$endform.="<input type='hidden' value='".&get_increment(). |
"' name='increment' />"; |
"' name='increment' />"; |
Line 2169 sub processHandGrade {
|
Line 2177 sub processHandGrade {
|
} |
} |
my $includemsg = $env{'form.includemsg'.$ctr}; |
my $includemsg = $env{'form.includemsg'.$ctr}; |
my ($subject,$message,$msgstatus) = ('','',''); |
my ($subject,$message,$msgstatus) = ('','',''); |
my $restitle = &Apache::lonnet::gettitle($symb); |
my $restitle = &Apache::lonnet::gettitle($symb); |
my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl', |
my ($feedurl,$showsymb) = |
$symb,$udom,$uname); |
&get_feedurl_and_symb($symb,$uname,$udom); |
my ($feedurl,$baseurl,$showsymb,$messagetail); |
my $messagetail; |
$feedurl = &Apache::lonnet::clutter($url); |
|
if ($encrypturl =~ /^yes$/i) { |
|
$baseurl = &Apache::lonenc::encrypted($feedurl,1); |
|
$showsymb = &Apache::lonenc::encrypted($symb,1); |
|
} else { |
|
$baseurl = $feedurl; |
|
$showsymb = $symb; |
|
} |
|
if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { |
if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { |
$subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/); |
$subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/); |
unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); } |
unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); } |
Line 2193 sub processHandGrade {
|
Line 2193 sub processHandGrade {
|
if ($env{'form.withgrades'.$ctr}) { |
if ($env{'form.withgrades'.$ctr}) { |
$message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt; |
$message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt; |
$messagetail = " for <a href=\"". |
$messagetail = " for <a href=\"". |
$baseurl."?symb=$showsymb\">$env{'form.probTitle'}</a>"; |
$feedurl."?symb=$showsymb\">$env{'form.probTitle'}</a>"; |
} |
} |
$msgstatus = |
$msgstatus = |
&Apache::lonmsg::user_normal_msg($uname,$udom,$subject, |
&Apache::lonmsg::user_normal_msg($uname,$udom,$subject, |
$message.$messagetail, |
$message.$messagetail, |
undef,$baseurl,undef, |
undef,$feedurl,undef, |
undef,undef,$showsymb, |
undef,undef,$showsymb, |
$restitle); |
$restitle); |
$request->print('<br />'.&mt('Sending message to [_1]:[_2]',$uname,$udom).': '. |
$request->print('<br />'.&mt('Sending message to [_1]:[_2]',$uname,$udom).': '. |
Line 2215 sub processHandGrade {
|
Line 2215 sub processHandGrade {
|
if ($errorflag eq 'not_allowed') { |
if ($errorflag eq 'not_allowed') { |
$request->print("<span class=\"LC_error\">".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")."</span>"); |
$request->print("<span class=\"LC_error\">".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")."</span>"); |
next; |
next; |
} else { |
} elsif ($message ne '') { |
if ($message ne '') { |
my ($baseurl,$showsymb) = |
$encrypturl= |
&get_feedurl_and_symb($symb,$collaborator, |
&Apache::lonnet::EXT('resource.0.encrypturl', |
$udom); |
$symb,$udom,$collaborator); |
if ($env{'form.withgrades'.$ctr}) { |
if ($encrypturl =~ /^yes$/i) { |
$messagetail = " for <a href=\"". |
$baseurl = &Apache::lonenc::encrypted($feedurl,1); |
|
$showsymb = &Apache::lonenc::encrypted($symb,1); |
|
} else { |
|
$baseurl = $feedurl; |
|
$showsymb = $symb; |
|
} |
|
if ($env{'form.withgrades'.$ctr}) { |
|
$messagetail = " for <a href=\"". |
|
$baseurl."?symb=$showsymb\">$env{'form.probTitle'}</a>"; |
$baseurl."?symb=$showsymb\">$env{'form.probTitle'}</a>"; |
|
|
} |
|
$msgstatus = |
|
&Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle); |
|
} |
} |
|
$msgstatus = |
|
&Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle); |
} |
} |
} |
} |
} |
} |
Line 2588 sub handback_files {
|
Line 2578 sub handback_files {
|
$message .= "<strong>".&Apache::lonnet::gettitle($symb)."</strong><br />"; |
$message .= "<strong>".&Apache::lonnet::gettitle($symb)."</strong><br />"; |
$message .= ' The returned file(s) are named: '. $file_msg; |
$message .= ' The returned file(s) are named: '. $file_msg; |
$message .= " and can be found in your portfolio space."; |
$message .= " and can be found in your portfolio space."; |
my $url = (&Apache::lonnet::decode_symb($symb))[2]; |
my ($feedurl,$showsymb) = |
my $feedurl = &Apache::lonnet::clutter($url); |
&get_feedurl_and_symb($symb,$domain,$stuname); |
my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl', |
|
$symb,$domain,$stuname); |
|
my ($baseurl,$showsymb); |
|
if ($encrypturl =~ /^yes$/i) { |
|
$baseurl = &Apache::lonenc::encrypted($feedurl,1); |
|
$showsymb = &Apache::lonenc::encrypted($symb,1); |
|
} else { |
|
$baseurl = $feedurl; |
|
$showsymb = $symb; |
|
} |
|
my $restitle = &Apache::lonnet::gettitle($symb); |
my $restitle = &Apache::lonnet::gettitle($symb); |
my $msgstatus = |
my $msgstatus = |
&Apache::lonmsg::user_normal_msg($stuname,$domain,$subject. |
&Apache::lonmsg::user_normal_msg($stuname,$domain,$subject. |
' (File Returned) ['.$restitle.']',$message,undef, |
' (File Returned) ['.$restitle.']',$message,undef, |
$baseurl,undef,undef,undef,$showsymb,$restitle); |
$feedurl,undef,undef,undef,$showsymb,$restitle); |
} |
} |
} |
} |
return; |
return; |
} |
} |
|
|
|
sub get_feedurl_and_symb { |
|
my ($symb,$uname,$udom) = @_; |
|
my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb); |
|
$url = &Apache::lonnet::clutter($url); |
|
my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl', |
|
$symb,$udom,$uname); |
|
if ($encrypturl =~ /^yes$/i) { |
|
&Apache::lonenc::encrypted(\$url,1); |
|
&Apache::lonenc::encrypted(\$symb,1); |
|
} |
|
return ($url,$symb); |
|
} |
|
|
sub get_submitted_files { |
sub get_submitted_files { |
my ($udom,$uname,$partid,$respid,$record) = @_; |
my ($udom,$uname,$partid,$respid,$record) = @_; |
my @files; |
my @files; |
Line 2970 sub viewgrades {
|
Line 2963 sub viewgrades {
|
|
|
#beginning of class grading form |
#beginning of class grading form |
$result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n". |
$result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="command" value="editgrades" />'."\n". |
'<input type="hidden" name="command" value="editgrades" />'."\n". |
'<input type="hidden" name="section" value="'.$env{'form.section'}.'" />'."\n". |
'<input type="hidden" name="section" value="'.$env{'form.section'}.'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n". |
Line 2978 sub viewgrades {
|
Line 2971 sub viewgrades {
|
'<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n"; |
'<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n"; |
|
|
my $sectionClass; |
my $sectionClass; |
|
my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section')); |
if ($env{'form.section'} eq 'all') { |
if ($env{'form.section'} eq 'all') { |
$sectionClass='Class </h3>'; |
$sectionClass='Class </h3>'; |
} elsif ($env{'form.section'} eq 'none') { |
} elsif ($env{'form.section'} eq 'none') { |
$sectionClass='Students in no Section </h3>'; |
$sectionClass=&mt('Students in no Section').'</h3>'; |
} else { |
} else { |
$sectionClass='Students in Section '.$env{'form.section'}.'</h3>'; |
$sectionClass=&mt('Students in Section(s) [_1]',$section_display).'</h3>'; |
} |
} |
$result.='<h3>Assign Common Grade To '.$sectionClass; |
$result.='<h3>'.&mt('Assign Common Grade To [_1]',$sectionClass); |
$result.= '<table border=0><tr><td bgcolor="#777777">'."\n". |
$result.= '<table border=0><tr><td bgcolor="#777777">'."\n". |
'<table border=0><tr bgcolor="#ffffdd"><td>'; |
'<table border=0><tr bgcolor="#ffffdd"><td>'; |
#radio buttons/text box for assigning points for a section or class. |
#radio buttons/text box for assigning points for a section or class. |
Line 3037 sub viewgrades {
|
Line 3031 sub viewgrades {
|
$result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n". |
$result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n". |
'<input type="hidden" name="totalparts" value="'.$ctsparts.'" />'; |
'<input type="hidden" name="totalparts" value="'.$ctsparts.'" />'; |
$result.='<input type="button" value="Revert to Default" '. |
$result.='<input type="button" value="Revert to Default" '. |
'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self>'; |
'onClick="javascript:resetEntry('.$ctsparts.');" target="_self" />'; |
|
|
#table listing all the students in a section/class |
#table listing all the students in a section/class |
#header of table |
#header of table |
Line 3088 sub viewgrades {
|
Line 3082 sub viewgrades {
|
$result.='</table></td></tr></table>'; |
$result.='</table></td></tr></table>'; |
$result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n"; |
$result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n"; |
$result.='<input type="button" value="Save" '. |
$result.='<input type="button" value="Save" '. |
'onClick="javascript:submit();" TARGET=_self /></form>'."\n"; |
'onClick="javascript:submit();" target="_self" /></form>'."\n"; |
if (scalar(%$fullname) eq 0) { |
if (scalar(%$fullname) eq 0) { |
my $colspan=3+scalar(@parts); |
my $colspan=3+scalar(@parts); |
$result='<span class="LC_warning">There are no students in section "'.$env{'form.section'}. |
$result='<span class="LC_warning">There are no students in section "'.$env{'form.section'}. |
Line 3108 sub viewstudentgrade {
|
Line 3102 sub viewstudentgrade {
|
'<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'. |
'<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'. |
"\n".$ctr.' </td><td> '. |
"\n".$ctr.' </td><td> '. |
'<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom. |
'<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom. |
'\')"; TARGET=_self>'.$fullname.'</a> '. |
'\');" target="_self">'.$fullname.'</a> '. |
'<span class="LC_internal_info">('.$uname.($env{'user.domain'} eq $udom ? '' : ':'.$udom).')</span></td>'."\n"; |
'<span class="LC_internal_info">('.$uname.($env{'user.domain'} eq $udom ? '' : ':'.$udom).')</span></td>'."\n"; |
$student=~s/:/_/; # colon doen't work in javascript for names |
$student=~s/:/_/; # colon doen't work in javascript for names |
foreach my $apart (@$parts) { |
foreach my $apart (@$parts) { |
Line 3472 sub csvuploadmap_header {
|
Line 3466 sub csvuploadmap_header {
|
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); |
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); |
my $checked=(($env{'form.noFirstLine'})?' checked="checked"':''); |
my $checked=(($env{'form.noFirstLine'})?' checked="checked"':''); |
my $ignore=&mt('Ignore First Line'); |
my $ignore=&mt('Ignore First Line'); |
|
$symb = &Apache::lonenc::check_encrypt($symb); |
$request->print(<<ENDPICK); |
$request->print(<<ENDPICK); |
<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> |
<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> |
<h3><span class="LC_info">Uploading Class Grades</span></h3> |
<h3><span class="LC_info">Uploading Class Grades</span></h3> |
Line 3566 sub upcsvScores_form {
|
Line 3561 sub upcsvScores_form {
|
my $upload=&mt("Upload Scores"); |
my $upload=&mt("Upload Scores"); |
my $upfile_select=&Apache::loncommon::upfile_select_html(); |
my $upfile_select=&Apache::loncommon::upfile_select_html(); |
my $ignore=&mt('Ignore First Line'); |
my $ignore=&mt('Ignore First Line'); |
|
$symb = &Apache::lonenc::check_encrypt($symb); |
$result.=<<ENDUPFORM; |
$result.=<<ENDUPFORM; |
<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> |
<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> |
<input type="hidden" name="symb" value="$symb" /> |
<input type="hidden" name="symb" value="$symb" /> |
Line 3840 LISTJAVASCRIPT
|
Line 3836 LISTJAVASCRIPT
|
|
|
$result.='<form action="/adm/grades" method="post" name="displayPage">'."\n"; |
$result.='<form action="/adm/grades" method="post" name="displayPage">'."\n"; |
$result.=' <b>Problems from:</b> <select name="selectpage">'."\n"; |
$result.=' <b>Problems from:</b> <select name="selectpage">'."\n"; |
my ($titles,$symbx) = &getSymbMap($request); |
my ($titles,$symbx) = &getSymbMap(); |
my ($curpage) =&Apache::lonnet::decode_symb($symb); |
my ($curpage) =&Apache::lonnet::decode_symb($symb); |
# my ($curpage,$mapId) =&Apache::lonnet::decode_symb($symb); |
# my ($curpage,$mapId) =&Apache::lonnet::decode_symb($symb); |
# my $type=($curpage =~ /\.(page|sequence)/); |
# my $type=($curpage =~ /\.(page|sequence)/); |
Line 3874 LISTJAVASCRIPT
|
Line 3870 LISTJAVASCRIPT
|
$result.='<input type="hidden" name="section" value="'.$getsec.'" />'."\n". |
$result.='<input type="hidden" name="section" value="'.$getsec.'" />'."\n". |
'<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n". |
'<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n". |
'<input type="hidden" name="command" value="displayPage" />'."\n". |
'<input type="hidden" name="command" value="displayPage" />'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n"; |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n"; |
|
|
$result.=' <b>'.&mt('Use CODE:').' </b>'. |
$result.=' <b>'.&mt('Use CODE:').' </b>'. |
Line 3922 LISTJAVASCRIPT
|
Line 3918 LISTJAVASCRIPT
|
} |
} |
|
|
sub getSymbMap { |
sub getSymbMap { |
my ($request) = @_; |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
|
my %symbx = (); |
my %symbx = (); |
Line 3998 sub displayPage {
|
Line 3993 sub displayPage {
|
'<input type="hidden" name="student" value="'.$env{'form.student'}.'" />'."\n". |
'<input type="hidden" name="student" value="'.$env{'form.student'}.'" />'."\n". |
'<input type="hidden" name="page" value="'.$pageTitle.'" />'."\n". |
'<input type="hidden" name="page" value="'.$pageTitle.'" />'."\n". |
'<input type="hidden" name="title" value="'.$env{'form.title'}.'" />'."\n". |
'<input type="hidden" name="title" value="'.$env{'form.title'}.'" />'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="overRideScore" value="no" />'."\n". |
'<input type="hidden" name="overRideScore" value="no" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n"; |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n"; |
|
|
Line 4367 sub updateGradeByPage {
|
Line 4362 sub updateGradeByPage {
|
# |
# |
#------ start of section for handling grading by page/sequence --------- |
#------ start of section for handling grading by page/sequence --------- |
|
|
|
=pod |
|
|
|
=head1 Bubble sheet grading routines |
|
|
|
For this documentation: |
|
|
|
'scanline' refers to the full line of characters |
|
from the file that we are parsing that represents one entire sheet |
|
|
|
'bubble line' refers to the data |
|
representing the line of bubbles that are on the physical bubble sheet |
|
|
|
|
|
The overall process is that a scanned in bubble sheet data is uploaded |
|
into a course. When a user wants to grade, they select a |
|
sequence/folder of resources, a file of bubble sheet info, and pick |
|
one of the predefined configurations for what each scanline looks |
|
like. |
|
|
|
Next each scanline is checked for any errors of either 'missing |
|
bubbles' (it's an error because it may have been missed scanned |
|
because too light bubbling), 'double bubble' (each bubble line should |
|
have no more that one letter picked), invalid or duplicated CODE, |
|
invalid student ID |
|
|
|
If the CODE option is used that determines the randomization of the |
|
homework problems, either way the student ID is looked up into a |
|
username:domain. |
|
|
|
During the validation phase the instructor can choose to skip scanlines. |
|
|
|
After the validation phase, there is now 3 bubble sheet files |
|
|
|
scantron_original_filename (unmodified original file) |
|
scantron_corrected_filename (file where the corrected information has replaced the original information) |
|
scantron_skipped_filename (contains the exact text of scanlines that where skipped) |
|
|
|
Also there is a separate hash nohist_scantrondata that contains extra |
|
correction information that isn't representable in the bubble sheet |
|
file (see &scantron_getfile() for more information) |
|
|
|
After all scanlines are either valid, marked as valid or skipped, then |
|
foreach line foreach problem in the picked sequence, an ssi request is |
|
made that simulates a user submitting their selected letter(s) against |
|
the homework problem. |
|
|
|
=over 4 |
|
|
|
=cut |
|
|
|
|
|
=pod |
|
|
|
=item defaultFormData |
|
|
|
Returns html hidden inputs used to hold context/default values. |
|
|
|
Arguments: |
|
$symb - $symb of the current resource |
|
|
|
=cut |
|
|
sub defaultFormData { |
sub defaultFormData { |
my ($symb)=@_; |
my ($symb)=@_; |
return ' |
return ' |
<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\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="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n"; |
} |
} |
|
|
|
=pod |
|
|
|
=item getSequenceDropDown |
|
|
|
Return html dropdown of possible sequences to grade |
|
|
|
Arguments: |
|
$symb - $symb of the current resource |
|
|
|
=cut |
|
|
sub getSequenceDropDown { |
sub getSequenceDropDown { |
my ($request,$symb)=@_; |
my ($symb)=@_; |
my $result='<select name="selectpage">'."\n"; |
my $result='<select name="selectpage">'."\n"; |
my ($titles,$symbx) = &getSymbMap($request); |
my ($titles,$symbx) = &getSymbMap(); |
my ($curpage)=&Apache::lonnet::decode_symb($symb); |
my ($curpage)=&Apache::lonnet::decode_symb($symb); |
my $ctr=0; |
my $ctr=0; |
foreach (@$titles) { |
foreach (@$titles) { |
Line 4392 sub getSequenceDropDown {
|
Line 4460 sub getSequenceDropDown {
|
return $result; |
return $result; |
} |
} |
|
|
|
|
|
=pod |
|
|
|
=item scantron_filenames |
|
|
|
Returns a list of the scantron files in the current course |
|
|
|
=cut |
|
|
sub scantron_filenames { |
sub scantron_filenames { |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
Line 4407 sub scantron_filenames {
|
Line 4484 sub scantron_filenames {
|
return @possiblenames; |
return @possiblenames; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_uploads |
|
|
|
Returns html drop-down list of scantron files in current course. |
|
|
|
Arguments: |
|
$file2grade - filename to set as selected in the dropdown |
|
|
|
=cut |
|
|
sub scantron_uploads { |
sub scantron_uploads { |
my ($file2grade) = @_; |
my ($file2grade) = @_; |
my $result= '<select name="scantron_selectfile">'; |
my $result= '<select name="scantron_selectfile">'; |
Line 4418 sub scantron_uploads {
|
Line 4506 sub scantron_uploads {
|
return $result; |
return $result; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_scantab |
|
|
|
Returns html drop down of the scantron formats in the scantronformat.tab |
|
file. |
|
|
|
=cut |
|
|
sub scantron_scantab { |
sub scantron_scantab { |
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); |
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); |
my $result='<select name="scantron_format">'."\n"; |
my $result='<select name="scantron_format">'."\n"; |
Line 4432 sub scantron_scantab {
|
Line 4529 sub scantron_scantab {
|
return $result; |
return $result; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_CODElist |
|
|
|
Returns html drop down of the saved CODE lists from current course, |
|
generated from earlier printings. |
|
|
|
=cut |
|
|
sub scantron_CODElist { |
sub scantron_CODElist { |
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
Line 4446 sub scantron_CODElist {
|
Line 4552 sub scantron_CODElist {
|
return $namechoice; |
return $namechoice; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_CODEunique |
|
|
|
Returns the html for "Each CODE to be used once" radio. |
|
|
|
=cut |
|
|
sub scantron_CODEunique { |
sub scantron_CODEunique { |
my $result='<span style="white-space: nowrap;"> |
my $result='<span style="white-space: nowrap;"> |
<label><input type="radio" name="scantron_CODEunique" |
<label><input type="radio" name="scantron_CODEunique" |
value="yes" checked="checked" /> Yes </label> |
value="yes" checked="checked" />'.&mt('Yes').' </label> |
</span> |
</span> |
<span style="white-space: nowrap;"> |
<span style="white-space: nowrap;"> |
<label><input type="radio" name="scantron_CODEunique" |
<label><input type="radio" name="scantron_CODEunique" |
value="no" /> No </label> |
value="no" />'.&mt('No').' </label> |
</span>'; |
</span>'; |
return $result; |
return $result; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_selectphase |
|
|
|
Generates the initial screen to start the bubble sheet process. |
|
Allows for - starting a grading run. |
|
- downloading existing scan data (original, corrected |
|
or skipped info) |
|
|
|
- uploading new scan data |
|
|
|
Arguments: |
|
$r - The Apache request object |
|
$file2grade - name of the file that contain the scanned data to score |
|
|
|
=cut |
|
|
sub scantron_selectphase { |
sub scantron_selectphase { |
my ($r,$file2grade) = @_; |
my ($r,$file2grade) = @_; |
my ($symb)=&get_symb($r); |
my ($symb)=&get_symb($r); |
if (!$symb) {return '';} |
if (!$symb) {return '';} |
my $sequence_selector=&getSequenceDropDown($r,$symb); |
my $sequence_selector=&getSequenceDropDown($symb); |
my $default_form_data=&defaultFormData($symb); |
my $default_form_data=&defaultFormData($symb); |
my $grading_menu_button=&show_grading_menu_form($symb); |
my $grading_menu_button=&show_grading_menu_form($symb); |
my $file_selector=&scantron_uploads($file2grade); |
my $file_selector=&scantron_uploads($file2grade); |
Line 4470 sub scantron_selectphase {
|
Line 4601 sub scantron_selectphase {
|
my $CODE_selector=&scantron_CODElist(); |
my $CODE_selector=&scantron_CODElist(); |
my $CODE_unique=&scantron_CODEunique(); |
my $CODE_unique=&scantron_CODEunique(); |
my $result; |
my $result; |
#FIXME allow instructor to be able to download the scantron file |
|
# and to upload it, |
# Chunk of form to prompt for a file to grade and how: |
|
|
$result.= <<SCANTRONFORM; |
$result.= <<SCANTRONFORM; |
<table width="100%" border="0"> |
<table width="100%" border="0"> |
<tr> |
<tr> |
Line 4504 sub scantron_selectphase {
|
Line 4636 sub scantron_selectphase {
|
<td> Options: </td> |
<td> Options: </td> |
<td> |
<td> |
<label><input type="checkbox" name="scantron_options_redo" value="redo_skipped"/> Do only previously skipped records</label> <br /> |
<label><input type="checkbox" name="scantron_options_redo" value="redo_skipped"/> Do only previously skipped records</label> <br /> |
<label><input type="checkbox" name="scantron_options_ignore" value="ignore_corrections"/> Remove all exisiting corrections</label> <br /> |
<label><input type="checkbox" name="scantron_options_ignore" value="ignore_corrections"/> Remove all existing corrections</label> <br /> |
<label><input type="checkbox" name="scantron_options_hidden" value="ignore_hidden"/> Skip hidden resources when grading</label> |
<label><input type="checkbox" name="scantron_options_hidden" value="ignore_hidden"/> Skip hidden resources when grading</label> |
</td> |
</td> |
</tr> |
</tr> |
Line 4524 SCANTRONFORM
|
Line 4656 SCANTRONFORM
|
if (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) || |
if (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) || |
&Apache::lonnet::allowed('usc',$env{'request.course.id'})) { |
&Apache::lonnet::allowed('usc',$env{'request.course.id'})) { |
|
|
|
# Chunk of form to prompt for a scantron file upload. |
|
|
$r->print(<<SCANTRONFORM); |
$r->print(<<SCANTRONFORM); |
<tr> |
<tr> |
<td bgcolor="#777777"> |
<td bgcolor="#777777"> |
Line 4569 UPLOAD
|
Line 4703 UPLOAD
|
</tr> |
</tr> |
SCANTRONFORM |
SCANTRONFORM |
} |
} |
|
|
|
# Chunk of the form that prompts to view a scoring office file, |
|
# corrected file, skipped records in a file. |
|
|
$r->print(<<SCANTRONFORM); |
$r->print(<<SCANTRONFORM); |
<tr> |
<tr> |
<form action='/adm/grades' name='scantron_download'> |
<form action='/adm/grades' name='scantron_download'> |
Line 4603 SCANTRONFORM
|
Line 4741 SCANTRONFORM
|
return |
return |
} |
} |
|
|
|
=pod |
|
|
|
=item get_scantron_config |
|
|
|
Parse and return the scantron configuration line selected as a |
|
hash of configuration file fields. |
|
|
|
Arguments: |
|
which - the name of the configuration to parse from the file. |
|
|
|
|
|
Returns: |
|
If the named configuration is not in the file, an empty |
|
hash is returned. |
|
a hash with the fields |
|
name - internal name for the this configuration setup |
|
description - text to display to operator that describes this config |
|
CODElocation - if 0 or the string 'none' |
|
- no CODE exists for this config |
|
if -1 || the string 'letter' |
|
- a CODE exists for this config and is |
|
a string of letters |
|
Unsupported value (but planned for future support) |
|
if a positive integer |
|
- The CODE exists as the first n items from |
|
the question section of the form |
|
if the string 'number' |
|
- The CODE exists for this config and is |
|
a string of numbers |
|
CODEstart - (only matter if a CODE exists) column in the line where |
|
the CODE starts |
|
CODElength - length of the CODE |
|
IDstart - column where the student ID number starts |
|
IDlength - length of the student ID info |
|
Qstart - column where the information from the bubbled |
|
'questions' start |
|
Qlength - number of columns comprising a single bubble line from |
|
the sheet. (usually either 1 or 10) |
|
Qon - either a single character representing the character used |
|
to signal a bubble was chosen in the positional setup, or |
|
the string 'letter' if the letter of the chosen bubble is |
|
in the final, or 'number' if a number representing the |
|
chosen bubble is in the file (1->A 0->J) |
|
Qoff - the character used to represent that a bubble was |
|
left blank |
|
PaperID - if the scanning process generates a unique number for each |
|
sheet scanned the column that this ID number starts in |
|
PaperIDlength - number of columns that comprise the unique ID number |
|
for the sheet of paper |
|
FirstName - column that the first name starts in |
|
FirstNameLength - number of columns that the first name spans |
|
|
|
LastName - column that the last name starts in |
|
LastNameLength - number of columns that the last name spans |
|
|
|
=cut |
|
|
sub get_scantron_config { |
sub get_scantron_config { |
my ($which) = @_; |
my ($which) = @_; |
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); |
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab'); |
Line 4635 sub get_scantron_config {
|
Line 4830 sub get_scantron_config {
|
return %config; |
return %config; |
} |
} |
|
|
|
=pod |
|
|
|
=item username_to_idmap |
|
|
|
creates a hash keyed by student id with values of the corresponding |
|
student username:domain. |
|
|
|
Arguments: |
|
|
|
$classlist - reference to the class list hash. This is a hash |
|
keyed by student name:domain whose elements are references |
|
to arrays containing various chunks of information |
|
about the student. (See loncoursedata for more info). |
|
|
|
Returns |
|
%idmap - the constructed hash |
|
|
|
=cut |
|
|
sub username_to_idmap { |
sub username_to_idmap { |
my ($classlist)= @_; |
my ($classlist)= @_; |
my %idmap; |
my %idmap; |
Line 4645 sub username_to_idmap {
|
Line 4859 sub username_to_idmap {
|
return %idmap; |
return %idmap; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_fixup_scanline |
|
|
|
Process a requested correction to a scanline. |
|
|
|
Arguments: |
|
$scantron_config - hash from &get_scantron_config() |
|
$scan_data - hash of correction information |
|
(see &scantron_getfile()) |
|
$line - existing scanline |
|
$whichline - line number of the passed in scanline |
|
$field - type of change to process |
|
(either |
|
'ID' -> correct the student ID number |
|
'CODE' -> correct the CODE |
|
'answer' -> fixup the submitted answers) |
|
|
|
$args - hash of additional info, |
|
- 'ID' |
|
'newid' -> studentID to use in replacement |
|
of existing one |
|
- 'CODE' |
|
'CODE_ignore_dup' - set to true if duplicates |
|
should be ignored. |
|
'CODE' - is new code or 'use_unfound' |
|
if the existing unfound code should |
|
be used as is |
|
- 'answer' |
|
'response' - new answer or 'none' if blank |
|
'question' - the bubble line to change |
|
|
|
Returns: |
|
$line - the modified scanline |
|
|
|
Side effects: |
|
$scan_data - may be updated |
|
|
|
=cut |
|
|
|
|
sub scantron_fixup_scanline { |
sub scantron_fixup_scanline { |
my ($scantron_config,$scan_data,$line,$whichline,$field,$args)=@_; |
my ($scantron_config,$scan_data,$line,$whichline,$field,$args)=@_; |
|
|
if ($field eq 'ID') { |
if ($field eq 'ID') { |
if (length($args->{'newid'}) > $$scantron_config{'IDlength'}) { |
if (length($args->{'newid'}) > $$scantron_config{'IDlength'}) { |
return ($line,1,'New value too large'); |
return ($line,1,'New value too large'); |
Line 4703 sub scantron_fixup_scanline {
|
Line 4959 sub scantron_fixup_scanline {
|
return $line; |
return $line; |
} |
} |
|
|
|
=pod |
|
|
|
=item scan_data |
|
|
|
Edit or look up an item in the scan_data hash. |
|
|
|
Arguments: |
|
$scan_data - The hash (see scantron_getfile) |
|
$key - shorthand of the key to edit (actual key is |
|
scantronfilename_key). |
|
$data - New value of the hash entry. |
|
$delete - If true, the entry is removed from the hash. |
|
|
|
Returns: |
|
The new value of the hash table field (undefined if deleted). |
|
|
|
=cut |
|
|
|
|
sub scan_data { |
sub scan_data { |
my ($scan_data,$key,$value,$delete)=@_; |
my ($scan_data,$key,$value,$delete)=@_; |
my $filename=$env{'form.scantron_selectfile'}; |
my $filename=$env{'form.scantron_selectfile'}; |
Line 4713 sub scan_data {
|
Line 4988 sub scan_data {
|
return $scan_data->{$filename.'_'.$key}; |
return $scan_data->{$filename.'_'.$key}; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_parse_scanline |
|
|
|
Decodes a scanline from the selected scantron file |
|
|
|
Arguments: |
|
line - The text of the scantron file line to process |
|
whichline - Line number |
|
scantron_config - Hash describing the format of the scantron lines. |
|
scan_data - Hash of extra information about the scanline |
|
(see scantron_getfile for more information) |
|
just_header - True if should not process question answers but only |
|
the stuff to the left of the answers. |
|
Returns: |
|
Hash containing the result of parsing the scanline |
|
|
|
Keys are all proceeded by the string 'scantron.' |
|
|
|
CODE - the CODE in use for this scanline |
|
useCODE - 1 if the CODE is invalid but it usage has been forced |
|
by the operator |
|
CODE_ignore_dup - 1 if the CODE is a duplicated use when unique |
|
CODEs were selected, but the usage has been |
|
forced by the operator |
|
ID - student ID |
|
PaperID - if used, the ID number printed on the sheet when the |
|
paper was scanned |
|
FirstName - first name from the sheet |
|
LastName - last name from the sheet |
|
|
|
if just_header was not true these key may also exist |
|
|
|
missingerror - a list of bubbled line numbers that had a blank bubble |
|
that is considered an error (if the operator had already |
|
okayed a blank bubble line as really being blank then |
|
that bubble line number won't appear here. |
|
doubleerror - a list of bubbled line numbers that had more than one |
|
bubble filled in and has not been corrected by the |
|
operator |
|
maxquest - the number of the last bubble line that was parsed |
|
|
|
(<number> starts at 1) |
|
<number>.answer - zero or more letters representing the selected |
|
letters from the scanline for the bubble line |
|
<number>. |
|
if blank there was either no bubble or there where |
|
multiple bubbles, (consult the keys missingerror and |
|
doubleerror if this is an error condition) |
|
|
|
=cut |
|
|
sub scantron_parse_scanline { |
sub scantron_parse_scanline { |
my ($line,$whichline,$scantron_config,$scan_data,$justHeader)=@_; |
my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_; |
my %record; |
my %record; |
my $questions=substr($line,$$scantron_config{'Qstart'}-1); |
my $questions=substr($line,$$scantron_config{'Qstart'}-1); # Answers |
my $data=substr($line,0,$$scantron_config{'Qstart'}-1); |
my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff |
if (!($$scantron_config{'CODElocation'} eq 0 || |
if (!($$scantron_config{'CODElocation'} eq 0 || |
$$scantron_config{'CODElocation'} eq 'none')) { |
$$scantron_config{'CODElocation'} eq 'none')) { |
if ($$scantron_config{'CODElocation'} < 0 || |
if ($$scantron_config{'CODElocation'} < 0 || |
Line 4747 sub scantron_parse_scanline {
|
Line 5074 sub scantron_parse_scanline {
|
$record{'scantron.LastName'}= |
$record{'scantron.LastName'}= |
substr($data,$$scantron_config{'LastName'}-1, |
substr($data,$$scantron_config{'LastName'}-1, |
$$scantron_config{'LastNamelength'}); |
$$scantron_config{'LastNamelength'}); |
if ($justHeader) { return \%record; } |
if ($just_header) { return \%record; } |
|
|
my @alphabet=('A'..'Z'); |
my @alphabet=('A'..'Z'); |
my $questnum=0; |
my $questnum=0; |
Line 4820 sub scantron_parse_scanline {
|
Line 5147 sub scantron_parse_scanline {
|
return \%record; |
return \%record; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_add_delay |
|
|
|
Adds an error message that occurred during the grading phase to a |
|
queue of messages to be shown after grading pass is complete |
|
|
|
Arguments: |
|
$delayqueue - arrary ref of hash ref of error messages |
|
$scanline - the scanline that caused the error |
|
$errormesage - the error message |
|
$errorcode - a numeric code for the error |
|
|
|
Side Effects: |
|
updates the $delayqueue to have a new hash ref of the error |
|
|
|
=cut |
|
|
sub scantron_add_delay { |
sub scantron_add_delay { |
my ($delayqueue,$scanline,$errormessage,$errorcode)=@_; |
my ($delayqueue,$scanline,$errormessage,$errorcode)=@_; |
push(@$delayqueue, |
push(@$delayqueue, |
Line 4828 sub scantron_add_delay {
|
Line 5173 sub scantron_add_delay {
|
); |
); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_find_student |
|
|
|
Finds the username for the current scanline |
|
|
|
Arguments: |
|
$scantron_record - hash result from scantron_parse_scanline |
|
$scan_data - hash of correction information |
|
(see &scantron_getfile() form more information) |
|
$idmap - hash from &username_to_idmap() |
|
$line - number of current scanline |
|
|
|
Returns: |
|
Either 'username:domain' or undef if unknown |
|
|
|
=cut |
|
|
sub scantron_find_student { |
sub scantron_find_student { |
my ($scantron_record,$scan_data,$idmap,$line)=@_; |
my ($scantron_record,$scan_data,$idmap,$line)=@_; |
my $scanID=$$scantron_record{'scantron.ID'}; |
my $scanID=$$scantron_record{'scantron.ID'}; |
Line 4842 sub scantron_find_student {
|
Line 5205 sub scantron_find_student {
|
return undef; |
return undef; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_filter |
|
|
|
Filter sub for lonnavmaps, filters out hidden resources if ignore |
|
hidden resources was selected |
|
|
|
=cut |
|
|
sub scantron_filter { |
sub scantron_filter { |
my ($curres)=@_; |
my ($curres)=@_; |
|
|
Line 4858 sub scantron_filter {
|
Line 5230 sub scantron_filter {
|
return 0; |
return 0; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_process_corrections |
|
|
|
Gets correction information out of submitted form data and corrects |
|
the scanline |
|
|
|
=cut |
|
|
sub scantron_process_corrections { |
sub scantron_process_corrections { |
my ($r) = @_; |
my ($r) = @_; |
my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); |
my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); |
Line 4915 sub scantron_process_corrections {
|
Line 5296 sub scantron_process_corrections {
|
} |
} |
} |
} |
|
|
|
=pod |
|
|
|
=item reset_skipping_status |
|
|
|
Forgets the current set of remember skipped scanlines (and thus |
|
reverts back to considering all lines in the |
|
scantron_skipped_<filename> file) |
|
|
|
=cut |
|
|
sub reset_skipping_status { |
sub reset_skipping_status { |
my ($scanlines,$scan_data)=&scantron_getfile(); |
my ($scanlines,$scan_data)=&scantron_getfile(); |
&scan_data($scan_data,'remember_skipping',undef,1); |
&scan_data($scan_data,'remember_skipping',undef,1); |
&scantron_putfile(undef,$scan_data); |
&scantron_putfile(undef,$scan_data); |
} |
} |
|
|
|
=pod |
|
|
|
=item start_skipping |
|
|
|
Marks a scanline to be skipped. |
|
|
|
=cut |
|
|
sub start_skipping { |
sub start_skipping { |
my ($scan_data,$i)=@_; |
my ($scan_data,$i)=@_; |
my %remembered=split(':',&scan_data($scan_data,'remember_skipping')); |
my %remembered=split(':',&scan_data($scan_data,'remember_skipping')); |
Line 4932 sub start_skipping {
|
Line 5331 sub start_skipping {
|
&scan_data($scan_data,'remember_skipping',join(':',%remembered)); |
&scan_data($scan_data,'remember_skipping',join(':',%remembered)); |
} |
} |
|
|
|
=pod |
|
|
|
=item should_be_skipped |
|
|
|
Checks whether a scanline should be skipped. |
|
|
|
=cut |
|
|
sub should_be_skipped { |
sub should_be_skipped { |
my ($scanlines,$scan_data,$i)=@_; |
my ($scanlines,$scan_data,$i)=@_; |
if ($env{'form.scantron_options_redo'} !~ /^redo_/) { |
if ($env{'form.scantron_options_redo'} !~ /^redo_/) { |
Line 4947 sub should_be_skipped {
|
Line 5354 sub should_be_skipped {
|
return 1; |
return 1; |
} |
} |
|
|
|
=pod |
|
|
|
=item remember_current_skipped |
|
|
|
Discovers what scanlines are in the scantron_skipped_<filename> |
|
file and remembers them into scan_data for later use. |
|
|
|
=cut |
|
|
sub remember_current_skipped { |
sub remember_current_skipped { |
my ($scanlines,$scan_data)=&scantron_getfile(); |
my ($scanlines,$scan_data)=&scantron_getfile(); |
my %to_remember; |
my %to_remember; |
Line 4960 sub remember_current_skipped {
|
Line 5376 sub remember_current_skipped {
|
&scantron_putfile(undef,$scan_data); |
&scantron_putfile(undef,$scan_data); |
} |
} |
|
|
|
=pod |
|
|
|
=item check_for_error |
|
|
|
Checks if there was an error when attempting to remove a specific |
|
scantron_.. bubble sheet data file. Prints out an error if |
|
something went wrong. |
|
|
|
=cut |
|
|
sub check_for_error { |
sub check_for_error { |
my ($r,$result)=@_; |
my ($r,$result)=@_; |
if ($result ne 'ok' && $result ne 'not_found' ) { |
if ($result ne 'ok' && $result ne 'not_found' ) { |
Line 4967 sub check_for_error {
|
Line 5393 sub check_for_error {
|
} |
} |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_warning_screen |
|
|
|
Interstitial screen to make sure the operator has selected the |
|
correct options before we start the validation phase. |
|
|
|
=cut |
|
|
sub scantron_warning_screen { |
sub scantron_warning_screen { |
my ($button_text)=@_; |
my ($button_text)=@_; |
my $title=&Apache::lonnet::gettitle($env{'form.selectpage'}); |
my $title=&Apache::lonnet::gettitle($env{'form.selectpage'}); |
Line 4999 $CODElist
|
Line 5434 $CODElist
|
STUFF |
STUFF |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_do_warning |
|
|
|
Check if the operator has picked something for all required |
|
fields. Error out if something is missing. |
|
|
|
=cut |
|
|
sub scantron_do_warning { |
sub scantron_do_warning { |
my ($r)=@_; |
my ($r)=@_; |
my ($symb)=&get_symb($r); |
my ($symb)=&get_symb($r); |
Line 5030 STUFF
|
Line 5474 STUFF
|
return ''; |
return ''; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_form_start |
|
|
|
html hidden input for remembering all selected grading options |
|
|
|
=cut |
|
|
sub scantron_form_start { |
sub scantron_form_start { |
my ($max_bubble)=@_; |
my ($max_bubble)=@_; |
my $result= <<SCANTRONFORM; |
my $result= <<SCANTRONFORM; |
Line 5047 SCANTRONFORM
|
Line 5499 SCANTRONFORM
|
return $result; |
return $result; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_file |
|
|
|
Dispatch routine for doing validation of a bubble sheet data file. |
|
|
|
Also processes any necessary information resets that need to |
|
occur before validation begins (ignore previous corrections, |
|
restarting the skipped records processing) |
|
|
|
=cut |
|
|
sub scantron_validate_file { |
sub scantron_validate_file { |
my ($r) = @_; |
my ($r) = @_; |
my ($symb)=&get_symb($r); |
my ($symb)=&get_symb($r); |
Line 5054 sub scantron_validate_file {
|
Line 5518 sub scantron_validate_file {
|
my $default_form_data=&defaultFormData($symb); |
my $default_form_data=&defaultFormData($symb); |
|
|
# do the detection of only doing skipped records first befroe we delete |
# do the detection of only doing skipped records first befroe we delete |
# them when doing the corrections reset |
# them when doing the corrections reset |
if ($env{'form.scantron_options_redo'} ne 'redo_skipped_ready') { |
if ($env{'form.scantron_options_redo'} ne 'redo_skipped_ready') { |
&reset_skipping_status(); |
&reset_skipping_status(); |
} |
} |
Line 5073 sub scantron_validate_file {
|
Line 5537 sub scantron_validate_file {
|
if ($env{'form.scantron_corrections'}) { |
if ($env{'form.scantron_corrections'}) { |
&scantron_process_corrections($r); |
&scantron_process_corrections($r); |
} |
} |
$r->print("<p>Gathering neccessary info.</p>");$r->rflush(); |
$r->print("<p>Gathering necessary info.</p>");$r->rflush(); |
#get the student pick code ready |
#get the student pick code ready |
$r->print(&Apache::loncommon::studentbrowser_javascript()); |
$r->print(&Apache::loncommon::studentbrowser_javascript()); |
my $max_bubble=&scantron_get_maxbubble(); |
my $max_bubble=&scantron_get_maxbubble(); |
Line 5130 STUFF
|
Line 5594 STUFF
|
return ''; |
return ''; |
} |
} |
|
|
|
|
|
=pod |
|
|
|
=item scantron_remove_file |
|
|
|
Removes the requested bubble sheet data file, makes sure that |
|
scantron_original_<filename> is never removed |
|
|
|
|
|
=cut |
|
|
sub scantron_remove_file { |
sub scantron_remove_file { |
my ($which)=@_; |
my ($which)=@_; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
Line 5144 sub scantron_remove_file {
|
Line 5619 sub scantron_remove_file {
|
return &Apache::lonnet::removeuserfile($cname,$cdom,$file); |
return &Apache::lonnet::removeuserfile($cname,$cdom,$file); |
} |
} |
|
|
|
|
|
=pod |
|
|
|
=item scantron_remove_scan_data |
|
|
|
Removes all scan_data correction for the requested bubble sheet |
|
data file. (In the case that both the are doing skipped records we need |
|
to remember the old skipped lines for the time being so that element |
|
persists for a while.) |
|
|
|
=cut |
|
|
sub scantron_remove_scan_data { |
sub scantron_remove_scan_data { |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
Line 5166 sub scantron_remove_scan_data {
|
Line 5653 sub scantron_remove_scan_data {
|
return $result; |
return $result; |
} |
} |
|
|
|
|
|
=pod |
|
|
|
=item scantron_getfile |
|
|
|
Fetches the requested bubble sheet data file (all 3 versions), and |
|
the scan_data hash |
|
|
|
Arguments: |
|
None |
|
|
|
Returns: |
|
2 hash references |
|
|
|
- first one has |
|
orig - |
|
corrected - |
|
skipped - each of which points to an array ref of the specified |
|
file broken up into individual lines |
|
count - number of scanlines |
|
|
|
- second is the scan_data hash possible keys are |
|
($number refers to scanline numbered $number and thus the key affects |
|
only that scanline |
|
$bubline refers to the specific bubble line element and the aspects |
|
refers to that specific bubble line element) |
|
|
|
$number.user - username:domain to use |
|
$number.CODE_ignore_dup |
|
- ignore the duplicate CODE error |
|
$number.useCODE |
|
- use the CODE in the scanline as is |
|
$number.no_bubble.$bubline |
|
- it is valid that there is no bubbled in bubble |
|
at $number $bubline |
|
remember_skipping |
|
- a frozen hash containing keys of $number and values |
|
of either |
|
1 - we are on a 'do skipped records pass' and plan |
|
on processing this line |
|
2 - we are on a 'do skipped records pass' and this |
|
scanline has been marked to skip yet again |
|
|
|
=cut |
|
|
sub scantron_getfile { |
sub scantron_getfile { |
#FIXME really would prefer a scantron directory |
#FIXME really would prefer a scantron directory |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
Line 5198 sub scantron_getfile {
|
Line 5730 sub scantron_getfile {
|
return (\%scanlines,\%scan_data); |
return (\%scanlines,\%scan_data); |
} |
} |
|
|
|
=pod |
|
|
|
=item lonnet_putfile |
|
|
|
Wrapper routine to call &Apache::lonnet::finishuserfileupload |
|
|
|
Arguments: |
|
$contents - data to store |
|
$filename - filename to store $contents into |
|
|
|
Returns: |
|
result value from &Apache::lonnet::finishuserfileupload |
|
|
|
=cut |
|
|
sub lonnet_putfile { |
sub lonnet_putfile { |
my ($contents,$filename)=@_; |
my ($contents,$filename)=@_; |
my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; |
Line 5207 sub lonnet_putfile {
|
Line 5754 sub lonnet_putfile {
|
|
|
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_putfile |
|
|
|
Stores the current version of the bubble sheet data files, and the |
|
scan_data hash. (Does not modify the original version only the |
|
corrected and skipped versions. |
|
|
|
Arguments: |
|
$scanlines - hash ref that looks like the first return value from |
|
&scantron_getfile() |
|
$scan_data - hash ref that looks like the second return value from |
|
&scantron_getfile() |
|
|
|
=cut |
|
|
sub scantron_putfile { |
sub scantron_putfile { |
my ($scanlines,$scan_data) = @_; |
my ($scanlines,$scan_data) = @_; |
#FIXME really would prefer a scantron directory |
#FIXME really would prefer a scantron directory |
Line 5227 sub scantron_putfile {
|
Line 5790 sub scantron_putfile {
|
&Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname); |
&Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_get_line |
|
|
|
Returns the correct version of the scanline |
|
|
|
Arguments: |
|
$scanlines - hash ref that looks like the first return value from |
|
&scantron_getfile() |
|
$scan_data - hash ref that looks like the second return value from |
|
&scantron_getfile() |
|
$i - number of the requested line (starts at 0) |
|
|
|
Returns: |
|
A scanline, (either the original or the corrected one if it |
|
exists), or undef if the requested scanline should be |
|
skipped. (Either because it's an skipped scanline, or it's an |
|
unskipped scanline and we are not doing a 'do skipped scanlines' |
|
pass. |
|
|
|
=cut |
|
|
sub scantron_get_line { |
sub scantron_get_line { |
my ($scanlines,$scan_data,$i)=@_; |
my ($scanlines,$scan_data,$i)=@_; |
if (&should_be_skipped($scanlines,$scan_data,$i)) { return undef; } |
if (&should_be_skipped($scanlines,$scan_data,$i)) { return undef; } |
Line 5235 sub scantron_get_line {
|
Line 5820 sub scantron_get_line {
|
return $scanlines->{'orig'}[$i]; |
return $scanlines->{'orig'}[$i]; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_todo_count |
|
|
|
Counts the number of scanlines that need processing. |
|
|
|
Arguments: |
|
$scanlines - hash ref that looks like the first return value from |
|
&scantron_getfile() |
|
$scan_data - hash ref that looks like the second return value from |
|
&scantron_getfile() |
|
|
|
Returns: |
|
$count - number of scanlines to process |
|
|
|
=cut |
|
|
sub get_todo_count { |
sub get_todo_count { |
my ($scanlines,$scan_data)=@_; |
my ($scanlines,$scan_data)=@_; |
my $count=0; |
my $count=0; |
Line 5246 sub get_todo_count {
|
Line 5848 sub get_todo_count {
|
return $count; |
return $count; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_put_line |
|
|
|
Updates the 'corrected' or 'skipped' versions of the bubble sheet |
|
data file. |
|
|
|
Arguments: |
|
$scanlines - hash ref that looks like the first return value from |
|
&scantron_getfile() |
|
$scan_data - hash ref that looks like the second return value from |
|
&scantron_getfile() |
|
$i - line number to update |
|
$newline - contents of the updated scanline |
|
$skip - if true make the line for skipping and update the |
|
'skipped' file |
|
|
|
=cut |
|
|
sub scantron_put_line { |
sub scantron_put_line { |
my ($scanlines,$scan_data,$i,$newline,$skip)=@_; |
my ($scanlines,$scan_data,$i,$newline,$skip)=@_; |
if ($skip) { |
if ($skip) { |
Line 5256 sub scantron_put_line {
|
Line 5877 sub scantron_put_line {
|
$scanlines->{'corrected'}[$i]=$newline; |
$scanlines->{'corrected'}[$i]=$newline; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_clear_skip |
|
|
|
Remove a line from the 'skipped' file |
|
|
|
Arguments: |
|
$scanlines - hash ref that looks like the first return value from |
|
&scantron_getfile() |
|
$scan_data - hash ref that looks like the second return value from |
|
&scantron_getfile() |
|
$i - line number to update |
|
|
|
=cut |
|
|
sub scantron_clear_skip { |
sub scantron_clear_skip { |
my ($scanlines,$scan_data,$i)=@_; |
my ($scanlines,$scan_data,$i)=@_; |
if (exists($scanlines->{'skipped'}[$i])) { |
if (exists($scanlines->{'skipped'}[$i])) { |
Line 5265 sub scantron_clear_skip {
|
Line 5901 sub scantron_clear_skip {
|
return 0; |
return 0; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_filter_not_exam |
|
|
|
Filter routine used by &Apache::lonnavmaps::retrieveResources(), to |
|
filter out resources that are not marked as 'exam' mode |
|
|
|
=cut |
|
|
sub scantron_filter_not_exam { |
sub scantron_filter_not_exam { |
my ($curres)=@_; |
my ($curres)=@_; |
|
|
Line 5281 sub scantron_filter_not_exam {
|
Line 5926 sub scantron_filter_not_exam {
|
return 0; |
return 0; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_sequence |
|
|
|
Validates the selected sequence, checking for resource that are |
|
not set to exam mode. |
|
|
|
=cut |
|
|
sub scantron_validate_sequence { |
sub scantron_validate_sequence { |
my ($r,$currentphase) = @_; |
my ($r,$currentphase) = @_; |
|
|
Line 5304 sub scantron_validate_sequence {
|
Line 5958 sub scantron_validate_sequence {
|
return (0,$currentphase+1); |
return (0,$currentphase+1); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_ID |
|
|
|
Validates all scanlines in the selected file to not have any |
|
invalid or underspecified student IDs |
|
|
|
=cut |
|
|
sub scantron_validate_ID { |
sub scantron_validate_ID { |
my ($r,$currentphase) = @_; |
my ($r,$currentphase) = @_; |
|
|
Line 5366 sub scantron_validate_ID {
|
Line 6029 sub scantron_validate_ID {
|
return (0,$currentphase+1); |
return (0,$currentphase+1); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_get_correction |
|
|
|
Builds the interface screen to interact with the operator to fix a |
|
specific error condition in a specific scanline |
|
|
|
Arguments: |
|
$r - Apache request object |
|
$i - number of the current scanline |
|
$scan_record - hash ref as returned from &scantron_parse_scanline() |
|
$scan_config - hash ref as returned from &get_scantron_config() |
|
$line - full contents of the current scanline |
|
$error - error condition, valid values are |
|
'incorrectCODE', 'duplicateCODE', |
|
'doublebubble', 'missingbubble', |
|
'duplicateID', 'incorrectID' |
|
$arg - extra information needed |
|
For errors: |
|
- duplicateID - paper number that this studentID was seen before on |
|
- duplicateCODE - array ref of the paper numbers this CODE was |
|
seen on before |
|
- incorrectCODE - current incorrect CODE |
|
- doublebubble - array ref of the bubble lines that have double |
|
bubble errors |
|
- missingbubble - array ref of the bubble lines that have missing |
|
bubble errors |
|
|
|
=cut |
|
|
sub scantron_get_correction { |
sub scantron_get_correction { |
my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_; |
my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_; |
|
|
Line 5469 ENDSCRIPT
|
Line 6162 ENDSCRIPT
|
$r->print("<p>Please indicate which bubble should be used for grading</p>"); |
$r->print("<p>Please indicate which bubble should be used for grading</p>"); |
foreach my $question (@{$arg}) { |
foreach my $question (@{$arg}) { |
my $selected=$$scan_record{"scantron.$question.answer"}; |
my $selected=$$scan_record{"scantron.$question.answer"}; |
&scantron_bubble_selector($r,$scan_config,$question,split('',$selected)); |
&scantron_bubble_selector($r,$scan_config,$question, |
|
split('',$selected)); |
} |
} |
} elsif ($error eq 'missingbubble') { |
} elsif ($error eq 'missingbubble') { |
$r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n"); |
$r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n"); |
Line 5489 ENDSCRIPT
|
Line 6183 ENDSCRIPT
|
|
|
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_bubble_selector |
|
|
|
Generates the html radiobuttons to correct a single bubble line |
|
possibly showing the existing the selected bubbles if known |
|
|
|
Arguments: |
|
$r - Apache request object |
|
$scan_config - hash from &get_scantron_config() |
|
$quest - number of the bubble line to make a corrector for |
|
$selected - array of letters of previously selected bubbles |
|
$lines - if present, number of bubble lines to show |
|
|
|
=cut |
|
|
sub scantron_bubble_selector { |
sub scantron_bubble_selector { |
my ($r,$scan_config,$quest,@selected)=@_; |
my ($r,$scan_config,$quest,@selected, $lines)=@_; |
my $max=$$scan_config{'Qlength'}; |
my $max=$$scan_config{'Qlength'}; |
|
|
my $scmode=$$scan_config{'Qon'}; |
my $scmode=$$scan_config{'Qon'}; |
if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; } |
if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; } |
|
|
my @alphabet=('A'..'Z'); |
|
$r->print("<table border='1'><tr><td rowspan='2'>$quest</td>"); |
if (!defined($lines)) { |
for (my $i=0;$i<$max+1;$i++) { |
$lines = 1; |
$r->print("\n".'<td align="center">'); |
|
if ($selected[0] eq $alphabet[$i]) { $r->print('X'); shift(@selected) } |
|
else { $r->print(' '); } |
|
$r->print('</td>'); |
|
} |
|
$r->print('</tr><tr>'); |
|
for (my $i=0;$i<$max;$i++) { |
|
$r->print("\n". |
|
'<td><label><input type="radio" name="scantron_correct_Q_'. |
|
$quest.'" value="'.$i.'" />'.$alphabet[$i]."</label></td>"); |
|
} |
} |
$r->print('<td><label><input type="radio" name="scantron_correct_Q_'. |
my $total_lines = $lines*2; |
|
my @alphabet=('A'..'Z'); |
|
$r->print("<table border='1'><tr><td rowspan='".$total_lines."'>$quest</td>"); |
|
|
|
for (my $l = 0; $l < $lines; $l++) { |
|
if ($l != 0) { |
|
$r->print('<tr>'); |
|
} |
|
|
|
# FIXME: This loop probably has to be considerably more clever for |
|
# multiline bubbles: User can multibubble by having bubbles in |
|
# several lines. User can skip lines legitimately etc. etc. |
|
|
|
for (my $i=0;$i<$max;$i++) { |
|
$r->print("\n".'<td align="center">'); |
|
if ($selected[0] eq $alphabet[$i]) { |
|
$r->print('X'); |
|
shift(@selected) ; |
|
} else { |
|
$r->print(' '); |
|
} |
|
$r->print('</td>'); |
|
|
|
} |
|
|
|
if ($l == 0) { |
|
my $lspan = $total_lines * 2; # 2 table rows per bubble line. |
|
|
|
$r->print('<td rowspan='.$lspan.'><label><input type="radio" name="scantron_correct_Q_'. |
$quest.'" value="none" /> No bubble </label></td>'); |
$quest.'" value="none" /> No bubble </label></td>'); |
$r->print('</tr></table>'); |
|
|
} |
|
|
|
$r->print('</tr><tr>'); |
|
|
|
# FIXME: This may have to be a bit more clever for |
|
# multiline questions (different values e.g..). |
|
|
|
for (my $i=0;$i<$max;$i++) { |
|
$r->print("\n". |
|
'<td><label><input type="radio" name="scantron_correct_Q_'. |
|
$quest.'" value="'.$i.'" />'.$alphabet[$i]."</label></td>"); |
|
} |
|
$r->print('</tr>'); |
|
|
|
|
|
} |
|
$r->print('</table>'); |
} |
} |
|
|
|
=pod |
|
|
|
=item num_matches |
|
|
|
Counts the number of characters that are the same between the two arguments. |
|
|
|
Arguments: |
|
$orig - CODE from the scanline |
|
$code - CODE to match against |
|
|
|
Returns: |
|
$count - integer count of the number of same characters between the |
|
two arguments |
|
|
|
=cut |
|
|
sub num_matches { |
sub num_matches { |
my ($orig,$code) = @_; |
my ($orig,$code) = @_; |
my @code=split(//,$code); |
my @code=split(//,$code); |
Line 5526 sub num_matches {
|
Line 6287 sub num_matches {
|
return $same; |
return $same; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_get_closely_matching_CODEs |
|
|
|
Cycles through all CODEs and finds the set that has the greatest |
|
number of same characters as the provided CODE |
|
|
|
Arguments: |
|
$allcodes - hash ref returned by &get_codes() |
|
$CODE - CODE from the current scanline |
|
|
|
Returns: |
|
2 element list |
|
- first elements is number of how closely matching the best fit is |
|
(5 means best set has 5 matching characters) |
|
- second element is an arrary ref containing the set of valid CODEs |
|
that best fit the passed in CODE |
|
|
|
=cut |
|
|
sub scantron_get_closely_matching_CODEs { |
sub scantron_get_closely_matching_CODEs { |
my ($allcodes,$CODE)=@_; |
my ($allcodes,$CODE)=@_; |
my @CODEs; |
my @CODEs; |
Line 5536 sub scantron_get_closely_matching_CODEs
|
Line 6317 sub scantron_get_closely_matching_CODEs
|
return ($#CODEs,$CODEs[-1]); |
return ($#CODEs,$CODEs[-1]); |
} |
} |
|
|
|
=pod |
|
|
|
=item get_codes |
|
|
|
Builds a hash which has keys of all of the valid CODEs from the selected |
|
set of remembered CODEs. |
|
|
|
Arguments: |
|
$old_name - name of the set of remembered CODEs |
|
$cdom - domain of the course |
|
$cnum - internal course name |
|
|
|
Returns: |
|
%allcodes - keys are the valid CODEs, values are all 1 |
|
|
|
=cut |
|
|
sub get_codes { |
sub get_codes { |
my ($old_name, $cdom, $cnum) = @_; |
my ($old_name, $cdom, $cnum) = @_; |
if (!$old_name) { |
if (!$old_name) { |
Line 5558 sub get_codes {
|
Line 6356 sub get_codes {
|
return %allcodes; |
return %allcodes; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_CODE |
|
|
|
Validates all scanlines in the selected file to not have any |
|
invalid or underspecified CODEs and that none of the codes are |
|
duplicated if this was requested. |
|
|
|
=cut |
|
|
sub scantron_validate_CODE { |
sub scantron_validate_CODE { |
my ($r,$currentphase) = @_; |
my ($r,$currentphase) = @_; |
my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); |
my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); |
Line 5609 sub scantron_validate_CODE {
|
Line 6417 sub scantron_validate_CODE {
|
return (0,$currentphase+1); |
return (0,$currentphase+1); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_doublebubble |
|
|
|
Validates all scanlines in the selected file to not have any |
|
bubble lines with multiple bubbles marked. |
|
|
|
=cut |
|
|
sub scantron_validate_doublebubble { |
sub scantron_validate_doublebubble { |
my ($r,$currentphase) = @_; |
my ($r,$currentphase) = @_; |
#get student info |
#get student info |
Line 5632 sub scantron_validate_doublebubble {
|
Line 6449 sub scantron_validate_doublebubble {
|
return (0,$currentphase+1); |
return (0,$currentphase+1); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_get_maxbubble |
|
|
|
Returns the maximum number of bubble lines that are expected to |
|
occur. Does this by walking the selected sequence rendering the |
|
resource and then checking &Apache::lonxml::get_problem_counter() |
|
for what the current value of the problem counter is. |
|
|
|
Caches the result to $env{'form.scantron_maxbubble'} |
|
|
|
=cut |
|
|
sub scantron_get_maxbubble { |
sub scantron_get_maxbubble { |
if (defined($env{'form.scantron_maxbubble'}) && |
if (defined($env{'form.scantron_maxbubble'}) && |
$env{'form.scantron_maxbubble'}) { |
$env{'form.scantron_maxbubble'}) { |
Line 5658 sub scantron_get_maxbubble {
|
Line 6488 sub scantron_get_maxbubble {
|
return $env{'form.scantron_maxbubble'}; |
return $env{'form.scantron_maxbubble'}; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_validate_missingbubbles |
|
|
|
Validates all scanlines in the selected file to not have any |
|
bubble lines with missing bubbles that haven't been verified as missing. |
|
|
|
=cut |
|
|
sub scantron_validate_missingbubbles { |
sub scantron_validate_missingbubbles { |
my ($r,$currentphase) = @_; |
my ($r,$currentphase) = @_; |
#get student info |
#get student info |
Line 5690 sub scantron_validate_missingbubbles {
|
Line 6529 sub scantron_validate_missingbubbles {
|
return (0,$currentphase+1); |
return (0,$currentphase+1); |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_process_students |
|
|
|
Routine that does the actual grading of the bubble sheet information. |
|
|
|
The parsed scanline hash is added to %env |
|
|
|
Then foreach unskipped scanline it does an &Apache::lonnet::ssi() |
|
foreach resource , with the form data of |
|
|
|
'submitted' =>'scantron' |
|
'grade_target' =>'grade', |
|
'grade_username'=> username of student |
|
'grade_domain' => domain of student |
|
'grade_courseid'=> of course |
|
'grade_symb' => symb of resource to grade |
|
|
|
This triggers a grading pass. The problem grading code takes care |
|
of converting the bubbled letter information (now in %env) into a |
|
valid submission. |
|
|
|
=cut |
|
|
sub scantron_process_students { |
sub scantron_process_students { |
my ($r) = @_; |
my ($r) = @_; |
my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'}); |
my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'}); |
Line 5794 SCANTRONFORM
|
Line 6657 SCANTRONFORM
|
return ''; |
return ''; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_upload_scantron_data |
|
|
|
Creates the screen for adding a new bubble sheet data file to a course. |
|
|
|
=cut |
|
|
sub scantron_upload_scantron_data { |
sub scantron_upload_scantron_data { |
my ($r)=@_; |
my ($r)=@_; |
$r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'})); |
$r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'})); |
Line 5830 UPLOAD
|
Line 6701 UPLOAD
|
return ''; |
return ''; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_upload_scantron_data_save |
|
|
|
Adds a provided bubble information data file to the course if user |
|
has the correct privileges to do so. |
|
|
|
=cut |
|
|
sub scantron_upload_scantron_data_save { |
sub scantron_upload_scantron_data_save { |
my($r)=@_; |
my($r)=@_; |
my ($symb)=&get_symb($r,1); |
my ($symb)=&get_symb($r,1); |
Line 5885 sub scantron_upload_scantron_data_save {
|
Line 6765 sub scantron_upload_scantron_data_save {
|
return ''; |
return ''; |
} |
} |
|
|
|
=pod |
|
|
|
=item valid_file |
|
|
|
Validates that the requested bubble data file exists in the course. |
|
|
|
=cut |
|
|
sub valid_file { |
sub valid_file { |
my ($requested_file)=@_; |
my ($requested_file)=@_; |
foreach my $filename (sort(&scantron_filenames())) { |
foreach my $filename (sort(&scantron_filenames())) { |
Line 5893 sub valid_file {
|
Line 6781 sub valid_file {
|
return 0; |
return 0; |
} |
} |
|
|
|
=pod |
|
|
|
=item scantron_download_scantron_data |
|
|
|
Shows a list of the three internal files (original, corrected, |
|
skipped) for a specific bubble sheet data file that exists in the |
|
course. |
|
|
|
=cut |
|
|
sub scantron_download_scantron_data { |
sub scantron_download_scantron_data { |
my ($r)=@_; |
my ($r)=@_; |
my $default_form_data=&defaultFormData(&get_symb($r,1)); |
my $default_form_data=&defaultFormData(&get_symb($r,1)); |
Line 5929 DOWNLOAD
|
Line 6827 DOWNLOAD
|
return ''; |
return ''; |
} |
} |
|
|
|
=pod |
|
|
|
=back |
|
|
|
=cut |
|
|
#-------- end of section for handling grading scantron forms ------- |
#-------- end of section for handling grading scantron forms ------- |
# |
# |
#------------------------------------------------------------------- |
#------------------------------------------------------------------- |
Line 5939 DOWNLOAD
|
Line 6843 DOWNLOAD
|
sub show_grading_menu_form { |
sub show_grading_menu_form { |
my ($symb)=@_; |
my ($symb)=@_; |
my $result.='<br /><form action="/adm/grades" method="post">'."\n". |
my $result.='<br /><form action="/adm/grades" method="post">'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n". |
'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n". |
'<input type="hidden" name="command" value="gradingmenu" />'."\n". |
'<input type="hidden" name="command" value="gradingmenu" />'."\n". |
'<input type="submit" name="submit" value="Grading Menu" />'."\n". |
'<input type="submit" name="submit" value="Grading Menu" />'."\n". |
Line 6014 GRADINGMENUJS
|
Line 6918 GRADINGMENUJS
|
my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'}); |
my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'}); |
|
|
$result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n". |
$result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n". |
'<input type="hidden" name="symb" value="'.$symb.'" />'."\n". |
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n". |
'<input type="hidden" name="handgrade" value="'.$hdgrade.'" />'."\n". |
'<input type="hidden" name="handgrade" value="'.$hdgrade.'" />'."\n". |
'<input type="hidden" name="probTitle" value="'.$probTitle.'" />'."\n". |
'<input type="hidden" name="probTitle" value="'.$probTitle.'" />'."\n". |
'<input type="hidden" name="command" value="" />'."\n". |
'<input type="hidden" name="command" value="" />'."\n". |
Line 6029 GRADINGMENUJS
|
Line 6933 GRADINGMENUJS
|
|
|
$result.='<table width="100%" border="0">'; |
$result.='<table width="100%" border="0">'; |
$result.='<tr bgcolor="#ffffe6" valign="top"><td>'."\n". |
$result.='<tr bgcolor="#ffffe6" valign="top"><td>'."\n". |
' '.&mt('Select Section').': <select name="section">'."\n"; |
' '.&mt('Select Section').': <select name="section" multiple="multiple" size="3">'."\n"; |
if (ref($sections)) { |
if (ref($sections)) { |
foreach (sort (@$sections)) { |
foreach (sort (@$sections)) { |
$result.='<option value="'.$_.'" '. |
$result.='<option value="'.$_.'" '. |
Line 6130 sub init_perm {
|
Line 7034 sub init_perm {
|
} |
} |
|
|
sub gather_clicker_ids { |
sub gather_clicker_ids { |
my %clickerids=(); |
my %clicker_ids; |
|
|
my $classlist = &Apache::loncoursedata::get_classlist(); |
my $classlist = &Apache::loncoursedata::get_classlist(); |
|
|
# Set up a couple variables. |
# Set up a couple variables. |
my $usernameidx = &Apache::loncoursedata::CL_SNAME(); |
my $username_idx = &Apache::loncoursedata::CL_SNAME(); |
my $domainidx = &Apache::loncoursedata::CL_SDOM(); |
my $domain_idx = &Apache::loncoursedata::CL_SDOM(); |
|
|
foreach my $student (keys %$classlist) { |
foreach my $student (keys(%$classlist)) { |
|
|
my $username = $classlist->{$student}->[$usernameidx]; |
my $username = $classlist->{$student}->[$username_idx]; |
my $domain = $classlist->{$student}->[$domainidx]; |
my $domain = $classlist->{$student}->[$domain_idx]; |
my $clickers = |
my $clickers = |
(&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1]; |
(&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1]; |
foreach my $id (split(/\,/,$clickers)) { |
foreach my $id (split(/\,/,$clickers)) { |
if (exists($clickerids{$id})) { |
$id=~s/^[\#0]+//; |
$clickerids{$id}.=','.$username.':'.$domain; |
$id=~s/[\-\:]//g; |
|
if (exists($clicker_ids{$id})) { |
|
$clicker_ids{$id}.=','.$username.':'.$domain; |
} else { |
} else { |
$clickerids{$id}=$username.':'.$domain; |
$clicker_ids{$id}=$username.':'.$domain; |
} |
} |
} |
} |
} |
} |
return %clickerids; |
return %clicker_ids; |
} |
} |
|
|
sub gather_adv_clicker_ids { |
sub gather_adv_clicker_ids { |
my %clickerids=(); |
my %clicker_ids; |
my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; |
my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum); |
my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum); |
foreach my $element (sort keys %coursepersonnel) { |
foreach my $element (sort(keys(%coursepersonnel))) { |
foreach my $person (split(/\,/,$coursepersonnel{$element})) { |
foreach my $person (split(/\,/,$coursepersonnel{$element})) { |
my ($puname,$pudom)=split(/\:/,$person); |
my ($puname,$pudom)=split(/\:/,$person); |
my $clickers = |
my $clickers = |
(&Apache::lonnet::userenvironment($pudom,$puname,'clickers'))[1]; |
(&Apache::lonnet::userenvironment($pudom,$puname,'clickers'))[1]; |
foreach my $id (split(/\,/,$clickers)) { |
foreach my $id (split(/\,/,$clickers)) { |
if (exists($clickerids{$id})) { |
$id=~s/^[\#0]+//; |
$clickerids{$id}.=','.$puname.':'.$pudom; |
$id=~s/[\-\:]//g; |
} else { |
if (exists($clicker_ids{$id})) { |
$clickerids{$id}=$puname.':'.$pudom; |
$clicker_ids{$id}.=','.$puname.':'.$pudom; |
} |
} else { |
} |
$clicker_ids{$id}=$puname.':'.$pudom; |
|
} |
|
} |
} |
} |
} |
} |
return %clickerids; |
return %clicker_ids; |
|
} |
|
|
|
sub clicker_grading_parameters { |
|
return ('gradingmechanism' => 'scalar', |
|
'upfiletype' => 'scalar', |
|
'specificid' => 'scalar', |
|
'pcorrect' => 'scalar', |
|
'pincorrect' => 'scalar'); |
} |
} |
|
|
sub process_clicker { |
sub process_clicker { |
Line 6190 sub process_clicker {
|
Line 7106 sub process_clicker {
|
$result.=' <b>'.&mt('Specify a file containing the clicker information for this resource'). |
$result.=' <b>'.&mt('Specify a file containing the clicker information for this resource'). |
'.</b></td></tr>'."\n"; |
'.</b></td></tr>'."\n"; |
$result.='<tr bgcolor=#ffffe6><td>'."\n"; |
$result.='<tr bgcolor=#ffffe6><td>'."\n"; |
|
# Attempt to restore parameters from last session, set defaults if not present |
|
my %Saveable_Parameters=&clicker_grading_parameters(); |
|
&Apache::loncommon::restore_course_settings('grades_clicker', |
|
\%Saveable_Parameters); |
|
if (!$env{'form.pcorrect'}) { $env{'form.pcorrect'}=100; } |
|
if (!$env{'form.pincorrect'}) { $env{'form.pincorrect'}=100; } |
|
if (!$env{'form.gradingmechanism'}) { $env{'form.gradingmechanism'}='attendance'; } |
|
if (!$env{'form.upfiletype'}) { $env{'form.upfiletype'}='iclicker'; } |
|
|
|
my %checked; |
|
foreach my $gradingmechanism ('attendance','personnel','specific') { |
|
if ($env{'form.gradingmechanism'} eq $gradingmechanism) { |
|
$checked{$gradingmechanism}="checked='checked'"; |
|
} |
|
} |
|
|
my $upload=&mt("Upload File"); |
my $upload=&mt("Upload File"); |
my $type=&mt("Type"); |
my $type=&mt("Type"); |
my $attendance=&mt("Award points just for participation"); |
my $attendance=&mt("Award points just for participation"); |
my $personnel=&mt("Correctness determined from response by course personnel"); |
my $personnel=&mt("Correctness determined from response by course personnel"); |
my $specific=&mt("Correctness determined from response with clicker ID"); |
my $specific=&mt("Correctness determined from response with clicker ID(s)"); |
my $pcorrect=&mt("Percentage points for correct solution"); |
my $pcorrect=&mt("Percentage points for correct solution"); |
my $pincorrect=&mt("Percentage points for incorrect solution"); |
my $pincorrect=&mt("Percentage points for incorrect solution"); |
my $selectform=&Apache::loncommon::select_form('iclicker','upfiletype', |
my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype', |
('iclicker' => 'iClicker')); |
('iclicker' => 'i>clicker', |
|
'interwrite' => 'interwrite PRS')); |
|
$symb = &Apache::lonenc::check_encrypt($symb); |
$result.=<<ENDUPFORM; |
$result.=<<ENDUPFORM; |
<script type="text/javascript"> |
<script type="text/javascript"> |
function sanitycheck() { |
function sanitycheck() { |
Line 6247 function sanitycheck() {
|
Line 7180 function sanitycheck() {
|
<input type="hidden" name="saveState" value="$env{'form.saveState'}" /> |
<input type="hidden" name="saveState" value="$env{'form.saveState'}" /> |
<input type="file" name="upfile" size="50" /> |
<input type="file" name="upfile" size="50" /> |
<br /><label>$type: $selectform</label> |
<br /><label>$type: $selectform</label> |
<br /><label>$attendance: <input type="radio" name="gradingmechanism" value="attendance" checked="checked" onClick="sanitycheck()" /></label> |
<br /><label>$attendance: <input type="radio" name="gradingmechanism" value="attendance" $checked{'attendance'} onClick="sanitycheck()" /></label> |
<br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" onClick="sanitycheck()" /></label> |
<br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" $checked{'personnel'} onClick="sanitycheck()" /></label> |
<br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" onClick="sanitycheck()" /></label> |
<br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" $checked{'specific'} onClick="sanitycheck()" /></label> |
<input type="text" name="specificid" size="15" /> |
<input type="text" name="specificid" value="$env{'form.specificid'}" size="20" /> |
<input type="hidden" name="waschecked" value="attendance" /> |
<input type="hidden" name="waschecked" value="$env{'form.gradingmechanism'}" /> |
<br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="100" onChange="sanitycheck()" /></label> |
<br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="$env{'form.pcorrect'}" onChange="sanitycheck()" /></label> |
<br /><label>$pincorrect: <input type="text" name="pincorrect" size="4" value="100" onChange="sanitycheck()" /></label> |
<br /><label>$pincorrect: <input type="text" name="pincorrect" size="4" value="$env{'form.pincorrect'}" onChange="sanitycheck()" /></label> |
<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="$upload" /> |
<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="$upload" /> |
</form> |
</form> |
ENDUPFORM |
ENDUPFORM |
Line 6267 sub process_clicker_file {
|
Line 7200 sub process_clicker_file {
|
my ($r)=@_; |
my ($r)=@_; |
my ($symb)=&get_symb($r); |
my ($symb)=&get_symb($r); |
if (!$symb) {return '';} |
if (!$symb) {return '';} |
|
|
|
my %Saveable_Parameters=&clicker_grading_parameters(); |
|
&Apache::loncommon::store_course_settings('grades_clicker', |
|
\%Saveable_Parameters); |
|
|
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); |
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); |
if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) { |
if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) { |
$result.='<span class="LC_error">'.&mt('You need to specify a clicker ID for the correct answer').'</span>'; |
$result.='<span class="LC_error">'.&mt('You need to specify a clicker ID for the correct answer').'</span>'; |
return $result.&show_grading_menu_form($symb); |
return $result.&show_grading_menu_form($symb); |
} |
} |
my %clickerids=&gather_clicker_ids(); |
my %clicker_ids=&gather_clicker_ids(); |
my %correctids=(); |
my %correct_ids; |
if ($env{'form.gradingmechanism'} eq 'personnel') { |
if ($env{'form.gradingmechanism'} eq 'personnel') { |
%correctids=&gather_adv_clicker_ids(); |
%correct_ids=&gather_adv_clicker_ids(); |
} |
} |
if ($env{'form.gradingmechanism'} eq 'specific') { |
if ($env{'form.gradingmechanism'} eq 'specific') { |
my $correctid=$env{'form.specificid'}; |
foreach my $correct_id (split(/[\s\,]/,$env{'form.specificid'})) {; |
$correctid=~tr/a-z/A-Z/; |
$correct_id=~tr/a-z/A-Z/; |
$correctid=~s/\s//gs; |
$correct_id=~s/\s//gs; |
$correctids{$correctid}='specified'; |
$correct_id=~s/^[\#0]+//; |
|
$correct_id=~s/[\-\:]//g; |
|
if ($correct_id) { |
|
$correct_ids{$correct_id}='specified'; |
|
} |
|
} |
} |
} |
if ($env{'form.gradingmechanism'} eq 'attendance') { |
if ($env{'form.gradingmechanism'} eq 'attendance') { |
$result.=&mt('Score based on attendance only'); |
$result.=&mt('Score based on attendance only'); |
} else { |
} else { |
my $number=0; |
my $number=0; |
$result.='<h3>'.&mt('Correctness determined by the following IDs').'</h3>'; |
$result.='<p><b>'.&mt('Correctness determined by the following IDs').'</b>'; |
foreach my $id (sort(keys(%correctids))) { |
foreach my $id (sort(keys(%correct_ids))) { |
$result.='<tt>'.$id.'</tt> - '; |
$result.='<br /><tt>'.$id.'</tt> - '; |
if ($correctids{$id} eq 'specified') { |
if ($correct_ids{$id} eq 'specified') { |
$result.=&mt('specified'); |
$result.=&mt('specified'); |
} else { |
} else { |
my ($uname,$udom)=split(/\:/,$correctids{$id}); |
my ($uname,$udom)=split(/\:/,$correct_ids{$id}); |
$result.=&Apache::loncommon::plainname($uname,$udom); |
$result.=&Apache::loncommon::plainname($uname,$udom); |
|
} |
|
$number++; |
|
} |
|
$result.="</p>\n"; |
|
if ($number==0) { |
|
$result.='<span class="LC_error">'.&mt('No IDs found to determine correct answer').'</span>'; |
|
return $result.&show_grading_menu_form($symb); |
|
} |
|
} |
|
if (length($env{'form.upfile'}) < 2) { |
|
$result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.', |
|
'<span class="LC_error">', |
|
'</span>', |
|
'<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>'); |
|
return $result.&show_grading_menu_form($symb); |
|
} |
|
|
|
# Were able to get all the info needed, now analyze the file |
|
|
|
$result.=&Apache::loncommon::studentbrowser_javascript(); |
|
$symb = &Apache::lonenc::check_encrypt($symb); |
|
my $heading=&mt('Scanning clicker file'); |
|
$result.=(<<ENDHEADER); |
|
<br /><table width="100%" border="0"><tr><td bgcolor="#777777"> |
|
<table width="100%" border="0"><tr bgcolor="#e6ffff"><td> |
|
<b>$heading</b></td></tr><tr bgcolor=#ffffe6><td> |
|
<form method="post" action="/adm/grades" name="clickeranalysis"> |
|
<input type="hidden" name="symb" value="$symb" /> |
|
<input type="hidden" name="command" value="assignclickergrades" /> |
|
<input type="hidden" name="probTitle" value="$env{'form.probTitle'}" /> |
|
<input type="hidden" name="saveState" value="$env{'form.saveState'}" /> |
|
<input type="hidden" name="gradingmechanism" value="$env{'form.gradingmechanism'}" /> |
|
<input type="hidden" name="pcorrect" value="$env{'form.pcorrect'}" /> |
|
<input type="hidden" name="pincorrect" value="$env{'form.pincorrect'}" /> |
|
ENDHEADER |
|
my %responses; |
|
my @questiontitles; |
|
my $errormsg=''; |
|
my $number=0; |
|
if ($env{'form.upfiletype'} eq 'iclicker') { |
|
($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses); |
|
} |
|
if ($env{'form.upfiletype'} eq 'interwrite') { |
|
($errormsg,$number)=&interwrite_eval(\@questiontitles,\%responses); |
|
} |
|
$result.='<br />'.&mt('Found [_1] question(s)',$number).'<br />'. |
|
'<input type="hidden" name="number" value="'.$number.'" />'. |
|
&mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses', |
|
$env{'form.pcorrect'},$env{'form.pincorrect'}). |
|
'<br />'; |
|
# Remember Question Titles |
|
# FIXME: Possibly need delimiter other than ":" |
|
for (my $i=0;$i<$number;$i++) { |
|
$result.='<input type="hidden" name="question:'.$i.'" value="'. |
|
&HTML::Entities::encode($questiontitles[$i],'"&<>').'" />'; |
|
} |
|
my $correct_count=0; |
|
my $student_count=0; |
|
my $unknown_count=0; |
|
# Match answers with usernames |
|
# FIXME: Possibly need delimiter other than ":" |
|
foreach my $id (keys(%responses)) { |
|
if ($correct_ids{$id}) { |
|
$result.="\n".'<input type="hidden" name="correct:'.$correct_count.':'.$correct_ids{$id}.'" value="'.$responses{$id}.'" />'; |
|
$correct_count++; |
|
} elsif ($clicker_ids{$id}) { |
|
$result.="\n".'<input type="hidden" name="student:'.$clicker_ids{$id}.'" value="'.$responses{$id}.'" />'; |
|
$student_count++; |
|
} else { |
|
$result.="\n<hr />".&mt('Unregistered Clicker')." <tt>".$id."</tt><br />"; |
|
$result.="\n".'<input type="hidden" name="unknown:'.$id.'" value="'.$responses{$id}.'" />'. |
|
"\n".&mt("Username").": <input type='text' name='uname".$id."' /> ". |
|
"\n".&mt("Domain").": ". |
|
&Apache::loncommon::select_dom_form($env{'course.'.$env{'request.course.id'}.'.domain'},'udom'.$id).' '. |
|
&Apache::loncommon::selectstudent_link('clickeranalysis','uname'.$id,'udom'.$id); |
|
$unknown_count++; |
|
} |
|
} |
|
$result.='<hr />'. |
|
&mt('Found [_1] registered and [_2] unregistered clickers.',$student_count,$unknown_count); |
|
if ($env{'form.gradingmechanism'} ne 'attendance') { |
|
if ($correct_count==0) { |
|
$errormsg.="Found no correct answers answers for grading!"; |
|
} elsif ($correct_count>1) { |
|
$result.='<br /><span class="LC_warning">'.&mt("Found [_1] entries for grading!",$correct_count).'</span>'; |
|
} |
|
} |
|
if ($number<1) { |
|
$errormsg.="Found no questions."; |
|
} |
|
if ($errormsg) { |
|
$result.='<br /><span class="LC_error">'.&mt($errormsg).'</span>'; |
|
} else { |
|
$result.='<br /><input type="submit" name="finalize" value="'.&mt('Finalize Grading').'" />'; |
|
} |
|
$result.='</form></td></tr></table>'."\n". |
|
'</td></tr></table><br /><br />'."\n"; |
|
return $result.&show_grading_menu_form($symb); |
|
} |
|
|
|
sub iclicker_eval { |
|
my ($questiontitles,$responses)=@_; |
|
my $number=0; |
|
my $errormsg=''; |
|
foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) { |
|
my %components=&Apache::loncommon::record_sep($line); |
|
my @entries=map {$components{$_}} (sort(keys(%components))); |
|
if ($entries[0] eq 'Question') { |
|
for (my $i=3;$i<$#entries;$i+=6) { |
|
$$questiontitles[$number]=$entries[$i]; |
|
$number++; |
|
} |
|
} |
|
if ($entries[0]=~/^\#/) { |
|
my $id=$entries[0]; |
|
my @idresponses; |
|
$id=~s/^[\#0]+//; |
|
for (my $i=0;$i<$number;$i++) { |
|
my $idx=3+$i*6; |
|
push(@idresponses,$entries[$idx]); |
|
} |
|
$$responses{$id}=join(',',@idresponses); |
|
} |
|
} |
|
return ($errormsg,$number); |
|
} |
|
|
|
sub interwrite_eval { |
|
my ($questiontitles,$responses)=@_; |
|
my $number=0; |
|
my $errormsg=''; |
|
my $skipline=1; |
|
my $questionnumber=0; |
|
my %idresponses=(); |
|
foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) { |
|
my %components=&Apache::loncommon::record_sep($line); |
|
my @entries=map {$components{$_}} (sort(keys(%components))); |
|
if ($entries[1] eq 'Time') { $skipline=0; next; } |
|
if ($entries[1] eq 'Response') { $skipline=1; } |
|
next if $skipline; |
|
if ($entries[0]!=$questionnumber) { |
|
$questionnumber=$entries[0]; |
|
$$questiontitles[$number]=&mt('Question [_1]',$questionnumber); |
|
$number++; |
|
} |
|
my $id=$entries[4]; |
|
$id=~s/^[\#0]+//; |
|
$id=~s/^v\d*\://i; |
|
$id=~s/[\-\:]//g; |
|
$idresponses{$id}[$number]=$entries[6]; |
|
} |
|
foreach my $id (keys %idresponses) { |
|
$$responses{$id}=join(',',@{$idresponses{$id}}); |
|
$$responses{$id}=~s/^\s*\,//; |
|
} |
|
return ($errormsg,$number); |
|
} |
|
|
|
sub assign_clicker_grades { |
|
my ($r)=@_; |
|
my ($symb)=&get_symb($r); |
|
if (!$symb) {return '';} |
|
# See which part we are saving to |
|
my ($partlist,$handgrade,$responseType) = &response_type($symb); |
|
# FIXME: This should probably look for the first handgradeable part |
|
my $part=$$partlist[0]; |
|
# Start screen output |
|
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}); |
|
|
|
my $heading=&mt('Assigning grades based on clicker file'); |
|
$result.=(<<ENDHEADER); |
|
<br /><table width="100%" border="0"><tr><td bgcolor="#777777"> |
|
<table width="100%" border="0"><tr bgcolor="#e6ffff"><td> |
|
<b>$heading</b></td></tr><tr bgcolor=#ffffe6><td> |
|
ENDHEADER |
|
# Get correct result |
|
# FIXME: Possibly need delimiter other than ":" |
|
my @correct=(); |
|
my $gradingmechanism=$env{'form.gradingmechanism'}; |
|
my $number=$env{'form.number'}; |
|
if ($gradingmechanism ne 'attendance') { |
|
foreach my $key (keys(%env)) { |
|
if ($key=~/^form\.correct\:/) { |
|
my @input=split(/\,/,$env{$key}); |
|
for (my $i=0;$i<=$#input;$i++) { |
|
if (($correct[$i]) && ($input[$i]) && |
|
($correct[$i] ne $input[$i])) { |
|
$result.='<br /><span class="LC_warning">'. |
|
&mt('More than one correct result given for question "[_1]": [_2] versus [_3].', |
|
$env{'form.question:'.$i},$correct[$i],$input[$i]).'</span>'; |
|
} elsif ($input[$i]) { |
|
$correct[$i]=$input[$i]; |
|
} |
|
} |
} |
} |
$result.='<br />'; |
|
$number++; |
|
} |
} |
if ($number==0) { |
for (my $i=0;$i<$number;$i++) { |
$result.='<span class="LC_error">'.&mt('No IDs found to determine correct answer').'</span>'; |
if (!$correct[$i]) { |
return $result.&show_grading_menu_form($symb); |
$result.='<br /><span class="LC_error">'. |
|
&mt('No correct result given for question "[_1]"!', |
|
$env{'form.question:'.$i}).'</span>'; |
|
} |
} |
} |
|
$result.='<br />'.&mt("Correct answer: [_1]",join(', ',map { ($_?$_:'-') } @correct)); |
} |
} |
|
# Start grading |
|
my $pcorrect=$env{'form.pcorrect'}; |
|
my $pincorrect=$env{'form.pincorrect'}; |
|
my $storecount=0; |
|
foreach my $key (keys(%env)) { |
|
my $user=''; |
|
if ($key=~/^form\.student\:(.*)$/) { |
|
$user=$1; |
|
} |
|
if ($key=~/^form\.unknown\:(.*)$/) { |
|
my $id=$1; |
|
if (($env{'form.uname'.$id}) && ($env{'form.udom'.$id})) { |
|
$user=$env{'form.uname'.$id}.':'.$env{'form.udom'.$id}; |
|
} |
|
} |
|
if ($user) { |
|
my @answer=split(/\,/,$env{$key}); |
|
my $sum=0; |
|
for (my $i=0;$i<$number;$i++) { |
|
if ($answer[$i]) { |
|
if ($gradingmechanism eq 'attendance') { |
|
$sum+=$pcorrect; |
|
} else { |
|
if ($answer[$i] eq $correct[$i]) { |
|
$sum+=$pcorrect; |
|
} else { |
|
$sum+=$pincorrect; |
|
} |
|
} |
|
} |
|
} |
|
my $ave=$sum/(100*$number); |
|
# Store |
|
my ($username,$domain)=split(/\:/,$user); |
|
my %grades=(); |
|
$grades{"resource.$part.solved"}='correct_by_override'; |
|
$grades{"resource.$part.awarded"}=$ave; |
|
$grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}"; |
|
my $returncode=&Apache::lonnet::cstore(\%grades,$symb, |
|
$env{'request.course.id'}, |
|
$domain,$username); |
|
if ($returncode ne 'ok') { |
|
$result.="<br /><span class=\"LC_error\">Failed to save student $username:$domain. Message when trying to save was ($returncode)</span>"; |
|
} else { |
|
$storecount++; |
|
} |
|
} |
|
} |
|
# We are done |
|
$result.='<br />'.&mt('Successfully stored grades for [_1] student(s).',$storecount). |
|
'</td></tr></table>'."\n". |
|
'</td></tr></table><br /><br />'."\n"; |
return $result.&show_grading_menu_form($symb); |
return $result.&show_grading_menu_form($symb); |
} |
} |
|
|
Line 6354 sub handler {
|
Line 7545 sub handler {
|
} |
} |
} else { |
} else { |
&init_perm(); |
&init_perm(); |
|
# &Apache::lonnet::logthis("command is $command"); |
|
# foreach my $key (keys %perm) { |
|
# &Apache::lonnet::logthis("a key is $key"); |
|
# } |
if ($command eq 'submission' && $perm{'vgr'}) { |
if ($command eq 'submission' && $perm{'vgr'}) { |
($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0)); |
($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0)); |
} elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) { |
} elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) { |
Line 6378 sub handler {
|
Line 7573 sub handler {
|
$request->print(&process_clicker($request)); |
$request->print(&process_clicker($request)); |
} elsif ($command eq 'processclickerfile' && $perm{'mgr'}) { |
} elsif ($command eq 'processclickerfile' && $perm{'mgr'}) { |
$request->print(&process_clicker_file($request)); |
$request->print(&process_clicker_file($request)); |
|
} elsif ($command eq 'assignclickergrades' && $perm{'mgr'}) { |
|
$request->print(&assign_clicker_grades($request)); |
} elsif ($command eq 'csvform' && $perm{'mgr'}) { |
} elsif ($command eq 'csvform' && $perm{'mgr'}) { |
$request->print(&upcsvScores_form($request)); |
$request->print(&upcsvScores_form($request)); |
} elsif ($command eq 'csvupload' && $perm{'mgr'}) { |
} elsif ($command eq 'csvupload' && $perm{'mgr'}) { |