--- loncom/interface/statistics/lonstudentsubmissions.pm 2004/09/02 21:02:54 1.16 +++ loncom/interface/statistics/lonstudentsubmissions.pm 2004/09/08 14:58:33 1.17 @@ -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 @@ sub BuildStudentSubmissionsPage { 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 @@ sub BuildStudentSubmissionsPage { $r->print('
'); } else { $r->print(''); + &mt('Prepare Report').'" />'); $r->print(' 'x5); $r->print('

'.&mt('Please select a problem to analyze').'

'); $r->print(&Apache::lonstathelpers::ProblemSelector('.')); @@ -166,10 +169,27 @@ my @DefaultColumns = 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{'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 @@ sub prepare_html_output { $r->print('

'.&mt('Student Responses').'

'); # $r->rflush(); - my $response_type; - for (my $i=0; - $i{'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('

'.&mt('Unable to determine response type').'

'); - } 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 = ''.$/.&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 = '
'.$/.&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 = ''.$header.''; + # + $r->print($/.$header.$/); + foreach my $student (@$Students) { + if ($count >= 50) { + $r->print('
'.$/.$header.$/); + $count = 0; } - $header = ''.$header.''; - # - $r->print($/.$header.$/); - foreach my $student (@$Students) { - if ($count >= 50) { - $r->print(''.$/.$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[$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 = ''; - foreach my $col (@Columns) { - $row .= ''. - $data->{$col->{'name'}}.''; - } - 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 .= ''; - $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[$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 = ''; + foreach my $col (@Columns) { + $row .= ''. + $data->{$col->{'name'}}.''; + } + 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 .= ''; + $r->print($row.$/); + $count++; } - $r->print(''.$/); } + $r->print(''.$/); return; } @@ -342,13 +353,17 @@ sub html_generic_headers { 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 .= ''.$submission.''; if ($ENV{'form.correctans'} eq 'true') { @@ -358,11 +373,7 @@ sub html_generic { return $Str; } -sub html_option_headers { - return &html_generic_headers(); -} - -sub html_option { +sub html_option_results { my ($submission,$correct,$tablewidth,$rowclass)=@_; $submission = '
    '. @@ -382,7 +393,206 @@ sub html_option { '
'; } # - 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('

'.&mt('Generating Correct Answers').'

'); + &Apache::lonstathelpers::GetStudentAnswers($r,$problem,$Students, + 'Statistics', + 'stats_status'); + } + # + $r->print('

'. + &mt('Generating CSV report of student responses').'

'); + # + # 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('

'.&mt('Unable to determine response type').'

'); + 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[$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('
'. + ''.&mt('Your csv file.').''."\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 @@ sub prepare_excel_output { # $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 @@ sub prepare_excel_output { $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 @@ sub prepare_excel_output { 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 @@ sub prepare_excel_output { ($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 @@ sub prepare_excel_output { # 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 @@ sub prepare_excel_output { 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 @@ sub CreateInterface { ## ## Output Selection my $OutputSelector = $/.'