File:  [LON-CAPA] / loncom / interface / lonstatistics.pm
Revision 1.70: download - view: text, annotated - select for diffs
Tue May 13 14:30:26 2003 UTC (21 years, 1 month ago) by matthew
Branches: MAIN
CVS tags: version_0_99_0, HEAD
Bug 1319 (again) - check for all whitespace instead of just '' for
section limits.

    1: # The LearningOnline Network with CAPA
    2: #
    3: # $Id: lonstatistics.pm,v 1.70 2003/05/13 14:30:26 matthew Exp $
    4: #
    5: # Copyright Michigan State University Board of Trustees
    6: #
    7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    8: #
    9: # LON-CAPA is free software; you can redistribute it and/or modify
   10: # it under the terms of the GNU General Public License as published by
   11: # the Free Software Foundation; either version 2 of the License, or
   12: # (at your option) any later version.
   13: #
   14: # LON-CAPA is distributed in the hope that it will be useful,
   15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17: # GNU General Public License for more details.
   18: #
   19: # You should have received a copy of the GNU General Public License
   20: # along with LON-CAPA; if not, write to the Free Software
   21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22: #
   23: # /home/httpd/html/adm/gpl.txt
   24: #
   25: # http://www.lon-capa.org/
   26: #
   27: # (Navigate problems for statistical reports
   28: #
   29: ###
   30: 
   31: =pod
   32: 
   33: =head1 NAME
   34: 
   35: lonstatistics
   36: 
   37: =head1 SYNOPSIS
   38: 
   39: Main handler for statistics and chart.
   40: 
   41: =head1 PACKAGES USED
   42: 
   43:     use strict;
   44:     use Apache::Constants qw(:common :http);
   45:     use Apache::lonnet();
   46:     use Apache::lonhomework;
   47:     use Apache::loncommon;
   48:     use Apache::loncoursedata;
   49:     use Apache::lonhtmlcommon;
   50:     use Apache::lonproblemanalysis;
   51:     use Apache::lonproblemstatistics;
   52:     use Apache::lonstudentassessment;
   53:     use Apache::lonpercentage;
   54:     use Apache::lonmysql;
   55: =over 4
   56: 
   57: =cut
   58: 
   59: package Apache::lonstatistics;
   60: 
   61: use strict;
   62: use Apache::Constants qw(:common :http);
   63: use vars qw(
   64:     @FullClasslist 
   65:     @Students
   66:     @Sections 
   67:     @SelectedSections
   68:     %StudentData
   69:     @StudentDataOrder
   70:     @SelectedStudentData
   71:     $top_map 
   72:     @Sequences 
   73:     @SelectedMaps
   74:     @Assessments);
   75: 
   76: use Apache::lonnet();
   77: use Apache::lonhomework;
   78: use Apache::loncommon;
   79: use Apache::loncoursedata;
   80: use Apache::lonhtmlcommon;
   81: use Apache::lonproblemanalysis();
   82: use Apache::lonproblemstatistics();
   83: use Apache::lonstudentassessment();
   84: use Apache::lonpercentage;
   85: use Apache::lonmysql;
   86: use Time::HiRes;
   87: 
   88: #######################################################
   89: #######################################################
   90: 
   91: =pod
   92: 
   93: =item Package Variables
   94: 
   95: =item @FullClasslist The full classlist
   96: 
   97: =item @Students The students we are concerned with for this invocation
   98: 
   99: =item @Sections The sections available in this class
  100: 
  101: =item $curr_student The student currently being examined
  102: 
  103: =item $prev_student The student previous in the classlist
  104: 
  105: =item $next_student The student next in the classlist
  106: 
  107: =over
  108: 
  109: =cut 
  110: 
  111: #######################################################
  112: #######################################################
  113: #
  114: # Classlist variables
  115: #
  116: my $curr_student;
  117: my $prev_student;
  118: my $next_student;
  119: 
  120: #######################################################
  121: #######################################################
  122: 
  123: =pod
  124: 
  125: =item &clear_classlist_variables()
  126: 
  127: undef the following package variables:
  128: 
  129: =over
  130: 
  131: =item @FullClasslist
  132: 
  133: =item @Students
  134: 
  135: =item @Sections
  136: 
  137: =item @SelectedSections
  138: 
  139: =item %StudentData
  140: 
  141: =item @StudentDataOrder
  142: 
  143: =item @SelectedStudentData
  144: 
  145: =item $curr_student
  146: 
  147: =item $prev_student
  148: 
  149: =item $next_student
  150: 
  151: =back
  152: 
  153: =cut
  154: 
  155: #######################################################
  156: #######################################################
  157: sub clear_classlist_variables {
  158:     undef(@FullClasslist);
  159:     undef(@Students);
  160:     undef(@Sections);
  161:     undef(@SelectedSections);
  162:     undef(%StudentData);
  163:     undef(@SelectedStudentData);
  164:     undef($curr_student);
  165:     undef($prev_student);
  166:     undef($next_student);
  167: }
  168: 
  169: #######################################################
  170: #######################################################
  171: 
  172: =pod
  173: 
  174: =item &PrepareClasslist()
  175: 
  176: Build up the classlist information.  The classlist information is kept in
  177: the following package variables:
  178: 
  179: =over
  180: 
  181: =item @FullClasslist
  182: 
  183: =item @Students
  184: 
  185: =item @Sections
  186: 
  187: =item @SelectedSections
  188: 
  189: =item %StudentData
  190: 
  191: =item @SelectedStudentData
  192: 
  193: =item $curr_student
  194: 
  195: =item $prev_student
  196: 
  197: =item $next_student
  198: 
  199: =back
  200: 
  201: $curr_student, $prev_student, and $next_student may not be defined, depending
  202: upon the calling context.
  203: 
  204: =cut
  205: 
  206: #######################################################
  207: #######################################################
  208: sub PrepareClasslist {
  209:     my $r = shift;
  210:     my %Sections;
  211:     &clear_classlist_variables();
  212:     #
  213:     # Retrieve the classlist
  214:     my $cid  = $ENV{'request.course.id'};
  215:     my $cdom = $ENV{'course.'.$cid.'.domain'};
  216:     my $cnum = $ENV{'course.'.$cid.'.num'};
  217:     my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cid,
  218:                                                                   $cdom,$cnum);
  219:     if (exists($ENV{'form.Section'})) {
  220:         if (ref($ENV{'form.Section'})) {
  221:             @SelectedSections = @{$ENV{'form.Section'}};
  222:         } elsif ($ENV{'form.Section'} !~ /^\s*$/) {
  223:             @SelectedSections = ($ENV{'form.Section'});
  224:         }
  225:     }
  226:     @SelectedSections = ('all') if (! @SelectedSections);
  227:     foreach (@SelectedSections) {
  228:         if ($_ eq 'all') {
  229:             @SelectedSections = ('all');
  230:         }
  231:     }
  232:     #
  233:     # Deal with instructors with restricted section access
  234:     if ($ENV{'request.course.sec'} !~ /^\s*$/) {
  235:         @SelectedSections = ($ENV{'request.course.sec'});
  236:     }
  237:     #
  238:     # Set up %StudentData
  239:     @StudentDataOrder = qw/fullname username domain id section status/;
  240:     foreach my $field (@StudentDataOrder) {
  241:         $StudentData{$field}->{'title'} = $field;
  242:         $StudentData{$field}->{'base_width'} = length($field);
  243:         $StudentData{$field}->{'width'} = 
  244:                                $StudentData{$field}->{'base_width'};
  245:     }
  246:     #
  247:     # get the status requested
  248:     my $requested_status = 'Active';
  249:     $requested_status = $ENV{'form.Status'} if (exists($ENV{'form.Status'}));
  250:     #
  251:     # Process the classlist
  252:     while (my ($student,$student_data) = each (%$classlist)) {
  253:         my $studenthash = ();
  254:         for (my $i=0; $i< scalar(@$field_names);$i++) {
  255:             my $field = $field_names->[$i];
  256:             # Store the data
  257:             $studenthash->{$field}=$student_data->[$i];
  258:             # Keep track of the width of the fields
  259:             next if (! exists($StudentData{$field}));
  260:             my $length = length($student_data->[$i]);
  261:             if ($StudentData{$field}->{'width'} < $length) {
  262:                 $StudentData{$field}->{'width'} = $length; 
  263:             }
  264:         }
  265:         push (@FullClasslist,$studenthash);
  266:         #
  267:         # Build up a list of sections
  268:         my $section = $studenthash->{'section'};
  269:         if (! defined($section) || $section =~/^\s*$/ || $section == -1) {
  270:             $studenthash->{'section'} = 'none';
  271:             $section = $studenthash->{'section'};
  272:         }
  273:         $Sections{$section}++;
  274:         #
  275:         # Only put in the list those students we are interested in
  276:         foreach my $sect (@SelectedSections) {
  277:             if ( (($sect eq 'all') || 
  278:                   ($section eq $sect)) &&
  279:                  (($studenthash->{'status'} eq $requested_status) || 
  280:                   ($requested_status eq 'Any')) 
  281:                  ){
  282:                 push (@Students,$studenthash);
  283:                 last;
  284:             }
  285:         }
  286:     }
  287:     #
  288:     # Put the consolidated section data in the right place
  289:     if ($ENV{'request.course.sec'} !~ /^\s*$/) {
  290:         @Sections = ($ENV{'request.course.sec'});
  291:     } else {
  292:         @Sections = sort {$a cmp $b} keys(%Sections);
  293:         unshift(@Sections,'all'); # Put 'all' at the front of the list
  294:     }
  295:     #
  296:     # Sort the Students
  297:     my $sortby = 'fullname';
  298:     $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'}));
  299:     my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
  300:                              $a->{'fullname'} cmp $b->{'fullname'} } @Students;
  301:     @Students = @TmpStudents;
  302:     # 
  303:     # Now deal with that current student thing....
  304:     if (exists($ENV{'form.StudentAssessmentStudent'})) {
  305:         my ($current_uname,$current_dom) = 
  306:             split(':',$ENV{'form.StudentAssessmentStudent'});
  307:         my $i;
  308:         for ($i = 0; $i<=$#Students; $i++) {
  309:             next if (($Students[$i]->{'username'} ne $current_uname) || 
  310:                      ($Students[$i]->{'domain'}   ne $current_dom));
  311:             $curr_student = $Students[$i];
  312:             last; # If we get here, we have our student.
  313:         }
  314:         if ($i == 0) {
  315:             $prev_student = 'none';
  316:         } else {
  317:             $prev_student = $Students[$i-1];
  318:         }
  319:         if ($i == $#Students) {
  320:             $next_student = 'none';
  321:         } else {
  322:             $next_student = $Students[$i+1];
  323:         }
  324:     }
  325:     #
  326:     if (exists($ENV{'form.StudentData'})) {
  327:         if (ref($ENV{'form.StudentData'}) eq 'ARRAY') {
  328:             @SelectedStudentData = @{$ENV{'form.StudentData'}};
  329:         } else {
  330:             @SelectedStudentData = ($ENV{'form.StudentData'});
  331:         }
  332:     } else {
  333:         @SelectedStudentData = ('fullname');
  334:     }
  335:     foreach (@SelectedStudentData) {
  336:         if ($_ eq 'all') {
  337:             @SelectedStudentData = ('all');
  338:             last;
  339:         }
  340:     }
  341:     #
  342:     return;
  343: }
  344: 
  345: #######################################################
  346: #######################################################
  347: 
  348: =pod
  349: 
  350: =item &current_student()
  351: 
  352: Returns a pointer to a hash containing data about the currently
  353: selected student.
  354: 
  355: =cut
  356: 
  357: #######################################################
  358: #######################################################
  359: sub current_student { 
  360:     if (defined($curr_student)) {
  361:         return $curr_student;
  362:     } else {
  363:         return 'All Students';
  364:     }
  365: }
  366: 
  367: #######################################################
  368: #######################################################
  369: 
  370: =pod
  371: 
  372: =item &previous_student()
  373: 
  374: Returns a pointer to a hash containing data about the student prior
  375: in the list of students.  Or something.  
  376: 
  377: =cut
  378: 
  379: #######################################################
  380: #######################################################
  381: sub previous_student { 
  382:     if (defined($prev_student)) {
  383:         return $prev_student;
  384:     } else {
  385:         return 'No Student Selected';
  386:     }
  387: }
  388: 
  389: #######################################################
  390: #######################################################
  391: 
  392: =pod
  393: 
  394: =item &next_student()
  395: 
  396: Returns a pointer to a hash containing data about the next student
  397: to be viewed.
  398: 
  399: =cut
  400: 
  401: #######################################################
  402: #######################################################
  403: sub next_student { 
  404:     if (defined($next_student)) {
  405:         return $next_student;
  406:     } else {
  407:         return 'No Student Selected';
  408:     }
  409: }
  410: 
  411: #######################################################
  412: #######################################################
  413: 
  414: =pod
  415: 
  416: =item &clear_sequence_variables()
  417: 
  418: =cut
  419: 
  420: #######################################################
  421: #######################################################
  422: sub clear_sequence_variables {
  423:     undef($top_map);
  424:     undef(@Sequences);
  425:     undef(@Assessments);
  426: }
  427: 
  428: #######################################################
  429: #######################################################
  430: 
  431: =pod
  432: 
  433: =item &SetSelectedMaps($elementname)
  434: 
  435: Sets the @SelectedMaps array from $ENV{'form.'.$elementname};
  436: 
  437: =cut
  438: 
  439: #######################################################
  440: #######################################################
  441: sub SetSelectedMaps {
  442:     my $elementname = shift;
  443:     if (exists($ENV{'form.'.$elementname})) {
  444:         if (ref($ENV{'form.'.$elementname})) {
  445:             @SelectedMaps = @{$ENV{'form.'.$elementname}};
  446:         } else {
  447:             @SelectedMaps = ($ENV{'form.'.$elementname});
  448:         }
  449:     } else {
  450:         @SelectedMaps = ('all');
  451:     }
  452: }
  453: 
  454: 
  455: #######################################################
  456: #######################################################
  457: 
  458: =pod
  459: 
  460: =item &Sequences_with_Assess()
  461: 
  462: Returns an array containing the subset of @Sequences which contain
  463: assessments.
  464: 
  465: =cut
  466: 
  467: #######################################################
  468: #######################################################
  469: sub Sequences_with_Assess {
  470:     my @Sequences_to_Show;
  471:     foreach my $map_symb (@SelectedMaps) {
  472:         foreach my $sequence (@Sequences) {
  473:             next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
  474:             next if ($sequence->{'num_assess'} < 1);
  475:             push (@Sequences_to_Show,$sequence);
  476:         }
  477:     }
  478:     return @Sequences_to_Show;
  479: }
  480: 
  481: #######################################################
  482: #######################################################
  483: 
  484: =pod
  485: 
  486: =item &PrepareCourseData($r)
  487: 
  488: =cut
  489: 
  490: #######################################################
  491: #######################################################
  492: sub PrepareCourseData {
  493:     my ($r) = @_;
  494:     &clear_sequence_variables();
  495:     my ($top,$sequences,$assessments) = 
  496:         &Apache::loncoursedata::get_sequence_assessment_data();
  497:     if (! defined($top) || ! ref($top)) {
  498:         # There has been an error, better report it
  499:         &Apache::lonnet::logthis('top is undefined');
  500:         return;
  501:     }
  502:     $top_map = $top if (ref($top));
  503:     @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
  504:     @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY');
  505:     #
  506:     # Compute column widths
  507:     foreach my $seq (@Sequences) {
  508:         my $name_length = length($seq->{'title'});
  509:         my $num_parts = $seq->{'num_assess_parts'};
  510:         #
  511:         # The number of columns needed for the summation text: 
  512:         #    " 1/5" = 1+3 columns, " 10/99" = 1+5 columns
  513:         my $sum_length = 1+1+2*(length($num_parts));
  514:         my $num_col = $num_parts+$sum_length;
  515:         if ($num_col < $name_length) {
  516:             $num_col = $name_length;
  517:         }
  518:         $seq->{'base_width'} = $name_length;
  519:         $seq->{'width'} = $num_col;
  520:     }
  521:     return;
  522: }
  523: 
  524: #######################################################
  525: #######################################################
  526: 
  527: =pod
  528: 
  529: =item &log_sequence($sequence,$recursive,$padding)
  530: 
  531: Write data about the sequence to a logfile.  If $recursive is not
  532: undef the data is written recursively.  $padding is used for recursive
  533: calls.
  534: 
  535: =cut
  536: 
  537: #######################################################
  538: #######################################################
  539: sub log_sequence {
  540:     my ($seq,$recursive,$padding) = @_;
  541:     $padding = '' if (! defined($padding));
  542:     if (ref($seq) ne 'HASH') {
  543:         &Apache::lonnet::logthis('log_sequence passed bad sequnce');
  544:         return;
  545:     }
  546:     &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'});
  547:     while (my($key,$value) = each(%$seq)) {
  548:         next if ($key eq 'contents');
  549:         if (ref($value) eq 'ARRAY') {
  550:             for (my $i=0;$i< scalar(@$value);$i++) {
  551:                 &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
  552:                                          $value->[$i]);
  553:             }
  554:         } else {
  555:             &Apache::lonnet::logthis($padding.$key.'='.$value);
  556:         }
  557:     }
  558:     if (defined($recursive)) {
  559:         &Apache::lonnet::logthis($padding.'-'x20);
  560:         &Apache::lonnet::logthis($padding.'contains:');
  561:         foreach my $item (@{$seq->{'contents'}}) {
  562:             if ($item->{'type'} eq 'container') {
  563:                 &log_sequence($item,$recursive,$padding.'    ');
  564:             } else {
  565:                 &Apache::lonnet::logthis($padding.'title = '.$item->{'title'});
  566:                 while (my($key,$value) = each(%$item)) {
  567:                     next if ($key eq 'title');
  568:                     if (ref($value) eq 'ARRAY') {
  569:                         for (my $i=0;$i< scalar(@$value);$i++) {
  570:                             &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
  571:                                                      $value->[$i]);
  572:                         }
  573:                     } else {
  574:                         &Apache::lonnet::logthis($padding.$key.'='.$value);
  575:                     }
  576:                 }
  577:             }
  578:         }
  579:         &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'});
  580:         &Apache::lonnet::logthis($padding.'-'x20);
  581:     }
  582:     return;
  583: }
  584: 
  585: ##############################################
  586: ##############################################
  587: 
  588: =pod 
  589: 
  590: =item &StudentDataSelect($elementname,$status,$numvisible,$selected)
  591: 
  592: Returns html for a selection box allowing the user to choose one (or more) 
  593: of the fields of student data available (fullname, username, id, section, etc)
  594: 
  595: =over 4
  596: 
  597: =item $elementname The name of the HTML form element
  598: 
  599: =item $status 'multiple' or 'single' selection box
  600: 
  601: =item $numvisible The number of options to be visible
  602: 
  603: =back
  604: 
  605: =cut
  606: 
  607: ##############################################
  608: ##############################################
  609: sub StudentDataSelect {
  610:     my ($elementname,$status,$numvisible)=@_;
  611:     if ($numvisible < 1) {
  612:         return;
  613:     }
  614:     #
  615:     # Build the form element
  616:     my $Str = "\n";
  617:     $Str .= '<select name="'.$elementname.'" ';
  618:     if ($status ne 'single') {
  619:         $Str .= 'multiple="true" ';
  620:     }
  621:     $Str .= 'size="'.$numvisible.'" >'."\n";
  622:     #
  623:     # Deal with 'all'
  624:     $Str .= '    <option value="all" ';
  625:     foreach (@SelectedStudentData) {
  626:         if ($_ eq 'all') {
  627:             $Str .= 'selected ';
  628:             last;
  629:         }
  630:     }
  631:     $Str .= ">all</option>\n";
  632:     #
  633:     # Loop through the student data fields
  634:     foreach my $item (@StudentDataOrder) {
  635:         $Str .= '    <option value="'.$item.'" ';
  636:         foreach (@SelectedStudentData) {
  637:             if ($item eq $_ ) {
  638:                 $Str .= 'selected ';
  639:                 last;
  640:             }
  641:         }
  642:         $Str .= '>'.$item."</option>\n";
  643:     }
  644:     $Str .= "</select>\n";
  645:     return $Str;
  646: }
  647: 
  648: ##############################################
  649: ##############################################
  650: 
  651: =pod 
  652: 
  653: =item &MapSelect($elementname,$status,$numvisible,$restriction) 
  654: 
  655: Returns html for a selection box allowing the user to choose one (or more) 
  656: of the sequences in the course.  The values of the sequences are the symbs.
  657: If the top sequence is selected, the value 'top' will result.
  658: 
  659: =over 4
  660: 
  661: =item $elementname The name of the HTML form element
  662: 
  663: =item $status 'multiple' or 'single' selection box
  664: 
  665: =item $numvisible The number of options to be visible
  666: 
  667: =item $restriction Code reference to subroutine which returns true or 
  668: false.  The code must expect a reference to a sequence data structure.
  669: 
  670: =back
  671: 
  672: =cut
  673: 
  674: ##############################################
  675: ##############################################
  676: sub MapSelect {
  677:     my ($elementname,$status,$numvisible,$restriction)=@_;
  678:     if ($numvisible < 1) {
  679:         return;
  680:     }
  681:     #
  682:     # Set up array of selected items
  683:     &SetSelectedMaps($elementname);
  684:     #
  685:     # Set up the restriction call
  686:     if (! defined($restriction)) {
  687:         $restriction = sub { 1; };
  688:     }
  689:     #
  690:     # Build the form element
  691:     my $Str = "\n";
  692:     $Str .= '<select name="'.$elementname.'" ';
  693:     if ($status ne 'single') {
  694:         $Str .= 'multiple="true" ';
  695:     }
  696:     $Str .= 'size="'.$numvisible.'" >'."\n";
  697:     #
  698:     # Deal with 'all'
  699:     foreach (@SelectedMaps) {
  700:         if ($_ eq 'all') {
  701:             @SelectedMaps = ('all');
  702:             last;
  703:         }
  704:     }
  705:     #
  706:     # Put in option for 'all'
  707:     $Str .= '    <option value="all" ';
  708:     foreach (@SelectedMaps) {
  709:         if ($_ eq 'all') {
  710:             $Str .= 'selected ';
  711:             last;
  712:         }
  713:     }
  714:     $Str .= ">all</option>\n";
  715:     #
  716:     # Loop through the sequences
  717:     foreach my $seq (@Sequences) {
  718:         next if (! $restriction->($seq));
  719:         $Str .= '    <option value="'.$seq->{'symb'}.'" ';
  720:         foreach (@SelectedMaps) {
  721:             if ($seq->{'symb'} eq $_) {
  722:                 $Str .= 'selected ';
  723:                 last;
  724:             }
  725:         }
  726:         $Str .= '>'.$seq->{'title'}."</option>\n";
  727:     }
  728:     $Str .= "</select>\n";
  729:     return $Str;
  730: }
  731: 
  732: ##############################################
  733: ##############################################
  734: 
  735: =pod 
  736: 
  737: =item &SectionSelect($elementname,$status,$numvisible) 
  738: 
  739: Returns html for a selection box allowing the user to choose one (or more) 
  740: of the sections in the course.  
  741: 
  742: =over 4
  743: 
  744: =item $elementname The name of the HTML form element
  745: 
  746: =item $status 'multiple' or 'single' selection box
  747: 
  748: =item $numvisible The number of options to be visible
  749: 
  750: =item $selected Array ref to the names of the already selected sections.
  751: If undef, $ENV{'form.'.$elementname} is used.  
  752: If $ENV{'form.'.$elementname} is also empty, none will be selected.
  753: 
  754: =item $restriction Code reference to subroutine which returns true or 
  755: false.  The code must expect a reference to a sequence data structure.
  756: 
  757: =back
  758: 
  759: =cut
  760: 
  761: ##############################################
  762: ##############################################
  763: sub SectionSelect {
  764:     my ($elementname,$status,$numvisible)=@_;
  765:     if ($numvisible < 1) {
  766:         return;
  767:     }
  768:     #
  769:     # Build the form element
  770:     my $Str = "\n";
  771:     $Str .= '<select name="'.$elementname.'" ';
  772:     if ($status ne 'single') {
  773:         $Str .= 'multiple="true" ';
  774:     }
  775:     $Str .= 'size="'.$numvisible.'" >'."\n";
  776:     #
  777:     # Loop through the sequences
  778:     foreach my $s (@Sections) {
  779:         $Str .= '    <option value="'.$s.'" ';
  780:         foreach (@SelectedSections) {
  781:             if ($s eq $_) {
  782:                 $Str .= 'selected ';
  783:                 last;
  784:             }
  785:         }
  786:         $Str .= '>'.$s."</option>\n";
  787:     }
  788:     $Str .= "</select>\n";
  789:     return $Str;
  790: }
  791: 
  792: ##################################################
  793: ##################################################
  794: sub DisplayClasslist {
  795:     my ($r)=@_;
  796:     #
  797:     my @Fields = ('fullname','username','domain','id','section');
  798:     #
  799:     my $Str='';
  800:     $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
  801:     $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
  802:     foreach my $field (@Fields) {
  803:         $Str .= '<th><a href="/adm/statistics?reportSelected=classlist&sort='.$field.'">'.$field.
  804:             '</a></th>';
  805:     }
  806:     $Str .= '</tr>'."\n";
  807:     #
  808:     my $alternate = 0;
  809:     foreach my $student (@Students) { # @Students is a package variable
  810:         my $sname = $student->{'username'}.':'.$student->{'domain'};
  811:         if($alternate) {
  812:             $Str .= '<tr bgcolor="#ffffe6">';
  813:         } else {
  814:             $Str .= '<tr bgcolor="#ffffc6">';
  815:         }
  816:         $alternate = ($alternate + 1) % 2;
  817:         #
  818:         foreach my $field (@Fields) {
  819:             $Str .= '<td>';
  820:             if ($field eq 'fullname') {
  821:                 $Str .= '<a href="/adm/statistics?reportSelected=';
  822:                 $Str .= &Apache::lonnet::escape('student_assessment');
  823:                 $Str .= '&StudentAssessmentStudent=';
  824:                 $Str .= &Apache::lonnet::escape($sname).'">';
  825:                 $Str .= $student->{$field}.'&nbsp';
  826:                 $Str .= '</a>';
  827:             } else {
  828:                 $Str .= $student->{$field};
  829:             }
  830:             $Str .= '</td>';
  831:         }
  832:         $Str .= "</tr>\n";
  833:     }
  834:     $Str .= '</table></td></tr></table>'."\n";
  835:     #
  836:     $r->print($Str);
  837:     $r->rflush();
  838:     #
  839:     return;
  840: }
  841: 
  842: ##############################################
  843: ##############################################
  844: sub CreateMainMenu {
  845:     my ($status,$reports,$current)=@_;
  846:     #
  847:     my $Str = '';
  848:     #
  849:     $Str .= '<table border="0"><tbody><tr>'."\n";
  850:     $Str .= '<td></td>'."\n";
  851:     $Str .= '<td></td>'."\n";
  852:     $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
  853:     $Str .= '<tr>'."\n";
  854:     #
  855:     $Str .= '<td align="center">'.
  856:         '<input type="submit" name="Refresh" value="Update Display" />'.
  857:             "</td>\n";
  858:     $Str .= '<td align="center">'.
  859:         '<input type="submit" name="ClearCache" value="Clear Caches" />'.
  860:             "</td>\n";
  861:     #
  862:     $Str .= '<td align="center">';
  863:     $Str .= '<select name="reportSelected" >'."\n";
  864:     foreach (sort(keys(%$reports))) {
  865:         $Str .= '<option value="'.$_.'"';
  866:         if($current eq $_) {
  867:             $Str .= ' selected';
  868:         }
  869:         $Str .= '>'.$reports->{$_}.'</option>'."\n";
  870:     }
  871:     $Str .= '</select></td>'."\n";
  872:     #
  873:     $Str .= '</tr></tbody></table>'."\n";
  874:     $Str .= '<hr>'."\n";
  875:     #
  876:     return $Str;
  877: }
  878: 
  879: ##############################################
  880: ##############################################
  881: sub handler {
  882:     my $r=shift;
  883:     my $c = $r->connection();
  884:     #
  885:     # Check for overloading
  886:     my $loaderror=&Apache::lonnet::overloaderror($r);
  887:     if ($loaderror) { return $loaderror; }
  888:     $loaderror=
  889:        &Apache::lonnet::overloaderror($r,
  890:          $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
  891:     if ($loaderror) { return $loaderror; }
  892:     #
  893:     # Check for access
  894:     if (! &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
  895:         $ENV{'user.error.msg'}=
  896:             $r->uri.":vgr:0:0:Cannot view grades for complete course";
  897:         if (! &Apache::lonnet::allowed('vgr',
  898:                       $ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) {
  899:             $ENV{'user.error.msg'}=
  900:                 $r->uri.":vgr:0:0:Cannot view grades with given role";
  901:             return HTTP_NOT_ACCEPTABLE;
  902:         }
  903:     }
  904:     #
  905:     # Set document type for header only
  906:     if($r->header_only) {
  907:         if ($ENV{'browser.mathml'}) {
  908:             $r->content_type('text/xml');
  909:         } else {
  910:             $r->content_type('text/html');
  911:         }
  912:         &Apache::loncommon::no_cache($r);
  913:         $r->send_http_header;
  914:         return OK;
  915:     }
  916:     #
  917:     # Send the header
  918:     $r->content_type('text/html');
  919:     $r->send_http_header;
  920:     #
  921:     # Extract form elements from query string
  922:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  923:                                             ['sort','reportSelected',
  924:                                              'StudentAssessmentStudent']);
  925:     if (! exists($ENV{'form.reportSelected'})) {
  926:         $ENV{'form.reportSelected'} = 'student_assessment';
  927:     }
  928:     #
  929:     # Give the LON-CAPA page header
  930:     $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
  931:     $r->rflush();
  932:     #
  933:     if (! &Apache::lonmysql::verify_sql_connection()) {
  934:         my $serveradmin = $r->dir_config('lonAdmEMail');
  935:         $r->print(<<END);
  936: <h2><font color="Red">Unable to connect to database!</font></h2>
  937: <p>
  938: Please notify the server administrator <b>$serveradmin</b>.
  939: </p><p>
  940: Course Statistics and Charts cannot be retrieved until the database is
  941: restarted.  Your data is intact but cannot be displayed at this time.
  942: </p>
  943: </body>
  944: </html>
  945: END
  946:         return;
  947:     }
  948:     #
  949:     # Clean out the caches
  950:     if (exists($ENV{'form.ClearCache'})) {
  951:         &Apache::loncoursedata::delete_caches($ENV{'requres.course.id'});
  952:     }
  953:     #
  954:     # Set up the statistics and chart environment
  955:     &PrepareClasslist($r);
  956:     &PrepareCourseData($r);
  957:     #
  958:     # Begin form output
  959:     $r->print('<form name="Statistics" ');
  960:     $r->print('method="post" action="/adm/statistics">');
  961:     #
  962:     # Print main menu
  963:     my %reports = ('classlist'          => 'Class list',
  964:                    'problem_statistics' => 'Problem Statistics',
  965:                    'student_assessment' => 'Problem Status Chart',
  966:                    'percentage'         => 'Correct-problems Plot',
  967:                    'option_response'    => 'Option Response Analysis',
  968: #                   'activitylog'        => 'Activity Log',
  969:                    );
  970:     $r->print(&CreateMainMenu($ENV{'form.status'},
  971:                               \%reports,$ENV{'form.reportSelected'}));
  972:     $r->rflush();
  973:     #
  974:     my $GoToPage = $ENV{'form.reportSelected'};
  975:     if($GoToPage eq 'activitylog') {
  976: #        &Apache::lonproblemstatistics::Activity();
  977:     } elsif($GoToPage eq 'problem_statistics') {
  978:         &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
  979:     } elsif($GoToPage eq 'option_response') {
  980: #        &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
  981:     } elsif($GoToPage eq 'student_assessment') {
  982:         &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
  983:     } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
  984: #        &Apache::lonproblemstatistics::BuildGraphicChart($r,$c);
  985:     } elsif($GoToPage eq 'classlist') {
  986:         &DisplayClasslist($r);
  987:     } elsif($GoToPage eq 'Correct-problems Plot') {
  988: #	&Apache::lonpercentage::BuildPercentageGraph($r,$c);
  989:     }
  990:     #
  991:     $r->print("</form>\n");
  992:     $r->print("</body>\n</html>\n");
  993:     $r->rflush();
  994:     #
  995:     return OK;
  996: }
  997: 
  998: 1;
  999: 
 1000: #######################################################
 1001: #######################################################
 1002: 
 1003: =pod
 1004: 
 1005: =back
 1006: 
 1007: =cut
 1008: 
 1009: #######################################################
 1010: #######################################################
 1011: 
 1012: __END__
 1013: 

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