File:  [LON-CAPA] / loncom / interface / lonstatistics.pm
Revision 1.66: download - view: text, annotated - select for diffs
Fri Apr 18 15:50:55 2003 UTC (21 years, 1 month ago) by matthew
Branches: MAIN
CVS tags: HEAD
Added &Apache::lonmysql::verify_sql_connection() to test the daemons ability
to talk to the database.
Modified &Apache::lonstatistics::handler to call verify_sql_connection and
give an error message to the user.

    1: # The LearningOnline Network with CAPA
    2: #
    3: # $Id: lonstatistics.pm,v 1.66 2003/04/18 15:50:55 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:     # Set up %StudentData
  234:     @StudentDataOrder = qw/fullname username domain id section status/;
  235:     foreach my $field (@StudentDataOrder) {
  236:         $StudentData{$field}->{'title'} = $field;
  237:         $StudentData{$field}->{'base_width'} = length($field);
  238:         $StudentData{$field}->{'width'} = 
  239:                                $StudentData{$field}->{'base_width'};
  240:     }
  241: 
  242:     #
  243:     # Process the classlist
  244:     while (my ($student,$student_data) = each (%$classlist)) {
  245:         my $studenthash = ();
  246:         for (my $i=0; $i< scalar(@$field_names);$i++) {
  247:             my $field = $field_names->[$i];
  248:             # Store the data
  249:             $studenthash->{$field}=$student_data->[$i];
  250:             # Keep track of the width of the fields
  251:             next if (! exists($StudentData{$field}));
  252:             my $length = length($student_data->[$i]);
  253:             if ($StudentData{$field}->{'width'} < $length) {
  254:                 $StudentData{$field}->{'width'} = $length; 
  255:             }
  256:         }
  257:         push (@FullClasslist,$studenthash);
  258:         #
  259:         # Build up a list of sections
  260:         my $section = $studenthash->{'section'};
  261:         if (! defined($section) || $section =~/^\s*$/ || $section == -1) {
  262:             $studenthash->{'section'} = 'none';
  263:             $section = $studenthash->{'section'};
  264:         }
  265:         $Sections{$section}++;
  266:         #
  267:         # Only put in the list those students we are interested in
  268:         foreach my $sect (@SelectedSections) {
  269:             if (($sect eq 'all') || ($section eq $sect)) {
  270:                 push (@Students,$studenthash);
  271:                 last;
  272:             }
  273:         }
  274:     }
  275:     #
  276:     # Put the consolidated section data in the right place
  277:     @Sections = sort {$a cmp $b} keys(%Sections);
  278:     unshift(@Sections,'all'); # Put 'all' at the front of the list
  279:     #
  280:     # Sort the Students
  281:     my $sortby = 'fullname';
  282:     $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'}));
  283:     my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
  284:                              $a->{'fullname'} cmp $b->{'fullname'} } @Students;
  285:     @Students = @TmpStudents;
  286:     # 
  287:     # Now deal with that current student thing....
  288:     if (exists($ENV{'form.StudentAssessmentStudent'})) {
  289:         my ($current_uname,$current_dom) = 
  290:             split(':',$ENV{'form.StudentAssessmentStudent'});
  291:         my $i;
  292:         for ($i = 0; $i<=$#Students; $i++) {
  293:             next if (($Students[$i]->{'username'} ne $current_uname) || 
  294:                      ($Students[$i]->{'domain'}   ne $current_dom));
  295:             $curr_student = $Students[$i];
  296:             last; # If we get here, we have our student.
  297:         }
  298:         if ($i == 0) {
  299:             $prev_student = 'none';
  300:         } else {
  301:             $prev_student = $Students[$i-1];
  302:         }
  303:         if ($i == $#Students) {
  304:             $next_student = 'none';
  305:         } else {
  306:             $next_student = $Students[$i+1];
  307:         }
  308:     }
  309:     #
  310:     if (exists($ENV{'form.StudentData'})) {
  311:         if (ref($ENV{'form.StudentData'}) eq 'ARRAY') {
  312:             @SelectedStudentData = @{$ENV{'form.StudentData'}};
  313:         } else {
  314:             @SelectedStudentData = ($ENV{'form.StudentData'});
  315:         }
  316:     } else {
  317:         @SelectedStudentData = ('fullname');
  318:     }
  319:     foreach (@SelectedStudentData) {
  320:         if ($_ eq 'all') {
  321:             @SelectedStudentData = ('all');
  322:             last;
  323:         }
  324:     }
  325:     #
  326:     return;
  327: }
  328: 
  329: #######################################################
  330: #######################################################
  331: 
  332: =pod
  333: 
  334: =item &current_student()
  335: 
  336: Returns a pointer to a hash containing data about the currently
  337: selected student.
  338: 
  339: =cut
  340: 
  341: #######################################################
  342: #######################################################
  343: sub current_student { 
  344:     if (defined($curr_student)) {
  345:         return $curr_student;
  346:     } else {
  347:         return 'All Students';
  348:     }
  349: }
  350: 
  351: #######################################################
  352: #######################################################
  353: 
  354: =pod
  355: 
  356: =item &previous_student()
  357: 
  358: Returns a pointer to a hash containing data about the student prior
  359: in the list of students.  Or something.  
  360: 
  361: =cut
  362: 
  363: #######################################################
  364: #######################################################
  365: sub previous_student { 
  366:     if (defined($prev_student)) {
  367:         return $prev_student;
  368:     } else {
  369:         return 'No Student Selected';
  370:     }
  371: }
  372: 
  373: #######################################################
  374: #######################################################
  375: 
  376: =pod
  377: 
  378: =item &next_student()
  379: 
  380: Returns a pointer to a hash containing data about the next student
  381: to be viewed.
  382: 
  383: =cut
  384: 
  385: #######################################################
  386: #######################################################
  387: sub next_student { 
  388:     if (defined($next_student)) {
  389:         return $next_student;
  390:     } else {
  391:         return 'No Student Selected';
  392:     }
  393: }
  394: 
  395: #######################################################
  396: #######################################################
  397: 
  398: =pod
  399: 
  400: =item &clear_sequence_variables()
  401: 
  402: =cut
  403: 
  404: #######################################################
  405: #######################################################
  406: sub clear_sequence_variables {
  407:     undef($top_map);
  408:     undef(@Sequences);
  409:     undef(@Assessments);
  410: }
  411: 
  412: #######################################################
  413: #######################################################
  414: 
  415: =pod
  416: 
  417: =item &SetSelectedMaps($elementname)
  418: 
  419: Sets the @SelectedMaps array from $ENV{'form.'.$elementname};
  420: 
  421: =cut
  422: 
  423: #######################################################
  424: #######################################################
  425: sub SetSelectedMaps {
  426:     my $elementname = shift;
  427:     if (exists($ENV{'form.'.$elementname})) {
  428:         if (ref($ENV{'form.'.$elementname})) {
  429:             @SelectedMaps = @{$ENV{'form.'.$elementname}};
  430:         } else {
  431:             @SelectedMaps = ($ENV{'form.'.$elementname});
  432:         }
  433:     } else {
  434:         @SelectedMaps = ('all');
  435:     }
  436: }
  437: 
  438: 
  439: #######################################################
  440: #######################################################
  441: 
  442: =pod
  443: 
  444: =item &Sequences_with_Assess()
  445: 
  446: Returns an array containing the subset of @Sequences which contain
  447: assessments.
  448: 
  449: =cut
  450: 
  451: #######################################################
  452: #######################################################
  453: sub Sequences_with_Assess {
  454:     my @Sequences_to_Show;
  455:     foreach my $map_symb (@SelectedMaps) {
  456:         foreach my $sequence (@Sequences) {
  457:             next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
  458:             next if ($sequence->{'num_assess'} < 1);
  459:             push (@Sequences_to_Show,$sequence);
  460:         }
  461:     }
  462:     return @Sequences_to_Show;
  463: }
  464: 
  465: #######################################################
  466: #######################################################
  467: 
  468: =pod
  469: 
  470: =item &PrepareCourseData($r)
  471: 
  472: =cut
  473: 
  474: #######################################################
  475: #######################################################
  476: sub PrepareCourseData {
  477:     my ($r) = @_;
  478:     &clear_sequence_variables();
  479:     my ($top,$sequences,$assessments) = 
  480:         &Apache::loncoursedata::get_sequence_assessment_data();
  481:     if (! defined($top) || ! ref($top)) {
  482:         # There has been an error, better report it
  483:         &Apache::lonnet::logthis('top is undefined');
  484:         return;
  485:     }
  486:     $top_map = $top if (ref($top));
  487:     @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
  488:     @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY');
  489:     #
  490:     # Compute column widths
  491:     foreach my $seq (@Sequences) {
  492:         my $name_length = length($seq->{'title'});
  493:         my $num_parts = $seq->{'num_assess_parts'};
  494:         #
  495:         # The number of columns needed for the summation text: 
  496:         #    " 1/5" = 1+3 columns, " 10/99" = 1+5 columns
  497:         my $sum_length = 1+1+2*(length($num_parts));
  498:         my $num_col = $num_parts+$sum_length;
  499:         if ($num_col < $name_length) {
  500:             $num_col = $name_length;
  501:         }
  502:         $seq->{'base_width'} = $name_length;
  503:         $seq->{'width'} = $num_col;
  504:     }
  505:     return;
  506: }
  507: 
  508: #######################################################
  509: #######################################################
  510: 
  511: =pod
  512: 
  513: =item &log_sequence($sequence,$recursive,$padding)
  514: 
  515: Write data about the sequence to a logfile.  If $recursive is not
  516: undef the data is written recursively.  $padding is used for recursive
  517: calls.
  518: 
  519: =cut
  520: 
  521: #######################################################
  522: #######################################################
  523: sub log_sequence {
  524:     my ($seq,$recursive,$padding) = @_;
  525:     $padding = '' if (! defined($padding));
  526:     if (ref($seq) ne 'HASH') {
  527:         &Apache::lonnet::logthis('log_sequence passed bad sequnce');
  528:         return;
  529:     }
  530:     &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'});
  531:     while (my($key,$value) = each(%$seq)) {
  532:         next if ($key eq 'contents');
  533:         if (ref($value) eq 'ARRAY') {
  534:             for (my $i=0;$i< scalar(@$value);$i++) {
  535:                 &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
  536:                                          $value->[$i]);
  537:             }
  538:         } else {
  539:             &Apache::lonnet::logthis($padding.$key.'='.$value);
  540:         }
  541:     }
  542:     if (defined($recursive)) {
  543:         &Apache::lonnet::logthis($padding.'-'x20);
  544:         &Apache::lonnet::logthis($padding.'contains:');
  545:         foreach my $item (@{$seq->{'contents'}}) {
  546:             if ($item->{'type'} eq 'container') {
  547:                 &log_sequence($item,$recursive,$padding.'    ');
  548:             } else {
  549:                 &Apache::lonnet::logthis($padding.'title = '.$item->{'title'});
  550:                 while (my($key,$value) = each(%$item)) {
  551:                     next if ($key eq 'title');
  552:                     if (ref($value) eq 'ARRAY') {
  553:                         for (my $i=0;$i< scalar(@$value);$i++) {
  554:                             &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
  555:                                                      $value->[$i]);
  556:                         }
  557:                     } else {
  558:                         &Apache::lonnet::logthis($padding.$key.'='.$value);
  559:                     }
  560:                 }
  561:             }
  562:         }
  563:         &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'});
  564:         &Apache::lonnet::logthis($padding.'-'x20);
  565:     }
  566:     return;
  567: }
  568: 
  569: ##############################################
  570: ##############################################
  571: 
  572: =pod 
  573: 
  574: =item &StudentDataSelect($elementname,$status,$numvisible,$selected)
  575: 
  576: Returns html for a selection box allowing the user to choose one (or more) 
  577: of the fields of student data available (fullname, username, id, section, etc)
  578: 
  579: =over 4
  580: 
  581: =item $elementname The name of the HTML form element
  582: 
  583: =item $status 'multiple' or 'single' selection box
  584: 
  585: =item $numvisible The number of options to be visible
  586: 
  587: =back
  588: 
  589: =cut
  590: 
  591: ##############################################
  592: ##############################################
  593: sub StudentDataSelect {
  594:     my ($elementname,$status,$numvisible)=@_;
  595:     if ($numvisible < 1) {
  596:         return;
  597:     }
  598:     #
  599:     # Build the form element
  600:     my $Str = "\n";
  601:     $Str .= '<select name="'.$elementname.'" ';
  602:     if ($status ne 'single') {
  603:         $Str .= 'multiple="true" ';
  604:     }
  605:     $Str .= 'size="'.$numvisible.'" >'."\n";
  606:     #
  607:     # Deal with 'all'
  608:     $Str .= '    <option value="all" ';
  609:     foreach (@SelectedStudentData) {
  610:         if ($_ eq 'all') {
  611:             $Str .= 'selected ';
  612:             last;
  613:         }
  614:     }
  615:     $Str .= ">all</option>\n";
  616:     #
  617:     # Loop through the student data fields
  618:     foreach my $item (@StudentDataOrder) {
  619:         $Str .= '    <option value="'.$item.'" ';
  620:         foreach (@SelectedStudentData) {
  621:             if ($item eq $_ ) {
  622:                 $Str .= 'selected ';
  623:                 last;
  624:             }
  625:         }
  626:         $Str .= '>'.$item."</option>\n";
  627:     }
  628:     $Str .= "</select>\n";
  629:     return $Str;
  630: }
  631: 
  632: ##############################################
  633: ##############################################
  634: 
  635: =pod 
  636: 
  637: =item &MapSelect($elementname,$status,$numvisible,$restriction) 
  638: 
  639: Returns html for a selection box allowing the user to choose one (or more) 
  640: of the sequences in the course.  The values of the sequences are the symbs.
  641: If the top sequence is selected, the value 'top' will result.
  642: 
  643: =over 4
  644: 
  645: =item $elementname The name of the HTML form element
  646: 
  647: =item $status 'multiple' or 'single' selection box
  648: 
  649: =item $numvisible The number of options to be visible
  650: 
  651: =item $restriction Code reference to subroutine which returns true or 
  652: false.  The code must expect a reference to a sequence data structure.
  653: 
  654: =back
  655: 
  656: =cut
  657: 
  658: ##############################################
  659: ##############################################
  660: sub MapSelect {
  661:     my ($elementname,$status,$numvisible,$restriction)=@_;
  662:     if ($numvisible < 1) {
  663:         return;
  664:     }
  665:     #
  666:     # Set up array of selected items
  667:     &SetSelectedMaps($elementname);
  668:     #
  669:     # Set up the restriction call
  670:     if (! defined($restriction)) {
  671:         $restriction = sub { 1; };
  672:     }
  673:     #
  674:     # Build the form element
  675:     my $Str = "\n";
  676:     $Str .= '<select name="'.$elementname.'" ';
  677:     if ($status ne 'single') {
  678:         $Str .= 'multiple="true" ';
  679:     }
  680:     $Str .= 'size="'.$numvisible.'" >'."\n";
  681:     #
  682:     # Deal with 'all'
  683:     foreach (@SelectedMaps) {
  684:         if ($_ eq 'all') {
  685:             @SelectedMaps = ('all');
  686:             last;
  687:         }
  688:     }
  689:     #
  690:     # Put in option for 'all'
  691:     $Str .= '    <option value="all" ';
  692:     foreach (@SelectedMaps) {
  693:         if ($_ eq 'all') {
  694:             $Str .= 'selected ';
  695:             last;
  696:         }
  697:     }
  698:     $Str .= ">all</option>\n";
  699:     #
  700:     # Loop through the sequences
  701:     foreach my $seq (@Sequences) {
  702:         next if (! $restriction->($seq));
  703:         $Str .= '    <option value="'.$seq->{'symb'}.'" ';
  704:         foreach (@SelectedMaps) {
  705:             if ($seq->{'symb'} eq $_) {
  706:                 $Str .= 'selected ';
  707:                 last;
  708:             }
  709:         }
  710:         $Str .= '>'.$seq->{'title'}."</option>\n";
  711:     }
  712:     $Str .= "</select>\n";
  713:     return $Str;
  714: }
  715: 
  716: ##############################################
  717: ##############################################
  718: 
  719: =pod 
  720: 
  721: =item &SectionSelect($elementname,$status,$numvisible) 
  722: 
  723: Returns html for a selection box allowing the user to choose one (or more) 
  724: of the sections in the course.  
  725: 
  726: =over 4
  727: 
  728: =item $elementname The name of the HTML form element
  729: 
  730: =item $status 'multiple' or 'single' selection box
  731: 
  732: =item $numvisible The number of options to be visible
  733: 
  734: =item $selected Array ref to the names of the already selected sections.
  735: If undef, $ENV{'form.'.$elementname} is used.  
  736: If $ENV{'form.'.$elementname} is also empty, none will be selected.
  737: 
  738: =item $restriction Code reference to subroutine which returns true or 
  739: false.  The code must expect a reference to a sequence data structure.
  740: 
  741: =back
  742: 
  743: =cut
  744: 
  745: ##############################################
  746: ##############################################
  747: sub SectionSelect {
  748:     my ($elementname,$status,$numvisible)=@_;
  749:     if ($numvisible < 1) {
  750:         return;
  751:     }
  752:     #
  753:     # Build the form element
  754:     my $Str = "\n";
  755:     $Str .= '<select name="'.$elementname.'" ';
  756:     if ($status ne 'single') {
  757:         $Str .= 'multiple="true" ';
  758:     }
  759:     $Str .= 'size="'.$numvisible.'" >'."\n";
  760:     #
  761:     # Loop through the sequences
  762:     foreach my $s (@Sections) {
  763:         $Str .= '    <option value="'.$s.'" ';
  764:         foreach (@SelectedSections) {
  765:             if ($s eq $_) {
  766:                 $Str .= 'selected ';
  767:                 last;
  768:             }
  769:         }
  770:         $Str .= '>'.$s."</option>\n";
  771:     }
  772:     $Str .= "</select>\n";
  773:     return $Str;
  774: }
  775: 
  776: ##################################################
  777: ##################################################
  778: sub DisplayClasslist {
  779:     my ($r)=@_;
  780:     #
  781:     my @Fields = ('fullname','username','domain','id','section');
  782:     #
  783:     my $Str='';
  784:     $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
  785:     $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
  786:     foreach my $field (@Fields) {
  787:         $Str .= '<th><a href="/adm/statistics?reportSelected=classlist&sort='.$field.'">'.$field.
  788:             '</a></th>';
  789:     }
  790:     $Str .= '</tr>'."\n";
  791:     #
  792:     my $alternate = 0;
  793:     foreach my $student (@Students) { # @Students is a package variable
  794:         my $sname = $student->{'username'}.':'.$student->{'domain'};
  795:         if($alternate) {
  796:             $Str .= '<tr bgcolor="#ffffe6">';
  797:         } else {
  798:             $Str .= '<tr bgcolor="#ffffc6">';
  799:         }
  800:         $alternate = ($alternate + 1) % 2;
  801:         #
  802:         foreach my $field (@Fields) {
  803:             $Str .= '<td>';
  804:             if ($field eq 'fullname') {
  805:                 $Str .= '<a href="/adm/statistics?reportSelected=';
  806:                 $Str .= &Apache::lonnet::escape('student_assessment');
  807:                 $Str .= '&StudentAssessmentStudent=';
  808:                 $Str .= &Apache::lonnet::escape($sname).'">';
  809:                 $Str .= $student->{$field}.'&nbsp';
  810:                 $Str .= '</a>';
  811:             } else {
  812:                 $Str .= $student->{$field};
  813:             }
  814:             $Str .= '</td>';
  815:         }
  816:         $Str .= "</tr>\n";
  817:     }
  818:     $Str .= '</table></td></tr></table>'."\n";
  819:     #
  820:     $r->print($Str);
  821:     $r->rflush();
  822:     #
  823:     return;
  824: }
  825: 
  826: ##############################################
  827: ##############################################
  828: sub CreateMainMenu {
  829:     my ($status,$reports,$current)=@_;
  830:     #
  831:     my $Str = '';
  832:     #
  833:     $Str .= '<table border="0"><tbody><tr>'."\n";
  834:     $Str .= '<td></td>'."\n";
  835:     $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
  836:     $Str .= '<td align="center"><b>Student Status</b></td></tr>'."\n";
  837:     $Str .= '<tr>'."\n";
  838:     #
  839:     $Str .= '<td align="center"><input type="submit" name="Refresh" ';
  840:     $Str .= 'value="Update Display" /></td>'."\n";
  841:     #
  842:     $Str .= '<td align="center">';
  843:     $Str .= '<select name="reportSelected" >'."\n";
  844:     foreach (sort(keys(%$reports))) {
  845:         $Str .= '<option value="'.$_.'"';
  846:         if($current eq $_) {
  847:             $Str .= ' selected';
  848:         }
  849:         $Str .= '>'.$reports->{$_}.'</option>'."\n";
  850:     }
  851:     $Str .= '</select></td>'."\n";
  852:     #
  853:     $Str .= '<td align="center">';
  854:     $Str .= &Apache::lonhtmlcommon::StatusOptions($status, 'Statistics');
  855:     $Str .= '</td>'."\n";
  856:     #
  857:     $Str .= '</tr></tbody></table>'."\n";
  858:     $Str .= '<hr>'."\n";
  859:     #
  860:     return $Str;
  861: }
  862: 
  863: ##############################################
  864: ##############################################
  865: sub handler {
  866:     my $r=shift;
  867:     my $c = $r->connection();
  868:     #
  869:     # Check for overloading
  870:     my $loaderror=&Apache::lonnet::overloaderror($r);
  871:     if ($loaderror) { return $loaderror; }
  872:     $loaderror=
  873:        &Apache::lonnet::overloaderror($r,
  874:          $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
  875:     if ($loaderror) { return $loaderror; }
  876:     #
  877:     # Check for access
  878:     unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
  879:         $ENV{'user.error.msg'}=
  880:         $r->uri.":vgr:0:0:Cannot view grades for complete course";
  881:         return HTTP_NOT_ACCEPTABLE;
  882:     }
  883:     #
  884:     # Set document type for header only
  885:     if($r->header_only) {
  886:         if ($ENV{'browser.mathml'}) {
  887:             $r->content_type('text/xml');
  888:         } else {
  889:             $r->content_type('text/html');
  890:         }
  891:         &Apache::loncommon::no_cache($r);
  892:         $r->send_http_header;
  893:         return OK;
  894:     }
  895:     #
  896:     # Send the header
  897:     $r->content_type('text/html');
  898:     $r->send_http_header;
  899:     #
  900:     # Extract form elements from query string
  901:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  902:                                             ['sort','reportSelected',
  903:                                              'StudentAssessmentStudent']);
  904:     if (! exists($ENV{'form.reportSelected'})) {
  905:         $ENV{'form.reportSelected'} = 'student_assessment';
  906:     }
  907:     #
  908:     # Give the LON-CAPA page header
  909:     $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
  910:     $r->rflush();
  911:     #
  912:     if (! &Apache::lonmysql::verify_sql_connection()) {
  913:         my $serveradmin = $r->dir_config('lonAdmEMail');
  914:         $r->print(<<END);
  915: <h2><font color="Red">Unable to connect to database!</font></h2>
  916: <p>
  917: Please notify the server administrator <b>$serveradmin</b>.
  918: </p><p>
  919: Course Statistics and Charts cannot be retrieved until the database is
  920: restarted.  Your data is intact but cannot be displayed at this time.
  921: </p>
  922: </body>
  923: </html>
  924: END
  925:         return;
  926:     }
  927:     #
  928:     # Set up the statistics and chart environment
  929:     &PrepareClasslist($r);
  930:     &PrepareCourseData($r);
  931:     #
  932:     # Begin form output
  933:     $r->print('<form name="Statistics" ');
  934:     $r->print('method="post" action="/adm/statistics">');
  935:     #
  936:     # Print main menu
  937:     my %reports = ('classlist'          => 'Class list',
  938:                    'problem_statistics' => 'Problem Statistics',
  939:                    'student_assessment' => 'Problem Status Chart',
  940:                    'percentage'         => 'Correct-problems Plot',
  941:                    'option_response'    => 'Option Response Analysis',
  942: #                   'activitylog'        => 'Activity Log',
  943:                    );
  944:     $r->print(&CreateMainMenu($ENV{'form.status'},
  945:                               \%reports,$ENV{'form.reportSelected'}));
  946:     $r->rflush();
  947:     #
  948:     my $GoToPage = $ENV{'form.reportSelected'};
  949:     if($GoToPage eq 'activitylog') {
  950: #        &Apache::lonproblemstatistics::Activity();
  951:     } elsif($GoToPage eq 'problem_statistics') {
  952:         &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
  953:     } elsif($GoToPage eq 'option_response') {
  954: #        &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
  955:     } elsif($GoToPage eq 'student_assessment') {
  956:         &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
  957:     } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
  958: #        &Apache::lonproblemstatistics::BuildGraphicChart($r,$c);
  959:     } elsif($GoToPage eq 'classlist') {
  960:         &DisplayClasslist($r);
  961:     } elsif($GoToPage eq 'Correct-problems Plot') {
  962: #	&Apache::lonpercentage::BuildPercentageGraph($r,$c);
  963:     }
  964:     #
  965:     $r->print("</form>\n");
  966:     $r->print("</body>\n</html>\n");
  967:     $r->rflush();
  968:     #
  969:     return OK;
  970: }
  971: 
  972: 1;
  973: 
  974: #######################################################
  975: #######################################################
  976: 
  977: =pod
  978: 
  979: =back
  980: 
  981: =cut
  982: 
  983: #######################################################
  984: #######################################################
  985: 
  986: __END__
  987: 

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