--- loncom/homework/grades.pm 2009/06/17 18:41:31 1.528.2.14 +++ loncom/homework/grades.pm 2008/12/31 18:09:57 1.544 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.528.2.14 2009/06/17 18:41:31 raeburn Exp $ +# $Id: grades.pm,v 1.544 2008/12/31 18:09:57 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,6 +26,8 @@ # http://www.lon-capa.org/ # + + package Apache::grades; use strict; use Apache::style; @@ -58,46 +60,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); @@ -256,8 +218,8 @@ sub showResourceInfo { } my $display_part=&get_display_part($partID,$symb); $result.=''.&mt('Part').': '.$display_part. - ' '.$resID.''. - ''.&mt('Type').': '.$responsetype.''; + ' '.$resID.''. + ''.&mt('Type').': '.$responsetype.''; # ''.&mt('Handgrade: [_1]',$handgrade).''; } } @@ -306,14 +268,11 @@ sub reset_caches { sub get_radiobutton_correct_foil { my ($partid,$respid,$symb,$uname,$udom)=@_; my $analyze = &get_analyze($symb,$uname,$udom); - my $foils = &get_order($partid,$respid,$symb,$uname,$udom); - if (ref($foils) eq 'ARRAY') { - foreach my $foil (@{$foils}) { - if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') { - return $foil; - } - } - } + foreach my $foil (@{&get_order($partid,$respid,$symb,$uname,$udom)}) { + if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') { + return $foil; + } + } } } @@ -740,7 +699,7 @@ sub verifyreceipt { my $title.= '

'. - &mt('Verifying Receipt No. [_1]',$receipt). + &mt('Verifying Submission Receipt [_1]',$receipt). '

'."\n". '

'.&mt('Resource: [_1]',$env{'form.probTitle'}). '

'."\n"; @@ -820,20 +779,22 @@ sub listStudents { 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'; + my $viewgrade = $env{'form.showgrading'} eq 'yes' ? &mt('View/Grade/Regrade') : &mt('View'); $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'}; - my $result='

 '. - &mt("$viewgrade Submissions for a Student or a Group of Students") + my $result='

 '.$viewgrade. + &mt(' Submissions for a Student or a Group of Students') .'

'; my ($table,undef,$hdgrade,$partlist,$handgrade) = &showResourceInfo($symb,$env{'form.probTitle'},($env{'form.showgrading'} eq 'yes')); - my %lt = &Apache::lonlocal::texthash ( - 'multiple' => 'Please select a student or group of students before clicking on the Next button.', - 'single' => 'Please select the student before clicking on the Next button.', - ); + my %lt = ( 'multiple' => + &mt("Please select a student or group of students before clicking on the Next button."), + 'single' => + &mt("Please select the student before clicking on the Next button."), + ); + %lt = &Apache::lonlocal::texthash(%lt); $request->print(< function checkSelect(checkBox) { @@ -928,7 +889,7 @@ LISTJAVASCRIPT &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);')).'
'; } - $gradeTable.=&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". + $gradeTable.=&mt('To [_1] 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.',lc($viewgrade)).'
'."\n". ''."\n"; # checkall buttons @@ -1151,7 +1112,7 @@ sub processGroup { #--- Javascript to handle the submission page functionality --- sub sub_page_js { my $request = shift; - my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = '); + my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = '); $request->print(< function updateRadio(formname,id,weight) { @@ -1708,8 +1669,9 @@ sub gradeBox { $line.=''."\n"; + #&mt('Part:[_1]Points:[_2]or[_3]',$display_part,$radio,$line); $result .= - ''.&mt('Part').':'.$display_part.''.&mt('Points').':'.$radio.''.&mt('or').''.$line.''; + ''.&mt('Part').':'.$display_part.''.&mt('Points').':'.$radio.''.&mt('or').''.$line.''. $result.=''."\n"; $result.=''."\n". @@ -2143,7 +2105,7 @@ KEYWORDS } $lastsubonly.=''.&mt('Submitted Answer:').' '. &cleanRecord($subval,$responsetype,$symb,$partid, - $respid,\%record,$order,undef,$uname,$udom); + $respid,\%record,$order); if ($similar) {$lastsubonly.="

$similar\n";} $lastsubonly.=''; } @@ -2272,7 +2234,7 @@ KEYWORDS ''."\n"; my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1'); $ntstu =~ s/
'; + ''.&mt('Nothing submitted - no attempts.').''; } return (\@string,\$timestamp); } @@ -3211,19 +3173,19 @@ sub viewgrades { ''."\n". ''."\n"; - my ($common_header,$specific_header); + my $sectionClass; + my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section')); if ($env{'form.section'} eq 'all') { - $common_header = &mt('Assign Common Grade to Class'); - $specific_header = &mt('Assign Grade to Specific Students in Class'); + $sectionClass=&mt('Class'); } elsif ($env{'form.section'} eq 'none') { - $common_header = &mt('Assign Common Grade to Students in no Section'); - $specific_header = &mt('Assign Grade to Specific Students in no Section'); + $sectionClass=&mt('Students in no Section'); } else { - 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); + $sectionClass=&mt('Students in Section(s) [_1]'); } - $result.= '

'.$common_header.'

'.&Apache::loncommon::start_data_table(); + $result.= + '

'. + &mt("Assign Common Grade to [_1]",$sectionClass,$section_display).'

'; + $result.= &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); @@ -3270,7 +3232,7 @@ sub viewgrades { $result.= &Apache::loncommon::start_data_table_row()."\n". - ''.&mt('Part').':'.$display_part.''.&mt('Points').':'.$radio.''.&mt('or').''.$line.''. + ''.&mt('Part').':'.$display_part.''.&mt('Points').':'.$radio.''.&mt('or').''.$line.''. &Apache::loncommon::end_data_table_row()."\n"; $ctsparts++; } @@ -3281,32 +3243,33 @@ sub viewgrades { #table listing all the students in a section/class #header of table - $result.= '

'.$specific_header.'

'. - &Apache::loncommon::start_data_table(). - &Apache::loncommon::start_data_table_header_row(). - ''.&mt('No.').''. - ''.&nameUserString('header')."\n"; + $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"; my (@parts) = sort(&getpartlist($symb)); my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb); my @partids = (); foreach my $part (@parts) { my $display=&Apache::lonnet::metadata($url,$part.'.display'); - my $narrowtext = &mt('Tries').'
'; - $display =~ s{^Number of Attempts}{$narrowtext}; # makes the column narrower + my $narrowtext = &mt('Tries'); + $display =~ s|^Number of Attempts|$narrowtext
|; # makes the column narrower if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); } my ($partid) = &split_part_type($part); push(@partids,$partid); my $display_part=&get_display_part($partid,$symb); if ($display =~ /^Partial Credit Factor/) { $result.=''. - &mt('Score Part: [_1] (weight = [_2])', - $display_part.'
',$weight{$partid}).''."\n"; + &mt('Score Part: [_1]
(weight = [_2])', + $display_part,$weight{$partid}).''."\n"; next; } else { if ($display =~ /Problem Status/) { - my $grade_status_mt = &mt('Grade Status').'
'; - $display =~ s{Problem Status}{$grade_status_mt}; + my $grade_status_mt = &mt('Grade Status'); + $display =~ s{Problem Status}{$grade_status_mt
}; } my $part_mt = &mt('Part:'); $display =~s{\[Part: \Q$partid\E\]}{$part_mt $display_part}; @@ -3463,9 +3426,9 @@ 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: \Q$part\E\]//; + $display =~ s/\[Part: (\w)+\]//; my $narrowtext = &mt('Tries'); - $display =~ s{Number of Attempts}{$narrowtext}; + $display =~ s/Number of Attempts/$narrowtext/; $header .= ''.&mt('Old').' '.$display.''. ''.&mt('New').' '.$display.''; $columns{$partid}+=2; @@ -3835,7 +3798,7 @@ sub upcsvScores_form { $result.='
'."\n"; $result.=''."\n"; + ''."\n"; $result.='
'."\n"; $result.=' '.&mt('Specify a file containing the class scores for current resource.'). - '.
'."\n"; my $upload=&mt("Upload Scores"); my $upfile_select=&Apache::loncommon::upfile_select_html(); @@ -4129,7 +4092,7 @@ LISTJAVASCRIPT $ctr++; } $select.= ''; - $result.=' '.&mt('Problems from').": $select
\n"; + $result.=' '.&mt('Problems from').': '.$select."
\n"; $ctr=0; foreach (@$titles) { @@ -4144,13 +4107,13 @@ LISTJAVASCRIPT my $options = ''."\n". ''."
\n"; - $result.=' '.&mt('View Problem Text').": $options"; + $result.=' '.&mt('View Problem Text').': '.$options; $options = ''."\n". ''."\n". ''."\n"; - $result.=' >b>'.&mt('Submissions').": $options"; + $result.=' '.&mt('Submissions').': '.$options; $result.=&build_section_inputs(); my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status')); @@ -4159,7 +4122,7 @@ LISTJAVASCRIPT ''."\n". ''."
\n"; - $result.=' '.&mt('Use CODE').':
'."\n"; + $result.=' '.&mt('Use CODE').':
'."\n"; $result.=' 
'."\n"; @@ -4201,7 +4164,7 @@ LISTJAVASCRIPT } $studentTable.=&Apache::loncommon::end_data_table()."\n"; $studentTable.=''."\n"; + 'onClick="javascript:checkPickOne(this.form);" value="'.&mt('Next').' →" />'."\n"; $studentTable.=&show_grading_menu_form($symb); $request->print($studentTable); @@ -5524,8 +5487,7 @@ sub scantron_parse_scanline { my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_; my %record; - my $lastpos = $env{'form.scantron_maxbubble'}*$$scantron_config{'Qlength'}; - my $questions=substr($line,$$scantron_config{'Qstart'}-1,$lastpos); # Answers + my $questions=substr($line,$$scantron_config{'Qstart'}-1); # Answers my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff if (!($$scantron_config{'CODElocation'} eq 0 || $$scantron_config{'CODElocation'} eq 'none')) { @@ -6214,8 +6176,8 @@ sub scantron_validate_file { } } if (!$stop) { - my $warning=&scantron_warning_screen('Start Grading'); - $r->print(&mt('Validation process complete.').'
'. + my $warning=&scantron_warning_screen('Start Grading'); + $r->print(&mt('Validation process complete.').'
'. $warning. &mt('Perform verification for each student after storage of submissions?'). ' 
'. - &mt('Grading will take longer if you use verification.').'
'. &mt("Alternatively, the 'Review scantron data' utility (see grading menu) can be used for all students after grading is complete.").'

'. + &mt('Grading will take longer if you use verification.').'
'. + &mt("Alternatively, the 'Review scantron data' utility (see grading menu) can be used for all students after grading is complete.").'

'. ''. ''."\n"); } else { - $r->print(''); - $r->print(""); + $r->print(''); + $r->print(""); } if ($stop) { if ($validate_phases[$currentphase] eq 'sequence') { - $r->print(''); + $r->print(''); $r->print(' '.&mt('this error').'
'); $r->print("

".&mt("Or click the 'Grading Menu' button to start over.")."

"); @@ -6618,14 +6581,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) = @_; @@ -6691,35 +6647,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)=@_; @@ -6833,7 +6760,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(" @@ -7290,25 +7217,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'}) && @@ -7340,8 +7248,7 @@ sub scantron_get_maxbubble { foreach my $resource (@resources) { my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,$udom); if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) { - foreach my $part_id (@{$parts}) { - + foreach my $part_id (@{$parts}) { my $lines; # TODO - make this a persistent hash not an array. @@ -7394,7 +7301,7 @@ sub scantron_get_maxbubble { } } } - &Apache::lonnet::delenv('scantron.'); + &Apache::lonnet::delenv('scantron\.'); &save_bubble_lines(); $env{'form.scantron_maxbubble'} = @@ -7404,7 +7311,7 @@ sub scantron_get_maxbubble { sub scantron_partids_tograde { my ($resource,$cid,$uname,$udom) = @_; - my (%analysis,@parts); + my (%analysis,@parts); if (ref($resource)) { my $symb = $resource->symb(); @@ -7429,16 +7336,6 @@ sub scantron_partids_tograde { return (\%analysis,\@parts); } -=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) = @_; #get student info @@ -7492,29 +7389,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) = @_; @@ -7536,8 +7410,8 @@ sub scantron_process_students { my ($uname,$udom,%partids_by_symb); foreach my $resource (@resources) { - my $ressymb = $resource->symb(); - my ($analysis,$parts) = + my $ressymb = $resource->symb(); + my ($analysis,$parts) = &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom); $partids_by_symb{$ressymb} = $parts; } @@ -7550,7 +7424,7 @@ SCANTRONFORM $r->print($result); my @delayqueue; - my (%completedstudents,,%scandata); + my (%completedstudents,%scandata); my $lock=&Apache::lonnet::set_lock(&mt('Grading bubblesheet exam')); my $count=&get_todo_count($scanlines,$scan_data); @@ -7612,7 +7486,7 @@ SCANTRONFORM if (&scantron_clear_skip($scanlines,$scan_data,$i)) { &scantron_putfile($scanlines,$scan_data); } - + my $scancode; if ((exists($scan_record->{'scantron.CODE'})) && (&Apache::lonnet::validCODE($scan_record->{'scantron.CODE'}))) { @@ -7647,17 +7521,6 @@ SCANTRONFORM $studentrecord .= $recording; } if ($studentrecord ne $studentdata) { - &Apache::lonxml::clear_problem_counter(); - if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode, - @resources) 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) { @@ -7697,10 +7560,10 @@ SCANTRONFORM } } } - if (&Apache::loncommon::connection_aborted($r)) { last; } + 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); @@ -7721,7 +7584,7 @@ sub grade_student_bubbles { 'grade_domain' => $udom, 'grade_courseid'=> $env{'request.course.id'}, 'grade_symb' => $resource->symb(), - 'CODE' => $scancode); + '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)); @@ -7729,14 +7592,6 @@ sub grade_student_bubbles { 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'})); @@ -7777,14 +7632,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)=@_; @@ -7846,14 +7693,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())) { @@ -7862,16 +7701,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)); @@ -7949,7 +7778,7 @@ sub checkscantron_results { my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Scantron/Submissions Comparison Status', 'Progress of Scantron Data/Submission Records Comparison',$count, 'inline',undef,'checkscantron'); - my ($username,$domain,$started); + my ($username,$domain,$uname,$started); &Apache::grades::scantron_get_maxbubble(); # Need the bubble lines array to parse. @@ -8174,7 +8003,7 @@ sub verify_scantron_grading { return ($counter,$record); } -sub letter_to_digits { +sub letter_to_digits { my %lettdig = ( A => 1, B => 2, @@ -8190,11 +8019,6 @@ sub letter_to_digits { return %lettdig; } -=pod - -=back - -=cut #-------- end of section for handling grading scantron forms ------- # @@ -8241,36 +8065,49 @@ sub grading_menu { 'saveState'=>"", 'gradingMenu'=>1, 'showgrading'=>"yes"); - my $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - my @menu = ({ url => $url, - name => &mt('Manual Grading/View Submissions'), - short_description => - &mt('Start the process of hand grading submissions.'), - }); + + my $url1 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + $fields{'command'} = 'csvform'; - $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - push(@menu, { url => $url, - name => &mt('Upload Scores'), - short_description => - &mt('Specify a file containing the class scores for current resource.')}); + my $url2 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + $fields{'command'} = 'processclicker'; - $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - push(@menu, { url => $url, - name => &mt('Process Clicker'), - short_description => - &mt('Specify a file containing the clicker information for this resource.')}); + my $url3 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + $fields{'command'} = 'scantron_selectphase'; - $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - push(@menu, { url => $url, - name => &mt('Grade/Manage/Review Scantron Forms'), - short_description => - &mt('Grade scantron exams, upload/download scantron data files, and review previously graded scantron exams.')}); - $fields{'command'} = 'verify'; - $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); - push(@menu, { url => "", - name => &mt('Verify Receipt'), - short_description => - &mt('')}); + my $url4 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); + + my @menu = ({ categorytitle=>'Course Grading', + items =>[ + { linktext => 'Manual Grading/View Submissions', + url => $url1, + permission => 'F', + icon => 'edit-find-replace.png', + linktitle => 'Start the process of hand grading submissions.' + }, + { linktext => 'Upload Scores', + url => $url2, + permission => 'F', + icon => 'uploadscores.png', + linktitle => 'Specify a file containing the class scores for current resource.' + }, + { linktext => 'Process Clicker', + url => $url3, + permission => 'F', + icon => 'addClickerInfoFile.png', + linktitle => 'Specify a file containing the clicker information for this resource.' + }, + { linktext => 'Grade/Manage/Review Scantron Forms', + url => $url4, + permission => 'F', + icon => 'stat.png', + linktitle => 'Grade scantron exams, upload/download scantron data files, and review previously graded scantron exams.' + } + ] + }); + + #$fields{'command'} = 'verify'; + #$url = &Apache::lonhtmlcommon::build_url('grades/',\%fields); # # Create the menu my $Str; @@ -8284,24 +8121,14 @@ sub grading_menu { ''."\n". ''."\n"; - foreach my $menudata (@menu) { - if ($menudata->{'name'} ne &mt('Verify Receipt')) { - $Str .='

{'jscript'}. - ' href="'. - $menudata->{'url'}.'" >'. - $menudata->{'name'}."

\n"; - } else { - $Str .='
{'jscript'}. - ' onClick="javascript:checkChoice(document.forms.gradingMenu,\'5\',\'verify\')" '. - ' /> '. - &Apache::lonnet::recprefix($env{'request.course.id'}). - '-'; - } - $Str .= ' '.(' 'x8).$menudata->{'short_description'}. - "\n"; - } + $Str .= Apache::lonhtmlcommon::generate_menu(@menu); + #$menudata->{'jscript'} + $Str .='
'. + &Apache::lonnet::recprefix($env{'request.course.id'}). + '-'; + $Str .="\n"; my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box."); $request->print(<'.$section.''."\n"; + } + } + $result.='
'."\n". ''."\n". ''."\n". @@ -8409,102 +8245,91 @@ GRADINGMENUJS ''."\n"; $result.=' -
-
-

- '.&mt('Grade Current Resource').' -

-
-
- '.$table.' -
-
-
- '.&mt('Sections').' -
-
- '."\n"; + $result.= $selsec; $result.= '   '; $result.=' -
-
-
-
- '.&mt('Groups').' -
-
- '.&Apache::lonstatistics::GroupSelect('group','multiple',5).' -
-
-
-
- '.&mt('Access Status').' -
-
- '.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,5,undef,'mult').' -
-
-
-
- '.&mt('Submission Status').' -
-
- - -
-
-
-
+ + + +
+ +
+
+
-
+
-
+
-
-
-
+ +

'.&mt('Grade Complete Folder for One Student').'

-
-
-
+
+
-
+
-
-
-
'; $result .= &show_grading_menu_form($symb); return $result; @@ -8604,7 +8429,7 @@ sub process_clicker { $result.='
'."\n"; $result.=''."\n"; + ''."\n"; $result.='
'."\n"; $result.=' '.&mt('Specify a file containing the clicker information for this resource.'). - '.
'."\n"; # Attempt to restore parameters from last session, set defaults if not present my %Saveable_Parameters=&clicker_grading_parameters(); @@ -9039,7 +8864,7 @@ ENDHEADER } } # We are done - $result.='
'.&mt('Successfully stored grades for [quant,_1,student].',$storecount). + $result.='
'.&mt('Successfully stored grades for [_1] student(s).',$storecount). '
'."\n". '


'."\n"; return $result.&show_grading_menu_form($symb); @@ -9065,7 +8890,9 @@ sub handler { } $ssi_error = 0; - $request->print(&Apache::loncommon::start_page('Grading')); + my $brcrum = [{href=>"/adm/grades",text=>"Grading"}]; + $request->print(&Apache::loncommon::start_page('Grading',undef, + {'bread_crumbs' => $brcrum})); if ($symb eq '' && $command eq '') { if ($env{'user.adv'}) { if (($env{'form.codeone'}) && ($env{'form.codetwo'}) && @@ -9177,3 +9004,162 @@ sub handler { 1; __END__; + + +=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 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