'
+ .&mt('To '.lc($viewgrade)." a submission or a group of submissions, click on the check box(es) next to the student's name(s). Then click on the Next button.")."\n"
+ .' '
+ .'
';
# checkall buttons
$gradeTable.=&check_script('gradesub', 'stuinfo');
@@ -898,7 +962,6 @@ LISTJAVASCRIPT
'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n".
'value="'.&mt('Next').' →" /> $nsel;
- $endform.=&mt('[_1]student(s)',$ntstu);
+ $endform.=&mt('[quant,_1,student]',$ntstu);
$endform.=' '."\n".
' '."\n".
' '."\n";
- my $sectionClass;
- my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+ my ($common_header,$specific_header);
if ($env{'form.section'} eq 'all') {
- $sectionClass=&mt('Class');
+ $common_header = &mt('Assign Common Grade to Class');
+ $specific_header = &mt('Assign Grade to Specific Students in Class');
} elsif ($env{'form.section'} eq 'none') {
- $sectionClass=&mt('Students in no Section');
+ $common_header = &mt('Assign Common Grade to Students in no Section');
+ $specific_header = &mt('Assign Grade to Specific Students in no Section');
} else {
- $sectionClass=&mt('Students in Section(s) [_1]');
+ my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+ $common_header = &mt('Assign Common Grade to Students in Section(s) [_1]',$section_display);
+ $specific_header = &mt('Assign Grade to Specific Students in Section(s) [_1]',$section_display);
}
- $result.=
- ''.
- &mt("Assign Common Grade to [_1]",$sectionClass,$section_display).' ';
- $result.= &Apache::loncommon::start_data_table();
+ $result.= ''.$common_header.' '.&Apache::loncommon::start_data_table();
#radio buttons/text box for assigning points for a section or class.
#handles different parts of a problem
my ($partlist,$handgrade,$responseType) = &response_type($symb);
@@ -3243,12 +3306,11 @@ sub viewgrades {
#table listing all the students in a section/class
#header of table
- $result.= ''.&mt('Assign Grade to Specific Students in ').$sectionClass,
- $section_display.' ';
- $result.= &Apache::loncommon::start_data_table().
- &Apache::loncommon::start_data_table_header_row().
- ''.&mt('No.').' '.
- ''.&nameUserString('header')." \n";
+ $result.= ''.$specific_header.' '.
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ''.&mt('No.').' '.
+ ''.&nameUserString('header')." \n";
my (@parts) = sort(&getpartlist($symb));
my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
my @partids = ();
@@ -3426,7 +3488,7 @@ sub editgrades {
if ($part !~ m/^\Q$partid\E/) { next;}
if ($type eq 'awarded' || $type eq 'solved') { next; }
my $display=&Apache::lonnet::metadata($url,$stores.'.display');
- $display =~ s/\[Part: (\w)+\]//;
+ $display =~ s/\[Part: \Q$part\E\]//;
my $narrowtext = &mt('Tries');
$display =~ s/Number of Attempts/$narrowtext/;
$header .= ''.&mt('Old').' '.$display.' '.
@@ -3742,7 +3804,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 +4717,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 +4790,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 +4831,6 @@ sub restore_bubble_lines {
$env{"form.scantron.responsetype.$line"};
$line++;
}
-
}
# Given the parsed scanline, get the response for
@@ -4778,7 +4839,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 +5194,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 +5241,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 +5302,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 +5341,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 +5515,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 +5551,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')) {
@@ -6760,7 +6825,7 @@ ENDSCRIPT
".&mt("[_1]Select[_2] a CODE from the list of all CODEs and use it.",
""," ")."
- ".&mt("Selected CODE is [_1]"," "));
+ ".&mt("Selected CODE is [_1]",' '));
$r->print("\n ");
}
$r->print("
@@ -7234,15 +7299,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 +7366,7 @@ sub scantron_get_maxbubble {
}
}
}
- &Apache::lonnet::delenv('scantron\.');
+ &Apache::lonnet::delenv('scantron.');
&save_bubble_lines();
$env{'form.scantron_maxbubble'} =
@@ -7309,33 +7374,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 +7445,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 +7486,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 +7526,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 +7555,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 +7573,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 +7635,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 +7647,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 +7866,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);
@@ -8990,7 +9102,7 @@ sub handler {
} elsif ($command eq 'checksubmissions' && $perm{'vgr'}) {
$request->print(&checkscantron_results($request));
} elsif ($command) {
- $request->print("Access Denied ($command)");
+ $request->print(''.&mt('Access Denied ([_1])',$command).'
');
}
}
if ($ssi_error) {
@@ -9158,7 +9270,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