--- loncom/homework/grades.pm 2008/06/24 18:54:36 1.524 +++ loncom/homework/grades.pm 2008/11/11 16:40:47 1.529 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.524 2008/06/24 18:54:36 raeburn Exp $ +# $Id: grades.pm,v 1.529 2008/11/11 16:40:47 jms Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,6 +26,183 @@ # http://www.lon-capa.org/ # +=head1 NAME + +Apache::grades + +=head1 SYNOPSIS + +Handles the viewing of grades. + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 OVERVIEW + +Do an ssi with retries: +While I'd love to factor out this with the vesrion in lonprintout, +that would either require a data coupling between modules, which I refuse to perpetuate (there's quite enough of that already), or would require the invention of another infrastructure +I'm not quite ready to invent (e.g. an ssi_with_retry object). + +At least the logic that drives this has been pulled out into loncommon. + + + +ssi_with_retries - Does the server side include of a resource. + if the ssi call returns an error we'll retry it up to + the number of times requested by the caller. + If we still have a proble, no text is appended to the + output and we set some global variables. + to indicate to the caller an SSI error occurred. + All of this is supposed to deal with the issues described + in LonCAPA BZ 5631 see: + http://bugs.lon-capa.org/show_bug.cgi?id=5631 + by informing the user that this happened. + +Parameters: + resource - The resource to include. This is passed directly, without + interpretation to lonnet::ssi. + form - The form hash parameters that guide the interpretation of the resource + + retries - Number of retries allowed before giving up completely. +Returns: + On success, returns the rendered resource identified by the resource parameter. +Side Effects: + The following global variables can be set: + ssi_error - If an unrecoverable error occurred this becomes true. + It is up to the caller to initialize this to false + if desired. + ssi_error_resource - If an unrecoverable error occurred, this is the value + of the resource that could not be rendered by the ssi + call. + ssi_error_message - The error string fetched from the ssi response + in the event of an error. + + +=head1 HANDLER SUBROUTINE + +ssi_with_retries() + +=head1 OTHER SUBROUTINES + +=over + +=item * + + +scantron_get_correction() : + + Builds the interface screen to interact with the operator to fix a + specific error condition in a specific scanline + + Arguments: + $r - Apache request object + $i - number of the current scanline + $scan_record - hash ref as returned from &scantron_parse_scanline() + $scan_config - hash ref as returned from &get_scantron_config() + $line - full contents of the current scanline + $error - error condition, valid values are + 'incorrectCODE', 'duplicateCODE', + 'doublebubble', 'missingbubble', + 'duplicateID', 'incorrectID' + $arg - extra information needed + For errors: + - duplicateID - paper number that this studentID was seen before on + - duplicateCODE - array ref of the paper numbers this CODE was + seen on before + - incorrectCODE - current incorrect CODE + - doublebubble - array ref of the bubble lines that have double + bubble errors + - missingbubble - array ref of the bubble lines that have missing + bubble errors + +=item * + +scantron_get_maxbubble() : + + 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() + for what the current value of the problem counter is. + + Caches the results to $env{'form.scantron_maxbubble'}, + $env{'form.scantron.bubble_lines.n'}, + $env{'form.scantron.first_bubble_line.n'} and + $env{"form.scantron.sub_bubblelines.n"} + which are the total number of bubble, lines, the number of bubble + lines for response n and number of the first bubble line for response n, + and a comma separated list of numbers of bubble lines for sub-questions + (for optionresponse, matchresponse, and rankresponse items), for response n. + + +=item * + +scantron_validate_missingbubbles() : + + Validates all scanlines in the selected file to not have any + answers that don't have bubbles that have not been verified + to be bubble free. + +=item * + +scantron_process_students() : + + Routine that does the actual grading of the bubble sheet information. + + The parsed scanline hash is added to %env + + Then foreach unskipped scanline it does an &Apache::lonnet::ssi() + foreach resource , with the form data of + + 'submitted' =>'scantron' + 'grade_target' =>'grade', + 'grade_username'=> username of student + 'grade_domain' => domain of student + 'grade_courseid'=> of course + 'grade_symb' => symb of resource to grade + + This triggers a grading pass. The problem grading code takes care + of converting the bubbled letter information (now in %env) into a + valid submission. + +=item * + +scantron_upload_scantron_data() : + + Creates the screen for adding a new bubble sheet data file to a course. + +=item * + +scantron_upload_scantron_data_save() : + + Adds a provided bubble information data file to the course if user + has the correct privileges to do so. + +=item * + +valid_file() : + + Validates that the requested bubble data file exists in the course. + +=item * + +scantron_download_scantron_data() : + + Shows a list of the three internal files (original, corrected, + skipped) for a specific bubble sheet data file that exists in the + course. + +=item * + +scantron_validate_ID() : + + Validates all scanlines in the selected file to not have any + invalid or underspecified student IDs + +=back + +=cut + package Apache::grades; use strict; use Apache::style; @@ -58,46 +235,6 @@ my $ssi_error_resource; my $ssi_error_message; -# Do an ssi with retries: -# While I'd love to factor out this with the vesrion in lonprintout, -# that would either require a data coupling between modules, which I refuse to perpetuate -# (there's quite enough of that already), or would require the invention of another infrastructure -# I'm not quite ready to invent (e.g. an ssi_with_retry object). -# -# At least the logic that drives this has been pulled out into loncommon. - - -# -# ssi_with_retries - Does the server side include of a resource. -# if the ssi call returns an error we'll retry it up to -# the number of times requested by the caller. -# If we still have a proble, no text is appended to the -# output and we set some global variables. -# to indicate to the caller an SSI error occurred. -# All of this is supposed to deal with the issues described -# in LonCAPA BZ 5631 see: -# http://bugs.lon-capa.org/show_bug.cgi?id=5631 -# by informing the user that this happened. -# -# Parameters: -# resource - The resource to include. This is passed directly, without -# interpretation to lonnet::ssi. -# form - The form hash parameters that guide the interpretation of the resource -# -# retries - Number of retries allowed before giving up completely. -# Returns: -# On success, returns the rendered resource identified by the resource parameter. -# Side Effects: -# The following global variables can be set: -# ssi_error - If an unrecoverable error occurred this becomes true. -# It is up to the caller to initialize this to false -# if desired. -# ssi_error_resource - If an unrecoverable error occurred, this is the value -# of the resource that could not be rendered by the ssi -# call. -# ssi_error_message - The error string fetched from the ssi response -# in the event of an error. -# sub ssi_with_retries { my ($resource, $retries, %form) = @_; my ($content, $response) = &Apache::loncommon::ssi_with_retries($resource, $retries, %form); @@ -278,7 +415,7 @@ sub reset_caches { } sub get_analyze { - my ($symb,$uname,$udom)=@_; + my ($symb,$uname,$udom,$no_increment)=@_; my $key = "$symb\0$uname\0$udom"; return $analyze_cache{$key} if (exists($analyze_cache{$key})); @@ -290,15 +427,16 @@ sub reset_caches { 'grade_symb' => $symb, 'grade_courseid' => $env{'request.course.id'}, - 'grade_username' => $uname)); + 'grade_username' => $uname, + 'grade_noincrement' => $no_increment)); (undef,$subresult)=split(/_HASH_REF__/,$subresult,2); my %analyze=&Apache::lonnet::str2hash($subresult); return $analyze_cache{$key} = \%analyze; } sub get_order { - my ($partid,$respid,$symb,$uname,$udom)=@_; - my $analyze = &get_analyze($symb,$uname,$udom); + my ($partid,$respid,$symb,$uname,$udom,$no_increment)=@_; + my $analyze = &get_analyze($symb,$uname,$udom,$no_increment); return $analyze->{"$partid.$respid.shown"}; } @@ -4410,6 +4548,7 @@ sub displaySubByDates { } my $interaction; + my $no_increment = 1; for ($version=1;$version<=$$record{'version'};$version++) { my $timestamp = &Apache::lonlocal::locallocaltime($$record{$version.':timestamp'}); @@ -4453,7 +4592,8 @@ sub displaySubByDates { if (!exists($orders{$partid})) { $orders{$partid}={}; } if (!exists($orders{$partid}->{$responseId})) { $orders{$partid}->{$responseId}= - &get_order($partid,$responseId,$symb,$uname,$udom); + &get_order($partid,$responseId,$symb,$uname,$udom, + $no_increment); } $displaySub[0].='  '. &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).'
'; @@ -4506,12 +4646,12 @@ sub updateGradeByPage { my ($uname,$udom) = split(/:/,$env{'form.student'}); my $usec=$classlist->{$env{'form.student'}}[5]; if (!&canmodify($usec)) { - $request->print('Unable to modify requested student.('.$env{'form.student'}.''); + $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'}.'

'; - $result.='

 Student: '.&nameUserString(undef,$env{'form.fullname'},$uname,$udom). + $result.='

 '.&mt('Student: ').&nameUserString(undef,$env{'form.fullname'},$uname,$udom). '

'."\n"; $request->print($result); @@ -4520,7 +4660,7 @@ sub updateGradeByPage { my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'}); my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps if (!$map) { - $request->print('Unable to grade requested sequence. ('.$resUrl.')'); + $request->print(''.&mt('Unable to grade requested sequence ([_1]).',$resUrl).''); my ($symb)=&get_symb($request); $request->print(&show_grading_menu_form($symb)); return; @@ -4552,8 +4692,8 @@ sub updateGradeByPage { &Apache::loncommon::start_data_table_row(). ''.$prob. (scalar(@{$parts}) == 1 ? '' - : '
('.&mt('[quant,_1, parts]',scalar(@{$parts})) - ).')'; + : '
('.&mt('[quant,_1, part]',scalar(@{$parts})) + .')').''; $studentTable.=' '.$title.' '; my %newrecord=(); @@ -4597,10 +4737,10 @@ sub updateGradeByPage { } my $display_part=&get_display_part($partid,$curRes->symb()); my $oldstatus = $env{'form.solved'.$question.'_'.$partid}; - $displayPts[0].=' Part: '.$display_part.' = '. + $displayPts[0].=' '.&mt('Part').': '.$display_part.' = '. (($oldstatus eq 'excused') ? 'excused' : $oldpts). ' 
'; - $displayPts[1].=' Part: '.$display_part.' = '. + $displayPts[1].=' '.&mt('Part').': '.$display_part.' = '. (($score eq 'excused') ? 'excused' : $newpts). ' 
'; $question++; @@ -4649,9 +4789,9 @@ sub updateGradeByPage { $studentTable.=&Apache::loncommon::end_data_table(); $studentTable.=&show_grading_menu_form($env{'form.symb'}); - my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' : - 'The scores were changed for '. - $changeflag.' problem'.($changeflag == 1 ? '.' : 's.')); + my $grademsg=($changeflag == 0 ? &mt('No score was changed or updated.') : + &mt('The scores were changed for [quant,_1,problem].', + $changeflag)); $request->print($grademsg.$studentTable); return ''; @@ -5146,7 +5286,7 @@ sub scantron_selectphase { &Apache::lonpickcode::code_list($r,2); - $r>print('
'. + $r->print('
'. $default_form_data."\n". &Apache::loncommon::start_data_table('LC_scantron_action')."\n". &Apache::loncommon::start_data_table_header_row()."\n". @@ -6608,14 +6748,7 @@ sub scantron_validate_sequence { return (0,$currentphase+1); } -=pod - -=item scantron_validate_ID - Validates all scanlines in the selected file to not have any - invalid or underspecified student IDs - -=cut sub scantron_validate_ID { my ($r,$currentphase) = @_; @@ -6681,35 +6814,6 @@ sub scantron_validate_ID { return (0,$currentphase+1); } -=pod - -=item scantron_get_correction - - Builds the interface screen to interact with the operator to fix a - specific error condition in a specific scanline - - Arguments: - $r - Apache request object - $i - number of the current scanline - $scan_record - hash ref as returned from &scantron_parse_scanline() - $scan_config - hash ref as returned from &get_scantron_config() - $line - full contents of the current scanline - $error - error condition, valid values are - 'incorrectCODE', 'duplicateCODE', - 'doublebubble', 'missingbubble', - 'duplicateID', 'incorrectID' - $arg - extra information needed - For errors: - - duplicateID - paper number that this studentID was seen before on - - duplicateCODE - array ref of the paper numbers this CODE was - seen on before - - incorrectCODE - current incorrect CODE - - doublebubble - array ref of the bubble lines that have double - bubble errors - - missingbubble - array ref of the bubble lines that have missing - bubble errors - -=cut sub scantron_get_correction { my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_; @@ -7280,25 +7384,6 @@ sub scantron_validate_doublebubble { return (0,$currentphase+1); } -=pod - -=item scantron_get_maxbubble - - 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() - for what the current value of the problem counter is. - - Caches the results to $env{'form.scantron_maxbubble'}, - $env{'form.scantron.bubble_lines.n'}, - $env{'form.scantron.first_bubble_line.n'} and - $env{"form.scantron.sub_bubblelines.n"} - which are the total number of bubble, lines, the number of bubble - lines for response n and number of the first bubble line for response n, - and a comma separated list of numbers of bubble lines for sub-questions - (for optionresponse, matchresponse, and rankresponse items), for response n. - -=cut sub scantron_get_maxbubble { if (defined($env{'form.scantron_maxbubble'}) && @@ -7441,15 +7526,6 @@ sub scantron_get_maxbubble { return $env{'form.scantron_maxbubble'}; } -=pod - -=item scantron_validate_missingbubbles - - Validates all scanlines in the selected file to not have any - answers that don't have bubbles that have not been verified - to be bubble free. - -=cut sub scantron_validate_missingbubbles { my ($r,$currentphase) = @_; @@ -7504,29 +7580,6 @@ sub scantron_validate_missingbubbles { return (0,$currentphase+1); } -=pod - -=item scantron_process_students - - Routine that does the actual grading of the bubble sheet information. - - The parsed scanline hash is added to %env - - Then foreach unskipped scanline it does an &Apache::lonnet::ssi() - foreach resource , with the form data of - - 'submitted' =>'scantron' - 'grade_target' =>'grade', - 'grade_username'=> username of student - 'grade_domain' => domain of student - 'grade_courseid'=> of course - 'grade_symb' => symb of resource to grade - - This triggers a grading pass. The problem grading code takes care - of converting the bubbled letter information (now in %env) into a - valid submission. - -=cut sub scantron_process_students { my ($r) = @_; @@ -7657,14 +7710,6 @@ SCANTRONFORM return ''; } -=pod - -=item scantron_upload_scantron_data - - Creates the screen for adding a new bubble sheet data file to a course. - -=cut - sub scantron_upload_scantron_data { my ($r)=@_; $r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'})); @@ -7705,14 +7750,6 @@ sub scantron_upload_scantron_data { return ''; } -=pod - -=item scantron_upload_scantron_data_save - - Adds a provided bubble information data file to the course if user - has the correct privileges to do so. - -=cut sub scantron_upload_scantron_data_save { my($r)=@_; @@ -7774,14 +7811,6 @@ sub scantron_upload_scantron_data_save { return ''; } -=pod - -=item valid_file - - Validates that the requested bubble data file exists in the course. - -=cut - sub valid_file { my ($requested_file)=@_; foreach my $filename (sort(&scantron_filenames())) { @@ -7790,16 +7819,6 @@ sub valid_file { return 0; } -=pod - -=item scantron_download_scantron_data - - Shows a list of the three internal files (original, corrected, - skipped) for a specific bubble sheet data file that exists in the - course. - -=cut - sub scantron_download_scantron_data { my ($r)=@_; my $default_form_data=&defaultFormData(&get_symb($r,1)); @@ -8104,11 +8123,6 @@ sub checkscantron_results { return; } -=pod - -=back - -=cut #-------- end of section for handling grading scantron forms ------- #