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

version 1.156, 2006/03/04 06:11:08 version 1.180, 2007/01/16 22:50:12
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 Apache::longroup;
 use Time::HiRes;  use Time::HiRes;
 use Apache::lonmysql;  use Apache::lonmysql;
 use HTML::TokeParser;  use HTML::TokeParser;
 use GDBM_File;  use GDBM_File;
   use lib '/home/httpd/lib/perl/';
   use LONCAPA;
   
 =pod  =pod
   
Line 75  and/or itself. Line 77  and/or itself.
   
 Returns a reference to a hash as described by $values.  $values is  Returns a reference to a hash as described by $values.  $values is
 assumed to be the result of   assumed to be the result of 
     join(':',map {&Apache::lonnet::escape($_)} %orighash);      join(':',map {&escape($_)} %orighash);
   
 This is a helper function for get_current_state.  This is a helper function for get_current_state.
   
Line 85  This is a helper function for get_curren Line 87  This is a helper function for get_curren
 ################################################  ################################################
 sub make_into_hash {  sub make_into_hash {
     my $values = shift;      my $values = shift;
     my %tmp = map { &Apache::lonnet::unescape($_); }      my %tmp = map { &unescape($_); } split(':',$values);
                                            split(':',$values);  
     return \%tmp;      return \%tmp;
 }  }
   
Line 160  fifth are 'section', 'status' (enrollmen Line 161  fifth are 'section', 'status' (enrollmen
 data.  This table has its PRIMARY KEY on the 'student_id' column and is indexed  data.  This table has its PRIMARY KEY on the 'student_id' column and is indexed
 on 'student', 'section', and 'status'.  on 'student', 'section', and 'status'.
   
   =item $groupnames_table
   
   The groupnames_table has 2 columns.  The first is a 'group_id' assigned by 
   MySQL.  The second is 'groupname' which is the name of the group in the course.
   
   =item $students_groups_table
   
   The students_groups_table has 2 columns.  The first is the 'student_id', and the 
   second is the 'group_id'. These two columns comprise the PRIMARY KEY for this 
   table, as an individual student may be affiliated with more than one group at
   any time. This table is indexed on both student_id and group_id.
   
 =back   =back 
   
 =item Tables used to store current status data  =item Tables used to store current status data
Line 205  The response table holds data (documente Line 218  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 271  my $current_course =''; Line 285  my $current_course ='';
 my $symb_table;  my $symb_table;
 my $part_table;  my $part_table;
 my $student_table;  my $student_table;
   my $groupnames_table;
   my $students_groups_table;
 my $performance_table;  my $performance_table;
 my $parameters_table;  my $parameters_table;
 my $fulldump_response_table;  my $fulldump_response_table;
Line 353  sub init_dbs { Line 369  sub init_dbs {
                     { name => 'section',                      { name => 'section',
                       type => 'VARCHAR(100) BINARY',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'status',                      { name => 'start',
                       type => 'VARCHAR(15) BINARY',                        type => 'INT',
                         restrictions => 'NOT NULL'},
                       { name => 'end',
                         type => 'INT',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'classification',                      { name => 'classification',
                       type => 'VARCHAR(100) BINARY', },                        type => 'VARCHAR(100) BINARY', },
Line 366  sub init_dbs { Line 385  sub init_dbs {
         'PRIMARY KEY' => ['student_id'],          'PRIMARY KEY' => ['student_id'],
         'KEY' => [{ columns => ['student (100)',          'KEY' => [{ columns => ['student (100)',
                                 'section (100)',                                  'section (100)',
                                 'status (15)',]},],                                  'start',
    'end']},],
       };
       #
       my $groupnames_table_def = {
           id => $groupnames_table,
           permanent => 'no',
           columns => [{ name => 'group_id',
                         type => 'MEDIUMINT UNSIGNED',
                         restrictions => 'NOT NULL',
                         auto_inc => 'yes', },
                       { name => 'groupname',
                         type => 'VARCHAR(100) BINARY',
                         restrictions => 'NOT NULL UNIQUE'},
                      ],
           'PRIMARY KEY' => ['group_id'],
           'KEY' => [{ columns => ['groupname (100)',]},],
       };
       #
       my $students_groups_table_def = {
           id => $students_groups_table,
           permanent => 'no',
           columns => [{ name => 'student_id',
                         type => 'MEDIUMINT UNSIGNED',
                         restrictions => 'NOT NULL', },
                       { name => 'group_id',
                         type => 'MEDIUMINT UNSIGNED',
                         restrictions => 'NOT NULL', },
                      ],
           'PRIMARY KEY' => ['student_id','group_id'],
           'KEY' => [{ columns => ['student_id'] },
                     { columns => ['group_id'] },],
     };      };
     #      #
     my $performance_table_def = {      my $performance_table_def = {
Line 467  sub init_dbs { Line 517  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 598  sub init_dbs { Line 652  sub init_dbs {
                                  &Apache::lonmysql::get_error());                                   &Apache::lonmysql::get_error());
         return 10;          return 10;
     }      }
       $tableid = &Apache::lonmysql::create_table($groupnames_table_def);
       if (! defined($tableid)) {
           &Apache::lonnet::logthis("error creating groupnames_table: ".
                                    &Apache::lonmysql::get_error());
           return 11;
       }
       $tableid = &Apache::lonmysql::create_table($students_groups_table_def);
       if (! defined($tableid)) {
           &Apache::lonnet::logthis("error creating student_groups_table: ".
                                    &Apache::lonmysql::get_error());
           return 12;
       }
     return 0;      return 0;
 }  }
   
Line 844  sub populate_student_table { Line 910  sub populate_student_table {
     &init_dbs($courseid,0);      &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,start,end) VALUES ";
     my $cdom = $env{'course.'.$courseid.'.domain'};      my $cdom = $env{'course.'.$courseid.'.domain'};
     my $cnum = $env{'course.'.$courseid.'.num'};      my $cnum = $env{'course.'.$courseid.'.num'};
     my $classlist = &get_classlist($cdom,$cnum);      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,$start,$end) = ($data->[&CL_SECTION()],
                                  $data->[&CL_STATUS()]);       $data->[&CL_START()],
        $data->[&CL_END()]);
         if ($section eq '' || $section =~ /^\s*$/) {          if ($section eq '' || $section =~ /^\s*$/) {
             $section = 'none';              $section = 'none';
         }          }
         $request .= "('".$student."','".$section."','".$status."'),";   if (!defined($start)) { $start = 0; }
    if (!defined($end))   { $end   = 0; }
           $request .= "('".$student."','".$section."','".$start."','".$end."'),";
         $student_count++;          $student_count++;
     }      }
     return if ($student_count == 0);      return if ($student_count == 0);
Line 869  sub populate_student_table { Line 938  sub populate_student_table {
     return;      return;
 }  }
   
   my $have_read_groupnames_table = 0;
   my %ids_by_groupname;
   
   sub get_group_id {
       my ($groupname) = @_;
       if (! $have_read_groupnames_table) {
           my @Result = &Apache::lonmysql::get_rows($groupnames_table);
           foreach (@Result) {
               $ids_by_groupname{$_->[1]}=$_->[0];
           }
           $have_read_groupnames_table = 1;
       }
       if (! exists($ids_by_groupname{$groupname})) {
           &populate_groupnames_table();
           undef(%ids_by_groupname);
           my @Result = &Apache::lonmysql::get_rows($groupnames_table);
           foreach (@Result) {
               $ids_by_groupname{$_->[1]}=$_->[0];
           }
       }
       if (exists($ids_by_groupname{$groupname})) {
           return $ids_by_groupname{$groupname};
       }
       return undef; # error
   }
   
   sub populate_groupnames_table {
       my ($courseid) = @_;
       if (! defined($courseid)) {
           $courseid = $env{'request.course.id'};
       }
       &setup_table_names($courseid);
       &init_dbs($courseid,0);
       my $dbh = &Apache::lonmysql::get_dbh();
       my $cdom = $env{'course.'.$courseid.'.domain'};
       my $cnum = $env{'course.'.$courseid.'.num'};
       my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
       return if (!%curr_groups);
       my $request = 'INSERT IGNORE INTO '.$groupnames_table.
                     '(groupname) VALUES ';
       foreach my $groupname (sort(keys(%curr_groups)),'none') {
           $request .= "('".$groupname."'),";
       }
       chop($request);
       $dbh->do($request);
       if ($dbh->err()) {
           &Apache::lonnet::logthis("error ".$dbh->errstr().
                                    " occured executing \n".
                                    $request);
       }
       return;
   }
   
   my $have_read_studentsgroups_table = 0;
   my %groupids_by_studentid;
   
   sub get_students_groupids {
       my ($student_id) = @_;
       if (! $have_read_studentsgroups_table) {
           my @Result = &Apache::lonmysql::get_rows($students_groups_table);
           foreach (@Result) {
               push(@{$groupids_by_studentid{$_->[0]}},$_->[1]);
           }
           $have_read_studentsgroups_table = 1;
       }
       if (! exists($groupids_by_studentid{$student_id})) {
           &populate_students_groups_table();
           undef(%groupids_by_studentid);
           my @Result = &Apache::lonmysql::get_rows($students_groups_table);
           foreach (@Result) {
               push(@{$groupids_by_studentid{$_->[0]}},$_->[1]);
           }
       }
       if (exists($groupids_by_studentid{$student_id})) {
           if (ref($groupids_by_studentid{$student_id}) eq 'ARRAY') {
               return @{$groupids_by_studentid{$student_id}};
           }
       }
       return undef; # error
   }
   
   
   sub populate_students_groups_table {
       my ($courseid) = @_;
       if (! defined($courseid)) {
           $courseid = $env{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       &init_dbs($courseid,0);
       my $dbh = &Apache::lonmysql::get_dbh();
       my $request = 'INSERT IGNORE INTO '.$students_groups_table.
           "(student_id,group_id) VALUES ";
       my $cdom = $env{'course.'.$courseid.'.domain'};
       my $cnum = $env{'course.'.$courseid.'.num'};
       my ($classlist,$keylist) = &get_classlist($cdom,$cnum);
       my ($classgroups,$studentgroups) = &get_group_memberships($classlist,
                                                                 $keylist,
                                                                 $cdom,$cnum);
       my $record_count = 0;
       foreach my $student (sort(keys(%{$classgroups}))) {
           my $student_id = &get_student_id(split(':',$student));
           my @studentsgroups = &get_students_groups($student,'Active',$classgroups);
           if (@studentsgroups < 1) {
               @studentsgroups = ('none');
           }
           foreach my $groupname (@studentsgroups) {
               my $group_id = &get_group_id($groupname);
               $request .= "('".$student_id."','".$group_id."'),";
               $record_count++;
           }
       }
       return if ($record_count == 0);
       chop($request);
       $dbh->do($request);
       if ($dbh->err()) {
           &Apache::lonnet::logthis("error ".$dbh->errstr().
                                    " occured executing \n".
                                    $request);
       }
       return;
   }
   
 ################################################  ################################################
 ################################################  ################################################
   
Line 896  sub clear_internal_caches { Line 1088  sub clear_internal_caches {
     $have_read_student_table = 0;      $have_read_student_table = 0;
     undef(%ids_by_student);      undef(%ids_by_student);
     undef(%students_by_id);      undef(%students_by_id);
       $have_read_groupnames_table = 0;
       undef(%ids_by_groupname);
   }
   
   
   ################################################
   ################################################
   
   sub symb_is_for_task {
       my ($symb) = @_;
       return ($symb =~ /\.task$/);
 }  }
   
 ################################################  ################################################
Line 949  sub update_full_student_data { Line 1152  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 974  sub update_full_student_data { Line 1177  sub update_full_student_data {
     while (my ($key,$value) = each(%studentdata)) {      while (my ($key,$value) = each(%studentdata)) {
         next if ($key =~ /^(\d+):(resource$|subnum$|keys:)/);          next if ($key =~ /^(\d+):(resource$|subnum$|keys:)/);
         my ($transaction,$symb,$parameter) = split(':',$key);          my ($transaction,$symb,$parameter) = split(':',$key);
    $symb = &unescape($symb);
    $parameter = &unescape($parameter);
         my $symb_id = &get_symb_id($symb);          my $symb_id = &get_symb_id($symb);
         if ($parameter eq 'timestamp') {          if ($parameter eq 'timestamp') {
             # We can deal with 'timestamp' right away              # We can deal with 'timestamp' right away
Line 989  sub update_full_student_data { Line 1194  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 1087  sub update_full_student_data { Line 1345  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 1176  sub update_student_data { Line 1436  sub update_student_data {
     #      #
     # Download students data      # Download students data
     my $time_of_retrieval = time;      my $time_of_retrieval = time;
     my @tmp = &Apache::lonnet::currentdump($courseid,$sdom,$sname);      my %student_data = &Apache::lonnet::currentdump($courseid,$sdom,$sname);
     if ((scalar(@tmp) > 0) && ($tmp[0] =~ /^error:/)) {      if (&Apache::lonnet::error(%student_data)) {
         &Apache::lonnet::logthis('error getting data for '.          &Apache::lonnet::logthis('error getting data for '.
                                  $sname.':'.$sdom.' in course '.$courseid.                                   $sname.':'.$sdom.' in course '.$courseid.
                                  ':'.$tmp[0]);                                   ':'.(%student_data)[0]);
         $returnstatus = 'error getting data';          $returnstatus =(%student_data)[0] ;
         return ($returnstatus,undef);          return ($returnstatus,undef);
     }      }
     if (scalar(@tmp) < 1) {      if (scalar(keys(%student_data)) < 1) {
         return ('no data',undef);          return ('no data',undef);
     }      }
     my %student_data = @tmp;  
     my @Results = &store_student_data($sname,$sdom,$courseid,\%student_data);      my @Results = &store_student_data($sname,$sdom,$courseid,\%student_data);
     #      #
     # Set the students update time      # Set the students update time
Line 1266  sub store_student_data { Line 1525  sub store_student_data {
         my %stored;          my %stored;
         while (my ($parameter,$value) = each(%$param_hash)) {          while (my ($parameter,$value) = each(%$param_hash)) {
             next if ($parameter !~ /^resource\.(.*)\.(solved|awarded)$/);              next if ($parameter !~ /^resource\.(.*)\.(solved|awarded)$/);
             my $part = $1;              my $part  = $1;
       my $which = $2;
     next if ($part =~ /\./);      next if ($part =~ /\./);
             next if (exists($stored{$part}));              next if (exists($stored{$part}));
             $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 $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));
Line 1344  sub ensure_tables_are_set_up { Line 1614  sub ensure_tables_are_set_up {
     #      #
     # if the tables do not exist, make them      # if the tables do not exist, make them
     my @CurrentTable = &Apache::lonmysql::tables_in_db();      my @CurrentTable = &Apache::lonmysql::tables_in_db();
     my ($found_symb,$found_student,$found_part,      my ($found_symb,$found_student,$found_groups,$found_groupnames,$found_part,
         $found_performance,$found_parameters,$found_fulldump_part,          $found_performance,$found_parameters,$found_fulldump_part,
         $found_fulldump_response,$found_fulldump_timestamp,          $found_fulldump_response,$found_fulldump_timestamp,
         $found_weight);          $found_weight);
     foreach (@CurrentTable) {      foreach (@CurrentTable) {
         $found_symb        = 1 if ($_ eq $symb_table);          $found_symb        = 1 if ($_ eq $symb_table);
         $found_student     = 1 if ($_ eq $student_table);          $found_student     = 1 if ($_ eq $student_table);
           $found_groups      = 1 if ($_ eq $students_groups_table);
           $found_groupnames  = 1 if ($_ eq $groupnames_table);
         $found_part        = 1 if ($_ eq $part_table);          $found_part        = 1 if ($_ eq $part_table);
         $found_performance = 1 if ($_ eq $performance_table);          $found_performance = 1 if ($_ eq $performance_table);
         $found_parameters  = 1 if ($_ eq $parameters_table);          $found_parameters  = 1 if ($_ eq $parameters_table);
Line 1403  sub ensure_current_data { Line 1675  sub ensure_current_data {
         ($sdom,$sname,$courseid.'.db',          ($sdom,$sname,$courseid.'.db',
          $Apache::lonnet::perlvar{'lonUsersDir'});           $Apache::lonnet::perlvar{'lonUsersDir'});
     #      #
       if ($modifiedtime == -1) {
    return ('no data',undef);
       }
   
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
     my @Result = &Apache::lonmysql::get_rows($student_table,      my @Result = &Apache::lonmysql::get_rows($student_table,
                                              "student_id ='$student_id'");                                               "student_id ='$student_id'");
     my $data = undef;      my $data = undef;
     if (@Result) {      if (@Result) {
         $updatetime = $Result[0]->[5];  # Ack!  This is dumb!          $updatetime = $Result[0]->[6];  # Ack!  This is dumb!
     }      }
     if ($modifiedtime > $updatetime) {      if ($modifiedtime > $updatetime) {
         ($status,$data) = &update_student_data($sname,$sdom,$courseid);          ($status,$data) = &update_student_data($sname,$sdom,$courseid);
Line 1456  sub ensure_current_full_data { Line 1732  sub ensure_current_full_data {
                                              "student_id ='$student_id'");                                               "student_id ='$student_id'");
     my $updatetime;      my $updatetime;
     if (@Result && ref($Result[0]) eq 'ARRAY') {      if (@Result && ref($Result[0]) eq 'ARRAY') {
         $updatetime = $Result[0]->[6];          $updatetime = $Result[0]->[7];
     }      }
     if (! defined($updatetime) || $modifiedtime > $updatetime) {      if (! defined($updatetime) || $modifiedtime > $updatetime) {
         $status = &update_full_student_data($sname,$sdom,$courseid);          $status = &update_full_student_data($sname,$sdom,$courseid);
Line 1646  sub get_current_state { Line 1922  sub get_current_state {
     } else {      } else {
         if ($status ne 'okay' && $status ne '') {          if ($status ne 'okay' && $status ne '') {
             &Apache::lonnet::logthis('status = '.$status);              &Apache::lonnet::logthis('status = '.$status);
             return ();              return ('error: '.$status,undef);
         }          }
         my $returnhash = &get_student_data_from_performance_cache($sname,$sdom,          my $returnhash = &get_student_data_from_performance_cache($sname,$sdom,
                                                       $symb,$courseid);                                                        $symb,$courseid);
Line 1667  populated and all local caching variable Line 1943  populated and all local caching variable
 properly.  This means you need to call &ensure_current_data for  properly.  This means you need to call &ensure_current_data for
 the students you are concerned with prior to calling this routine.  the students you are concerned with prior to calling this routine.
   
 Inputs: $Sections, $status, $symb, $part, $courseid, $starttime, $endtime  Inputs: $Sections, Groups, $status, $symb, $part, $courseid, $starttime,
           $endtime
   
 =over 4  =over 4
   
 =item $Sections Array ref containing section names for students.    =item $Sections Array ref containing section names for students.  
 'all' is allowed to be the first (and only) item in the array.  'all' is allowed to be the first (and only) item in the array.
   
   =item $Groups Array ref containing group names for students.
   'all' is allowed to be the first (and only) item in the array.
   
 =item $status String describing the status of students  =item $status String describing the status of students
   
 =item $symb is the symb for the problem.  =item $symb is the symb for the problem.
Line 1720  able to answer it correctly. Line 2000  able to answer it correctly.
 ################################################  ################################################
 ################################################  ################################################
 sub get_problem_statistics {  sub get_problem_statistics {
     my ($Sections,$status,$symb,$part,$courseid,$starttime,$endtime) = @_;      my ($Sections,$Groups,$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));
     #      #
Line 1744  sub get_problem_statistics { Line 2024  sub get_problem_statistics {
         (defined($status)   && lc($status)        ne 'any')) {          (defined($status)   && lc($status)        ne 'any')) {
         $request .= 'NATURAL LEFT JOIN '.$student_table.' AS b ';          $request .= 'NATURAL LEFT JOIN '.$student_table.' AS b ';
     }      }
       my ($groups_join,$group_limits) = &limit_by_group($Groups,'b','c','d');
       if (defined($groups_join)) {
           $request .= $groups_join;
       }
     $request .= ' WHERE a.symb_id='.$symb_id.' AND a.part_id='.$part_id;      $request .= ' WHERE a.symb_id='.$symb_id.' AND a.part_id='.$part_id;
     #      #
     # Limit the students included to those specified      # Limit the students included to those specified
     if (defined($Sections) && lc($Sections->[0]) ne 'all') {      my ($section_limits,$enrollment_limits)=
         $request .= ' AND ('.          &limit_by_section_and_status($Sections,$status,'b');
             join(' OR ', map { "b.section='".$_."'" } @$Sections  
                  ).')';  
     }  
     if (defined($status) && lc($status) ne 'any') {  
         $request .= " AND b.status='".$status."'";  
     }  
     #      #
     # Limit by starttime and endtime      # Limit by starttime and endtime
     my $time_requirements = undef;      my $time_requirements = undef;
Line 1769  sub get_problem_statistics { Line 2047  sub get_problem_statistics {
     if (defined($time_requirements)) {      if (defined($time_requirements)) {
         $request .= ' AND '.$time_requirements;          $request .= ' AND '.$time_requirements;
     }      }
       if (defined($section_limits)) {
           $request .= ' AND '.$section_limits;
       }
       if (defined($enrollment_limits)) {
           $request .= ' AND '.$enrollment_limits;
       }
       # Limit by group, as required
       if (defined($group_limits)) {
           $request .= ' AND '.$group_limits;
       }
     #      #
     # Finally, execute the request to create the temporary table      # Finally, execute the request to create the temporary table
     $dbh->do($request);      $dbh->do($request);
Line 1989  sub limit_by_section_and_status { Line 2277  sub limit_by_section_and_status {
             join(' OR ', map { $tablename.".section='".$_."'" } @$Sections              join(' OR ', map { $tablename.".section='".$_."'" } @$Sections
                  ).')';                   ).')';
     }      }
     #  
     my $enrollment_requirements=undef;      my $enrollment_requirements=undef;
     if (defined($enrollment) && $enrollment ne 'Any') {      if (defined($enrollment) && $enrollment ne 'Any') {
         $enrollment_requirements = $tablename.".status='".$enrollment."'";   my $now = time();
    if ( $enrollment eq 'Future' ) {
       $enrollment_requirements = 
    "( $tablename.start > $now AND ".
    "( $tablename.end = 0 OR $tablename.end > $now))";
    } elsif ( $enrollment eq 'Active' ) {
       $enrollment_requirements = 
    "(( $tablename.start = 0 OR $tablename.start < $now )  AND ".
    " ( $tablename.end   = 0 OR $tablename.end   > $now ))";
    } elsif ( $enrollment eq 'Expired' ) {
       $enrollment_requirements = 
    "(( $tablename.start < $now )  AND ".
    " ( $tablename.end   < $now ))";
    }
     }      }
     return ($student_requirements,$enrollment_requirements);      return ($student_requirements,$enrollment_requirements);
 }  }
   
 ######################################################  ######################################################
 ######################################################  ######################################################
                                                                                  
   =pod
                                                                                  
   =item &limit_by_group
                                                                                  
   Build SQL LEFT JOIN statement to include students_groups and groupnames tables and SQL WHERE condition which limits the data collected by group.
                                                                                  
   Inputs: $Groups (array ref)
       $stutable   The name of the table which holds the student data.
       $grptable   The name of the table which maps group_id to groupname.
       $stugrptab  The name of the table which holds student group affiliations.   
   Returns: $groups_join,$group_limits
      $groups_join  JOIN part of SQL statement (to include group related tables) 
      $group_limits SQL WHERE condition limiting to requested groups
   =cut
   
   sub limit_by_group {
       my ($Groups,$stutable,$grptable,$stugrptab) = @_;
       my $groups_join = undef;
       my $group_limits = undef;
       if ( (defined($Groups) && $Groups->[0] ne 'all')) {
           $groups_join =
             ' LEFT JOIN '.$students_groups_table.
                        ' AS '.$stugrptab.' ON '.
                        $stugrptab.'.student_id = '.$stutable.'.student_id'.
             ' LEFT JOIN '.$groupnames_table.
                        ' AS '.$grptable.' ON '.
                        $stugrptab.'.group_id = '.$grptable.'.group_id ';
           $group_limits =
             ' ('.
                join(' OR ', map {  "$grptable.groupname='".$_."'" } @$Groups
              ).')';
       }
       return ($groups_join,$group_limits);
   }
   
 =pod  =pod
   
Line 2007  sub limit_by_section_and_status { Line 2342  sub limit_by_section_and_status {
 Inputs:   Inputs: 
     $resources: array ref of hash ref.  Each hash ref needs key 'symb'.      $resources: array ref of hash ref.  Each hash ref needs key 'symb'.
     $Sections: array ref of sections to include,      $Sections: array ref of sections to include,
       $Groups: array ref of groups to include.
     $enrollment: string,      $enrollment: string,
     $courseid (may be omitted)      $courseid (may be omitted)
     $starttime (may be omitted)      $starttime (may be omitted)
Line 2029  sub RNK_student { return 0; }; Line 2365  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,$has_award_for) = @_;      my ($resources,$Sections,$Groups,$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'};
Line 2039  sub rank_students_by_scores_on_resources Line 2376  sub rank_students_by_scores_on_resources
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     my ($section_limits,$enrollment_limits)=      my ($section_limits,$enrollment_limits)=
         &limit_by_section_and_status($Sections,$enrollment,'b');          &limit_by_section_and_status($Sections,$enrollment,'b');
       my ($groups_join,$group_limits) = &limit_by_group($Groups,'b','c','d');
     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
                                ).')';                                 ).')';
Line 2055  sub rank_students_by_scores_on_resources Line 2393  sub rank_students_by_scores_on_resources
         ."$award_col FROM $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 ".
         "$award_join WHERE ";          "$award_join $groups_join "; 
       my $limits;
     if (defined($section_limits)) {      if (defined($section_limits)) {
         $request .= $section_limits.' AND ';          $limits .= $section_limits.' AND ';
     }      }
     if (defined($enrollment_limits)) {      if (defined($enrollment_limits)) {
         $request .= $enrollment_limits.' AND ';          $limits .= $enrollment_limits.' AND ';
     }      }
     if (defined($time_limits)) {      if (defined($time_limits)) {
         $request .= $time_limits.' AND ';          $limits .= $time_limits.' AND ';
     }      }
     if ($symb_limits ne '()') {      if ($symb_limits ne '()') {
         $request .= $symb_limits.' AND ';          $limits .= $symb_limits.' AND ';
       }
       if (defined($group_limits)) {
           $limits .= $group_limits.' AND ';
     }      }
     $request =~ s/( AND )$//;   # Remove extra conjunction      if ($limits) {
     $request =~ s/( WHERE )$//; # In case there were no limits placed on it          $limits =~ s/( AND )$//;   # Remove extra conjunction
           $request .= "WHERE $limits";
       } 
     $request .= " $award_clause 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) or die "Can't prepare $request";      my $sth = $dbh->prepare($request) or die "Can't prepare $request";
Line 2162  Returns: minimum, maximum, mean, s.d., n Line 2506  Returns: minimum, maximum, mean, s.d., n
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub score_stats {  sub score_stats {
     my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;      my ($Sections,$Groups,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $env{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
Line 2172  sub score_stats { Line 2516  sub score_stats {
     #      #
     my ($section_limits,$enrollment_limits)=      my ($section_limits,$enrollment_limits)=
         &limit_by_section_and_status($Sections,$enrollment,'b');          &limit_by_section_and_status($Sections,$enrollment,'b');
       my ($groups_join,$group_limits) = &limit_by_group($Groups,'b','c','d');
     my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');      my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
     my @Symbids = map { &get_symb_id($_); } @{$symbs};      my @Symbids = map { &get_symb_id($_); } @{$symbs};
     #      #
Line 2186  sub score_stats { Line 2531  sub score_stats {
         $performance_table.' AS a '.          $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 ('.$symb_restriction.')';          $groups_join;
       my $limit = ' WHERE ('.$symb_restriction.')';
     if ($time_limits) {      if ($time_limits) {
         $request .= ' AND '.$time_limits;          $limit .= ' AND '.$time_limits;
     }      }
     if ($section_limits) {      if ($section_limits) {
         $request .= ' AND '.$section_limits;          $limit .= ' AND '.$section_limits;
     }      }
     if ($enrollment_limits) {      if ($enrollment_limits) {
         $request .= ' AND '.$enrollment_limits;          $limit .= ' AND '.$enrollment_limits;
     }      }
     $request .= ' GROUP BY a.student_id';      if ($group_limits) {
           $limit .= ' AND '.$group_limits;
       }
       $request .= $limit.' 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();
Line 2221  sub score_stats { Line 2570  sub score_stats {
   
 =item &count_stats  =item &count_stats
   
 Inputs: $Sections, $enrollment, $symbs, $starttime,  Inputs: $Sections, $Groups, $enrollment, $symbs, $starttime,
         $endtime, $courseid          $endtime, $courseid
   
 $Sections, $enrollment, $starttime, $endtime, and $courseid are the same as   $Sections, $Groups $enrollment, $starttime, $endtime, and $courseid are the 
 elsewhere in this module.    same as elsewhere in this module.  
 $symbs is an array ref of symbs  $symbs is an array ref of symbs
   
 Returns: minimum, maximum, mean, s.d., and number of students  Returns: minimum, maximum, mean, s.d., and number of students
Line 2236  Returns: minimum, maximum, mean, s.d., a Line 2585  Returns: minimum, maximum, mean, s.d., a
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub count_stats {  sub count_stats {
     my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;      my ($Sections,$Groups,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $env{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
Line 2246  sub count_stats { Line 2595  sub count_stats {
     #      #
     my ($section_limits,$enrollment_limits)=      my ($section_limits,$enrollment_limits)=
         &limit_by_section_and_status($Sections,$enrollment,'b');          &limit_by_section_and_status($Sections,$enrollment,'b');
       my ($groups_join,$group_limits) = &limit_by_group($Groups,'b','c','d');
     my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');      my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
     my @Symbids = map { &get_symb_id($_); } @{$symbs};      my @Symbids = map { &get_symb_id($_); } @{$symbs};
     #      #
Line 2259  sub count_stats { Line 2609  sub count_stats {
         'SUM(a.awarded) 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.')';          $groups_join;
       my $limit =  ' WHERE ('.$symb_restriction.')';
     if ($time_limits) {      if ($time_limits) {
         $request .= ' AND '.$time_limits;          $limit .= ' AND '.$time_limits;
     }      }
     if ($section_limits) {      if ($section_limits) {
         $request .= ' AND '.$section_limits;          $limit .= ' AND '.$section_limits;
     }      }
     if ($enrollment_limits) {      if ($enrollment_limits) {
         $request .= ' AND '.$enrollment_limits;          $limit .= ' AND '.$enrollment_limits;
     }      }
     $request .= ' GROUP BY a.student_id';      if ($group_limits) {
           $limit .= ' AND '.$group_limits;
       }
       $request .= $limit.' 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();
Line 2323  sub get_student_data { Line 2677  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,$Groups,$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));
Line 2354  sub get_response_data { Line 2709  sub get_response_data {
     #      #
     my ($student_requirements,$enrollment_requirements) =       my ($student_requirements,$enrollment_requirements) = 
         &limit_by_section_and_status($Sections,$enrollment,'d');          &limit_by_section_and_status($Sections,$enrollment,'d');
       my ($groups_join,$group_limits) = &limit_by_group($Groups,'d','e','f');
     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 2366  sub get_response_data { Line 2723  sub get_response_data {
         'a.part_id=c.part_id AND a.transaction = c.transaction '.          'a.part_id=c.part_id AND a.transaction = c.transaction '.
         'LEFT JOIN '.$student_table.' AS d '.          'LEFT JOIN '.$student_table.' AS d '.
         'ON a.student_id=d.student_id '.          'ON a.student_id=d.student_id '.
         'WHERE '.          $groups_join;
       my $limit = ' WHERE '.
         'a.symb_id='.$symb_id.' AND a.response_id='.$response_id;          'a.symb_id='.$symb_id.' AND a.response_id='.$response_id;
     if (defined($student_requirements) || defined($enrollment_requirements)) {      if (defined($student_requirements)) {
         $request .= ' AND ';          $limit .= ' AND '.$student_requirements;
         if (defined($student_requirements)) {      }
             $request .= $student_requirements.' AND ';      if (defined($enrollment_requirements)) {
         }          $limit .= ' AND '.$enrollment_requirements;
         if (defined($enrollment_requirements)) {      }
             $request .= $enrollment_requirements.' AND ';      if (defined($group_limits)) {
         }          $limit .= ' AND '.$group_limits;
         $request =~ s/( AND )$//;  
     }      }
     $request .= ' ORDER BY b.timestamp';      $request .= $limit.' 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();
Line 2391  sub get_response_data { Line 2748  sub get_response_data {
     if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) {      if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) {
         # Clear the \'s from around the submission          # Clear the \'s from around the submission
         for (my $i =0;$i<scalar(@$dataset);$i++) {          for (my $i =0;$i<scalar(@$dataset);$i++) {
             $dataset->[$i]->[3] =~ s/(\'$|^\')//g;              $dataset->[$i]->[&RD_submission()] =~ s/(\'$|^\')//g;
         }          }
         return $dataset;          return $dataset;
     }      }
 }  }
   
   
 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) = @_;
Line 2420  sub get_response_data_by_student { Line 2780  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 2448  sub get_response_data_by_student { Line 2809  sub get_response_data_by_student {
     if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) {      if (ref($dataset) eq 'ARRAY' && scalar(@$dataset)>0) {
         # Clear the \'s from around the submission          # Clear the \'s from around the submission
         for (my $i =0;$i<scalar(@$dataset);$i++) {          for (my $i =0;$i<scalar(@$dataset);$i++) {
             $dataset->[$i]->[2] =~ s/(\'$|^\')//g;              $dataset->[$i]->[&RDs_submission] =~ s/(\'$|^\')//g;
         }          }
         return $dataset;          return $dataset;
     }      }
Line 2461  sub RT_tries      { return 2; } Line 2822  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 ($sections,$enrollment,$symb,$part,$courseid) = @_;      my ($sections,$groups,$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));
Line 2482  sub get_response_time_data { Line 2843  sub get_response_time_data {
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
     my ($student_requirements,$enrollment_requirements) =       my ($student_requirements,$enrollment_requirements) = 
         &limit_by_section_and_status($sections,$enrollment,'d');          &limit_by_section_and_status($sections,$enrollment,'d');
       my ($groups_join,$group_limits) = &limit_by_group($groups,'d','e','f');
     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 '.
Line 2490  sub get_response_time_data { Line 2852  sub get_response_time_data {
         'a.transaction = b.transaction '.          'a.transaction = b.transaction '.
         'LEFT JOIN '.$student_table.' as d '.          'LEFT JOIN '.$student_table.' as d '.
         'ON a.student_id=d.student_id '.          'ON a.student_id=d.student_id '.
         'WHERE '.          $groups_join;
       my $limit = ' 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($student_requirements) || defined($enrollment_requirements)) {      if (defined($student_requirements)) {
         $request .= ' AND ';          $limit .= ' AND '.$student_requirements;
         if (defined($student_requirements)) {  
             $request .= $student_requirements.' AND ';  
         }  
         if (defined($enrollment_requirements)) {  
             $request .= $enrollment_requirements.' AND ';  
         }  
         $request =~ s/( AND )$//;  
     }      }
     $request .= ' ORDER BY b.timestamp';      if (defined($enrollment_requirements)) {
           $limit .= ' AND '.$enrollment_requirements;
       }
       if (defined($group_limits)) {
           $limit .= ' AND '.$group_limits;  
       }
       $request .= $limit.' 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();
Line 2523  sub get_response_time_data { Line 2885  sub get_response_time_data {
   
 =pod  =pod
   
 =item &get_student_scores($Sections,$Symbs,$enrollment,$courseid)  =item &get_student_scores($Sections,$Groups,$Symbs,$enrollment,$courseid)
   
 =cut  =cut
   
 ################################################  ################################################
 ################################################  ################################################
 sub get_student_scores {  sub get_student_scores {
     my ($sections,$Symbs,$enrollment,$courseid,$starttime,$endtime) = @_;      my ($sections,$groups,$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();
Line 2552  sub get_student_scores { Line 2914  sub get_student_scores {
     my ($student_requirements,$enrollment_requirements) =       my ($student_requirements,$enrollment_requirements) = 
         &limit_by_section_and_status($sections,$enrollment,'b');          &limit_by_section_and_status($sections,$enrollment,'b');
     #      #
       my ($groups_join,$group_limits) = &limit_by_group($groups,'b','d','e');
     my $time_requirements = &limit_by_start_end_time($starttime,$endtime,'a');      my $time_requirements = &limit_by_start_end_time($starttime,$endtime,'a');
     ##      ##
     $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable.      $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable.
Line 2559  sub get_student_scores { Line 2922  sub get_student_scores {
         $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 ';      $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 .= ' LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id';          $request .= ' LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id ';
       }
       if (defined($groups_join)) {
           $request .= $groups_join;
     }      }
     if (defined($symb_requirements)      ||       if (defined($symb_requirements)       || 
         defined($student_requirements)   ||          defined($student_requirements)    ||
         defined($enrollment_requirements) ) {          defined($enrollment_requirements) ||
           defined($group_limits) ) {
         $request .= ' WHERE ';          $request .= ' WHERE ';
     }      }
     if (defined($symb_requirements)) {      if (defined($symb_requirements)) {
Line 2635  sub setup_table_names { Line 3002  sub setup_table_names {
         $have_read_student_table = 0;          $have_read_student_table = 0;
         undef(%ids_by_student);          undef(%ids_by_student);
         undef(%students_by_id);          undef(%students_by_id);
           $have_read_groupnames_table = 0;
           undef(%ids_by_groupname);
         #          #
         $current_course = $courseid;          $current_course = $courseid;
     }      }
     #      #
     # Set up database names      # Set up database names
     my $base_id = $courseid;      my $base_id = $courseid;
     $symb_table        = $base_id.'_'.'symb';      $symb_table               = $base_id.'_'.'symb';
     $part_table        = $base_id.'_'.'part';      $part_table               = $base_id.'_'.'part';
     $student_table     = $base_id.'_'.'student';      $student_table            = $base_id.'_'.'student';
     $performance_table = $base_id.'_'.'performance';      $groupnames_table         = $base_id.'_'.'groupnames';
     $parameters_table  = $base_id.'_'.'parameters';      $students_groups_table    = $base_id.'_'.'studentgroups';
       $performance_table        = $base_id.'_'.'performance';
       $parameters_table         = $base_id.'_'.'parameters';
     $fulldump_part_table      = $base_id.'_'.'partdata';      $fulldump_part_table      = $base_id.'_'.'partdata';
     $fulldump_response_table  = $base_id.'_'.'responsedata';      $fulldump_response_table  = $base_id.'_'.'responsedata';
     $fulldump_timestamp_table = $base_id.'_'.'timestampdata';      $fulldump_timestamp_table = $base_id.'_'.'timestampdata';
Line 2655  sub setup_table_names { Line 3026  sub setup_table_names {
                $symb_table,                 $symb_table,
                $part_table,                 $part_table,
                $student_table,                 $student_table,
                  $groupnames_table,
                  $students_groups_table,
                $performance_table,                 $performance_table,
                $parameters_table,                 $parameters_table,
                $fulldump_part_table,                 $fulldump_part_table,
Line 2778  sub get_classlist { Line 3151  sub get_classlist {
         if(((!$end) || $now < $end) && ((!$start) || ($now > $start))) {          if(((!$end) || $now < $end) && ((!$start) || ($now > $start))) {
             $status='Active';              $status='Active';
         }          }
           if(($now < $start) && ((!$end) || $now < $end )) {
               $status='Future';
           }
         $classlist{$student} =           $classlist{$student} = 
             [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type,$lockedtype];              [$sdom,$sname,$end,$start,$id,$section,$fullname,$status,$type,$lockedtype];
     }      }
Line 2789  sub get_classlist { Line 3165  sub get_classlist {
     }      }
 }  }
   
   sub get_group_memberships {
       my ($classlist,$keylist,$cdom,$cnum) = @_;
   
       return ({},{}) if (!ref($classlist) || !ref($keylist));
   
       my $cid = $cdom.'_'.$cnum;
       if (!defined($cdom) || !defined($cnum)) {
           $cid =  $env{'request.course.id'};
           $cdom = $env{'course.'.$cid.'.domain'};
           $cnum = $env{'course.'.$cid.'.num'};
       }
       my (%classgroups,%studentgroups);
       my $now = time;
       my $access_end = $env{'course.'.$cid.'.default_enrollment_end_date'};
       my %curr_groups =&Apache::longroup::coursegroups($cdom,$cnum);
       if (%curr_groups) {
           my $grpindex = scalar(@{$keylist});
           my %groupmemberhash = 
       &Apache::lonnet::get_group_membership($cdom,$cnum);
           foreach my $student (keys(%{$classlist})) {
               %{$classgroups{$student}} = ();
               my $hasgroup = 0;
               foreach my $status ('previous','future','active','aftercourse') {
                   %{$classgroups{$student}{$status}} = ();
               }
               foreach my $group (keys(%curr_groups)) {
                   if (defined($groupmemberhash{$group.':'.$student})) {
                       my ($end,$start) = split(/:/,$groupmemberhash{$group.':'.
                                                                       $student});
                       if ($start == -1) {
                           next;
                       } else {
                           $studentgroups{$group} ++;
                           $hasgroup = 1;
                           if ($end && $end < $now) {
                               $classgroups{$student}{'previous'}{$group} =
                                            $groupmemberhash{$group.':'.$student};
                               if ($classlist->{$student}[&CL_STATUS()] eq 'Expired') {
                                   if ($access_end && $access_end < $now) {
                                       if ($access_end - $end < 86400) {
                                           $classgroups{$student}{'aftercourse'}{$group} = $groupmemberhash{$group.':'.$student};
                                       }
                                   }
                               }
                           } elsif ($now > $start) {
                               if (!$end || $end > $now) {
                                   $classgroups{$student}{'active'}{$group} =
                                            $groupmemberhash{$group.':'.$student};
                               }
                           } else {
                               $classgroups{$student}{'future'}{$group} =
                                            $groupmemberhash{$group.':'.$student};
                           }
                       }
                   }
               }
               if (!$hasgroup) {
                   $studentgroups{'none'} ++;
               } else {
                   $classlist->{$student}->[$grpindex] = join(',',
                                 sort(keys(%{$classgroups{$student}{'active'}})));
               }
           }
       }
       return (\%classgroups,\%studentgroups);
   }
                                                                                      
   sub get_students_groups {
       my ($student,$enrollment_status,$classgroups) = @_;
       my @studentsgroups = ();
       if (ref($$classgroups{$student}{'active'}) eq 'HASH') {
           push(@studentsgroups,keys(%{$$classgroups{$student}{'active'}}));
       }
       if ($enrollment_status eq 'Any') {
           foreach my $status ('previous','future') {
               if (ref($$classgroups{$student}{$status}) eq 'HASH') {
                   push(@studentsgroups,keys(%{$$classgroups{$student}{$status}}));
               }
           }
       } else {
           if (ref($$classgroups{$student}{'aftercourse'}) eq 'HASH') {
               push(@studentsgroups,keys(%{$$classgroups{$student}{'aftercourse'}}));
           }
       }
       return @studentsgroups;
   }
   
   
 # ----- END HELPER FUNCTIONS --------------------------------------------  # ----- END HELPER FUNCTIONS --------------------------------------------
   
 1;  1;
 __END__  __END__
   
   

Removed from v.1.156  
changed lines
  Added in v.1.180


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