--- loncom/interface/lonstatistics.pm 2003/02/28 21:19:53 1.62 +++ loncom/interface/lonstatistics.pm 2003/06/20 18:50:17 1.78 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonstatistics.pm,v 1.62 2003/02/28 21:19:53 matthew Exp $ +# $Id: lonstatistics.pm,v 1.78 2003/06/20 18:50:17 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -51,8 +51,7 @@ Main handler for statistics and chart. use Apache::lonproblemstatistics; use Apache::lonstudentassessment; use Apache::lonpercentage; - use GDBM_File; - + use Apache::lonmysql; =over 4 =cut @@ -83,8 +82,8 @@ use Apache::lonproblemanalysis(); use Apache::lonproblemstatistics(); use Apache::lonstudentassessment(); use Apache::lonpercentage; -use GDBM_File; - +use Apache::lonmysql; +use Time::HiRes; ####################################################### ####################################################### @@ -207,7 +206,6 @@ upon the calling context. ####################################################### ####################################################### sub PrepareClasslist { - my $r = shift; my %Sections; &clear_classlist_variables(); # @@ -231,16 +229,23 @@ sub PrepareClasslist { } } # + # Deal with instructors with restricted section access + if ($ENV{'request.course.sec'} !~ /^\s*$/) { + @SelectedSections = ($ENV{'request.course.sec'}); + } + # # Set up %StudentData @StudentDataOrder = qw/fullname username domain id section status/; foreach my $field (@StudentDataOrder) { $StudentData{$field}->{'title'} = $field; - $StudentData{$field}->{'base_width'} = - scalar (my @Tmp = split(//,$field)); + $StudentData{$field}->{'base_width'} = length($field); $StudentData{$field}->{'width'} = $StudentData{$field}->{'base_width'}; } - + # + # get the status requested + my $requested_status = 'Active'; + $requested_status = $ENV{'form.Status'} if (exists($ENV{'form.Status'})); # # Process the classlist while (my ($student,$student_data) = each (%$classlist)) { @@ -251,7 +256,7 @@ sub PrepareClasslist { $studenthash->{$field}=$student_data->[$i]; # Keep track of the width of the fields next if (! exists($StudentData{$field})); - my $length = scalar(my @Tmp1 = split(//,$student_data->[$i])); + my $length = length($student_data->[$i]); if ($StudentData{$field}->{'width'} < $length) { $StudentData{$field}->{'width'} = $length; } @@ -268,7 +273,11 @@ sub PrepareClasslist { # # Only put in the list those students we are interested in foreach my $sect (@SelectedSections) { - if (($sect eq 'all') || ($section eq $sect)) { + if ( (($sect eq 'all') || + ($section eq $sect)) && + (($studenthash->{'status'} eq $requested_status) || + ($requested_status eq 'Any')) + ){ push (@Students,$studenthash); last; } @@ -276,8 +285,12 @@ sub PrepareClasslist { } # # Put the consolidated section data in the right place - @Sections = sort {$a cmp $b} keys(%Sections); - unshift(@Sections,'all'); # Put 'all' at the front of the list + if ($ENV{'request.course.sec'} !~ /^\s*$/) { + @Sections = ($ENV{'request.course.sec'}); + } else { + @Sections = sort {$a cmp $b} keys(%Sections); + unshift(@Sections,'all'); # Put 'all' at the front of the list + } # # Sort the Students my $sortby = 'fullname'; @@ -287,9 +300,10 @@ sub PrepareClasslist { @Students = @TmpStudents; # # Now deal with that current student thing.... - if (exists($ENV{'form.StudentAssessmentStudent'})) { + $curr_student = undef; + if (exists($ENV{'form.SelectedStudent'})) { my ($current_uname,$current_dom) = - split(':',$ENV{'form.StudentAssessmentStudent'}); + split(':',$ENV{'form.SelectedStudent'}); my $i; for ($i = 0; $i<=$#Students; $i++) { next if (($Students[$i]->{'username'} ne $current_uname) || @@ -297,15 +311,17 @@ sub PrepareClasslist { $curr_student = $Students[$i]; last; # If we get here, we have our student. } - if ($i == 0) { - $prev_student = 'none'; - } else { - $prev_student = $Students[$i-1]; - } - if ($i == $#Students) { - $next_student = 'none'; - } else { - $next_student = $Students[$i+1]; + if (defined($curr_student)) { + if ($i == 0) { + $prev_student = undef; + } else { + $prev_student = $Students[$i-1]; + } + if ($i == $#Students) { + $next_student = undef; + } else { + $next_student = $Students[$i+1]; + } } } # @@ -316,7 +332,7 @@ sub PrepareClasslist { @SelectedStudentData = ($ENV{'form.StudentData'}); } } else { - @SelectedStudentData = ('fullname'); + @SelectedStudentData = ('username'); } foreach (@SelectedStudentData) { if ($_ eq 'all') { @@ -328,6 +344,27 @@ sub PrepareClasslist { return; } + +####################################################### +####################################################### + +=pod + +=item get_students + +Returns a list of the selected students + +=cut + +####################################################### +####################################################### +sub get_students { + if (! @Students) { + &PrepareClasslist() + } + return @Students; +} + ####################################################### ####################################################### @@ -343,11 +380,7 @@ selected student. ####################################################### ####################################################### sub current_student { - if (defined($curr_student)) { - return $curr_student; - } else { - return 'All Students'; - } + return $curr_student; } ####################################################### @@ -365,11 +398,7 @@ in the list of students. Or something. ####################################################### ####################################################### sub previous_student { - if (defined($prev_student)) { - return $prev_student; - } else { - return 'No Student Selected'; - } + return $prev_student; } ####################################################### @@ -387,11 +416,7 @@ to be viewed. ####################################################### ####################################################### sub next_student { - if (defined($next_student)) { - return $next_student; - } else { - return 'No Student Selected'; - } + return $next_student; } ####################################################### @@ -437,6 +462,33 @@ sub SetSelectedMaps { } } + +####################################################### +####################################################### + +=pod + +=item &Sequences_with_Assess() + +Returns an array containing the subset of @Sequences which contain +assessments. + +=cut + +####################################################### +####################################################### +sub Sequences_with_Assess { + my @Sequences_to_Show; + foreach my $map_symb (@SelectedMaps) { + foreach my $sequence (@Sequences) { + next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all'); + next if ($sequence->{'num_assess'} < 1); + push (@Sequences_to_Show,$sequence); + } + } + return @Sequences_to_Show; +} + ####################################################### ####################################################### @@ -464,13 +516,11 @@ sub PrepareCourseData { # # Compute column widths foreach my $seq (@Sequences) { - my $name_length = scalar(my @Tmp1 = split(//,$seq->{'title'})); + my $name_length = length($seq->{'title'}); my $num_parts = $seq->{'num_assess_parts'}; # - # The number of columns needed for the summation text: - # " 1/5" = 1+3 columns, " 10/99" = 1+5 columns - my $sum_length = 1+1+2*(scalar(my @Tmp2 = split(//,$num_parts))); - my $num_col = $num_parts+$sum_length; + # Use 3 digits for each the sum and total, which means 7 total... + my $num_col = $num_parts+7; if ($num_col < $name_length) { $num_col = $name_length; } @@ -698,6 +748,7 @@ sub MapSelect { Returns html for a selection box allowing the user to choose one (or more) of the sections in the course. +Uses the package variables @Sections and @SelectedSections =over 4 =item $elementname The name of the HTML form element @@ -706,13 +757,6 @@ of the sections in the course. =item $numvisible The number of options to be visible -=item $selected Array ref to the names of the already selected sections. -If undef, $ENV{'form.'.$elementname} is used. -If $ENV{'form.'.$elementname} is also empty, none will be selected. - -=item $restriction Code reference to subroutine which returns true or -false. The code must expect a reference to a sequence data structure. - =back =cut @@ -725,6 +769,11 @@ sub SectionSelect { return; } # + # Make sure we have the data we need to continue + if (! @Sections) { + &PrepareClasslist() + } + # # Build the form element my $Str = "\n"; $Str .= '{'reportSelected'} eq $reports->{$_}) { - $Str .= ' selected=""'; - } - $Str .= '>'.$reports->{$_}.''."\n"; - } - $Str .= ''."\n"; - - $Str .= ''; - $Str .= &Apache::lonhtmlcommon::StatusOptions($status, 'Statistics'); - $Str .= ''."\n"; - - $Str .= ''."\n"; - $Str .= '
'."\n"; - + # + $Str = ''; +# $Str .= ''."\n"; +# $Str .= ''."\n"; +# $Str .= ''."\n"; +# # +# $Str .= ''; +# $Str .= '\n"; +# $Str .= '
Report:'; +# $Str .= ''.(' 'x30).''. +# ''. +# "
'."\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', - 'percentage' => 'Correct-problems Plot', -# '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('Course Statistics and Charts')); - - 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'}; - } - - if(defined($cache{'OptionResponses'})) { - $reports{'problem_analysis'} = 'Option Response Analysis'; - } - - $r->print('
print('method="post" action="/adm/statistics">'); - $r->print(&CreateMainMenu($cache{'Status'}, \%reports)); - $r->rflush(); - untie(%cache); - } else { - $r->print('Unable to tie database.'); - return OK; - } - - if($GoToPage eq 'Activity Log') { - &Apache::lonproblemstatistics::Activity(); - } elsif($GoToPage eq 'Problem Statistics') { - &Apache::lonproblemstatistics::BuildProblemStatisticsPage($cacheDB, - $students, - $courseID, - $c,$r); - } elsif($GoToPage eq 'Option Response Analysis') { - &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB, $r); - } elsif($GoToPage eq 'Student Assessment') { - &Apache::lonstudentassessment::BuildStudentAssessmentPage($r, $c); - } elsif($GoToPage eq 'Analyze') { - &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') { - &DisplayClasslist($r); -# &BuildClasslist($cacheDB, $students, \@studentInformation, -# \@headings, $r); - } elsif($GoToPage eq 'Correct-problems Plot') { - &Apache::lonpercentage::BuildPercentageGraph($cacheDB, $students, - $courseID, $c, $r); - } - - $r->print('
'."\n"); - $r->print("\n".''."\n".''); - $r->rflush(); - - return OK; -} - -# ================================================================ Main Handler - +############################################## +############################################## sub handler { my $r=shift; - -# $jr = $r; - + my $c = $r->connection(); + # + # Check for overloading 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'})) { + # + # Check for access + if (! &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; + $r->uri.":vgr:0:0:Cannot view grades for complete course"; + if (! &Apache::lonnet::allowed('vgr', + $ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) { + $ENV{'user.error.msg'}= + $r->uri.":vgr:0:0:Cannot view grades with given role"; + return HTTP_NOT_ACCEPTABLE; + } } - + # # Set document type for header only if($r->header_only) { if ($ENV{'browser.mathml'}) { @@ -1414,35 +957,99 @@ sub handler { $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; - } - + # + # Send the header $r->content_type('text/html'); $r->send_http_header; - + # + # Extract form elements from query string &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['sort', - 'StudentAssessmentStudent']); - - &PrepareClasslist($r); - + ['sort','reportSelected', + 'SelectedStudent']); + if (! exists($ENV{'form.reportSelected'})) { + $ENV{'form.reportSelected'} = 'student_assessment'; + } + # + # Give the LON-CAPA page header + $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts')); + $r->rflush(); + # + if (! &Apache::lonmysql::verify_sql_connection()) { + my $serveradmin = $r->dir_config('lonAdmEMail'); + $r->print(<Unable to connect to database! +

+Please notify the server administrator $serveradmin. +

+Course Statistics and Charts cannot be retrieved until the database is +restarted. Your data is intact but cannot be displayed at this time. +

+ + +END + return; + } + # + # Clean out the caches + if (exists($ENV{'form.ClearCache'})) { + &Apache::loncoursedata::delete_caches($ENV{'requres.course.id'}); + } + # + # Set up the statistics and chart environment + &PrepareClasslist(); &PrepareCourseData($r); - - &BuildStatistics($r); - + # + # Begin form output + $r->print('
print('method="post" action="/adm/statistics">'); + # + # Print main menu + my %reports = ('classlist' => 'Class list', + 'problem_statistics' => 'Problem Statistics', + 'student_assessment' => 'Problem Status Chart', +# 'percentage' => 'Correct-problems Plot', +# 'option_response' => 'Option Response Analysis', +# 'activitylog' => 'Activity Log', + ); + $r->print(&CreateMainMenu($ENV{'form.status'}, + \%reports,$ENV{'form.reportSelected'})); + $r->rflush(); + # + my $GoToPage = $ENV{'form.reportSelected'}; + if($GoToPage eq 'activitylog') { +# &Apache::lonproblemstatistics::Activity(); + } elsif($GoToPage eq 'problem_statistics') { + &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c); + } elsif($GoToPage eq 'option_response') { +# &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c); + } elsif($GoToPage eq 'student_assessment') { + &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c); + } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') { +# &Apache::lonproblemstatistics::BuildGraphicChart($r,$c); + } elsif($GoToPage eq 'Correct-problems Plot') { +# &Apache::lonpercentage::BuildPercentageGraph($r,$c); + } + # + $r->print("
\n"); + $r->print("\n\n"); + $r->rflush(); + # return OK; } + 1; +####################################################### +####################################################### + =pod =back =cut +####################################################### +####################################################### + __END__