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

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

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