$nsel;
- $endform.=&mt('[_1]student(s)',$ntstu);
+ $endform.=&mt('[quant,_1,student]',$ntstu);
$endform.=' '."\n".
' '.
@@ -3742,7 +3797,7 @@ ENDPICK
sub csvupload_fields {
my ($symb) = @_;
my (@parts) = &getpartlist($symb);
- my @fields=(['ID','Student ID'],
+ my @fields=(['ID','Student/Employee ID'],
['username','Student Username'],
['domain','Student Domain']);
my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);
@@ -4655,10 +4710,10 @@ Next each scanline is checked for any er
bubbles' (it's an error because it may have been mis-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
+invalid student/employee 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
+homework problems, either way the student/employee ID is looked up into a
username:domain.
During the validation phase the instructor can choose to skip scanlines.
@@ -4728,7 +4783,7 @@ sub getSequenceDropDown {
}
my %bubble_lines_per_response; # no. bubble lines for each response.
- # index is "symb.part_id"
+ # key is zero-based index - 0, 1, 2 ...
my %first_bubble_line; # First bubble line no. for each bubble.
@@ -4769,7 +4824,6 @@ sub restore_bubble_lines {
$env{"form.scantron.responsetype.$line"};
$line++;
}
-
}
# Given the parsed scanline, get the response for
@@ -4778,7 +4832,6 @@ sub restore_bubble_lines {
sub get_response_bubbles {
my ($parsed_line, $response) = @_;
-
my $bubble_line = $first_bubble_line{$response-1} +1;
my $bubble_lines= $bubble_lines_per_response{$response-1};
@@ -5134,6 +5187,10 @@ sub scantron_selectphase {
' '.$format_selector.' '."\n".
&Apache::loncommon::end_data_table_row()."\n".
&Apache::loncommon::start_data_table_row()."\n".
+ ' '.&mt('Options').' '."\n".
+ ' '.&mt('Skip hidden resources').' '.
+ &Apache::loncommon::end_data_table_row()."\n".
+ &Apache::loncommon::start_data_table_row()."\n".
''."\n".
' '."\n".
' '."\n".
@@ -5177,8 +5234,8 @@ sub scantron_selectphase {
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
+ IDstart - column where the student/employee ID number starts
+ IDlength - length of the student/employee ID info
Qstart - column where the information from the bubbled
'questions' start
Qlength - number of columns comprising a single bubble line from
@@ -5238,7 +5295,7 @@ sub get_scantron_config {
=item username_to_idmap
- creates a hash keyed by student id with values of the corresponding
+ creates a hash keyed by student/employee ID with values of the corresponding
student username:domain.
Arguments:
@@ -5277,7 +5334,7 @@ sub username_to_idmap {
$whichline - line number of the passed in scanline
$field - type of change to process
(either
- 'ID' -> correct the student ID number
+ 'ID' -> correct the student/employee ID number
'CODE' -> correct the CODE
'answer' -> fixup the submitted answers)
@@ -5451,7 +5508,7 @@ sub digits_to_letters {
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
+ ID - student/employee ID
PaperID - if used, the ID number printed on the sheet when the
paper was scanned
FirstName - first name from the sheet
@@ -5487,7 +5544,8 @@ sub scantron_parse_scanline {
my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;
my %record;
- my $questions=substr($line,$$scantron_config{'Qstart'}-1); # Answers
+ my $lastpos = $env{'form.scantron_maxbubble'}*$$scantron_config{'Qlength'};
+ my $questions=substr($line,$$scantron_config{'Qstart'}-1,$lastpos); # Answers
my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff
if (!($$scantron_config{'CODElocation'} eq 0 ||
$$scantron_config{'CODElocation'} eq 'none')) {
@@ -7234,15 +7292,15 @@ sub scantron_get_maxbubble {
&Apache::lonxml::clear_problem_counter();
- my $uname = $env{'form.student'};
- my $udom = $env{'form.userdom'};
+ my $uname = $env{'user.name'};
+ my $udom = $env{'user.domain'};
my $cid = $env{'request.course.id'};
my $total_lines = 0;
%bubble_lines_per_response = ();
%first_bubble_line = ();
%subdivided_bubble_lines = ();
%responsetype_per_response = ();
-
+
my $response_number = 0;
my $bubble_line = 0;
foreach my $resource (@resources) {
@@ -7301,7 +7359,7 @@ sub scantron_get_maxbubble {
}
}
}
- &Apache::lonnet::delenv('scantron\.');
+ &Apache::lonnet::delenv('scantron.');
&save_bubble_lines();
$env{'form.scantron_maxbubble'} =
@@ -7309,33 +7367,6 @@ sub scantron_get_maxbubble {
return $env{'form.scantron_maxbubble'};
}
-sub scantron_partids_tograde {
- my ($resource,$cid,$uname,$udom) = @_;
- my (%analysis,@parts);
-
- if (ref($resource)) {
- my $symb = $resource->symb();
- my $result=&ssi_with_retries($resource->src(), $ssi_retries,
- ('symb' => $symb,
- 'grade_target' => 'analyze',
- 'grade_courseid' => $cid,
- 'grade_domain' => $udom,
- 'grade_username' => $uname));
- my (undef, $an) = split(/_HASH_REF__/,$result, 2);
- %analysis = &Apache::lonnet::str2hash($an);
-
- if (ref($analysis{'parts'}) eq 'ARRAY') {
- foreach my $part (@{$analysis{'parts'}}) {
- my ($id,$respid) = split(/\./,$part);
- if (!&Apache::loncommon::check_if_partid_hidden($id,$symb,$udom,$uname)) {
- push(@parts,$part);
- }
- }
- }
- }
- return (\%analysis,\@parts);
-}
-
sub scantron_validate_missingbubbles {
my ($r,$currentphase) = @_;
#get student info
@@ -7407,15 +7438,24 @@ sub scantron_process_students {
my $navmap=Apache::lonnavmaps::navmap->new();
my $map=$navmap->getResourceByUrl($sequence);
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
-
- my ($uname,$udom,%partids_by_symb);
+ my (%grader_partids_by_symb,%grader_randomlists_by_symb);
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb);
foreach my $resource (@resources) {
- my $ressymb = $resource->symb();
- my ($analysis,$parts) =
- &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom);
- $partids_by_symb{$ressymb} = $parts;
+ my $ressymb = $resource->symb();
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $env{'user.name'},$env{'user.domain'},1);
+ $grader_partids_by_symb{$ressymb} = $parts;
+ if (ref($analysis) eq 'HASH') {
+ if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') {
+ $grader_randomlists_by_symb{$ressymb} =
+ $analysis->{'parts_withrandomlist'};
+ }
+ }
}
-# $r->print("geto ".scalar(@resources)." ");
+
+ my ($uname,$udom);
my $result= <
@@ -7439,7 +7479,6 @@ SCANTRONFORM
my $started;
&scantron_get_maxbubble(); # Need the bubble lines array to parse.
-
# If an ssi failed in scantron_get_maxbubble, put an error message out to
# the user and return.
@@ -7480,6 +7519,19 @@ SCANTRONFORM
}
($uname,$udom)=split(/:/,$uname);
+ my %partids_by_symb;
+ foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
+ if ((exists($grader_randomlists_by_symb{$ressymb})) ||
+ (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) {
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom);
+ $partids_by_symb{$ressymb} = $parts;
+ } else {
+ $partids_by_symb{$ressymb} = $grader_partids_by_symb{$ressymb};
+ }
+ }
+
&Apache::lonxml::clear_problem_counter();
&Apache::lonnet::appenv($scan_record);
@@ -7496,7 +7548,7 @@ SCANTRONFORM
}
if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
- @resources) eq 'ssi_error') {
+ \@resources,\%partids_by_symb) eq 'ssi_error') {
$ssi_error = 0; # So end of handler error message does not trigger.
$r->print("");
&ssi_print_error($r);
@@ -7514,19 +7566,32 @@ SCANTRONFORM
my $studentrecord = '';
my $counter = -1;
foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
($counter,my $recording) =
&verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
- $counter,$studentdata,\%partids_by_symb,
+ $counter,$studentdata,$partids_by_symb{$ressymb},
\%scantron_config,\%lettdig,$numletts);
$studentrecord .= $recording;
}
if ($studentrecord ne $studentdata) {
+ &Apache::lonxml::clear_problem_counter();
+ if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
+ \@resources,\%partids_by_symb) eq 'ssi_error') {
+ $ssi_error = 0; # So end of handler error message does not trigger.
+ $r->print("");
+ &ssi_print_error($r);
+ $r->print(&show_grading_menu_form($symb));
+ &Apache::lonnet::remove_lock($lock);
+ delete($completedstudents{$uname});
+ return '';
+ }
$counter = -1;
$studentrecord = '';
foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
($counter,my $recording) =
&verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
- $counter,$studentdata,\%partids_by_symb,
+ $counter,$studentdata,$partids_by_symb{$ressymb},
\%scantron_config,\%lettdig,$numletts);
$studentrecord .= $recording;
}
@@ -7563,7 +7628,7 @@ SCANTRONFORM
if (&Apache::loncommon::connection_aborted($r)) { last; }
} continue {
&Apache::lonxml::clear_problem_counter();
- &Apache::lonnet::delenv('scantron\.');
+ &Apache::lonnet::delenv('scantron.');
}
&Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
&Apache::lonnet::remove_lock($lock);
@@ -7575,19 +7640,54 @@ SCANTRONFORM
return '';
}
+sub graders_resources_pass {
+ my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb) = @_;
+ if ((ref($resources) eq 'ARRAY') && (ref($grader_partids_by_symb)) &&
+ (ref($grader_randomlists_by_symb) eq 'HASH')) {
+ foreach my $resource (@{$resources}) {
+ my $ressymb = $resource->symb();
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $env{'user.name'},$env{'user.domain'},1);
+ $grader_partids_by_symb->{$ressymb} = $parts;
+ if (ref($analysis) eq 'HASH') {
+ if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') {
+ $grader_randomlists_by_symb->{$ressymb} =
+ $analysis->{'parts_withrandomlist'};
+ }
+ }
+ }
+ }
+ return;
+}
+
sub grade_student_bubbles {
- my ($r,$uname,$udom,$scan_record,$scancode,@resources) = @_;
- foreach my $resource (@resources) {
- my %form = ('submitted' => 'scantron',
- 'grade_target' => 'grade',
- 'grade_username'=> $uname,
- 'grade_domain' => $udom,
- 'grade_courseid'=> $env{'request.course.id'},
- 'grade_symb' => $resource->symb(),
- 'CODE' => $scancode);
- my $result=&ssi_with_retries($resource->src(),$ssi_retries,%form);
- return 'ssi_error' if ($ssi_error);
- last if (&Apache::loncommon::connection_aborted($r));
+ my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts) = @_;
+ if (ref($resources) eq 'ARRAY') {
+ my $count = 0;
+ foreach my $resource (@{$resources}) {
+ my $ressymb = $resource->symb();
+ my %form = ('submitted' => 'scantron',
+ 'grade_target' => 'grade',
+ 'grade_username' => $uname,
+ 'grade_domain' => $udom,
+ 'grade_courseid' => $env{'request.course.id'},
+ 'grade_symb' => $ressymb,
+ 'CODE' => $scancode
+ );
+ if (ref($parts) eq 'HASH') {
+ if (ref($parts->{$ressymb}) eq 'ARRAY') {
+ foreach my $part (@{$parts->{$ressymb}}) {
+ $form{'scantron_questnum_start.'.$part} =
+ 1+$env{'form.scantron.first_bubble_line.'.$count};
+ $count++;
+ }
+ }
+ }
+ my $result=&ssi_with_retries($resource->src(),$ssi_retries,%form);
+ return 'ssi_error' if ($ssi_error);
+ last if (&Apache::loncommon::connection_aborted($r));
+ }
}
return;
}
@@ -7759,14 +7859,11 @@ sub checkscantron_results {
my %idmap=&Apache::grades::username_to_idmap($classlist);
my $navmap=Apache::lonnavmaps::navmap->new();
my $map=$navmap->getResourceByUrl($sequence);
- my @resources=$navmap->retrieveResources($map,undef,1,0);
- my ($uname,$udom,%partids_by_symb);
- foreach my $resource (@resources) {
- my $ressymb = $resource->symb();
- my ($analysis,$parts) =
- &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom);
- $partids_by_symb{$ressymb} = $parts;
- }
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ my (%grader_partids_by_symb,%grader_randomlists_by_symb);
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb, \%grader_randomlists_by_symb);
+
+ my ($uname,$udom);
my (%scandata,%lastname,%bylast);
$r->print('
'."\n".
' '."\n";
return $result.&show_grading_menu_form($symb);
@@ -9158,7 +9263,7 @@ ssi_with_retries()
=item scantron_validate_ID() :
Validates all scanlines in the selected file to not have any
- invalid or underspecified student IDs
+ invalid or underspecified student/employee IDs
=back