--- loncom/interface/lonstatistics.pm 2002/03/07 00:28:55 1.10 +++ loncom/interface/lonstatistics.pm 2002/08/14 16:18:55 1.44 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # (Publication Handler # -# $Id: lonstatistics.pm,v 1.10 2002/03/07 00:28:55 minaeibi Exp $ +# $Id: lonstatistics.pm,v 1.44 2002/08/14 16:18:55 stredwic Exp $ # # Copyright Michigan State University Board of Trustees # @@ -27,10 +27,12 @@ # # (Navigate problems for statistical reports # YEAR=2001 -# 5/05,7/09,7/25/01,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 +# 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 Behrouz Minaei +# 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,25/7,29/7 Behrouz Minaei +# ### package Apache::lonstatistics; @@ -39,1201 +41,596 @@ 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 HTML::TokeParser; use GDBM_File; -# -------------------------------------------------------------- Module Globals -my %hash; -my %CachData; -my %GraphDat; -my %maps; -my %mapsort; -my %section; -my %StuBox; -my %DiscFac; -my %DisUp; -my %DisLow; -my $UpCnt; -my $CurMap; -my $CurSec; -my $CurStu; -my @cols; -my @list; -my @students; -my $p_count; -my $Pos; -my $r; -my $OpSel1; -my $OpSel2; -my $OpSelDis1; -my $OpSelDis2; -my $OpSel3; -my $OpSel4; -my $GData; -my $cid; -my $firstres; -my $lastres; -my $DiscFlag; -my $HWN; -my $P_Order; -my %Header = (0,"Homework Sets Order",1,"#Stdnts",2,"Tries",3,"Mod", - 4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"DoDiff", - 9,"S.D.",10,"Skew.",11,"D.F.1st",12,"D.F.2nd"); - -#------- Processing upperlist and lowerlist according to each problem -sub ProcessDisc { - my @List = @_; - @List = sort (@List); - my $Count = $#List+1; - my $Prb; - my @Dis; - my $Slvd=0; - my $tmp; - my $Sum1=0; - my $Sum2=0; - my $nIdx=0; - my $nStud=0; - my %Proc; - undef %Proc; - while ($nIdx<$Count) { - ($Prb,$tmp)=split(/\=/,$List[$nIdx]); - @Dis=split(/\+/,$tmp); - my $Temp = $Prb; - do { - $nIdx++; - $nStud++; - $Sum1 += $Dis[0]; - $Sum2 += $Dis[1]; - ($Prb,$tmp)=split(/\=/,$List[$nIdx]); - @Dis=split(/\+/,$tmp); - } while ( $Prb eq $Temp && $nIdx < $Count ); -# $Proc{$Temp}=($Sum1/$nStud).':'.$nStud; - $Proc{$Temp}=($Sum1/$nStud).':'.($Sum2/$nStud); -# $r->print("$nIdx) $Temp --> ($nStud) $Proc{$Temp}
"); - $Sum1=0; - $Sum2=0; - $nStud=0; + +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', + 'ProblemStatisticsSort']); + &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'); + &CheckFormElement($cache, 'StatisticsMaps', + 'StatisticsMaps', 'All Maps'); + 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'})) { + $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, 'StudentAssessmentStudent', + 'StudentAssessmentStudent', 'All Students'); + $cache->{'StudentAssessmentStudent'} = + &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'}); + &CheckFormElement($cache, 'DefaultColumns', 'DefaultColumns', 'false'); + + # 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'); + + # 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 %Proc; -} + $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'; + } + + if(defined($ENV{'form.DoDiffGraph'})) { + $cache->{'reportSelected'} = 'DoDiffGraph'; + $cache->{'reportKey'} = 'DoDiffGraph'; + } elsif(defined($ENV{'form.PercentWrongGraph'})) { + $cache->{'reportSelected'} = 'PercentWrongGraph'; + $cache->{'reportKey'} = 'PercentWrongGraph'; + } + + 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; + } + } -#------- Creating Discimination factor -sub Discriminant { - my $Count=0; - foreach (keys(%DiscFac)){ - $Count++; - } - $UpCnt = int(0.27*$Count); - my $low=0; - my $up=$Count-$UpCnt; - my @UpList=(); - my @LowList=(); - $Count=0; - foreach my $key (sort(keys(%DiscFac))){ - $Count++; - #$r->print("
$Count) $key = $DiscFac{$key}"); - if ($low < $UpCnt || $Count > $up) { - $low++; - my $str=$DiscFac{$key}; - foreach(split(/\:/,$str)){ - if ($_) { - if ($low<$UpCnt){push(@LowList,$_);} - else {push(@UpList,$_);} - } - } - } + if($foundColumn) { + $cache->{'HeadingsFound'} = join(':', @headingColumns); + $cache->{'SequencesFound'} = join(':', @sequenceColumns);; } - %DisUp=&ProcessDisc(@UpList); - %DisLow=&ProcessDisc(@LowList); -} + 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'; - -sub NumericSort { - $a <=> $b; + return; } -# ------ Create different Student Report -sub StudentReport { +=pod - my ($sname,$sdom)=@_; +=item &SortStudents() - if ( $sname eq 'All Students' ) { - $r->print( '

WARNING: - Please select a student

' ); - return; - } - my $shome=&Apache::lonnet::homeserver($sname,$sdom); - my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname.':'.$cid,$shome ); - my %result = (); - my $ResId; - my $PrOrd; - my $Code; - my $Tries; - my $TotalTries = 0; - my $ParCr = 0; - my $Wrongs; - my %TempHash; - my $Version; - my $LatestVersion; - my $PtrTry=''; - my $PtrCod=''; - my $SetNo=0; - my $Str = "\n".''. - "\n".''. - "\n".''. - "\n".''. - "\n".''. - "\n".''. - "\n".''; - unless ($reply=~/^error\:/) { - foreach (split(/\&/,$reply)){ - my ($name,$value)=split(/\=/,&Apache::lonnet::unescape($_)); - $result{$name}=$value; - } - foreach my $CurCol (@cols) { - if (!$CurCol){ - my $Set=&Apache::lonnet::declutter($hash{'map_id_'.$1}); - if ( $Set ) { - $SetNo++; - $Str .= "\n"."". - "\n"."". - "\n"."". - "\n"."". - "\n"."". - "\n".""; - } - $PtrTry=''; - $PtrCod=''; - next; - } - ($PrOrd,$ResId)=split(/\:/,$CurCol); - $ResId=~/(\d+)\.(\d+)/; - my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} ); - if ( $CurMap ne 'All Maps' ) { - my ( $ResMap, $NameMap ) = split(/\=/,$CurMap); - if ( $Map ne $ResMap ) { next; } - } - my $meta=$hash{'src_'.$ResId}; - my $PartNo = 0; - undef %TempHash; - foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))){ - if ($_=~/^stores\_(\d+)\_tries$/) { - my $Part=&Apache::lonnet::metadata($meta,$_.'.part'); - if ( $TempHash{"$Part"} eq '' ) { - $TempHash{"$Part"} = $Part; - $TempHash{$PartNo}=$Part; - $TempHash{"$Part.Code"} = '-'; - $TempHash{"$Part.PrOrd"} = $PrOrd+$PartNo; - $PartNo++; - } - } - } +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. - my $Prob = $Map.'___'.$2.'___'. - &Apache::lonnet::declutter( $hash{'src_'.$ResId} ); - $Code='U'; - $Tries = 0; - $Wrongs = 0; - $LatestVersion = $result{"version:$Prob"}; - if ( $LatestVersion ) { - for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) { - my $vkeys = $result{"$Version:keys:$Prob"}; - my @keys = split(/\:/,$vkeys); - - foreach my $Key (@keys) { - if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) { - my $Part = $1; - $Tries = $result{"$Version:$Prob:resource.$Part.tries"}; - $TempHash{"$Part.Tries"} = ($Tries) ? $Tries : 0; - $TotalTries += $Tries; - my $Val = $result{"$Version:$Prob:resource.$Part.solved"}; - if ( $Val eq 'correct_by_student' ) - { $Wrongs = $Tries - 1; $Code = 'Y'; } - elsif ( $Val eq 'correct_by_override' ) - { $Wrongs = $Tries - 1; $Code = 'y'; } - elsif ( $Val eq 'incorrect_attempted' || - $Val eq 'incorrect_by_override' ) - { $Wrongs = $Tries; $Code = 'N'; } - $TempHash{"$Part.Code"} = $Code; - $TempHash{"$Part.Wrongs"} = $Wrongs; - } - } - } - for ( my $n = 0; $n < $PartNo; $n++ ) { - my $part = $TempHash{$n}; - if ($PtrTry ne '') {$PtrTry .= ',';} - $PtrTry .= "$TempHash{$part.'.Tries'}"; - $PtrCod .= "$TempHash{$part.'.Code'}"; - } - } - else { - for(my $n=0; $n<$PartNo; $n++) { - if ($PtrTry ne '') {$PtrTry .= ',';} - $PtrTry .= "0"; - $PtrCod .= "-"; - } - } - } - } - $Str .= "\n".'
# Set Title Results Tries
$SetNo $Set $PtrCod $PtrTry
'; - $r->print($Str); - $r->rflush(); -} +=over 4 -sub CreateTable { - my $ColNo=0; - foreach (keys(%Header)){ - $ColNo++; - } - my ($Hd, $Hid)=@_; - if ( $Hd == 1 ) { - $r->print('
'.$hash{'title_'.$Hid}.''); - } - my $Result = "\n".''; - $Result .= ''."\n"; - for ( my $nIdx=0; $nIdx < $ColNo; $nIdx++ ) { - $Result .= ''."\n"; - } - $Result .= "\n".''."\n"; - $r->print( $Result ); - $r->rflush(); -} +Input: $students, $CacheData -sub CloseTable { - $r->print("\n".'
P#'.''.'
'."\n"); - $r->rflush(); -} - -# ------------------------------------------- Prepare Statistics Table -sub PreStatTable { - my $CacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}". - "_$ENV{'user.domain'}_$cid\_statistics.db"; - my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}". - "_$ENV{'user.domain'}_$cid\_graph.db"; - my $OpSel11=''; - my $OpSel12=''; - my $OpSel13=''; - my $Status = $ENV{'form.status'}; - if ( $Status eq 'Any' ) { $OpSel13='selected'; } - elsif ($Status eq 'Expired' ) { $OpSel12 = 'selected'; } - else { $OpSel11 = 'selected'; } - - my $Ptr = ''; - $Ptr .= '
Student Status:   '."\n". - ' '."\n"; - $Ptr .= '   '; - $Ptr .= ''."\n"; - - $Ptr .= '
Sorting Type:   '."\n". - ' '."\n"; - $Ptr .= '   '; - $Ptr .= ''."\n"; - $Ptr .= '   '; - $Ptr .= ''."\n"; - - $Ptr .= '
'.
-    '  #Stdnts: Total Number of Students opened the problem.
'. - ' Tries : Total Number of Tries for solving the problem.
'. - ' Mod : Maximunm Number of Tries for solving the problem.
'. - ' Mean : Average Number of the tries. [ Tries / #Stdnts ]
'. - ' #YES : Number of students solved the problem correctly.
'. - ' #yes : Number of students solved the problem by override.
'. - ' %Wrng : Percentage of students tried to solve the problem but'. - ' still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]
'. -# ' DoDiff : Degree of Difficulty of the problem. [ Tries/(#YES+#yes+0.1) ]
'. Kashy formula - ' DoDiff : Degree of Difficulty of the problem. [ 1 - ((#YES+#yes) / Tries) ]
'. #Gerd formula - ' S.D. : Standard Deviation of the tries.'. - '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1)'. - ' where Xi denotes every student\'s tries ]
'. - ' Skew. : Skewness of the students tries.'. - ' [ (sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3) ]
'. - ' Dis.F. : Discrimination Factor: A Standard for '. - 'evaluating the problem according to a Criterion
'. - ' [Applied Criterion in %27 Upper Students - '. - 'Applied the same Criterion in %27 Lower Students]
'. - ' 1st Criterion for Sorting the Students: '. - 'Sum of Partial Credit Awarded / Total Number of Tries
'. - ' 2nd Criterion for Sorting the Students: '. - 'Total number of Correct Answers / Total Number of Tries'. - '
'; - - $r->print($Ptr); - $r->rflush(); - - if ((-e "$CacheDB")&&($ENV{'form.sort'} ne 'Recalculate Statistics')) { - if (tie(%CachData,'GDBM_File',"$CacheDB",&GDBM_READER,0640)) { - tie(%GraphDat,'GDBM_File',$GraphDB,&GDBM_WRCREAT,0640); - &Cache_Statistics(); - } - else { - $r->print("Unable to tie hash to db file"); +$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, $_); } } - else { - if (tie(%CachData,'GDBM_File',$CacheDB,&GDBM_WRCREAT,0640)) { - tie(%GraphDat,'GDBM_File',$GraphDB,&GDBM_WRCREAT,0640); - foreach (keys %DiscFac) {delete $CachData{$_};} - foreach (keys %CachData) {delete $CachData{$_};} - $DiscFlag=0; - &Build_Statistics(); - } - else { - $r->print("Unable to tie hash to db file"); - } + + my $sortBy = ''; + if(defined($cache->{'sort'})) { + $sortBy = ':'.$cache->{'sort'}; } - #$r->print('Total instances of the problems : '.($p_count*($#students+1))); + my @order = sort { $cache->{$a.$sortBy} cmp $cache->{$b.$sortBy} || + $cache->{$a.':fullname'} cmp $cache->{$b.':fullname'} } + @sorted1Students; - untie(%CachData); - untie(%GraphDat); + return \@order; } +=pod -# ------------------------------------- Find the section of student in a course +=item &SpaceColumns() -sub usection { - my ($udom,$unam,$courseid,$ActiveFlag)=@_; - $courseid=~s/\_/\//g; - $courseid=~s/^(\w)/\/$1/; - foreach (split(/\&/,&Apache::lonnet::reply('dump:'. - $udom.':'.$unam.':roles', - &Apache::lonnet::homeserver($unam,$udom)))){ - my ($key,$value)=split(/\=/,$_); - $key=&Apache::lonnet::unescape($key); - if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) { - my $section=$1; - if ($key eq $courseid.'_st') { $section=''; } - my ($dummy,$end,$start)=split(/\_/,&Apache::lonnet::unescape($value)); - if ( $ActiveFlag ne 'Any' ) { - my $now=time; - my $notactive=0; - if ($start) { - if ($now<$start) { $notactive=1; } - } - if ($end) { - if ($now>$end) { $notactive=1; } - } - if ((($ActiveFlag eq 'Expired') && $notactive == 1) || - (($ActiveFlag eq 'Active') && $notactive == 0 ) ) { - return $section; - } - else { return '-1'; } - } - return $section; - } - } - return '-1'; -} +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 -# ------ Dump the Student's DB file and handling the data for statistics table +Input: $students, $studentInformation, $headings, $ChartDB -sub ExtractStudentData { - my ($student,$coid)=@_; - my ($sname,$sdom) = split( /\:/, $student ); - my $shome=&Apache::lonnet::homeserver( $sname,$sdom ); - my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname.':'.$coid,$shome ); - my %result = (); - my $ResId; - my $PrOrd; - my $Dis = ''; - my $Code; - my $Tries; - my $ParCr; - my $TotalTries = 0; - my $TotalOpend = 0; - my $ProbSolved = 0; - my $ProbTot = 0; - my $TimeTot = 0; - my $TotParCr = 0; - my $Wrongs; - my %TempHash; - my $Version; - my $LatestVersion; - my $SecLimit; - my $MapLimit; - unless ($reply=~/^error\:/) { - foreach (split(/\&/,$reply)) { - my ($name,$value)=split(/\=/,&Apache::lonnet::unescape($_)); - $result{$name}=$value; - } - foreach my $CurCol(@cols) { - ($PrOrd,$ResId)=split(/\:/,$CurCol); - if ( !$CurCol ) { next; } - $ResId=~/(\d+)\.(\d+)/; - my $MapId=$1; - my $PrbId=$2; - my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$MapId} ); - if ( $CurMap ne 'All Maps' ) { - my ( $ResMap, $NameMap ) = split(/\=/,$CurMap); - if ( $Map ne $ResMap ) { next; } - } - my $meta=$hash{'src_'.$ResId}; - my $PartNo = 0; - $Dis .= ':'; - undef %TempHash; - foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) { - if ($_=~/^stores\_(\d+)\_tries$/) { - my $Part=&Apache::lonnet::metadata($meta,$_.'.part'); - if ( $TempHash{"$Part"} eq '' ) { - $TempHash{"$Part"} = $Part; - $TempHash{$PartNo}=$Part; - $TempHash{"$Part.Code"} = 'U'; - $TempHash{"$Part.PrOrd"} = $PrOrd+$PartNo; - $PartNo++; - } - } - } +$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 - my $Prob = $Map.'___'.$PrbId.'___'. - &Apache::lonnet::declutter( $hash{'src_'.$ResId} ); - $Code='U'; - $Tries = 0; - $ParCr = 0; - $Wrongs = 0; - $LatestVersion = $result{"version:$Prob"}; - - if ( $LatestVersion ) { - for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) { - my $vkeys = $result{"$Version:keys:$Prob"}; - my @keys = split(/\:/,$vkeys); - - foreach my $Key (@keys) { - if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) { - my $Part = $1; - $Tries = $result{"$Version:$Prob:resource.$Part.tries"}; - $ParCr = $result{"$Version:$Prob:resource.$Part.awarded"}; - my $Time = $result{"$Version:$Prob:timestamp"}; - $TempHash{"$Part.Time"} = ($Time) ? $Time : 0; - $TempHash{"$Part.Tries"} = ($Tries) ? $Tries : 0; - $TempHash{"$Part.ParCr"} = ($ParCr) ? $ParCr : 0; - $TotalTries += $TempHash{"$Part.Tries"}; - $TotParCr += $TempHash{"$Part.ParCr"}; - my $Val = $result{"$Version:$Prob:resource.$Part.solved"}; - if ( $Val eq 'correct_by_student' ) - { $Wrongs = $Tries - 1; $Code = 'C'; } - elsif ( $Val eq 'correct_by_override' ) - { $Wrongs = $Tries - 1; $Code = 'O'; } - elsif ( $Val eq 'incorrect_attempted' || - $Val eq 'incorrect_by_override' ) - { $Wrongs = $Tries; $Code = 'I'; } - $TempHash{"$Part.Code"} = $Code; - $TempHash{"$Part.Wrongs"} = $Wrongs; - } - } - } - for ( my $n = 0; $n < $PartNo; $n++ ) { - my $part = $TempHash{$n}; - my $Yes = 0; - if ( $TempHash{$part.'.Code'} eq 'C' || - $TempHash{$part.'.Code'} eq 'O' ) - {$ProbSolved++;$Yes=1;} - - # my $ptr = "$hash{'title_'.$ResId}"; - my $ptr = $TempHash{$part.'.PrOrd'}.':'.$ResId; - - if ( $PartNo > 1 ) { - $ptr .= "*(part $part)"; - $Dis .= ':'; - } - my $Fac = ($TempHash{"$part.Tries"}) ? - ($TempHash{"$part.ParCr"}/$TempHash{"$part.Tries"}) : 0; - my $DisF; - if ( $Fac > 0 && $Fac < 1 ) { - $DisF = sprintf( "%.4f", $Fac ); - } - else {$DisF = $Fac;} -# $DisF .= '+'.$TempHash{"$part.Time"}; - $TimeTot += $TempHash{"$part.Time"}; - $Dis .= $TempHash{$part.'.PrOrd'}.'='.$DisF.'+'.$Yes; - $ptr .= ":$TempHash{$part.'.Tries'}". - ":$TempHash{$part.'.Wrongs'}". - ":$TempHash{$part.'.Code'}"; - push (@list, $ptr); - $TotalOpend++; - $ProbTot++; - } +=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; } - #else { - #for(my $n=0; $n<$PartNo; $n++) { - # push (@list, "$hash{'title_'.$ResId}*$ResId:0:0:U"); - # $ProbTot++; - #} - #} } - if ( $TotalTries ) { - my $DisFac = ( $TotalTries ) ? ($TotParCr/$TotalTries) : 0; - my $DisFactor = sprintf( "%.4f", $DisFac ); - $DiscFac{$DisFactor}=$Dis; - #my $time; - #if ($ProbSolved){ - #$time = int(($TimeTot/$ProbSolved)-10000000); - #} - #$DiscFac{($DisFactor.':'.$sname.':'.$ProbTot.':'.$TotalOpend.':'. - # $TotalTries.':'.$ProbSolved.':'.$time)}=$Dis; - } } - #$r->print($sname.' PrCr= '.$TotParCr.' Slvd= '.$ProbSolved.' Tries='.$TotalTries.'
'); + + return; } +sub PrepareData { + my ($c, $cacheDB, $studentInformation, $headings,$r)=@_; -# ------------------------------------------------------------ Build page table -sub tracetable { - my ($rid,$beenhere)=@_; - $rid=~/(\d+)\.(\d+)/; - $maps{&Apache::lonnet::declutter($hash{'map_id_'.$1})}='';#$hash{'title_'.$rid}; - #$maps{$HWN}=$hash{'title_'.$rid}; - unless ($beenhere=~/\&$rid\&/) { - $beenhere.=$rid.'&'; - if (defined($hash{'is_map_'.$rid})) { - my $cmap=$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}}; - if ( $cmap eq 'sequence' || $cmap eq 'page' ) { - $cols[$#cols+1]=0; - $P_Order++; - $HWN=$P_Order; - $mapsort{$HWN} = $rid.':'; - #$maps{&Apache::lonnet::declutter($hash{'src_'.$rid})}= - # $hash{'title_'.$rid}; - } - if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) && - (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) { - my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}}; - - &tracetable($hash{'map_start_'.$hash{'src_'.$rid}}, - '&'.$frid.'&'); - - $cols[$#cols+1]=($P_Order+1).':'.$frid; - - my $meta=$hash{'src_'.$frid}; - my $PartNo = 0; - if ($meta) { - if ($meta=~/\.(problem|exam|quiz|assess|survey|form)$/) { - foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) { - if ($_=~/^stores\_(\d+)\_tries$/) { - &Apache::lonnet::metadata($meta,$_.'.part'); - $P_Order++; - $mapsort{$HWN} .= '&'.$P_Order; - $PartNo++; - $r->print('
'.$PartNo.'---'.$P_Order); - } - } - } - } - } - } else { - $cols[$#cols+1]=($P_Order+1).':'.$rid; - my $meta=$hash{'src_'.$rid}; - my $PartNo = 0; - if ($meta) { - if ($meta=~/\.(problem|exam|quiz|assess|survey|form)$/) { - foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) { - if ($_=~/^stores\_(\d+)\_tries$/) { - &Apache::lonnet::metadata($meta,$_.'.part'); - $P_Order++; - $mapsort{$HWN} .= '&'.$P_Order; - $PartNo++; - } - } - } - } - } - if (defined($hash{'to_'.$rid})) { - foreach (split(/\,/,$hash{'to_'.$rid})){ - &tracetable($hash{'goesto_'.$_},$beenhere); - } - } + # Test for access to the cache data + my $courseID=$ENV{'request.course.id'}; + my $isRecalculate=0; + if(defined($ENV{'form.Recalculate'})) { + $isRecalculate=1; } -} -sub MySort { - if ( $Pos > 0 ) { - if ($ENV{'form.order'} eq 'Descending') {$b <=> $a;} - else { $a <=> $b; } - } - else { - if ($ENV{'form.order'} eq 'Descending') {$b cmp $a;} - else { $a cmp $b; } + my $isCached = &Apache::loncoursedata::TestCacheData($cacheDB, + $isRecalculate); + if($isCached < 0) { + return "Unable to tie hash to db file."; } -} -sub Build_Statistics { - $r->print(< - popwin=open('','popwin','width=400,height=100'); - popwin.document.writeln(''+ - 'LON-CAPA Statistics'+ - '

Computation Progress

'+ - '
'+ - '
'+ - ''); - popwin.document.close(); - -ENDPOP + # 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."; + } - $r->rflush(); -# ---------------------------- Gathering the Data of students' tries - my $index; - for ($index=0;$index<=$#students;$index++) { -#----------- update progress - $r->print(''); - $r->rflush(); + if(!$isCached) { + my $processTopResourceMapReturn= + &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c, $r); + if($processTopResourceMapReturn ne 'OK') { + untie(%cache); + return $processTopResourceMapReturn; + } + } - &ExtractStudentData($students[$index],$cid); + if($c->aborted()) { + untie(%cache); + return 'aborted'; } -# -------------------- sorting the Data - $r->print(''); - - @list = sort (@list); - - - &Discriminant(); - - $OpSel2=''; - $OpSel1='selected'; - - $p_count = 0; - my $nIdx = 0; - my $dummy; - my $p_val; - my $ResId; - my $NoElements = $#list + 1; -#-------------------------------- loop for data representation - foreach (sort keys %mapsort) { - my ($Hid,$pr)=split(/\:/,$mapsort{$_}); - my @lpr=split(/\&/,$pr); - &CreateTable(1,$Hid); - for (my $i=1; $i<=$#lpr; $i++) { - my %storestats=(); - my ($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\:/,$list[$nIdx]); - my $Temp = $Prob; - my $MxTries = 0; - my $TotalTries = 0; - my $YES = 0; - my $Incorrect = 0; - my $Override = 0; - my $StdNo = 0; - my @StdLst; - while ( $PrOrd == $lpr[$i] ) - { - $nIdx++; - $StdNo++; - $StdLst[ $StdNo ] = $Tries; - $TotalTries += $Tries; - if ( $MxTries < $Tries ) { $MxTries = $Tries; } - if ( $Code eq 'C' ){ $YES++; } - elsif( $Code eq 'I' ) { $Incorrect++; } - elsif( $Code eq 'O' ) { $Override++; } - elsif( $Code eq 'U' ) { $StdNo--; } - ($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\:/,$list[$nIdx]); - } - - $p_count++; - my $Dummy; - ($ResId,$Dummy)=split(/\*/,$Temp); - - $Temp = ''.$hash{'title_'.$ResId}.$Dummy.''; - - my $res = &Apache::lonnet::declutter($hash{'src_'.$ResId}); - my $urlres=$res; - - $ResId=~/(\d+)\.(\d+)/; - my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} ); - $urlres=$Map; - - $res = ''.$res.''; - #$Map = ''.$res.''; - -#------------------------ Compute the Average of Tries about one problem - my $Average = ($StdNo) ? $TotalTries/$StdNo : 0; - - $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___timestamp'}=time; - $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___stdno'}=$StdNo; - $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___avetries'}=$Average; - -#-------------------------------- Compute percentage of Wrong tries - my $Wrong = ( $StdNo ) ? 100 * ( $Incorrect / $StdNo ) : 0; - -#-------------------------------- Compute Standard Deviation - my $StdDev = 0; - if ( $StdNo > 1 ) { - for ( my $n = 0; $n < $StdNo; $n++ ) { - my $Dif = $StdLst[ $n ]-$Average; - $StdDev += $Dif*$Dif; - } - $StdDev /= ( $StdNo - 1 ); - $StdDev = sqrt( $StdDev ); - } - -#-------------------------------- Compute Degree of Difficulty - my $DoDiff = 0; - if( $TotalTries > 0 ) { - $DoDiff = 1 - ( ( $YES + $Override ) / $TotalTries ); -# $DoDiff = ($TotalTries)/($YES + $Override+ 0.1); - } - - $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___difficulty'}=$DoDiff; - -#-------------------------------- Compute the Skewness - my $Skewness = 0; - my $Sum = 0; - if ( $StdNo > 0 && $StdDev > 0 ) { - for ( my $n = 0; $n < $StdNo; $n++ ) { - my $Dif = $StdLst[ $n ]-$Average; - $Skewness += $Dif*$Dif*$Dif; - } - $Skewness /= $StdNo; - $Skewness /= $StdDev*$StdDev*$StdDev; - } - -#--------------------- Compute the Discrimination Factors - my ($Up1,$Up2)=split(/\:/,$DisUp{$lpr[$i]}); - my ($Lw1,$Lw2)=split(/\:/,$DisLow{$lpr[$i]}); - my $Dis1 = $Up1 - $Lw1; - my $Dis2 = $Up2 - $Lw2; - my $_D1 = sprintf("%.2f", $Dis1); - my $_D2 = sprintf("%.2f", $Dis2); - -#----------------- Some restition in presenting the float numbers - my $Avg = sprintf( "%.2f", $Average ); - my $Wrng = sprintf( "%.1f", $Wrong ); - my $SD = sprintf( "%.1f", $StdDev ); - my $DoD = sprintf( "%.2f", $DoDiff ); - my $Sk = sprintf( "%.1f", $Skewness ); - my $join = $PrOrd.':'.$Temp.':'.$StdNo.':'. - $TotalTries.':'.$MxTries.':'.$Avg.':'. - $YES.':'.$Override.':'.$Wrng.':'.$DoD.':'. - $SD.':'.$Sk.':'.$_D1.':'.$_D2.':'.$Prob; - $CachData{($p_count-1)}=$join; - - $urlres=~/^(\w+)\/(\w+)/; - if ($StdNo) { - &Apache::lonnet::put('resevaldata',\%storestats,$1,$2); - } -#-------------------------------- Row of statistical table - if ( $DiscFlag == 0 ) { - &TableRow($join,$i,($p_count-1)); - } - } - &CloseTable(); - } -#--------------------- close Progress Line - $r->print(''); - $r->rflush(); -} + 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."; + } + } -sub Cache_Statistics { - my @list = (); - my $Useful; - my $UnUseful; - my %myHeader = reverse( %Header ); - $Pos = $myHeader{$ENV{'form.sort'}}; - if ($Pos > 0) {$Pos++;} - $p_count = 0; - foreach my $key( keys %CachData) { - my @Temp=split(/\:/,$CachData{$key}); - if ( $Pos == 0 ) { - ($UnUseful,$Useful)=split(/\>/,$Temp[$Pos]); - } - else { - $Useful = $Temp[$Pos]; - } - $list[$p_count]=$Useful.'&'.$CachData{$key}; - $p_count++; - } - - @list = sort MySort (@list); - - my $nIdx=0; - - if ( $Pos == 0 ) { - foreach (sort keys %mapsort) { - my ($Hid,$pr)=split(/\:/,$mapsort{$_}); - &CreateTable(1,$Hid); - my @lpr=split(/\&/,$pr); - for (my $i=1; $i<=$#lpr; $i++) { - my($Pre, $Post) = split(/\&/,$list[$nIdx]); - &TableRow($Post,$i,$nIdx); - $nIdx++; - } - &CloseTable(); - } - } - else { - &CreateTable(0); - for ( my $nIdx = 0; $nIdx < $p_count; $nIdx++ ) { - my($Pre, $Post) = split(/\&/,$list[$nIdx]); - &TableRow($Post,$nIdx,$nIdx); - } - &CloseTable(); + 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); + &SpaceColumns($students, $studentInformation, $headings, \%cache); + $cache{'updateTime:columnWidth'}=24; + + if($cache{'download'} ne 'false') { + my @who = ($cache{'download'}); + $cache{'download'} = 'false'; + if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false', + $cacheDB, 'true', + 'false', $courseID, + $r, $c) ne 'OK') { + untie(%cache); + return 'Stop at download individual'; + } + } elsif($cache{'DownloadAll'} ne 'false') { + $cache{'DownloadAll'} = 'false'; + my @allStudents; + if($cache{'DownloadAll'} eq 'sorted') { + @allStudents = @$students; + } else { + @allStudents = split(':::', $cache{'NamesOfStudents'}); + } + if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents, + 'false', + $cacheDB, 'true', + 'true', $courseID, + $r, $c) ne 'OK') { + untie(%cache); + return 'Stop at download all'; + } } -} -sub TableRow { - my ($Str,$Idx,$RealIdx)=@_; - my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES, - $Override,$Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$Prob)=split(/\:/,$Str); - $r->print( "\n".''. - "\n".''.($RealIdx+1).''. - "\n".''.$Temp.''. - "\n".' '.$StdNo.''. - "\n".''.$TotalTries.''. - "\n".''.$MxTries.''. - "\n".''.$Avg.''. - "\n".' '.$YES.''. - "\n".' '.$Override.''. - "\n".' '.$Wrng.''. - "\n".''.$DoD.''. - "\n".' '.$SD.''. - "\n".' '.$Sk.''. - "\n".' '.$_D1.''. - "\n".' '.$_D2.''. - "\n".'' ); - $GraphDat{$RealIdx}=$DoD.':'.$Wrng; -} + if($c->aborted()) { + untie(%cache); + return 'aborted'; + } -# ------------------------------------------- Prepare data for Graphical chart + untie(%cache); -sub GetGraphData { - my $Tag = shift; - my $Col; - my $data=''; - my $count = 0; - my $Max = 0; - my $cid=$ENV{'request.course.id'}; - my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}". - "_$ENV{'user.domain'}_$cid\_graph.db"; - foreach (keys %GraphDat) {delete $GraphDat{$_};} - if (-e "$GraphDB") { - if (tie(%GraphDat,'GDBM_File',"$GraphDB",&GDBM_READER,0640)) { - if ( $Tag eq 'DoDiff Graph' ) { - $Tag = 'Degree-of-Difficulty'; - $Col = 0; - } - else { - $Tag = 'Wrong-Percentage'; - $Col = 1; - } - foreach (sort NumericSort keys %GraphDat) { - my @Temp=split(/\:/,$GraphDat{$_}); - my $inf = $Temp[$Col]; - if ( $Max < $inf ) {$Max = $inf;} - $data .= $inf.','; - $count++; - } - untie(%GraphDat); - my $Course = $ENV{'course.'.$cid.'.description'}; - $Course =~ s/\ /"_"/eg; - $GData=$Course.'&'.$Tag.'&'.$Max.'&'.$count.'&'.$data; - - } - else { - $r->print("Unable to tie hash to db file"); - } - } + return ('OK', $students); } +sub BuildClasslist { + my ($cacheDB,$students,$studentInformation,$headings,$r)=@_; -sub initial { -# --------------------------------- Initialize the global varaibles - undef @students; - undef @cols; - undef %maps; - undef %section; - undef %StuBox; - undef @list; - undef %CachData; - undef %GraphDat; - undef %DiscFac; - undef $CurMap; - undef $CurSec; - undef $CurStu; - undef $p_count; - undef $Pos; - undef $GData; - $DiscFlag=0; - $P_Order=100000; - $HWN=$P_Order; -} + my %cache; + unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) { + return 'Unable to tie database.'; + } + my $Str=''; + $Str .= '
'."\n"; + $Str .= ''."\n"; -sub ClassList { + my $displayString = ''."\n"; + $Str .= &Apache::lonhtmlcommon::CreateHeadings(\%cache, + $studentInformation, + $headings, $displayString); + $Str .= ''."\n"; - &GetStatus(); + my $alternate=0; + foreach (@$students) { + my ($username, $domain) = split(':', $_); + if($alternate) { + $Str .= ''; + } else { + $Str .= ''; + } + $alternate = ($alternate + 1) % 2; + foreach my $data (@$studentInformation) { + $Str .= ''."\n"; + } } -# ------------------------------------------------------------- End render page - else { - $r->print('

Undefined course sequence

'); - } - &MapSecOptions(); -} + $Str .= ''."\n"; + $Str .= '
DISPLAYDATA 
'; + if($data eq 'fullname') { + $Str .= ''; + $Str .= $cache{$_.':'.$data}.' '; + $Str .= ''; + } elsif($data eq 'updateTime') { + $Str .= ''; + $Str .= $cache{$_.':'.$data}.' '; + $Str .= ' '; + } else { + $Str .= $cache{$_.':'.$data}.' '; + } - $cid=$ENV{'request.course.id'}; - my $chome=$ENV{'course.'.$cid.'.home'}; - my ($cdom,$cnum)=split(/\_/,$cid); -# ----------------------- Get first and last resource, see if there is anything - $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}}; - $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}}; - if (($firstres) && ($lastres)) { -# ----------------------------------------------------------------- Render page - my $classlst=&Apache::lonnet::reply - ('dump:'.$cdom.':'.$cnum.':classlist',$chome); - my $StudNo = 0; - my $now=time; - unless ($classlst=~/^error\:/) { - foreach (sort split(/\&/,$classlst)) { - my ($name,$value)=split(/\=/,$_); - my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value)); - $name=&Apache::lonnet::unescape($name); - my ($sname,$sdom)=split(/\:/,$name); - my $active=1; - my $Status=$ENV{'form.status'}; - $Status = ($Status) ? $Status : 'Active'; - if ( ( ($end) && $now > $end ) && - ( ($Status eq 'Active') ) ) { $active=0; } - if ( ($Status eq 'Expired') && - ($end == 0 || $now < $end) ) { $active=0; } - if ($active) { - my $thisindex=$#students+1; - $name=&Apache::lonnet::unescape($name); - $students[$thisindex]=$name; - my ($sname,$sdom)=split(/\:/,$name); - #my %reply=&Apache::lonnet::idrget($sdom,$sname); - #my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname. - # ':environment:lastname&generation&firstname&middlename', - # &Apache::lonnet::homeserver($sname,$sdom)); - my $ssec=&usection($sdom,$sname,$cid,$Status); - if ($ssec==-1) {next;} - $ssec=($ssec) ? $ssec : '(none)'; - #$ssec=(int($ssec)) ? int($ssec) : $ssec; - $section{$ssec}=$ssec; - if ($CurSec eq 'All Sections' || $ssec eq $CurSec) { - $students[$StudNo]=$name; - $StuBox{$sname}=$sdom; - } - $StudNo++; - } - } - } - else { - $r->print('

Could not access course data

'); - } - $r->print("Total number of students : ".($#students+1)); - $r->rflush(); -# --------------- Find all assessments and put them into some linear-like order - &tracetable($firstres,'&'.$lastres.'&'); -# my $c=0; -# foreach (sort keys %mapsort) { -# $r->print('
'.$c.')'.$_.' ... '.$mapsort{$_}); -# $c++; -# } + $Str .= '
'."\n"; + $r->print($Str); + $r->rflush(); + untie(%cache); -sub Menu { - my $InpStr = $ENV{'form.sort'}; - if ( $InpStr eq 'DoDiff Graph' || $InpStr eq '%Wrong Graph' ) { - &GetGraphData($InpStr); - $r->print(''); - } - else { - $r->print('LON-CAPA Statistics'); - - - $r->print(''. - ''. - ''); -# ---------------------------------------------------------------- Course title - $r->print('

Course : "'. - $ENV{'course.'.$ENV{'request.course.id'}. - '.description'}.'"

'.localtime().'

'); -# ------------------------------- This is going to take a while, produce output - $r->rflush(); - - $r->print("\n".'
'); - - my $content = $ENV{'form.sort'}; - if ($content eq '' || $content eq 'Return to Menu') { - my $Ptr = '

'; - $Ptr .= ''; - $Ptr .= '

'; - $Ptr .= ''; - $Ptr .= '

'; - $r->print( $Ptr ); - } - else { - &initial(); - &ClassList(); - if ( $content eq 'Student Assessment' || - $content eq 'Create Student Report' ) { - &StudentOptions(); - &StudentReport($CurStu,$StuBox{"$CurStu"}); - } - else { - &PreStatTable(); - } - } - $r->print("\n".'
'. - "\n".''. - "\n".''); - $r->rflush(); - } + return; } -sub StudentOptions { - my $OpSel5=''; - $CurStu = $ENV{'form.student'}; - if ( $CurStu eq '' ) { - $CurStu = 'All Students'; - $OpSel5 = 'selected'; - } - my $Ptr =''; -# ----------------------------------- Loading the Students Combobox - $Ptr .= '
Select Student'."\n". - ''; - $Ptr .= '
'; - $r->print( $Ptr ); - $r->rflush(); -} +sub CreateMainMenu { + my ($status, $reports)=@_; -sub GetStatus { - $OpSel1=''; - $OpSel2=''; - $OpSel3=''; - $OpSel4=''; - - if ( $ENV{'form.order'} eq 'Descending' ) { $OpSel2='selected'; } - else { $OpSel1 = 'selected'; } - - my %myHeader = reverse( %Header ); - $Pos = $myHeader{$ENV{'form.sort'}}; - if ($Pos == 0) { - $OpSel1 = 'selected'; - $ENV{'form.order'}='Ascendig'; - } - - $CurMap = $ENV{'form.maps'}; - if ( $CurMap eq '' ) { - $CurMap = 'All Maps'; - $OpSel3 = 'selected'; - } - $CurSec = $ENV{'form.section'}; - if ( $CurSec eq '' ) { - $CurSec = 'All Sections'; - $OpSel4 = 'selected'; + 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; +} + +sub BuildStatistics { + my ($r)=@_; + + my $c = $r->connection; + 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', +# 'activitylog' => 'Activity Log', + '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"; + + $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics')); + + my ($returnValue, $students) = &PrepareData($c, $cacheDB, + \@studentInformation, + \@headings,$r); + if($returnValue ne 'OK') { + $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)) { + $GoToPage = $cache{'reportSelected'}; + $reports{'reportSelected'} = $cache{'reportSelected'}; + if(defined($cache{'reportKey'}) && + !exists($reports{$cache{'reportKey'}}) && + $cache{'reportKey'} ne 'false') { + $reports{$cache{'reportKey'}} = $cache{'reportSelected'}; + } -sub MapSecOptions { -# ----------------------------------- Loading the Maps Combobox - my $Ptr = '
'; - $Ptr .= '
'; - $Ptr .= '
Select   Map     '."\n". - ''; - $Ptr .= '   '; - -# ----------------------------------- Loading the Sections Combobox - $Ptr .= '
Select Section'."\n". - ''."\n"; - $r->print( $Ptr ); + $r->print(''."\n"); + $r->print("\n".''."\n".''); $r->rflush(); -} + return OK; +} # ================================================================ Main Handler sub handler { - $r=shift; - - if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) { -# ------------------------------------------- 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'); - } - $r->send_http_header; - return OK; - } - my $requrl=$r->uri; -# ----------------------------------------------------------------- Tie db file + my $r=shift; - undef %hash; +# $jr = $r; - if ($ENV{'request.course.fn'}) { - my $fn=$ENV{'request.course.fn'}; - if (-e "$fn.db") { - if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) { -# ------------------------------------------------------------------- Hash tied - $r->content_type('text/html'); - $r->send_http_header; - &Menu(); - } - else { - $r->content_type('text/html'); - $r->send_http_header; - $r->print('Coursemap undefined.'); - } -# ------------------------------------------------------------------ Untie hash - unless (untie(%hash)) { - &Apache::lonnet::logthis("WARNING: ". - "Could not untie coursemap $fn (browse)."); - } - -# -------------------------------------------------------------------- All done - return OK; -# ----------------------------------------------- Errors, hash could no be tied - } - } - else { - $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized"; - return HTTP_NOT_ACCEPTABLE; - } - } - else { + 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__ - - 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.