Diff for /loncom/interface/loncoursedata.pm between versions 1.141.2.2 and 1.175

version 1.141.2.2, 2005/04/19 21:41:17 version 1.175, 2006/08/10 21:07:01
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 66  and/or itself. Line 68  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(1);  
  if (!$curRes) { last; }  
         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->compTitle;  
             $symb  = $previous->symb();  
             $src   = $previous->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->compTitle();  
         $symb  = $curRes->symb();  
         $src   = $curRes->src();  
         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;  
             $partdata{$part}->{'Survey'}       = $curRes->is_survey($part);  
             # 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);  
     }  
     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;  
 }  
   
 ################################################  ################################################
 ################################################  ################################################
   
Line 245  sub LoadDiscussion { Line 77  sub LoadDiscussion {
   
 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 255  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 330  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 375  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 441  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 539  sub init_dbs { Line 385  sub init_dbs {
                                 'status (15)',]},],                                  'status (15)',]},],
     };      };
     #      #
       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 = {
         id => $performance_table,          id => $performance_table,
         permanent => 'no',          permanent => 'no',
Line 637  sub init_dbs { Line 513  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 768  sub init_dbs { Line 648  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 778  sub init_dbs { Line 670  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 1000  sub get_student { Line 899  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);
Line 1008  sub populate_student_table { Line 907  sub populate_student_table {
     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 1030  sub populate_student_table { Line 931  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 1057  sub clear_internal_caches { Line 1081  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$/);
   }
   
   ################################################
   ################################################
   
 =pod  =pod
   
 =item &update_full_student_data($sname,$sdom,$courseid)  =item &update_full_student_data($sname,$sdom,$courseid)
Line 1111  sub update_full_student_data { Line 1145  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 1151  sub update_full_student_data { Line 1185  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 1249  sub update_full_student_data { Line 1336  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 1354  sub update_student_data { Line 1443  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 1410  sub store_student_data { Line 1499  sub store_student_data {
         # make sure the symb is set up properly          # make sure the symb is set up properly
         my $symb_id = &get_symb_id($current_symb);          my $symb_id = &get_symb_id($current_symb);
         #          #
         # Load data into the tables          # Parameters
         while (my ($parameter,$value) = each(%$param_hash)) {          while (my ($parameter,$value) = each(%$param_hash)) {
             my $newstring;  
             if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) {              if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) {
                 $newstring = "('".join("','",                  my $sql_parameter = "('".join("','",
                                        $symb_id,$student_id,                                                $symb_id,$student_id,
                                        $parameter)."',".                                                $parameter)."',".
                                            $dbh->quote($value)."),\n";                                                    $dbh->quote($value)."),\n";
                 $num_parameters ++;                  $num_parameters ++;
                 if ($newstring !~ /''/) {                  if ($sql_parameter !~ /''/) {
                     $store_parameters_command .= $newstring;                      $store_parameters_command .= $sql_parameter;
                     $rows_stored++;                      #$rows_stored++;
                 }                  }
             }              }
             next if ($parameter !~ /^resource\.(.*)\.solved$/);          }
           # Performance
           my %stored;
           while (my ($parameter,$value) = each(%$param_hash)) {
               next if ($parameter !~ /^resource\.(.*)\.(solved|awarded)$/);
               my $part  = $1;
       my $which = $2;
       next if ($part =~ /\./);
               next if (exists($stored{$part}));
               $stored{$part}++;
             #              #
             my $part = $1;  
             my $part_id = &get_part_id($part);              my $part_id = &get_part_id($part);
             next if (!defined($part_id));              next if (!defined($part_id));
             my $solved  = $value;      
             my $tries   = $param_hash->{'resource.'.$part.'.tries'};              my ($solved,$awarded);
             my $awarded = $param_hash->{'resource.'.$part.'.awarded'};      if ($which eq 'solved') {
    $solved  = $value;
    $awarded = $param_hash->{'resource.'.$part.'.awarded'};
       } else {
    $solved  = $param_hash->{'resource.'.$part.'.solved'};
    $awarded = $value;
       }
             my $award   = $param_hash->{'resource.'.$part.'.award'};              my $award   = $param_hash->{'resource.'.$part.'.award'};
             my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'};              my $awarddetail = $param_hash->{'resource.'.$part.'.awarddetail'};
             my $timestamp = $param_hash->{'timestamp'};              my $timestamp = $param_hash->{'timestamp'};
       my $tries   = $param_hash->{'resource.'.$part.'.tries'};
       if (&symb_is_for_task($current_symb)) {
    $tries   = $param_hash->{'resource.'.$part.'.version'};
       }
             #              #
             $solved      = '' if (! defined($solved));              $solved      = '' if (! defined($solved));
             $tries       = '' if (! defined($tries));              $tries       = '' if (! defined($tries));
             $awarded     = '' if (! defined($awarded));              $awarded     = '' if (! defined($awarded));
             $award       = '' if (! defined($award));              $award       = '' if (! defined($award));
             $awarddetail = '' if (! defined($awarddetail));              $awarddetail = '' if (! defined($awarddetail));
             $newstring = "('".join("','",$symb_id,$student_id,$part_id,$part,              my $sql_performance = 
                                    $solved,$tries,$awarded,$award,                  "('".join("','",$symb_id,$student_id,$part_id,$part,
                                    $awarddetail,$timestamp)."'),\n";                                  $solved,$tries,$awarded,$award,
             $store_performance_command .= $newstring;                                  $awarddetail,$timestamp)."'),\n";
               $store_performance_command .= $sql_performance;
             $rows_stored++;              $rows_stored++;
         }          }
     }      }
     chop $store_parameters_command;      if (! $rows_stored) { return ($returnstatus, undef); }
     chop $store_parameters_command;      $store_parameters_command =~ s|,\n$||;
     chop $store_performance_command;      $store_performance_command =~ s|,\n$||;
     chop $store_performance_command;  
     my $start = Time::HiRes::time;      my $start = Time::HiRes::time;
     $dbh->do($store_performance_command);      $dbh->do($store_performance_command);
     if ($dbh->err()) {      if ($dbh->err()) {
         &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr());          &Apache::lonnet::logthis('performance bigass insert error:'.
         &Apache::lonnet::logthis('command = '.$store_performance_command);                                   $dbh->errstr());
           &Apache::lonnet::logthis('command = '.$/.$store_performance_command);
         $returnstatus = 'error: unable to insert performance into database';          $returnstatus = 'error: unable to insert performance into database';
         return ($returnstatus,$student_data);          return ($returnstatus,$student_data);
     }      }
     $dbh->do($store_parameters_command) if ($num_parameters>0);      $dbh->do($store_parameters_command) if ($num_parameters>0);
     if ($dbh->err()) {      if ($dbh->err()) {
         &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr());          &Apache::lonnet::logthis('parameters bigass insert error:'.
         &Apache::lonnet::logthis('command = '.$store_parameters_command);                                   $dbh->errstr());
           &Apache::lonnet::logthis('command = '.$/.$store_parameters_command);
         &Apache::lonnet::logthis('rows_stored = '.$rows_stored);          &Apache::lonnet::logthis('rows_stored = '.$rows_stored);
         &Apache::lonnet::logthis('student_id = '.$student_id);          &Apache::lonnet::logthis('student_id = '.$student_id);
         $returnstatus = 'error: unable to insert parameters into database';          $returnstatus = 'error: unable to insert parameters into database';
Line 1491  Returns nothing on success and 'error' o Line 1599  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);
     #      #
     # 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 1548  sub ensure_current_data { Line 1658  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 1597  sub ensure_current_full_data { Line 1707  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 1773  an empty list is returned. Line 1883  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 1821  populated and all local caching variable Line 1931  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 1874  able to answer it correctly. Line 1988  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));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
Line 1898  sub get_problem_statistics { Line 2012  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
Line 1923  sub get_problem_statistics { Line 2041  sub get_problem_statistics {
     if (defined($time_requirements)) {      if (defined($time_requirements)) {
         $request .= ' AND '.$time_requirements;          $request .= ' AND '.$time_requirements;
     }      }
       # 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 2003  sub execute_SQL_request { Line 2125  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 2025  sub execute_SQL_request { Line 2150  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 2042  sub populate_weight_table { Line 2181  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 2126  sub limit_by_section_and_status { Line 2265  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."'";          $enrollment_requirements = $tablename.".status='".$enrollment."'";
Line 2136  sub limit_by_section_and_status { Line 2274  sub limit_by_section_and_status {
   
 ######################################################  ######################################################
 ######################################################  ######################################################
                                                                                  
   =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 2144  sub limit_by_section_and_status { Line 2317  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)
       $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 2158  sub RNK_student { return 0; }; Line 2340  sub RNK_student { return 0; };
 sub RNK_score   { return 1; };  sub RNK_score   { return 1; };
   
 sub rank_students_by_scores_on_resources {  sub rank_students_by_scores_on_resources {
     my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime) = @_;      my ($resources,$Sections,$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'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     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
                                ).')';                                 ).')';
       my ($award_col, $award_join, $award_clause) = ('', '', '');
       if ($has_award_for) {
           my $resource_id = &get_symb_id($has_award_for);
           $award_col = ", perf.awarded";
           $award_join = "LEFT JOIN $performance_table AS perf ON perf.symb_id"
               ." = $resource_id AND perf.student_id = b.student_id ";
           $award_clause = "AND perf.awarded IS NOT NULL";
       }
     my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');      my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
     my $request = 'SELECT b.student,SUM(a.awarded*w.weight) AS score FROM '.      my $request = "SELECT b.student,SUM(a.awarded*w.weight) AS score "
         $performance_table.' AS a '.          ."$award_col FROM $performance_table AS a ".
         'NATURAL LEFT JOIN '.$weight_table.' AS w '.          "NATURAL LEFT JOIN $weight_table AS w ".
         'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.          "LEFT JOIN $student_table AS b ON a.student_id=b.student_id ".
         'WHERE ';          "$award_join $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 .= ' GROUP BY a.student_id ORDER BY score';          $request .= "WHERE $limits";
       } 
       $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 2219  Returns: the sum of the score on the pro Line 2417  Returns: the sum of the score on the pro
 ########################################################  ########################################################
 ########################################################  ########################################################
 sub get_sum_of_scores {  sub get_sum_of_scores {
     my ($resource,$part,$students,$courseid,$starttime,$endtime) = @_;      my ($symb,$part,$students,$courseid,$starttime,$endtime) = @_;
     if (! defined($courseid)) {      if (! defined($courseid)) {
         $courseid = $ENV{'request.course.id'};          $courseid = $env{'request.course.id'};
     }      }
     if (defined($students) &&       if (defined($students) && 
         ((@$students == 0) ||          ((@$students == 0) ||
Line 2238  sub get_sum_of_scores { Line 2436  sub get_sum_of_scores {
     my $request = 'SELECT SUM(a.awarded*w.weight),SUM(w.weight) FROM '.      my $request = 'SELECT SUM(a.awarded*w.weight),SUM(w.weight) FROM '.
         $performance_table.' AS a '.          $performance_table.' AS a '.
         'NATURAL LEFT JOIN '.$weight_table.' AS w ';          'NATURAL LEFT JOIN '.$weight_table.' AS w ';
     $request .= 'WHERE a.symb_id='.&get_symb_id($resource->{'symb'}).      $request .= 'WHERE a.symb_id='.&get_symb_id($symb).
         ' AND a.part_id='.&get_part_id($part);          ' AND a.part_id='.&get_part_id($part);
     if (defined($time_limits)) {      if (defined($time_limits)) {
         $request .= ' AND '.$time_limits;          $request .= ' AND '.$time_limits;
Line 2283  Returns: minimum, maximum, mean, s.d., n Line 2481  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'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2293  sub score_stats { Line 2491  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 2307  sub score_stats { Line 2506  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 2328  sub score_stats { Line 2531  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 2342  sub score_stats { Line 2545  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 2357  Returns: minimum, maximum, mean, s.d., a Line 2560  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'};
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
Line 2367  sub count_stats { Line 2570  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 2377  sub count_stats { Line 2581  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.')'.          $groups_join;
         " AND a.award!='INCORRECT_ATTEMPTED'";      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 2416  sub count_stats { Line 2623  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 2445  sub get_student_data { Line 2652  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));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
Line 2476  sub get_response_data { Line 2684  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 2488  sub get_response_data { Line 2698  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 ';  
         }  
         $request =~ s/( AND )$//;  
     }      }
     $request .= ' ORDER BY b.timestamp';      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 2520  sub get_response_data { Line 2730  sub get_response_data {
 }  }
   
   
 sub RDs_awarddetail   { return 3; }  sub RDs_awarddetail     { return 3; }
 sub RDs_submission    { return 2; }  sub RDs_submission      { return 2; }
 sub RDs_timestamp     { return 1; }  sub RDs_timestamp       { return 1; }
 sub RDs_tries         { return 0; }  sub RDs_tries           { return 0; }
 sub RDs_awarded       { return 4; }  sub RDs_awarded         { return 4; }
   sub RDs_response_eval   { return 5; }
   sub RDs_response_eval_2 { return 6; }
   sub RDs_part_award      { return 7; }
   
 sub get_response_data_by_student {  sub get_response_data_by_student {
     my ($student,$symb,$response,$courseid) = @_;      my ($student,$symb,$response,$courseid) = @_;
     return undef if (! defined($symb) ||       return undef if (! defined($symb) || 
                      ! defined($response));                       ! defined($response));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $env{'request.course.id'} if (! defined($courseid));
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
     my $symb_id = &get_symb_id($symb);      my $symb_id = &get_symb_id($symb);
Line 2542  sub get_response_data_by_student { Line 2755  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 2583  sub RT_tries      { return 2; } Line 2797  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,$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));
     #      #
     &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 ($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 '.
         '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 '.
         'WHERE '.          'LEFT JOIN '.$student_table.' as d '.
           'ON a.student_id=d.student_id '.
           $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($students)) {      if (defined($student_requirements)) {
         $request .= ' AND ('.          $limit .= ' AND '.$student_requirements;
             join(' OR ', map {'a.student_id='.      }
                                   &get_student_id($_->{'username'},      if (defined($enrollment_requirements)) {
                                                   $_->{'domain'})          $limit .= ' AND '.$enrollment_requirements;
                               } @$students  
                  ).')';  
     }      }
     $request .= ' ORDER BY b.timestamp';      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 2631  sub get_response_time_data { Line 2860  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();
     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 2654  sub get_student_scores { Line 2886  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 ($groups_join,$group_limits) = &limit_by_group($groups,'b','d','e');
     if (defined($starttime)) {      my $time_requirements = &limit_by_start_end_time($starttime,$endtime,'a');
         $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($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 2743  Cleans up the package variables for loca Line 2963  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 2757  sub setup_table_names { Line 2977  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 2777  sub setup_table_names { Line 3001  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 2816  Retrieve the classist of a given class o Line 3042  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'
Line 2846  sub CL_TYPE     { return 8; } Line 3072  sub CL_TYPE     { return 8; }
 sub CL_LOCKEDTYPE   { return 9; }  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 2897  sub get_classlist { Line 3126  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 2908  sub get_classlist { Line 3140  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.141.2.2  
changed lines
  Added in v.1.175


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