--- loncom/interface/loncoursedata.pm 2005/03/03 18:57:36 1.144 +++ loncom/interface/loncoursedata.pm 2006/04/08 06:51:47 1.158 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: loncoursedata.pm,v 1.144 2005/03/03 18:57:36 matthew Exp $ +# $Id: loncoursedata.pm,v 1.158 2006/04/08 06:51:47 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -49,8 +49,7 @@ Set of functions that download and proce package Apache::loncoursedata; use strict; -use Apache::Constants qw(:common :http); -use Apache::lonnet(); +use Apache::lonnet; use Apache::lonhtmlcommon; use Time::HiRes; use Apache::lonmysql; @@ -66,30 +65,6 @@ and/or itself. =cut -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; -} - ################################################ ################################################ @@ -645,7 +620,7 @@ Returns: nothing ################################################ sub delete_caches { my $courseid = shift; - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + $courseid = $env{'request.course.id'} if (! defined($courseid)); # &setup_table_names($courseid); # @@ -861,7 +836,7 @@ sub get_student { sub populate_student_table { my ($courseid) = @_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # &setup_table_names($courseid); @@ -869,7 +844,9 @@ sub populate_student_table { my $dbh = &Apache::lonmysql::get_dbh(); my $request = 'INSERT IGNORE INTO '.$student_table. "(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; while (my ($student,$data) = each %$classlist) { my ($section,$status) = ($data->[&CL_SECTION()], @@ -971,7 +948,7 @@ sub update_full_student_data { # # Download students data 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/) { $returnstatus = 'error retrieving full student data'; return $returnstatus; @@ -1214,7 +1191,7 @@ sub update_student_data { # # Set the students update time if ($Results[0] eq 'okay') { - &store_updatetime($student_id,$time_of_retrieval,$time_of_retrieval); + &store_updatetime($student_id,$time_of_retrieval); } # return @Results; @@ -1270,23 +1247,29 @@ sub store_student_data { # make sure the symb is set up properly my $symb_id = &get_symb_id($current_symb); # - # Load data into the tables + # Parameters while (my ($parameter,$value) = each(%$param_hash)) { - my $newstring; if ($parameter !~ /(timestamp|resource\.(.*)\.(solved|tries|awarded|award|awarddetail|previous))/) { - $newstring = "('".join("','", - $symb_id,$student_id, - $parameter)."',". - $dbh->quote($value)."),\n"; + my $sql_parameter = "('".join("','", + $symb_id,$student_id, + $parameter)."',". + $dbh->quote($value)."),\n"; $num_parameters ++; - if ($newstring !~ /''/) { - $store_parameters_command .= $newstring; - $rows_stored++; + if ($sql_parameter !~ /''/) { + $store_parameters_command .= $sql_parameter; + #$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; + next if ($part =~ /\./); + next if (exists($stored{$part})); + $stored{$part}++; + # my $part_id = &get_part_id($part); next if (!defined($part_id)); my $solved = $value; @@ -1301,29 +1284,31 @@ sub store_student_data { $awarded = '' if (! defined($awarded)); $award = '' if (! defined($award)); $awarddetail = '' if (! defined($awarddetail)); - $newstring = "('".join("','",$symb_id,$student_id,$part_id,$part, - $solved,$tries,$awarded,$award, - $awarddetail,$timestamp)."'),\n"; - $store_performance_command .= $newstring; + my $sql_performance = + "('".join("','",$symb_id,$student_id,$part_id,$part, + $solved,$tries,$awarded,$award, + $awarddetail,$timestamp)."'),\n"; + $store_performance_command .= $sql_performance; $rows_stored++; } } - chop $store_parameters_command; - chop $store_parameters_command; - chop $store_performance_command; - chop $store_performance_command; + if (! $rows_stored) { return ($returnstatus, undef); } + $store_parameters_command =~ s|,\n$||; + $store_performance_command =~ s|,\n$||; my $start = Time::HiRes::time; $dbh->do($store_performance_command); if ($dbh->err()) { - &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); - &Apache::lonnet::logthis('command = '.$store_performance_command); + &Apache::lonnet::logthis('performance bigass insert error:'. + $dbh->errstr()); + &Apache::lonnet::logthis('command = '.$/.$store_performance_command); $returnstatus = 'error: unable to insert performance into database'; return ($returnstatus,$student_data); } $dbh->do($store_parameters_command) if ($num_parameters>0); if ($dbh->err()) { - &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr()); - &Apache::lonnet::logthis('command = '.$store_parameters_command); + &Apache::lonnet::logthis('parameters bigass insert error:'. + $dbh->errstr()); + &Apache::lonnet::logthis('command = '.$/.$store_parameters_command); &Apache::lonnet::logthis('rows_stored = '.$rows_stored); &Apache::lonnet::logthis('student_id = '.$student_id); $returnstatus = 'error: unable to insert parameters into database'; @@ -1351,7 +1336,7 @@ Returns nothing on success and 'error' o ###################################### sub ensure_tables_are_set_up { my ($courseid) = @_; - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + $courseid = $env{'request.course.id'} if (! defined($courseid)); # # Clean out package variables &setup_table_names($courseid); @@ -1408,7 +1393,7 @@ sub ensure_current_data { my ($sname,$sdom,$courseid) = @_; 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); # # Get the update time for the user @@ -1457,7 +1442,7 @@ sub ensure_current_full_data { my ($sname,$sdom,$courseid) = @_; 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); # # Get the update time for the user @@ -1633,7 +1618,7 @@ an empty list is returned. sub get_current_state { 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)); # @@ -1736,7 +1721,7 @@ able to answer it correctly. sub get_problem_statistics { my ($Sections,$status,$symb,$part,$courseid,$starttime,$endtime) = @_; 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); my $symb_id = &get_symb_id($symb); @@ -1863,6 +1848,9 @@ sub execute_SQL_request { my ($dbh,$request)=@_; # &Apache::lonnet::logthis($request); my $sth = $dbh->prepare($request); + if (!$sth) { + die($dbh->errstr . " SQL: $request"); + } $sth->execute(); my $row = $sth->fetchrow_arrayref(); if (ref($row) eq 'ARRAY' && scalar(@$row)>0) { @@ -1885,7 +1873,7 @@ sub execute_SQL_request { sub populate_weight_table { my ($courseid) = @_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # &setup_table_names($courseid); @@ -2020,9 +2008,17 @@ Inputs: $Sections: array ref of sections to include, $enrollment: string, $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 -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 @@ -2032,10 +2028,10 @@ sub RNK_student { return 0; }; sub RNK_score { return 1; }; sub rank_students_by_scores_on_resources { - my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime) = @_; + my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime,$has_award_for) = @_; return if (! defined($resources) || ! ref($resources) eq 'ARRAY'); if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # &setup_table_names($courseid); @@ -2045,12 +2041,20 @@ sub rank_students_by_scores_on_resources my $symb_limits = '('.join(' OR ',map {'a.symb_id='.&get_symb_id($_); } @$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 $request = 'SELECT b.student,SUM(a.awarded*w.weight) AS score FROM '. - $performance_table.' AS a '. - 'NATURAL LEFT JOIN '.$weight_table.' AS w '. - 'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '. - 'WHERE '; + my $request = "SELECT b.student,SUM(a.awarded*w.weight) AS score " + ."$award_col FROM $performance_table AS a ". + "NATURAL LEFT JOIN $weight_table AS w ". + "LEFT JOIN $student_table AS b ON a.student_id=b.student_id ". + "$award_join WHERE "; if (defined($section_limits)) { $request .= $section_limits.' AND '; } @@ -2065,9 +2069,9 @@ sub rank_students_by_scores_on_resources } $request =~ s/( AND )$//; # Remove extra conjunction $request =~ s/( WHERE )$//; # In case there were no limits placed on it - $request .= ' GROUP BY a.student_id ORDER BY score'; + $request .= " $award_clause GROUP BY a.student_id ORDER BY score"; #&Apache::lonnet::logthis('request = '.$/.$request); - my $sth = $dbh->prepare($request); + my $sth = $dbh->prepare($request) or die "Can't prepare $request"; $sth->execute(); my $rows = $sth->fetchall_arrayref(); return ($rows); @@ -2095,7 +2099,7 @@ Returns: the sum of the score on the pro sub get_sum_of_scores { my ($symb,$part,$students,$courseid,$starttime,$endtime) = @_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } if (defined($students) && ((@$students == 0) || @@ -2159,7 +2163,7 @@ Returns: minimum, maximum, mean, s.d., n sub score_stats { my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # &setup_table_names($courseid); @@ -2202,7 +2206,7 @@ sub score_stats { # &Apache::lonnet::logthis('request = '.$/.$request); $request = 'SELECT SUM(weight) FROM '.$weight_table. - ' WHERE ('.$symb_restriction.')'; + ' AS a WHERE ('.$symb_restriction.')'; my ($max_possible) = &execute_SQL_request($dbh,$request); # &Apache::lonnet::logthis('request = '.$/.$request); return($min,$max,$ave,$std,$count,$max_possible); @@ -2233,7 +2237,7 @@ Returns: minimum, maximum, mean, s.d., a sub count_stats { my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # &setup_table_names($courseid); @@ -2251,11 +2255,10 @@ sub count_stats { $request = 'CREATE TEMPORARY TABLE '.$stats_table.' '. 'SELECT a.student_id,'. - 'COUNT(a.award) AS count FROM '. + 'SUM(a.awarded) AS count FROM '. $performance_table.' AS a '. 'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '. - 'WHERE ('.$symb_restriction.')'. - " AND a.award!='INCORRECT_ATTEMPTED'"; + 'WHERE ('.$symb_restriction.')'; if ($time_limits) { $request .= ' AND '.$time_limits; } @@ -2290,7 +2293,7 @@ sub count_stats { ###################################################### sub get_student_data { my ($students,$courseid) = @_; - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + $courseid = $env{'request.course.id'} if (! defined($courseid)); &setup_table_names($courseid); my $dbh = &Apache::lonmysql::get_dbh(); return undef if (! defined($dbh)); @@ -2331,7 +2334,7 @@ sub get_response_data { my ($Sections,$enrollment,$symb,$response,$courseid) = @_; return undef if (! defined($symb) || ! defined($response)); - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + $courseid = $env{'request.course.id'} if (! defined($courseid)); # &setup_table_names($courseid); my $symb_id = &get_symb_id($symb); @@ -2404,7 +2407,7 @@ sub get_response_data_by_student { my ($student,$symb,$response,$courseid) = @_; return undef if (! defined($symb) || ! defined($response)); - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + $courseid = $env{'request.course.id'} if (! defined($courseid)); # &setup_table_names($courseid); my $symb_id = &get_symb_id($symb); @@ -2460,7 +2463,7 @@ sub get_response_time_data { my ($sections,$enrollment,$symb,$part,$courseid) = @_; return undef 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); my $symb_id = &get_symb_id($symb); @@ -2526,12 +2529,15 @@ sub get_response_time_data { ################################################ ################################################ sub get_student_scores { - my ($Sections,$Symbs,$enrollment,$courseid,$starttime,$endtime) = @_; - $courseid = $ENV{'request.course.id'} if (! defined($courseid)); + my ($sections,$Symbs,$enrollment,$courseid,$starttime,$endtime) = @_; + $courseid = $env{'request.course.id'} if (! defined($courseid)); &setup_table_names($courseid); my $dbh = &Apache::lonmysql::get_dbh(); return (undef) if (! defined($dbh)); my $tmptable = $courseid.'_temp_'.time; + my $request = 'DROP TABLE IF EXISTS '.$tmptable; +# &Apache::lonnet::logthis('request = '.$/.$request); + $dbh->do($request); # my $symb_requirements; if (defined($Symbs) && @$Symbs) { @@ -2542,34 +2548,17 @@ sub get_student_scores { } @$Symbs).')'; } # - my $student_requirements; - if ( (defined($Sections) && $Sections->[0] ne 'all')) { - $student_requirements = '('. - join(' OR ', map { "b.section='".$_."'" } @$Sections - ).')'; - } - # - my $enrollment_requirements=undef; - if (defined($enrollment) && $enrollment ne 'Any') { - $enrollment_requirements = "b.status='".$enrollment."'"; - } + my ($student_requirements,$enrollment_requirements) = + &limit_by_section_and_status($sections,$enrollment,'b'); # - my $time_requirements = undef; - if (defined($starttime)) { - $time_requirements .= "a.timestamp>='".$starttime."'"; - if (defined($endtime)) { - $time_requirements .= " AND a.timestamp<='".$endtime."'"; - } - } elsif (defined($endtime)) { - $time_requirements .= "a.timestamp<='".$endtime."'"; - } + my $time_requirements = &limit_by_start_end_time($starttime,$endtime,'a'); ## - ## - my $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable. - ' SELECT a.student_id,SUM(a.awarded) AS score FROM '. + $request = 'CREATE TEMPORARY TABLE IF NOT EXISTS '.$tmptable. + ' SELECT a.student_id,SUM(a.awarded*c.weight) AS score FROM '. $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)) { - $request .= ' NATURAL LEFT JOIN '.$student_table.' AS b '; + $request .= ' LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id'; } if (defined($symb_requirements) || defined($student_requirements) || @@ -2631,7 +2620,7 @@ Cleans up the package variables for loca sub setup_table_names { my ($courseid) = @_; if (! defined($courseid)) { - $courseid = $ENV{'request.course.id'}; + $courseid = $env{'request.course.id'}; } # if (! defined($current_course) || $current_course ne $courseid) { @@ -2704,10 +2693,10 @@ Retrieve the classist of a given class o information is returned from the classlist.db file and, if needed, from the students environment. -Optional arguments are $cid, $cdom, and $cnum (course id, course domain, -and course number, respectively). Any omitted arguments will be taken -from the current environment ($ENV{'request.course.id'}, -$ENV{'course.'.$cid.'.domain'}, and $ENV{'course.'.$cid.'.num'}). +Optional arguments are $cdom, and $cnum (course domain, +and course number, respectively). If either is ommitted the course +will be taken from the current environment ($env{'request.course.id'}, +$env{'course.'.$cid.'.domain'}, and $env{'course.'.$cid.'.num'}). Returns a reference to a hash which contains: keys '$sname:$sdom' @@ -2734,10 +2723,13 @@ sub CL_TYPE { return 8; } sub CL_LOCKEDTYPE { return 9; } sub get_classlist { - my ($cid,$cdom,$cnum) = @_; - $cid = $cid || $ENV{'request.course.id'}; - $cdom = $cdom || $ENV{'course.'.$cid.'.domain'}; - $cnum = $cnum || $ENV{'course.'.$cid.'.num'}; + my ($cdom,$cnum) = @_; + 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 $now = time; # my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);