Diff for /loncom/homework/grades.pm between versions 1.745 and 1.755

version 1.745, 2017/12/18 23:51:24 version 1.755, 2019/01/27 23:16:25
Line 46  use Apache::lonenc; Line 46  use Apache::lonenc;
 use Apache::lonstathelpers;  use Apache::lonstathelpers;
 use Apache::lonquickgrades;  use Apache::lonquickgrades;
 use Apache::bridgetask();  use Apache::bridgetask();
   use Apache::lontexconvert();
 use String::Similarity;  use String::Similarity;
 use LONCAPA;  use LONCAPA;
   
Line 417  sub cleanRecord { Line 418  sub cleanRecord {
     $env{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';      $env{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
     $env{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob.      $env{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob.
  }   }
           $answer = &Apache::lontexconvert::msgtexconverted($answer);
  return '<br /><br /><blockquote><tt>'.&keywords_highlight($answer).'</tt></blockquote>';   return '<br /><br /><blockquote><tt>'.&keywords_highlight($answer).'</tt></blockquote>';
   
     } elsif ( $response eq 'organic') {      } elsif ( $response eq 'organic') {
Line 502  COMMONJSFUNCTIONS Line 504  COMMONJSFUNCTIONS
 #--- Dumps the class list with usernames,list of sections,  #--- Dumps the class list with usernames,list of sections,
 #--- section, ids and fullnames for each user.  #--- section, ids and fullnames for each user.
 sub getclasslist {  sub getclasslist {
     my ($getsec,$filterlist,$getgroup) = @_;      my ($getsec,$filterbyaccstatus,$getgroup,$symb,$submitonly,$filterbysubmstatus) = @_;
     my @getsec;      my @getsec;
     my @getgroup;      my @getgroup;
     my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));      my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
Line 530  sub getclasslist { Line 532  sub getclasslist {
     #      #
     my %sections;      my %sections;
     my %fullnames;      my %fullnames;
       my ($cdom,$cnum,$partlist);
       if (($filterbysubmstatus) && ($submitonly ne 'all') && ($symb ne '')) {
           $cdom = $env{"course.$env{'request.course.id'}.domain"};
           $cnum = $env{"course.$env{'request.course.id'}.num"};
           my $res_error;
           ($partlist,my $handgrade,my $responseType) = &response_type($symb,\$res_error);
       }
     foreach my $student (keys(%$classlist)) {      foreach my $student (keys(%$classlist)) {
         my $end      =           my $end      = 
             $classlist->{$student}->[&Apache::loncoursedata::CL_END()];              $classlist->{$student}->[&Apache::loncoursedata::CL_END()];
Line 546  sub getclasslist { Line 555  sub getclasslist {
         my $group   =           my $group   = 
             $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()];              $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()];
  # filter students according to status selected   # filter students according to status selected
  if ($filterlist && (!($stu_status =~ /Any/))) {   if ($filterbyaccstatus && (!($stu_status =~ /Any/))) {
     if (!($stu_status =~ $status)) {      if (!($stu_status =~ $status)) {
  delete($classlist->{$student});   delete($classlist->{$student});
  next;   next;
Line 563  sub getclasslist { Line 572  sub getclasslist {
                }                  } 
         }          }
            if (($grp eq 'none') && !$group) {             if (($grp eq 'none') && !$group) {
                $exclude = 0;             $exclude = 0;
         }          }
     }      }
     if ($exclude) {      if ($exclude) {
         delete($classlist->{$student});          delete($classlist->{$student});
    next;
     }      }
  }   }
           if (($filterbysubmstatus) && ($submitonly ne 'all') && ($symb ne '')) {
               my $udom =
                   $classlist->{$student}->[&Apache::loncoursedata::CL_SDOM()];
               my $uname =
                   $classlist->{$student}->[&Apache::loncoursedata::CL_SNAME()];
               if (($symb ne '') && ($udom ne '') && ($uname ne '')) {
                   if ($submitonly eq 'queued') {
                       my %queue_status =
                           &Apache::bridgetask::get_student_status($symb,$cdom,$cnum,
                                                                   $udom,$uname);
                       if (!defined($queue_status{'gradingqueue'})) {
                           delete($classlist->{$student});
                           next;
                       }
                   } else {
                       my (%status) =&student_gradeStatus($symb,$udom,$uname,$partlist);
                       my $submitted = 0;
                       my $graded = 0;
                       my $incorrect = 0;
                       foreach (keys(%status)) {
                           $submitted = 1 if ($status{$_} ne 'nothing');
                           $graded = 1 if ($status{$_} =~ /^ungraded/);
                           $incorrect = 1 if ($status{$_} =~ /^incorrect/);
   
                           my ($foo,$partid,$foo1) = split(/\./,$_);
                           if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
                               $submitted = 0;
                           }
                       }
                       if (!$submitted && ($submitonly eq 'yes' ||
                                           $submitonly eq 'incorrect' ||
                                           $submitonly eq 'graded')) {
                           delete($classlist->{$student});
                           next;
                       } elsif (!$graded && ($submitonly eq 'graded')) {
                           delete($classlist->{$student});
                           next;
                       } elsif (!$incorrect && $submitonly eq 'incorrect') {
                           delete($classlist->{$student});
                           next;
                       }
                   }
               }
           }
  $section = ($section ne '' ? $section : 'none');   $section = ($section ne '' ? $section : 'none');
  if (&canview($section)) {   if (&canview($section)) {
     if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {      if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {
Line 584  sub getclasslist { Line 638  sub getclasslist {
     delete($classlist->{$student});      delete($classlist->{$student});
  }   }
     }      }
     my %seen = ();  
     my @sections = sort(keys(%sections));      my @sections = sort(keys(%sections));
     return ($classlist,\@sections,\%fullnames);      return ($classlist,\@sections,\%fullnames);
 }  }
Line 856  sub verifyreceipt { Line 909  sub verifyreceipt {
 sub listStudents {  sub listStudents {
     my ($request,$symb,$submitonly) = @_;      my ($request,$symb,$submitonly) = @_;
   
     my ($is_tool) = ($symb =~ /ext\.tool$/);      my $is_tool   = ($symb =~ /ext\.tool$/);
     my $cdom      = $env{"course.$env{'request.course.id'}.domain"};      my $cdom      = $env{"course.$env{'request.course.id'}.domain"};
     my $cnum      = $env{"course.$env{'request.course.id'}.num"};      my $cnum      = $env{"course.$env{'request.course.id'}.num"};
     my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
Line 1952  sub show_problem { Line 2005  sub show_problem {
 sub files_exist {  sub files_exist {
     my ($r, $symb) = @_;      my ($r, $symb) = @_;
     my @students = &Apache::loncommon::get_env_multiple('form.stuinfo');      my @students = &Apache::loncommon::get_env_multiple('form.stuinfo');
   
     foreach my $student (@students) {      foreach my $student (@students) {
         my ($uname,$udom,$fullname) = split(/:/,$student);          my ($uname,$udom,$fullname) = split(/:/,$student);
         my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},          my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},
Line 1975  sub download_all_link { Line 2027  sub download_all_link {
        $r->print(&mt('There are currently no submitted documents.'));         $r->print(&mt('There are currently no submitted documents.'));
        return;         return;
     }      }
   
     my $all_students =       my $all_students = 
  join("\n", &Apache::loncommon::get_env_multiple('form.stuinfo'));   join("\n", &Apache::loncommon::get_env_multiple('form.stuinfo'));
   
Line 1995  sub submit_download_link { Line 2046  sub submit_download_link {
     my ($request,$symb) = @_;      my ($request,$symb) = @_;
     if (!$symb) { return ''; }      if (!$symb) { return ''; }
 #FIXME: Figure out which type of problem this is and provide appropriate download  #FIXME: Figure out which type of problem this is and provide appropriate download
     &download_all_link($request,$symb);      my $res_error;
       my ($partlist,$handgrade,$responseType) = &response_type($symb,$res_error);
       if (ref($res_error)) {
           if ($$res_error) {
               $request->print(&mt('An error occurred retrieving response types'));
               return;
           }
       }
       my ($numupload,$numessay) = (0,0);
       if (ref($responseType) eq 'HASH') {
           foreach my $part (sort(keys(%$responseType))) {
               foreach my $id (sort(keys(%{ $responseType->{$part} }))) {
                   my $responsetype = $responseType->{$part}->{$id};
                   if ($responsetype eq 'essay') {
                       my $uploadedfiletypes =
                           &Apache::lonnet::EXT("resource.$part".'_'."$id.uploadedfiletypes",$symb);
                       if ($uploadedfiletypes) {
                           $numupload++;
                       } else {
                           $numessay++;
                       }
                   }
               }
           }
       }
       if (($numupload) || ($numessay)) {
           my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'};
           my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
           my $getgroup  = $env{'form.group'} eq '' ? 'all' : $env{'form.group'};
           (undef,undef,my $fullname) = &getclasslist($getsec,1,$getgroup,$symb,$submitonly,1);
           if (ref($fullname) eq 'HASH') {
               my @students = map { $_.':'.$fullname->{$_} } (keys(%{$fullname}));
               if (@students) {
                   @{$env{'form.stuinfo'}} = @students;
                   if ($numupload) {
                       &download_all_link($request,$symb);
                   }
   # FIXME Need to provide a mechanism to download essays, i.e., if $numessay > 0
   # Needs to omit user's identity if resource instance is for an anonymous survey.
               } else {
                   $request->print(&mt('No students match the criteria you selected'));
               }
           } else {
               $request->print(&mt('Could not retrieve student information'));
           }
       } else {
           $request->print(&mt('No essayresponse items found'));
       }
       return;
 }  }
   
 sub build_section_inputs {  sub build_section_inputs {
Line 2021  sub submission { Line 2120  sub submission {
   
     my $probtitle=&Apache::lonnet::gettitle($symb);       my $probtitle=&Apache::lonnet::gettitle($symb); 
     if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; }      if ($symb eq '') { $request->print("Unable to handle ambiguous references:."); return ''; }
     my ($is_tool) = ($symb =~ /ext\.tool$/);      my $is_tool = ($symb =~ /ext\.tool$/);
       my ($essayurl,%coursedesc_by_cid);
   
     if (!&canview($usec)) {      if (!&canview($usec)) {
         $request->print(          $request->print(
Line 2152  sub submission { Line 2252  sub submission {
 #  #
 # Load the other essays for similarity check  # Load the other essays for similarity check
 #  #
             my (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb);              (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb);
     my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/);              if ($essayurl eq 'lib/templates/simpleproblem.problem') {
     $apath=&escape($apath);                  my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     $apath=~s/\W/\_/gs;                  my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
             &init_old_essays($symb,$apath,$adom,$aname);                  if ($cdom ne '' && $cnum ne '') {
                       my ($map,$id,$res) = &Apache::lonnet::decode_symb($symb);
                       if ($map =~ m{^\Quploaded/$cdom/$cnum/\E(default(?:|_\d+)\.(?:sequence|page))$}) {
                           my $apath = $1.'_'.$id;
                           $apath=~s/\W/\_/gs;
                           &init_old_essays($symb,$apath,$cdom,$cnum);
                       }
                   }
               } else {
           my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/);
           $apath=&escape($apath);
           $apath=~s/\W/\_/gs;
                   &init_old_essays($symb,$apath,$adom,$aname);
               }
         }          }
     }      }
   
Line 2307  sub submission { Line 2420  sub submission {
         &most_similar($uname,$udom,$symb,$subval);          &most_similar($uname,$udom,$symb,$subval);
     if ($osim) {      if ($osim) {
  $osim=int($osim*100.0);   $osim=int($osim*100.0);
  my %old_course_desc =   
     &Apache::lonnet::coursedescription($ocrsid,  
  {'one_time' => 1});  
   
                         if ($hide eq 'anon') {                          if ($hide eq 'anon') {
                             $similar='<hr /><span class="LC_warning">'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'<br />'.                              $similar='<hr /><span class="LC_warning">'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'<br />'.
                                      &mt('As the current submission is for an anonymous survey, no other details are available.').'</span><hr />';                                       &mt('As the current submission is for an anonymous survey, no other details are available.').'</span><hr />';
                         } else {                          } else {
     $similar="<hr /><h3><span class=\"LC_warning\">".      $similar='<hr />';
  &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])',                              if ($essayurl eq 'lib/templates/simpleproblem.problem') {
     $osim,                                  $similar .= '<h3><span class="LC_warning">'.
     &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')',                                              &mt('Essay is [_1]% similar to an essay by [_2]',
         $old_course_desc{'description'},                                                  $osim,
         $old_course_desc{'num'},                                                  &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
         $old_course_desc{'domain'}).                                              '</span></h3>';
     '</span></h3><blockquote><i>'.                              } else {
     &keywords_highlight($oessay).                                  my %old_course_desc;
     '</i></blockquote><hr />';                                  if ($ocrsid ne '') {
                                       if (ref($coursedesc_by_cid{$ocrsid}) eq 'HASH') {
                                           %old_course_desc = %{$coursedesc_by_cid{$ocrsid}};
                                       } else {
                                           my $args;
                                           if ($ocrsid ne $env{'request.course.id'}) {
                                               $args = {'one_time' => 1};
                                           }
                                           %old_course_desc =
                                               &Apache::lonnet::coursedescription($ocrsid,$args);
                                           $coursedesc_by_cid{$ocrsid} = \%old_course_desc;
                                       }
                                       $similar .=
                                           '<h3><span class="LC_warning">'.
                                           &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])',
                                               $osim,
                                               &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')',
                                               $old_course_desc{'description'},
                                               $old_course_desc{'num'},
                                               $old_course_desc{'domain'}).
                                           '</span></h3>';
                                   } else {
                                       $similar .=
                                           '<h3><span class="LC_warning">'.
                                           &mt('Essay is [_1]% similar to an essay by [_2] in an unknown course',
                                               $osim,
                                               &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
                                           '</span></h3>';
                                   }
                               }
                               $similar .= '<blockquote><i>'.
                                           &keywords_highlight($oessay).
                                           '</i></blockquote><hr />';
                         }                          }
             }              }
  }   }
Line 2635  sub get_last_submission { Line 2776  sub get_last_submission {
     if (!@string) {      if (!@string) {
         my $msg;          my $msg;
         if ($is_tool) {          if ($is_tool) {
             $msg = &mt('Nothing passed back - no attempts.');              $msg = &mt('No grade passed back.');
         } else {          } else {
             $msg = &mt('Nothing submitted - no attempts.');              $msg = &mt('Nothing submitted - no attempts.');
         }          }
Line 4090  sub editgrades { Line 4231  sub editgrades {
  $ctr++;   $ctr++;
     }      }
     my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);      my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);
       my $totcolspan = 0;
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
  $header .= '<th align="center">'.&mt('Old Score').'</th>'.   $header .= '<th align="center">'.&mt('Old Score').'</th>'.
     '<th align="center">'.&mt('New Score').'</th>';      '<th align="center">'.&mt('New Score').'</th>';
Line 4106  sub editgrades { Line 4248  sub editgrades {
  '<th align="center">'.&mt('New').' '.$display.'</th>';   '<th align="center">'.&mt('New').' '.$display.'</th>';
     $columns{$partid}+=2;      $columns{$partid}+=2;
  }   }
           $totcolspan += $columns{$partid};
     }      }
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
  my $display_part=&get_display_part($partid,$symb);   my $display_part=&get_display_part($partid,$symb);
Line 4121  sub editgrades { Line 4264  sub editgrades {
     my @noupdate;      my @noupdate;
     my ($updateCtr,$noupdateCtr) = (1,1);      my ($updateCtr,$noupdateCtr) = (1,1);
     for ($i=0; $i<$env{'form.total'}; $i++) {      for ($i=0; $i<$env{'form.total'}; $i++) {
  my $line;  
  my $user = $env{'form.ctr'.$i};   my $user = $env{'form.ctr'.$i};
  my ($uname,$udom)=split(/:/,$user);   my ($uname,$udom)=split(/:/,$user);
  my %newrecord;   my %newrecord;
  my $updateflag = 0;   my $updateflag = 0;
  $line .= '<td>'.&nameUserString(undef,$$fullname{$user},$uname,$udom).'</td>';  
  my $usec=$classlist->{"$uname:$udom"}[5];   my $usec=$classlist->{"$uname:$udom"}[5];
  if (!&canmodify($usec)) {   my $canmodify = &canmodify($usec);
     my $numcols=scalar(@partid)*4+2;   my $line = '<td'.($canmodify?'':' colspan="2"').'>'.
      &nameUserString(undef,$$fullname{$user},$uname,$udom).'</td>';
    if (!$canmodify) {
     push(@noupdate,      push(@noupdate,
  $line."<td colspan=\"$numcols\"><span class=\"LC_warning\">".   $line."<td colspan=\"$totcolspan\"><span class=\"LC_warning\">".
  &mt('Not allowed to modify student')."</span></td></tr>");   &mt('Not allowed to modify student')."</span></td>");
     next;      next;
  }   }
         my %aggregate = ();          my %aggregate = ();
Line 4249  sub editgrades { Line 4392  sub editgrades {
         }          }
     }      }
     if (@noupdate) {      if (@noupdate) {
 # my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;          my $numcols=$totcolspan+2;
  my $numcols=scalar(@partid)*4+2;  
  $result .= &Apache::loncommon::start_data_table_row('LC_empty_row').   $result .= &Apache::loncommon::start_data_table_row('LC_empty_row').
     '<td align="center" colspan="'.$numcols.'">'.      '<td align="center" colspan="'.$numcols.'">'.
     &mt('No Changes Occurred For the Students Below').      &mt('No Changes Occurred For the Students Below').
Line 5021  sub displayPage { Line 5163  sub displayPage {
     my $parts = $curRes->parts();      my $parts = $curRes->parts();
             my $title = $curRes->compTitle();              my $title = $curRes->compTitle();
     my $symbx = $curRes->symb();      my $symbx = $curRes->symb();
             my ($is_tool) = ($symbx =~ /ext\.tool$/);              my $is_tool = ($symbx =~ /ext\.tool$/);
     $studentTable.=      $studentTable.=
  &Apache::loncommon::start_data_table_row().   &Apache::loncommon::start_data_table_row().
  '<td align="center" valign="top" >'.$prob.   '<td align="center" valign="top" >'.$prob.
Line 5032  sub displayPage { Line 5174  sub displayPage {
  '</td>';   '</td>';
     $studentTable.='<td valign="top">';      $studentTable.='<td valign="top">';
     my %form = ('CODE' => $env{'form.CODE'},);      my %form = ('CODE' => $env{'form.CODE'},);
             unless ($is_tool) {              if ($is_tool) {
                   $studentTable.='&nbsp;<b>'.$title.'</b><br />';
               } else {
         if ($env{'form.vProb'} eq 'yes' ) {          if ($env{'form.vProb'} eq 'yes' ) {
     $studentTable.=&show_problem($request,$symbx,$uname,$udom,1,      $studentTable.=&show_problem($request,$symbx,$uname,$udom,1,
          undef,'both',\%form);           undef,'both',\%form);
Line 5110  sub displaySubByDates { Line 5254  sub displaySubByDates {
     my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;      my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;
     my $isCODE=0;      my $isCODE=0;
     my $isTask = ($symb =~/\.task$/);      my $isTask = ($symb =~/\.task$/);
       my $is_tool = ($symb =~/\.tool$/);
     if (exists($record->{'resource.CODE'})) { $isCODE=1; }      if (exists($record->{'resource.CODE'})) { $isCODE=1; }
     my $studentTable=&Apache::loncommon::start_data_table().      my $studentTable=&Apache::loncommon::start_data_table().
  &Apache::loncommon::start_data_table_header_row().   &Apache::loncommon::start_data_table_header_row().
  '<th>'.&mt('Date/Time').'</th>'.   '<th>'.&mt('Date/Time').'</th>'.
  ($isCODE?'<th>'.&mt('CODE').'</th>':'').   ($isCODE?'<th>'.&mt('CODE').'</th>':'').
         ($isTask?'<th>'.&mt('Version').'</th>':'').          ($isTask?'<th>'.&mt('Version').'</th>':'').
  '<th>'.&mt('Submission').'</th>'.   '<th>'.($is_tool?&mt('Grade'):&mt('Submission')).'</th>'.
  '<th>'.&mt('Status').'</th>'.   '<th>'.&mt('Status').'</th>'.
  &Apache::loncommon::end_data_table_header_row();   &Apache::loncommon::end_data_table_header_row();
     my ($version);      my ($version);
Line 5124  sub displaySubByDates { Line 5269  sub displaySubByDates {
     my %orders;      my %orders;
     $mark{'correct_by_student'} = $checkIcon;      $mark{'correct_by_student'} = $checkIcon;
     if (!exists($$record{'1:timestamp'})) {      if (!exists($$record{'1:timestamp'})) {
  return '<br />&nbsp;<span class="LC_warning">'.&mt('Nothing submitted - no attempts.').'</span><br />';          if ($is_tool) {
               return '<br />&nbsp;<span class="LC_warning">'.&mt('No grade passed back.').'</span><br />';
           } else {
               return '<br />&nbsp;<span class="LC_warning">'.&mt('Nothing submitted - no attempts.').'</span><br />';
           }
     }      }
   
     my $interaction;      my $interaction;
Line 5157  sub displaySubByDates { Line 5306  sub displaySubByDates {
             if (($type eq 'anonsurvey') || ($type eq 'anonsurveycred')) {              if (($type eq 'anonsurvey') || ($type eq 'anonsurveycred')) {
                 $hidden = 1;                  $hidden = 1;
             }              }
     my @matchKey = ($isTask ? sort(grep /^resource\.\d+\.\Q$partid\E\.award$/,@versionKeys)              my @matchKey;
             : sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys));              if ($isTask) {
                       @matchKey = sort(grep /^resource\.\d+\.\Q$partid\E\.award$/,@versionKeys);
               } elsif ($is_tool) {
                   @matchKey = sort(grep /^resource\.\Q$partid\E\.awarded$/,@versionKeys);
               } else {
                   @matchKey = sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys);
               }
 #    next if ($$record{"$version:resource.$partid.solved"} eq '');  #    next if ($$record{"$version:resource.$partid.solved"} eq '');
     my $display_part=&get_display_part($partid,$symb);      my $display_part=&get_display_part($partid,$symb);
     foreach my $matchKey (@matchKey) {      foreach my $matchKey (@matchKey) {
  if (exists($$record{$version.':'.$matchKey}) &&   if (exists($$record{$version.':'.$matchKey}) &&
     $$record{$version.':'.$matchKey} ne '') {      $$record{$version.':'.$matchKey} ne '') {
                                           if ($is_tool) {
     my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)                          $displaySub[0].=$$record{"$version:resource.$partid.awarded"};
                : ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));  
                     $displaySub[0].='<span class="LC_nobreak">';  
                     $displaySub[0].='<b>'.&mt('Part: [_1]',$display_part).'</b>'  
                                    .' <span class="LC_internal_info">'  
                                    .'('.&mt('Response ID: [_1]',$responseId).')'  
                                    .'</span>'  
                                    .' <b>';  
                     if ($hidden) {  
                         $displaySub[0].= &mt('Anonymous Survey').'</b>';  
                     } else {                      } else {
                         my ($trial,$rndseed,$newvariation);          my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)
                         if ($type eq 'randomizetry') {                     : ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));
                             $trial = $$record{"$where.$partid.tries"};                          $displaySub[0].='<span class="LC_nobreak">';
                             $rndseed = $$record{"$where.$partid.rndseed"};                          $displaySub[0].='<b>'.&mt('Part: [_1]',$display_part).'</b>'
                         }                                         .' <span class="LC_internal_info">'
         if ($$record{"$where.$partid.tries"} eq '') {                                         .'('.&mt('Response ID: [_1]',$responseId).')'
     $displaySub[0].=&mt('Trial not counted');                                         .'</span>'
         } else {                                         .' <b>';
     $displaySub[0].=&mt('Trial: [_1]',                          if ($hidden) {
     $$record{"$where.$partid.tries"});                              $displaySub[0].= &mt('Anonymous Survey').'</b>';
                             if (($rndseed ne '') && ($lastrndseed{$partid} ne '')) {                          } else {
                                 if (($rndseed ne $lastrndseed{$partid}) &&                              my ($trial,$rndseed,$newvariation);
                                     (($type eq 'randomizetry') || ($lasttype{$partid} eq 'randomizetry'))) {                              if ($type eq 'randomizetry') {
                                     $newvariation = '&nbsp;('.&mt('New variation this try').')';                                  $trial = $$record{"$where.$partid.tries"};
                                 }                                  $rndseed = $$record{"$where.$partid.rndseed"};
                             }                              }
                             $lastrndseed{$partid} = $rndseed;              if ($$record{"$where.$partid.tries"} eq '') {
                             $lasttype{$partid} = $type;          $displaySub[0].=&mt('Trial not counted');
         }              } else {
         my $responseType=($isTask ? 'Task'          $displaySub[0].=&mt('Trial: [_1]',
           $$record{"$where.$partid.tries"});
                                   if (($rndseed ne '') && ($lastrndseed{$partid} ne '')) {
                                       if (($rndseed ne $lastrndseed{$partid}) &&
                                           (($type eq 'randomizetry') || ($lasttype{$partid} eq 'randomizetry'))) {
                                           $newvariation = '&nbsp;('.&mt('New variation this try').')';
                                       }
                                   }
                                   $lastrndseed{$partid} = $rndseed;
                                   $lasttype{$partid} = $type;
               }
               my $responseType=($isTask ? 'Task'
                                               : $responseType->{$partid}->{$responseId});                                                : $responseType->{$partid}->{$responseId});
         if (!exists($orders{$partid})) { $orders{$partid}={}; }              if (!exists($orders{$partid})) { $orders{$partid}={}; }
         if ((!exists($orders{$partid}->{$responseId})) || ($trial)) {              if ((!exists($orders{$partid}->{$responseId})) || ($trial)) {
     $orders{$partid}->{$responseId}=          $orders{$partid}->{$responseId}=
         &get_order($partid,$responseId,$symb,$uname,$udom,              &get_order($partid,$responseId,$symb,$uname,$udom,
                                            $no_increment,$type,$trial,$rndseed);                                                 $no_increment,$type,$trial,$rndseed);
         }              }
         $displaySub[0].='</b>'.$newvariation.'</span>'; # /nobreak              $displaySub[0].='</b>'.$newvariation.'</span>'; # /nobreak
         $displaySub[0].='&nbsp; '.              $displaySub[0].='&nbsp; '.
     &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom,$type,$trial,$rndseed).'<br />';          &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom,$type,$trial,$rndseed).'<br />';
                           }
                     }                      }
  }   }
     }      }
Line 5221  sub displaySubByDates { Line 5378  sub displaySubByDates {
     lc($$record{"$where.$partid.award"}).' '.      lc($$record{"$where.$partid.award"}).' '.
     $mark{$$record{"$where.$partid.solved"}}.      $mark{$$record{"$where.$partid.solved"}}.
     '<br />';      '<br />';
       } elsif (($is_tool) && (exists($$record{"$version:resource.$partid.solved"}))) {
    if ($$record{"$version:resource.$partid.solved"} =~ /^(in|)correct_by_passback$/) {
       $displaySub[1].=&mt('Grade passed back by external tool');
    }
     }      }
     if (exists $$record{"$where.$partid.regrader"}) {      if (exists $$record{"$where.$partid.regrader"}) {
  $displaySub[2].=$$record{"$where.$partid.regrader"}.   $displaySub[2].=$$record{"$where.$partid.regrader"};
     ' (<b>'.&mt('Part').':</b> '.$display_part.')';   unless ($is_tool) {
       $displaySub[2].=' (<b>'.&mt('Part').':</b> '.$display_part.')';
    }
     } elsif ($$record{"$version:resource.$partid.regrader"} =~ /\S/) {      } elsif ($$record{"$version:resource.$partid.regrader"} =~ /\S/) {
  $displaySub[2].=   $displaySub[2].=
     $$record{"$version:resource.$partid.regrader"}.      $$record{"$version:resource.$partid.regrader"};
     ' (<b>'.&mt('Part').':</b> '.$display_part.')';                  unless ($is_tool) {
       $displaySub[2].=' (<b>'.&mt('Part').':</b> '.$display_part.')';
                   }
     }      }
  }   }
  # needed because old essay regrader has not parts info   # needed because old essay regrader has not parts info
Line 5640  sub scantron_uploads { Line 5805  sub scantron_uploads {
 sub scantron_scantab {  sub scantron_scantab {
     my $result='<select name="scantron_format">'."\n";      my $result='<select name="scantron_format">'."\n";
     $result.='<option></option>'."\n";      $result.='<option></option>'."\n";
     my @lines = &get_scantronformat_file();      my @lines = &Apache::lonnet::get_scantronformat_file();
     if (@lines > 0) {      if (@lines > 0) {
         foreach my $line (@lines) {          foreach my $line (@lines) {
             next if (($line =~ /^\#/) || ($line eq ''));              next if (($line =~ /^\#/) || ($line eq ''));
Line 5652  sub scantron_scantab { Line 5817  sub scantron_scantab {
     return $result;      return $result;
 }  }
   
 =pod  
   
 =item get_scantronformat_file  
   
   Returns an array containing lines from the scantron format file for  
   the domain of the course.  
   
   If a url for a custom.tab file is listed in domain's configuration.db,   
   lines are from this file.  
   
   Otherwise, if a default.tab has been published in RES space by the   
   domainconfig user, lines are from this file.  
   
   Otherwise, fall back to getting lines from the legacy file on the  
   local server:  /home/httpd/lonTabs/default_scantronformat.tab      
   
 =cut  
   
 sub get_scantronformat_file {  
     my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};  
     my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$cdom);  
     my $gottab = 0;  
     my @lines;  
     if (ref($domconfig{'scantron'}) eq 'HASH') {  
         if ($domconfig{'scantron'}{'scantronformat'} ne '') {  
             my $formatfile = &Apache::lonnet::getfile($Apache::lonnet::perlvar{'lonDocRoot'}.$domconfig{'scantron'}{'scantronformat'});  
             if ($formatfile ne '-1') {  
                 @lines = split("\n",$formatfile,-1);  
                 $gottab = 1;  
             }  
         }  
     }  
     if (!$gottab) {  
         my $confname = $cdom.'-domainconfig';  
         my $default = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$cdom.'/'.$confname.'/default.tab';  
         my $formatfile =  &Apache::lonnet::getfile($default);  
         if ($formatfile ne '-1') {  
             @lines = split("\n",$formatfile,-1);  
             $gottab = 1;  
         }  
     }  
     if (!$gottab) {  
         my @domains = &Apache::lonnet::current_machine_domains();  
         if (grep(/^\Q$cdom\E$/,@domains)) {  
             my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');  
             @lines = <$fh>;  
             close($fh);  
         } else {  
             my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab');  
             @lines = <$fh>;  
             close($fh);  
         }  
     }  
     return @lines;  
 }  
   
 =pod   =pod 
   
 =item scantron_CODElist  =item scantron_CODElist
Line 5792  sub scantron_selectphase { Line 5901  sub scantron_selectphase {
  # Chunk of form to prompt for a scantron file upload.   # Chunk of form to prompt for a scantron file upload.
   
         $r->print('          $r->print('
     <br />      <br />');
     '.&Apache::loncommon::start_data_table('LC_scantron_action').'  
        '.&Apache::loncommon::start_data_table_header_row().'  
             <th>  
               &nbsp;'.&mt('Specify a bubblesheet data file to upload.').'  
             </th>  
        '.&Apache::loncommon::end_data_table_header_row().'  
        '.&Apache::loncommon::start_data_table_row().'  
             <td>  
 ');  
     my $default_form_data=&defaultFormData($symb);      my $default_form_data=&defaultFormData($symb);
     my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};      my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
     my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'};      my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'};
     my $alertmsg = &mt('Please use the browse button to select a file from your local directory.');      my $alertmsg = &mt('Please use the browse button to select a file from your local directory.');
     &js_escape(\$alertmsg);      &js_escape(\$alertmsg);
       my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($cdom);
     $r->print(&Apache::lonhtmlcommon::scripttag('      $r->print(&Apache::lonhtmlcommon::scripttag('
     function checkUpload(formname) {      function checkUpload(formname) {
  if (formname.upfile.value == "") {   if (formname.upfile.value == "") {
Line 5814  sub scantron_selectphase { Line 5915  sub scantron_selectphase {
     return false;      return false;
  }   }
  formname.submit();   formname.submit();
     }'));      }'.$formatjs));
     $r->print('      $r->print('
               <form enctype="multipart/form-data" action="/adm/grades" name="rules" method="post">                <form enctype="multipart/form-data" action="/adm/grades" name="rules" method="post">
                 '.$default_form_data.'                  '.$default_form_data.'
                 <input name="courseid" type="hidden" value="'.$cnum.'" />                  <input name="courseid" type="hidden" value="'.$cnum.'" />
                 <input name="domainid" type="hidden" value="'.$cdom.'" />                  <input name="domainid" type="hidden" value="'.$cdom.'" />
                 <input name="command" value="scantronupload_save" type="hidden" />                  <input name="command" value="scantronupload_save" type="hidden" />
                 '.&mt('File to upload: [_1]','<input type="file" name="upfile" size="50" />').'                '.&Apache::loncommon::start_data_table('LC_scantron_action').'
                 <br />                '.&Apache::loncommon::start_data_table_header_row().'
                 <input type="button" onclick="javascript:checkUpload(this.form);" value="'.&mt('Upload Bubblesheet Data').'" />                  <th>
               </form>                  &nbsp;'.&mt('Specify a bubblesheet data file to upload.').'
 ');                  </th>
                 '.&Apache::loncommon::end_data_table_header_row().'
                 '.&Apache::loncommon::start_data_table_row().'
               <td>
                   '.&mt('File to upload: [_1]','<input type="file" name="upfile" size="50" />').'<br />'."\n");
       if ($formatoptions) {
           $r->print('</td>
                    '.&Apache::loncommon::end_data_table_row().'
                    '.&Apache::loncommon::start_data_table_row().'
                    <td>'.$formattitle.('&nbsp;'x2).$formatoptions.'
                    </td>
                    '.&Apache::loncommon::end_data_table_row().'
                    '.&Apache::loncommon::start_data_table_row().'
                    <td>'
           );
       } else {
           $r->print(' <br />');
       }
       $r->print('<input type="button" onclick="javascript:checkUpload(this.form);" value="'.&mt('Upload Bubblesheet Data').'" />
                 </td>
                '.&Apache::loncommon::end_data_table_row().'
                '.&Apache::loncommon::end_data_table().'
                </form>'
       );
   
         $r->print('  
             </td>  
        '.&Apache::loncommon::end_data_table_row().'  
        '.&Apache::loncommon::end_data_table().'  
 ');  
     }      }
   
     # Chunk of form to prompt for a file to grade and how:      # Chunk of form to prompt for a file to grade and how:
Line 5944  sub scantron_selectphase { Line 6063  sub scantron_selectphase {
     return;      return;
 }  }
   
 =pod  
   
 =item get_scantron_config  
   
    Parse and return the bubblesheet configuration line selected as a  
    hash of configuration file fields.  
   
  Arguments:  
     which - the name of the configuration to parse from the file.  
   
   
  Returns:  
             If the named configuration is not in the file, an empty  
             hash is returned.  
     a hash with the fields  
       name         - internal name for the this configuration setup  
       description  - text to display to operator that describes this config  
       CODElocation - if 0 or the string 'none'  
                           - no CODE exists for this config  
                      if -1 || the string 'letter'  
                           - a CODE exists for this config and is  
                             a string of letters  
                      Unsupported value (but planned for future support)  
                           if a positive integer  
                                - The CODE exists as the first n items from  
                                  the question section of the form  
                           if the string 'number'  
                                - The CODE exists for this config and is  
                                  a string of numbers  
       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/employee ID 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  
                     the sheet. (usually either 1 or 10)  
       Qon         - either a single character representing the character used  
                     to signal a bubble was chosen in the positional setup, or  
                     the string 'letter' if the letter of the chosen bubble is  
                     in the final, or 'number' if a number representing the  
                     chosen bubble is in the file (1->A 0->J)  
       Qoff        - the character used to represent that a bubble was  
                     left blank  
       PaperID     - if the scanning process generates a unique number for each  
                     sheet scanned the column that this ID number starts in  
       PaperIDlength - number of columns that comprise the unique ID number  
                       for the sheet of paper  
       FirstName   - column that the first name starts in  
       FirstNameLength - number of columns that the first name spans  
    
       LastName    - column that the last name starts in  
       LastNameLength - number of columns that the last name spans  
       BubblesPerRow - number of bubbles available in each row used to   
                       bubble an answer. (If not specified, 10 assumed).  
   
 =cut  
   
 sub get_scantron_config {  
     my ($which) = @_;  
     my @lines = &get_scantronformat_file();  
     my %config;  
     #FIXME probably should move to XML it has already gotten a bit much now  
     foreach my $line (@lines) {  
  my ($name,$descrip)=split(/:/,$line);  
  if ($name ne $which ) { next; }  
  chomp($line);  
  my @config=split(/:/,$line);  
  $config{'name'}=$config[0];  
  $config{'description'}=$config[1];  
  $config{'CODElocation'}=$config[2];  
  $config{'CODEstart'}=$config[3];  
  $config{'CODElength'}=$config[4];  
  $config{'IDstart'}=$config[5];  
  $config{'IDlength'}=$config[6];  
  $config{'Qstart'}=$config[7];  
   $config{'Qlength'}=$config[8];  
  $config{'Qoff'}=$config[9];  
  $config{'Qon'}=$config[10];  
  $config{'PaperID'}=$config[11];  
  $config{'PaperIDlength'}=$config[12];  
  $config{'FirstName'}=$config[13];  
  $config{'FirstNamelength'}=$config[14];  
  $config{'LastName'}=$config[15];  
  $config{'LastNamelength'}=$config[16];  
         $config{'BubblesPerRow'}=$config[17];  
  last;  
     }  
     return %config;  
 }  
   
 =pod   =pod 
   
 =item username_to_idmap  =item username_to_idmap
Line 6083  sub username_to_idmap { Line 6110  sub username_to_idmap {
    Process a requested correction to a scanline.     Process a requested correction to a scanline.
   
   Arguments:    Arguments:
     $scantron_config   - hash from &get_scantron_config()      $scantron_config   - hash from &Apache::lonnet::get_scantron_config()
     $scan_data         - hash of correction information       $scan_data         - hash of correction information 
                           (see &scantron_getfile())                            (see &scantron_getfile())
     $line              - existing scanline      $line              - existing scanline
Line 6766  sub scantron_filter { Line 6793  sub scantron_filter {
   
 sub scantron_process_corrections {  sub scantron_process_corrections {
     my ($r) = @_;      my ($r) = @_;
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
     my $which=$env{'form.scantron_line'};      my $which=$env{'form.scantron_line'};
Line 6935  sub check_for_error { Line 6962  sub check_for_error {
 sub scantron_warning_screen {  sub scantron_warning_screen {
     my ($button_text,$symb)=@_;      my ($button_text,$symb)=@_;
     my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});      my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my $CODElist;      my $CODElist;
     if ($scantron_config{'CODElocation'} &&      if ($scantron_config{'CODElocation'} &&
  $scantron_config{'CODEstart'} &&   $scantron_config{'CODEstart'} &&
Line 7091  sub scantron_validate_file { Line 7118  sub scantron_validate_file {
     #get the student pick code ready      #get the student pick code ready
     $r->print(&Apache::loncommon::studentbrowser_javascript());      $r->print(&Apache::loncommon::studentbrowser_javascript());
     my $nav_error;      my $nav_error;
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config);      my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config);
     if ($nav_error) {      if ($nav_error) {
         $r->print(&navmap_errormsg());          $r->print(&navmap_errormsg());
Line 7551  sub scantron_validate_ID { Line 7578  sub scantron_validate_ID {
     my %idmap=&username_to_idmap($classlist);      my %idmap=&username_to_idmap($classlist);
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
   
     my $nav_error;      my $nav_error;
Line 8021  sub prompt_for_corrections { Line 8048  sub prompt_for_corrections {
   
  Arguments:   Arguments:
     $r           - Apache request object      $r           - Apache request object
     $scan_config - hash from &get_scantron_config()      $scan_config - hash from &Apache::lonnet::get_scantron_config()
     $line        - Number of the line being displayed.      $line        - Number of the line being displayed.
     $questionnum - Question number (may include subquestion)      $questionnum - Question number (may include subquestion)
     $error       - Type of error.      $error       - Type of error.
Line 8185  sub get_codes { Line 8212  sub get_codes {
   
 sub scantron_validate_CODE {  sub scantron_validate_CODE {
     my ($r,$currentphase) = @_;      my ($r,$currentphase) = @_;
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     if ($scantron_config{'CODElocation'} &&      if ($scantron_config{'CODElocation'} &&
  $scantron_config{'CODEstart'} &&   $scantron_config{'CODEstart'} &&
  $scantron_config{'CODElength'}) {   $scantron_config{'CODElength'}) {
Line 8259  sub scantron_validate_doublebubble { Line 8286  sub scantron_validate_doublebubble {
         &Apache::lonnet::decode_symb($env{'form.selectpage'});          &Apache::lonnet::decode_symb($env{'form.selectpage'});
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
   
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
Line 8441  sub scantron_validate_missingbubbles { Line 8468  sub scantron_validate_missingbubbles {
         &Apache::lonnet::decode_symb($env{'form.selectpage'});          &Apache::lonnet::decode_symb($env{'form.selectpage'});
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
   
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
Line 8570  sub hand_bubble_option { Line 8597  sub hand_bubble_option {
         }          }
     }      }
     if ($needs_hand_bubbles) {      if ($needs_hand_bubbles) {
         my %scantron_config=&get_scantron_config($env{'form.scantron_format'});          my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
         my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);          my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
         return &mt('The sequence to be graded contains response types which are handgraded.').'<p>'.          return &mt('The sequence to be graded contains response types which are handgraded.').'<p>'.
                &mt('If you have already graded these by bubbling sheets to indicate points awarded, [_1]what point value is assigned to a filled last bubble in each row?','<br />').                 &mt('If you have already graded these by bubbling sheets to indicate points awarded, [_1]what point value is assigned to a filled last bubble in each row?','<br />').
Line 8589  sub scantron_process_students { Line 8616  sub scantron_process_students {
     }      }
     my $default_form_data=&defaultFormData($symb);      my $default_form_data=&defaultFormData($symb);
   
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);       my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config); 
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
Line 8657  SCANTRONFORM Line 8684  SCANTRONFORM
  return ''; # Dunno why the other returns return '' rather than just returning.   return ''; # Dunno why the other returns return '' rather than just returning.
     }      }
   
     my %lettdig = &letter_to_digits();      my %lettdig = &Apache::lonnet::letter_to_digits();
     my $numletts = scalar(keys(%lettdig));      my $numletts = scalar(keys(%lettdig));
     my %orderedforcode;      my %orderedforcode;
   
Line 8984  sub grade_student_bubbles { Line 9011  sub grade_student_bubbles {
 sub scantron_upload_scantron_data {  sub scantron_upload_scantron_data {
     my ($r,$symb)=@_;      my ($r,$symb)=@_;
     my $dom = $env{'request.role.domain'};      my $dom = $env{'request.role.domain'};
       my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($dom);
     my $domdesc = &Apache::lonnet::domain($dom,'description');      my $domdesc = &Apache::lonnet::domain($dom,'description');
     $r->print(&Apache::loncommon::coursebrowser_javascript($dom));      $r->print(&Apache::loncommon::coursebrowser_javascript($dom));
     my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',      my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',
Line 9023  sub scantron_upload_scantron_data { Line 9051  sub scantron_upload_scantron_data {
         return;          return;
     }      }
   
       '.$formatjs.'
 '));  '));
     $r->print('      $r->print('
 <h3>'.&mt('Send bubblesheet data to a course').'</h3>  <h3>'.&mt('Send bubblesheet data to a course').'</h3>
Line 9038  sub scantron_upload_scantron_data { Line 9067  sub scantron_upload_scantron_data {
   &Apache::lonhtmlcommon::row_closure().    &Apache::lonhtmlcommon::row_closure().
   &Apache::lonhtmlcommon::row_title(&mt('Domain')).    &Apache::lonhtmlcommon::row_title(&mt('Domain')).
   '<input name="domainid" type="hidden" />'.$domdesc.    '<input name="domainid" type="hidden" />'.$domdesc.
   &Apache::lonhtmlcommon::row_closure().    &Apache::lonhtmlcommon::row_closure());
       if ($formatoptions) {
           $r->print(&Apache::lonhtmlcommon::row_title($formattitle).$formatoptions.
                     &Apache::lonhtmlcommon::row_closure());
       }
       $r->print(
   &Apache::lonhtmlcommon::row_title(&mt('File to upload')).    &Apache::lonhtmlcommon::row_title(&mt('File to upload')).
   '<input type="file" name="upfile" size="50" />'.    '<input type="file" name="upfile" size="50" />'.
   &Apache::lonhtmlcommon::row_closure(1).    &Apache::lonhtmlcommon::row_closure(1).
Line 9051  sub scantron_upload_scantron_data { Line 9085  sub scantron_upload_scantron_data {
     return '';      return '';
 }  }
   
   sub scantron_upload_dataformat {
       my ($dom) = @_;
       my ($formatoptions,$formattitle,$formatjs);
       $formatjs = <<'END';
   function toggleScantab(form) {
      return;
   }
   END
       my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$dom);
       if (ref($domconfig{'scantron'}) eq 'HASH') {
           if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
               if (keys(%{$domconfig{'scantron'}{'config'}}) > 1) {
                   if (($domconfig{'scantron'}{'config'}{'dat'}) &&
                       (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH')) {
                       if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}})) {
                           my ($onclick,$formatextra,$singleline);
                           my @lines = &Apache::lonnet::get_scantronformat_file();
                           my $count = 0;
                           foreach my $line (@lines) {
                               next if ($line =~ /^#/);
                               $singleline = $line;
                               $count ++;
                           }
                           if ($count > 1) {
                               $formatextra = '<div style="display:none" id="bubbletype">'.
                                              &scantron_scantab().'</div>';
                               $onclick = ' onclick="toggleScantab(this.form);"';
                               $formatjs = <<"END";
   function toggleScantab(form) {
       var divid = 'bubbletype';
       if (document.getElementById(divid)) {
           var radioname = 'fileformat';
           var num = form.elements[radioname].length;
           if (num) {
               for (var i=0; i<num; i++) {
                   if (form.elements[radioname][i].checked) {
                       var chosen = form.elements[radioname][i].value;
                       if (chosen == 'dat') {
                           document.getElementById(divid).style.display = 'none';
                       } else if (chosen == 'csv') {
                           document.getElementById(divid).style.display = 'inline-block';
                       }
                   }
               }
           }
       }
       return;
   }
   
   END
                           } elsif ($count == 1) {
                               my $formatname = (split(/:/,$singleline,2))[0];
                               $formatextra = '<input type="hidden" name="scantron_format" value="'.$formatname.'" />';
                           }
                           $formattitle = &mt('File format');
                           $formatoptions = '<label><input name="fileformat" type="radio" value="dat" checked="checked"'.$onclick.' />'.
                                            &mt('Plain Text (no delimiters)').
                                            '</label>'.('&nbsp;'x2).
                                            '<label><input name="fileformat" type="radio" value="csv"'.$onclick.' />'.
                                            &mt('Comma separated values').'</label>'.$formatextra;
                       }
                   }
               } elsif (keys(%{$domconfig{'scantron'}{'config'}}) == 1) {
                   if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}})) {
                       $formattitle = &mt('Format of bubblesheet data file:');
                       $formatoptions = &scantron_scantab();
                   }
               }
           }
       }
       return ($formatoptions,$formattitle,$formatjs);
   }
   
 sub scantron_upload_scantron_data_save {  sub scantron_upload_scantron_data_save {
     my($r,$symb)=@_;      my($r,$symb)=@_;
Line 9077  sub scantron_upload_scantron_data_save { Line 9183  sub scantron_upload_scantron_data_save {
                 &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.',                  &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.',
                         '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>'),1));                          '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>'),1));
     } else {      } else {
         my $result =           my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$env{'form.domainid'});
             &Apache::lonnet::userfileupload('upfile','','scantron','','','',          my $parser;
           if (ref($domconfig{'scantron'}) eq 'HASH') {
               if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
                   my $is_csv;
                   my @possibles = keys(%{$domconfig{'scantron'}{'config'}});
                   if (@possibles > 1) {
                       if ($env{'form.fileformat'} eq 'csv') {
                           if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
                               if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) {
                                   $is_csv = 1;
                               }
                           }
                       }
                   } elsif (@possibles == 1) {
                       if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
                           if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) {
                               $is_csv = 1;
                           }
                       }
                   }
                   if ($is_csv) {
                      $parser = $domconfig{'scantron'}{'config'}{'csv'};
                   }
               }
           }
           my $result =
               &Apache::lonnet::userfileupload('upfile','scantron','scantron',$parser,'','',
                                             $env{'form.courseid'},$env{'form.domainid'});                                              $env{'form.courseid'},$env{'form.domainid'});
         if ($result =~ m{^/uploaded/}) {          if ($result =~ m{^/uploaded/}) {
             $r->print(              $r->print(
Line 9123  sub validate_uploaded_scantron_file { Line 9255  sub validate_uploaded_scantron_file {
             $idmap{$lckey} = $idmap{$key};              $idmap{$lckey} = $idmap{$key};
         }          }
         my %unique_formats;          my %unique_formats;
         my @formatlines = &get_scantronformat_file();          my @formatlines = &Apache::lonnet::get_scantronformat_file();
         foreach my $line (@formatlines) {          foreach my $line (@formatlines) {
             chomp($line);              chomp($line);
             my @config = split(/:/,$line);              my @config = split(/:/,$line);
Line 9264  sub checkscantron_results { Line 9396  sub checkscantron_results {
     my ($r,$symb) = @_;      my ($r,$symb) = @_;
     if (!$symb) {return '';}      if (!$symb) {return '';}
     my $cid = $env{'request.course.id'};      my $cid = $env{'request.course.id'};
     my %lettdig = &letter_to_digits();      my %lettdig = &Apache::lonnet::letter_to_digits();
     my $numletts = scalar(keys(%lettdig));      my $numletts = scalar(keys(%lettdig));
     my $cnum = $env{'course.'.$cid.'.num'};      my $cnum = $env{'course.'.$cid.'.num'};
     my $cdom = $env{'course.'.$cid.'.domain'};      my $cdom = $env{'course.'.$cid.'.domain'};
     my (undef, undef, $sequence) = &Apache::lonnet::decode_symb($env{'form.selectpage'});      my (undef, undef, $sequence) = &Apache::lonnet::decode_symb($env{'form.selectpage'});
     my %record;      my %record;
     my %scantron_config =      my %scantron_config =
         &Apache::grades::get_scantron_config($env{'form.scantron_format'});          &Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
     my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);      my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
     my ($scanlines,$scan_data)=&Apache::grades::scantron_getfile();      my ($scanlines,$scan_data)=&Apache::grades::scantron_getfile();
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
Line 9595  sub verify_scantron_grading { Line 9727  sub verify_scantron_grading {
     return ($counter,$record);      return ($counter,$record);
 }  }
   
 sub letter_to_digits {  
     my %lettdig = (  
                     A => 1,  
                     B => 2,  
                     C => 3,  
                     D => 4,  
                     E => 5,  
                     F => 6,  
                     G => 7,  
                     H => 8,  
                     I => 9,  
                     J => 0,  
                   );  
     return %lettdig;  
 }  
   
   
 #-------- end of section for handling grading scantron forms -------  #-------- end of section for handling grading scantron forms -------
 #  #
Line 9760  sub submit_options_table { Line 9876  sub submit_options_table {
     my ($request,$symb) = @_;      my ($request,$symb) = @_;
     if (!$symb) {return '';}      if (!$symb) {return '';}
     &commonJSfunctions($request);      &commonJSfunctions($request);
     my ($is_tool) = ($symb =~ /ext\.tool$/);      my $is_tool = ($symb =~ /ext\.tool$/);
     my $result;      my $result;
   
     $result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n".      $result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n".
Line 9780  sub submit_options_download { Line 9896  sub submit_options_download {
     my ($request,$symb) = @_;      my ($request,$symb) = @_;
     if (!$symb) {return '';}      if (!$symb) {return '';}
   
     my ($is_tool) = ($symb =~ /ext\.tool$/);      my $is_tool = ($symb =~ /ext\.tool$/);
     &commonJSfunctions($request);      &commonJSfunctions($request);
   
     my $result='<form action="/adm/grades" method="post" name="gradingMenu">'."\n".      my $result='<form action="/adm/grades" method="post" name="gradingMenu">'."\n".
         '<input type="hidden" name="symb"        value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n";          '<input type="hidden" name="symb"        value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n";
     $result.='      $result.='
 <h2>  <h2>
   '.&mt('Select Students for Which to Download Submissions').'    '.&mt('Select Students for whom to Download Submissions').'
 </h2>'.&selectfield(1,$is_tool).'  </h2>'.&selectfield(1,$is_tool).'
                 <input type="hidden" name="command" value="downloadfileslink" />                   <input type="hidden" name="command" value="downloadfileslink" /> 
               <input type="submit" value="'.&mt('Next').' &rarr;" />                <input type="submit" value="'.&mt('Next').' &rarr;" />
Line 9804  sub submit_options { Line 9920  sub submit_options {
     my ($request,$symb) = @_;      my ($request,$symb) = @_;
     if (!$symb) {return '';}      if (!$symb) {return '';}
   
     my ($is_tool) = ($symb =~ /ext\.tool$/);      my $is_tool = ($symb =~ /ext\.tool$/);
     &commonJSfunctions($request);      &commonJSfunctions($request);
     my $result;      my $result;
   
Line 10503  sub navmap_errormsg { Line 10619  sub navmap_errormsg {
 }  }
   
 sub startpage {  sub startpage {
     my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js) = @_;      my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js,$onload) = @_;
       my %args;
       if ($onload) {
            my %loaditems = (
                           'onload' => $onload,
                         );
            $args{'add_entries'} = \%loaditems;
       }
     if ($nomenu) {      if ($nomenu) {
         $r->print(&Apache::loncommon::start_page("Student's Version",$js,{'only_body' => '1'}));          $args{'only_body'} = 1; 
           $r->print(&Apache::loncommon::start_page("Student's Version",$js,\%args);
     } else {      } else {
         unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});          unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
         $r->print(&Apache::loncommon::start_page('Grading',$js,          $args{'bread_crumbs'} = $crumbs;
                                                  {'bread_crumbs' => $crumbs}));          $r->print(&Apache::loncommon::start_page('Grading',$js,\%args));
         &Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));          &Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));
     }      }
     unless ($nodisplayflag) {      unless ($nodisplayflag) {
Line 10693  sub handler { Line 10817  sub handler {
             &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);              &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
     $request->print(&csvuploadassign($request,$symb));      $request->print(&csvuploadassign($request,$symb));
  } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {   } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {
             &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);              &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1,
                          undef,undef,undef,undef,'toggleScantab(document.rules);');
     $request->print(&scantron_selectphase($request,undef,$symb));      $request->print(&scantron_selectphase($request,undef,$symb));
   } elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {    } elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {
             &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);              &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
Line 10707  sub handler { Line 10832  sub handler {
   } elsif ($command eq 'scantronupload' &&     } elsif ($command eq 'scantronupload' && 
   (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||    (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
   &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {    &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
             &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);              &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1,
                          undef,undef,undef,undef,'toggleScantab(document.rules);');
      $request->print(&scantron_upload_scantron_data($request,$symb));        $request->print(&scantron_upload_scantron_data($request,$symb)); 
   } elsif ($command eq 'scantronupload_save' &&    } elsif ($command eq 'scantronupload_save' &&
   (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||    (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
Line 10727  sub handler { Line 10853  sub handler {
          } elsif ($command eq 'downloadfileslink' && $perm{'vgr'}) {           } elsif ($command eq 'downloadfileslink' && $perm{'vgr'}) {
             &startpage($request,$symb,              &startpage($request,$symb,
    [{href=>&href_symb_cmd($symb,'downloadfilesselect'), text=>'Select which submissions to download'},     [{href=>&href_symb_cmd($symb,'downloadfilesselect'), text=>'Select which submissions to download'},
     {href=>'', text=>'Download submissions'}]);      {href=>'', text=>'Download submitted files'}]);
             &submit_download_link($request,$symb);              &submit_download_link($request,$symb);
  } elsif ($command) {   } elsif ($command) {
             &startpage($request,$symb,[{href=>'', text=>'Access denied'}]);              &startpage($request,$symb,[{href=>'', text=>'Access denied'}]);

Removed from v.1.745  
changed lines
  Added in v.1.755


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>