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

version 1.3, 2002/07/22 20:35:05 version 1.21, 2002/08/28 18:29:22
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 60  use GDBM_File; Line 61  use GDBM_File;
   
 This section contains all the files that get data from other servers   This section contains all the files that get data from other servers 
 and/or itself.  There is one function that has a call to get remote  and/or itself.  There is one function that has a call to get remote
 information but isn't included here which is ProcessTopLevelMap.  The  information but is not included here which is ProcessTopLevelMap.  The
 usage was small enough to be ignored, but that portion may be moved  usage was small enough to be ignored, but that portion may be moved
 here in the future.  here in the future.
   
Line 78  collecting a classlist for the course th Line 79  collecting a classlist for the course th
   
 =over 4  =over 4
   
 Input: $courseID, $c  Input: $courseID, $lastDownloadTime, $c
   
 $courseID:  The id of the course  $courseID:  The id of the course
   
   $lastDownloadTime: I am not sure.
   
 $c: The connection class that can determine if the browser has aborted.  It  $c: The connection class that can determine if the browser has aborted.  It
 is used to short circuit this function so that it doesn't continue to   is used to short circuit this function so that it does not continue to 
 get information when there is no need.  get information when there is no need.
   
 Output: \%classlist  Output: \%classlist
Line 118  sub DownloadClasslist { Line 121  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)) {
         if($c->aborted()) {          if((defined($c) && ($c->aborted())) {
             $classlist{'error'}='aborted';              $classlist{'error'}='aborted';
             return \%classlist;              return \%classlist;
         }          }
Line 157  sub DownloadClasslist { Line 161  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 185  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 268  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 291  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 330  sub ProcessTopResourceMap {
     last;      last;
  }   }
     }      }
               next;
  }   }
   
  # Handle gradable resources: exams, problems, etc   # Handle gradable resources: exams, problems, etc
Line 321  sub ProcessTopResourceMap { Line 339  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 362  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;
                           }
                       }
                       if($beenHere{'r:'.$partId.':'.$responseId} == 0) {
                           $beenHere{'r:'.$partId.':'.$responseId}++;
                           if(!defined($cache->{$currentSequence.':'.
                                                $currentResourceID.':'.$partId.
                                                ':responseIDs'})) {
                               $cache->{$currentSequence.':'.$currentResourceID.
                                        ':'.$partId.':responseIDs'}=$responseId;
                           } else {
                               $cache->{$currentSequence.':'.$currentResourceID.
                                        ':'.$partId.':responseIDs'}.=':'.
                                                                     $responseId;
                           }
                     }                      }
                     foreach (split(/\,/,                      if(/^optionresponse/ && 
                              &Apache::lonnet::metadata($meta,'packages'))) {                         $beenHere{'o:'.$partId.':'.$currentResourceID} == 0) {
                         if($_=~/^optionresponse\_($Part)\_(\w+)$/) {                          $beenHere{'o:'.$partId.$currentResourceID}++;
                             if(defined($cache->{'OptionResponses'})) {                          if(defined($cache->{'OptionResponses'})) {
                                 $cache->{'OptionResponses'}.= ':::'.                              $cache->{'OptionResponses'}.= ':::'.
                                     $hash{'src_'.$currentResourceID}.'::'.                                  $currentSequence.':'.$currentResourceID.':'.
                                     $hash{'title_'.$currentResourceID}.'::'.                                  $partId.':'.$responseId;
                                     $Part.'::'.$Problem;                          } else {
                             } else {                              $cache->{'OptionResponses'}= $currentSequence.':'.
                                 $cache->{'OptionResponses'}=                                  $currentResourceID.':'.
                                     $hash{'src_'.$currentResourceID}.'::'.                                  $partId.':'.$responseId;
                                     $hash{'title_'.$currentResourceID}.'::'.  
                                     $Part.'::'.$Problem;  
                             }  
                         }                          }
                     }                      }
                 }                  }
     }              }
  }          }
   
  # 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 458  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 493  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 549  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 556  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 607  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 631  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 653  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 662  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 867  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 992  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 1011  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 1235  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.21


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