Diff for /loncom/interface/loncoursedata.pm between versions 1.3 and 1.20

version 1.3, 2002/07/22 20:35:05 version 1.20, 2002/08/15 18:16:29
Line 51  package Apache::loncoursedata; Line 51  package Apache::loncoursedata;
 use strict;  use strict;
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
 use Apache::lonnet();  use Apache::lonnet();
   use Apache::lonhtmlcommon;
 use HTML::TokeParser;  use HTML::TokeParser;
 use GDBM_File;  use GDBM_File;
   
Line 118  sub DownloadClasslist { Line 119  sub DownloadClasslist {
     }      }
   
     %classlist=&Apache::lonnet::dump('classlist',$courseDomain, $courseNumber);      %classlist=&Apache::lonnet::dump('classlist',$courseDomain, $courseNumber);
     my ($checkForError)=keys (%classlist);      foreach(keys (%classlist)) {
     if($checkForError =~ /^(con_lost|error|no_such_host)/i) {          if(/^(con_lost|error|no_such_host)/i) {
         return \%classlist;              return \%classlist;
           }
     }      }
   
     foreach my $name (keys(%classlist)) {      foreach my $name (keys(%classlist)) {
Line 157  sub DownloadClasslist { Line 159  sub DownloadClasslist {
   
 =pod  =pod
   
 =item &DownloadStudentCourseInformation()  =item &DownloadCourseInformation()
   
 Dump of all the course information for a single student.  There is no  Dump of all the course information for a single student.  There is no
 pruning of data, it is all stored in a hash and returned.  It also  pruning of data, it is all stored in a hash and returned.  It also
Line 181  database. Line 183  database.
   
 =cut  =cut
   
 sub DownloadStudentCourseInformation {  sub DownloadCourseInformation {
     my ($name,$courseID,$lastDownloadTime)=@_;      my ($namedata,$courseID,$lastDownloadTime,$WhatIWant)=@_;
     my %courseData;      my %courseData;
     my ($studentName,$studentDomain) = split(/\:/,$name);      my ($name,$domain) = split(/\:/,$namedata);
   
     my $modifiedTime = &GetFileTimestamp($studentDomain, $studentName,      my $modifiedTime = &GetFileTimestamp($domain, $name,
                                       $courseID.'.db',                                         $courseID.'.db', 
                                       $Apache::lonnet::perlvar{'lonUsersDir'});                                        $Apache::lonnet::perlvar{'lonUsersDir'});
     if($lastDownloadTime >= $modifiedTime) {  
         $courseData{'lastDownloadTime'}=time;      if($lastDownloadTime >= $modifiedTime && $modifiedTime >= 0) {
         $courseData{'UpToDate'} = 'true';          $courseData{$namedata.':lastDownloadTime'}=time;
           $courseData{$namedata.':UpToDate'} = 'true';
         return \%courseData;          return \%courseData;
     }      }
   
     # Download student course data      # Download course data
     %courseData=&Apache::lonnet::dump($courseID, $studentDomain, $studentName);      if(!defined($WhatIWant)) {
           $WhatIWant = '.';
       }
       %courseData=&Apache::lonnet::dump($courseID, $domain, $name, $WhatIWant);
     $courseData{'UpToDate'} = 'false';      $courseData{'UpToDate'} = 'false';
     $courseData{'lastDownloadTime'}=time;      $courseData{'lastDownloadTime'}=time;
     return \%courseData;  
       my %newData;
       foreach (keys(%courseData)) {
           $newData{$namedata.':'.$_} = $courseData{$_};
       }
   
       return \%newData;
 }  }
   
 # ----- END DOWNLOAD INFORMATION ---------------------------------------  # ----- END DOWNLOAD INFORMATION ---------------------------------------
Line 254  sub ProcessTopResourceMap { Line 266  sub ProcessTopResourceMap {
             if($c->aborted()) {              if($c->aborted()) {
                 return;                  return;
             }              }
     if(tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {      if(tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) {
  last;   last;
     }      }
     $tieTries++;      $tieTries++;
Line 277  sub ProcessTopResourceMap { Line 289  sub ProcessTopResourceMap {
     $currentSequence=-1;      $currentSequence=-1;
     my $topLevelSequenceNumber = $currentSequence;      my $topLevelSequenceNumber = $currentSequence;
   
       my %sequenceRecord;
     while(1) {      while(1) {
         if($c->aborted()) {          if($c->aborted()) {
             last;              last;
         }          }
  # HANDLE NEW SEQUENCE!   # HANDLE NEW SEQUENCE!
  #if page || sequence   #if page || sequence
  if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}})) {   if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}}) &&
              !defined($sequenceRecord{$currentResourceID})) {
               $sequenceRecord{$currentResourceID}++;
     push(@sequences, $currentSequence);      push(@sequences, $currentSequence);
     push(@currentResource, $currentResourceID);      push(@currentResource, $currentResourceID);
     push(@finishResource, $lastResourceID);      push(@finishResource, $lastResourceID);
Line 313  sub ProcessTopResourceMap { Line 328  sub ProcessTopResourceMap {
     last;      last;
  }   }
     }      }
               next;
  }   }
   
  # Handle gradable resources: exams, problems, etc   # Handle gradable resources: exams, problems, etc
Line 321  sub ProcessTopResourceMap { Line 337  sub ProcessTopResourceMap {
         my $partB=$2;          my $partB=$2;
  if($hash{'src_'.$currentResourceID}=~   if($hash{'src_'.$currentResourceID}=~
    /\.(problem|exam|quiz|assess|survey|form)$/ &&     /\.(problem|exam|quiz|assess|survey|form)$/ &&
    $partA eq $currentSequence) {     $partA eq $currentSequence && 
              !defined($sequenceRecord{$currentSequence.':'.
                                       $currentResourceID})) {
               $sequenceRecord{$currentSequence.':'.$currentResourceID}++;
     my $Problem = &Apache::lonnet::symbclean(      my $Problem = &Apache::lonnet::symbclean(
   &Apache::lonnet::declutter($hash{'map_id_'.$partA}).    &Apache::lonnet::declutter($hash{'map_id_'.$partA}).
   '___'.$partB.'___'.    '___'.$partB.'___'.
Line 341  sub ProcessTopResourceMap { Line 360  sub ProcessTopResourceMap {
 #                &Apache::lonnet::metdata($meta,'title');  #                &Apache::lonnet::metdata($meta,'title');
             $cache->{$currentResourceID.':title'}=              $cache->{$currentResourceID.':title'}=
                 $hash{'title_'.$currentResourceID};                  $hash{'title_'.$currentResourceID};
               $cache->{$currentResourceID.':source'}=
                   $hash{'src_'.$currentResourceID};
   
             # Get Parts for problem              # Get Parts for problem
     foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {              my %beenHere;
  if($_=~/^stores\_(\d+)\_tries$/) {              foreach (split(/\,/,&Apache::lonnet::metadata($meta,'packages'))) {
     my $Part=&Apache::lonnet::metadata($meta,$_.'.part');                  if(/^\w+response_\d+.*/) {
                     if(!defined($cache->{$currentSequence.':'.                      my (undef, $partId, $responseId) = split(/_/,$_);
                                           $currentResourceID.':parts'})) {                      if($beenHere{'p:'.$partId} ==  0) {
                         $cache->{$currentSequence.':'.$currentResourceID.                          $beenHere{'p:'.$partId}++;
                                    ':parts'}=$Part;                          if(!defined($cache->{$currentSequence.':'.
                     } else {                                              $currentResourceID.':parts'})) {
                         $cache->{$currentSequence.':'.$currentResourceID.                              $cache->{$currentSequence.':'.$currentResourceID.
                                    ':parts'}.=':'.$Part;                                       ':parts'}=$partId;
                           } else {
                               $cache->{$currentSequence.':'.$currentResourceID.
                                        ':parts'}.=':'.$partId;
                           }
                     }                      }
                     foreach (split(/\,/,                      if($beenHere{'r:'.$partId.':'.$responseId} == 0) {
                              &Apache::lonnet::metadata($meta,'packages'))) {                          $beenHere{'r:'.$partId.':'.$responseId}++;
                         if($_=~/^optionresponse\_($Part)\_(\w+)$/) {                          if(!defined($cache->{$currentSequence.':'.
                             if(defined($cache->{'OptionResponses'})) {                                               $currentResourceID.':'.$partId.
                                 $cache->{'OptionResponses'}.= ':::'.                                               ':responseIDs'})) {
                                     $hash{'src_'.$currentResourceID}.'::'.                              $cache->{$currentSequence.':'.$currentResourceID.
                                     $hash{'title_'.$currentResourceID}.'::'.                                       ':'.$partId.':responseIDs'}=$responseId;
                                     $Part.'::'.$Problem;                          } else {
                             } else {                              $cache->{$currentSequence.':'.$currentResourceID.
                                 $cache->{'OptionResponses'}=                                       ':'.$partId.':responseIDs'}.=':'.
                                     $hash{'src_'.$currentResourceID}.'::'.                                                                    $responseId;
                                     $hash{'title_'.$currentResourceID}.'::'.                          }
                                     $Part.'::'.$Problem;                      }
                             }                      if(/^optionresponse/ && 
                          $beenHere{'o:'.$partId.':'.$currentResourceID} == 0) {
                           $beenHere{'o:'.$partId.$currentResourceID}++;
                           if(defined($cache->{'OptionResponses'})) {
                               $cache->{'OptionResponses'}.= ':::'.
                                   $currentSequence.':'.$currentResourceID.':'.
                                   $partId.':'.$responseId;
                           } else {
                               $cache->{'OptionResponses'}= $currentSequence.':'.
                                   $currentResourceID.':'.
                                   $partId.':'.$responseId;
                         }                          }
                     }                      }
                 }                  }
     }              }
  }          }
   
  # if resource == finish resource, then it is the end of a sequence/page   # if resource == finish resource, then it is the end of a sequence/page
  if($currentResourceID eq $lastResourceID) {   if($currentResourceID eq $lastResourceID) {
Line 421  sub ProcessTopResourceMap { Line 456  sub ProcessTopResourceMap {
     if($currentSequence eq $topLevelSequenceNumber) {      if($currentSequence eq $topLevelSequenceNumber) {
  last;   last;
     }      }
  }          }
   
  # MOVE!!!   # MOVE!!!
  # move to next resource   # move to next resource
  unless(defined($hash{'to_'.$currentResourceID})) {   unless(defined($hash{'to_'.$currentResourceID})) {
     # big problem, need to handle.  Next is probably wrong      # big problem, need to handle.  Next is probably wrong
               my $errorMessage = 'Big problem in ';
               $errorMessage .= 'loncoursedata::ProcessTopLevelMap.';
               $errorMessage .= '  bighash to_$currentResourceID not defined!';
               &Apache::lonnet::logthis($errorMessage);
     last;      last;
  }   }
  my @nextResources=();   my @nextResources=();
  foreach (split(/\,/,$hash{'to_'.$currentResourceID})) {   foreach (split(/\,/,$hash{'to_'.$currentResourceID})) {
     push(@nextResources, $hash{'goesto_'.$_});              if(!defined($sequenceRecord{$currentSequence.':'.
                                           $hash{'goesto_'.$_}})) {
                   push(@nextResources, $hash{'goesto_'.$_});
               }
  }   }
  push(@currentResource, @nextResources);   push(@currentResource, @nextResources);
  # Set the next resource to be processed   # Set the next resource to be processed
Line 449  sub ProcessTopResourceMap { Line 491  sub ProcessTopResourceMap {
   
 =pod  =pod
   
 =item &ProcessSection()  
   
 Determine the section number for a student for the class.  A student can have   
 multiple sections for the same class.  The correct one is chosen.  
   
 =over 4  
   
 Input: $sectionData, $courseid, $ActiveFlag  
   
 $sectionData:  A pointer to a hash containing all section data for this   
 student for the class  
   
 $courseid:  The course ID.  
   
 $ActiveFlag:  The student's active status (Active/Expired)  
   
 Output: $oldsection, $cursection, or -1  
   
 $oldsection and $cursection and sections number that will be displayed in the   
 chart.  
   
 -1 is returned if an error occurs.  
   
 =back  
   
   
 sub ProcessSection {  
     my ($sectionData,$courseid,$ActiveFlag)=@_;  
     $courseid=~s/\_/\//g;  
     $courseid=~s/^(\w)/\/$1/;  
   
     my $cursection='-1';  
     my $oldend='-1';  
     my $status='Expired';  
     my $section='';  
     foreach my $key (keys (%$sectionData)) {  
  my $value = $sectionData->{$key};  
         if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {  
     $section=$1;  
     if($key eq $courseid.'_st') {  
  $section='';  
     }  
   
     my ($dummy,$end,$start)=split(/\_/,$value);  
     my $now=time;  
             my $notactive=0;  
             if ($start) {  
                 if($now<$start) {  
                     $notactive=1;  
                 }  
             }  
             if($end) {  
                 if ($now>$end) {  
                     $notactive=1;  
                 }  
             }  
             if($notactive == 0) {  
                 $status='Active';  
                 $cursection=$section;  
                 last;  
             }  
             if($notactive == 1) {  
                 if($end > $oldend) {  
                     $cursection=$section;  
                     $oldend = $end;  
                 }  
             }  
  }  
     }  
   
     return ($cursections, $status);  
 }  
   
 =cut  
   
 =pod  
   
 =item &ProcessClasslist()  =item &ProcessClasslist()
   
 Taking the class list dumped from &DownloadClasslist(), all the   Taking the class list dumped from &DownloadClasslist(), all the 
Line 582  sub ProcessClasslist { Line 547  sub ProcessClasslist {
         if($c->aborted()) {          if($c->aborted()) {
             return ();              return ();
         }          }
         push(@names,$name);  
         my $studentInformation = $classlist->{$name.':studentInformation'},          my $studentInformation = $classlist->{$name.':studentInformation'},
         my $sectionData = $classlist->{$name.':sections'},          my $sectionData = $classlist->{$name.':sections'},
         my $date = $classlist->{$name},          my $date = $classlist->{$name},
Line 590  sub ProcessClasslist { Line 554  sub ProcessClasslist {
   
         $cache->{$name.':username'}=$studentName;          $cache->{$name.':username'}=$studentName;
         $cache->{$name.':domain'}=$studentDomain;          $cache->{$name.':domain'}=$studentDomain;
           # Initialize timestamp for student
         if(!defined($cache->{$name.':lastDownloadTime'})) {          if(!defined($cache->{$name.':lastDownloadTime'})) {
             $cache->{$name.':lastDownloadTime'}='Not downloaded';              $cache->{$name.':lastDownloadTime'}='Not downloaded';
               $cache->{$name.':updateTime'}=' Not updated';
         }          }
   
         my ($checkForError)=keys(%$studentInformation);          my $error = 0;
         if($checkForError =~ /^(con_lost|error|no_such_host)/i) {          foreach(keys(%$studentInformation)) {
             $cache->{$name.':error'}=              if(/^(con_lost|error|no_such_host)/i) {
                 'Could not download student environment data.';                  $cache->{$name.':error'}=
             $cache->{$name.':fullname'}='';                      'Could not download student environment data.';
             $cache->{$name.':id'}='';                  $cache->{$name.':fullname'}='';
         } else {                  $cache->{$name.':id'}='';
             $cache->{$name.':fullname'}=&ProcessFullName(                  $error = 1;
               }
           }
           next if($error);
           push(@names,$name);
           $cache->{$name.':fullname'}=&ProcessFullName(
                                           $studentInformation->{'lastname'},                                            $studentInformation->{'lastname'},
                                           $studentInformation->{'generation'},                                            $studentInformation->{'generation'},
                                           $studentInformation->{'firstname'},                                            $studentInformation->{'firstname'},
                                           $studentInformation->{'middlename'});                                            $studentInformation->{'middlename'});
             $cache->{$name.':id'}=$studentInformation->{'id'};          $cache->{$name.':id'}=$studentInformation->{'id'};
         }  
   
         my ($end, $start)=split(':',$date);          my ($end, $start)=split(':',$date);
         $courseID=~s/\_/\//g;          $courseID=~s/\_/\//g;
Line 635  sub ProcessClasslist { Line 605  sub ProcessClasslist {
         }          }
         $cache->{$name.':Status'}=$status;          $cache->{$name.':Status'}=$status;
         $cache->{$name.':section'}=$sec;          $cache->{$name.':section'}=$sec;
   
           if($sec eq '' || !defined($sec) || $sec eq ' ') {
               $sec = 'none';
           }
           if(defined($cache->{'sectionList'})) {
               if($cache->{'sectionList'} !~ /(^$sec:|^$sec$|:$sec$|:$sec:)/) {
                   $cache->{'sectionList'} .= ':'.$sec;
               }
           } else {
               $cache->{'sectionList'} = $sec;
           }
     }      }
   
     $cache->{'ClasslistTimestamp'}=time;      $cache->{'ClasslistTimestamp'}=time;
Line 648  sub ProcessClasslist { Line 629  sub ProcessClasslist {
 =item &ProcessStudentData()  =item &ProcessStudentData()
   
 Takes the course data downloaded for a student in   Takes the course data downloaded for a student in 
 &DownloadStudentCourseInformation() and breaks it up into key value pairs  &DownloadCourseInformation() and breaks it up into key value pairs
 to be stored in the cached data.  The keys are comprised of the   to be stored in the cached data.  The keys are comprised of the 
 $username:$domain:$keyFromCourseDatabase.  The student username:domain is  $username:$domain:$keyFromCourseDatabase.  The student username:domain is
 stored away signifying that the student's information has been downloaded and   stored away signifying that the student's information has been downloaded and 
Line 670  Output: None Line 651  Output: None
 *NOTE:  There is no output, but an error message is stored away in the cache   *NOTE:  There is no output, but an error message is stored away in the cache 
 data.  This is checked in &FormatStudentData().  The key username:domain:error   data.  This is checked in &FormatStudentData().  The key username:domain:error 
 will only exist if an error occured.  The error is an error from   will only exist if an error occured.  The error is an error from 
 &DownloadStudentCourseInformation().  &DownloadCourseInformation().
   
 =back  =back
   
Line 679  will only exist if an error occured.  Th Line 660  will only exist if an error occured.  Th
 sub ProcessStudentData {  sub ProcessStudentData {
     my ($cache,$courseData,$name)=@_;      my ($cache,$courseData,$name)=@_;
   
     if($courseData->{'UpToDate'} eq 'true') {      if(!&CheckDateStampError($courseData, $cache, $name)) {
         $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};  
         return;          return;
     }      }
   
     my @courseKeys = keys(%$courseData);      foreach (keys %$courseData) {
           $cache->{$_}=$courseData->{$_};
       }
   
     foreach (@courseKeys) {      return;
         if(/^(con_lost|error|no_such_host)/i) {  }
             $cache->{$name.':error'}='Could not download course data.';  
             return;  sub ExtractStudentData {
         }      my ($input, $output, $data, $name)=@_;
   
       if(!&CheckDateStampError($input, $data, $name)) {
           return;
     }      }
   
     $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};      my ($username,$domain)=split(':',$name);
     foreach (@courseKeys) {  
         $cache->{$name.':'.$_}=$courseData->{$_};      my $Version;
       my $problemsCorrect = 0;
       my $totalProblems   = 0;
       my $problemsSolved  = 0;
       my $numberOfParts   = 0;
       my $totalAwarded    = 0;
       foreach my $sequence (split(':', $data->{'orderedSequences'})) {
           foreach my $problemID (split(':', $data->{$sequence.':problems'})) {
               my $problem = $data->{$problemID.':problem'};
               my $LatestVersion = $input->{$name.':version:'.$problem};
   
               # Output dashes for all the parts of this problem if there
               # is no version information about the current problem.
               if(!$LatestVersion) {
                   foreach my $part (split(/\:/,$data->{$sequence.':'.
                                                         $problemID.
                                                         ':parts'})) {
                       $output->{$name.':'.$problemID.':'.$part.':tries'} = 0;
                       $output->{$name.':'.$problemID.':'.$part.':awarded'} = 0;
                       $output->{$name.':'.$problemID.':'.$part.':code'} = ' ';
                       $totalProblems++;
                   }
                   $output->{$name.':'.$problemID.':NoVersion'} = 'true';
                   next;
               }
   
               my %partData=undef;
               # Initialize part data, display skips correctly
               # Skip refers to when a student made no submissions on that
               # part/problem.
               foreach my $part (split(/\:/,$data->{$sequence.':'.
                                                    $problemID.
                                                    ':parts'})) {
                   $partData{$part.':tries'}=0;
                   $partData{$part.':code'}=' ';
                   $partData{$part.':awarded'}=0;
                   $partData{$part.':timestamp'}=0;
                   foreach my $response (split(':', $data->{$sequence.':'.
                                                            $problemID.':'.
                                                            $part.':responseIDs'})) {
                       $partData{$part.':'.$response.':submission'}='';
                   }
               }
   
               # Looping through all the versions of each part, starting with the
               # oldest version.  Basically, it gets the most recent 
               # set of grade data for each part.
               my @submissions = ();
       for(my $Version=1; $Version<=$LatestVersion; $Version++) {
                   foreach my $part (split(/\:/,$data->{$sequence.':'.
                                                        $problemID.
                                                        ':parts'})) {
   
                       if(!defined($input->{"$name:$Version:$problem".
                                            ":resource.$part.solved"})) {
                           # No grade for this submission, so skip
                           next;
                       }
   
                       my $tries=0;
                       my $code=' ';
                       my $awarded=0;
   
                       $tries = $input->{$name.':'.$Version.':'.$problem.
                                         ':resource.'.$part.'.tries'};
                       $awarded = $input->{$name.':'.$Version.':'.$problem.
                                           ':resource.'.$part.'.awarded'};
   
                       $partData{$part.':awarded'}=($awarded) ? $awarded : 0;
                       $partData{$part.':tries'}=($tries) ? $tries : 0;
   
                       $partData{$part.':timestamp'}=$input->{$name.':'.$Version.':'.
                                                              $problem.
                                                              ':timestamp'};
                       if(!$input->{$name.':'.$Version.':'.$problem.':resource.'.$part.
                                    '.previous'}) {
                           foreach my $response (split(':',
                                                      $data->{$sequence.':'.
                                                              $problemID.':'.
                                                              $part.':responseIDs'})) {
                               @submissions=($input->{$name.':'.$Version.':'.
                                                      $problem.
                                                      ':resource.'.$part.'.'.
                                                      $response.'.submission'},
                                             @submissions);
                           }
                       }
   
                       my $val = $input->{$name.':'.$Version.':'.$problem.
                                          ':resource.'.$part.'.solved'};
                       if    ($val eq 'correct_by_student')   {$code = '*';} 
                       elsif ($val eq 'correct_by_override')  {$code = '+';}
                       elsif ($val eq 'incorrect_attempted')  {$code = '.';} 
                       elsif ($val eq 'incorrect_by_override'){$code = '-';}
                       elsif ($val eq 'excused')              {$code = 'x';}
                       elsif ($val eq 'ungraded_attempted')   {$code = '#';}
                       else                                   {$code = ' ';}
                       $partData{$part.':code'}=$code;
                   }
               }
   
               foreach my $part (split(/\:/,$data->{$sequence.':'.$problemID.
                                                    ':parts'})) {
                   $output->{$name.':'.$problemID.':'.$part.':wrong'} = 
                       $partData{$part.':tries'};
   
                   if($partData{$part.':code'} eq '*') {
                       $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
                       $problemsCorrect++;
                   } elsif($partData{$part.':code'} eq '+') {
                       $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
                       $problemsCorrect++;
                   }
   
                   $output->{$name.':'.$problemID.':'.$part.':tries'} = 
                       $partData{$part.':tries'};
                   $output->{$name.':'.$problemID.':'.$part.':code'} =
                       $partData{$part.':code'};
                   $output->{$name.':'.$problemID.':'.$part.':awarded'} =
                       $partData{$part.':awarded'};
                   $totalAwarded += $partData{$part.':awarded'};
                   $output->{$name.':'.$problemID.':'.$part.':timestamp'} =
                       $partData{$part.':timestamp'};
                   foreach my $response (split(':', $data->{$sequence.':'.
                                                            $problemID.':'.
                                                            $part.':responseIDs'})) {
                       $output->{$name.':'.$problemID.':'.$part.':'.$response.
                                 ':submission'}=join(':::',@submissions);
                   }
   
                   if($partData{$part.':code'} ne 'x') {
                       $totalProblems++;
                   }
               }
           }
   
           $output->{$name.':'.$sequence.':problemsCorrect'} = $problemsCorrect;
           $problemsSolved += $problemsCorrect;
    $problemsCorrect=0;
     }      }
   
       $output->{$name.':problemsSolved'} = $problemsSolved;
       $output->{$name.':totalProblems'} = $totalProblems;
       $output->{$name.':totalAwarded'} = $totalAwarded;
   
     return;      return;
 }  }
   
   sub LoadDiscussion {
       my ($courseID)=@_;
       my %Discuss=();
       my %contrib=&Apache::lonnet::dump(
                   $courseID,
                   $ENV{'course.'.$courseID.'.domain'},
                   $ENV{'course.'.$courseID.'.num'});
     
       #my %contrib=&DownloadCourseInformation($name, $courseID, 0);
   
       foreach my $temp(keys %contrib) {
    if ($temp=~/^version/) {
       my $ver=$contrib{$temp};
       my ($dummy,$prb)=split(':',$temp);
       for (my $idx=1; $idx<=$ver; $idx++ ) {
    my $name=$contrib{"$idx:$prb:sendername"};
    $Discuss{"$name:$prb"}=$idx;
       }
    }
       }       
   
       return \%Discuss;
   }
   
 # ----- END PROCESSING FUNCTIONS ---------------------------------------  # ----- END PROCESSING FUNCTIONS ---------------------------------------
   
 =pod  =pod
Line 714  jobs. Line 865  jobs.
   
 # ----- HELPER FUNCTIONS -----------------------------------------------  # ----- HELPER FUNCTIONS -----------------------------------------------
   
   sub CheckDateStampError {
       my ($courseData, $cache, $name)=@_;
       if($courseData->{$name.':UpToDate'} eq 'true') {
           $cache->{$name.':lastDownloadTime'} = 
               $courseData->{$name.':lastDownloadTime'};
           if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
               $cache->{$name.':updateTime'} = ' Not updated';
           } else {
               $cache->{$name.':updateTime'}=
                   localtime($courseData->{$name.':lastDownloadTime'});
           }
           return 0;
       }
   
       $cache->{$name.':lastDownloadTime'}=$courseData->{$name.':lastDownloadTime'};
       if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
           $cache->{$name.':updateTime'} = ' Not updated';
       } else {
           $cache->{$name.':updateTime'}=
               localtime($courseData->{$name.':lastDownloadTime'});
       }
   
       if(defined($courseData->{$name.':error'})) {
           $cache->{$name.':error'}=$courseData->{$name.':error'};
           return 0;
       }
   
       return 1;
   }
   
 =pod  =pod
   
 =item &ProcessFullName()  =item &ProcessFullName()
Line 809  sub TestCacheData { Line 990  sub TestCacheData {
     while($tieTries < $totalDelay) {      while($tieTries < $totalDelay) {
         my $result=0;          my $result=0;
         if($isCached) {          if($isCached) {
             $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_READER,0640);              $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_READER(),0640);
         } else {          } else {
             $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_NEWDB,0640);              $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_NEWDB(),0640);
         }          }
         if($result) {          if($result) {
             last;              last;
Line 828  sub TestCacheData { Line 1009  sub TestCacheData {
     return $isCached;      return $isCached;
 }  }
   
   sub DownloadStudentCourseData {
       my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
   
       my $title = 'LON-CAPA Statistics';
       my $heading = 'Download and Process Course Data';
       my $studentCount = scalar(@$students);
       my %cache;
   
   
       my $WhatIWant;
       $WhatIWant = '(^version:|';
       $WhatIWant .= '^\d+:.+?:(resource\.\d+\.';
       $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
       $WhatIWant .= '|timestamp)';
       $WhatIWant .= ')';
   #    $WhatIWant = '.';
   
       if($status eq 'true') {
           &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
       }
   
       my $displayString;
       my $count=0;
       foreach (@$students) {
           if($c->aborted()) { return 'Aborted'; }
   
           if($status eq 'true') {
               $count++;
               my $displayString = $count.'/'.$studentCount.': '.$_;
               &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
           }
   
           my $downloadTime='Not downloaded';
           if($checkDate eq 'true'  && 
              tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
               $downloadTime = $cache{$_.':lastDownloadTime'};
               untie(%cache);
           }
   
           if($c->aborted()) { return 'Aborted'; }
   
           if($downloadTime eq 'Not downloaded') {
               my $courseData = 
                   &DownloadCourseInformation($_, $courseID, $downloadTime, 
                                              $WhatIWant);
               if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
                   foreach my $key (keys(%$courseData)) {
                       if($key =~ /^(con_lost|error|no_such_host)/i) {
                           $courseData->{$_.':error'} = 'No course data for '.$_;
                           last;
                       }
                   }
                   if($extract eq 'true') {
                       &ExtractStudentData($courseData, \%cache, \%cache, $_);
                   } else {
                       &ProcessStudentData(\%cache, $courseData, $_);
                   }
                   untie(%cache);
               } else {
                   next;
               }
           }
       }
       if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
   
       return 'OK';
   }
   
   sub DownloadStudentCourseDataSeparate {
       my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
       my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
       my $title = 'LON-CAPA Statistics';
       my $heading = 'Download Course Data';
   
       my $WhatIWant;
       $WhatIWant = '(^version:|';
       $WhatIWant .= '^\d+:.+?:(resource\.\d+\.';
       $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
       $WhatIWant .= '|timestamp)';
       $WhatIWant .= ')';
   
       &CheckForResidualDownload($courseID, $cacheDB, $students, $c);
   
       my %cache;
   
       my $studentCount = scalar(@$students);
       if($status eq 'true') {
           &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
       }
       my $count=0;
       my $displayString='';
       foreach (@$students) {
           if($c->aborted()) {
               return 'Aborted';
           }
   
           if($status eq 'true') {
               $count++;
               $displayString = $count.'/'.$studentCount.': '.$_;
               &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
           }
   
           my $downloadTime='Not downloaded';
           if($checkDate eq 'true'  && 
              tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
               $downloadTime = $cache{$_.':lastDownloadTime'};
               untie(%cache);
           }
   
           if($c->aborted()) {
               return 'Aborted';
           }
   
           if($downloadTime eq 'Not downloaded') {
               my $error = 0;
               my $courseData = 
                   &DownloadCourseInformation($_, $courseID, $downloadTime,
                                              $WhatIWant);
               my %downloadData;
               unless(tie(%downloadData,'GDBM_File',$residualFile,
                          &GDBM_WRCREAT(),0640)) {
                   return 'Failed to tie temporary download hash.';
               }
               foreach my $key (keys(%$courseData)) {
                   $downloadData{$key} = $courseData->{$key};
                   if($key =~ /^(con_lost|error|no_such_host)/i) {
                       $error = 1;
                       last;
                   }
               }
               if($error) {
                   foreach my $deleteKey (keys(%$courseData)) {
                       delete $downloadData{$deleteKey};
                   }
                   $downloadData{$_.':error'} = 'No course data for '.$_;
               }
               untie(%downloadData);
           }
       }
       if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
   
       return &CheckForResidualDownload($cacheDB, 'true', 'true', 
                                        $courseID, $r, $c);
   }
   
   sub CheckForResidualDownload {
       my ($cacheDB,$extract,$status,$courseID,$r,$c)=@_;
   
       my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
       if(!-e $residualFile) {
           return 'OK';
       }
   
       my %downloadData;
       my %cache;
       unless(tie(%downloadData,'GDBM_File',$residualFile,&GDBM_READER(),0640)) {
           return 'Can not tie database for check for residual download: tempDB';
       }
       unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
           untie(%downloadData);
           return 'Can not tie database for check for residual download: cacheDB';
       }
   
       my @students=();
       my %checkStudent;
       my $key;
       while(($key, undef) = each %downloadData) {
           my @temp = split(':', $key);
           my $student = $temp[0].':'.$temp[1];
           if(!defined($checkStudent{$student})) {
               $checkStudent{$student}++;
               push(@students, $student);
           }
       }
   
       my $heading = 'Process Course Data';
       my $title = 'LON-CAPA Statistics';
       my $studentCount = scalar(@students);
       if($status eq 'true') {
           &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
       }
   
       my $count=1;
       foreach my $name (@students) {
           last if($c->aborted());
   
           if($status eq 'true') {
               my $displayString = $count.'/'.$studentCount.': '.$name;
               &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
           }
   
           if($extract eq 'true') {
               &ExtractStudentData(\%downloadData, \%cache, \%cache, $name);
           } else {
               &ProcessStudentData(\%cache, \%downloadData, $name);
           }
           $count++;
       }
   
       if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
   
       untie(%cache);
       untie(%downloadData);
   
       if(!$c->aborted()) {
           my @files = ($residualFile);
           unlink(@files);
       }
   
       return 'OK';
   }
   
 sub GetFileTimestamp {  sub GetFileTimestamp {
     my ($studentDomain,$studentName,$filename,$root)=@_;      my ($studentDomain,$studentName,$filename,$root)=@_;
     $studentDomain=~s/\W//g;      $studentDomain=~s/\W//g;
Line 840  sub GetFileTimestamp { Line 1233  sub GetFileTimestamp {
                                        $root);                                         $root);
     my $fileStat = $dir[0];      my $fileStat = $dir[0];
     my @stats = split('&', $fileStat);      my @stats = split('&', $fileStat);
     if(@stats) {      if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
         return $stats[9];          return $stats[9];
     } else {      } else {
         return -1;          return -1;

Removed from v.1.3  
changed lines
  Added in v.1.20


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