--- loncom/interface/lonstatistics.pm 2002/07/24 14:52:32 1.30 +++ loncom/interface/lonstatistics.pm 2002/10/22 16:30:34 1.53 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # (Publication Handler # -# $Id: lonstatistics.pm,v 1.30 2002/07/24 14:52:32 stredwic Exp $ +# $Id: lonstatistics.pm,v 1.53 2002/10/22 16:30:34 minaeibi Exp $ # # Copyright Michigan State University Board of Trustees # @@ -31,7 +31,7 @@ # 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 +# 5/12,5/14,5/15,5/19,5/26,7/16,25/7,29/7 Behrouz Minaei # ### @@ -47,12 +47,10 @@ use Apache::lonhtmlcommon; use Apache::lonproblemanalysis; use Apache::lonproblemstatistics; use Apache::lonstudentassessment; -use Apache::lonchart; +use Apache::lonpercentage; use HTML::TokeParser; use GDBM_File; -my $r; -my %color; sub CheckFormElement { my ($cache, $ENVName, $cacheName, $default)=@_; @@ -72,8 +70,10 @@ sub ProcessFormData{ $cache->{'reportKey'} = 'false'; &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['sort','download','reportSelected', - 'StudentAssessmentStudent']); + ['sort','download', + 'reportSelected', + 'StudentAssessmentStudent', + 'ProblemStatisticsSort']); &CheckFormElement($cache, 'Status', 'Status', 'Active'); &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list'); &CheckFormElement($cache, 'reportSelected', 'reportSelected', @@ -83,7 +83,22 @@ sub ProcessFormData{ &CheckFormElement($cache, 'DownloadAll', 'DownloadAll', 'false'); &CheckFormElement($cache, 'sort', 'sort', 'fullname'); &CheckFormElement($cache, 'download', 'download', 'false'); + &CheckFormElement($cache, 'StatisticsMaps', + 'StatisticsMaps', 'All Maps'); + &CheckFormElement($cache, 'StatisticsProblemSelect', + 'StatisticsProblemSelect', 'All Problems'); + &CheckFormElement($cache, 'StatisticsPartSelect', + 'StatisticsPartSelect', 'All Parts'); + if(defined($ENV{'form.Section'})) { + my @sectionsSelected = (ref($ENV{'form.Section'}) ? + @{$ENV{'form.Section'}} : + ($ENV{'form.Section'})); + $cache->{'sectionsSelected'} = join(':', @sectionsSelected); + } elsif(!defined($cache->{'sectionsSelected'})) { + $cache->{'sectionsSelected'} = $cache->{'sectionList'}; + } + # student assessment if(defined($ENV{'form.CreateStudentAssessment'}) || defined($ENV{'form.NextStudent'}) || defined($ENV{'form.PreviousStudent'})) { @@ -96,55 +111,96 @@ sub ProcessFormData{ } else { $cache->{'StudentAssessmentMove'} = 'selected'; } - &CheckFormElement($cache, 'StudentAssessmentMap', 'StudentAssessmentMap', - 'All Maps'); &CheckFormElement($cache, 'StudentAssessmentStudent', 'StudentAssessmentStudent', 'All Students'); $cache->{'StudentAssessmentStudent'} = &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'}); + &CheckFormElement($cache, 'DefaultColumns', 'DefaultColumns', 'false'); - 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'); + # Problem analysis + &CheckFormElement($cache, 'Interval', 'Interval', '1'); + + # ProblemStatistcs + &CheckFormElement($cache, 'DisplayCSVFormat', + 'DisplayFormat', 'Display Table Format'); + &CheckFormElement($cache, 'ProblemStatisticsAscend', + 'ProblemStatisticsAscend', 'Ascending'); + &CheckFormElement($cache, 'ProblemStatisticsSort', + 'ProblemStatisticsSort', 'Homework Sets Order'); + &CheckFormElement($cache, 'DisplayLegend', 'DisplayLegend', + 'Hide Legend'); + &CheckFormElement($cache, 'SortProblems', 'SortProblems', + 'Sort Within Sequence'); + + # Search only form elements + my @headingColumns=(); + my @sequenceColumns=(); + my $foundColumn = 0; + if(defined($ENV{'form.ReselectColumns'})) { + my @reselected = (ref($ENV{'form.ReselectColumns'}) ? + @{$ENV{'form.ReselectColumns'}} + : ($ENV{'form.ReselectColumns'})); + foreach (@reselected) { + if(/HeadingColumn/) { + push(@headingColumns, $_); + $foundColumn = 1; + } elsif(/SequenceColumn/) { + push(@sequenceColumns, $_); + $foundColumn = 1; + } } } - return; + $cache->{'reportKey'} = 'false'; + if($cache->{'reportSelected'} eq 'Analyze') { + $cache->{'reportKey'} = 'Analyze'; + } elsif($cache->{'reportSelected'} eq 'DoDiffGraph') { + $cache->{'reportKey'} = 'DoDiffGraph'; + } elsif($cache->{'reportSelected'} eq 'PercentWrongGraph') { + $cache->{'reportKey'} = 'PercentWrongGraph'; + } - # 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'; + if(defined($ENV{'form.DoDiffGraph'})) { + $cache->{'reportSelected'} = 'DoDiffGraph'; + $cache->{'reportKey'} = 'DoDiffGraph'; } elsif(defined($ENV{'form.PercentWrongGraph'})) { - $cache->{'GoToPage'} = 'PercentWrongGraph'; - } elsif(defined($ENV{'form.ActivityLog'})) { - $cache->{'GoToPage'} = 'ActivityLog'; - } else { - $cache->{'GoToPage'} = 'Menu'; + $cache->{'reportSelected'} = 'PercentWrongGraph'; + $cache->{'reportKey'} = 'PercentWrongGraph'; } - &CheckFormElement($cache, 'Status', 'Status', 'Active'); + foreach (keys(%ENV)) { + if(/form\.Analyze/) { + $cache->{'reportSelected'} = 'Analyze'; + $cache->{'reportKey'} = 'Analyze'; + my $data; + (undef, $data)=split(':::', $_); + $cache->{'AnalyzeInfo'}=$data; + } elsif(/form\.HeadingColumn/) { + my $value = $_; + $value =~ s/form\.//; + push(@headingColumns, $value); + $foundColumn=1; + } elsif(/form\.SequenceColumn/) { + my $value = $_; + $value =~ s/form\.//; + push(@sequenceColumns, $value); + $foundColumn=1; + } + } + + if($foundColumn) { + $cache->{'HeadingsFound'} = join(':', @headingColumns); + $cache->{'SequencesFound'} = join(':', @sequenceColumns);; + } + if(!defined($cache->{'HeadingsFound'}) || + $cache->{'DefaultColumns'} ne 'false') { + $cache->{'HeadingsFound'}='HeadingColumnFull Name'; + } + if(!defined($cache->{'SequencesFound'}) || + $cache->{'DefaultColumns'} ne 'false') { + $cache->{'SequencesFound'}='All Sequences'; + } + $cache->{'DefaultColumns'} = 'false'; return; } @@ -197,8 +253,57 @@ sub SortStudents { return \@order; } +=pod + +=item &SpaceColumns() + +Determines the width of all the columns in the chart. It is based on +the max of the data for that column and its header. + +=over 4 + +Input: $students, $studentInformation, $headings, $ChartDB + +$students: An array pointer to a list of students (username:domain) + +$studentInformatin: The type of data for the student information. It is +used as part of the key in $CacheData. + +$headings: The name of the student information columns. + +$ChartDB: The name of the cache database which is opened for read/write. + +Output: None - All data stored in cache. + +=back + +=cut + +sub SpaceColumns { + my ($students,$studentInformation,$headings,$cache)=@_; + + # Initialize Lengths + for(my $index=0; $index<(scalar @$headings); $index++) { + my @titleLength=split(//,$headings->[$index]); + $cache->{$studentInformation->[$index].':columnWidth'}= + scalar @titleLength; + } + + foreach my $name (@$students) { + foreach (@$studentInformation) { + my @dataLength=split(//,$cache->{$name.':'.$_}); + my $length=(scalar @dataLength); + if($length > $cache->{$_.':columnWidth'}) { + $cache->{$_.':columnWidth'}=$length; + } + } + } + + return; +} + sub PrepareData { - my ($c, $cacheDB)=@_; + my ($c, $cacheDB, $studentInformation, $headings,$r)=@_; # Test for access to the cache data my $courseID=$ENV{'request.course.id'}; @@ -215,18 +320,18 @@ sub PrepareData { # Download class list information if not using cached data my %cache; - unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) { + unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) { return "Unable to tie hash to db file."; } - if(!$isCached) { +# if(!$isCached) { my $processTopResourceMapReturn= &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c); if($processTopResourceMapReturn ne 'OK') { untie(%cache); return $processTopResourceMapReturn; } - } + # } if($c->aborted()) { untie(%cache); @@ -257,111 +362,51 @@ sub PrepareData { &ProcessFormData(\%cache); my $students = &SortStudents(\%cache); + &SpaceColumns($students, $studentInformation, $headings, \%cache); + $cache{'updateTime:columnWidth'}=24; - 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); + my $download = $cache{'download'}; + my $downloadAll = $cache{'DownloadAll'}; + my @allStudents=(); + if($download ne 'false') { $cache{'download'} = 'false'; - } elsif($cache{'DownloadAll'} ne 'false') { - my @allStudents; - if($cache{'DownloadAll'} eq 'sorted') { + } elsif($downloadAll ne 'false') { + $cache{'DownloadAll'} = 'false'; + if($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"; + if($download ne 'false') { + my @who = ($download); + if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false', + $cacheDB, 'true', + 'false', $courseID, + $r, $c) ne 'OK') { + return 'Stop at download individual'; + } + } elsif($downloadAll ne 'false') { + if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents, + 'false', + $cacheDB, 'true', + 'true', $courseID, + $r, $c) ne 'OK') { + return 'Stop at download all'; + } } - return; + return ('OK', $students); } sub BuildClasslist { - my ($cacheDB,$students,$studentInformation,$headings,$spacePadding)=@_; + my ($cacheDB,$students,$studentInformation,$headings,$r)=@_; my %cache; - unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) { + unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) { return 'Unable to tie database.'; } @@ -371,55 +416,88 @@ sub BuildClasslist { my $displayString = 'DISPLAYDATA '."\n"; - $Str .= &Apache::lonhtmlcommon::CreateStudentInformationHeadings(\%cache, - $studentInformation, - $headings, - $displayString); - $Str .= ''; - $Str .= ''; - $Str .= 'Last Updated '."\n"; + $Str .= &Apache::lonhtmlcommon::CreateHeadings(\%cache, + $studentInformation, + $headings, $displayString); $Str .= ''."\n"; + my $alternate=0; foreach (@$students) { my ($username, $domain) = split(':', $_); if($alternate) { - $Str .= ''; + $Str .= ''; } else { - $Str .= ''; + $Str .= ''; } $alternate = ($alternate + 1) % 2; foreach my $data (@$studentInformation) { + $Str .= ''; if($data eq 'fullname') { $Str .= ''; - #$Str .= 'Student Assessment'.'">'; - } - - $Str .= $cache{$_.':'.$data}.' '; - - if($data eq 'fullname') { + $Str .= $cache{$_.':'.$data}.' '; $Str .= ''; + } elsif($data eq 'updateTime') { + $Str .= ''; + $Str .= $cache{$_.':'.$data}.' '; + $Str .= ' '; + } else { + $Str .= $cache{$_.':'.$data}.' '; } - $Str .= ''; - } - - $Str .= ''; - my $downloadTime = $cache{$_.':lastDownloadTime'}; - if($downloadTime ne 'Not downloaded') { - $downloadTime = localtime($downloadTime); + $Str .= ''."\n"; } - $Str .= $downloadTime; - - $Str .= ' '."\n"; } + $Str .= ''."\n"; $Str .= ''."\n"; + $r->print($Str); + $r->rflush(); untie(%cache); + return; +} + +sub CreateMainMenu { + my ($status, $reports)=@_; + + my $Str = ''; + + $Str .= ''."\n"; + $Str .= ''."\n"; + $Str .= ''."\n"; + $Str .= ''."\n"; + $Str .= ''."\n"; + $Str .= ''."\n"; + + $Str .= ''."\n"; + + $Str .= '
Analysis Reports:Student Status:
{'reportSelected'} eq $reports->{$_}) { + $Str .= ' selected=""'; + } + $Str .= '>'.$reports->{$_}.''."\n"; + } + $Str .= ''; + $Str .= &Apache::lonhtmlcommon::StatusOptions($status, 'Statistics'); + $Str .= '
'."\n"; + $Str .= '
'."\n"; + return $Str; } @@ -427,12 +505,17 @@ 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 @studentInformation=('fullname','section','id','domain','username', + 'updateTime'); + my @headings=('Full Name', 'Section', 'PID', 'Domain', 'User Name', + 'Last Updated'); + my $spacing = ' '; + my %reports = ('classlist' => 'Class list', 'problem_statistics' => 'Problem Statistics', 'student_assessment' => 'Student Assessment', + 'percentage' => 'Percentage Graphs', +# 'activitylog' => 'Activity Log', 'reportSelected' => 'Class list'); my %cache; @@ -440,31 +523,40 @@ sub BuildStatistics { my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}". "_$ENV{'user.domain'}_$courseID\_statistics.db"; - &setbgcolor(0); - my ($returnValue, $students) = &PrepareData($c, $cacheDB); + $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts')); + + my ($returnValue, $students) = &PrepareData($c, $cacheDB, + \@studentInformation, + \@headings,$r); if($returnValue ne 'OK') { - $r->print(''.$returnValue."\n".''); + $r->print($returnValue."\n".''); return OK; } + if(!$c->aborted()) { + &Apache::loncoursedata::CheckForResidualDownload($cacheDB, + 'true', 'true', + $courseID, + $r, $c); + } my $GoToPage; - if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) { + 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{'reportKey'}) && + !exists($reports{$cache{'reportKey'}}) && + $cache{'reportKey'} ne 'false') { + $reports{$cache{'reportKey'}} = $cache{'reportSelected'}; + } if(defined($cache{'OptionResponses'})) { - $reports{'problem_analysis'} = 'Problem Analysis'; + $reports{'problem_analysis'} = 'Option Response 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)); + $r->print(&CreateMainMenu($cache{'Status'}, \%reports)); + $r->rflush(); untie(%cache); } else { $r->print('Unable to tie database.'); @@ -474,31 +566,37 @@ sub BuildStatistics { 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)); + $c,$r); + } elsif($GoToPage eq 'Option Response Analysis') { + &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB, $r); } elsif($GoToPage eq 'Student Assessment') { - $r->print( - &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB, - $students, - $courseID, - $c)); + &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB, + $students, + $courseID, + 'Statistics', + \@headings, + $spacing, + \@studentInformation, + $r, $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); + &Apache::lonproblemanalysis::BuildAnalyzePage($cacheDB, $students, + $courseID, $r); + } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') { + my $courseDescription = $ENV{'course.'.$courseID.'.description'}; + $courseDescription =~ s/\ /"_"/eg; + &Apache::lonproblemstatistics::BuildGraphicChart($GoToPage, $cacheDB, + $courseDescription, + $students, $courseID, + $r, $c); } elsif($GoToPage eq 'Class list') { - $r->print(&BuildClasslist($cacheDB, $students, \@studentInformation, - \@headings, $spacePadding)); + &BuildClasslist($cacheDB, $students, \@studentInformation, + \@headings, $r); + } elsif($GoToPage eq 'Percentage Graphs') { + &Apache::lonpercentage::BuildPercentageGraph($cacheDB, $students, + $courseID, $c, $r); } $r->print('
'."\n"); @@ -511,7 +609,16 @@ sub BuildStatistics { # ================================================================ Main Handler sub handler { - $r=shift; + my $r=shift; + +# $jr = $r; + + my $loaderror=&Apache::lonnet::overloaderror($r); + if ($loaderror) { return $loaderror; } + $loaderror= + &Apache::lonnet::overloaderror($r, + $ENV{'course.'.$ENV{'request.course.id'}.'.home'}); + if ($loaderror) { return $loaderror; } unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) { $ENV{'user.error.msg'}= @@ -546,3 +653,4 @@ sub handler { } 1; __END__ +