Diff for /loncom/interface/loncoursedata.pm between versions 1.162 and 1.174

version 1.162, 2006/04/28 21:51:35 version 1.174, 2006/08/08 19:02:04
Line 51  package Apache::loncoursedata; Line 51  package Apache::loncoursedata;
 use strict;  use strict;
 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 74  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 84  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 159  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 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 369  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 602  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 873  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 900  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$/);
 }  }
   
 ################################################  ################################################
Line 947  sub update_full_student_data { Line 1139  sub update_full_student_data {
     &setup_table_names($courseid);      &setup_table_names($courseid);
     #      #
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
       my @group_ids = &get_students_groupids($student_id);
     my $student = $sname.':'.$sdom;      my $student = $sname.':'.$sdom;
     #      #
     my $returnstatus = 'okay';      my $returnstatus = 'okay';
Line 993  sub update_full_student_data { Line 1186  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 1176  sub update_student_data { Line 1422  sub update_student_data {
     &setup_table_names($courseid);      &setup_table_names($courseid);
     #      #
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
       my @group_ids = &get_students_groupids($student_id);
     my $student = $sname.':'.$sdom;      my $student = $sname.':'.$sdom;
     #      #
     my $returnstatus = 'okay';      my $returnstatus = 'okay';
Line 1227  sub store_student_data { Line 1474  sub store_student_data {
     my ($sname,$sdom,$courseid,$student_data) = @_;      my ($sname,$sdom,$courseid,$student_data) = @_;
     #      #
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
       my @group_ids = &get_students_groupids($student_id);
     my $student = $sname.':'.$sdom;      my $student = $sname.':'.$sdom;
     #      #
     my $returnstatus = 'okay';      my $returnstatus = 'okay';
Line 1292  sub store_student_data { Line 1540  sub store_student_data {
             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 1357  sub ensure_tables_are_set_up { Line 1609  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 1417  sub ensure_current_data { Line 1671  sub ensure_current_data {
          $Apache::lonnet::perlvar{'lonUsersDir'});           $Apache::lonnet::perlvar{'lonUsersDir'});
     #      #
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
       my @group_ids = &get_students_groupids($student_id);
     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;
Line 1465  sub ensure_current_full_data { Line 1720  sub ensure_current_full_data {
          $Apache::lonnet::perlvar{'lonUsersDir'});           $Apache::lonnet::perlvar{'lonUsersDir'});
     #      #
     my $student_id = &get_student_id($sname,$sdom);      my $student_id = &get_student_id($sname,$sdom);
       my @group_ids = &get_students_groupids($student_id);
     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 $updatetime;      my $updatetime;
Line 1680  populated and all local caching variable Line 1936  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 1733  able to answer it correctly. Line 1993  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 1757  sub get_problem_statistics { Line 2017  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 1782  sub get_problem_statistics { Line 2046  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 2002  sub limit_by_section_and_status { Line 2270  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 2012  sub limit_by_section_and_status { Line 2279  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 2020  sub limit_by_section_and_status { Line 2322  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 2042  sub RNK_student { return 0; }; Line 2345  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 2052  sub rank_students_by_scores_on_resources Line 2356  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 2068  sub rank_students_by_scores_on_resources Line 2373  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 ';
     }      }
     $request =~ s/( AND )$//;   # Remove extra conjunction      if (defined($group_limits)) {
     $request =~ s/( WHERE )$//; # In case there were no limits placed on it          $limits .= $group_limits.' AND ';
       }
       if ($limits) {
           $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 2175  Returns: minimum, maximum, mean, s.d., n Line 2486  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 2185  sub score_stats { Line 2496  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 2199  sub score_stats { Line 2511  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 2234  sub score_stats { Line 2550  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 2249  Returns: minimum, maximum, mean, s.d., a Line 2565  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 2259  sub count_stats { Line 2575  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 2272  sub count_stats { Line 2589  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 2346  sub RD_tries           { return 6; } Line 2667  sub RD_tries           { return 6; }
 sub RD_sname           { return 7; }  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 2368  sub get_response_data { Line 2689  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.response_specific_value_2, a.submission, b.timestamp, '.          'a.response_specific_value_2, a.submission, b.timestamp, '.
Line 2381  sub get_response_data { Line 2703  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 2434  sub get_response_data_by_student { Line 2756  sub get_response_data_by_student {
     #      #
     my $student_id = &get_student_id($student->{'username'},      my $student_id = &get_student_id($student->{'username'},
                                      $student->{'domain'});                                       $student->{'domain'});
       my @group_ids = &get_students_groupids($student_id);
     #      #
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
Line 2480  sub RT_tries      { return 2; } Line 2803  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 2501  sub get_response_time_data { Line 2824  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 2509  sub get_response_time_data { Line 2833  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)) {
         }          $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 2542  sub get_response_time_data { Line 2866  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 2571  sub get_student_scores { Line 2895  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 2578  sub get_student_scores { Line 2903  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($symb_requirements)      ||       if (defined($groups_join)) {
         defined($student_requirements)   ||          $request .= $groups_join;
         defined($enrollment_requirements) ) {      }
       if (defined($symb_requirements)       || 
           defined($student_requirements)    ||
           defined($enrollment_requirements) ||
           defined($group_limits) ) {
         $request .= ' WHERE ';          $request .= ' WHERE ';
     }      }
     if (defined($symb_requirements)) {      if (defined($symb_requirements)) {
Line 2654  sub setup_table_names { Line 2983  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 2674  sub setup_table_names { Line 3007  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 2797  sub get_classlist { Line 3132  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 2808  sub get_classlist { Line 3146  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.162  
changed lines
  Added in v.1.174


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