# The LearningOnline Network with CAPA # (Publication Handler # # $Id: lonstatistics.pm,v 1.30 2002/07/24 14:52:32 stredwic Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # # (Navigate problems for statistical reports # YEAR=2001 # 5/5,7/9,7/25/1,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei # YEAR=2002 # 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26,4/7,5/6 Behrouz Minaei # 5/12,5/14,5/15,5/19,5/26,7/16 Behrouz Minaei # ### package Apache::lonstatistics; use strict; use Apache::Constants qw(:common :http); use Apache::lonnet(); use Apache::lonhomework; use Apache::loncommon; use Apache::loncoursedata; use Apache::lonhtmlcommon; use Apache::lonproblemanalysis; use Apache::lonproblemstatistics; use Apache::lonstudentassessment; use Apache::lonchart; use HTML::TokeParser; use GDBM_File; my $r; my %color; sub CheckFormElement { my ($cache, $ENVName, $cacheName, $default)=@_; if(defined($ENV{'form.'.$ENVName})) { $cache->{$cacheName} = $ENV{'form.'.$ENVName}; } elsif(!defined($cache->{$cacheName})) { $cache->{$cacheName} = $default; } return; } sub ProcessFormData{ my ($cache)=@_; $cache->{'reportKey'} = 'false'; &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['sort','download','reportSelected', 'StudentAssessmentStudent']); &CheckFormElement($cache, 'Status', 'Status', 'Active'); &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list'); &CheckFormElement($cache, 'reportSelected', 'reportSelected', 'Class list'); $cache->{'reportSelected'} = &Apache::lonnet::unescape($cache->{'reportSelected'}); &CheckFormElement($cache, 'DownloadAll', 'DownloadAll', 'false'); &CheckFormElement($cache, 'sort', 'sort', 'fullname'); &CheckFormElement($cache, 'download', 'download', 'false'); if(defined($ENV{'form.CreateStudentAssessment'}) || defined($ENV{'form.NextStudent'}) || defined($ENV{'form.PreviousStudent'})) { $cache->{'reportSelected'} = 'Student Assessment'; } if(defined($ENV{'form.NextStudent'})) { $cache->{'StudentAssessmentMove'} = 'next'; } elsif(defined($ENV{'form.PreviousStudent'})) { $cache->{'StudentAssessmentMove'} = 'previous'; } else { $cache->{'StudentAssessmentMove'} = 'selected'; } &CheckFormElement($cache, 'StudentAssessmentMap', 'StudentAssessmentMap', 'All Maps'); &CheckFormElement($cache, 'StudentAssessmentStudent', 'StudentAssessmentStudent', 'All Students'); $cache->{'StudentAssessmentStudent'} = &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'}); foreach (keys(%ENV)) { if(/form\.Analyze:::/) { # $cache->{'reportSelected'} = 'Analyze'; # $cache->{'reportKey'} = 'Problem Analysis'; my ($uri, $title, $part, $problem); (undef, $uri, $title, $part, $problem)=split(':::', $_); $cache->{'AnalyzeURI'} = $uri; $cache->{'AnalyzeTitle'} = $title; $cache->{'AnalyzePart'} = $part; $cache->{'AnalyzeProblem'} = $problem; &CheckFormElement($cache, 'Interval', 'Interval', '1'); } } return; # Select page to display if(defined($ENV{'form.ProblemStatistics'}) || defined($ENV{'form.ProblemStatisticsRecalculate'}) || defined($ENV{'form.DisplayCSVFormat'})) { $cache->{'GoToPage'} = 'ProblemStatistics'; &CheckFormElement($cache, 'DisplayCSVFormat', 'DisplayFormat', 'Display Table Format'); &CheckFormElement($cache, 'Ascend','ProblemStatisticsAscend', 'Ascending'); &CheckFormElement($cache, 'Maps', 'ProblemStatisticsMap', 'All Maps'); } elsif(defined($ENV{'form.ProblemAnalysis'})) { $cache->{'GoToPage'} = 'ProblemAnalysis'; &CheckFormElement($cache, 'Interval', 'Interval', '1'); } elsif(defined($ENV{'form.DoDiffGraph'})) { $cache->{'GoToPage'} = 'DoDiffGraph'; } elsif(defined($ENV{'form.PercentWrongGraph'})) { $cache->{'GoToPage'} = 'PercentWrongGraph'; } elsif(defined($ENV{'form.ActivityLog'})) { $cache->{'GoToPage'} = 'ActivityLog'; } else { $cache->{'GoToPage'} = 'Menu'; } &CheckFormElement($cache, 'Status', 'Status', 'Active'); return; } =pod =item &SortStudents() Determines which students to display and in which order. Which are displayed are determined by their status(active/expired). The order is determined by the sort button pressed (default to username). The type of sorting is username, lastname, or section. =over 4 Input: $students, $CacheData $students: A array pointer to a list of students (username:domain) $CacheData: A pointer to the hash tied to the cached data Output: \@order @order: An ordered list of students (username:domain) =back =cut sub SortStudents { my ($cache)=@_; my @students = split(':::',$cache->{'NamesOfStudents'}); my @sorted1Students=(); foreach (@students) { if($cache->{'Status'} eq 'Any' || $cache->{$_.':Status'} eq $cache->{'Status'}) { push(@sorted1Students, $_); } } my $sortBy = ''; if(defined($cache->{'sort'})) { $sortBy = ':'.$cache->{'sort'}; } my @order = sort { $cache->{$a.$sortBy} cmp $cache->{$b.$sortBy} || $cache->{$a.':fullname'} cmp $cache->{$b.':fullname'} } @sorted1Students; return \@order; } sub PrepareData { my ($c, $cacheDB)=@_; # Test for access to the cache data my $courseID=$ENV{'request.course.id'}; my $isRecalculate=0; if(defined($ENV{'form.Recalculate'})) { $isRecalculate=1; } my $isCached = &Apache::loncoursedata::TestCacheData($cacheDB, $isRecalculate); if($isCached < 0) { return "Unable to tie hash to db file."; } # Download class list information if not using cached data my %cache; unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) { return "Unable to tie hash to db file."; } if(!$isCached) { my $processTopResourceMapReturn= &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c); if($processTopResourceMapReturn ne 'OK') { untie(%cache); return $processTopResourceMapReturn; } } if($c->aborted()) { untie(%cache); return 'aborted'; } my $classlist=&Apache::loncoursedata::DownloadClasslist($courseID, $cache{'ClasslistTimestamp'}, $c); foreach (keys(%$classlist)) { if(/^(con_lost|error|no_such_host)/i) { untie(%cache); return "Error getting student data."; } } if($c->aborted()) { untie(%cache); return 'aborted'; } # Active is a temporary solution, remember to change Apache::loncoursedata::ProcessClasslist(\%cache,$classlist,$courseID,$c); if($c->aborted()) { untie(%cache); return 'aborted'; } &ProcessFormData(\%cache); my $students = &SortStudents(\%cache); if($cache{'download'} ne 'false') { my $who = $cache{'download'}; my $courseData = &Apache::loncoursedata::DownloadCourseInformation( $who, $courseID, $cache{$who.':lastDownloadTime'}); &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, $who); $cache{'download'} = 'false'; } elsif($cache{'DownloadAll'} ne 'false') { my @allStudents; if($cache{'DownloadAll'} eq 'sorted') { @allStudents = @$students; } else { @allStudents = split(':::', $cache{'NamesOfStudents'}); } foreach (@allStudents) { my $courseData = &Apache::loncoursedata::DownloadCourseInformation( $_, $courseID, $cache{$_.':lastDownloadTime'}); &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, $_); if($c->aborted()) { untie(%cache); return 'aborted'; } } $cache{'DownloadAll'} = 'false'; } if($c->aborted()) { untie(%cache); return 'aborted'; } if($c->aborted()) { untie(%cache); return 'aborted'; } untie(%cache); return ('OK', $students); } # Create progress sub Create_PrgWin { $r->print(< popwin=open('','popwin','width=400,height=100'); popwin.document.writeln(''+ 'LON-CAPA Statistics'+ '

Computation Progress

'+ '
'+ '
'+ ''); popwin.document.close(); ENDPOP $r->rflush(); } # update progress sub Update_PrgWin { my ($totalStudents,$index,$name)=@_; $r->print(''); $r->rflush(); } # close Progress Line sub Close_PrgWin { $r->print(''); $r->rflush(); } # For loading the colored table for display or un-colored for print sub setbgcolor { my $PrintTable=shift; undef %color; if ($PrintTable){ $color{"gb"}="#FFFFFF"; $color{"red"}="#FFFFFF"; $color{"yellow"}="#FFFFFF"; $color{"green"}="#FFFFFF"; $color{"purple"}="#FFFFFF"; } else { $color{"gb"}="#DDFFFF"; $color{"red"}="#FFDDDD"; $color{"yellow"}="#EEFFCC"; $color{"green"}="#DDFFDD"; $color{"purple"}="#FFDDFF"; } return; } sub BuildClasslist { my ($cacheDB,$students,$studentInformation,$headings,$spacePadding)=@_; my %cache; unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) { return 'Unable to tie database.'; } my $Str=''; $Str .= '
'."\n"; $Str .= ''."\n"; my $displayString = ''."\n"; $Str .= &Apache::lonhtmlcommon::CreateStudentInformationHeadings(\%cache, $studentInformation, $headings, $displayString); $Str .= ''."\n"; $Str .= ''."\n"; my $alternate=0; foreach (@$students) { my ($username, $domain) = split(':', $_); if($alternate) { $Str .= ''."\n"; } $Str .= '
DISPLAYDATA '; $Str .= ''; $Str .= 'Last Updated 
'; } else { $Str .= '
'; } $alternate = ($alternate + 1) % 2; foreach my $data (@$studentInformation) { if($data eq 'fullname') { $Str .= ''; #$Str .= 'Student Assessment'.'">'; } $Str .= $cache{$_.':'.$data}.' '; if($data eq 'fullname') { $Str .= ''; } $Str .= ''; } $Str .= ''; my $downloadTime = $cache{$_.':lastDownloadTime'}; if($downloadTime ne 'Not downloaded') { $downloadTime = localtime($downloadTime); } $Str .= $downloadTime; $Str .= ' 
'."\n"; untie(%cache); return $Str; } sub BuildStatistics { my ($r)=@_; my $c = $r->connection; my @studentInformation=('fullname','section','id','domain','username'); my @headings=('Full Name', 'Section', 'PID', 'Domain', 'User Name'); my $spacePadding = ' '; my %reports = ('classlist' => 'Class list', 'problem_statistics' => 'Problem Statistics', 'student_assessment' => 'Student Assessment', 'reportSelected' => 'Class list'); my %cache; my $courseID=$ENV{'request.course.id'}; my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}". "_$ENV{'user.domain'}_$courseID\_statistics.db"; &setbgcolor(0); my ($returnValue, $students) = &PrepareData($c, $cacheDB); if($returnValue ne 'OK') { $r->print(''.$returnValue."\n".''); return OK; } my $GoToPage; if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) { $GoToPage = $cache{'reportSelected'}; $reports{'reportSelected'} = $cache{'reportSelected'}; # if(defined($cache{'reportKey'}) && $cache{'reportKey'} ne 'false') { # $reports{$cache{'reportKey'}} = $cache{'reportSelected'}; # } if(defined($cache{'OptionResponses'})) { $reports{'problem_analysis'} = 'Problem Analysis'; } $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics')); $r->print('
print('method="post" action="/adm/statistics">'); $r->print(&Apache::lonhtmlcommon::CreateStatisticsMainMenu( $cache{'Status'}, \%reports)); untie(%cache); } else { $r->print('Unable to tie database.'); return OK; } if($GoToPage eq 'Activity Log') { &Apache::lonproblemstatistics::Activity(); } elsif($GoToPage eq 'Problem Statistics') { $r->print( &Apache::lonproblemstatistics::BuildProblemStatisticsPage($cacheDB, $students, $courseID, $c,$r)); } elsif($GoToPage eq 'Problem Analysis') { $r->print( &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB)); } elsif($GoToPage eq 'Student Assessment') { $r->print( &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB, $students, $courseID, $c)); } elsif($GoToPage eq 'Analyze') { $r->print(&Apache::lonproblemanalysis::BuildAnalyzePage($cacheDB, $students, $courseID)); } elsif($GoToPage eq 'DoDiffGraph') { &Apache::lonproblemstatistics::BuildDiffGraph($courseID); } elsif($GoToPage eq 'PercentWrongGraph') { &Apache::lonproblemstatistics::BuildWrongGraph($courseID); } elsif($GoToPage eq 'Class list') { $r->print(&BuildClasslist($cacheDB, $students, \@studentInformation, \@headings, $spacePadding)); } $r->print('
'."\n"); $r->print("\n".''."\n".''); $r->rflush(); return OK; } # ================================================================ Main Handler sub handler { $r=shift; unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) { $ENV{'user.error.msg'}= $r->uri.":vgr:0:0:Cannot view grades for complete course"; return HTTP_NOT_ACCEPTABLE; } # Set document type for header only if($r->header_only) { if ($ENV{'browser.mathml'}) { $r->content_type('text/xml'); } else { $r->content_type('text/html'); } &Apache::loncommon::no_cache($r); $r->send_http_header; return OK; } unless($ENV{'request.course.fn'}) { my $requrl=$r->uri; $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized"; return HTTP_NOT_ACCEPTABLE; } $r->content_type('text/html'); $r->send_http_header; &BuildStatistics($r); return OK; } 1; __END__