Diff for /loncom/interface/loncoursedata.pm between versions 1.129 and 1.156

version 1.129, 2004/04/01 20:02:55 version 1.156, 2006/03/04 06:11:08
Line 50  package Apache::loncoursedata; Line 50  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 Apache::lonhtmlcommon;
 use Time::HiRes;  use Time::HiRes;
 use Apache::lonmysql;  use Apache::lonmysql;
Line 66  and/or itself. Line 66  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 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 580  sub init_dbs { Line 333  sub init_dbs {
                       restrictions => 'NOT NULL',                        restrictions => 'NOT NULL',
                       auto_inc     => 'yes', },                        auto_inc     => 'yes', },
                     { name => 'part',                      { name => 'part',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     ],                      ],
         'PRIMARY KEY' => ['part (100)'],          'PRIMARY KEY' => ['part (100)'],
Line 595  sub init_dbs { Line 348  sub init_dbs {
                       restrictions => 'NOT NULL',                        restrictions => 'NOT NULL',
                       auto_inc     => 'yes', },                        auto_inc     => 'yes', },
                     { name => 'student',                      { name => 'student',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL UNIQUE'},                        restrictions => 'NOT NULL UNIQUE'},
                     { name => 'section',                      { name => 'section',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'status',                      { name => 'status',
                       type => 'VARCHAR(15)',                        type => 'VARCHAR(15) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'classification',                      { name => 'classification',
                       type => 'varchar(100)', },                        type => 'VARCHAR(100) BINARY', },
                     { name => 'updatetime',                      { name => 'updatetime',
                       type => 'INT UNSIGNED'},                        type => 'INT UNSIGNED'},
                     { name => 'fullupdatetime',                      { name => 'fullupdatetime',
Line 629  sub init_dbs { Line 382  sub init_dbs {
                       type => 'MEDIUMINT UNSIGNED',                        type => 'MEDIUMINT UNSIGNED',
                       restrictions => 'NOT NULL' },                        restrictions => 'NOT NULL' },
                     { name => 'part',                      { name => 'part',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                                            restrictions => 'NOT NULL'},                    
                     { name => 'solved',                      { name => 'solved',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
Line 709  sub init_dbs { Line 462  sub init_dbs {
                     { name => 'awarddetail',                      { name => 'awarddetail',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
 #                    { name => 'message',  #                    { name => 'message',
 #                      type => 'CHAR' },  #                      type => 'CHAR BINARY'},
                     { name => 'response_specific',                      { name => 'response_specific',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'response_specific_value',                      { name => 'response_specific_value',
Line 855  sub init_dbs { Line 608  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 837  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 1135  sub clear_internal_caches { Line 898  sub clear_internal_caches {
     undef(%students_by_id);      undef(%students_by_id);
 }  }
   
   
 ################################################  ################################################
 ################################################  ################################################
   
Line 1430  sub update_student_data { Line 1192  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 1248  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 $part = $1;
       next if ($part =~ /\./);
               next if (exists($stored{$part}));
               $stored{$part}++;
               #
             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 $solved  = $value;
Line 1517  sub store_student_data { Line 1285  sub store_student_data {
             $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 1337  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 1364  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 1394  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 1443  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 1619  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 1722  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 1800  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 2056  sub get_problem_statistics { Line 1828  sub get_problem_statistics {
     # Drop the temporary table      # Drop the temporary table
     $dbh->do('DROP TABLE '.$stats_table);  # May return an error      $dbh->do('DROP TABLE '.$stats_table);  # May return an error
     #      #
     # Store in metadata  
     if ($num) {  
  my %storestats=();  
         #  
         my $urlres=(&Apache::lonnet::decode_symb($symb))[2];  
         #  
  $storestats{$courseid.'___'.$urlres.'___timestamp'}=time;         
  $storestats{$courseid.'___'.$urlres.'___stdno'}=$num;  
  $storestats{$courseid.'___'.$urlres.'___avetries'}=$mean;     
  $storestats{$courseid.'___'.$urlres.'___difficulty'}=$DegOfDiff;  
         #  
  $urlres=~/^(\w+)\/(\w+)/;   
  &Apache::lonnet::put('nohist_resevaldata',\%storestats,$1,$2);   
     }  
     #  
     # Return result      # Return result
     return { num_students => $num,      return { num_students => $num,
              tries        => $tries,               tries        => $tries,
Line 2092  sub execute_SQL_request { Line 1849  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 2114  sub execute_SQL_request { Line 1874  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 2131  sub populate_weight_table { Line 1905  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 2235  Inputs: Line 2009  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 2247  sub RNK_student { return 0; }; Line 2029  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) = @_;      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 2260  sub rank_students_by_scores_on_resources Line 2042  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 $request = 'SELECT b.student,SUM(a.awarded*w.weight) AS score FROM '.      my ($award_col, $award_join, $award_clause) = ('', '', '');
         $performance_table.' AS a '.      if ($has_award_for) {
         'NATURAL LEFT JOIN '.$weight_table.' AS w '.          my $resource_id = &get_symb_id($has_award_for);
         'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.          $award_col = ", perf.awarded";
         'WHERE ';          $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 $request = "SELECT b.student,SUM(a.awarded*w.weight) AS score "
           ."$award_col FROM $performance_table AS a ".
           "NATURAL LEFT JOIN $weight_table AS w ".
           "LEFT JOIN $student_table AS b ON a.student_id=b.student_id ".
           "$award_join WHERE ";
     if (defined($section_limits)) {      if (defined($section_limits)) {
         $request .= $section_limits.' AND ';          $request .= $section_limits.' AND ';
     }      }
     if (defined($enrollment_limits)) {      if (defined($enrollment_limits)) {
         $request .= $enrollment_limits.' AND ';          $request .= $enrollment_limits.' AND ';
     }      }
       if (defined($time_limits)) {
           $request .= $time_limits.' AND ';
       }
     if ($symb_limits ne '()') {      if ($symb_limits ne '()') {
         $request .= $symb_limits.' AND ';          $request .= $symb_limits.' AND ';
     }      }
     $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 2304  Returns: the sum of the score on the pro Line 2098  Returns: the sum of the score on the pro
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub get_sum_of_scores {  sub get_sum_of_scores {
     my ($resource,$part,$students,$courseid) = @_;      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);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
       my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
     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)) {
           $request .= ' AND '.$time_limits;
       }
     if (defined($students)) {      if (defined($students)) {
         $request .= ' AND ('.          $request .= ' AND ('.
             join(' OR ',map {'a.student_id='.&get_student_id(split(':',$_));              join(' OR ',map {'a.student_id='.&get_student_id(split(':',$_));
Line 2326  sub get_sum_of_scores { Line 2132  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 2356  Returns: minimum, maximum, mean, s.d., n Line 2164  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 2399  sub score_stats { Line 2207  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 2430  Returns: minimum, maximum, mean, s.d., a Line 2238  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 2448  sub count_stats { Line 2256  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 2463  sub count_stats { Line 2270  sub count_stats {
         $request .= ' AND '.$enrollment_limits;          $request .= ' AND '.$enrollment_limits;
     }      }
     $request .= ' GROUP BY a.student_id';      $request .= ' GROUP BY a.student_id';
     &Apache::lonnet::logthis('request = '.$/.$request);  #    &Apache::lonnet::logthis('request = '.$/.$request);
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     $request =       $request = 
         'SELECT AVG(count),STD(count),MAX(count),MIN(count),COUNT(count) '.          'SELECT AVG(count),STD(count),MAX(count),MIN(count),COUNT(count) '.
         'FROM '.$stats_table;          'FROM '.$stats_table;
     my ($ave,$std,$max,$min,$count) = &execute_SQL_request($dbh,$request);      my ($ave,$std,$max,$min,$count) = &execute_SQL_request($dbh,$request);
     &Apache::lonnet::logthis('request = '.$/.$request);  #    &Apache::lonnet::logthis('request = '.$/.$request);
     return($min,$max,$ave,$std,$count);      return($min,$max,$ave,$std,$count);
 }  }
   
Line 2487  sub count_stats { Line 2294  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 2506  sub get_student_data { Line 2313  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 2527  sub get_response_data { Line 2335  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 2567  sub get_response_data { Line 2383  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 2591  sub get_response_data_by_student { Line 2408  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 2623  sub get_response_data_by_student { Line 2440  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 2643  sub RT_tries      { return 2; } Line 2461  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 2697  sub get_response_time_data { Line 2530  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 2713  sub get_student_scores { Line 2549  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 2765  sub get_student_scores { Line 2584  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 2773  sub get_student_scores { Line 2593  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 2800  Cleans up the package variables for loca Line 2621  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 2873  Retrieve the classist of a given class o Line 2694  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 2900  sub CL_SECTION  { return 5; } Line 2721  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 2916  sub get_classlist { Line 2741  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 2933  sub get_classlist { Line 2758  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 2955  sub get_classlist { Line 2779  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.129  
changed lines
  Added in v.1.156


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