'."\n".
''."\n";
- $result.='Fullname: '.$ENV{'form.fullname'}.
- ' Username: '.$uname.
- ($ENV{'user.domain'} eq $udom ? '' : ' ('.$udom.')').' '."\n";
+ $result.='Fullname: '.&nameUserString(undef,$ENV{'form.fullname'},$uname,$udom).' '."\n";
$result.=' '."\n";
@@ -1528,17 +1541,21 @@ KEYWORDS
my %seen = ();
my @partlist;
+ my @gradePartRespid;
for (sort keys(%$handgrade)) {
my ($partid,$respid) = split(/_/);
next if ($seen{$partid} > 0);
$seen{$partid}++;
next if ($$handgrade{$_} =~ /:no$/ && $ENV{'form.lastSub'} =~ /^(hdgrade)$/);
push @partlist,$partid;
+ push @gradePartRespid,$partid.'.'.$respid;
$request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record));
}
$result=' '."\n";
+ $result.=' '."\n" if ($counter == 0);
my $ctr = 0;
while ($ctr < scalar(@partlist)) {
$result.=' '."\n".
' No. '.
- ' Fullname (Username) '."\n";
+ ''.&nameUserString('header')." \n";
my (@parts) = sort(&getpartlist($url));
foreach my $part (@parts) {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
@@ -2160,7 +2175,7 @@ sub viewgrades {
#--- call by previous routine to display each student
sub viewstudentgrade {
- my ($$url,$symb,$courseid,$student,$fullname,$parts,$weight,$ctr) = @_;
+ my ($url,$symb,$courseid,$student,$fullname,$parts,$weight,$ctr) = @_;
my ($uname,$udom) = split(/:/,$student);
$student=~s/:/_/;
my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
@@ -2216,8 +2231,9 @@ sub editgrades {
$title.='Section: '.$ENV{'form.section'}.' '."\n";
my $result= ''."\n";
- $result.= ' No. '.
- ' Fullname (username) '."\n";
+ $result.= ''.
+ ' No. '.
+ ''.&nameUserString('header')." \n";
my %scoreptr = (
'correct' =>'correct_by_override',
@@ -2276,8 +2292,7 @@ sub editgrades {
my ($uname,$udom)=split(/_/,$user);
my %newrecord;
my $updateflag = 0;
- $line .= ' '.$$fullname{$usercolon}.
- ' ('.$uname.($udom eq $ENV{'user.domain'} ? '' : '$udom').') ';
+ $line .= ''.&nameUserString(undef,$$fullname{$usercolon},$uname,$udom).' ';
my $usec=$classlist->{"$uname:$udom"}[5];
if (!&canmodify($usec)) {
my $numcols=scalar(@partid)*4+2;
@@ -2495,7 +2510,6 @@ to this page if the data selected is ins
$javascript
ENDPICK
- $request->print(&show_grading_menu_form($symb,$url));
return '';
}
@@ -2756,9 +2770,9 @@ LISTJAVASCRIPT
''.
''.
' No. '.
- ' Fullname (username) '.
+ ''.&nameUserString('header').' '.
' No. '.
- ' Fullname (username) ';
+ ''.&nameUserString('header').' ';
my (undef,undef,$fullname) = &getclasslist($getsec,'1');
my $ptr = 1;
@@ -2766,8 +2780,8 @@ LISTJAVASCRIPT
my ($uname,$udom) = split(/:/,$student);
$studentTable.=($ptr%2 == 1 ? '' : '');
$studentTable.=''.$ptr.' ';
- $studentTable.=' '.$$fullname{$student}.
- ' ('.$uname.($udom eq $cdom ? '':':'.$udom).') '."\n";
+ $studentTable.=' '
+ .&nameUserString(undef,$$fullname{$student},$uname,$udom)."\n";
$studentTable.=($ptr%2 == 0 ? ' ' : '');
$ptr++;
}
@@ -2786,7 +2800,7 @@ sub getSymbMap {
my ($request) = @_;
my $navmap = Apache::lonnavmaps::navmap-> new($ENV{'request.course.fn'}.'.db',
$ENV{'request.course.fn'}.'_parms.db');
- $navmap->init();
+# $navmap->init();
my %symbx = ();
my @titles = ();
@@ -2826,9 +2840,8 @@ sub displayPage {
return;
}
my $result=' '.$ENV{'form.title'}.' ';
- $result.=' Student: '.$$fullname{$ENV{'form.student'}}.
- ' ('.$uname.($udom eq $cdom ? '':':'.$udom).') '."\n";
-
+ $result.=' Student: '.&nameUserString(undef,$$fullname{$ENV{'form.student'}},$uname,$udom).
+ ' '."\n";
&sub_page_js($request);
$request->print($result);
@@ -2990,8 +3003,8 @@ sub updateGradeByPage {
return;
}
my $result=' '.$ENV{'form.title'}.' ';
- $result.=' Student: '.$ENV{'form.fullname'}.
- ' ('.$uname.($udom eq $cdom ? '':':'.$udom).') '."\n";
+ $result.=' Student: '.&nameUserString(undef,$ENV{'form.fullname'},$uname,$udom).
+ ' '."\n";
$request->print($result);
@@ -3133,6 +3146,8 @@ sub getSequenceDropDown {
}
sub scantron_uploads {
+ #FIXME need to support scantron files put in another location,
+ # maybe the course directory? a scantron dir in the course directory?
if (!-e $Apache::lonnet::perlvar{'lonScansDir'}) { return ''};
my $result= '';
opendir(DIR,$Apache::lonnet::perlvar{'lonScansDir'});
@@ -3169,9 +3184,11 @@ sub scantron_selectphase {
my $file_selector=&scantron_uploads();
my $format_selector=&scantron_scantab();
my $result;
+ #FIXME allow instructor to be able to download the scantron file
+ # and to upload it,
$result.= <
-
+
$default_form_data
@@ -3201,7 +3218,7 @@ sub scantron_selectphase {
-
+
$grading_menu_button
SCANTRONFORM
@@ -3213,6 +3230,7 @@ sub get_scantron_config {
my ($which) = @_;
my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
my %config;
+ #FIXME probably should move to XML it has already gotten a bit much now
foreach my $line (<$fh>) {
my ($name,$descrip)=split(/:/,$line);
if ($name ne $which ) { next; }
@@ -3229,6 +3247,12 @@ sub get_scantron_config {
$config{'Qlength'}=$config[8];
$config{'Qoff'}=$config[9];
$config{'Qon'}=$config[10];
+ $config{'PaperID'}=$config[11];
+ $config{'PaperIDlength'}=$config[12];
+ $config{'FirstName'}=$config[13];
+ $config{'FirstNamelength'}=$config[14];
+ $config{'LastName'}=$config[15];
+ $config{'LastNamelength'}=$config[16];
last;
}
return %config;
@@ -3244,6 +3268,22 @@ sub username_to_idmap {
return %idmap;
}
+sub scantron_fixup_scanline {
+ my ($scantron_config,$line,$field,$newvalue) = @_;
+ if ($field eq 'ID') {
+ if ($newvalue > $$scantron_config{'IDlength'}) {
+ return ($line,1,'New value to large');
+ }
+ if ($newvalue < $$scantron_config{'IDlength'}) {
+ $newvalue=sprintf('%-'.$$scantron_config{'IDlength'}.'s',
+ $newvalue);
+ }
+ substr($line,$$scantron_config{'IDstart'}-1,
+ $$scantron_config{'IDlength'})=$newvalue;
+ }
+ return $line;
+}
+
sub scantron_parse_scanline {
my ($line,$scantron_config)=@_;
my %record;
@@ -3259,6 +3299,15 @@ sub scantron_parse_scanline {
}
$record{'scantron.ID'}=substr($data,$$scantron_config{'IDstart'}-1,
$$scantron_config{'IDlength'});
+ $record{'scantron.paperID'}=
+ substr($data,$$scantron_config{'PaperID'}-1,
+ $$scantron_config{'PaperIDlength'});
+ $record{'scantron.FirstName'}=
+ substr($data,$$scantron_config{'FirstName'}-1,
+ $$scantron_config{'FirstNamelength'});
+ $record{'scantron.LastName'}=
+ substr($data,$$scantron_config{'LastName'}-1,
+ $$scantron_config{'LastNamelength'});
my @alphabet=('A'..'Z');
my $questnum=0;
while ($questions) {
@@ -3269,6 +3318,7 @@ sub scantron_parse_scanline {
my (@array)=split(/$$scantron_config{'Qon'}/,$currentquest);
if (scalar(@array) gt 2) {
#FIXME do something intelligent with double bubbles
+ #actually not a concern right now, should be taking care of later
Apache->request->print("Wha!!! ".scalar(@array).
'-'.$currentquest.'-'.$questnum.' ');
}
@@ -3283,14 +3333,23 @@ sub scantron_parse_scanline {
}
sub scantron_add_delay {
+ my ($delayqueue,$scanline,$errormessage,$errorcode)=@_;
+ Apache->request->print('add_delay_error '.$_[2] );
+ push(@$delayqueue,
+ {'line' => $scanline, 'emsg' => $errormessage,
+ 'ecode' => $errorcode }
+ );
}
sub scantron_find_student {
my ($scantron_record,$idmap)=@_;
my $scanID=$$scantron_record{'scantron.ID'};
foreach my $id (keys(%$idmap)) {
- Apache->request->print('checking studnet -'.$id.'- againt -'.$scanID.'- ');
- if (lc($id) eq lc($scanID)) { Apache->request->print('success');return $$idmap{$id}; }
+ #Apache->request->print('checking studnet -'.$id.'- againt -'.$scanID.'- ');
+ if (lc($id) eq lc($scanID)) {
+ #Apache->request->print('success');
+ return $$idmap{$id};
+ }
}
return undef;
}
@@ -3303,6 +3362,238 @@ sub scantron_filter {
return 0;
}
+#FIXME I think I am doing this in the wrong order, I think it would be
+#better to make a several passes analyzing all of the lines in the
+#file for common errors wrong/invalid PID/username duplicated
+#PID/username, missing bubbles, double bubbles, missing/invalid CODE
+#and then get the instructor to fix all of these errors, then grade
+#the corrected one, I'll still need to catch error conditions, but
+#maybe most will taken care even before we start
+
+sub scantron_process_corrections {
+ my ($r) = @_;
+ if ($ENV{'form.scantron_corrections'} =~ /^(duplicate|incorrect)ID$/) {
+ my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});
+ my $scanlines=&scantron_getfile();
+ my $classlist=&Apache::loncoursedata::get_classlist();
+ my $which=$ENV{'form.scantron_line'};
+ my $line=&scantron_get_line($scanlines,$which);
+ my $newstudent=$ENV{'form.scantron_username'}.':'.
+ $ENV{'form.scantron_domain'};
+ my $newid=$classlist->{$newstudent}->[&Apache::loncoursedata::CL_ID];
+ ($line,my $err,my $errmsg)=
+ &scantron_fixup_scanline(\%scantron_config,$line,'ID',$newid);
+ if ($err) {
+ $r->print("Unable to accept last correction, an error occurred :$errmsg:");
+ } else {
+ &scantron_put_line($scanlines,$which,$line);
+ &scantron_putfile($scanlines);
+ }
+ }
+}
+
+sub scantron_validate_file {
+ my ($r) = @_;
+ my ($symb,$url)=&get_symb_and_url($r);
+ if (!$symb) {return '';}
+ my $default_form_data=&defaultFormData($symb,$url);
+
+ if ($ENV{'form.scantron_corrections'}) {
+ &scantron_process_corrections($r);
+ }
+ #get the student pick code ready
+ $r->print(&Apache::loncommon::studentbrowser_javascript());
+ my $result= <
+
+
+
+
+ $default_form_data
+SCANTRONFORM
+ $r->print($result);
+
+ my @validate_phases=( 'ID',
+ 'CODE',
+ 'doublebubble',
+ 'missingbubbles');
+ if (!$ENV{'form.validatepass'}) {
+ $ENV{'form.valiadatepass'} = 0;
+ }
+ my $currentphase=$ENV{'form.valiadatepass'};
+
+ if ($ENV{'form.scantron_selectfile'}=~m-^/-) {
+ #first pass copy file to classdir
+
+ }
+ my $stop=0;
+ while (!$stop && $currentphase < scalar(@validate_phases)) {
+ my $which="scantron_validate_".$validate_phases[$currentphase];
+ {
+ no strict 'refs';
+ ($stop,$currentphase)=&$which($r,$currentphase);
+ }
+ }
+ $r->print(" ");
+ return '';
+}
+
+sub scantron_getfile {
+ #my $scanlines=Apache::File->new($Apache::lonnet::perlvar{'lonScansDir'}."/$ENV{'form.scantron_selectfile'}");
+ #FIXME really would prefer a scantron directory but tokenwrapper
+ # doesn't allow access to subdirs of userfiles
+ my $lines;
+ $lines=&Apache::lonnet::getfile('/uploaded/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.'/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.'/'.
+ 'scantron_orig_'.$ENV{'form.scantron_selectfile'});
+ if ($lines eq '-1') {
+ #FIXME need to actually replicate file to course space
+ }
+ my %scanlines;
+ $scanlines{'orig'}=[split("\n",$lines)];
+ my $temp=$scanlines{'orig'};
+ $scanlines{'count'}=$#$temp;
+
+ $lines=&Apache::lonnet::getfile('/uploaded/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.'/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.'/'.
+ 'scantron_corrected_'.$ENV{'form.scantron_selectfile'});
+ if ($lines eq '-1') {
+ $scanlines{'corrected'}=[];
+ } else {
+ $scanlines{'corrected'}=[split("\n",$lines)];
+ }
+ $lines=&Apache::lonnet::getfile('/uploaded/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.'/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.'/'.
+ 'scantron_skipped_'.$ENV{'form.scantron_selectfile'});
+ if ($lines eq '-1') {
+ $scanlines{'skipped'}=[];
+ } else {
+ $scanlines{'skipped'}=[split("\n",$lines)];
+ }
+ return \%scanlines;
+}
+
+sub lonnet_putfile {
+ my ($contents,$filename)=@_;
+ my $docuname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};
+ my $docudom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
+ my $docuhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};
+ $ENV{'form.sillywaytopassafilearound'}=$contents;
+ &Apache::lonnet::finishuserfileupload($docuname,$docudom,$docuhome,'sillywaytopassafilearound',$filename);
+
+}
+
+sub scantron_putfile {
+ my ($scanlines) = @_;
+ #FIXME really would prefer a scantron directory but tokenwrapper
+ # doesn't allow access to subdirs of userfiles
+ my $prefix='/uploaded/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.'/'.
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.'/'.
+ 'scantron_';
+ 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'});
+}
+
+sub scantron_get_line {
+ my ($scanlines,$i)=@_;
+ if ($scanlines->{'skipped'}[$i]) {return undef;}
+ if ($scanlines->{'corrected'}[$i]) {return $scanlines->{'corrected'}[$i];}
+ return $scanlines->{'orig'}[$i];
+}
+
+sub scantron_put_line {
+ my ($scanlines,$i,$newline,$skip)=@_;
+ if ($skip) { $scanlines->{'skipped'}[$i]=$newline;return; }
+ $scanlines->{'corrected'}[$i]=$newline;
+}
+
+sub scantron_validate_ID {
+ my ($r,$currentphase) = @_;
+
+ #get student info
+ my $classlist=&Apache::loncoursedata::get_classlist();
+ my %idmap=&username_to_idmap($classlist);
+
+ #get scantron line setup
+ my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});
+ my $scanlines=&scantron_getfile();
+
+ my %found=('ids'=>{},'usernames'=>{});
+ for (my $i=0;$i<=$scanlines->{'count'};$i++) {
+ my $line=&scantron_get_line($scanlines,$i);
+ if (!$line) { next; }
+ my $scan_record=&scantron_parse_scanline($line,\%scantron_config);
+ my $id=$$scan_record{'scantron.ID'};
+ $r->print("Checking ID ".$$scan_record{'scantron.ID'}."
\n");
+ my $found;
+ foreach my $checkid (keys(%idmap)) {
+ if (lc($checkid) eq lc($id)) {
+ if ($checkid ne $id) {
+ $r->print("Using $checkid for bubbled $id
\n");
+ }
+ $found=$checkid;last;
+ }
+ }
+ if ($found) {
+ if ($found{'ids'}{$found}) {
+ #FIXME store away line we prviously saw the ID on
+ &scantron_get_ID_correction($r,$i,$scan_record,
+ 'duplicateID',$found);
+ return(1);
+ } else {
+ $found{'ids'}{$found}++;
+ }
+ } else {
+ &scantron_get_ID_correction($r,$i,$scan_record,'incorrectID');
+ return(1);
+ }
+ }
+
+ return (0,$currentphase+1);
+}
+
+sub scantron_get_ID_correction {
+ my ($r,$i,$scan_record,$error,$arg)=@_;
+#FIXME allow th poosibility of skipping a line, or in the case of a duplicated ID the previous line, probaly need to show both the current line and the previous one.
+ $r->print("need to correct ID
\n");
+ $r->print(' '."\n");
+ $r->print(' '."\n");
+ if ($error eq 'unknownID') {
+ $r->print(" Unknown ID
\n");
+ } elsif ($error eq 'duplicateID') {
+ $r->print(" Duplicated ID
\n");
+ }
+ $r->print("Original ID is ".$$scan_record{'scantron.ID'}."
\n");
+ $r->print("Name on paper is ".$$scan_record{'scantron.LastName'}.",".
+ $$scan_record{'scantron.FirstName'}."
");
+ $r->print("Corrected User -- ");
+ $r->print("\nusername: ");
+ $r->print("\ndomain:".
+ &Apache::loncommon::select_dom_form(undef,'scantron_domain'));
+ #FIXME it would be nice if this sent back the user ID and
+ #could do partial userID matches
+ $r->print(&Apache::loncommon::selectstudent_link('scantronupload',
+ 'scantron_username','scantron_domain'));
+ &scantron_end_validate_form($r);
+}
+
+sub scantron_end_validate_form {
+ my ($r) = @_;
+ $r->print('