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

matthew lon-capa-cvs@mail.lon-capa.org
Wed, 08 Sep 2004 14:58:33 -0000


This is a MIME encoded message

--matthew1094655513
Content-Type: text/plain

matthew		Wed Sep  8 10:58:33 2004 EDT

  Modified files:              
    /loncom/interface/statistics	lonstudentsubmissions.pm 
  Log:
  CSV output works now.  Excel is broken.  More work to do....
  
  
--matthew1094655513
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20040908105833.txt"

Index: loncom/interface/statistics/lonstudentsubmissions.pm
diff -u loncom/interface/statistics/lonstudentsubmissions.pm:1.16 loncom/interface/statistics/lonstudentsubmissions.pm:1.17
--- loncom/interface/statistics/lonstudentsubmissions.pm:1.16	Thu Sep  2 17:02:54 2004
+++ loncom/interface/statistics/lonstudentsubmissions.pm	Wed Sep  8 10:58:33 2004
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstudentsubmissions.pm,v 1.16 2004/09/02 21:02:54 matthew Exp $
+# $Id: lonstudentsubmissions.pm,v 1.17 2004/09/08 14:58:33 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -134,6 +134,9 @@
             if ($ENV{'form.output'} eq 'excel') {
                 &prepare_excel_output($r,$current_problem,
                                       $ProblemData,\@Students);
+            } elsif ($ENV{'form.output'} eq 'csv') {
+                &prepare_csv_output($r,$current_problem,
+                                      $ProblemData,\@Students);
             } else {
                 &prepare_html_output($r,$current_problem,
                                      $ProblemData,\@Students);
@@ -142,7 +145,7 @@
         $r->print('<hr />');
     } else {
         $r->print('<input type="submit" name="Generate" value="'.
-                  &mt('Generate Spreadsheet').'" />');
+                  &mt('Prepare Report').'" />');
         $r->print('&nbsp;'x5);
         $r->print('<h3>'.&mt('Please select a problem to analyze').'</h3>');
         $r->print(&Apache::lonstathelpers::ProblemSelector('.'));
@@ -166,10 +169,27 @@
       display =>'Attempt'},
      {name => 'awarddetail',
       display =>'Awarddetail'},
-     {name => 'grading',
-      display =>'Score'},
+     {name => 'awarded',
+      display =>'Award'},
+     # FIXME: Probably need to add score
     );
 
+sub get_response_type {
+    my ($resource,$partid,$respid) = @_;
+    my $response_type = '';
+    for (my $i=0;
+         $i<scalar(@{$resource->{'partdata'}->{$partid}->{'ResponseIds'}});
+         $i++) {
+        if($resource->{'partdata'}->{$partid}->{'ResponseIds'}->[$i] eq $respid){
+            $response_type = 
+                $resource->{'partdata'}->{$partid}->{'ResponseTypes'}->[$i];
+            last;
+        }
+    }
+    return $response_type;
+}
+
+
 #########################################################
 #########################################################
 ##
@@ -194,102 +214,93 @@
     $r->print('<h2>'.&mt('Student Responses').'</h2>');
     #
     $r->rflush();
-    my $response_type;
-    for (my $i=0;
-         $i<scalar(@{$resource->{'partdata'}->{$partid}->{'ResponseIds'}});
-         $i++) {
-        if($resource->{'partdata'}->{$partid}->{'ResponseIds'}->[$i] eq $respid){
-            $response_type = 
-                $resource->{'partdata'}->{$partid}->{'ResponseTypes'}->[$i];
-            last;
-        }
-    }
+    my $response_type = &get_response_type($resource,$partid,$respid);
     if (! defined($response_type)) {
         $r->print('<h2>'.&mt('Unable to determine response type').'</h2>');
-    } else {
-        my $count = 0;
-        my @Columns;
-        if (exists($ENV{'form.concise'}) && $ENV{'form.concise'} eq 'true') {
-            foreach (@DefaultColumns) {
-                if ($_->{'name'} =~ /^(username|domain|id)$/){
-                    push(@Columns,$_);
-                }
+        return;
+    }
+    my $count = 0;
+    my @Columns;
+    if (exists($ENV{'form.concise'}) && $ENV{'form.concise'} eq 'true') {
+        foreach (@DefaultColumns) {
+            if ($_->{'name'} =~ /^(username|domain|id)$/){
+                push(@Columns,$_);
             }
-        } else {
-            @Columns = @DefaultColumns;
         }
-        my $header = '<table>'.$/.&html_headers(\@Columns);
-        if ($response_type eq 'essay') {
-            $header .= &html_essay_headers();
-        } elsif ($response_type eq 'option') {
-            $header .= &html_option_headers();
-        } else {
-            $header .= &html_generic_headers();
+    } else {
+        @Columns = @DefaultColumns;
+    }
+    my $header = '<table>'.$/.&html_headers(\@Columns);
+    if ($response_type eq 'essay') {
+        $header .= &html_essay_headers();
+    } elsif ($response_type eq 'option') {
+        $header .= &html_option_headers();
+    } else {
+        $header .= &html_generic_headers();
+    }
+    $header = '<tr>'.$header.'</tr>';
+    #
+    $r->print($/.$header.$/);
+    foreach my $student (@$Students) {
+        if ($count >= 50) {
+            $r->print('</table>'.$/.$header.$/);
+            $count = 0;
         }
-        $header = '<tr>'.$header.'</tr>';
-        #
-        $r->print($/.$header.$/);
-        foreach my $student (@$Students) {
-            if ($count >= 50) {
-                $r->print('</table>'.$/.$header.$/);
-                $count = 0;
-            }
-            last if ($c->aborted());
-            my $results = &Apache::loncoursedata::get_response_data_by_student
-                ($student,$resource->{'symb'},$respid);
-            next if (! defined($results) || ref($results) ne 'ARRAY');
-            for (my $i=0;$i<scalar(@$results);$i++) {
-                my $response = $results->[$i];
-                if ($ENV{'form.last_sub_only'} eq 'true' && 
-                    $i < (scalar(@$results)-1)) {
-                    next;
-                }
-                my $data;
-                $data->{'username'} = $student->{'username'};
-                $data->{'domain'}   = $student->{'domain'};
-                $data->{'id'} = $student->{'id'};
-                $data->{'fullname'} = $student->{'fullanem'};
-                $data->{'status'} = $student->{'status'};
-                $data->{'time'} = &Apache::lonlocal::locallocaltime
-                    ($response->[&Apache::loncoursedata::RDs_timestamp()]);
-                $data->{'attempt'} = 
-                    $response->[&Apache::loncoursedata::RDs_tries()];
-                $data->{'awarded'} = 
-                    $response->[&Apache::loncoursedata::RDs_awarded()];
-                $data->{'awarddetail'} = 
-                    $response->[&Apache::loncoursedata::RDs_awarddetail()];
-                my $rowextra = 'bgcolor="#CCCCCC"';
-                if ($count % 2 == 1) {
-                    $rowextra = 'bgcolor="#EEEEEE"';
-                }
-                my $row = '<tr '.$rowextra.'>';
-                foreach my $col (@Columns) {
-                    $row .= '<td valign="top">'.
-                        $data->{$col->{'name'}}.'</td>';
-                }
-                if ($response_type eq 'essay') {
-                    $row .= &html_essay
-                        ($response->[&Apache::loncoursedata::RDs_submission()],
-                         $student->{'answer'},
-                         scalar(@Columns),$rowextra);
-                } elsif ($response_type eq 'option') {
-                    $row .= &html_option
-                        ($response->[&Apache::loncoursedata::RDs_submission()],
-                         $student->{'answer'},
-                         scalar(@Columns),$rowextra);
-                } else {
-                    $row .= &html_generic
-                        ($response->[&Apache::loncoursedata::RDs_submission()],
-                         $student->{'answer'},
-                         scalar(@Columns),$rowextra);
-                }
-                $row .= '</tr>';
-                $r->print($row.$/);
-                $count++;
+        last if ($c->aborted());
+        my $results = &Apache::loncoursedata::get_response_data_by_student
+            ($student,$resource->{'symb'},$respid);
+        next if (! defined($results) || ref($results) ne 'ARRAY');
+        for (my $i=0;$i<scalar(@$results);$i++) {
+            my $response = $results->[$i];
+            if ($ENV{'form.last_sub_only'} eq 'true' && 
+                $i < (scalar(@$results)-1)) {
+                next;
+            }
+            my $data;
+            $data->{'username'} = $student->{'username'};
+            $data->{'domain'}   = $student->{'domain'};
+            $data->{'id'} = $student->{'id'};
+            $data->{'fullname'} = $student->{'fullanem'};
+            $data->{'status'} = $student->{'status'};
+            $data->{'time'} = &Apache::lonlocal::locallocaltime
+                ($response->[&Apache::loncoursedata::RDs_timestamp()]);
+            $data->{'attempt'} = 
+                $response->[&Apache::loncoursedata::RDs_tries()];
+            $data->{'awarded'} = 
+                $response->[&Apache::loncoursedata::RDs_awarded()];
+            $data->{'awarddetail'} = 
+                $response->[&Apache::loncoursedata::RDs_awarddetail()];
+            my $rowextra = 'bgcolor="#CCCCCC"';
+            if ($count % 2 == 1) {
+                $rowextra = 'bgcolor="#EEEEEE"';
+            }
+            my $row = '<tr '.$rowextra.'>';
+            foreach my $col (@Columns) {
+                $row .= '<td valign="top">'.
+                    $data->{$col->{'name'}}.'</td>';
             }
+            if ($response_type eq 'essay') {
+                $row .= &html_essay_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            } elsif ($response_type eq 'option') {
+                $row .= &html_option_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            } else {
+                $row .= &html_generic_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            }
+            $row .= '</tr>';
+            $r->print($row.$/);
+            $count++;
         }
-        $r->print('</table>'.$/);
     }
+    $r->print('</table>'.$/);
     return;
 }
 
@@ -342,13 +353,17 @@
     return $header;
 }
 
-sub html_radiobutton {
+sub html_option_headers {
+    return &html_generic_headers();
+}
+
+sub html_radiobutton_results {
     my ($submission,$correct,$tablewidth,$rowclass)=@_;
     $submission =~ s/=([^=])$//;
     return &html_generic_results($submission,$correct,$tablewidth,$rowclass);
 }
 
-sub html_generic {
+sub html_generic_results {
     my ($submission,$correct,$tablewidth,$rowclass)=@_;
     my $Str .= '<td>'.$submission.'</td>';
     if ($ENV{'form.correctans'} eq 'true') {
@@ -358,11 +373,7 @@
     return $Str;
 }
 
-sub html_option_headers {
-    return &html_generic_headers();
-}
-
-sub html_option {
+sub html_option_results {
     my ($submission,$correct,$tablewidth,$rowclass)=@_;
     $submission = 
         '<ul class="sub_studentans">'.
@@ -382,7 +393,206 @@
                         '</li></ul>';
     }
     #
-    return &html_generic($submission,$correct,$tablewidth,$rowclass);
+    return &html_generic_results($submission,$correct,$tablewidth,$rowclass);
+}
+
+#########################################################
+#########################################################
+##
+##      CSV output of student answers
+##
+#########################################################
+#########################################################
+sub prepare_csv_output {
+    my ($r,$problem,$ProblemData,$Students) = @_;
+    #
+    my $c = $r->connection();
+    my ($resource,$respid,$partid) = ($problem->{'resource'},
+                                      $problem->{'respid'},
+                                      $problem->{'part'});
+    #
+    if ($ENV{'form.correctans'} eq 'true') {
+        $r->print('<h2>'.&mt('Generating Correct Answers').'</h2>');
+        &Apache::lonstathelpers::GetStudentAnswers($r,$problem,$Students,
+                                                   'Statistics',
+                                                   'stats_status');
+    }
+    #
+    $r->print('<h2>'.
+              &mt('Generating CSV report of student responses').'</h2>');
+    #
+    # Progress window
+    my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
+        ($r,'CSV File Compilation Status',
+         'CSV File Compilation Progress', 
+         scalar(@$Students),'inline',undef,'Statistics','stats_status');
+
+    $r->rflush();
+    #
+    # Open a file
+    my $outputfile;
+    my $filename = '/prtspool/'.
+        $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
+            time.'_'.rand(1000000000).'.csv';
+    unless ($outputfile = Apache::File->new('>/home/httpd'.$filename)) {
+        $r->log_error("Couldn't open $filename for output $!");
+        $r->print("Problems occured in writing the csv file.  ".
+                  "This error has been logged.  ".
+                  "Please alert your LON-CAPA administrator.");
+        $outputfile = undef;
+    }
+    #
+    #
+    my @Columns;
+    if (exists($ENV{'form.concise'}) && $ENV{'form.concise'} eq 'true') {
+        foreach (@DefaultColumns) {
+            if ($_->{'name'} =~ /^(username|domain|id)$/){
+                push(@Columns,$_);
+            }
+        }
+    } else {
+        @Columns = @DefaultColumns;
+    }
+    #
+    my $response_type = &get_response_type($resource,$partid,$respid);
+    if (! defined($response_type) || $response_type eq '') {
+        $r->print('<h2>'.&mt('Unable to determine response type').'</h2>');
+        return;
+    }
+    #
+    my $header = &csv_headers(\@Columns).','.&csv_generic_headers();
+    print $outputfile $header.$/;
+    #
+    foreach my $student (@$Students) {
+        last if ($c->aborted());
+        my $results = &Apache::loncoursedata::get_response_data_by_student
+            ($student,$resource->{'symb'},$respid);
+        next if (! defined($results) || ref($results) ne 'ARRAY');
+        for (my $i=0;$i<scalar(@$results);$i++) {
+            my $response = $results->[$i];
+            if ($ENV{'form.last_sub_only'} eq 'true' && 
+                $i < (scalar(@$results)-1)) {
+                next;
+            }
+            my $data;
+            $data->{'username'} = $student->{'username'};
+            $data->{'domain'}   = $student->{'domain'};
+            $data->{'id'} = $student->{'id'};
+            $data->{'fullname'} = $student->{'fullanem'};
+            $data->{'status'} = $student->{'status'};
+            $data->{'time'} = &Apache::lonlocal::locallocaltime
+                ($response->[&Apache::loncoursedata::RDs_timestamp()]);
+            $data->{'attempt'} = 
+                $response->[&Apache::loncoursedata::RDs_tries()];
+            $data->{'awarded'} = 
+                $response->[&Apache::loncoursedata::RDs_awarded()];
+            $data->{'awarddetail'} = 
+                $response->[&Apache::loncoursedata::RDs_awarddetail()];
+            my $rowextra = '';
+            my $row;
+            foreach my $col (@Columns) {
+                $row .= '"'.
+                    &Apache::loncommon::csv_translate($data->{$col->{'name'}}).'",';
+            }
+            if ($response_type eq 'option') {
+                $row .= &csv_option_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            } elsif ($response_type eq 'radiobutton') {
+                $row .= &csv_radiobutton_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            } else {
+                $row .= &csv_generic_results
+                    ($response->[&Apache::loncoursedata::RDs_submission()],
+                     $student->{'answer'},
+                     scalar(@Columns),$rowextra);
+            }
+            print $outputfile $row.$/;
+        }
+        &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
+                                                 'last student');
+    }
+    close($outputfile);
+    #
+    # Close the progress window
+    &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+    #
+    # Tell the user where to get their csv file
+    $r->print('<br />'.
+              '<a href="'.$filename.'">'.&mt('Your csv file.').'</a>'."\n");
+    $r->rflush();
+    return;
+}
+
+sub csv_headers {
+    my ($Columns) = @_;
+    my $Str;
+    foreach my $column (@$Columns) {
+        $Str .= 
+            '"'.&Apache::loncommon::csv_translate($column->{'display'}).'",';
+    }
+    chop($Str);
+    return $Str;
+}
+
+sub csv_generic_headers {
+    my ($title) = @_;
+    if (! defined($title)) {
+        $title = &mt('Submission');
+    }
+    my $header = '"'.&Apache::loncommon::csv_translate($title).'"';
+    if ($ENV{'form.correctans'} eq 'true') {
+        $header .= ',"'.&Apache::loncommon::csv_translate(&mt('Correct')).'"';
+    }
+    return $header;
+}
+
+#------------------------------------------
+sub csv_essay_results {
+    my ($submission,$correct,$tablewidth,$rowextra)=@_;
+    #
+    $submission =~ s|\\r|\\\\r|g;
+    $submission =~ s|\\n|\\\\n|g;
+    #
+    return &csv_generic_results($submission,$correct,$tablewidth);
+}
+
+#------------------------------------------
+sub csv_radiobutton_results {
+    my ($submission,$correct,$tablewidth,$rowclass)=@_;
+    $submission =~ s/=[^=]*$//;
+    return &csv_generic_results($submission,$correct,$tablewidth,$rowclass);
+}
+
+#------------------------------------------
+sub csv_option_results {
+    my ($submission,$correct,$tablewidth,$rowclass)=@_;
+    $submission = join(',',
+                       map { 
+                           &Apache::lonnet::unescape($_) ;
+                       } sort split('&',$submission)
+                       );
+    if (defined($correct) && $correct !~ /^\s*$/) {
+        $correct =join(',',
+                       map { 
+                           &Apache::lonnet::unescape($_) ;
+                       } sort split('&',$submission));
+    }
+    return &csv_generic_results($submission,$correct,$tablewidth,$rowclass);
+}
+
+#------------------------------------------
+sub csv_generic_results {
+    my ($submission,$correct,$tablewidth,$rowclass)=@_;
+    my $Str .= 
+        '"'.&Apache::loncommon::csv_translate($submission).'"';
+    if ($ENV{'form.correctans'} eq 'true') {
+        $Str .= ',"'.&Apache::loncommon::csv_translate($correct).'"';
+    }
+    return $Str;
 }
 
 #########################################################
@@ -417,18 +627,20 @@
     #
     $r->rflush();
     my @Columns;
-    push(@Columns,'username');
-    push(@Columns,'domain');
-    push(@Columns,'attempt');
-    push(@Columns,'time');
-    push(@Columns,'submission');
-    if ($ENV{'form.correctans'} eq 'true') { push(@Columns,'correct'); }
-    push(@Columns,'grading');
-    push(@Columns,'awarded');
-    my $awarded_col = $#Columns;
-    push(@Columns,'weight');
-    my $weight_col  = $#Columns;
-    push(@Columns,'score');
+    if (exists($ENV{'form.concise'}) && $ENV{'form.concise'} eq 'true') {
+        foreach (@DefaultColumns) {
+            if ($_->{'name'} =~ /^(username|domain|id)$/){
+                push(@Columns,$_);
+            }
+        }
+    } else {
+        @Columns = @DefaultColumns;
+    }
+    my ($awarded_col,$weight_col);
+    for (my $i=0;$i<=$#Columns;$i++) {
+        if ($Columns[$i]->{'name'} eq 'weight' ) { $weight_col = $i; }
+        if ($Columns[$i]->{'name'} eq 'awarded') { $awarded_col = $i; }
+    }
     #
     # Create excel worksheet
     my $filename = '/prtspool/'.
@@ -457,7 +669,9 @@
     $worksheet->write($rows_output++,0,$resource->{'title'},$format->{'h1'});
     $worksheet->write($rows_output++,0,$resource->{'src'},$format->{'h3'});
     $rows_output++;
-    $worksheet->write_row($rows_output++,0,\@Columns,$format->{'bold'});
+    $worksheet->write_row($rows_output++,0,
+                          [map {$_->{'display'}} @Columns],
+                          $format->{'bold'});
     #
     # Populate the worksheet with the student data
     my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
@@ -472,6 +686,7 @@
         my %row;
         $row{'username'} = $student->{'username'};
         $row{'domain'}   = $student->{'domain'};
+        $row{'id'}       = $student->{'id'};
         $row{'correct'}  = $student->{'answer'};
         $row{'weight'} = &Apache::lonnet::EXT
             ('resource.'.$partid.'.weight',$resource->{'symb'},
@@ -485,11 +700,12 @@
                     ($rows_output,$weight_col);
             my $cols_output = 0;
             foreach my $col (@Columns) {
-                if (! exists($row{$col})) {
+                if (! exists($row{$col->{'name'}})) {
                     $cols_output++;
                     next;
                 }
-                $worksheet->write($rows_output,$cols_output++,$row{$col});
+                $worksheet->write($rows_output,$cols_output++,
+                                  $row{$col->{'name'}});
             }
             $rows_output++;
         } else {
@@ -520,7 +736,7 @@
                     # This will be interpreted as a formula.  That is bad!
                     $row{'submission'} = " ".$row{'submission'};
                 }
-                $row{'grading'} = $response->[
+                $row{'awarddetail'} = $response->[
                      &Apache::loncoursedata::RDs_awarddetail()];
                 $row{'awarded'} = $response->[
                      &Apache::loncoursedata::RDs_awarded()];
@@ -533,7 +749,7 @@
                 my $cols_output = 0;
                 foreach my $col (@Columns) {
                     $worksheet->write($rows_output,$cols_output++,$row{$col},
-                                      $row_format{$col});
+                                      $row_format{$col->{'name'}});
                 }
                 $rows_output++;
             }
@@ -569,7 +785,7 @@
     ##
     ## Output Selection
     my $OutputSelector = $/.'<select name="output">'.$/;
-    foreach ('HTML','Excel') {
+    foreach ('HTML','Excel','CSV') {
         $OutputSelector .= '    <option value="'.lc($_).'"';
         if ($ENV{'form.output'} eq lc($_)) {
             $OutputSelector .= ' selected ';

--matthew1094655513--