[LON-CAPA-cvs] cvs: loncom /interface/statistics lonstudentassessment.pm

matthew lon-capa-cvs@mail.lon-capa.org
Mon, 03 Mar 2003 19:28:29 -0000


This is a MIME encoded message

--matthew1046719709
Content-Type: text/plain

matthew		Mon Mar  3 14:28:29 2003 EDT

  Modified files:              
    /loncom/interface/statistics	lonstudentassessment.pm 
  Log:
  Big Changes:
     Started adding different output options.
     No longer begins computing before the user has made selections.
  
  The code is being simplified to some degree and obfuscated in other ways.  
  
  Each output type has three subroutines associated with it: initialize, 
  outputstudent, and finish.  Function pointers are used (defaulting the output
  mode to 'html').  Currently excel and csv output both result in 
  "Not Implemented".
  
  Renamed &CreateTableHeadings to &html_initialize, &ChartOutputStudent to
  &html_outputstudent, and added &html_finish.  Each of these routines was
  changed to make it responsible for *all* html output of the chart, other than
  the selection form.
  
  Still remaining to be filled in are the routines for csv and excel output.
  
  
--matthew1046719709
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20030303142829.txt"

Index: loncom/interface/statistics/lonstudentassessment.pm
diff -u loncom/interface/statistics/lonstudentassessment.pm:1.30 loncom/interface/statistics/lonstudentassessment.pm:1.31
--- loncom/interface/statistics/lonstudentassessment.pm:1.30	Fri Feb 28 16:19:00 2003
+++ loncom/interface/statistics/lonstudentassessment.pm	Mon Mar  3 14:28:29 2003
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstudentassessment.pm,v 1.30 2003/02/28 21:19:00 matthew Exp $
+# $Id: lonstudentassessment.pm,v 1.31 2003/03/03 19:28:29 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -54,7 +54,23 @@
 use Apache::lonhtmlcommon;
 use Apache::loncoursedata;
 use Apache::lonnet; # for logging porpoises
-use GDBM_File;
+use Spreadsheet::WriteExcel;
+
+#######################################################
+#######################################################
+=pod
+
+=item Package Variables
+
+=over 4
+
+=item $Statistics Hash ref to store student data.  Indexed by symb,
+      contains hashes with keys 'score' and 'max'.
+
+=cut
+
+#######################################################
+#######################################################
 
 my $Statistics;
 
@@ -63,27 +79,40 @@
 
 =pod
 
-=item &BuildStudentAssessmentPage()
+=item $show_links 'yes' or 'no' for linking to student performance data
 
-Inputs: 
+=item $output_mode 'html', 'excel', or 'csv' for output mode
 
-=over 4
+=item $show 'all' or 'totals' determines how much data is output
 
-=item $cacheDB The name of the cache file used to store student data
+=cut
 
-=item $students Array ref containing the name(s) of the students 
-selected for display
+#######################################################
+#######################################################
+my $show_links;
+my $output_mode;
+my $show;
 
-=item $courseID The ID of the course
+#######################################################
+#######################################################
+# End of package variable declarations
 
-=item $formName The name of the html form - 'Statistics'
+=pod
 
-=item $headings Array ref of headings to show
+=back
 
-=item $spacing A string of spaces
+=cut
 
-=item $studentInformation Array ref of possible headings for student info
-('fullname','section',...)
+#######################################################
+#######################################################
+
+=pod
+
+=item &BuildStudentAssessmentPage()
+
+Inputs: 
+
+=over 4
 
 =item $r Apache Request
 
@@ -98,36 +127,88 @@
 sub BuildStudentAssessmentPage {
     my ($r,$c)=@_;
     undef($Statistics);
-    
     #
+    # Print out the HTML headers for the interface
+    #    This also parses the output mode selector
+    #    This step must always be done.
     $r->print(&CreateInterface());
+    $r->print('<input type="hidden" name="notfirstrun" value="true" />');
     $r->rflush();
+    if (! exists($ENV{'form.notfirstrun'})) {
+        $r->print(<<ENDMSG);
+<p>
+<font size="+1">
+Please make your selections in the boxes above and hit 
+the button marked &quot;Update&nbsp;Display&quot;.
+</font>
+</p>
+ENDMSG
+        return;
+    }
+    #
+    #
+    my $initialize     = \&html_initialize;
+    my $output_student = \&html_outputstudent;
+    my $finish         = \&html_finish;
+    #
+    if ($output_mode eq 'excel') {
+        $initialize     = \&excel_initialize;
+        $output_student = \&excel_outputstudent;
+        $finish         = \&excel_finish;
+    } elsif ($output_mode eq 'csv') {
+        $initialize     = \&csv_initialize;
+        $output_student = \&csv_outputstudent;
+        $finish         = \&csv_finish;
+    }
     #
-    $r->print(&CreateTableHeadings());
     if($c->aborted()) {  return ; }
-    
-    my $Count = 0;
-    $r->print('<pre>'."\n");
+    #
+    # Call the initialize routine selected above
+    $initialize->($r);
     foreach my $student (@Apache::lonstatistics::Students) {
-        if($c->aborted()) { return ; }
-        $r->print(&ChartOutputStudent($student));
-        # output it
-
-        $Count++;
-        if($Count % 5 == 0) {
-            $r->print("</pre>\n<pre>");
+        if($c->aborted()) { 
+            $finish->($r);
+            return ; 
         }
-
-        $r->rflush();
+        # Call the output_student routine selected above
+        $output_student->($r,$student);
     }
-    $r->print('</pre>'."\n"); 
-    my $Str;
+    # Call the "finish" routine selected above
+    $finish->($r);
+    #
     return;
 }
 
 #######################################################
 #######################################################
 
+sub get_student_fields_to_show {
+    my @to_show = @Apache::lonstatistics::SelectedStudentData;
+    foreach (@to_show) {
+        if ($_ eq 'all') {
+            @to_show = @Apache::lonstatistics::StudentDataOrder;
+            last;
+        }
+    }
+    return @to_show;
+}
+
+sub get_sequences_to_show {
+    my @Sequences;
+    foreach my $map_symb (@Apache::lonstatistics::SelectedMaps) {
+        foreach my $sequence (@Apache::lonstatistics::Sequences) {
+            next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
+            next if ($sequence->{'num_assess'} < 1);
+            push (@Sequences,$sequence);
+        }
+    }
+    return @Sequences;
+}
+
+
+#######################################################
+#######################################################
+
 =pod
 
 =item &CreateInterface()
@@ -152,6 +233,7 @@
     $Str .= '<td align="center"><b>Sections</b></td>';
     $Str .= '<td align="center"><b>Student Data</b></td>';
     $Str .= '<td align="center"><b>Sequences and Folders</b></td>';
+    $Str .= '<td align="center"><b>Output Format</b></td>';
     $Str .= '</tr>'."\n";
     #
     $Str .= '<tr><td align="center">'."\n";
@@ -170,78 +252,108 @@
     $Str .= '</td><td>'."\n";
     $Str .= &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
                                               $only_seq_with_assessments);
+    $Str .= '</td><td>'."\n";
+    $Str .= &CreateAndParseOutputSelector();
     $Str .= '</td></tr>'."\n";
     $Str .= '</table>'."\n";
     return $Str;
 }
 
-
 #######################################################
 #######################################################
 
 =pod
 
-=item Table Output Routines
-
-=over 4
+=item &CreateAndParseOutputSelector()
 
 =cut
 
 #######################################################
 #######################################################
-{
-    my $padding;
+sub CreateAndParseOutputSelector {
+    my $Str = '';
+    my $elementname = 'outputmode';
+    #
+    # Format for output options is 'mode, restrictions';
+    my @Options = ('html, with links','html, without links',
+                   'html, totals only','excel, totals only',
+                   'csv, totals only','csv, everything');
+    my $selected = 'html, with links';
+    if (exists($ENV{'form.'.$elementname})) {
+        if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
+            $selected = $ENV{'form.'.$elementname}->[0];
+        } else {
+            $selected = $ENV{'form.'.$elementname};
+        }
+    }
+    #
+    # Set package variables describing output mode
+    $show_links  = 'no';
+    $output_mode = 'html';
+    $show        = 'all';
+    my ($mode,$restriction) = split(',',$selected);
+    $restriction =~ s/^\s*//;
+    if ($mode =~ /^(html|excel|csv)$/) {
+        $output_mode = $mode;
+    } else {
+        $output_mode = 'html';
+    }
+    if ($restriction eq 'with links') {
+        $show_links = 'yes';
+    } else {
+        $show_links = 'no';
+    }
+    if ($restriction eq 'totals only') {
+        $show = 'totals';
+    } else {
+        $show = 'everything';
+    }
+    #
+    # Build the form element
+    $Str = qq/<select size="5" name="$elementname">/;
+    foreach my $option (@Options) {
+        $Str .= qq/\n    <option value="$option"/;
+        $Str .= " selected " if ($option eq $selected);
+        $Str .= ">$option<\/option>";
+    }
+    $Str .= "\n</select>";
+    return $Str;
+}
 
 #######################################################
 #######################################################
 
 =pod
 
-=item &CreateTableHeadings()
+=head2 HTML output routines
 
-Create HTML for the columns of student data to show.
-Called by &BuildStudentAssessmentPage().  Calls
-&Apache::lonhtmlcommon::CreateHeadings().
+=item &html_initialize($r)
 
-Inputs:
+Create labels for the columns of student data to show.
 
-=over 4
+=item &html_outputstudent($r,$student)
 
-=item $cache The ubiquitous cache
-
-=item $spacing A string of spaces
-
-=item $infoKeys Array ref to names of keys to display from the cache 
-which describe students
-
-=item $infoHeadings Array ref to headings of columns for student info
-
-=item $sequenceKeys Array ref of names of keys to use to retrieve sequence
-data from the cache
-
-=item $sequenceHeadings Array ref of names of sequences used for output.
-
-=back
+Return a line of the chart for a student.
 
-Returns: A string containing the HTML of the table headings.
+=item &html_finish($r)
 
 =cut
 
 #######################################################
 #######################################################
-sub CreateTableHeadings {
+{
+    my $padding;
+    my $count;
+
+sub html_initialize {
+    my ($r) = @_;
     #
     $padding = ' 'x3;
+    $count = 1;
     #
-    my $Str = '<pre>';
+    my $Str = "<pre>\n";
     # First, the @StudentData fields need to be listed
-    my @to_show = @Apache::lonstatistics::SelectedStudentData;
-    foreach (@to_show) {
-        if ($_ eq 'all') {
-            @to_show = @Apache::lonstatistics::StudentDataOrder;
-            last;
-        }
-    }
+    my @to_show = &get_student_fields_to_show();
     foreach my $field (@to_show) {
         my $title=$Apache::lonstatistics::StudentData{$field}->{'title'};
         my $base =$Apache::lonstatistics::StudentData{$field}->{'base_width'};
@@ -249,48 +361,27 @@
         $Str .= $title.' 'x($width-$base).$padding;
     }
     # Now the selected sequences need to be listed
-    foreach my $map_symb (@Apache::lonstatistics::SelectedMaps) {
-        foreach my $sequence (@Apache::lonstatistics::Sequences) {
-            next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
-            next if ($sequence->{'num_assess'} < 1);
-            my $title = $sequence->{'title'};
-            my $base  = $sequence->{'base_width'};
-            my $width = $sequence->{'width'};
-            $Str .= $title.' 'x($width-$base).$padding;
-        }
+    foreach my $sequence (&get_sequences_to_show) {
+        my $title = $sequence->{'title'};
+        my $base  = $sequence->{'base_width'};
+        my $width = $sequence->{'width'};
+        $Str .= $title.' 'x($width-$base).$padding;
     }
-    $Str .= 'total';
-    $Str .= "</pre>\n";
-    return $Str;
+    $Str .= "total (of shown problems)</pre>\n";
+    $Str .= "<pre>";
+    $r->print($Str);
+    $r->rflush();
+    return;
 }
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &ChartOutputStudent($student)
-
-Return a line of the chart for a student.
-
-=cut
-
-#######################################################
-#######################################################
-sub ChartOutputStudent {
-    my $student = shift;
+sub html_outputstudent {
+    my ($r,$student) = @_;
     my $Str = '';
     # First, the @StudentData fields need to be listed
-    my @to_show = @Apache::lonstatistics::SelectedStudentData;
-    foreach (@to_show) {
-        if ($_ eq 'all') {
-            @to_show = @Apache::lonstatistics::StudentDataOrder;
-            last;
-        }
-    }
+    my @to_show = &get_student_fields_to_show();
     foreach my $field (@to_show) {
         my $title=$student->{$field};
-        my $base =scalar(my @Tmp = split(//,$title));
+        my $base = length($title);
         my $width=$Apache::lonstatistics::StudentData{$field}->{'width'};
         $Str .= $title.' 'x($width-$base).$padding;
     }
@@ -304,22 +395,34 @@
     }
     if (scalar(@tmp) < 1) {
         $Str .= '<font color="blue">No Course Data</font>'."\n";
-        return $Str;
+        $r->print($Str);
+        $r->rflush();
+        return;
     }
     #
     # By sequence build up the data
     my $studentstats;
-    foreach my $map_symb (@Apache::lonstatistics::SelectedMaps) {
-        foreach my $seq (@Apache::lonstatistics::Sequences) {
-            next if ($map_symb ne $seq->{'symb'} && $map_symb ne 'all');
-            next if ($seq->{'num_assess'} < 1);
-            my ($performance,$score,$seq_max) =
-                &StudentPerformanceOnSequence($student,\%StudentsData,
-                                              $seq,'linkify');
-            $Str .= $performance.$padding;
-            $studentstats->{$seq->{'symb'}}->{'score'}= $score;
-            $studentstats->{$seq->{'symb'}}->{'max'}  = $seq_max;
+    my $PerformanceStr = '';
+    foreach my $seq (&get_sequences_to_show) {
+        my ($performance,$score,$seq_max) =
+            &StudentPerformanceOnSequence($student,\%StudentsData,
+                                          $seq,$show_links);
+        my $ratio = $score.'/'.$seq_max;
+        #
+        if ($show eq 'totals') {
+            $performance = ' 'x(length($seq_max)-length($score)).$ratio;
+            $performance .= ' 'x($seq->{'width'}-length($performance));
+        } else {
+            # Pad with extra spaces
+            $performance .= ' 'x($seq->{'width'}-$seq_max-
+                                 length($ratio)
+                                 ).$ratio;
         }
+        #
+        $Str .= $performance.$padding;
+        #
+        $studentstats->{$seq->{'symb'}}->{'score'}= $score;
+        $studentstats->{$seq->{'symb'}}->{'max'}  = $seq_max;
     }
     #
     # Total it up and store the statistics info.
@@ -330,24 +433,119 @@
         $score += $seq_stats->{'score'};
         $max   += $seq_stats->{'max'};
     }
-    my $scorelength = scalar(my @tmp1 = split(//,$score));
-    my $maxlength   = scalar(my @tmp2 = split(//,$max));
-    $Str .= ' '.' 'x($maxlength-$scorelength).$score.'/'.$max;
+    $Str .= ' '.' 'x(length($max)-length($score)).$score.'/'.$max;
     $Str .= " \n";
-    return $Str;
+    $r->print($Str);
+    #
+    $count++;
+    if($count % 5 == 0) {
+        $r->print("</pre><pre>");
+    }
+    #
+    $r->rflush();
+    return;
 }    
 
+sub html_finish {
+    my ($r) = @_;
+    $r->print("</pre>\n"); 
+    $r->rflush();
+    return;
+}
+
+}
+
 #######################################################
 #######################################################
 
 =pod
 
-=back
+=head2 EXCEL subroutines
+
+=item &excel_initialize($r)
+
+=item &excel_outputstudent($r,$student)
+
+=item &excel_finish($r)
+
+=cut
+
+#######################################################
+#######################################################
+{
+
+my $excel_sheet;
+
+sub excel_initialize {
+    my ($r) = @_;
+    #
+    $r->print("<h1>Not implemented yet</h1>");
+    return;
+    my $filename = '/prtspool/'.
+        $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
+            time.'_'.rand(1000000000).'.xls';
+    $excel_sheet = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
+    if (! defined($excel_sheet)) {
+        $r->log_error("Error creating excel spreadsheet $filename: $!");
+        $r->print("Problems creating new Excel file.  ".
+                  "This error has been logged.  ".
+                  "Please alert your LON-CAPA administrator");
+        return 0;
+    }
+    #
+    # The excel spreadsheet stores temporary data in files, then put them
+    # together.  If needed we should be able to disable this (memory only).
+    # The temporary directory must be specified before calling 'addworksheet'.
+    # File::Temp is used to determine the temporary directory.
+    $excel_sheet->set_tempdir($Apache::lonnet::tmpdir);
+    #
+    # Determine the name to give the worksheet
+#    $excel_sheet->addworksheet();
+
+    return;
+}
+
+sub excel_outputstudent {
+    my ($r,$student) = @_;
+}
+
+sub excel_finish {
+    my ($r) = @_;
+}
+
+}
+#######################################################
+#######################################################
+
+=pod
+
+=head2 CSV output routines
+
+=item &csv_initialize($r)
+
+=item &csv_outputstudent($r,$student)
+
+=item &csv_finish($r)
 
 =cut
 
 #######################################################
 #######################################################
+{
+
+sub csv_initialize{
+    my ($r) = @_;
+    $r->print("<h1>Not implemented yet</h1>");
+    return;
+}
+
+sub csv_outputstudent {
+    my ($r,$student) = @_;
+}
+
+sub csv_finish {
+    my ($r) = @_;
+}
 
 }
 
@@ -377,9 +575,10 @@
 #######################################################
 #######################################################
 sub StudentPerformanceOnSequence {
-    my ($student,$studentdata,$seq,$links) = @_;
+    my ($student,$studentdata,$seq,$links,$totalonly) = @_;
+    $totalonly = 0 if (! defined($totalonly));
+    $links = 'no' if (! defined($links));
     my $Str = '';
-    my $output_width = 0;
     my ($sum,$max) = (0,0);
     foreach my $resource (@{$seq->{'contents'}}) {
         next if ($resource->{'type'} ne 'assessment');
@@ -426,8 +625,7 @@
                 }
             }
             #
-            $output_width++;
-            if (defined($links) && $symbol ne ' ') {
+            if ($links eq 'yes' && $symbol ne ' ') {
                 $symbol = '<a href="/adm/grades'.
                     '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
                         '&student='.$student->{'username'}.
@@ -438,13 +636,6 @@
         }
         $Str .= $value;
     }
-    # Put on the totals
-    my $ratio = $sum.'/'.$max;
-    my $ratio_length = scalar(my @tmp1 = split(//,$ratio));
-    # Pad with extra spaces
-    my $width = $seq->{'width'};
-    $Str .= ' 'x($width-$output_width-$ratio_length).$ratio;
-    #
     return ($Str,$sum,$max);
 }
 

--matthew1046719709--