Diff for /loncom/interface/loncoursedata.pm between versions 1.132 and 1.165

version 1.132, 2004/04/30 14:36:52 version 1.165, 2006/04/29 18:00:17
Line 49  Set of functions that download and proce Line 49  Set of functions that download and proce
 package Apache::loncoursedata;  package Apache::loncoursedata;
   
 use strict;  use strict;
 use Apache::Constants qw(:common :http);  use Apache::lonnet;
 use Apache::lonnet();  
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
 use Time::HiRes;  use Time::HiRes;
 use Apache::lonmysql;  use Apache::lonmysql;
Line 66  and/or itself. Line 65  and/or itself.
   
 =cut  =cut
   
 ####################################################  
 ####################################################  
   
 =pod  
   
 =item &get_sequence_assessment_data()  
   
 Use lonnavmaps to build a data structure describing the order and   
 assessment contents of each sequence in the current course.  
   
 The returned structure is a hash reference.   
   
 { title => 'title',  
   symb  => 'symb',  
   src   => '/s/o/u/r/c/e',  
   type  => (container|assessment),  
   num_assess   => 2,               # only for container  
   parts        => [11,13,15],      # only for assessment  
   response_ids => [12,14,16],      # only for assessment  
   contents     => [........]       # only for container  
 }  
   
 $hash->{'contents'} is a reference to an array of hashes of the same structure.  
   
 Also returned are array references to the sequences and assessments contained  
 in the course.  
   
   
 =cut  
   
 ####################################################  
 ####################################################  
 sub get_sequence_assessment_data {  
     my $fn=$ENV{'request.course.fn'};  
     ##  
     ## use navmaps  
     my $navmap = Apache::lonnavmaps::navmap->new();  
     if (!defined($navmap)) {  
         return 'Can not open Coursemap';  
     }  
     # We explicity grab the top level map because I am not sure we  
     # are pulling it from the iterator.  
     my $top_level_map = $navmap->getById('0.0');  
     #  
     my $iterator = $navmap->getIterator(undef, undef, undef, 1);  
     my $curRes = $iterator->next(); # Top level sequence  
     ##  
     ## Prime the pump   
     ##   
     ## We are going to loop until we run out of sequences/pages to explore for  
     ## resources.  This means we have to start out with something to look  
     ## at.  
     my $title = $ENV{'course.'.$ENV{'request.course.id'}.'.description'};  
     my $symb  = $top_level_map->symb();  
     my $src   = $top_level_map->src();  
     my $randompick = $top_level_map->randompick();  
     #  
     my @Sequences;   
     my @Assessments;  
     my @Nested_Sequences = ();   # Stack of sequences, keeps track of depth  
     my $top = { title    => $title,  
                 src      => $src,  
                 symb     => $symb,  
                 type     => 'container',  
                 num_assess => 0,  
                 num_assess_parts => 0,  
                 contents   => [],   
                 randompick => $randompick,  
             };  
     push (@Sequences,$top);  
     push (@Nested_Sequences, $top);  
     #  
     # We need to keep track of which sequences contain homework problems  
     #   
     my $previous_too;  
     my $previous;  
     while (scalar(@Nested_Sequences)) {  
         $previous_too = $previous;  
         $previous = $curRes;  
         $curRes = $iterator->next();  
         my $currentmap = $Nested_Sequences[-1]; # Last one on the stack  
         if ($curRes == $iterator->BEGIN_MAP()) {  
             if (! ref($previous)) {  
                 $previous = $previous_too;  
             }  
             if (! ref($previous)) {  
                 next;  
             }  
             # get the map itself, instead of BEGIN_MAP  
             $title = $previous->title();  
             $title =~ s/\:/\&\#058;/g;  
             $symb  = $previous->symb();  
             $src   = $previous->src();  
             # pick up the filename if there is no title available  
             if (! defined($title) || $title eq '') {  
                 ($title) = ($src=~/\/([^\/]*)$/);  
             }  
             $randompick = $previous->randompick();  
             my $newmap = { title    => $title,  
                            src      => $src,  
                            symb     => $symb,  
                            type     => 'container',  
                            num_assess => 0,  
                            randompick => $randompick,  
                            contents   => [],  
                        };  
             push (@{$currentmap->{'contents'}},$newmap); # this is permanent  
             push (@Sequences,$newmap);  
             push (@Nested_Sequences, $newmap); # this is a stack  
             next;  
         }  
         if ($curRes == $iterator->END_MAP()) {  
             pop(@Nested_Sequences);  
             next;  
         }  
         next if (! ref($curRes));  
         next if (! $curRes->is_problem() && $curRes->src() !~ /\.survey$/);  
         # Okay, from here on out we only deal with assessments  
         $title = $curRes->title();  
         $title =~ s/\:/\&\#058;/g;  
         $symb  = $curRes->symb();  
         $src   = $curRes->src();  
         # Grab the filename if there is not title available  
         if (! defined($title) || $title eq '') {  
             ($title) = ($src=~ m:/([^/]*)$:);  
         }  
         my $parts = $curRes->parts();  
         my %partdata;  
         foreach my $part (@$parts) {  
             my @Responses = $curRes->responseType($part);  
             my @Ids       = $curRes->responseIds($part);  
             $partdata{$part}->{'ResponseTypes'}= \@Responses;  
             $partdata{$part}->{'ResponseIds'}  = \@Ids;  
             # Count how many responses of each type there are in this part  
             foreach (@Responses) {  
                 $partdata{$part}->{$_}++;  
             }  
         }  
         my $assessment = { title => $title,  
                            src   => $src,  
                            symb  => $symb,  
                            type  => 'assessment',  
                            parts => $parts,  
                            num_parts => scalar(@$parts),  
                            partdata => \%partdata,  
                        };  
         push(@Assessments,$assessment);  
         push(@{$currentmap->{'contents'}},$assessment);  
         $currentmap->{'num_assess'}++;  
         $currentmap->{'num_assess_parts'}+= scalar(@$parts);  
     }  
     $navmap->untieHashes();  
     return ($top,\@Sequences,\@Assessments);  
 }  
   
 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;  
 }  
   
 ################################################  
 ################################################  
   
 =pod  
   
 =item &GetUserName(username,userdomain)  
   
 Returns a hash with the following entries:  
    'firstname', 'middlename', 'lastname', 'generation', and 'fullname'  
   
    'fullname' is the result of &Apache::loncoursedata::ProcessFullName.  
   
 =cut  
   
 ################################################  
 ################################################  
 sub GetUserName {  
     my ($username,$userdomain) = @_;  
     $username = $ENV{'user.name'} if (! defined($username));  
     $userdomain = $ENV{'user.domain'} if (! defined($username));  
     my %userenv = &Apache::lonnet::get('environment',  
                            ['firstname','middlename','lastname','generation'],  
                                        $userdomain,$username);  
     $userenv{'fullname'} = &ProcessFullName($userenv{'lastname'},  
                                             $userenv{'generation'},  
                                             $userenv{'firstname'},  
                                             $userenv{'middlename'});  
     return %userenv;  
 }  
   
 ################################################  
 ################################################  
   
 =pod  
   
 =item &ProcessFullName()  
   
 Takes lastname, generation, firstname, and middlename (or some partial  
 set of this data) and returns the full name version as a string.  Format  
 is Lastname generation, firstname middlename or a subset of this.  
   
 =cut  
   
 ################################################  
 ################################################  
 sub ProcessFullName {  
     my ($lastname, $generation, $firstname, $middlename)=@_;  
     my $Str = '';  
   
     # Strip whitespace preceeding & following name components.  
     $lastname   =~ s/(\s+$|^\s+)//g;  
     $generation =~ s/(\s+$|^\s+)//g;  
     $firstname  =~ s/(\s+$|^\s+)//g;  
     $middlename =~ s/(\s+$|^\s+)//g;  
   
     if($lastname ne '') {  
  $Str .= $lastname;  
  $Str .= ' '.$generation if ($generation ne '');  
  $Str .= ',';  
         $Str .= ' '.$firstname  if ($firstname ne '');  
         $Str .= ' '.$middlename if ($middlename ne '');  
     } else {  
         $Str .= $firstname      if ($firstname ne '');  
         $Str .= ' '.$middlename if ($middlename ne '');  
         $Str .= ' '.$generation if ($generation ne '');  
     }  
   
     return $Str;  
 }  
   
 ################################################  ################################################
 ################################################  ################################################
   
Line 454  The response table holds data (documente Line 204  The response table holds data (documente
 associated with a particular response id which is stored when a student   associated with a particular response id which is stored when a student 
 attempts a problem.  The following are the columns of the table, in order:  attempts a problem.  The following are the columns of the table, in order:
 'symb_id','part_id','response_id','student_id','transaction','tries',  'symb_id','part_id','response_id','student_id','transaction','tries',
 'awarddetail', 'response_specific' (data particular to the response  'awarddetail', 'response_specific', 'response_specific_value',
 type), 'response_specific_value', and 'submission (the text of the students  'response_specific_2', 'response_specific_value_2', and 'submission
 submission).  The primary key is based on the first five columns listed above.  (the text of the students submission).  The primary key is based on the
   first five columns listed above.
   
 =item $fulldump_part_table  =item $fulldump_part_table
   
Line 547  store student data. Line 298  store student data.
 ################################################  ################################################
 ################################################  ################################################
 sub init_dbs {  sub init_dbs {
     my $courseid = shift;      my ($courseid,$drop) = @_;
     &setup_table_names($courseid);      &setup_table_names($courseid);
     #      #
     # Drop any of the existing tables      # Drop any of the existing tables
     foreach my $table (@Tables) {      if ($drop) {
         &Apache::lonmysql::drop_table($table);          foreach my $table (@Tables) {
               &Apache::lonmysql::drop_table($table);
           }
     }      }
     #      #
     # Note - changes to this table must be reflected in the code that       # Note - changes to this table must be reflected in the code that 
Line 714  sub init_dbs { Line 467  sub init_dbs {
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'response_specific_value',                      { name => 'response_specific_value',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                       { name => 'response_specific_2',
                         type => 'TINYTEXT' },
                       { name => 'response_specific_value_2',
                         type => 'TINYTEXT' },
                     { name => 'submission',                      { name => 'submission',
                       type => 'TEXT'},                        type => 'TEXT'},
                     ],                      ],
Line 855  sub init_dbs { Line 612  sub init_dbs {
   
 =item &delete_caches()  =item &delete_caches()
   
   This routine drops all the tables associated with a course from the 
   MySQL database.
   
   Input: course id (optional, determined by environment if omitted) 
   
   Returns: nothing
   
 =cut  =cut
   
 ################################################  ################################################
 ################################################  ################################################
 sub delete_caches {  sub delete_caches {
     my $courseid = shift;      my $courseid = shift;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     #      #
Line 1077  sub get_student { Line 841  sub get_student {
 sub populate_student_table {  sub populate_student_table {
     my ($courseid) = @_;      my ($courseid) = @_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
       &init_dbs($courseid,0);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     my $request = 'INSERT IGNORE INTO '.$student_table.      my $request = 'INSERT IGNORE INTO '.$student_table.
         "(student,section,status) VALUES ";          "(student,section,status) VALUES ";
     my $classlist = &get_classlist($courseid);      my $cdom = $env{'course.'.$courseid.'.domain'};
       my $cnum = $env{'course.'.$courseid.'.num'};
       my $classlist = &get_classlist($cdom,$cnum);
     my $student_count=0;      my $student_count=0;
     while (my ($student,$data) = each %$classlist) {      while (my ($student,$data) = each %$classlist) {
         my ($section,$status) = ($data->[&CL_SECTION()],          my ($section,$status) = ($data->[&CL_SECTION()],
Line 1139  sub clear_internal_caches { Line 906  sub clear_internal_caches {
 ################################################  ################################################
 ################################################  ################################################
   
   sub symb_is_for_task {
       my ($symb) = @_;
       return ($symb =~ /\.task$/);
   }
   
   ################################################
   ################################################
   
 =pod  =pod
   
 =item &update_full_student_data($sname,$sdom,$courseid)  =item &update_full_student_data($sname,$sdom,$courseid)
Line 1187  sub update_full_student_data { Line 962  sub update_full_student_data {
     #      #
     # Download students data      # Download students data
     my $time_of_retrieval = time;      my $time_of_retrieval = time;
     my @tmp = &Apache::lonnet::dump($courseid,$sdom,$sname);      my @tmp = &Apache::lonnet::dumpstore($courseid,$sdom,$sname);
     if (@tmp && $tmp[0] =~ /^error/) {      if (@tmp && $tmp[0] =~ /^error/) {
         $returnstatus = 'error retrieving full student data';          $returnstatus = 'error retrieving full student data';
         return $returnstatus;          return $returnstatus;
Line 1227  sub update_full_student_data { Line 1002  sub update_full_student_data {
             next;              next;
         } elsif ($parameter eq 'version') {          } elsif ($parameter eq 'version') {
             next;              next;
         } elsif ($parameter =~ /^resource\.(.*)\.(tries|   } elsif (&symb_is_for_task($symb)) {
       next if ($parameter !~ /^resource\.(.*)\.(award|
         awarded|
         solved|
         submission|
         portfiles|
         status|
         version|
         regrader)\s*$/x);
       my ($version_and_part_id, $field) = ($1,$2);
   
       next if ($version_and_part_id !~ /\./ 
        && $field ne 'regrader' && $field ne 'version');
   
       my ($version, $part, $instance) = 
    split(/\./,$version_and_part_id);
   
       #skip and instance dimension or criteria specific data
       next if (defined($instance) 
        && $instance ne $field
        && $instance ne 'bridgetask');
       
       if (!defined($part)) {
    $part = $version;
       }
       my $resp_id = &get_part_id('0');
       my $part_id = &get_part_id($part);
       
       if ($field eq 'version') {
    # for tasks each version is an attempt at it thus
    #     version -> tries
    $partdata->{$symb_id}{$part_id}{$transaction}{'tries'}=
       $value;
    # at new version time the record gets reset thus adding a
    # virtual response awarddetail of 'new_version'
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific'}='status';
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific_value'}='new_version';
   
       } elsif ($field eq 'award' || $field eq 'awarded' 
        || $field eq 'solved') {
    $partdata->{$symb_id}{$part_id}{$transaction}{$field}=
       $value;
       } elsif ($field eq 'portfiles') {
    # tasks only accepts portfolio submissions
    $value = $dbh->quote($value);
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'submission'}=$value;
       } elsif ($field eq 'status') {
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific'}=$field;
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific_value'}=$value;
       } elsif ($field eq 'regrader') {
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific_2'}=$field;
    $respdata->{$symb_id}{$part_id}{$resp_id}{$transaction}{'response_specific_value_2'}=$value;
       }
    } elsif ($parameter =~ /^resource\.(.*)\.(tries|
                                                   award|                                                    award|
                                                   awarded|                                                    awarded|
                                                   previous|                                                    previous|
Line 1325  sub update_full_student_data { Line 1153  sub update_full_student_data {
                              $transaction,                               $transaction,
                              $data->{'awarddetail'},                               $data->{'awarddetail'},
                              $data->{'response_specific'},                               $data->{'response_specific'},
                              $data->{'response_specific_value'}).                               $data->{'response_specific_value'},
                                $data->{'response_specific_2'},
                                $data->{'response_specific_value_2'}).
                              "',".$submission."),";                               "',".$submission."),";
                     $store_rows++;                      $store_rows++;
                 }                  }
Line 1430  sub update_student_data { Line 1260  sub update_student_data {
     #      #
     # Set the students update time      # Set the students update time
     if ($Results[0] eq 'okay') {      if ($Results[0] eq 'okay') {
         &store_updatetime($student_id,$time_of_retrieval,$time_of_retrieval);          &store_updatetime($student_id,$time_of_retrieval);
     }      }
     #      #
     return @Results;      return @Results;
Line 1486  sub store_student_data { Line 1316  sub store_student_data {
         # make sure the symb is set up properly          # make sure the symb is set up properly
         my $symb_id = &get_symb_id($current_symb);          my $symb_id = &get_symb_id($current_symb);
         #          #
         # Load data into the tables          # Parameters
         while (my ($parameter,$value) = each(%$param_hash)) {          while (my ($parameter,$value) = each(%$param_hash)) {
             my $newstring;  
             if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) {              if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) {
                 $newstring = "('".join("','",                  my $sql_parameter = "('".join("','",
                                        $symb_id,$student_id,                                                $symb_id,$student_id,
                                        $parameter)."',".                                                $parameter)."',".
                                            $dbh->quote($value)."),\n";                                                    $dbh->quote($value)."),\n";
                 $num_parameters ++;                  $num_parameters ++;
                 if ($newstring !~ /''/) {                  if ($sql_parameter !~ /''/) {
                     $store_parameters_command .= $newstring;                      $store_parameters_command .= $sql_parameter;
                     $rows_stored++;                      #$rows_stored++;
                 }                  }
             }              }
             next if ($parameter !~ /^resource\.(.*)\.solved$/);          }
           # Performance
           my %stored;
           while (my ($parameter,$value) = each(%$param_hash)) {
               next if ($parameter !~ /^resource\.(.*)\.(solved|awarded)$/);
               my $part  = $1;
       my $which = $2;
       next if ($part =~ /\./);
               next if (exists($stored{$part}));
               $stored{$part}++;
             #              #
             my $part = $1;  
             my $part_id = &get_part_id($part);              my $part_id = &get_part_id($part);
             next if (!defined($part_id));              next if (!defined($part_id));
             my $solved  = $value;      
             my $tries   = $param_hash->{'resource.'.$part.'.tries'};              my ($solved,$awarded);
             my $awarded = $param_hash->{'resource.'.$part.'.awarded'};      if ($which eq 'solved') {
    $solved  = $value;
    $awarded = $param_hash->{'resource.'.$part.'.awarded'};
       } else {
    $solved  = $param_hash->{'resource.'.$part.'.solved'};
    $awarded = $value;
       }
             my $award   = $param_hash->{'resource.'.$part.'.award'};              my $award   = $param_hash->{'resource.'.$part.'.award'};
             my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'};              my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'};
             my $timestamp = $param_hash->{'timestamp'};              my $timestamp = $param_hash->{'timestamp'};
       my $tries   = $param_hash->{'resource.'.$part.'.tries'};
       if (&symb_is_for_task($current_symb)) {
    $tries   = $param_hash->{'resource.'.$part.'.version'};
       }
             #              #
             $solved      = '' if (! defined($solved));              $solved      = '' if (! defined($solved));
             $tries       = '' if (! defined($tries));              $tries       = '' if (! defined($tries));
             $awarded     = '' if (! defined($awarded));              $awarded     = '' if (! defined($awarded));
             $award       = '' if (! defined($award));              $award       = '' if (! defined($award));
             $awarddetail = '' if (! defined($awarddetail));              $awarddetail = '' if (! defined($awarddetail));
             $newstring = "('".join("','",$symb_id,$student_id,$part_id,$part,              my $sql_performance = 
                                    $solved,$tries,$awarded,$award,                  "('".join("','",$symb_id,$student_id,$part_id,$part,
                                    $awarddetail,$timestamp)."'),\n";                                  $solved,$tries,$awarded,$award,
             $store_performance_command .= $newstring;                                  $awarddetail,$timestamp)."'),\n";
               $store_performance_command .= $sql_performance;
             $rows_stored++;              $rows_stored++;
         }          }
     }      }
     chop $store_parameters_command;      if (! $rows_stored) { return ($returnstatus, undef); }
     chop $store_parameters_command;      $store_parameters_command =~ s|,\n$||;
     chop $store_performance_command;      $store_performance_command =~ s|,\n$||;
     chop $store_performance_command;  
     my $start = Time::HiRes::time;      my $start = Time::HiRes::time;
     $dbh->do($store_performance_command);      $dbh->do($store_performance_command);
     if ($dbh->err()) {      if ($dbh->err()) {
         &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr());          &Apache::lonnet::logthis('performance bigass insert error:'.
         &Apache::lonnet::logthis('command = '.$store_performance_command);                                   $dbh->errstr());
           &Apache::lonnet::logthis('command = '.$/.$store_performance_command);
         $returnstatus = 'error: unable to insert performance into database';          $returnstatus = 'error: unable to insert performance into database';
         return ($returnstatus,$student_data);          return ($returnstatus,$student_data);
     }      }
     $dbh->do($store_parameters_command) if ($num_parameters>0);      $dbh->do($store_parameters_command) if ($num_parameters>0);
     if ($dbh->err()) {      if ($dbh->err()) {
         &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr());          &Apache::lonnet::logthis('parameters bigass insert error:'.
         &Apache::lonnet::logthis('command = '.$store_parameters_command);                                   $dbh->errstr());
           &Apache::lonnet::logthis('command = '.$/.$store_parameters_command);
         &Apache::lonnet::logthis('rows_stored = '.$rows_stored);          &Apache::lonnet::logthis('rows_stored = '.$rows_stored);
         &Apache::lonnet::logthis('student_id = '.$student_id);          &Apache::lonnet::logthis('student_id = '.$student_id);
         $returnstatus = 'error: unable to insert parameters into database';          $returnstatus = 'error: unable to insert parameters into database';
Line 1567  Returns nothing on success and 'error' o Line 1416  Returns nothing on success and 'error' o
 ######################################  ######################################
 sub ensure_tables_are_set_up {  sub ensure_tables_are_set_up {
     my ($courseid) = @_;      my ($courseid) = @_;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #       # 
     # Clean out package variables      # Clean out package variables
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 1594  sub ensure_tables_are_set_up { Line 1443  sub ensure_tables_are_set_up {
         !$found_performance   || !$found_parameters        ||          !$found_performance   || !$found_parameters        ||
         !$found_fulldump_part || !$found_fulldump_response ||          !$found_fulldump_part || !$found_fulldump_response ||
         !$found_fulldump_timestamp || !$found_weight ) {          !$found_fulldump_timestamp || !$found_weight ) {
         if (&init_dbs($courseid)) {          if (&init_dbs($courseid,1)) {
             return 'error';              return 'error';
         }          }
     }      }
Line 1624  sub ensure_current_data { Line 1473  sub ensure_current_data {
     my ($sname,$sdom,$courseid) = @_;      my ($sname,$sdom,$courseid) = @_;
     my $status = 'okay';   # return value      my $status = 'okay';   # return value
     #      #
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     &ensure_tables_are_set_up($courseid);      &ensure_tables_are_set_up($courseid);
     #      #
     # Get the update time for the user      # Get the update time for the user
Line 1673  sub ensure_current_full_data { Line 1522  sub ensure_current_full_data {
     my ($sname,$sdom,$courseid) = @_;      my ($sname,$sdom,$courseid) = @_;
     my $status = 'okay';   # return value      my $status = 'okay';   # return value
     #      #
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     &ensure_tables_are_set_up($courseid);      &ensure_tables_are_set_up($courseid);
     #      #
     # Get the update time for the user      # Get the update time for the user
Line 1849  an empty list is returned. Line 1698  an empty list is returned.
 sub get_current_state {  sub get_current_state {
     my ($sname,$sdom,$symb,$courseid,$forcedownload)=@_;      my ($sname,$sdom,$symb,$courseid,$forcedownload)=@_;
     #      #
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     return () if (! defined($sname) || ! defined($sdom));      return () if (! defined($sname) || ! defined($sdom));
     #      #
Line 1952  able to answer it correctly. Line 1801  able to answer it correctly.
 sub get_problem_statistics {  sub get_problem_statistics {
     my ($Sections,$status,$symb,$part,$courseid,$starttime,$endtime) = @_;      my ($Sections,$status,$symb,$part,$courseid,$starttime,$endtime) = @_;
     return if (! defined($symb) || ! defined($part));      return if (! defined($symb) || ! defined($part));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
Line 2030  sub get_problem_statistics { Line 1879  sub get_problem_statistics {
     }      }
     my ($solved) = &execute_SQL_request($dbh,$request);      my ($solved) = &execute_SQL_request($dbh,$request);
     #      #
       $Solved -= $solved;
       #
     $num    = 0 if (! defined($num));      $num    = 0 if (! defined($num));
     $tries  = 0 if (! defined($tries));      $tries  = 0 if (! defined($tries));
     $max    = 0 if (! defined($max));      $max    = 0 if (! defined($max));
     $min    = 0 if (! defined($min));      $min    = 0 if (! defined($min));
     $STD    = 0 if (! defined($STD));      $STD    = 0 if (! defined($STD));
     $Solved = 0 if (! defined($Solved));      $Solved = 0 if (! defined($Solved) || $Solved < 0);
     $solved = 0 if (! defined($solved));      $solved = 0 if (! defined($solved));
     #      #
     # Compute the more complicated statistics      # Compute the more complicated statistics
Line 2077  sub execute_SQL_request { Line 1928  sub execute_SQL_request {
     my ($dbh,$request)=@_;      my ($dbh,$request)=@_;
 #    &Apache::lonnet::logthis($request);  #    &Apache::lonnet::logthis($request);
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
       if (!$sth) {
    die($dbh->errstr . " SQL: $request");
       }
     $sth->execute();      $sth->execute();
     my $row = $sth->fetchrow_arrayref();      my $row = $sth->fetchrow_arrayref();
     if (ref($row) eq 'ARRAY' && scalar(@$row)>0) {      if (ref($row) eq 'ARRAY' && scalar(@$row)>0) {
Line 2099  sub execute_SQL_request { Line 1953  sub execute_SQL_request {
 sub populate_weight_table {  sub populate_weight_table {
     my ($courseid) = @_;      my ($courseid) = @_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my ($top,$sequences,$assessments) = get_sequence_assessment_data();      my $navmap = Apache::lonnavmaps::navmap->new();
     if (! defined($top) || ! ref($top)) {      if (!defined($navmap)) {
         # There has been an error, better report it          &Apache::lonnet::logthis('loncoursedata::populate_weight_table:'.$/.
         &Apache::lonnet::logthis('top is undefined');                                   '  unable to get navmaps resource'.$/.
                                    '  '.join(' ',(caller)));
           return;
       }
       my @sequences = $navmap->retrieveResources(undef,
                                                  sub { shift->is_map(); },1,0,1);
       my @resources;
       foreach my $seq (@sequences) {
           push(@resources,$navmap->retrieveResources($seq,
                                                      sub {shift->is_problem();},
                                                      0,0,0));
       }
       if (! scalar(@resources)) {
           &Apache::lonnet::logthis('loncoursedata::populate_weight_table:'.$/.
                                    ' no resources returned for '.$courseid);
         return;          return;
     }      }
     #       Since we use lonnet::EXT to retrieve problem weights,      #       Since we use lonnet::EXT to retrieve problem weights,
Line 2116  sub populate_weight_table { Line 1984  sub populate_weight_table {
     my $request = 'INSERT IGNORE INTO '.$weight_table.      my $request = 'INSERT IGNORE INTO '.$weight_table.
         "(symb_id,part_id,weight) VALUES ";          "(symb_id,part_id,weight) VALUES ";
     my $weight;      my $weight;
     foreach my $res (@$assessments) {      foreach my $res (@resources) {
         my $symb_id = &get_symb_id($res->{'symb'});          my $symb_id = &get_symb_id($res->symb);
         foreach my $part (@{$res->{'parts'}}) {          foreach my $part (@{$res->parts}) {
             my $part_id = &get_part_id($part);              my $part_id = &get_part_id($part);
             $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',              $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
                                            $res->{'symb'},                                             $res->symb,
                                            undef,undef,undef);                                             undef,undef,undef);
             if (!defined($weight) || ($weight eq '')) {               if (!defined($weight) || ($weight eq '')) { 
                 $weight=1;                  $weight=1;
Line 2220  Inputs: Line 2088  Inputs:
     $Sections: array ref of sections to include,      $Sections: array ref of sections to include,
     $enrollment: string,      $enrollment: string,
     $courseid (may be omitted)      $courseid (may be omitted)
       $starttime (may be omitted)
       $endtime (may be omitted)
       $has_award_for (may be omitted)
   
 Returns; An array of arrays.  The sub arrays contain a student name and  Returns; An array of arrays.  The sub arrays contain a student name and
 their score on the resources.  their score on the resources. $starttime and $endtime constrain the
   list to awards obtained during the given time limits. $has_score_on
   constrains the list to those students who at least attempted the
   resource identified by the given symb, which is used to filter out
   such students for statistics that would be adversely affected by such
   students. 
   
 =cut  =cut
   
Line 2232  sub RNK_student { return 0; }; Line 2108  sub RNK_student { return 0; };
 sub RNK_score   { return 1; };  sub RNK_score   { return 1; };
   
 sub rank_students_by_scores_on_resources {  sub rank_students_by_scores_on_resources {
     my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime) = @_;      my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime,$has_award_for) = @_;
     return if (! defined($resources) || ! ref($resources) eq 'ARRAY');      return if (! defined($resources) || ! ref($resources) eq 'ARRAY');
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2245  sub rank_students_by_scores_on_resources Line 2121  sub rank_students_by_scores_on_resources
     my $symb_limits = '('.join(' OR ',map {'a.symb_id='.&get_symb_id($_);      my $symb_limits = '('.join(' OR ',map {'a.symb_id='.&get_symb_id($_);
                                        } @$resources                                         } @$resources
                                ).')';                                 ).')';
       my ($award_col, $award_join, $award_clause) = ('', '', '');
       if ($has_award_for) {
           my $resource_id = &get_symb_id($has_award_for);
           $award_col = ", perf.awarded";
           $award_join = "LEFT JOIN $performance_table AS perf ON perf.symb_id"
               ." = $resource_id AND perf.student_id = b.student_id ";
           $award_clause = "AND perf.awarded IS NOT NULL";
       }
     my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');      my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
     my $request = 'SELECT b.student,SUM(a.awarded*w.weight) AS score FROM '.      my $request = "SELECT b.student,SUM(a.awarded*w.weight) AS score "
         $performance_table.' AS a '.          ."$award_col FROM $performance_table AS a ".
         'NATURAL LEFT JOIN '.$weight_table.' AS w '.          "NATURAL LEFT JOIN $weight_table AS w ".
         'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.          "LEFT JOIN $student_table AS b ON a.student_id=b.student_id ".
         'WHERE ';          "$award_join WHERE ";
     if (defined($section_limits)) {      if (defined($section_limits)) {
         $request .= $section_limits.' AND ';          $request .= $section_limits.' AND ';
     }      }
Line 2265  sub rank_students_by_scores_on_resources Line 2149  sub rank_students_by_scores_on_resources
     }      }
     $request =~ s/( AND )$//;   # Remove extra conjunction      $request =~ s/( AND )$//;   # Remove extra conjunction
     $request =~ s/( WHERE )$//; # In case there were no limits placed on it      $request =~ s/( WHERE )$//; # In case there were no limits placed on it
     $request .= ' GROUP BY a.student_id ORDER BY score';      $request .= " $award_clause GROUP BY a.student_id ORDER BY score";
     #&Apache::lonnet::logthis('request = '.$/.$request);      #&Apache::lonnet::logthis('request = '.$/.$request);
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request) or die "Can't prepare $request";
     $sth->execute();      $sth->execute();
     my $rows = $sth->fetchall_arrayref();      my $rows = $sth->fetchall_arrayref();
     return ($rows);      return ($rows);
Line 2293  Returns: the sum of the score on the pro Line 2177  Returns: the sum of the score on the pro
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub get_sum_of_scores {  sub get_sum_of_scores {
     my ($resource,$part,$students,$courseid,$starttime,$endtime) = @_;      my ($symb,$part,$students,$courseid,$starttime,$endtime) = @_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
       }
       if (defined($students) && 
           ((@$students == 0) ||
            (@$students == 1 && (! defined($students->[0]) || 
                                 $students->[0] eq ''))
            )
           ){
           undef($students);
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2304  sub get_sum_of_scores { Line 2196  sub get_sum_of_scores {
     my $request = 'SELECT SUM(a.awarded*w.weight),SUM(w.weight) FROM '.      my $request = 'SELECT SUM(a.awarded*w.weight),SUM(w.weight) FROM '.
         $performance_table.' AS a '.          $performance_table.' AS a '.
         'NATURAL LEFT JOIN '.$weight_table.' AS w ';          'NATURAL LEFT JOIN '.$weight_table.' AS w ';
     $request .= 'WHERE a.symb_id='.&get_symb_id($resource->{'symb'}).      $request .= 'WHERE a.symb_id='.&get_symb_id($symb).
         ' AND a.part_id='.&get_part_id($part);          ' AND a.part_id='.&get_part_id($part);
     if (defined($time_limits)) {      if (defined($time_limits)) {
         $request .= ' AND '.$time_limits;          $request .= ' AND '.$time_limits;
Line 2319  sub get_sum_of_scores { Line 2211  sub get_sum_of_scores {
     $sth->execute();      $sth->execute();
     my $rows = $sth->fetchrow_arrayref();      my $rows = $sth->fetchrow_arrayref();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 1 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed, fetchrow_arrayrefed'.
                                    $/.$request);
         return (undef,undef);          return (undef,undef);
     }      }
     return ($rows->[0],$rows->[1]);      return ($rows->[0],$rows->[1]);
Line 2349  Returns: minimum, maximum, mean, s.d., n Line 2243  Returns: minimum, maximum, mean, s.d., n
 sub score_stats {  sub score_stats {
     my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;      my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2392  sub score_stats { Line 2286  sub score_stats {
 #    &Apache::lonnet::logthis('request = '.$/.$request);  #    &Apache::lonnet::logthis('request = '.$/.$request);
           
     $request = 'SELECT SUM(weight) FROM '.$weight_table.      $request = 'SELECT SUM(weight) FROM '.$weight_table.
         ' WHERE ('.$symb_restriction.')';          ' AS a WHERE ('.$symb_restriction.')';
     my ($max_possible) = &execute_SQL_request($dbh,$request);      my ($max_possible) = &execute_SQL_request($dbh,$request);
     # &Apache::lonnet::logthis('request = '.$/.$request);      # &Apache::lonnet::logthis('request = '.$/.$request);
     return($min,$max,$ave,$std,$count,$max_possible);      return($min,$max,$ave,$std,$count,$max_possible);
Line 2423  Returns: minimum, maximum, mean, s.d., a Line 2317  Returns: minimum, maximum, mean, s.d., a
 sub count_stats {  sub count_stats {
     my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;      my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2441  sub count_stats { Line 2335  sub count_stats {
     $request =       $request = 
         'CREATE TEMPORARY TABLE '.$stats_table.' '.          'CREATE TEMPORARY TABLE '.$stats_table.' '.
         'SELECT a.student_id,'.          'SELECT a.student_id,'.
         'COUNT(a.award) AS count FROM '.          'SUM(a.awarded) AS count FROM '.
         $performance_table.' AS a '.          $performance_table.' AS a '.
         'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.          'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.
         'WHERE ('.$symb_restriction.')'.          'WHERE ('.$symb_restriction.')';
         " AND a.award!='INCORRECT_ATTEMPTED'";  
     if ($time_limits) {      if ($time_limits) {
         $request .= ' AND '.$time_limits;          $request .= ' AND '.$time_limits;
     }      }
Line 2480  sub count_stats { Line 2373  sub count_stats {
 ######################################################  ######################################################
 sub get_student_data {  sub get_student_data {
     my ($students,$courseid) = @_;      my ($students,$courseid) = @_;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
Line 2499  sub get_student_data { Line 2392  sub get_student_data {
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 2 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     my $dataset = $sth->fetchall_arrayref();      my $dataset = $sth->fetchall_arrayref();
Line 2508  sub get_student_data { Line 2402  sub get_student_data {
     }      }
 }  }
   
 sub RD_student_id    { return 0; }  sub RD_student_id      { return 0; }
 sub RD_awarddetail   { return 1; }  sub RD_awarddetail     { return 1; }
 sub RD_response_eval { return 2; }  sub RD_response_eval   { return 2; }
 sub RD_submission    { return 3; }  sub RD_response_eval_2 { return 3; }
 sub RD_timestamp     { return 4; }  sub RD_submission      { return 4; }
 sub RD_tries         { return 5; }  sub RD_timestamp       { return 5; }
 sub RD_sname         { return 6; }  sub RD_tries           { return 6; }
   sub RD_sname           { return 7; }
   
 sub get_response_data {  sub get_response_data {
     my ($Sections,$enrollment,$symb,$response,$courseid) = @_;      my ($Sections,$enrollment,$symb,$response,$courseid) = @_;
     return undef if (! defined($symb) ||       return undef if (! defined($symb) || 
                ! defined($response));                 ! defined($response));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
       if (! defined($symb_id)) {
           &Apache::lonnet::logthis('Unable to find symb for '.$symb.' in '.$courseid);
           return undef;
       }
     my $response_id = &get_part_id($response);      my $response_id = &get_part_id($response);
       if (! defined($response_id)) {
           &Apache::lonnet::logthis('Unable to find id for '.$response.' in '.$courseid);
           return undef;
       }
     #      #
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
Line 2533  sub get_response_data { Line 2436  sub get_response_data {
         &limit_by_section_and_status($Sections,$enrollment,'d');          &limit_by_section_and_status($Sections,$enrollment,'d');
     my $request = 'SELECT '.      my $request = 'SELECT '.
         'a.student_id, a.awarddetail, a.response_specific_value, '.          'a.student_id, a.awarddetail, a.response_specific_value, '.
         'a.submission, b.timestamp, c.tries, d.student '.          'a.response_specific_value_2, a.submission, b.timestamp, '.
    'c.tries, d.student '.
         'FROM '.$fulldump_response_table.' AS a '.          'FROM '.$fulldump_response_table.' AS a '.
         'LEFT JOIN '.$fulldump_timestamp_table.' AS b '.          'LEFT JOIN '.$fulldump_timestamp_table.' AS b '.
         'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.          'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.
Line 2560  sub get_response_data { Line 2464  sub get_response_data {
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 3 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     my $dataset = $sth->fetchall_arrayref();      my $dataset = $sth->fetchall_arrayref();
Line 2574  sub get_response_data { Line 2479  sub get_response_data {
 }  }
   
   
 sub RDs_awarddetail   { return 3; }  sub RDs_awarddetail     { return 3; }
 sub RDs_submission    { return 2; }  sub RDs_submission      { return 2; }
 sub RDs_timestamp     { return 1; }  sub RDs_timestamp       { return 1; }
 sub RDs_tries         { return 0; }  sub RDs_tries           { return 0; }
 sub RDs_awarded       { return 4; }  sub RDs_awarded         { return 4; }
   sub RDs_response_eval   { return 5; }
   sub RDs_response_eval_2 { return 6; }
   sub RDs_part_award      { return 7; }
   
 sub get_response_data_by_student {  sub get_response_data_by_student {
     my ($student,$symb,$response,$courseid) = @_;      my ($student,$symb,$response,$courseid) = @_;
     return undef if (! defined($symb) ||       return undef if (! defined($symb) || 
                      ! defined($response));                       ! defined($response));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
Line 2596  sub get_response_data_by_student { Line 2504  sub get_response_data_by_student {
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
     my $request = 'SELECT '.      my $request = 'SELECT '.
         'c.tries, b.timestamp, a.submission, a.awarddetail, e.awarded '.          'c.tries, b.timestamp, a.submission, a.awarddetail, c.awarded, '.
    'a.response_specific_value, a.response_specific_value_2, c.award '.
         'FROM '.$fulldump_response_table.' AS a '.          'FROM '.$fulldump_response_table.' AS a '.
         'LEFT JOIN '.$fulldump_timestamp_table.' AS b '.          'LEFT JOIN '.$fulldump_timestamp_table.' AS b '.
         'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.          'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.
Line 2616  sub get_response_data_by_student { Line 2525  sub get_response_data_by_student {
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 4 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     my $dataset = $sth->fetchall_arrayref();      my $dataset = $sth->fetchall_arrayref();
Line 2636  sub RT_tries      { return 2; } Line 2546  sub RT_tries      { return 2; }
 sub RT_timestamp  { return 3; }  sub RT_timestamp  { return 3; }
   
 sub get_response_time_data {  sub get_response_time_data {
     my ($students,$symb,$part,$courseid) = @_;      my ($sections,$enrollment,$symb,$part,$courseid) = @_;
     return undef if (! defined($symb) ||       return undef if (! defined($symb) || 
                      ! defined($part));                       ! defined($part));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
       if (! defined($symb_id)) {
           &Apache::lonnet::logthis('Unable to find symb for '.$symb.' in '.$courseid);
           return undef;
       }
     my $part_id = &get_part_id($part);      my $part_id = &get_part_id($part);
       if (! defined($part_id)) {
           &Apache::lonnet::logthis('Unable to find id for '.$part.' in '.$courseid);
           return undef;
       }
     #      #
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
       my ($student_requirements,$enrollment_requirements) = 
           &limit_by_section_and_status($sections,$enrollment,'d');
     my $request = 'SELECT '.      my $request = 'SELECT '.
         'a.student_id, a.awarded, a.tries, b.timestamp '.          'a.student_id, a.awarded, a.tries, b.timestamp '.
         'FROM '.$fulldump_part_table.' AS a '.          'FROM '.$fulldump_part_table.' AS a '.
         'NATURAL LEFT JOIN '.$fulldump_timestamp_table.' AS b '.          'LEFT JOIN '.$fulldump_timestamp_table.' AS b '.
 #        'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.          'ON a.symb_id=b.symb_id AND a.student_id=b.student_id AND '.
 #        'a.transaction = b.transaction '.          'a.transaction = b.transaction '.
           'LEFT JOIN '.$student_table.' as d '.
           'ON a.student_id=d.student_id '.
         'WHERE '.          'WHERE '.
         'a.symb_id='.$symb_id.' AND a.part_id='.$part_id;          'a.symb_id='.$symb_id.' AND a.part_id='.$part_id;
     if (defined($students)) {      if (defined($student_requirements) || defined($enrollment_requirements)) {
         $request .= ' AND ('.          $request .= ' AND ';
             join(' OR ', map {'a.student_id='.          if (defined($student_requirements)) {
                                   &get_student_id($_->{'username'},              $request .= $student_requirements.' AND ';
                                                   $_->{'domain'})          }
                               } @$students          if (defined($enrollment_requirements)) {
                  ).')';              $request .= $enrollment_requirements.' AND ';
           }
           $request =~ s/( AND )$//;
     }      }
     $request .= ' ORDER BY b.timestamp';      $request .= ' ORDER BY b.timestamp';
 #    &Apache::lonnet::logthis("request =\n".$request);  #    &Apache::lonnet::logthis("request =\n".$request);
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 5 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     my $dataset = $sth->fetchall_arrayref();      my $dataset = $sth->fetchall_arrayref();
Line 2690  sub get_response_time_data { Line 2615  sub get_response_time_data {
 ################################################  ################################################
 ################################################  ################################################
 sub get_student_scores {  sub get_student_scores {
     my ($Sections,$Symbs,$enrollment,$courseid,$starttime,$endtime) = @_;      my ($sections,$Symbs,$enrollment,$courseid,$starttime,$endtime) = @_;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return (undef) if (! defined($dbh));      return (undef) if (! defined($dbh));
     my $tmptable = $courseid.'_temp_'.time;      my $tmptable = $courseid.'_temp_'.time;
       my $request = 'DROP TABLE IF EXISTS '.$tmptable;
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       $dbh->do($request);
     #      #
     my $symb_requirements;      my $symb_requirements;
     if (defined($Symbs)  && @$Symbs) {      if (defined($Symbs)  && @$Symbs) {
Line 2706  sub get_student_scores { Line 2634  sub get_student_scores {
                               } @$Symbs).')';                                } @$Symbs).')';
     }      }
     #      #
     my $student_requirements;      my ($student_requirements,$enrollment_requirements) = 
     if ( (defined($Sections) && $Sections->[0] ne 'all')) {          &limit_by_section_and_status($sections,$enrollment,'b');
         $student_requirements = '('.  
             join(' OR ', map { "b.section='".$_."'" } @$Sections  
                  ).')';  
     }  
     #  
     my $enrollment_requirements=undef;  
     if (defined($enrollment) && $enrollment ne 'Any') {  
         $enrollment_requirements = "b.status='".$enrollment."'";  
     }  
     #      #
     my $time_requirements = undef;      my $time_requirements = &limit_by_start_end_time($starttime,$endtime,'a');
     if (defined($starttime)) {  
         $time_requirements .= "a.timestamp>='".$starttime."'";  
         if (defined($endtime)) {  
             $time_requirements .= " AND a.timestamp<='".$endtime."'";  
         }  
     } elsif (defined($endtime)) {  
         $time_requirements .= "a.timestamp<='".$endtime."'";  
     }  
     ##      ##
     ##      $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable.
     my $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable.          ' SELECT a.student_id,SUM(a.awarded*c.weight) AS score FROM '.
         ' SELECT a.student_id,SUM(a.awarded) AS score FROM '.  
         $performance_table.' AS a ';          $performance_table.' AS a ';
       $request .= "LEFT JOIN ".$weight_table.' AS c ON a.symb_id=c.symb_id AND a.part_id=c.part_id ';
     if (defined($student_requirements) || defined($enrollment_requirements)) {      if (defined($student_requirements) || defined($enrollment_requirements)) {
         $request .= ' NATURAL LEFT JOIN '.$student_table.' AS b ';          $request .= ' LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id';
     }      }
     if (defined($symb_requirements)      ||       if (defined($symb_requirements)      || 
         defined($student_requirements)   ||          defined($student_requirements)   ||
Line 2758  sub get_student_scores { Line 2669  sub get_student_scores {
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 6 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     $request = 'SELECT score,COUNT(*) FROM '.$tmptable.' GROUP BY score';      $request = 'SELECT score,COUNT(*) FROM '.$tmptable.' GROUP BY score';
Line 2766  sub get_student_scores { Line 2678  sub get_student_scores {
     $sth = $dbh->prepare($request);      $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
         &Apache::lonnet::logthis('error = '.$dbh->errstr());          &Apache::lonnet::logthis('error 7 = '.$dbh->errstr());
           &Apache::lonnet::logthis('prepared then executed '.$/.$request);
         return undef;          return undef;
     }      }
     my $dataset = $sth->fetchall_arrayref();      my $dataset = $sth->fetchall_arrayref();
Line 2793  Cleans up the package variables for loca Line 2706  Cleans up the package variables for loca
 sub setup_table_names {  sub setup_table_names {
     my ($courseid) = @_;      my ($courseid) = @_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     #      #
     if (! defined($current_course) || $current_course ne $courseid) {      if (! defined($current_course) || $current_course ne $courseid) {
Line 2866  Retrieve the classist of a given class o Line 2779  Retrieve the classist of a given class o
 information is returned from the classlist.db file and, if needed,  information is returned from the classlist.db file and, if needed,
 from the students environment.  from the students environment.
   
 Optional arguments are $cid, $cdom, and $cnum (course id, course domain,  Optional arguments are $cdom, and $cnum (course domain,
 and course number, respectively).  Any omitted arguments will be taken   and course number, respectively).  If either is ommitted the course
 from the current environment ($ENV{'request.course.id'},  will be taken from the current environment ($env{'request.course.id'},
 $ENV{'course.'.$cid.'.domain'}, and $ENV{'course.'.$cid.'.num'}).  $env{'course.'.$cid.'.domain'}, and $env{'course.'.$cid.'.num'}).
   
 Returns a reference to a hash which contains:  Returns a reference to a hash which contains:
  keys    '$sname:$sdom'   keys    '$sname:$sdom'
  values  [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type]   values  [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type,$lockedtype]
   
 The constant values CL_SDOM, CL_SNAME, CL_END, etc. can be used  The constant values CL_SDOM, CL_SNAME, CL_END, etc. can be used
 as indices into the returned list to future-proof clients against  as indices into the returned list to future-proof clients against
Line 2893  sub CL_SECTION  { return 5; } Line 2806  sub CL_SECTION  { return 5; }
 sub CL_FULLNAME { return 6; }  sub CL_FULLNAME { return 6; }
 sub CL_STATUS   { return 7; }  sub CL_STATUS   { return 7; }
 sub CL_TYPE     { return 8; }  sub CL_TYPE     { return 8; }
   sub CL_LOCKEDTYPE   { return 9; }
   
 sub get_classlist {  sub get_classlist {
     my ($cid,$cdom,$cnum) = @_;      my ($cdom,$cnum) = @_;
     $cid = $cid || $ENV{'request.course.id'};      my $cid = $cdom.'_'.$cnum;
     $cdom = $cdom || $ENV{'course.'.$cid.'.domain'};      if (!defined($cdom) || !defined($cnum)) {
     $cnum = $cnum || $ENV{'course.'.$cid.'.num'};   $cid =  $env{'request.course.id'};
    $cdom = $env{'course.'.$cid.'.domain'};
    $cnum = $env{'course.'.$cid.'.num'};
       }
     my $now = time;      my $now = time;
     #      #
     my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);      my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);
Line 2909  sub get_classlist { Line 2826  sub get_classlist {
         }          }
         my ($sname,$sdom) = split(/:/,$student);          my ($sname,$sdom) = split(/:/,$student);
         my @Values = split(/:/,$info);          my @Values = split(/:/,$info);
         my ($end,$start,$id,$section,$fullname,$type);          my ($end,$start,$id,$section,$fullname,$type,$lockedtype);
         if (@Values > 2) {          if (@Values > 2) {
             ($end,$start,$id,$section,$fullname,$type) = @Values;              ($end,$start,$id,$section,$fullname,$type,$lockedtype) = @Values;
         } else { # We have to get the data ourselves          } else { # We have to get the data ourselves
             ($end,$start) = @Values;              ($end,$start) = @Values;
             $section = &Apache::lonnet::getsection($sdom,$sname,$cid);              $section = &Apache::lonnet::getsection($sdom,$sname,$cid);
Line 2926  sub get_classlist { Line 2843  sub get_classlist {
                 &Apache::lonnet::logthis('unable to retrieve environment '.                  &Apache::lonnet::logthis('unable to retrieve environment '.
                                          'for '.$sname.':'.$sdom);                                           'for '.$sname.':'.$sdom);
             } else {              } else {
                 $fullname = &ProcessFullName(@info{qw/lastname generation                   $fullname = &Apache::lonnet::format_name(@info{qw/firstname middlename lastname generation/},'lastname');
                                                        firstname middlename/});  
                 $id = $info{'id'};                  $id = $info{'id'};
             }              }
             # Update the classlist with this students information              # Update the classlist with this students information
             if ($fullname ne 'not available') {              if ($fullname ne 'not available') {
                 my $enrolldata = join(':',$end,$start,$id,$section,$fullname);   my $enrolldata = join(':',$end,$start,$id,$section,$fullname);
                 my $reply=&Apache::lonnet::cput('classlist',   my $reply=&Apache::lonnet::cput('classlist',
                                                 {$student => $enrolldata},                                                  {$student => $enrolldata},
                                                 $cdom,$cnum);                                                  $cdom,$cnum);
                 if ($reply !~ /^(ok|delayed)/) {                  if ($reply !~ /^(ok|delayed)/) {
Line 2948  sub get_classlist { Line 2864  sub get_classlist {
             $status='Active';              $status='Active';
         }          }
         $classlist{$student} =           $classlist{$student} = 
             [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type];              [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type,$lockedtype];
     }      }
     if (wantarray()) {      if (wantarray()) {
         return (\%classlist,['domain','username','end','start','id',          return (\%classlist,['domain','username','end','start','id',
                              'section','fullname','status','type']);                               'section','fullname','status','type','lockedtype']);
     } else {      } else {
         return \%classlist;          return \%classlist;
     }      }

Removed from v.1.132  
changed lines
  Added in v.1.165


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