File:  [LON-CAPA] / loncom / interface / lonstatistics.pm
Revision 1.59: download - view: text, annotated - select for diffs
Tue Feb 18 20:27:33 2003 UTC (21 years, 3 months ago) by matthew
Branches: MAIN
CVS tags: HEAD
Untested but not borken.
Added POD documentation.
Removed 'use HTML::TokeParser'.  May need to re-introduce.
Added package variables for classlist, &clear_classlist_variables(),
and &PrepareClasslist().  More changes to these routines are inevitable.

    1: # The LearningOnline Network with CAPA
    2: # (Publication Handler
    3: #
    4: # $Id: lonstatistics.pm,v 1.59 2003/02/18 20:27:33 matthew Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: # (Navigate problems for statistical reports
   29: # YEAR=2001
   30: # 5/5,7/9,7/25/1,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei
   31: # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
   32: # YEAR=2002
   33: # 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
   34: # 5/12,5/14,5/15,5/19,5/26,7/16,25/7,29/7  Behrouz Minaei
   35: #
   36: ###
   37: 
   38: =pod
   39: 
   40: =head1 NAME
   41: 
   42: lonstatistics
   43: 
   44: =head1 SYNOPSIS
   45: 
   46: Main handler for statistics and chart.
   47: 
   48: =head1 PACKAGES USED
   49: 
   50: use strict;
   51: use Apache::Constants qw(:common :http);
   52: use Apache::lonnet();
   53: use Apache::lonhomework;
   54: use Apache::loncommon;
   55: use Apache::loncoursedata;
   56: use Apache::lonhtmlcommon;
   57: use Apache::lonproblemanalysis;
   58: use Apache::lonproblemstatistics;
   59: use Apache::lonstudentassessment;
   60: use Apache::lonpercentage;
   61: use GDBM_File;
   62: 
   63: =over 4
   64: 
   65: =cut
   66: 
   67: package Apache::lonstatistics;
   68: 
   69: use strict;
   70: use Apache::Constants qw(:common :http);
   71: use Apache::lonnet();
   72: use Apache::lonhomework;
   73: use Apache::loncommon;
   74: use Apache::loncoursedata;
   75: use Apache::lonhtmlcommon;
   76: use Apache::lonproblemanalysis;
   77: use Apache::lonproblemstatistics;
   78: use Apache::lonstudentassessment;
   79: use Apache::lonpercentage;
   80: use GDBM_File;
   81: 
   82: my @FullClasslist;
   83: my @Students;
   84: my @Sections;
   85: my $curr_student;
   86: my $prev_student;
   87: my $next_student;
   88: 
   89: #######################################################
   90: #######################################################
   91: 
   92: =pod
   93: 
   94: =item &clear_classlist_variables()
   95: 
   96: undef the following package variables:
   97: 
   98: =over
   99: 
  100: =item @FullClasslist The full classlist
  101: 
  102: =item @Students The students we are concerned with for this invocation
  103: 
  104: =item @Sections The sections available in this class
  105: 
  106: =item $curr_student The student currently being examined
  107: 
  108: =item $prev_student The student previous in the classlist
  109: 
  110: =item $next_student The student next in the classlist
  111: 
  112: =back
  113: 
  114: =cut
  115: 
  116: #######################################################
  117: #######################################################
  118: sub clear_classlist_variables {
  119:     undef(@FullClasslist);
  120:     undef(@Students);
  121:     undef(@Sections);
  122:     undef($curr_student);
  123:     undef($prev_student);
  124:     undef($next_student);
  125: }
  126: 
  127: #######################################################
  128: #######################################################
  129: 
  130: =pod
  131: 
  132: =item &PrepareClasslist()
  133: 
  134: Build up the classlist information.  The classlist information is kept in
  135: the following package variables:
  136: 
  137: =over
  138: 
  139: =item @FullClasslist The full classlist
  140: 
  141: =item @Students The students we are concerned with for this invocation
  142: 
  143: =item @Sections The sections available in this class
  144: 
  145: =item $curr_student The student currently being examined
  146: 
  147: =item $prev_student The student previous in the classlist
  148: 
  149: =item $next_student The student next in the classlist
  150: 
  151: =back
  152: 
  153: $curr_student, $prev_student, and $next_student may not be defined, depending
  154: upon the calling context.
  155: 
  156: =cut
  157: 
  158: #######################################################
  159: #######################################################
  160: sub PrepareClasslist {
  161:     my $r = shift;
  162:     my %Sections;
  163:     &clear_classlist_variables();
  164:     #
  165:     # Retrieve the classlist
  166:     my $cid  = $ENV{'request.course.id'};
  167:     my $cdom = $ENV{'course.'.$cid.'.domain'};
  168:     my $cnum = $ENV{'course.'.$cid.'.num'};
  169:     my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cid,
  170:                                                                   $cdom,$cnum);
  171:     my %valid_section;
  172:     if (exists($ENV{'form.Section'}) && $ENV{'form.Section'} !~ /(all|any)/) {
  173:         if (ref($ENV{'form.Section'})) {
  174:             foreach (@$ENV{'form.section'}) {
  175:                 $valid_section{$_}++;
  176:             }
  177:         } else {
  178:             $valid_section{$_}++;
  179:         }
  180:     }
  181:     #
  182:     # Process the classlist
  183:     while (my ($student,$student_data) = each (%$classlist)) {
  184:         my $studenthash = ();
  185:         for (my $i=0; $i< scalar(@$field_names);$i++) {
  186:             $studenthash->{$field_names->[$i]}=$student_data->[$i];
  187:         }
  188:         push (@FullClasslist,$studenthash);
  189:         #
  190:         # Build up a list of sections
  191:         my $section = $studenthash->{'section'};
  192:         $section = 'no section' if (! defined($section) || $section =~/^\s*/ );
  193:         $Sections{$section}++;
  194:         #
  195:         # Only put in the list those students we are interested in
  196:         if (defined($ENV{'form.Section'}) &&
  197:             $ENV{'form.Section'} !~ /(all|any)/ && 
  198:             ! exists($valid_section{$section})) {
  199:             next;
  200:         }
  201:         push (@Students,$studenthash);
  202:     }
  203:     #
  204:     # Put the consolidated section data in the right place
  205:     @Sections = sort {$a<=>$b} keys(%Sections);
  206:     #
  207:     # Sort the Students
  208:     my $sortby = 'fullname';
  209:     @Students = sort {$a->{$sortby} <=> $b->{$sortby}} @Students;
  210:     # 
  211:     # Now deal with that current student thing....
  212:     if (exists($ENV{'form.StudentAssessmentStudent'})) {
  213:         my ($current_uname,$current_dom) = 
  214:             split(':',$ENV{'form.StudentAssessmentStudent'});
  215:         my $i;
  216:         for ($i = 0; $i<=$#Students; $i++) {
  217:             next if (($Students[$i]->{'username'} ne $current_uname) || 
  218:                      ($Students[$i]->{'domain'}   ne $current_dom));
  219:             last; # If we get here, we have our student.
  220:         }
  221:         if ($i == 0) {
  222:             $prev_student = 'none';
  223:         } else {
  224:             $prev_student = $Students[$i-1];
  225:         }
  226:         if ($i == $#Students) {
  227:             $next_student = 'none';
  228:         } else {
  229:             $next_student = $Students[$i+1];
  230:         }
  231:     }
  232: }
  233: 
  234: #######################################################
  235: #######################################################
  236: 
  237: sub CheckFormElement {
  238:     my ($cache, $ENVName, $cacheName, $default)=@_;
  239: 
  240:     if(defined($ENV{'form.'.$ENVName})) {
  241:         $cache->{$cacheName} = $ENV{'form.'.$ENVName};
  242:     } elsif(!defined($cache->{$cacheName})) {
  243:         $cache->{$cacheName} = $default;
  244:     }
  245: 
  246:     return;
  247: }
  248: 
  249: sub ProcessFormData{
  250:     my ($cache)=@_;
  251: 
  252:     $cache->{'reportKey'} = 'false';
  253: 
  254:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  255:                                             ['sort','download',
  256:                                              'reportSelected',
  257:                                              'StudentAssessmentStudent',
  258:                                              'ProblemStatisticsSort']);
  259:     &CheckFormElement($cache, 'DownloadAll', 'DownloadAll', 'false');
  260:     if ($cache->{'DownloadAll'} ne 'false') {
  261:         # Clean the hell out of that cache!
  262:         # We cannot untie the hash at this scope (stupid libgd :( )
  263:         # So, remove every single key.  What a waste of time....
  264:         # Of course, if you are doing this you are probably resigned
  265:         # to waiting a while.
  266:         &Apache::lonnet::logthis("Cleaning out the cache file");
  267:         while (my ($key,undef)=each(%$cache)) {
  268:             next if ($key eq 'DownloadAll');
  269:             delete($cache->{$key});
  270:         }
  271:     }
  272:     &CheckFormElement($cache, 'Status', 'Status', 'Active');
  273:     &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list');
  274:     &CheckFormElement($cache, 'reportSelected', 'reportSelected', 
  275:                       'Class list');
  276:     $cache->{'reportSelected'} = 
  277:         &Apache::lonnet::unescape($cache->{'reportSelected'});
  278:     &CheckFormElement($cache, 'sort', 'sort', 'fullname');
  279:     &CheckFormElement($cache, 'download', 'download', 'false');
  280:     &CheckFormElement($cache, 'StatisticsMaps', 
  281:                       'StatisticsMaps', 'All Maps');
  282:     &CheckFormElement($cache, 'StatisticsProblemSelect',
  283: 		      'StatisticsProblemSelect', 'All Problems');
  284:     &CheckFormElement($cache, 'StatisticsPartSelect',
  285: 		      'StatisticsPartSelect', 'All Parts');
  286:     if(defined($ENV{'form.Section'})) {
  287:         my @sectionsSelected = (ref($ENV{'form.Section'}) ?
  288:                                @{$ENV{'form.Section'}} :
  289:                                 ($ENV{'form.Section'}));
  290:         $cache->{'sectionsSelected'} = join(':', @sectionsSelected);
  291:     } elsif(!defined($cache->{'sectionsSelected'})) {
  292:         $cache->{'sectionsSelected'} = $cache->{'sectionList'};
  293:     }
  294: 
  295:     # student assessment
  296:     if(defined($ENV{'form.CreateStudentAssessment'}) ||
  297:        defined($ENV{'form.NextStudent'}) ||
  298:        defined($ENV{'form.PreviousStudent'})) {
  299:         $cache->{'reportSelected'} = 'Student Assessment';
  300:     }
  301:     if(defined($ENV{'form.NextStudent'})) {
  302:         $cache->{'StudentAssessmentMove'} = 'next';
  303:     } elsif(defined($ENV{'form.PreviousStudent'})) {
  304:         $cache->{'StudentAssessmentMove'} = 'previous';
  305:     } else {
  306:         $cache->{'StudentAssessmentMove'} = 'selected';
  307:     }
  308:     &CheckFormElement($cache, 'StudentAssessmentStudent', 
  309:                       'StudentAssessmentStudent', 'All Students');
  310:     $cache->{'StudentAssessmentStudent'} = 
  311:         &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'});
  312:     &CheckFormElement($cache, 'DefaultColumns', 'DefaultColumns', 'false');
  313: 
  314:     # Problem analysis
  315:     &CheckFormElement($cache, 'Interval', 'Interval', '1');
  316: 
  317:     # ProblemStatistcs
  318:     &CheckFormElement($cache, 'DisplayCSVFormat',
  319:                       'DisplayFormat', 'Display Table Format');
  320:     &CheckFormElement($cache, 'ProblemStatisticsAscend',
  321:                       'ProblemStatisticsAscend', 'Ascending');
  322:     &CheckFormElement($cache, 'ProblemStatisticsSort',
  323:                       'ProblemStatisticsSort', 'Homework Sets Order');
  324:     &CheckFormElement($cache, 'DisplayLegend', 'DisplayLegend', 
  325: 		      'Hide Legend');
  326:     &CheckFormElement($cache, 'SortProblems', 'SortProblems', 
  327:                       'Sort Within Sequence');
  328: 
  329:     # Search only form elements
  330:     my @headingColumns=();
  331:     my @sequenceColumns=();
  332:     my $foundColumn = 0;
  333:     if(defined($ENV{'form.ReselectColumns'})) {
  334:         my @reselected = (ref($ENV{'form.ReselectColumns'}) ? 
  335:                           @{$ENV{'form.ReselectColumns'}}
  336:                           : ($ENV{'form.ReselectColumns'}));
  337:         foreach (@reselected) {
  338:             if(/HeadingColumn/) {
  339:                 push(@headingColumns, $_);
  340:                 $foundColumn = 1;
  341:             } elsif(/SequenceColumn/) {
  342:                 push(@sequenceColumns, $_);
  343:                 $foundColumn = 1;
  344:             }
  345:         }
  346:     }
  347: 
  348:     $cache->{'reportKey'} = 'false';
  349:     if($cache->{'reportSelected'} eq 'Analyze') {
  350:         $cache->{'reportKey'} = 'Analyze';
  351:     } elsif($cache->{'reportSelected'} eq 'DoDiffGraph') {
  352:         $cache->{'reportKey'} = 'DoDiffGraph';
  353:     } elsif($cache->{'reportSelected'} eq 'PercentWrongGraph') {
  354:         $cache->{'reportKey'} = 'PercentWrongGraph';
  355:     }
  356: 
  357:     if(defined($ENV{'form.DoDiffGraph'})) {
  358:         $cache->{'reportSelected'} = 'DoDiffGraph';
  359:         $cache->{'reportKey'} = 'DoDiffGraph';
  360:     } elsif(defined($ENV{'form.PercentWrongGraph'})) {
  361:         $cache->{'reportSelected'} = 'PercentWrongGraph';
  362:         $cache->{'reportKey'} = 'PercentWrongGraph';
  363:     }
  364: 
  365:     foreach (keys(%ENV)) {
  366:         if(/form\.Analyze/) {
  367:             $cache->{'reportSelected'} = 'Analyze';
  368:             $cache->{'reportKey'} = 'Analyze';
  369:             my $data;
  370:             (undef, $data)=split(':::', $_);
  371:             $cache->{'AnalyzeInfo'}=$data;
  372:         } elsif(/form\.HeadingColumn/) {
  373:             my $value = $_;
  374:             $value =~ s/form\.//;
  375:             push(@headingColumns, $value);
  376:             $foundColumn=1;
  377:         } elsif(/form\.SequenceColumn/) {
  378:             my $value = $_;
  379:             $value =~ s/form\.//;
  380:             push(@sequenceColumns, $value);
  381:             $foundColumn=1;
  382:         }
  383:     }
  384: 
  385:     if($foundColumn) {
  386:         $cache->{'HeadingsFound'} = join(':', @headingColumns);
  387:         $cache->{'SequencesFound'} = join(':', @sequenceColumns);;
  388:     }
  389:     if(!defined($cache->{'HeadingsFound'}) || 
  390:        $cache->{'DefaultColumns'} ne 'false') {
  391:         $cache->{'HeadingsFound'}='HeadingColumnFull Name';
  392:     }
  393:     if(!defined($cache->{'SequencesFound'}) ||
  394:        $cache->{'DefaultColumns'} ne 'false') {
  395:         $cache->{'SequencesFound'}='All Sequences';
  396:     }
  397:     $cache->{'DefaultColumns'} = 'false';
  398: 
  399:     return;
  400: }
  401: 
  402: =pod
  403: 
  404: =item &SortStudents()
  405: 
  406: Determines which students to display and in which order.  Which are 
  407: displayed are determined by their status(active/expired).  The order
  408: is determined by the sort button pressed (default to username).  The
  409: type of sorting is username, lastname, or section.
  410: 
  411: =over 4
  412: 
  413: Input: $students, $CacheData
  414: 
  415: $students: A array pointer to a list of students (username:domain)
  416: 
  417: $CacheData: A pointer to the hash tied to the cached data
  418: 
  419: Output: \@order
  420: 
  421: @order: An ordered list of students (username:domain)
  422: 
  423: =back
  424: 
  425: =cut
  426: 
  427: sub SortStudents {
  428:     my ($cache)=@_;
  429: 
  430:     my @students = split(':::',$cache->{'NamesOfStudents'});
  431:     my @sorted1Students=();
  432:     foreach (@students) {
  433:         if($cache->{'Status'} eq 'Any' || 
  434:            $cache->{$_.':Status'} eq $cache->{'Status'}) {
  435:             push(@sorted1Students, $_);
  436:         }
  437:     }
  438: 
  439:     my $sortBy = '';
  440:     if(defined($cache->{'sort'})) {
  441:         $sortBy = ':'.$cache->{'sort'};
  442:     } else {
  443:         $sortBy = ':fullname';
  444:     }
  445:     my @order = sort { lc($cache->{$a.$sortBy}) cmp lc($cache->{$b.$sortBy}) ||
  446:                        lc($cache->{$a.':fullname'}) cmp lc($cache->{$b.':fullname'}) } 
  447:                 @sorted1Students;
  448: 
  449:     return \@order;
  450: }
  451: 
  452: =pod
  453: 
  454: =item &SpaceColumns()
  455: 
  456: Determines the width of all the columns in the chart.  It is based on
  457: the max of the data for that column and its header.
  458: 
  459: =over 4
  460: 
  461: Input: $students, $studentInformation, $headings, $ChartDB
  462: 
  463: $students: An array pointer to a list of students (username:domain)
  464: 
  465: $studentInformatin: The type of data for the student information.  It is
  466: used as part of the key in $CacheData.
  467: 
  468: $headings: The name of the student information columns.
  469: 
  470: $ChartDB: The name of the cache database which is opened for read/write.
  471: 
  472: Output: None - All data stored in cache.
  473: 
  474: =back
  475: 
  476: =cut
  477: 
  478: sub SpaceColumns {
  479:     my ($students,$studentInformation,$headings,$cache)=@_;
  480: 
  481:     # Initialize Lengths
  482:     for(my $index=0; $index<(scalar @$headings); $index++) {
  483:         my @titleLength=split(//,$headings->[$index]);
  484:         $cache->{$studentInformation->[$index].':columnWidth'}=
  485:             scalar @titleLength;
  486:     }
  487: 
  488:     foreach my $name (@$students) {
  489:         foreach (@$studentInformation) {
  490:             my @dataLength=split(//,$cache->{$name.':'.$_});
  491:             my $length=(scalar @dataLength);
  492:             if($length > $cache->{$_.':columnWidth'}) {
  493:                 $cache->{$_.':columnWidth'}=$length;
  494:             }
  495:         }
  496:     }
  497: 
  498:     return;
  499: }
  500: 
  501: sub PrepareData {
  502:     my ($c, $cacheDB, $studentInformation, $headings,$r)=@_;
  503: 
  504:     # Test for access to the cache data
  505:     my $courseID=$ENV{'request.course.id'};
  506:     my $isRecalculate=0;
  507:     if(defined($ENV{'form.Recalculate'})) {
  508:         $isRecalculate=1;
  509:     }
  510: 
  511:     my $isCached = &Apache::loncoursedata::TestCacheData($cacheDB,
  512:                                                          $isRecalculate);
  513:     if($isCached < 0) {
  514:         return "Unable to tie hash to db file.";
  515:     }
  516: 
  517:     # Download class list information if not using cached data
  518:     my %cache;
  519:     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
  520:         return "Unable to tie hash to db file.";
  521:     }
  522: 
  523: #    if(!$isCached) {
  524:         my $processTopResourceMapReturn=
  525:             &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c);
  526:         if($processTopResourceMapReturn ne 'OK') {
  527:             untie(%cache);
  528:             return $processTopResourceMapReturn;
  529:         }
  530:  #   }
  531: 
  532:     if($c->aborted()) {
  533:         untie(%cache);
  534:         return 'aborted'; 
  535:     }
  536: 
  537:     my $classlist=&Apache::loncoursedata::DownloadClasslist($courseID,
  538:                                                 $cache{'ClasslistTimestamp'},
  539:                                                 $c);
  540:     foreach (keys(%$classlist)) {
  541:         if(/^(con_lost|error|no_such_host)/i) {
  542:             untie(%cache);
  543:             return "Error getting student data.";
  544:         }
  545:     }
  546: 
  547:     if($c->aborted()) {
  548:         untie(%cache);
  549:         return 'aborted'; 
  550:     }
  551: 
  552:     # Active is a temporary solution, remember to change
  553:     Apache::loncoursedata::ProcessClasslist(\%cache,$classlist,$courseID,$c);
  554:     if($c->aborted()) {
  555:         untie(%cache);
  556:         return 'aborted'; 
  557:     }
  558: 
  559:     &ProcessFormData(\%cache);
  560:     my $students = &SortStudents(\%cache);
  561:     &SpaceColumns($students, $studentInformation, $headings, \%cache);
  562:     $cache{'updateTime:columnWidth'}=24;
  563: 
  564:     my $download = $cache{'download'};
  565:     my $downloadAll = $cache{'DownloadAll'};
  566:     my @allStudents=();
  567:     if($download ne 'false') {
  568:         $cache{'download'} = 'false';
  569:     } elsif($downloadAll ne 'false') {
  570:         $cache{'DownloadAll'} = 'false';
  571:         if($downloadAll eq 'sorted') {
  572:             @allStudents = @$students;
  573:         } else {
  574:             @allStudents = split(':::', $cache{'NamesOfStudents'});
  575:         }
  576:     }
  577: 
  578:     untie(%cache);
  579: 
  580:     if($download ne 'false') {
  581:         my @who = ($download);
  582:         if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false',
  583:                                                              $cacheDB, 'true',
  584:                                                              'false', $courseID,
  585:                                                              $r, $c) ne 'OK') {
  586:             return 'Stop at download individual';
  587:         }
  588:     } elsif($downloadAll ne 'false') {
  589:         if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents,
  590:                                                              'false',
  591:                                                              $cacheDB, 'true',
  592:                                                              'true', $courseID,
  593:                                                              $r, $c) ne 'OK') {
  594:             return 'Stop at download all';
  595:         }
  596:     }
  597: 
  598:     return ('OK', $students);
  599: }
  600: 
  601: sub BuildClasslist {
  602:     my ($cacheDB,$students,$studentInformation,$headings,$r)=@_;
  603: 
  604:     my %cache;
  605:     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
  606:         return '<html><body>Unable to tie database.</body></html>';
  607:     }
  608: 
  609: #    my $Ptr = '';
  610: #    $Ptr .= '<table border="0"><tbody>';
  611: #    $Ptr .= '<tr><td align="right"><b>Select Sections</b>';
  612: #    $Ptr .= '</td>'."\n";
  613: #    $Ptr .= '<td align="left">'."\n";
  614: #    my @sectionsSelected = split(':',$cache{'sectionsSelected'});
  615: #    my @sections = split(':',$cache{'sectionList'});
  616: #    $Ptr .= &Apache::lonhtmlcommon::MultipleSectionSelect(\@sections,
  617: #                                                          \@sectionsSelected,
  618: #                                                          'Statistics');
  619: #    $Ptr .= '</td></tr></table><br>';
  620: #    $r->print($Ptr);
  621: #    $r->rflush();
  622: #    my %mySections = ();
  623: #    foreach (@sections) { $mySections{$_} = 'True'; }
  624: #    $r->print("<br>$cache{'sectionsSelected'}<br>");
  625: 
  626:     my $Str='';
  627:     $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
  628:     $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
  629: 
  630:     my $displayString = '<td align="left"><a href="/adm/statistics?';
  631:     $displayString .= 'sort=LINKDATA">DISPLAYDATA&nbsp</a></td>'."\n";
  632:     $Str .= &Apache::lonhtmlcommon::CreateHeadings(\%cache,
  633:                                                    $studentInformation,
  634:                                                    $headings, $displayString);
  635:     $Str .= '</tr>'."\n";
  636: 
  637:     my $alternate=0;
  638:     foreach (@$students) {
  639: #        if ($mySections{$cache{$_.':'.'section'}} ne 'True') {next;}
  640:         my ($username, $domain) = split(':', $_);
  641:         if($alternate) {
  642:             $Str .= '<tr bgcolor="#ffffe6">';
  643:         } else {
  644:             $Str .= '<tr bgcolor="#ffffc6">';
  645:         }
  646:         $alternate = ($alternate + 1) % 2;
  647:         foreach my $data (@$studentInformation) {
  648:             $Str .= '<td>';
  649:             if($data eq 'fullname') {
  650:                 $Str .= '<a href="/adm/statistics?reportSelected=';
  651:                 $Str .= &Apache::lonnet::escape('Student Assessment');
  652:                 $Str .= '&StudentAssessmentStudent=';
  653:                 $Str .= &Apache::lonnet::escape($cache{$_.':'.$data}).'">';
  654:                 $Str .= $cache{$_.':'.$data}.'&nbsp';
  655:                 $Str .= '</a>';
  656:             } elsif($data eq 'updateTime') {
  657:                 $Str .= '<a href="/adm/statistics?reportSelected=';
  658:                 $Str .= &Apache::lonnet::escape('Class list');
  659:                 $Str .= '&download='.$_.'">';
  660:                 $Str .= $cache{$_.':'.$data}.'&nbsp';
  661:                 $Str .= '&nbsp</a>';
  662:             } else {
  663:                 $Str .= $cache{$_.':'.$data}.'&nbsp';
  664:             }
  665: 
  666:             $Str .= '</td>'."\n";
  667:         }
  668:     }
  669: 
  670:     $Str .= '</tr>'."\n";
  671:     $Str .= '</table></td></tr></table>'."\n";
  672:     $r->print($Str);
  673:     $r->rflush();
  674: 
  675:     untie(%cache);
  676: 
  677:     return;
  678: }
  679: 
  680: sub CreateMainMenu {
  681:     my ($status, $reports)=@_;
  682: 
  683:     my $Str = '';
  684: 
  685:     $Str .= '<table border="0"><tbody><tr>'."\n";
  686:     $Str .= '<td></td><td></td>'."\n";
  687:     $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
  688:     $Str .= '<td align="center"><b>Student Status</b></td></tr>'."\n";
  689:     $Str .= '<tr>'."\n";
  690:     $Str .= '<td align="center"><input type="submit" name="Refresh" ';
  691:     $Str .= 'value="Refresh" /></td>'."\n";
  692:     $Str .= '<td align="center"><input type="submit" name="DownloadAll" ';
  693:     $Str .= 'value="Update All Student Data" /></td>'."\n";
  694:     $Str .= '<td align="center">';
  695:     $Str .= '<select name="reportSelected" onchange="document.';
  696:     $Str .= 'Statistics.submit()">'."\n";
  697: 
  698:     foreach (sort(keys(%$reports))) {
  699:         next if($_ eq 'reportSelected');
  700:         $Str .= '<option name="'.$_.'"';
  701:         if($reports->{'reportSelected'} eq $reports->{$_}) {
  702:             $Str .= ' selected=""';
  703:         }
  704:         $Str .= '>'.$reports->{$_}.'</option>'."\n";
  705:     }
  706:     $Str .= '</select></td>'."\n";
  707: 
  708:     $Str .= '<td align="center">';
  709:     $Str .= &Apache::lonhtmlcommon::StatusOptions($status, 'Statistics');
  710:     $Str .= '</td>'."\n";
  711: 
  712:     $Str .= '</tr></tbody></table>'."\n";
  713:     $Str .= '<hr>'."\n";
  714: 
  715:     return $Str;
  716: }
  717: 
  718: sub BuildStatistics {
  719:     my ($r)=@_;
  720: 
  721:     my $c = $r->connection;
  722:     my @studentInformation=('fullname','section','id','domain','username',
  723:                             'updateTime');
  724:     my @headings=('Full Name', 'Section', 'PID', 'Domain', 'User Name',
  725:                   'Last Updated');
  726:     my $spacing = '   ';
  727: 
  728:     my %reports = ('classlist'          => 'Class list',
  729:                    'problem_statistics' => 'Problem Statistics',
  730:                    'student_assessment' => 'Student Assessment',
  731: 		   'percentage'         => 'Correct-problems Plot',
  732: #                   'activitylog'        => 'Activity Log',
  733:                    'reportSelected'     => 'Class list');
  734: 
  735:     my %cache;
  736:     my $courseID=$ENV{'request.course.id'};
  737:     my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
  738:                   "_$ENV{'user.domain'}_$courseID\_statistics.db";
  739: 
  740:     $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
  741: 
  742:     my ($returnValue, $students) = &PrepareData($c, $cacheDB,
  743:                                                 \@studentInformation,
  744:                                                 \@headings,$r);
  745:     if($returnValue ne 'OK') {
  746:         $r->print($returnValue."\n".'</body></html>');
  747:         return OK;
  748:     }
  749:     if(!$c->aborted()) {
  750:         &Apache::loncoursedata::CheckForResidualDownload($cacheDB,
  751:                                                          'true', 'true',
  752:                                                          $courseID,
  753:                                                          $r, $c);
  754:     }
  755: 
  756:     my $GoToPage;
  757:     if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
  758:         $GoToPage = $cache{'reportSelected'};
  759:         $reports{'reportSelected'} = $cache{'reportSelected'};
  760:         if(defined($cache{'reportKey'}) &&
  761:            !exists($reports{$cache{'reportKey'}}) &&
  762:            $cache{'reportKey'} ne 'false') {
  763:             $reports{$cache{'reportKey'}} = $cache{'reportSelected'};
  764:         }
  765: 
  766:         if(defined($cache{'OptionResponses'})) {
  767:             $reports{'problem_analysis'} = 'Option Response Analysis';
  768:         }
  769: 
  770:         $r->print('<form name="Statistics" ');
  771:         $r->print('method="post" action="/adm/statistics">');
  772:         $r->print(&CreateMainMenu($cache{'Status'}, \%reports));
  773:         $r->rflush();
  774:         untie(%cache);
  775:     } else {
  776:         $r->print('<html><body>Unable to tie database.</body></html>');
  777:         return OK;
  778:     }
  779: 
  780:     if($GoToPage eq 'Activity Log') {
  781:         &Apache::lonproblemstatistics::Activity();
  782:     } elsif($GoToPage eq 'Problem Statistics') {
  783:         &Apache::lonproblemstatistics::BuildProblemStatisticsPage($cacheDB,
  784:                                                                   $students,
  785:                                                                   $courseID,
  786:                                                                   $c,$r);
  787:     } elsif($GoToPage eq 'Option Response Analysis') {
  788:         &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB, $r);
  789:     } elsif($GoToPage eq 'Student Assessment') {
  790:         &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB,
  791:                                                           $students,
  792:                                                           $courseID,
  793:                                                           'Statistics',
  794:                                                           \@headings,
  795:                                                           $spacing,
  796:                                                           \@studentInformation,
  797:                                                           $r, $c);
  798:     } elsif($GoToPage eq 'Analyze') {
  799:         &Apache::lonproblemanalysis::BuildAnalyzePage($cacheDB, $students,
  800:                                                       $courseID, $r);
  801:     } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
  802:         my $courseDescription = $ENV{'course.'.$courseID.'.description'};
  803:         $courseDescription =~ s/\ /"_"/eg;
  804:         &Apache::lonproblemstatistics::BuildGraphicChart($GoToPage, $cacheDB,
  805:                                                          $courseDescription,
  806:                                                          $students, $courseID,
  807:                                                          $r, $c);
  808:     } elsif($GoToPage eq 'Class list') {
  809:         &BuildClasslist($cacheDB, $students, \@studentInformation,
  810:                         \@headings, $r);
  811:     } elsif($GoToPage eq 'Correct-problems Plot') {
  812: 	&Apache::lonpercentage::BuildPercentageGraph($cacheDB, $students,
  813: 						     $courseID, $c, $r);
  814:     }
  815: 
  816:     $r->print('</form>'."\n");
  817:     $r->print("\n".'</body>'."\n".'</html>');
  818:     $r->rflush();
  819: 
  820:     return OK;
  821: }
  822: 
  823: # ================================================================ Main Handler
  824: 
  825: sub handler {
  826:     my $r=shift;
  827: 
  828: #    $jr = $r;
  829: 
  830:     my $loaderror=&Apache::lonnet::overloaderror($r);
  831:     if ($loaderror) { return $loaderror; }
  832:     $loaderror=
  833:        &Apache::lonnet::overloaderror($r,
  834:          $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
  835:     if ($loaderror) { return $loaderror; }
  836: 
  837:     unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
  838:         $ENV{'user.error.msg'}=
  839:         $r->uri.":vgr:0:0:Cannot view grades for complete course";
  840:         return HTTP_NOT_ACCEPTABLE;
  841:     }
  842: 
  843:     # Set document type for header only
  844:     if($r->header_only) {
  845:         if ($ENV{'browser.mathml'}) {
  846:             $r->content_type('text/xml');
  847:         } else {
  848:             $r->content_type('text/html');
  849:         }
  850:         &Apache::loncommon::no_cache($r);
  851:         $r->send_http_header;
  852:         return OK;
  853:     }
  854: 
  855:     unless($ENV{'request.course.fn'}) {
  856: 	my $requrl=$r->uri;
  857:         $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
  858:         return HTTP_NOT_ACCEPTABLE;
  859:     }
  860: 
  861:     $r->content_type('text/html');
  862:     $r->send_http_header;
  863: 
  864:     &PrepareClasslist($r);
  865: 
  866:     &BuildStatistics($r);
  867: 
  868:     return OK;
  869: }
  870: 1;
  871: 
  872: =pod
  873: 
  874: =back
  875: 
  876: =cut
  877: 
  878: __END__
  879: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>