--- loncom/homework/grades.pm 2004/04/20 06:11:49 1.186
+++ loncom/homework/grades.pm 2004/11/17 20:07:01 1.227
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.186 2004/04/20 06:11:49 albertel Exp $
+# $Id: grades.pm,v 1.227 2004/11/17 20:07:01 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -25,16 +25,6 @@
#
# http://www.lon-capa.org/
#
-# 2/9,2/13 Guy Albertelli
-# 6/8 Gerd Kortemeyer
-# 7/26 H.K. Ng
-# 8/20 Gerd Kortemeyer
-# Year 2002
-# June-August H.K. Ng
-# Year 2003
-# February, March H.K. Ng
-# July, H. K. Ng
-#
package Apache::grades;
use strict;
@@ -101,25 +91,6 @@ sub get_symb_and_url {
return ($symb,$url);
}
-# --- Retrieve the fullname for a user. Return lastname, first middle ---
-# --- Generation is attached next to the lastname if it exists. ---
-sub get_fullname {
- my ($uname,$udom) = @_;
- my %name=&Apache::lonnet::get('environment', ['lastname','generation',
- 'firstname','middlename'],
- $udom,$uname);
- my $fullname;
- my ($tmp) = keys(%name);
- if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
- $fullname = &Apache::loncoursedata::ProcessFullName
- (@name{qw/lastname generation firstname middlename/});
- } else {
- &Apache::lonnet::logthis('grades.pm: no name data for '.$uname.
- '@'.$udom.':'.$tmp);
- }
- return $fullname;
-}
-
#--- Format fullname, username:domain if different for display
#--- Use anywhere where the student names are listed
sub nameUserString {
@@ -167,6 +138,20 @@ sub response_type {
return \@partlist,\%handgrade,\%responseType;
}
+sub get_display_part {
+ my ($partID,$url,$symb)=@_;
+ if (!defined($symb) || $symb eq '') {
+ $symb=$ENV{'form.symb'};
+ if ($symb eq '') { $symb=&Apache::lonnet::symbread($url) }
+ }
+ my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',$symb);
+ if (defined($display) and $display ne '') {
+ $display.= " (id $partID )";
+ } else {
+ $display=$partID;
+ }
+ return $display;
+}
#--- Show resource title
#--- and parts and response type
sub showResourceInfo {
@@ -194,7 +179,8 @@ sub showResourceInfo {
}
$partsseen{$partID}=1;
}
- $result.='
Part '.$partID.' '.
+ my $display_part=&get_display_part($partID,$url);
+ $result.=' Part: '.$display_part.' '.
$resID.' '.
'Type: '.$responsetype.' ';
# 'Handgrade: '.$handgrade.' ';
@@ -349,27 +335,36 @@ sub getclasslist {
#
my %sections;
my %fullnames;
- foreach (keys(%$classlist)) {
- # the following undefs are for 'domain', and 'username' respectively.
- my (undef,undef,$end,$start,$id,$section,$fullname,$status)=
- @{$classlist->{$_}};
+ foreach my $student (keys(%$classlist)) {
+ my $end =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_END()];
+ my $start =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_START()];
+ my $id =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_ID()];
+ my $section =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];
+ my $fullname =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_FULLNAME()];
+ my $status =
+ $classlist->{$student}->[&Apache::loncoursedata::CL_STATUS()];
# filter students according to status selected
if ($filterlist && $ENV{'form.Status'} ne 'Any') {
if ($ENV{'form.Status'} ne $status) {
- delete ($classlist->{$_});
+ delete ($classlist->{$student});
next;
}
}
- $section = ($section ne '' ? $section : 'no');
+ $section = ($section ne '' ? $section : 'none');
if (&canview($section)) {
if ($getsec eq 'all' || $getsec eq $section) {
$sections{$section}++;
- $fullnames{$_}=$fullname;
+ $fullnames{$student}=$fullname;
} else {
- delete($classlist->{$_});
+ delete($classlist->{$student});
}
} else {
- delete($classlist->{$_});
+ delete($classlist->{$student});
}
}
my %seen = ();
@@ -682,7 +677,9 @@ LISTJAVASCRIPT
''.&nameUserString('header').' ';
if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
foreach (sort(@$partlist)) {
- $gradeTable.=' Part '.(split(/_/))[0].' Status ';
+ my $display_part=&get_display_part((split(/_/))[0],$url,$symb);
+ $gradeTable.=' Part: '.$display_part.
+ ' Status ';
}
}
$loop++;
@@ -975,6 +972,7 @@ sub sub_page_kw_js {
my $request = shift;
my $iconpath = $request->dir_config('lonIconsURL');
&commonJSfunctions($request);
+ my $docopen=&Apache::lonhtmlcommon::javascript_docopen();
$request->print(<
@@ -1084,10 +1082,10 @@ sub sub_page_kw_js {
var ypos = (screen.height-height)/2-30;
ypos = (ypos < 0) ? '0' : ypos;
- pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=600,height='+height);
+ pWin = window.open('', 'MessageCenter', 'resizable=yes,toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=600,height='+height);
pWin.focus();
pDoc = pWin.document;
- pDoc.open('text/html','replace');
+ pDoc.$docopen;
pDoc.write("");
pDoc.write("Message Central ");
@@ -1215,10 +1213,10 @@ sub sub_page_kw_js {
var ypos = (screen.height-330)/2-30;
ypos = (ypos < 0) ? '0' : ypos;
- hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx='+xpos+',screeny='+ypos);
+ hwdWin = window.open('', 'KeywordHighlightCentral', 'resizeable=yes,toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx='+xpos+',screeny='+ypos);
hwdWin.focus();
var hDoc = hwdWin.document;
- hDoc.open('text/html','replace');
+ hDoc.$docopen;
hDoc.write("");
hDoc.write("Highlight Central ");
@@ -1289,8 +1287,9 @@ sub gradeBox {
'' : $$record{'resource.'.$partid.'.awarded'}*$wgt);
my $result=' '."\n";
+ my $display_part=&get_display_part($partid,undef,$symb);
$result.=''.
- 'Part '.$partid.' Points: '."\n";
+ 'Part: '.$display_part.' Points: '."\n";
my $ctr = 0;
$result.=''."\n"; # display radio buttons in a nice table 10 across
@@ -1386,14 +1385,15 @@ sub submission {
my ($uname,$udom) = ($ENV{'form.student'},$ENV{'form.userdom'});
$udom = ($udom eq '' ? $ENV{'user.domain'} : $udom); #has form.userdom changed for a student?
my $usec = &Apache::lonnet::getsection($udom,$uname,$ENV{'request.course.id'});
- $ENV{'form.fullname'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq '';
+ $ENV{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $ENV{'form.fullname'} eq '';
my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
if (!&canview($usec)) {
$request->print('Unable to view requested student.('.
- $uname.$udom.$usec.$ENV{'request.course.id'}.') ');
+ $uname.'@'.$udom.' in section '.$usec.' in course id '.
+ $ENV{'request.course.id'}.')');
$request->print(&show_grading_menu_form($symb,$url));
return;
}
@@ -1622,11 +1622,12 @@ KEYWORDS
my %seenparts;
for my $part (sort keys(%$handgrade)) {
my ($partid,$respid) = split(/_/,$part);
+ my $display_part=&get_display_part($partid,$url,$symb);
if ($ENV{"form.$uname:$udom:$partid:submitted_by"}) {
if (exists($seenparts{$partid})) { next; }
$seenparts{$partid}=1;
- my $submitby='Part '.$partid.
- ' Collaborative submission by: '.
+ my $submitby='Part: '.$display_part.
+ ' Collaborative submission by: '.
''.
@@ -1636,8 +1637,8 @@ KEYWORDS
}
my $responsetype = $responseType->{$partid}->{$respid};
if (!exists($record{"resource.$partid.$respid.submission"})) {
- $lastsubonly.='Part '.
- $partid.' ( ID '.$respid.
+ $lastsubonly.='Part: '.
+ $display_part.' ( ID '.$respid.
' ) '.
'Nothing submitted - no attempts ';
next;
@@ -1665,11 +1666,14 @@ KEYWORDS
if ($ENV{'form.lastSub'} eq 'lastonly' ||
($ENV{'form.lastSub'} eq 'hdgrade' &&
$$handgrade{$part} eq 'yes')) {
- $lastsubonly.='Part '.
- $partid.' ( ID '.$respid.
+ my $display_part=&get_display_part($partid,$url,$symb);
+ $lastsubonly.='Part: '.
+ $display_part.' ( ID '.$respid.
' ) ';
if ($record{"resource.$partid.$respid.uploadedurl"}) {
- $lastsubonly.=' File uploaded by student Like all files provided by users, this file may contain virusses ';
+ &Apache::lonnet::allowuploaded('/adm/grades',
+ $record{"resource.$partid.$respid.uploadedurl"});
+ $lastsubonly.=' File uploaded by student Like all files provided by users, this file may contain virusses ';
}
$lastsubonly.='Submitted Answer: '.
&cleanRecord($subval,$responsetype,$symb,$partid,
@@ -2049,11 +2053,11 @@ sub saveHandGrade {
}
} elsif ($dropMenu eq 'reset status'
&& exists($record{'resource.'.$_.'.solved'})) { #don't bother if no old records -> no attempts
- $newrecord{'resource.'.$_.'.tries'} = 0;
- $newrecord{'resource.'.$_.'.solved'} = '';
- $newrecord{'resource.'.$_.'.award'} = '';
- $newrecord{'resource.'.$_.'.awarded'} = 0;
- $newrecord{'resource.'.$_.'.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
+ foreach my $key (keys (%record)) {
+ if ($key=~/^resource\.\Q$_\E\./) { $newrecord{$key} = ''; }
+ }
+ $newrecord{'resource.'.$_.'.regrader'}=
+ "$ENV{'user.name'}:$ENV{'user.domain'}";
} elsif ($dropMenu eq '') {
$pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ?
$ENV{'form.GD_BOX'.$newflg.'_'.$_} :
@@ -2297,7 +2301,7 @@ sub viewgrades {
my $sectionClass;
if ($ENV{'form.section'} eq 'all') {
$sectionClass='Class ';
- } elsif ($ENV{'form.section'} eq 'no') {
+ } elsif ($ENV{'form.section'} eq 'none') {
$sectionClass='Students in no Section ';
} else {
$sectionClass='Students in Section '.$ENV{'form.section'}.'';
@@ -2324,7 +2328,8 @@ sub viewgrades {
$ctsparts.'" value="'.$partid.'" />'."\n";
$result.=' '."\n";
- $result.='Part '.$partid.' Point: ';
+ my $display_part=&get_display_part($partid,$url,$symb);
+ $result.=' Part: '.$display_part.' Point: ';
$result.='';
my $ctr = 0;
while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
@@ -2363,14 +2368,17 @@ sub viewgrades {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
$display =~ s|^Number of Attempts|Tries |; # makes the column narrower
if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
+ my ($partid) = &split_part_type($part);
+ my $display_part=&get_display_part($partid,$url,$symb);
if ($display =~ /^Partial Credit Factor/) {
- my ($partid) = &split_part_type($part);
- $result.='Score Part '.$partid.' (weight = '.
- $weight{$partid}.') '."\n";
+ $result.='Score Part: '.$display_part.
+ ' (weight = '.$weight{$partid}.') '."\n";
next;
+ } else {
+ $display =~s/\[Part: \Q$partid\E\]/Part:<\/b> $display_part/;
}
$display =~ s|Problem Status|Grade Status |;
- $result.=''.$display.' '."\n";
+ $result.=''.$display.' '."\n";
}
$result.=' ';
@@ -2500,9 +2508,10 @@ sub editgrades {
}
}
foreach my $partid (@partid) {
+ my $display_part=&get_display_part($partid,$url,$symb);
$result .= 'Part '.$partid.
- ' (Weight = '.$weight{$partid}.') ';
+ '" align="center">Part: '.$display_part.
+ ' (Weight = '.$weight{$partid}.')';
}
$result .= '';
@@ -2596,7 +2605,7 @@ sub editgrades {
if ($noupdate) {
# my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;
my $numcols=scalar(@partid)*4+2;
- $result .= ' No Changes Occurred For the Students Below '.$noupdate;
+ $result .= 'No Changes Occurred For the Students Below '.$noupdate;
}
$result .= '
'."\n".
&show_grading_menu_form ($symb,$url);
@@ -3043,8 +3052,6 @@ sub getSymbMap {
$minder++;
}
}
-
- $navmap->untieHashes();
return \@titles,\%symbx;
}
@@ -3108,7 +3115,7 @@ sub displayPage {
' Prob. '.
' '.($ENV{'form.vProb'} eq 'no' ? 'Title' : 'Problem Text').'/Grade ';
- my ($depth,$question) = (1,1);
+ my ($depth,$question,$prob) = (1,1,1);
$iterator->next(); # skip the first BEGIN_MAP
my $curRes = $iterator->next(); # for "current resource"
while ($depth > 0) {
@@ -3119,7 +3126,7 @@ sub displayPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
- $studentTable.=''.$question.
+ $studentTable.=' '.$prob.
(scalar(@{$parts}) == 1 ? '' : ' ('.scalar(@{$parts}).' parts)').' ';
$studentTable.='';
if ($ENV{'form.vProb'} eq 'yes' ) {
@@ -3169,6 +3176,7 @@ sub displayPage {
$studentTable.=' '."\n";
$question++;
}
+ $prob++;
}
$studentTable.=' ';
@@ -3176,8 +3184,6 @@ sub displayPage {
$curRes = $iterator->next();
}
- $navmap->untieHashes();
-
$studentTable.='
'."\n".
' '.
@@ -3190,9 +3196,12 @@ sub displayPage {
sub displaySubByDates {
my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;
+ my $isCODE=0;
+ if (exists($record->{'resource.CODE'})) { $isCODE=1; }
my $studentTable=''.
''.
'Date/Time '.
+ ($isCODE?'CODE ':'').
'Submission '.
'Status ';
my ($version);
@@ -3205,17 +3214,22 @@ sub displaySubByDates {
for ($version=1;$version<=$$record{'version'};$version++) {
my $timestamp = scalar(localtime($$record{$version.':timestamp'}));
$studentTable.=''.$timestamp.' ';
+ if ($isCODE) {
+ $studentTable.=''.$record->{$version.':resource.CODE'}.' ';
+ }
my @versionKeys = split(/\:/,$$record{$version.':keys'});
my @displaySub = ();
foreach my $partid (@{$parts}) {
my @matchKey = sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys);
# next if ($$record{"$version:resource.$partid.solved"} eq '');
+ my $display_part=&get_display_part($partid,undef,$symb);
foreach my $matchKey (@matchKey) {
- if (exists $$record{$version.':'.$matchKey}) {
+ if (exists($$record{$version.':'.$matchKey}) &&
+ $$record{$version.':'.$matchKey} ne '') {
my ($responseId)=($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/);
- $displaySub[0].='Part '.$partid.' ';
+ $displaySub[0].='Part: '.$display_part.' ';
$displaySub[0].='(ID '.
- $responseId.') ';
+ $responseId.') ';
if ($$record{"$version:resource.$partid.tries"} eq '') {
$displaySub[0].='Trial not counted';
} else {
@@ -3233,14 +3247,14 @@ sub displaySubByDates {
}
}
if (exists $$record{"$version:resource.$partid.award"}) {
- $displaySub[1].='Part '.$partid.' '.
+ $displaySub[1].='Part: '.$display_part.' '.
lc($$record{"$version:resource.$partid.award"}).' '.
$mark{$$record{"$version:resource.$partid.solved"}}.
' ';
}
if (exists $$record{"$version:resource.$partid.regrader"}) {
$displaySub[2].=$$record{"$version:resource.$partid.regrader"}.
- ' ('.&mt('Part').': '.$partid.')';
+ ' ('.&mt('Part').': '.$display_part.')';
}
}
# needed because old essay regrader has not parts info
@@ -3295,7 +3309,7 @@ sub updateGradeByPage {
$iterator->next(); # skip the first BEGIN_MAP
my $curRes = $iterator->next(); # for "current resource"
- my ($depth,$question,$changeflag)= (1,1,0);
+ my ($depth,$question,$prob,$changeflag)= (1,1,1,0);
while ($depth > 0) {
if($curRes == $iterator->BEGIN_MAP) { $depth++; }
if($curRes == $iterator->END_MAP) { $depth--; }
@@ -3304,7 +3318,7 @@ sub updateGradeByPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
- $studentTable.=''.$question.
+ $studentTable.=' '.$prob.
(scalar(@{$parts}) == 1 ? '' : ' ('.scalar(@{$parts}).' parts)').' ';
$studentTable.=' '.$title.' ';
@@ -3337,12 +3351,13 @@ sub updateGradeByPage {
$changeflag++;
$newpts = '';
}
-
+ my $display_part=&get_display_part($partid,undef,
+ $curRes->symb());
my $oldstatus = $ENV{'form.solved'.$question.'_'.$partid};
- $displayPts[0].=' Part '.$partid.' = '.
+ $displayPts[0].=' Part: '.$display_part.' = '.
(($oldstatus eq 'excused') ? 'excused' : $oldpts).
' ';
- $displayPts[1].=' Part '.$partid.' = '.
+ $displayPts[1].=' Part: '.$display_part.' = '.
(($score eq 'excused') ? 'excused' : $newpts).
' ';
@@ -3365,12 +3380,11 @@ sub updateGradeByPage {
''.$displayPts[1].' '.
' ';
+ $prob++;
}
$curRes = $iterator->next();
}
- $navmap->untieHashes();
-
$studentTable.='
';
$studentTable.=&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'});
my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' :
@@ -3415,18 +3429,27 @@ sub getSequenceDropDown {
return $result;
}
-sub scantron_uploads {
- if (!-e $Apache::lonnet::perlvar{'lonScansDir'}) { return ''};
- my $result= '';
+sub scantron_filenames {
my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname,
&Apache::loncommon::propath($cdom,$cname));
- foreach my $filename (@files) {
+ my @possiblenames;
+ foreach my $filename (sort(@files)) {
($filename)=split(/&/,$filename);
if ($filename!~/^scantron_orig_/) { next ; }
$filename=~s/^scantron_orig_//;
- $result.="$filename \n";
+ push(@possiblenames,$filename);
+ }
+ return @possiblenames;
+}
+
+sub scantron_uploads {
+ my ($file2grade) = @_;
+ my $result= '';
+ $result.=" ";
+ foreach my $filename (sort(&scantron_filenames())) {
+ $result.="$filename \n";
}
$result.=" ";
return $result;
@@ -3435,6 +3458,7 @@ sub scantron_uploads {
sub scantron_scantab {
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
my $result=''."\n";
+ $result.=' '."\n";
foreach my $line (<$fh>) {
my ($name,$descrip)=split(/:/,$line);
if ($name =~ /^\#/) { next; }
@@ -3450,7 +3474,8 @@ sub scantron_CODElist {
my $cnum = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};
my @names=&Apache::lonnet::getkeys('CODEs',$cdom,$cnum);
my $namechoice=' ';
- foreach my $name (@names) {
+ foreach my $name (sort {uc($a) cmp uc($b)} @names) {
+ if ($name =~ /^error: 2 /) { next; }
$namechoice.=''.$name.' ';
}
$namechoice=''.$namechoice.' ';
@@ -3470,13 +3495,13 @@ sub scantron_CODEunique {
}
sub scantron_selectphase {
- my ($r) = @_;
+ my ($r,$file2grade) = @_;
my ($symb,$url)=&get_symb_and_url($r);
if (!$symb) {return '';}
my $sequence_selector=&getSequenceDropDown($r,$symb);
my $default_form_data=&defaultFormData($symb,$url);
my $grading_menu_button=&show_grading_menu_form($symb,$url);
- my $file_selector=&scantron_uploads();
+ my $file_selector=&scantron_uploads($file2grade);
my $format_selector=&scantron_scantab();
my $CODE_selector=&scantron_CODElist();
my $CODE_unique=&scantron_CODEunique();
@@ -3486,9 +3511,9 @@ sub scantron_selectphase {
$result.= <
+
SCANTRONFORM
@@ -3579,10 +3604,33 @@ UPLOAD
SCANTRONFORM
}
+ $r->print(<
+
+
+
+
+
+
+
+SCANTRONFORM
$r->print(<
-
$grading_menu_button
SCANTRONFORM
@@ -3648,17 +3696,19 @@ sub scantron_fixup_scanline {
$args->{'username'}.':'.$args->{'domain'});
}
} elsif ($field eq 'CODE') {
- if (length($args->{'CODE'}) > $$scantron_config{'CODElength'}) {
- return ($line,1,'New CODE value too large');
+ if ($args->{'CODE_ignore_dup'}) {
+ &scan_data($scan_data,"$whichline.CODE_ignore_dup",'1');
}
- if (length($args->{'CODE'}) < $$scantron_config{'CODElength'}) {
- $args->{'CODE'}=sprintf('%-'.$$scantron_config{'CODElength'}.'s',
- $args->{'CODE'});
- }
- substr($line,$$scantron_config{'CODEstart'}-1,
- $$scantron_config{'CODElength'})=$args->{'CODE'};
- if ($args->{'CODE'}=~/^\s*$/) {
- &scan_data($scan_data,"$whichline.CODE",$args->{'CODE'});
+ &scan_data($scan_data,"$whichline.useCODE",'1');
+ if ($args->{'CODE'} ne 'use_unfound') {
+ if (length($args->{'CODE'}) > $$scantron_config{'CODElength'}) {
+ return ($line,1,'New CODE value too large');
+ }
+ if (length($args->{'CODE'}) < $$scantron_config{'CODElength'}) {
+ $args->{'CODE'}=sprintf('%-'.$$scantron_config{'CODElength'}.'s',$args->{'CODE'});
+ }
+ substr($line,$$scantron_config{'CODEstart'}-1,
+ $$scantron_config{'CODElength'})=$args->{'CODE'};
}
} elsif ($field eq 'answer') {
my $length=$scantron_config->{'Qlength'};
@@ -3690,14 +3740,21 @@ sub scan_data {
}
sub scantron_parse_scanline {
- my ($line,$whichline,$scantron_config,$scan_data)=@_;
+ my ($line,$whichline,$scantron_config,$scan_data,$justHeader)=@_;
my %record;
my $questions=substr($line,$$scantron_config{'Qstart'}-1);
my $data=substr($line,0,$$scantron_config{'Qstart'}-1);
if ($$scantron_config{'CODElocation'} ne 0) {
if ($$scantron_config{'CODElocation'} < 0) {
- $record{'scantron.CODE'}=substr($data,$$scantron_config{'CODEstart'}-1,
+ $record{'scantron.CODE'}=substr($data,
+ $$scantron_config{'CODEstart'}-1,
$$scantron_config{'CODElength'});
+ if (&scan_data($scan_data,"$whichline.useCODE")) {
+ $record{'scantron.useCODE'}=1;
+ }
+ if (&scan_data($scan_data,"$whichline.CODE_ignore_dup")) {
+ $record{'scantron.CODE_ignore_dup'}=1;
+ }
} else {
#FIXME interpret first N questions
}
@@ -3713,6 +3770,8 @@ sub scantron_parse_scanline {
$record{'scantron.LastName'}=
substr($data,$$scantron_config{'LastName'}-1,
$$scantron_config{'LastNamelength'});
+ if ($justHeader) { return \%record; }
+
my @alphabet=('A'..'Z');
my $questnum=0;
while ($questions) {
@@ -3768,7 +3827,8 @@ sub scantron_find_student {
sub scantron_filter {
my ($curres)=@_;
- if (ref($curres) && $curres->is_problem() && !$curres->randomout) {
+ # randomout is dysfunctional at best for this purpose
+ if (ref($curres) && $curres->is_problem()) { #&& !$curres->randomout) {
return 1;
}
return 0;
@@ -3780,7 +3840,7 @@ sub scantron_process_corrections {
my ($scanlines,$scan_data)=&scantron_getfile();
my $classlist=&Apache::loncoursedata::get_classlist();
my $which=$ENV{'form.scantron_line'};
- my $line=&scantron_get_line($scanlines,$which);
+ my $line=&scantron_get_line($scanlines,$scan_data,$which);
my ($skip,$err,$errmsg);
if ($ENV{'form.scantron_skip_record'}) {
$skip=1;
@@ -3794,10 +3854,25 @@ sub scantron_process_corrections {
'username'=>$ENV{'form.scantron_username'},
'domain'=>$ENV{'form.scantron_domain'}});
} elsif ($ENV{'form.scantron_corrections'} =~ /^(duplicate|incorrect)CODE$/) {
- my $newCODE=$ENV{'form.scantron_CODE'};
+ my $resolution=$ENV{'form.scantron_CODE_resolution'};
+ my $newCODE;
+ my %args;
+ if ($resolution eq 'use_unfound') {
+ $newCODE='use_unfound';
+ } elsif ($resolution eq 'use_found') {
+ $newCODE=$ENV{'form.scantron_CODE_selectedvalue'};
+ } elsif ($resolution eq 'use_typed') {
+ $newCODE=$ENV{'form.scantron_CODE_newvalue'};
+ } elsif ($resolution =~ /^use_closest_(\d+)/) {
+ $newCODE=$ENV{"form.scantron_CODE_closest_$1"};
+ }
+ if ($ENV{'form.scantron_corrections'} eq 'duplicateCODE') {
+ $args{'CODE_ignore_dup'}=1;
+ }
+ $args{'CODE'}=$newCODE;
($line,$err,$errmsg)=
&scantron_fixup_scanline(\%scantron_config,$scan_data,$line,$which,
- 'CODE',{'CODE'=>$newCODE});
+ 'CODE',\%args);
} elsif ($ENV{'form.scantron_corrections'} =~ /^(missing|double)bubble$/) {
foreach my $question (split(',',$ENV{'form.scantron_questions'})) {
($line,$err,$errmsg)=
@@ -3811,31 +3886,141 @@ sub scantron_process_corrections {
if ($err) {
$r->print("Unable to accept last correction, an error occurred :$errmsg:");
} else {
- &scantron_put_line($scanlines,$which,$line,$skip);
+ &scantron_put_line($scanlines,$scan_data,$which,$line,$skip);
&scantron_putfile($scanlines,$scan_data);
}
}
+sub reset_skipping_status {
+ my ($scanlines,$scan_data)=&scantron_getfile();
+ &scan_data($scan_data,'remember_skipping',undef,1);
+ &scantron_putfile(undef,$scan_data);
+}
+
+sub allow_skipping {
+ my ($scan_data,$i)=@_;
+ my %remembered=split(':',&scan_data($scan_data,'remember_skipping'));
+ delete($remembered{$i});
+ &scan_data($scan_data,'remember_skipping',join(':',%remembered));
+}
+
+sub should_be_skipped {
+ my ($scan_data,$i)=@_;
+ if ($ENV{'form.scantron_options_redo'} !~ /^redo_/) {
+ # not redoing old skips
+ return 0;
+ }
+ my %remembered=split(':',&scan_data($scan_data,'remember_skipping'));
+ if (exists($remembered{$i})) { return 0; }
+ return 1;
+}
+
+sub remember_current_skipped {
+ my ($scanlines,$scan_data)=&scantron_getfile();
+ my %to_remember;
+ for (my $i=0;$i<=$scanlines->{'count'};$i++) {
+ if ($scanlines->{'skipped'}[$i]) {
+ $to_remember{$i}=1;
+ }
+ }
+ &Apache::lonnet::logthis('remembering '.join(':',%to_remember));
+ &scan_data($scan_data,'remember_skipping',join(':',%to_remember));
+ &scantron_putfile(undef,$scan_data);
+}
+
+sub check_for_error {
+ my ($r,$result)=@_;
+ if ($result ne 'ok' && $result ne 'not_found' ) {
+ $r->print("An error occured ($result) when trying to Remove the existing corrections.");
+ }
+}
+
+sub scantron_warning_screen {
+ my ($button_text)=@_;
+ my $title=&Apache::lonnet::gettitle($ENV{'form.selectpage'});
+ return (<
+Please double check the information
+ below before clicking on '$button_text'
+
+
+Sequence To be Graded: $title
+Data File that will be used: $ENV{'form.scantron_selectfile'}
+
+
+
+ If this information is correct, please click on '$button_text'.
+ If something is incorrect, please click the 'Grading Menu' button to start over.
+
+
+STUFF
+}
+
+sub scantron_do_warning {
+ my ($r)=@_;
+ my ($symb,$url)=&get_symb_and_url($r);
+ if (!$symb) {return '';}
+ my $default_form_data=&defaultFormData($symb,$url);
+ $r->print(&scantron_form_start().$default_form_data);
+ my $warning=&scantron_warning_screen('Validate Records');
+ $r->print(<
+
+
+STUFF
+ $r->print(" ".&show_grading_menu_form($symb,$url)."");
+ return '';
+}
+
+sub scantron_form_start {
+ my ($max_bubble)=@_;
+ my $result= <
+
+
+
+
+
+
+
+
+SCANTRONFORM
+ return $result;
+}
sub scantron_validate_file {
my ($r) = @_;
my ($symb,$url)=&get_symb_and_url($r);
if (!$symb) {return '';}
my $default_form_data=&defaultFormData($symb,$url);
+
+ # do the detection of only doing skipped records first befroe we delete
+ # them when doing the corrections reset
+ if ($ENV{'form.scantron_options_redo'} ne 'redo_skipped_ready') {
+ &reset_skipping_status();
+ }
+ if ($ENV{'form.scantron_options_redo'} eq 'redo_skipped') {
+ &remember_current_skipped();
+ &scantron_remove_file('skipped');
+ $ENV{'form.scantron_options_redo'}='redo_skipped_ready';
+ }
+
+ if ($ENV{'form.scantron_options_ignore'} eq 'ignore_corrections') {
+ &check_for_error($r,&scantron_remove_file('corrected'));
+ &check_for_error($r,&scantron_remove_file('skipped'));
+ &check_for_error($r,&scantron_remove_scan_data());
+ $ENV{'form.scantron_options_ignore'}='done';
+ }
if ($ENV{'form.scantron_corrections'}) {
&scantron_process_corrections($r);
}
+ $r->print("Gathering neccessary info.
");$r->rflush();
#get the student pick code ready
$r->print(&Apache::loncommon::studentbrowser_javascript());
- my $result= <
-
-
-
-
- $default_form_data
-SCANTRONFORM
+ my $max_bubble=&scantron_get_maxbubble($r);
+ my $result=&scantron_form_start($max_bubble).$default_form_data;
$r->print($result);
my @validate_phases=( 'ID',
@@ -3843,14 +4028,10 @@ SCANTRONFORM
'doublebubble',
'missingbubbles');
if (!$ENV{'form.validatepass'}) {
- $ENV{'form.valiadatepass'} = 0;
+ $ENV{'form.validatepass'} = 0;
}
- my $currentphase=$ENV{'form.valiadatepass'};
+ my $currentphase=$ENV{'form.validatepass'};
- if ($ENV{'form.scantron_selectfile'}=~m-^/-) {
- #first pass copy file to classdir
-
- }
my $stop=0;
while (!$stop && $currentphase < scalar(@validate_phases)) {
$r->print(" Validating ".$validate_phases[$currentphase]."
");
@@ -3862,9 +4043,14 @@ SCANTRONFORM
}
}
if (!$stop) {
- $r->print("Validation process complete. ");
- $r->print(' ');
- $r->print(' ');
+ my $warning=&scantron_warning_screen('Start Grading');
+ $r->print(<
+$warning
+
+
+STUFF
+
} else {
$r->print(' ');
$r->print(" ");
@@ -3880,9 +4066,44 @@ SCANTRONFORM
return '';
}
+sub scantron_remove_file {
+ my ($which)=@_;
+ my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
+ my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
+ my $file='scantron_';
+ if ($which eq 'corrected' || $which eq 'skipped') {
+ $file.=$which.'_';
+ } else {
+ return 'refused';
+ }
+ $file.=$ENV{'form.scantron_selectfile'};
+ return &Apache::lonnet::removeuserfile($cname,$cdom,$file);
+}
+
+sub scantron_remove_scan_data {
+ my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
+ my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
+ my @keys=&Apache::lonnet::getkeys('nohist_scantrondata',$cdom,$cname);
+ my @todelete;
+ my $filename=$ENV{'form.scantron_selectfile'};
+ foreach my $key (@keys) {
+ if ($key=~/^\Q$filename\E_/) {
+ if ($ENV{'form.scantron_options_redo'} eq 'redo_skipped_ready' &&
+ $key=~/remember_skipping/) {
+ next;
+ }
+ push(@todelete,$key);
+ }
+ }
+ my $result;
+ if (@todelete) {
+ $result=&Apache::lonnet::del('nohist_scantrondata',\@todelete,$cdom,$cname);
+ }
+ return $result;
+}
+
sub scantron_getfile {
- #FIXME really would prefer a scantron directory but tokenwrapper
- # doesn't allow access to subdirs of userfiles
+ #FIXME really would prefer a scantron directory
my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
my $lines;
@@ -3925,34 +4146,48 @@ sub lonnet_putfile {
sub scantron_putfile {
my ($scanlines,$scan_data) = @_;
- #FIXME really would prefer a scantron directory but tokenwrapper
- # doesn't allow access to subdirs of userfiles
+ #FIXME really would prefer a scantron directory
my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
- my $prefix='scantron_';
+ if ($scanlines) {
+ my $prefix='scantron_';
# no need to update orig, shouldn't change
# &lonnet_putfile(join("\n",@{$scanlines->{'orig'}}),$prefix.'orig_'.
# $ENV{'form.scantron_selectfile'});
- &lonnet_putfile(join("\n",@{$scanlines->{'corrected'}}),
- $prefix.'corrected_'.
- $ENV{'form.scantron_selectfile'});
- &lonnet_putfile(join("\n",@{$scanlines->{'skipped'}}),
- $prefix.'skipped_'.
- $ENV{'form.scantron_selectfile'});
+ &lonnet_putfile(join("\n",@{$scanlines->{'corrected'}}),
+ $prefix.'corrected_'.
+ $ENV{'form.scantron_selectfile'});
+ &lonnet_putfile(join("\n",@{$scanlines->{'skipped'}}),
+ $prefix.'skipped_'.
+ $ENV{'form.scantron_selectfile'});
+ }
&Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname);
}
sub scantron_get_line {
- my ($scanlines,$i)=@_;
- if ($scanlines->{'skipped'}[$i]) {return undef;}
+ my ($scanlines,$scan_data,$i)=@_;
+ if (&should_be_skipped($scan_data,$i)) { return undef; }
+ if ($scanlines->{'skipped'}[$i]) { return undef; }
if ($scanlines->{'corrected'}[$i]) {return $scanlines->{'corrected'}[$i];}
return $scanlines->{'orig'}[$i];
}
+sub get_todo_count {
+ my ($scanlines,$scan_data)=@_;
+ my $count=0;
+ for (my $i=0;$i<=$scanlines->{'count'};$i++) {
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
+ if ($line=~/^[\s\cz]*$/) { next; }
+ $count++;
+ }
+ return $count;
+}
+
sub scantron_put_line {
- my ($scanlines,$i,$newline,$skip)=@_;
+ my ($scanlines,$scan_data,$i,$newline,$skip)=@_;
if ($skip) {
$scanlines->{'skipped'}[$i]=$newline;
+ &allow_skipping($scan_data,$i);
return;
}
$scanlines->{'corrected'}[$i]=$newline;
@@ -3971,7 +4206,7 @@ sub scantron_validate_ID {
my %found=('ids'=>{},'usernames'=>{});
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
- my $line=&scantron_get_line($scanlines,$i);
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
@@ -3985,11 +4220,11 @@ sub scantron_validate_ID {
if ($found{'ids'}{$found}) {
&scantron_get_correction($r,$i,$scan_record,\%scantron_config,
$line,'duplicateID',$found);
- return(1);
+ return(1,$currentphase);
} elsif ($found{'usernames'}{$username}) {
&scantron_get_correction($r,$i,$scan_record,\%scantron_config,
$line,'duplicateID',$username);
- return(1);
+ return(1,$currentphase);
}
#FIXME store away line we previously saw the ID on to use above
$found{'ids'}{$found}++;
@@ -4001,18 +4236,18 @@ sub scantron_validate_ID {
&scantron_get_correction($r,$i,$scan_record,
\%scantron_config,
$line,'duplicateID',$username);
- return(1);
+ return(1,$currentphase);
} elsif (!defined($username)) {
&scantron_get_correction($r,$i,$scan_record,
\%scantron_config,
$line,'incorrectID');
- return(1);
+ return(1,$currentphase);
}
$found{'usernames'}{$username}++;
} else {
&scantron_get_correction($r,$i,$scan_record,\%scantron_config,
$line,'incorrectID');
- return(1);
+ return(1,$currentphase);
}
}
}
@@ -4061,20 +4296,56 @@ sub scantron_get_correction {
$r->print('');
} elsif ($error =~ /CODE$/) {
if ($error eq 'incorrectCODE') {
- $r->print("The encoded CODE is not in the list of possible CODEs\n");
+ $r->print("The encoded CODE is not in the list of possible CODEs
\n");
} elsif ($error eq 'duplicateCODE') {
- $r->print("The encoded CODE has also been used by a previous paper $arg, and CODEs were supposed to be unique\n");
+ $r->print("The encoded CODE has also been used by a previous paper ".join(', ',@{$arg}).", and CODEs are supposed to be unique
\n");
}
+ $r->print("The CODE on the form is '".
+ $$scan_record{'scantron.CODE'}."' \n");
$r->print("
The ID on the form is ".
$$scan_record{'scantron.ID'}." \n");
$r->print("The name on the paper is ".
$$scan_record{'scantron.LastName'}.",".
$$scan_record{'scantron.FirstName'}."
");
$r->print("How should I handle this? \n");
- $r->print("\n
");
- $r->print(' ');
+ $r->print("\n ");
+ my $i=0;
+ if ($error eq 'incorrectCODE') {
+ my ($max,$closest)=&scantron_get_closely_matching_CODEs($arg,$$scan_record{'scantron.CODE'});
+ foreach my $testcode (@{$closest}) {
+ my $checked='';
+ if (!$i) { $checked=' checked="on" '; }
+ $r->print(" Use the similar CODE ".$testcode." instead. ");
+ $r->print("\n ");
+ $i++;
+ }
+ }
+ my $checked; if (!$i) { $checked=' checked="on" '; }
+ $r->print(" Use the CODE ".$$scan_record{'scantron.CODE'}." that is was on the paper, ignoring the error.");
+ $r->print("\n ");
+
+ $r->print(<
+function change_radio(field) {
+ var slct=document.scantronupload.scantron_CODE_resolution;
+ var i;
+ for (i=0;i
+ENDSCRIPT
+ my $href="/adm/pickcode?".
+ "form=".&Apache::lonnet::escape("scantronupload").
+ "&scantron_format=".&Apache::lonnet::escape($ENV{'form.scantron_format'}).
+ "&scantron_CODElist=".&Apache::lonnet::escape($ENV{'form.scantron_CODElist'}).
+ "&curCODE=".&Apache::lonnet::escape($$scan_record{'scantron.CODE'}).
+ "&scantron_selectfile=".&Apache::lonnet::escape($ENV{'form.scantron_selectfile'});
+ $r->print(" Select a CODE from the list of all CODEs and use it. Selected CODE is ");
+ $r->print("\n ");
+ $r->print(" Use as the CODE.");
+ $r->print("\n ");
} elsif ($error eq 'doublebubble') {
-#FIXME Need to print out who this is along with the paper info
$r->print("There have been multiple bubbles scanned for a some question(s)
\n");
$r->print(' ');
@@ -4121,50 +4392,83 @@ sub scantron_bubble_selector {
$r->print('');
}
+sub num_matches {
+ my ($orig,$code) = @_;
+ my @code=split(//,$code);
+ my @orig=split(//,$orig);
+ my $same=0;
+ for (my $i=0;$i{'count'};$i++) {
- my $line=&scantron_get_line($scanlines,$i);
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
my $CODE=$$scan_record{'scantron.CODE'};
my $error=0;
- if (!exists($allcodes{$CODE})) {
+ if (!&Apache::lonnet::validCODE($CODE)) {
+ &scantron_get_correction($r,$i,$scan_record,
+ \%scantron_config,
+ $line,'incorrectCODE',\%allcodes);
+ return(1,$currentphase);
+ }
+ if (%allcodes && !exists($allcodes{$CODE})
+ && !$$scan_record{'scantron.useCODE'}) {
&scantron_get_correction($r,$i,$scan_record,
\%scantron_config,
- $line,'incorrectCODE',$CODE);
- return(1);
+ $line,'incorrectCODE',\%allcodes);
+ return(1,$currentphase);
}
- if (exists($usedCODEs{$CODE}) && $ENV{'form.scantron_CODEunique'}) {
+ if (exists($usedCODEs{$CODE})
+ && $ENV{'form.scantron_CODEunique'} eq 'yes'
+ && !$$scan_record{'scantron.CODE_ignore_dup'}) {
&scantron_get_correction($r,$i,$scan_record,
\%scantron_config,
- $line,'duplicateCODE',$CODE);
- return(1);
+ $line,'duplicateCODE',$usedCODEs{$CODE});
+ return(1,$currentphase);
}
- $usedCODEs{$CODE}++;
+ push (@{$usedCODEs{$CODE}},$$scan_record{'scantron.PaperID'});
}
return (0,$currentphase+1);
}
@@ -4179,7 +4483,7 @@ sub scantron_validate_doublebubble {
my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
- my $line=&scantron_get_line($scanlines,$i);
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
@@ -4192,6 +4496,31 @@ sub scantron_validate_doublebubble {
return (0,$currentphase+1);
}
+sub scantron_get_maxbubble {
+ my ($r)=@_;
+ if (defined($ENV{'form.scantron_maxbubble'}) &&
+ $ENV{'form.scantron_maxbubble'}) {
+ return $ENV{'form.scantron_maxbubble'};
+ }
+ my $navmap=Apache::lonnavmaps::navmap->new();
+ my (undef,undef,$sequence)=
+ &Apache::lonnet::decode_symb($ENV{'form.selectpage'});
+ my $map=$navmap->getResourceByUrl($sequence);
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ &Apache::lonnet::delenv('form.counter');
+ foreach my $resource (@resources) {
+ my $result=&Apache::lonnet::ssi($resource->src());
+ }
+ &Apache::lonnet::delenv('scantron\.');
+ my $envfile=$ENV{'user.environment'};
+ $envfile=~/\/([^\/]+)\.id$/;
+ $envfile=$1;
+ &Apache::lonnet::transfer_profile_to_env($r->dir_config('lonIDsDir'),
+ $envfile);
+ $ENV{'form.scantron_maxbubble'}=$ENV{'form.counter'}-1;
+ return $ENV{'form.scantron_maxbubble'};
+}
+
sub scantron_validate_missingbubbles {
my ($r,$currentphase) = @_;
#get student info
@@ -4201,10 +4530,10 @@ sub scantron_validate_missingbubbles {
#get scantron line setup
my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
- my $max_bubble=$ENV{'form.scantron_maxbubble'};
+ my $max_bubble=&scantron_get_maxbubble();
if (!$max_bubble) { $max_bubble=2**31; }
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
- my $line=&scantron_get_line($scanlines,$i);
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
@@ -4249,18 +4578,25 @@ SCANTRONFORM
my @delayqueue;
my %completedstudents;
+ my $count=&get_todo_count($scanlines,$scan_data);
my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Scantron Status',
- 'Scantron Progress',$scanlines->{'count'});
+ 'Scantron Progress',$count,
+ 'inline',undef,'scantronupload');
&Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
'Processing first student');
my $start=&Time::HiRes::time();
my $i=-1;
- my ($uname,$udom);
+ my ($uname,$udom,$started);
while ($i<$scanlines->{'count'}) {
($uname,$udom)=('','');
$i++;
- my $line=&scantron_get_line($scanlines,$i);
+ my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
+ if ($started) {
+ &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
+ 'last student');
+ }
+ $started=1;
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
unless ($uname=&scantron_find_student($scan_record,$scan_data,
@@ -4281,27 +4617,35 @@ SCANTRONFORM
my $i=0;
foreach my $resource (@resources) {
$i++;
- my $result=&Apache::lonnet::ssi($resource->src(),
- ('submitted' =>'scantron',
- 'grade_target' =>'grade',
- 'grade_username'=>$uname,
- 'grade_domain' =>$udom,
- 'grade_courseid'=>$ENV{'request.course.id'},
- 'grade_symb' =>$resource->symb()));
+ my %form=('submitted' =>'scantron',
+ 'grade_target' =>'grade',
+ 'grade_username'=>$uname,
+ 'grade_domain' =>$udom,
+ 'grade_courseid'=>$ENV{'request.course.id'},
+ 'grade_symb' =>$resource->symb());
+ if (exists($scan_record->{'scantron.CODE'}) &&
+ $scan_record->{'scantron.CODE'}) {
+ $form{'CODE'}=$scan_record->{'scantron.CODE'};
+ } else {
+ $form{'CODE'}='';
+ }
+ my $result=&Apache::lonnet::ssi($resource->src(),%form);
+ if ($result ne '') {
+ &Apache::lonnet::logthis("scantron grading error -> $result");
+ }
+ if (&Apache::loncommon::connection_aborted($r)) { last; }
}
$completedstudents{$uname}={'line'=>$line};
+ if (&Apache::loncommon::connection_aborted($r)) { last; }
} continue {
&Apache::lonnet::delenv('form.counter');
&Apache::lonnet::delenv('scantron\.');
- &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
- 'last student');
}
&Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
# my $lasttime = &Time::HiRes::time()-$start;
# $r->print("took $lasttime
");
- $navmap->untieHashes();
- $r->print("Done
");
+ $r->print("");
$r->print(&show_grading_menu_form($symb,$url));
return '';
}
@@ -4361,7 +4705,8 @@ sub scantron_upload_scantron_data_save {
}
return '';
}
- $r->print("Doing upload to ".$ENV{'form.courseid'}." ");
+ my %coursedata=&Apache::lonnet::coursedescription($ENV{'form.domainid'}.'_'.$ENV{'form.courseid'});
+ $r->print("Doing upload to ".$coursedata{'description'}." ");
my $home=&Apache::lonnet::homeserver($ENV{'form.courseid'},
$ENV{'form.domainid'});
my $fname=$ENV{'form.upfile.filename'};
@@ -4378,6 +4723,7 @@ sub scantron_upload_scantron_data_save {
$fname=~s/[^\w\.\-]//g;
# See if there is anything left
unless ($fname) { return 'error: no uploaded file'; }
+ my $uploadedfile=$fname;
$fname='scantron_orig_'.$fname;
if (length($ENV{'form.upfile'}) < 2) {
$r->print("Error: The file you attempted to upload, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"')." , contained no information. Please check that you entered the correct filename.");
@@ -4386,17 +4732,61 @@ sub scantron_upload_scantron_data_save {
if ($result =~ m|^/uploaded/|) {
$r->print("Success: Successfully uploaded ".(length($ENV{'form.upfile'})-1)." bytes of data into location ".$result." ");
} else {
- $r->print("Error: An error (".$result.") occured when attempting to upload the file, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"')." ");
+ $r->print("Error: An error (".$result.") occurred when attempting to upload the file, ".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"')." ");
}
}
if ($symb) {
- $r->print(&show_grading_menu_form($symb,$url));
+ $r->print(&scantron_selectphase($r,$uploadedfile));
} else {
$r->print($doanotherupload);
}
return '';
}
+sub valid_file {
+ my ($requested_file)=@_;
+ foreach my $filename (sort(&scantron_filenames())) {
+ &Apache::lonnet::logthis("$requested_file $filename");
+ if ($requested_file eq $filename) { return 1; }
+ }
+ return 0;
+}
+
+sub scantron_download_scantron_data {
+ my ($r)=@_;
+ my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));
+ my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
+ my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
+ my $file=$ENV{'form.scantron_selectfile'};
+ if (! &valid_file($file)) {
+ $r->print(<
+ The requested file name was invalid.
+
+ERROR
+ $r->print(&show_grading_menu_form(&get_symb_and_url($r,1)));
+ return;
+ }
+ my $orig='/uploaded/'.$cdom.'/'.$cname.'/scantron_orig_'.$file;
+ my $corrected='/uploaded/'.$cdom.'/'.$cname.'/scantron_corrected_'.$file;
+ my $skipped='/uploaded/'.$cdom.'/'.$cname.'/scantron_skipped_'.$file;
+ &Apache::lonnet::allowuploaded('/adm/grades',$orig);
+ &Apache::lonnet::allowuploaded('/adm/grades',$corrected);
+ &Apache::lonnet::allowuploaded('/adm/grades',$skipped);
+ $r->print(<
+ Original file as uploaded by the scantron office.
+
+
+ Corrections , a file of corrected records that were used in grading.
+
+
+ Skipped , a file of records that were skipped.
+
+DOWNLOAD
+ $r->print(&show_grading_menu_form(&get_symb_and_url($r,1)));
+ return '';
+}
#-------- end of section for handling grading scantron forms -------
#
@@ -4511,9 +4901,6 @@ GRADINGMENUJS
$result.=&mt('Student Status').':'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
- if (ref($sections) && (grep /no/,@$sections)) {
- $result.=' (Section "no" implies the students were not assigned a section.) ';
- }
$result.='';
$result.=''.
@@ -4674,8 +5061,8 @@ sub handler {
}
} elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {
$request->print(&scantron_selectphase($request));
- } elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {
- $request->print(&scantron_validate_file($request));
+ } elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {
+ $request->print(&scantron_do_warning($request));
} elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {
$request->print(&scantron_validate_file($request));
} elsif ($command eq 'scantron_process' && $perm{'mgr'}) {
@@ -4688,7 +5075,7 @@ sub handler {
(&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})||
&Apache::lonnet::allowed('usc',$ENV{'request.course.id'}))) {
$request->print(&scantron_upload_scantron_data_save($request));
- } elsif ($command eq 'scantrondownload' &&
+ } elsif ($command eq 'scantron_download' &&
&Apache::lonnet::allowed('usc',$ENV{'request.course.id'})) {
$request->print(&scantron_download_scantron_data($request));
} elsif ($command) {
@@ -4713,8 +5100,7 @@ sub send_header {
sub send_footer {
my ($request)= @_;
- $request->print('');
- $request->print(&Apache::lontexconvert::footer());
+ $request->print('