--- loncom/homework/grades.pm 2009/05/14 14:24:07 1.574 +++ loncom/homework/grades.pm 2011/10/09 15:31:12 1.655 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.574 2009/05/14 14:24:07 bisitz Exp $ +# $Id: grades.pm,v 1.655 2011/10/09 15:31:12 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -40,9 +40,11 @@ use Apache::lonhomework; use Apache::lonpickcode; use Apache::loncoursedata; use Apache::lonmsg(); -use Apache::Constants qw(:common); +use Apache::Constants qw(:common :http); use Apache::lonlocal; use Apache::lonenc; +use Apache::lonstathelpers; +use Apache::lonquickgrades; use String::Similarity; use LONCAPA; @@ -96,10 +98,19 @@ sub ssi_print_error { # # --- Retrieve the parts from the metadata file.--- +# Returns an array of everything that the resources stores away +# + sub getpartlist { - my ($symb) = @_; + my ($symb,$errorref) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + if (ref($errorref)) { + $$errorref = 'navmap'; + return; + } + } my $res = $navmap->getBySymb($symb); my $partlist = $res->parts(); my $url = $res->src(); @@ -114,21 +125,6 @@ sub getpartlist { return @stores; } -# --- Get the symbolic name of a problem and the url -sub get_symb { - my ($request,$silent) = @_; - (my $url=$env{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; - my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url))); - if ($symb eq '') { - if (!$silent) { - $request->print("Unable to handle ambiguous references:$url:."); - return (); - } - } - &Apache::lonenc::check_decrypt(\$symb); - return ($symb); -} - #--- Format fullname, username:domain if different for display #--- Use anywhere where the student names are listed sub nameUserString { @@ -143,11 +139,22 @@ sub nameUserString { #--- Get the partlist and the response type for a given problem. --- #--- Indicate if a response type is coded handgraded or not. --- +#--- Sets response_error pointer to "1" if navmaps object broken --- sub response_type { - my ($symb) = shift; + my ($symb,$response_error) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + if (ref($response_error)) { + $$response_error = 1; + } + return; + } my $res = $navmap->getBySymb($symb); + unless (ref($res)) { + $$response_error = 1; + return; + } my $partlist = $res->parts(); my %vPart = map { $_ => 1 } (&Apache::loncommon::get_env_multiple('form.vPart')); @@ -183,50 +190,14 @@ sub get_display_part { my ($partID,$symb)=@_; my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',$symb); if (defined($display) and $display ne '') { - $display.= " (id $partID)"; + $display.= ' (' + .&mt('Part ID: [_1]',$partID).')'; } else { $display=$partID; } return $display; } -#--- Show resource title -#--- and parts and response type -sub showResourceInfo { - my ($symb,$probTitle,$checkboxes) = @_; - my $col=3; - if ($checkboxes) { $col=4; } - my $result = '
"; - } else { - $result.=" | "; - } - $partsseen{$partID}=1; - } - my $display_part=&get_display_part($partID,$symb); - $result.=' | '.&mt('Part').': '.$display_part. - ' '.$resID.' | '. - ''.&mt('Type').': '.$responsetype.' | '.&mt('Handgrade: [_1]',$handgrade).' | '; - } - } - $result.='
'; + $bottomrow.''.''; } elsif ($response eq 'essay') { if (! exists ($env{'form.'.$symb})) { my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade', @@ -458,8 +445,7 @@ sub cleanRecord { #-- A couple of common js functions sub commonJSfunctions { my $request = shift; - $request->print(<'. '
'. ' '.&mt('Answer').' '.$toprow.''.' '.$grayFont.&mt('Option ID').' '. - $grayFont.$bottomrow.'
' + .&mt('No match found for the above receipt number.') + .'
'; } else { $string = &jscriptNform($symb).$title. ''. - &mt('The above receipt matches the following [numerate,_1,student].',$matches). + &mt('The above receipt number matches the following [quant,_1,student].',$matches). '
'. $header. $contents. &Apache::loncommon::end_data_table()."\n"; } - return $string.&show_grading_menu_form($symb); + return $string; } #--- This is called by a number of programs. @@ -826,30 +827,25 @@ sub verifyreceipt { #--- Also called directly when one clicks on the subm button # on the problem page. sub listStudents { - my ($request) = shift; + my ($request,$symb,$submitonly) = @_; - my ($symb) = &get_symb($request); my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'}; my $getgroup = $env{'form.group'} eq '' ? 'all' : $env{'form.group'}; - my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'}; - my $viewgrade = $env{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View'; - $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? - &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'}; - - my $result='');
pDoc.write('
'; + if (!exists($orders{$partid})) { $orders{$partid}={}; } + if ((!exists($orders{$partid}->{$responseId})) || ($trial)) { + $orders{$partid}->{$responseId}= + &get_order($partid,$responseId,$symb,$uname,$udom, + $no_increment,$type,$trial,$rndseed); + } + $displaySub[0].=''.$newvariation.''; # /nobreak + $displaySub[0].=' '. + &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom,$type,$trial,$rndseed).' '; + } } } if (exists($$record{"$where.$partid.checkedin"})) { @@ -4524,7 +4649,7 @@ sub displaySubByDates { } sub updateGradeByPage { - my ($request) = shift; + my ($request,$symb) = @_; my $cdom = $env{"course.$env{'request.course.id'}.domain"}; my $cnum = $env{"course.$env{'request.course.id'}.num"}; @@ -4535,7 +4660,6 @@ sub updateGradeByPage { my $usec=$classlist->{$env{'form.student'}}[5]; if (!&canmodify($usec)) { $request->print(''.&mt('Unable to modify requested student ([_1])',$env{'form.student'}).''); - $request->print(&show_grading_menu_form($env{'form.symb'})); return; } my $result=' '.$env{'form.title'}.''; @@ -4544,13 +4668,16 @@ sub updateGradeByPage { $request->print($result); + my $navmap = Apache::lonnavmaps::navmap->new(); + unless (ref($navmap)) { + $request->print(&navmap_errormsg()); + return; + } my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps if (!$map) { $request->print(''.&mt('Unable to grade requested sequence ([_1]).',$resUrl).''); - my ($symb)=&get_symb($request); - $request->print(&show_grading_menu_form($symb)); return; } my $iterator = $navmap->getIterator($map->map_start(), @@ -4580,7 +4707,7 @@ sub updateGradeByPage { &Apache::loncommon::start_data_table_row(). ' | '.$prob.
(scalar(@{$parts}) == 1 ? ''
- : ' ('.&mt('[quant,_1, part]',scalar(@{$parts})) + : ' ('.&mt('[quant,_1,part]',scalar(@{$parts})) .')').' | ';
$studentTable.=''.$title.' | '; @@ -4676,7 +4803,6 @@ sub updateGradeByPage { } $studentTable.=&Apache::loncommon::end_data_table(); - $studentTable.=&show_grading_menu_form($env{'form.symb'}); my $grademsg=($changeflag == 0 ? &mt('No score was changed or updated.') : &mt('The scores were changed for [quant,_1,problem].', $changeflag)); @@ -4689,7 +4815,7 @@ sub updateGradeByPage { # #------------------------------------------------------------------- -#--------------------Scantron Grading----------------------------------- +#-------------------- Bubblesheet (Scantron) Grading ------------------- # #------ start of section for handling grading by page/sequence --------- @@ -4754,9 +4880,7 @@ the homework problem. sub defaultFormData { my ($symb)=@_; - return ''."\n". - ''."\n". - ''."\n"; + return ''; } @@ -4767,14 +4891,19 @@ sub defaultFormData { Return html dropdown of possible sequences to grade Arguments: - $symb - $symb of the current resource + $symb - $symb of the current resource + $map_error - ref to scalar which will container error if + $navmap object is unavailable in &getSymbMap(). =cut sub getSequenceDropDown { - my ($symb)=@_; + my ($symb,$map_error)=@_; my $result='
'.&mt('If this information is correct, please click on \'[_1]\'.',&mt($button_text)).'
-'.&mt('If something is incorrect, please click the \'Grading Menu\' button to start over.').'
+ '.&mt('If this information is correct, please click on \'[_1]\'.',&mt($button_text)).'
+'.&mt('If something is incorrect, please return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','','').'
".&mt('You have forgetten to specify some information. Please go Back and try again.')."
"); + $r->print("".&mt('You have forgotten to specify some information. Please go Back and try again.')."
"); if ( $env{'form.selectpage'} eq '') { $r->print(''.&mt('You have not selected a Sequence to grade').'
'); } if ( $env{'form.scantron_selectfile'} eq '') { - $r->print(''.&mt('You have not selected a file that contains the student\'s response data.').'
'); + $r->print(''.&mt("You have not selected a file that contains the student's response data.").'
'); } if ( $env{'form.scantron_format'} eq '') { - $r->print(''.&mt('You have not selected a the format of the student\'s response data.').'
'); + $r->print(''.&mt("You have not selected the format of the student's response data.").'
'); } } else { - my $warning=&scantron_warning_screen('Grading: Validate Records'); + my $warning=&scantron_warning_screen('Grading: Validate Records',$symb); $r->print(' '.$warning.' '); } - $r->print("'.&mt('Gathering necessary information.').'
');$r->rflush(); #get the student pick code ready $r->print(&Apache::loncommon::studentbrowser_javascript()); - my $max_bubble=&scantron_get_maxbubble(); + my $nav_error; + my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); + my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config); + if ($nav_error) { + $r->print(&navmap_errormsg()); + return ''; + } my $result=&scantron_form_start($max_bubble).$default_form_data; $r->print($result); @@ -6240,7 +6376,7 @@ sub scantron_validate_file { } } if (!$stop) { - my $warning=&scantron_warning_screen('Start Grading'); + my $warning=&scantron_warning_screen('Start Grading',$symb); $r->print(&mt('Validation process complete.').'".&mt("Or click the 'Grading Menu' button to start over.")."
"); + $r->print(''.&mt('Or return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','','').'
'); } else { if ($validate_phases[$currentphase] eq 'doublebubble' || $validate_phases[$currentphase] eq 'missingbubbles') { $r->print(''); @@ -6274,7 +6410,7 @@ sub scantron_validate_file { $r->print(" ".&mt("this scanline saving it for later.")); } } - $r->print("took $lasttime
"); $r->print(""); - $r->print(&show_grading_menu_form($symb)); return ''; } sub graders_resources_pass { - my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb) = @_; + my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb, + $bubbles_per_row) = @_; 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); + $env{'user.name'},$env{'user.domain'},1,$bubbles_per_row); $grader_partids_by_symb->{$ressymb} = $parts; if (ref($analysis) eq 'HASH') { if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') { @@ -7668,7 +7888,8 @@ sub graders_resources_pass { } sub grade_student_bubbles { - my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts) = @_; + my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts,$bubbles_per_row) = @_; +# Walk folder as student here to get resources in order student sees. if (ref($resources) eq 'ARRAY') { my $count = 0; foreach my $resource (@{$resources}) { @@ -7681,6 +7902,9 @@ sub grade_student_bubbles { 'grade_symb' => $ressymb, 'CODE' => $scancode ); + if ($bubbles_per_row ne '') { + $form{'bubbles_per_row'} = $bubbles_per_row; + } if (ref($parts) eq 'HASH') { if (ref($parts->{$ressymb}) eq 'ARRAY') { foreach my $part (@{$parts->{$ressymb}}) { @@ -7699,7 +7923,7 @@ sub grade_student_bubbles { } sub scantron_upload_scantron_data { - my ($r)=@_; + my ($r,$symb)=@_; my $dom = $env{'request.role.domain'}; my $domdesc = &Apache::lonnet::domain($dom,'description'); $r->print(&Apache::loncommon::coursebrowser_javascript($dom)); @@ -7708,16 +7932,17 @@ sub scantron_upload_scantron_data { 'coursename',$dom); my $syllabuslink = ''.&mt('Syllabus').''. (' 'x2).&mt('(shows course personnel)'); - my $default_form_data=&defaultFormData(&get_symb($r,1)); - $r->print(' - - -'.&mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [quant,_1,student] ([_2] scantron lines/student).',$numstudents,$env{'form.scantron_maxbubble'}).'
'); + $r->print( + '' + .&mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).', + '', + $numstudents, + '', + $env{'form.scantron_maxbubble'}) + .'
' + ); $r->print(''.&mt('Exact matches for [quant,_1,student].',$passed).'
'.&mt('Discrepancies detected for [quant,_1,student].',$failed).'
'."\n";
- $result.='
|
-
|
-
|
'.&mt('Access Denied ([_1])',$command).'
'); } } if ($ssi_error) { &ssi_print_error($request); } + &Apache::lonquickgrades::endGradeScreen($request); $request->print(&Apache::loncommon::end_page()); &reset_caches(); - return ''; + return OK; } 1; @@ -9308,6 +9591,15 @@ ssi_with_retries() =item scantron_get_maxbubble() : + Arguments: + $nav_error - Reference to scalar which is a flag to indicate a + failure to retrieve a navmap object. + if $nav_error is set to 1 by scantron_get_maxbubble(), the + calling routine should trap the error condition and display the warning + found in &navmap_errormsg(). + + $scantron_config - Reference to bubblesheet format configuration hash. + 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() @@ -9373,6 +9665,11 @@ ssi_with_retries() Validates all scanlines in the selected file to not have any invalid or underspecified student/employee IDs +=item navmap_errormsg() : + + Returns HTML mark-up inside a with a link to re-initialize the course. + Should be called whenever the request to instantiate a navmap object fails. + =back =cut