Annotation of loncom/interface/lonchart.pm, revision 1.60

1.1       www         1: # The LearningOnline Network with CAPA
1.25      minaeibi    2: # (Publication Handler
                      3: #
1.60    ! stredwic    4: # $Id: lonchart.pm,v 1.59 2002/07/09 15:43:49 stredwic Exp $
1.25      minaeibi    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: #
1.1       www        28: # Homework Performance Chart
                     29: #
                     30: # (Navigate Maps Handler
                     31: #
                     32: # (Page Handler
                     33: #
                     34: # (TeX Content Handler
1.27      minaeibi   35: # YEAR=2000
1.1       www        36: # 05/29/00,05/30 Gerd Kortemeyer)
                     37: # 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
                     38: # 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16 Gerd Kortemeyer)
1.27      minaeibi   39: # YEAR=2001
1.14      minaeibi   40: # 3/1/1,6/1,17/1,29/1,30/1,31/1 Gerd Kortemeyer)
1.5       minaeibi   41: # 7/10/01 Behrouz Minaei
1.6       www        42: # 9/8 Gerd Kortemeyer
1.27      minaeibi   43: # 10/1, 10/19, 11/17, 11/22, 11/24, 11/28 12/18 Behrouz Minaei
                     44: # YEAR=2002
1.33      minaeibi   45: # 2/1, 2/6, 2/19, 2/28 Behrouz Minaei
1.26      minaeibi   46: #
                     47: ###
1.1       www        48: 
1.51      stredwic   49: =pod
                     50: 
1.55      stredwic   51: =head1 NAME
                     52: 
                     53: lonchart
                     54: 
                     55: =head1 SYNOPSIS
                     56: 
                     57: Quick display of students grades for a course in a compressed table format.
                     58: 
                     59: =head1 DESCRIPTION
                     60: 
                     61: This module process all student grades for a course and turns them into a 
                     62: table like structure.
                     63: 
                     64: This is part of the LearningOnline Network with CAPA project
                     65: described at http://www.lon-capa.org
                     66: 
                     67: lonchart presents the user with a condensed view all a course's data.  The
                     68: class title, the number of students, and the date for the last update of the
                     69: displayed data.  There is also a legend that describes the chart values.  
                     70: 
                     71: For each valid grade for a student is linked with a submission record for that
                     72: problem.  The ability to add and remove columns of data from the chart was
                     73: added for reducing the burden of having to scroll through large quantities
                     74: of data.  The interface also allows for sorting of students by username,
                     75: last name, and section number of class.  Active and expired students are
                     76: also available.
                     77: 
                     78: The interface is controlled by three primary buttons: Recalculate Chart, 
                     79: Refresh Chart, and Reset Selections.  Recalculate Chart will update 
                     80: the chart to the most recent data and keep the display settings for the chart
                     81: the same.  Refresh Chart is used to redisplay the chart after selecting
                     82: different output formatting.  Reset Selections is used to set the chart
                     83: display options back to default values.
                     84: 
                     85: =head1 CODE LAYOUT DESCRIPTION
                     86: 
1.59      stredwic   87: The code is broken down into three components: formatting data for printing,
                     88: helper functions, and the central processing functions.  The module is broken 
                     89: into chunks for each component.
1.55      stredwic   90: 
                     91: =head1 PACKAGES USED
                     92: 
                     93:  Apache::Constants qw(:common :http)
                     94:  Apache::lonnet()
                     95:  Apache::loncommon()
                     96:  HTML::TokeParser
                     97:  GDBM_File
                     98: 
1.51      stredwic   99: =cut
                    100: 
1.1       www       101: package Apache::lonchart;
                    102: 
                    103: use strict;
                    104: use Apache::Constants qw(:common :http);
                    105: use Apache::lonnet();
1.28      albertel  106: use Apache::loncommon();
1.59      stredwic  107: use Apache::loncoursedata();
1.1       www       108: use HTML::TokeParser;
                    109: use GDBM_File;
                    110: 
1.51      stredwic  111: #my $jr; 
1.55      stredwic  112: 
                    113: =pod
                    114: 
                    115: =head1 FORMAT DATA FOR PRINTING
                    116: 
                    117: =cut
                    118: 
1.44      stredwic  119: # ----- FORMAT PRINT DATA ----------------------------------------------
1.1       www       120: 
1.55      stredwic  121: =pod
                    122: 
                    123: =item &FormatStudentInformation()
                    124: 
                    125: This function produces a formatted string of the student's information:
                    126: username, domain, section, full name, and PID.
                    127: 
                    128: =over 4
                    129: 
                    130: Input: $cache, $name, $studentInformation, $spacePadding
                    131: 
                    132: $cache: This is a pointer to a hash that is tied to the cached data
                    133: 
                    134: $name:  The name and domain of the current student in name:domain format
                    135: 
                    136: $studentInformation: A pointer to an array holding the names used to
                    137: 
                    138: remove data from the hash.  They represent the name of the data to be removed.
                    139: 
                    140: $spacePadding: Extra spaces that represent the space between columns
                    141: 
                    142: Output: $Str
                    143: 
                    144: $Str: Formatted string.
                    145: 
                    146: =back
                    147: 
                    148: =cut
                    149: 
1.44      stredwic  150: sub FormatStudentInformation {
1.51      stredwic  151:     my ($cache,$name,$studentInformation,$spacePadding)=@_;
1.50      stredwic  152:     my $Str='';
1.60    ! stredwic  153:     my $data;
1.44      stredwic  154: 
1.49      stredwic  155:     for(my $index=0; $index<(scalar @$studentInformation); $index++) {
1.59      stredwic  156:         if(!&ShouldShowColumn($cache, 'ChartHeading'.$index)) {
1.49      stredwic  157:             next;
                    158:         }
1.60    ! stredwic  159:         $data=$cache->{$name.':'.$studentInformation->[$index]};
1.44      stredwic  160: 	$Str .= $data;
                    161: 
                    162: 	my @dataLength=split(//,$data);
                    163: 	my $length=scalar @dataLength;
1.49      stredwic  164: 	$Str .= (' 'x($cache->{$studentInformation->[$index].'Length'}-
                    165:                       $length));
1.44      stredwic  166: 	$Str .= $spacePadding;
                    167:     }
                    168: 
                    169:     return $Str;
                    170: }
                    171: 
1.55      stredwic  172: =pod
                    173: 
                    174: =item &FormatStudentData()
                    175: 
                    176: First, FormatStudentInformation is called and prefixes the course information.
                    177: This function produces a formatted string of the student's course information.
                    178: Each column of data represents all the problems for a given sequence.  For
                    179: valid grade data, a link is created for that problem to a submission record
                    180: for that problem.
                    181: 
                    182: =over 4
                    183: 
                    184: Input: $name, $studentInformation, $spacePadding, $ChartDB
                    185: 
                    186: $name: The name and domain of the current student in name:domain format
                    187: 
                    188: $studentInformation: A pointer to an array holding the names used to 
                    189: remove data from the hash.  They represent 
                    190: the name of the data to be removed.
                    191: 
                    192: $spacePadding: Extra spaces that represent the space between columns
                    193: 
                    194: $ChartDB: The name of the cached data database which will be tied to that 
                    195: database.
                    196: 
                    197: Output: $Str
                    198: 
                    199: $Str: Formatted string that is an entire row of the chart.  It is a 
                    200: concatenation of student information and student course information.
                    201: 
                    202: =back
                    203: 
                    204: =cut
                    205: 
1.44      stredwic  206: sub FormatStudentData {
1.55      stredwic  207:     my ($name,$studentInformation,$spacePadding,$ChartDB)=@_;
1.43      stredwic  208:     my ($sname,$sdom) = split(/\:/,$name);
                    209:     my $Str;
1.44      stredwic  210:     my %CacheData;
1.43      stredwic  211: 
1.44      stredwic  212:     unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
                    213:         return '';
                    214:     }
1.60    ! stredwic  215: 
        !           216: #    my $section = &Apache::loncoursedata::CheckStatus($name, \%CacheData, 
        !           217: #                                               $CacheData{'form.Status'});
        !           218: #    if($section eq 'not found') {
        !           219: #        untie(%CacheData);
        !           220: #        return;
        !           221: #    }
        !           222: 
1.43      stredwic  223:     # Handle Student information ------------------------------------------
1.44      stredwic  224:     # Handle user data
                    225:     $Str=&FormatStudentInformation(\%CacheData, $name, $studentInformation, 
1.51      stredwic  226:                                    $spacePadding);
1.44      stredwic  227: 
1.43      stredwic  228:     # Handle errors
1.44      stredwic  229:     if($CacheData{$name.':error'} =~ /environment/) {
1.50      stredwic  230:         $Str .= '<br>';
1.44      stredwic  231:         untie(%CacheData);
                    232:         return $Str;
                    233:     }
1.43      stredwic  234: 
1.44      stredwic  235:     if($CacheData{$name.':error'} =~ /course/) {
1.50      stredwic  236:         $Str .= '<br>';
1.44      stredwic  237:         untie(%CacheData);
1.50      stredwic  238:         return $Str;
1.40      stredwic  239:     }
                    240: 
1.43      stredwic  241:     # Handle problem data ------------------------------------------------
1.44      stredwic  242:     my $Version;
                    243:     my $problemsCorrect = 0;
                    244:     my $totalProblems   = 0;
                    245:     my $problemsSolved  = 0;
                    246:     my $numberOfParts   = 0;
                    247:     foreach my $sequence (split(/\:/,$CacheData{'orderedSequences'})) {
1.59      stredwic  248:         if(!&ShouldShowColumn(\%CacheData, 'ChartSequence'.$sequence)) {
1.49      stredwic  249:             next;
                    250:         }
                    251: 
1.44      stredwic  252: 	my $characterCount=0;
                    253: 	foreach my $problemID (split(/\:/,$CacheData{$sequence.':problems'})) {
                    254: 	    my $problem = $CacheData{$problemID.':problem'};
                    255: 	    my $LatestVersion = $CacheData{$name.":version:$problem"};
                    256: 
1.58      stredwic  257:             # Output blanks for all the parts of this problem if there
                    258:             # is no version information about the current problem.
1.44      stredwic  259:             if(!$LatestVersion) {
                    260:                 foreach my $part (split(/\:/,$CacheData{$sequence.':'.
                    261:                                                         $problemID.
                    262:                                                         ':parts'})) {
                    263:                     $Str .= ' ';
                    264:                     $totalProblems++;
                    265:                     $characterCount++;
                    266:                 }
                    267:                 next;
                    268:             }
                    269: 
                    270:             my %partData=undef;
1.58      stredwic  271:             # Initialize part data, display skips correctly
                    272:             # Skip refers to when a student made no submissions on that
                    273:             # part/problem.
1.44      stredwic  274:             foreach my $part (split(/\:/,$CacheData{$sequence.':'.
                    275:                                                     $problemID.
                    276:                                                     ':parts'})) {
                    277:                 $partData{$part.':tries'}=0;
                    278:                 $partData{$part.':code'}=' ';
                    279:             }
1.58      stredwic  280: 
                    281:             # Looping through all the versions of each part, starting with the
                    282:             # oldest version.  Basically, it gets the most recent 
                    283:             # set of grade data for each part.
1.44      stredwic  284: 	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
                    285:                 foreach my $part (split(/\:/,$CacheData{$sequence.':'.
                    286:                                                         $problemID.
                    287:                                                         ':parts'})) {
                    288: 
                    289:                     if(!defined($CacheData{$name.":$Version:$problem".
                    290:                                                ":resource.$part.solved"})) {
1.58      stredwic  291:                         # No grade for this submission, so skip
1.44      stredwic  292:                         next;
                    293:                     }
                    294: 
                    295:                     my $tries=0;
                    296:                     my $code=' ';
                    297: 
                    298:                     $tries = $CacheData{$name.":$Version:$problem".
                    299:                                         ":resource.$part.tries"};
                    300:                     $partData{$part.':tries'}=($tries) ? $tries : 0;
                    301: 
                    302:                     my $val = $CacheData{$name.":$Version:$problem".
                    303:                                          ":resource.$part.solved"};
                    304:                     if    ($val eq 'correct_by_student')   {$code = '*';} 
                    305:                     elsif ($val eq 'correct_by_override')  {$code = '+';}
                    306:                     elsif ($val eq 'incorrect_attempted')  {$code = '.';} 
                    307:                     elsif ($val eq 'incorrect_by_override'){$code = '-';}
                    308:                     elsif ($val eq 'excused')              {$code = 'x';}
                    309:                     elsif ($val eq 'ungraded_attempted')   {$code = '#';}
                    310:                     else                                   {$code = ' ';}
                    311:                     $partData{$part.':code'}=$code;
                    312:                 }
                    313:             }
                    314: 
1.58      stredwic  315:             # All grades (except for versionless parts) are displayed as links
                    316:             # to their submission record.  Loop through all the parts for the
                    317:             # current problem in the correct order and prepare the output links
1.44      stredwic  318:             $Str.='<a href="/adm/grades?symb='.
                    319:                 &Apache::lonnet::escape($problem).
                    320:                 '&student='.$sname.'&domain='.$sdom.'&command=submission">'; 
                    321:             foreach(split(/\:/,$CacheData{$sequence.':'.$problemID.
                    322:                                           ':parts'})) {
                    323:                 if($partData{$_.':code'} eq '*') {
                    324:                     $problemsCorrect++;
                    325:                     if (($partData{$_.':tries'}<10) &&
                    326:                         ($partData{$_.':tries'} ne '')) {
                    327:                         $partData{$_.':code'}=$partData{$_.':tries'};
                    328:                     }
                    329:                 } elsif($partData{$_.':code'} eq '+') {
                    330:                     $problemsCorrect++;
                    331:                 }
                    332: 
                    333:                 $Str .= $partData{$_.':code'};
                    334:                 $characterCount++;
                    335: 
                    336:                 if($partData{$_.':code'} ne 'x') {
                    337:                     $totalProblems++;
                    338:                 }
                    339:             }
                    340:             $Str.='</a>';
                    341:         }
                    342: 
1.58      stredwic  343:         # Output the number of correct answers for the current sequence.
                    344:         # This part takes up 6 character slots, but is formated right 
                    345:         # justified.
1.44      stredwic  346:         my $spacesNeeded=$CacheData{$sequence.':columnWidth'}-$characterCount;
                    347:         $spacesNeeded -= 3;
                    348:         $Str .= (' 'x$spacesNeeded);
                    349: 
                    350: 	my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
                    351: 	$Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
                    352: 	$problemsSolved += $problemsCorrect;
                    353: 	$problemsCorrect=0;
                    354: 
                    355:         $Str .= $spacePadding;
                    356:     }
1.11      minaeibi  357: 
1.58      stredwic  358:     # Output the total correct problems over the total number of problems.
                    359:     # I don't like this type of formatting, but it is a solution.  Need
                    360:     # a way to dynamically determine the space requirements.
1.51      stredwic  361:     my $outputProblemsSolved = sprintf( "%4d", $problemsSolved );
                    362:     my $outputTotalProblems  = sprintf( "%4d", $totalProblems );
                    363:     $Str .= '<font color="#000088">'.$outputProblemsSolved.
                    364: 	    ' / '.$outputTotalProblems.'</font><br>';
1.39      stredwic  365: 
1.44      stredwic  366:     untie(%CacheData);
                    367:     return $Str;
                    368: }
1.43      stredwic  369: 
1.55      stredwic  370: =pod
                    371: 
                    372: =item &CreateTableHeadings()
                    373: 
                    374: This function generates the column headings for the chart.
                    375: 
                    376: =over 4
                    377: 
                    378: Inputs: $CacheData, $studentInformation, $headings, $spacePadding
                    379: 
                    380: $CacheData: pointer to a hash tied to the cached data database
                    381: 
                    382: $studentInformation: a pointer to an array containing the names of the data 
                    383: held in a column and is used as part of a key into $CacheData
                    384: 
                    385: $headings: The names of the headings for the student information
                    386: 
                    387: $spacePadding: The spaces to go between columns
                    388: 
                    389: Output: $Str
                    390: 
                    391: $Str: A formatted string of the table column headings.
                    392: 
                    393: =back
                    394: 
                    395: =cut
                    396: 
1.44      stredwic  397: sub CreateTableHeadings {
1.51      stredwic  398:     my ($CacheData,$studentInformation,$headings,$spacePadding)=@_;
1.53      stredwic  399:     my $Str='<tr>';
1.43      stredwic  400: 
1.44      stredwic  401:     for(my $index=0; $index<(scalar @$headings); $index++) {
1.59      stredwic  402:         if(!&ShouldShowColumn($CacheData, 'ChartHeading'.$index)) {
1.49      stredwic  403:             next;
                    404:         }
                    405: 
1.53      stredwic  406:         $Str .= '<td align="left"><pre>';
1.44      stredwic  407: 	my $data=$$headings[$index];
                    408: 	$Str .= $data;
                    409: 
                    410: 	my @dataLength=split(//,$data);
                    411: 	my $length=scalar @dataLength;
                    412: 	$Str .= (' 'x($CacheData->{$$studentInformation[$index].'Length'}-
                    413:                       $length));
                    414: 	$Str .= $spacePadding;
1.53      stredwic  415:         $Str .= '</pre></td>';
1.44      stredwic  416:     }
                    417: 
                    418:     foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) {
1.59      stredwic  419:         if(!&ShouldShowColumn($CacheData, 'ChartSequence'.$sequence)) {
1.49      stredwic  420:             next;
                    421:         }
                    422: 
1.53      stredwic  423:         $Str .= '<td align="left"><pre>';
1.49      stredwic  424:         my $name = $CacheData->{$sequence.':title'};
                    425: 	$Str .= $name;
1.44      stredwic  426: 	my @titleLength=split(//,$CacheData->{$sequence.':title'});
                    427: 	my $leftover=$CacheData->{$sequence.':columnWidth'}-
                    428:                      (scalar @titleLength);
                    429: 	$Str .= (' 'x$leftover);
                    430: 	$Str .= $spacePadding;
1.53      stredwic  431:         $Str .= '</pre></td>';
1.1       www       432:     }
1.39      stredwic  433: 
1.54      stredwic  434:     $Str .= '<td><pre>Total Solved/Total Problems</pre></td>';
1.55      stredwic  435:     $Str .= '</tr>';
1.11      minaeibi  436: 
1.43      stredwic  437:     return $Str;
                    438: }
                    439: 
1.55      stredwic  440: =pod
                    441: 
                    442: =item &CreateColumnSelectionBox()
                    443: 
                    444: If there are columns not being displayed then this selection box is created
                    445: with a list of those columns.  When selections are made and the page 
                    446: refreshed, the columns will be removed from this box and the column is
                    447: put back in the chart.  If there is no columns to select, no row is added
                    448: to the interface table.
                    449: 
                    450: =over 4
                    451: Input: $CacheData, $headings
                    452: 
                    453: 
                    454: $CacheData: A pointer to a hash tied to the cached data
                    455: 
                    456: $headings:  An array of the names of the columns for the student information.  
                    457: They are used for displaying which columns are missing.
                    458: 
                    459: Output: $notThere
                    460: 
                    461: $notThere: The string contains one row of a table.  The first column has the 
                    462: name of the selection box.  The second contains the selection box 
                    463: which has a size of four.
                    464: 
                    465: =back
                    466: 
                    467: =cut
                    468: 
1.49      stredwic  469: sub CreateColumnSelectionBox {
1.55      stredwic  470:     my ($CacheData,$headings)=@_;
1.46      stredwic  471: 
1.49      stredwic  472:     my $missing=0;
1.50      stredwic  473:     my $notThere='<tr><td align="right"><b>Select column to view:</b>';
1.49      stredwic  474:     my $name;
1.50      stredwic  475:     $notThere .= '<td align="left">';
1.59      stredwic  476:     $notThere .= '<select name="ChartReselect" size="4" multiple="true">'."\n";
1.46      stredwic  477: 
                    478:     for(my $index=0; $index<(scalar @$headings); $index++) {
1.59      stredwic  479:         if(&ShouldShowColumn($CacheData, 'ChartHeading'.$index)) {
1.49      stredwic  480:             next;
                    481:         }
                    482:         $name = $headings->[$index];
1.59      stredwic  483:         $notThere .= '<option value="ChartHeading'.$index.'">';
1.49      stredwic  484:         $notThere .= $name.'</option>'."\n";
                    485:         $missing++;
                    486:     }
                    487: 
                    488:     foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) {
1.59      stredwic  489:         if(&ShouldShowColumn($CacheData, 'ChartSequence'.$sequence)) {
1.49      stredwic  490:             next;
                    491:         }
                    492:         $name = $CacheData->{$sequence.':title'};
1.59      stredwic  493:         $notThere .= '<option value="ChartSequence'.$sequence.'">';
1.49      stredwic  494:         $notThere .= $name.'</option>'."\n";
                    495:         $missing++;
                    496:     }
                    497: 
                    498:     if($missing) {
1.50      stredwic  499:         $notThere .= '</select>';
1.49      stredwic  500:     } else {
1.50      stredwic  501:         $notThere='<tr><td>';
1.49      stredwic  502:     }
                    503: 
1.55      stredwic  504:     return $notThere.'</td></tr>';
1.49      stredwic  505: }
                    506: 
1.55      stredwic  507: =pod
                    508: 
                    509: =item &CreateColumnSelectors()
                    510: 
                    511: This function generates the checkboxes above the column headings.  The 
                    512: column will be removed if the checkbox is unchecked.
                    513: 
                    514: =over 4
                    515: 
                    516: Input: $CacheData, $headings
                    517: 
                    518: $CacheData: A pointer to a hash tied to the cached data
                    519: 
                    520: $headings:  An array of the names of the columns for the student 
                    521: information.  They are used to know what are the student information columns
                    522: 
                    523: Output: $present
                    524: 
                    525: $present: The string contains the first row of a table.  Each column contains
                    526: a checkbox which is left justified.  Currently left justification is used
                    527: for consistency of location over the column in which it presides.
                    528: 
                    529: =back
                    530: 
                    531: =cut
                    532: 
1.49      stredwic  533: sub CreateColumnSelectors {
1.55      stredwic  534:     my ($CacheData,$headings)=@_;
1.46      stredwic  535: 
1.49      stredwic  536:     my $found=0;
                    537:     my ($name, $length, $position);
1.54      stredwic  538: 
1.55      stredwic  539:     my $present = '<tr>';
1.49      stredwic  540:     for(my $index=0; $index<(scalar @$headings); $index++) {
1.59      stredwic  541:         if(!&ShouldShowColumn($CacheData, 'ChartHeading'.$index)) {
1.49      stredwic  542:             next;
                    543:         }
1.54      stredwic  544:         $present .= '<td align="left">';
1.49      stredwic  545:         $present .= '<input type="checkbox" checked="on" ';
1.59      stredwic  546:         $present .= 'name="ChartHeading'.$index.'" />';
1.53      stredwic  547:         $present .= '</td>';
1.49      stredwic  548:         $found++;
1.46      stredwic  549:     }
                    550: 
                    551:     foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) {
1.59      stredwic  552:         if(!&ShouldShowColumn($CacheData, 'ChartSequence'.$sequence)) {
1.49      stredwic  553:             next;
                    554:         }
1.54      stredwic  555:         $present .= '<td align="left">';
1.49      stredwic  556:         $present .= '<input type="checkbox" checked="on" ';
1.59      stredwic  557:         $present .= 'name="ChartSequence'.$sequence.'" />';
1.53      stredwic  558:         $present .= '</td>';
1.49      stredwic  559:         $found++;
                    560:     }
                    561: 
1.54      stredwic  562:     if(!$found) {
                    563:         $present = '';
1.46      stredwic  564:     }
                    565: 
1.54      stredwic  566:     return $present.'<td></td></tr></form>'."\n";;
1.46      stredwic  567: }
                    568: 
1.55      stredwic  569: =pod
                    570: 
                    571: =item &CreateForm()
                    572: 
                    573: The interface for this module consists primarily of the controls in this
                    574: function.  The student status selection (active, expired, any) is set here.
                    575: The sort buttons: username, last name, and section are set here.  The
                    576: other buttons are Recalculate Chart, Refresh Chart, and Reset Selections.
                    577: These controls are in a table to clean up the interface.
                    578: 
                    579: =over 4
                    580: 
                    581: Input: $CacheData
                    582: 
                    583: $CacheData is a hash pointer to tied database for cached data.
                    584: 
                    585: Output: $Ptr
                    586: 
                    587: $Ptr is a string containing all the html for the above mentioned buttons.
                    588: 
                    589: =back
                    590: 
                    591: =cut
                    592: 
1.43      stredwic  593: sub CreateForm {
1.51      stredwic  594:     my ($CacheData)=@_;
1.43      stredwic  595:     my $OpSel1='';
                    596:     my $OpSel2='';
                    597:     my $OpSel3='';
1.60    ! stredwic  598:     my $Status = $CacheData->{'form.Status'};
1.43      stredwic  599:     if ( $Status eq 'Any' ) { $OpSel3='selected'; }
                    600:     elsif ($Status eq 'Expired' ) { $OpSel2 = 'selected'; }
                    601:     else { $OpSel1 = 'selected'; }
                    602: 
1.59      stredwic  603:     my $Ptr .= '<form name="ChartStat" method="post" action="/adm/chart" >';
                    604:     $Ptr .= "\n";
1.50      stredwic  605:     $Ptr .= '<tr><td align="right">';
                    606:     $Ptr .= '</td><td align="left">';
1.59      stredwic  607:     $Ptr .= '<input type="submit" name="ChartRecalculate" ';
1.50      stredwic  608:     $Ptr .= 'value="Recalculate Chart"/>'."\n";
1.43      stredwic  609:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
1.59      stredwic  610:     $Ptr .= '<input type="submit" name="ChartRefresh" ';
1.51      stredwic  611:     $Ptr .= 'value="Refresh Chart"/>'."\n";
                    612:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
1.59      stredwic  613:     $Ptr .= '<input type="submit" name="ChartReset" ';
1.51      stredwic  614:     $Ptr .= 'value="Reset Selections"/></td>'."\n";
1.50      stredwic  615:     $Ptr .= '</tr><tr><td align="right">';
                    616:     $Ptr .= '<b> Sort by: </b>'."\n";
                    617:     $Ptr .= '</td><td align="left">';
1.59      stredwic  618:     $Ptr .= '<input type="submit" name="ChartSort" value="User Name" />'."\n";
1.43      stredwic  619:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
1.59      stredwic  620:     $Ptr .= '<input type="submit" name="ChartSort" value="Last Name" />'."\n";
1.43      stredwic  621:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
1.59      stredwic  622:     $Ptr .= '<input type="submit" name="ChartSort" value="Section"/>'."\n";
1.50      stredwic  623:     $Ptr .= '</td></tr><tr><td align="right">';
1.43      stredwic  624:     $Ptr .= '<b> Student Status: &nbsp; </b>'."\n".
1.50      stredwic  625:             '</td><td align="left">'.
1.60    ! stredwic  626:             '<select name="Status">'. 
1.43      stredwic  627:             '<option '.$OpSel1.' >Active</option>'."\n".
                    628:             '<option '.$OpSel2.' >Expired</option>'."\n".
                    629: 	    '<option '.$OpSel3.' >Any</option> </select> '."\n";
1.50      stredwic  630:     $Ptr .= '</td></tr>';
1.44      stredwic  631: 
                    632:     return $Ptr;
                    633: }
                    634: 
1.55      stredwic  635: =pod
                    636: 
                    637: =item &CreateLegend()
                    638: 
                    639: This function returns a formatted string containing the legend for the
                    640: chart.  The legend describes the symbols used to represent grades for
                    641: problems.
                    642: 
                    643: =cut
                    644: 
1.44      stredwic  645: sub CreateLegend {
1.50      stredwic  646:     my $Str = "<p><pre>".
                    647:               "1..9: correct by student in 1..9 tries\n".
1.44      stredwic  648:               "   *: correct by student in more than 9 tries\n".
                    649: 	      "   +: correct by override\n".
                    650:               "   -: incorrect by override\n".
                    651: 	      "   .: incorrect attempted\n".
                    652: 	      "   #: ungraded attempted\n".
                    653:               "    : not attempted\n".
1.50      stredwic  654: 	      "   x: excused".
                    655:               "</pre><p>"; 
1.44      stredwic  656:     return $Str;
                    657: }
                    658: 
1.55      stredwic  659: =pod
                    660: 
                    661: =item &StartDocument()
                    662: 
                    663: Returns a string containing the header information for the chart: title,
                    664: logo, and course title.
                    665: 
                    666: =cut
                    667: 
1.44      stredwic  668: sub StartDocument {
1.59      stredwic  669:     my ($title, $header)=@_;
1.44      stredwic  670:     my $Str = '';
                    671:     $Str .= '<html>';
                    672:     $Str .= '<head><title>';
1.59      stredwic  673:     $Str .= $title.'</title></head>';
1.44      stredwic  674:     $Str .= '<body bgcolor="#FFFFFF">';
                    675:     $Str .= '<script>window.focus();</script>';
                    676:     $Str .= '<img align=right src=/adm/lonIcons/lonlogos.gif>';
1.59      stredwic  677:     $Str .= '<h1>'.$header.'</h1>';
1.50      stredwic  678:     $Str .= '<h1>'.$ENV{'course.'.$ENV{'request.course.id'}.'.description'};
                    679:     $Str .= '</h1>';
1.44      stredwic  680: 
                    681:     return $Str;
                    682: }
                    683: 
                    684: # ----- END FORMAT PRINT DATA ------------------------------------------
                    685: 
1.55      stredwic  686: =pod
                    687: 
1.59      stredwic  688: =head1 HELPER FUNCTIONS
1.55      stredwic  689: 
1.59      stredwic  690: These are just a couple of functions do various odd and end 
                    691: jobs.
1.55      stredwic  692: 
                    693: =cut
                    694: 
1.59      stredwic  695: # ----- HELPER FUNCTIONS -----------------------------------------------
1.55      stredwic  696: 
                    697: =pod
                    698: 
                    699: =item &ProcessFormData()
                    700: 
                    701: Cache form data and set default form data (sort, status, heading.$number,
                    702: sequence.$number, reselect, reset, recalculate, and refresh)
                    703: 
                    704: =over 4
                    705: 
                    706: Input: $ChartDB, $isCached
                    707: 
                    708: $ChartDB: The name of the database for cached data
                    709: 
                    710: $isCached: Is there already data for this course cached.  This is used in 
                    711: conjunction with the absence of all form data to know to display all selection 
                    712: types.
                    713: 
                    714: Output: None
                    715: 
                    716: =back
                    717: 
                    718: =cut
                    719: 
1.58      stredwic  720: # For all data, if ENV data doesn't exist for it, default values is used.
1.55      stredwic  721: sub ProcessFormData {
                    722:     my ($ChartDB, $isCached)=@_;
                    723:     my %CacheData;
                    724: 
                    725:     if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
1.59      stredwic  726:         # Ignore $ENV{'form.ChartRefresh'}
                    727:         # Ignore $ENV{'form.ChartRecalculate'}
1.58      stredwic  728: 
1.59      stredwic  729:         if(defined($ENV{'form.ChartSort'})) {
                    730:             $CacheData{'form.ChartSort'}=$ENV{'form.ChartSort'};
                    731:         } elsif(!defined($CacheData{'form.ChartSort'})) {
                    732:             $CacheData{'form.ChartSort'}='username';
1.55      stredwic  733:         }
                    734: 
1.60    ! stredwic  735:         if(defined($ENV{'form.Status'})) {
        !           736:             $CacheData{'form.Status'}=$ENV{'form.Status'};
        !           737:         } elsif(!defined($CacheData{'form.Status'})) {
        !           738:             $CacheData{'form.Status'}='Active';
1.55      stredwic  739:         }
                    740: 
1.58      stredwic  741:         # $found checks for any instances of form data in the ENV.  If it is
                    742:         # missing I assume the chrt button on the remote has been pressed.
1.55      stredwic  743:         my @headings=();
                    744:         my @sequences=();
                    745:         my $found=0;
                    746:         foreach (keys(%ENV)) {
1.59      stredwic  747:             if(/form\.ChartHeading/) {
1.55      stredwic  748:                 $found++;
                    749:                 push(@headings, $_);
1.59      stredwic  750:             } elsif(/form\.ChartSequence/) {
1.55      stredwic  751:                 $found++;
                    752:                 push(@sequences, $_);
                    753:             } elsif(/form\./) {
                    754:                 $found++;
                    755:             }
                    756:         }
                    757: 
                    758:         if($found) {
1.59      stredwic  759:             $CacheData{'form.ChartHeadings'}=join(":::",@headings);
                    760:             $CacheData{'form.ChartSequences'}=join(":::",@sequences);
1.55      stredwic  761:         }
                    762: 
1.59      stredwic  763:         if(defined($ENV{'form.ChartReselect'})) {
                    764:             my @reselected = (ref($ENV{'form.ChartReselect'}) ? 
                    765:                               @{$ENV{'form.ChartReselect'}}
                    766:                               : ($ENV{'form.ChartReselect'}));
1.55      stredwic  767:             foreach (@reselected) {
1.59      stredwic  768:                 if(/ChartHeading/) {
                    769:                     $CacheData{'form.ChartHeadings'}.=":::".$_;
                    770:                 } elsif(/ChartSequence/) {
                    771:                     $CacheData{'form.ChartSequences'}.=":::".$_;
1.55      stredwic  772:                 }
                    773:             }
                    774:         }
                    775: 
1.58      stredwic  776:         # !$found and !$isCached are how I determine if the chrt button
                    777:         # on the remote was pressed and needs to reset all the selections
1.59      stredwic  778:         if(defined($ENV{'form.ChartReset'}) || (!$found && !$isCached)) {
                    779:             $CacheData{'form.ChartReset'}='true';
1.60    ! stredwic  780:             $CacheData{'form.Status'}='Active';
1.59      stredwic  781:             $CacheData{'form.ChartSort'}='username';
                    782:             $CacheData{'form.ChartHeadings'}='ALLHEADINGS';
                    783:             $CacheData{'form.ChartSequences'}='ALLSEQUENCES';
1.55      stredwic  784:         } else {
1.59      stredwic  785:             $CacheData{'form.ChartReset'}='false';
1.55      stredwic  786:         }
                    787: 
                    788:         untie(%CacheData);
                    789:     }
                    790: 
                    791:     return;
                    792: }
                    793: 
                    794: =pod
                    795: 
                    796: =item &SpaceColumns()
                    797: 
                    798: Determines the width of all the columns in the chart.  It is based on
                    799: the max of the data for that column and its header.
                    800: 
                    801: =over 4
                    802: 
                    803: Input: $students, $studentInformation, $headings, $ChartDB
                    804: 
                    805: $students: An array pointer to a list of students (username:domain)
                    806: 
                    807: $studentInformatin: The type of data for the student information.  It is
                    808: used as part of the key in $CacheData.
                    809: 
                    810: $headings: The name of the student information columns.
                    811: 
                    812: $ChartDB: The name of the cache database which is opened for read/write.
                    813: 
                    814: Output: None - All data stored in cache.
                    815: 
                    816: =back
1.44      stredwic  817: 
1.55      stredwic  818: =cut
1.44      stredwic  819: 
                    820: sub SpaceColumns {
1.59      stredwic  821:     my ($students,$studentInformation,$headings,$cache)=@_;
1.44      stredwic  822: 
1.59      stredwic  823:     # Initialize Lengths
                    824:     for(my $index=0; $index<(scalar @$headings); $index++) {
                    825:         my @titleLength=split(//,$$headings[$index]);
                    826:         $cache->{$$studentInformation[$index].'Length'}=
                    827:             scalar @titleLength;
                    828:     }
1.44      stredwic  829: 
1.59      stredwic  830:     foreach my $name (@$students) {
                    831:         foreach (@$studentInformation) {
                    832:             my @dataLength=split(//,$cache->{$name.':'.$_});
                    833:             my $length=scalar @dataLength;
                    834:             if($length > $cache->{$_.'Length'}) {
                    835:                 $cache->{$_.'Length'}=$length;
1.44      stredwic  836:             }
                    837:         }
                    838:     }
                    839: 
                    840:     return;
                    841: }
                    842: 
1.55      stredwic  843: =pod
                    844: 
                    845: =item &SortStudents()
                    846: 
                    847: Determines which students to display and in which order.  Which are 
                    848: displayed are determined by their status(active/expired).  The order
                    849: is determined by the sort button pressed (default to username).  The
                    850: type of sorting is username, lastname, or section.
                    851: 
                    852: =over 4
                    853: 
                    854: Input: $students, $CacheData
                    855: 
                    856: $students: A array pointer to a list of students (username:domain)
                    857: 
                    858: $CacheData: A pointer to the hash tied to the cached data
                    859: 
                    860: Output: @order
                    861: 
                    862: @order: An ordered list of students (username:domain)
                    863: 
                    864: =back
                    865: 
                    866: =cut
                    867: 
1.44      stredwic  868: sub SortStudents {
1.48      stredwic  869:     my ($students,$CacheData)=@_;
1.44      stredwic  870: 
                    871:     my @sorted1Students=();
1.48      stredwic  872:     foreach (@$students) {
1.44      stredwic  873:         my ($end,$start)=split(/\:/,$CacheData->{$_.':date'});
                    874:         my $active=1;
                    875:         my $now=time;
1.60    ! stredwic  876:         my $Status=$CacheData->{'form.Status'};
1.44      stredwic  877:         $Status = ($Status) ? $Status : 'Active';
                    878:         if((($end) && $now > $end) && (($Status eq 'Active'))) { 
                    879:             $active=0; 
                    880:         }
                    881:         if(($Status eq 'Expired') && ($end == 0 || $now < $end)) {
                    882:             $active=0;
                    883:         }
                    884:         if($active) {
                    885:             push(@sorted1Students, $_);
                    886:         }
1.43      stredwic  887:     }
1.1       www       888: 
1.59      stredwic  889:     my $Pos = $CacheData->{'form.ChartSort'};
1.43      stredwic  890:     my %sortData;
                    891:     if($Pos eq 'Last Name') {
1.44      stredwic  892: 	for(my $index=0; $index<scalar @sorted1Students; $index++) {
                    893: 	    $sortData{$CacheData->{$sorted1Students[$index].':fullname'}}=
                    894: 		$sorted1Students[$index];
1.43      stredwic  895: 	}
                    896:     } elsif($Pos eq 'Section') {
1.44      stredwic  897: 	for(my $index=0; $index<scalar @sorted1Students; $index++) {
                    898: 	    $sortData{$CacheData->{$sorted1Students[$index].':section'}.
                    899: 		      $sorted1Students[$index]}=$sorted1Students[$index];
1.43      stredwic  900: 	}
                    901:     } else {
                    902: 	# Sort by user name
1.44      stredwic  903: 	for(my $index=0; $index<scalar @sorted1Students; $index++) {
                    904: 	    $sortData{$sorted1Students[$index]}=$sorted1Students[$index];
1.43      stredwic  905: 	}
                    906:     }
                    907: 
                    908:     my @order = ();
1.48      stredwic  909:     foreach my $key (sort(keys(%sortData))) {
1.43      stredwic  910: 	push (@order,$sortData{$key});
                    911:     }
1.33      minaeibi  912: 
1.43      stredwic  913:     return @order;
1.30      minaeibi  914: }
1.1       www       915: 
1.55      stredwic  916: =pod
                    917: 
                    918: =item &ShouldShowColumn()
                    919: 
                    920: Determine if a specified column should be shown on the chart.
                    921: 
                    922: =over 4
                    923: 
                    924: Input: $cache, $test
                    925: 
                    926: $cache: A pointer to the hash tied to the cached data
                    927: 
                    928: $test: The form name of the column (heading.$headingIndex) or 
                    929: (sequence.$sequenceIndex)
                    930: 
                    931: Output: 0 (false), 1 (true)
1.44      stredwic  932: 
1.55      stredwic  933: =back
1.1       www       934: 
1.55      stredwic  935: =cut
1.44      stredwic  936: 
1.49      stredwic  937: sub ShouldShowColumn {
1.51      stredwic  938:     my ($cache,$test)=@_;
1.49      stredwic  939: 
1.59      stredwic  940:     if($cache->{'form.ChartReset'} eq 'true') {
1.49      stredwic  941:         return 1;
                    942:     }
                    943: 
1.59      stredwic  944:     my $headings=$cache->{'form.ChartHeadings'};
                    945:     my $sequences=$cache->{'form.ChartSequences'};
1.51      stredwic  946:     if($headings eq 'ALLHEADINGS' || $sequences eq 'ALLSEQUENCES' ||
                    947:        $headings=~/$test/ || $sequences=~/$test/) {
1.49      stredwic  948:         return 1;
                    949:     }
                    950: 
1.51      stredwic  951:     return 0;
1.49      stredwic  952: }
                    953: 
1.55      stredwic  954: # ----- END HELPER FUNCTIONS --------------------------------------------
                    955: 
                    956: =pod
                    957: 
                    958: =head1 Handler and main function(BuildChart)
                    959: 
                    960: The handler does some initial error checking and then passes the torch to
                    961: BuildChart.  BuildChart calls all the appropriate functions to get the
                    962: job done.  These are the only two functions that use print ($r).  All other
                    963: functions return strings to BuildChart to be printed.
                    964: 
                    965: =cut
1.51      stredwic  966: 
1.55      stredwic  967: =pod
1.51      stredwic  968: 
1.55      stredwic  969: =item &BuildChart()
1.51      stredwic  970: 
1.57      stredwic  971:  The following is the process that BuildChart goes through to 
                    972:   create the html document.
1.51      stredwic  973: 
1.55      stredwic  974:  -Start the lonchart document
                    975:  -Test for access to the CacheData
                    976:  -Download class list information if not using cached data 
                    977:  -Sort students and print out table desciptive data
                    978:  -Output student data
1.57      stredwic  979:  -If recalculating, store a list of students, but only if all 
                    980:   their data was downloaded.  Leave off the others.
1.55      stredwic  981:  -End document
1.51      stredwic  982: 
1.55      stredwic  983: =over 4
1.51      stredwic  984: 
1.55      stredwic  985: Input: $r
1.51      stredwic  986: 
1.55      stredwic  987: $r:  Used to print html
1.51      stredwic  988: 
1.55      stredwic  989: Output: None
1.51      stredwic  990: 
1.55      stredwic  991: =back
1.49      stredwic  992: 
1.55      stredwic  993: =cut
1.44      stredwic  994: 
                    995: sub BuildChart {
                    996:     my ($r)=@_;
                    997:     my $c = $r->connection;
1.1       www       998: 
1.44      stredwic  999:     # Start the lonchart document
                   1000:     $r->content_type('text/html');
                   1001:     $r->send_http_header;
1.59      stredwic 1002:     $r->print(&StartDocument('LON-CAPA Assessment Chart', 'Assessment Chart'));
1.44      stredwic 1003:     $r->rflush();
1.43      stredwic 1004: 
1.44      stredwic 1005:     # Test for access to the CacheData
                   1006:     my $isCached=0;
1.43      stredwic 1007:     my $cid=$ENV{'request.course.id'};
                   1008:     my $ChartDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
                   1009:                   "_$ENV{'user.domain'}_$cid\_chart.db";
1.59      stredwic 1010:     my $isRecalculate=0;
                   1011:     if(defined($ENV{'form.ChartRecalculate'})) {
                   1012:         $isRecalculate=1;
                   1013:     }
                   1014:     $isCached=&Apache::loncoursedata::TestCacheData($ChartDB, $isRecalculate);
1.44      stredwic 1015:     if($isCached < 0) {
1.59      stredwic 1016:         $r->print("Unable to tie hash to db file</body></html>");
1.44      stredwic 1017:         $r->rflush();
                   1018:         return;
                   1019:     }
1.55      stredwic 1020:     &ProcessFormData($ChartDB, $isCached);
1.44      stredwic 1021: 
                   1022:     # Download class list information if not using cached data
1.48      stredwic 1023:     my %CacheData;
1.44      stredwic 1024:     my @students=();
                   1025:     my @studentInformation=('username','domain','section','id','fullname');
                   1026:     my @headings=('User Name','Domain','Section','PID','Full Name');
                   1027:     my $spacePadding='   ';
                   1028:     if(!$isCached) {
1.59      stredwic 1029:         unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
                   1030:             $r->print("Unable to tie hash to db file</body></html>");
                   1031:             $r->rflush();
                   1032:             return;
                   1033:         }
                   1034: 
                   1035:         my $processTopResourceMapReturn=
                   1036:             &Apache::loncoursedata::ProcessTopResourceMap(\%CacheData,$c);
1.44      stredwic 1037:         if($processTopResourceMapReturn ne 'OK') {
1.59      stredwic 1038:             $r->print($processTopResourceMapReturn.'</body></html>');
                   1039:             untie(%CacheData);
1.44      stredwic 1040:             return;
                   1041:         }
1.59      stredwic 1042: 
                   1043:         if($c->aborted()) {
                   1044:             untie(%CacheData);
                   1045:             $r->print('</body></html>'); 
                   1046:             return;
                   1047:         }
                   1048: 
                   1049:         my $classlist=&Apache::loncoursedata::DownloadStudentNamePIDSection(
                   1050:                                                                    $cid, $c);
1.44      stredwic 1051:         my ($checkForError)=keys(%$classlist);
                   1052:         if($checkForError =~ /^(con_lost|error|no_such_host)/i ||
                   1053:            defined($classlist->{'error'})) {
1.59      stredwic 1054:             $r->print("Error getting student data.</body></html>");
                   1055:             $r->rflush();
                   1056:             untie(%CacheData);
1.44      stredwic 1057:             return;
                   1058:         }
1.59      stredwic 1059: 
                   1060:         if($c->aborted()) {
                   1061:             untie(%CacheData);
                   1062:             $r->print('</body></html>'); 
                   1063:             return;
                   1064:         }
                   1065: 
                   1066: 
                   1067:         @students=&Apache::loncoursedata::ProcessClassList(\%CacheData, 
1.60    ! stredwic 1068:                                                      $classlist, $cid, 
        !          1069:                                                      $CacheData{'form.Status'},
        !          1070:                                                      $c);
1.59      stredwic 1071: 
                   1072:         if($c->aborted()) {
                   1073:             untie(%CacheData);
                   1074:             $r->print('</body></html>'); 
                   1075:             return;
                   1076:         }
                   1077: 
1.44      stredwic 1078:         &SpaceColumns(\@students,\@studentInformation,\@headings,
1.59      stredwic 1079:                       \%CacheData);
                   1080: 
                   1081:         if($c->aborted()) {
                   1082:             untie(%CacheData);
                   1083:             $r->print('</body></html>'); 
                   1084:             return;
                   1085:         }
                   1086: 
                   1087:         untie(%CacheData);
1.48      stredwic 1088:     } else {
                   1089:         if(!$c->aborted() && tie(%CacheData,'GDBM_File',$ChartDB,
                   1090:                                  &GDBM_READER,0640)) {
                   1091:             @students=split(/:::/,$CacheData{'NamesOfStudents'});
                   1092:         }
1.44      stredwic 1093:     }
                   1094: 
                   1095:     # Sort students and print out table desciptive data
1.55      stredwic 1096:     my $downloadTime=0;
1.44      stredwic 1097:     if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
1.48      stredwic 1098:         if(!$c->aborted()) { @students=&SortStudents(\@students,\%CacheData); }
1.54      stredwic 1099:         if(defined($CacheData{'time'})) { $downloadTime=$CacheData{'time'}; }
                   1100:         else { $downloadTime=localtime(); }
                   1101:         if(!$c->aborted()) { $r->print('<h3>'.$downloadTime.'</h3>'); }
1.50      stredwic 1102:         if(!$c->aborted()) { $r->print('<h1>'.(scalar @students).
                   1103:                                        ' students</h1>'); }
                   1104: 	if(!$c->aborted()) { $r->rflush(); }
1.44      stredwic 1105: 	if(!$c->aborted()) { $r->print(&CreateLegend()); }
1.55      stredwic 1106:         if(!$c->aborted()) { $r->print('<table border="0"><tbody>'); }
1.51      stredwic 1107: 	if(!$c->aborted()) { $r->print(&CreateForm(\%CacheData)); }
1.49      stredwic 1108: 	if(!$c->aborted()) { $r->print(&CreateColumnSelectionBox(
                   1109:                                                        \%CacheData,
1.55      stredwic 1110:                                                        \@headings)); }
                   1111:         if(!$c->aborted()) { $r->print('</tbody></table>'); }
                   1112:         if(!$c->aborted()) { $r->print('<b>Note: Uncheck the boxes above a'); }
                   1113:         if(!$c->aborted()) { $r->print(' column to remove that column from'); }
                   1114:         if(!$c->aborted()) { $r->print(' the display.</b></pre>'); }
                   1115:         if(!$c->aborted()) { $r->print('<table border="0" cellpadding="0" '); }
                   1116:         if(!$c->aborted()) { $r->print('cellspacing="0"><tbody>'); }
1.49      stredwic 1117: 	if(!$c->aborted()) { $r->print(&CreateColumnSelectors(
                   1118:                                                        \%CacheData,
1.55      stredwic 1119:                                                        \@headings)); }
1.44      stredwic 1120: 	if(!$c->aborted()) { $r->print(&CreateTableHeadings(
                   1121:                                                          \%CacheData,
                   1122:                                                          \@studentInformation, 
                   1123: 							 \@headings, 
                   1124: 							 $spacePadding)); }
1.55      stredwic 1125:         if(!$c->aborted()) { $r->print('</tbody></table>'); }
1.49      stredwic 1126: 	if(!$c->aborted()) { $r->rflush(); }
1.44      stredwic 1127: 	untie(%CacheData);
1.43      stredwic 1128:     } else {
1.44      stredwic 1129: 	$r->print("Init2: Unable to tie hash to db file");
                   1130: 	return;
1.43      stredwic 1131:     }
                   1132: 
1.55      stredwic 1133:     # Output student data
1.43      stredwic 1134:     my @updateStudentList = ();
1.44      stredwic 1135:     my $courseData;
1.50      stredwic 1136:     $r->print('<pre>');
1.44      stredwic 1137:     foreach (@students) {
                   1138:         if($c->aborted()) {
                   1139:             last;
                   1140:         }
                   1141: 
                   1142:         if(!$isCached) {
1.59      stredwic 1143:             $courseData=
                   1144:                 &Apache::loncoursedata::DownloadStudentCourseInformation($_, 
                   1145:                                                                          $cid);
1.50      stredwic 1146:             if($c->aborted()) { last; }
1.59      stredwic 1147:             if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
                   1148:                 &Apache::loncoursedata::ProcessStudentData(\%CacheData, 
                   1149:                                                            $courseData, $_);
                   1150:                 push(@updateStudentList, $_);
                   1151:                 untie(%CacheData);
                   1152:             } else {
                   1153:                 next;
                   1154:             }
1.44      stredwic 1155:         }
1.55      stredwic 1156:         $r->print(&FormatStudentData($_, \@studentInformation,
1.44      stredwic 1157:                                      $spacePadding, $ChartDB));
                   1158:         $r->rflush();
1.43      stredwic 1159:     }
                   1160: 
1.55      stredwic 1161:     # If recalculating, store a list of students, but only if all their 
                   1162:     # data was downloaded.  Leave off the others.
1.50      stredwic 1163:     if(!$isCached && tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
                   1164:         $CacheData{'NamesOfStudents'}=join(":::", @updateStudentList);
                   1165: #		    $CacheData{'NamesOfStudents'}=
                   1166: #		            &Apache::lonnet::arrayref2str(\@updateStudentList);
                   1167:         untie(%CacheData);
                   1168:     }
                   1169: 
1.55      stredwic 1170:     # End document
1.50      stredwic 1171:     $r->print('</pre></body></html>');
1.30      minaeibi 1172:     $r->rflush();
1.1       www      1173: 
1.43      stredwic 1174:     return;
1.30      minaeibi 1175: }
1.1       www      1176: 
1.30      minaeibi 1177: # ================================================================ Main Handler
1.55      stredwic 1178: 
                   1179: =pod
                   1180: 
                   1181: =item &handler()
                   1182: 
                   1183: The handler checks for permission to access the course data and for 
                   1184: initial header problem.  Then it passes the torch to the work horse
                   1185: function BuildChart.
                   1186: 
                   1187: =over 4
                   1188: 
                   1189: Input: $r
                   1190: 
                   1191: $r: This is the object that is used to print.
                   1192: 
                   1193: Output: A Value (OK or HTTP_NOT_ACCEPTABLE)
                   1194: 
                   1195: =back
                   1196: 
                   1197: =cut
1.1       www      1198: 
1.30      minaeibi 1199: sub handler {
1.44      stredwic 1200:     my $r=shift;
1.51      stredwic 1201: #    $jr=$r;
1.44      stredwic 1202:     unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
1.30      minaeibi 1203: 	$ENV{'user.error.msg'}=
1.1       www      1204:         $r->uri.":vgr:0:0:Cannot view grades for complete course";
1.30      minaeibi 1205: 	return HTTP_NOT_ACCEPTABLE; 
                   1206:     }
1.44      stredwic 1207: 
                   1208:     # Set document type for header only
                   1209:     if ($r->header_only) {
                   1210:         if($ENV{'browser.mathml'}) {
                   1211:             $r->content_type('text/xml');
                   1212:         } else {
                   1213:             $r->content_type('text/html');
                   1214:         }
                   1215:         &Apache::loncommon::no_cache($r);
                   1216:         $r->send_http_header;
                   1217:         return OK;
                   1218:     }
1.58      stredwic 1219: 
1.44      stredwic 1220:     unless($ENV{'request.course.fn'}) {
                   1221:         my $requrl=$r->uri;
                   1222:         $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
                   1223:         return HTTP_NOT_ACCEPTABLE; 
                   1224:     }
                   1225: 
                   1226:     &BuildChart($r);
                   1227: 
                   1228:     return OK;
1.1       www      1229: }
                   1230: 1;
                   1231: __END__

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