--- loncom/interface/statistics/lonstudentsubmissions.pm 2004/09/08 14:58:33 1.17 +++ loncom/interface/statistics/lonstudentsubmissions.pm 2004/09/23 14:55:24 1.24 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonstudentsubmissions.pm,v 1.17 2004/09/08 14:58:33 matthew Exp $ +# $Id: lonstudentsubmissions.pm,v 1.24 2004/09/23 14:55:24 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,12 +38,7 @@ use HTML::Entities(); use Time::Local(); use Spreadsheet::WriteExcel(); -my @SubmitButtons = ({ name => 'PrevProblem', - text => 'Previous Problem' }, - { name => 'NextProblem', - text => 'Next Problem' }, - { name => 'break'}, - { name => 'SelectAnother', +my @SubmitButtons = ({ name => 'SelectAnother', text => 'Choose a different Problem' }, { name => 'Generate', text => 'Generate Report'}, @@ -72,7 +67,8 @@ sub BuildStudentSubmissionsPage { } # my @CacheButtonHTML = - &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status'); + &Apache::lonstathelpers::manage_caches($r,'Statistics','stats_status', + '
'. + &mt('Computing correct answers greatly increasese the amount of time required to prepare a report.'). + '
'); + $r->print(''. + &mt('please select problems and use the Prepare Report button to continue.'). + '
'); + $r->print(&Apache::lonstathelpers::MultipleProblemSelector + (undef,'problemchoice','Statistics')); } - return $response_type; } - ######################################################### ######################################################### ## -## prepare_html_output +## HTML Output Routines ## ######################################################### ######################################################### sub prepare_html_output { - my ($r,$problem,$ProblemData,$Students) = @_; + my ($r,$problems,$students) = @_; my $c = $r->connection(); - my ($resource,$respid,$partid) = ($problem->{'resource'}, - $problem->{'respid'}, - $problem->{'part'}); # - if ($ENV{'form.correctans'} eq 'true') { - $r->print('$/|g; - $submission =~ s|\\||g; - $submission = '
'.$submission.'
'; + my $submission =$response->[&Apache::loncoursedata::RDs_submission()]; + $submission = &html_format_sub($submission,'essay'); # - my $Str = '$/|g; + $submission =~ s|\\||g; + $submission = '
'.$submission.'
'; + } elsif ($resptype eq 'radiobutton') { + $submission =~ s/=([^=])$//; + } elsif ($resptype =~ /^(option|match|rank)$/) { + $submission = + ''.&mt('LON-CAPA is unable to produce your Excel spreadsheet because your selections will result in more than 255 columns. Excel allows only 255 columns in a spreadsheet.').'
'.$/. + ''.&mt('Consider selecting fewer problems to generate reports on, or reducing the number of items per problem. Or use HTML or CSV output.').'
'.$/. + ''.&mt('The last problem that will fit in the current spreadsheet is [_1].',$lastprob->compTitle).'
'); + $r->rflush(); + return; + } # - # 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'); - + # Print out a message telling them what we are doing + if (scalar(@$Problems) > 1) { + $r->print(''.&mt("Unable to create new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"). + '
'); + return undef; } # + $workbook->set_tempdir('/home/httpd/perl/tmp'); + # + my $format = &Apache::loncommon::define_excel_formats($workbook); + my $worksheet = $workbook->addworksheet('Student Submission Data'); # - my @Columns; - if (exists($ENV{'form.concise'}) && $ENV{'form.concise'} eq 'true') { - foreach (@DefaultColumns) { - if ($_->{'name'} =~ /^(username|domain|id)$/){ - push(@Columns,$_); + # Add headers to the worksheet + my $rows_output = 0; + $worksheet->write($rows_output++,0, + $ENV{'course.'.$ENV{'request.course.id'}.'.description'}, + $format->{'h1'}); + $rows_output++; + my $cols_output = 0; + my $title_row = $rows_output++; + my $partid_row = $rows_output++; + my $respid_row = $rows_output++; + my $header_row = $rows_output++; + $worksheet->write($title_row ,0,'Problem Title',$format->{'bold'}); + $worksheet->write($partid_row,0,'Part ID',$format->{'bold'}); + $worksheet->write($respid_row,0,'Response ID',$format->{'bold'}); + # Student headers + my @StudentColumns = ('username','domain','id'); + foreach (@StudentColumns) { + $worksheet->write($header_row,$cols_output++,ucfirst($_), + $format->{'bold'}); + } + # Problem headers + foreach my $prob (@$Problems) { + my $title = $prob->compTitle; + $worksheet->write($title_row,$cols_output, + $title,$format->{'h3'}); + foreach my $partid (@{$prob->parts}) { + $worksheet->write($partid_row,$cols_output, + $prob->part_display($partid)); + my $responses = [$prob->responseIds($partid)]; + my $resptypes = [$prob->responseType($partid)]; + for (my $i=0;$i'. + &mt('Your Excel spreadsheet.'). + '
'."\n"); + $r->print(''); $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).'"'; +sub write_excel_row { + my ($worksheet,$row,$col,$response,$student,$prob,$partid,$respid, + $format,$resptype) = @_; + # + my $submission =$response->[&Apache::loncoursedata::RDs_submission()]; + $submission = &excel_format_response($submission,$resptype); + $worksheet->write($row,$col++,$submission); 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(',', + my $correct = &Apache::lonstathelpers::analyze_problem_as_student + ($prob,$student->{'username'},$student->{'domain'}, + $partid,$respid); + $correct =&excel_format_response($correct,$resptype); + $worksheet->write($row,$col++,$correct); + } + if ($ENV{'form.prob_status'} eq 'true') { + $worksheet->write + ($row,$col++, + $response->[&Apache::loncoursedata::RDs_awarddetail()]); + $worksheet->write + ($row,$col++,$response->[&Apache::loncoursedata::RDs_tries()]); + $worksheet->write + ($row,$col++, + &Apache::lonstathelpers::calc_serial + ($response->[&Apache::loncoursedata::RDs_timestamp()]), + $format->{'date'}); + $worksheet->write + ($row,$col++,$response->[&Apache::loncoursedata::RDs_awarded()]); + } + return $col; +} + +sub excel_format_response { + my ($answer,$responsetype) = @_; + if ($responsetype eq 'radiobutton') { + $answer =~ s/=([^=])$//; + } elsif ($responsetype =~ /^(option|match)$/) { + $answer = join("\n", map { &Apache::lonnet::unescape($_) ; - } sort split('&',$submission) + } sort split('&',$answer) ); - 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).'"'; + if ($answer =~ m/^=/) { + $answer = ' '.$answer; } - return $Str; + return $answer; } ######################################################### ######################################################### ## -## Excel output of student answers and correct answers +## CSV output of student answers ## ######################################################### ######################################################### -sub prepare_excel_output { - my ($r,$problem,$ProblemData,$Students) = @_; +sub prepare_csv_output { + my ($r,$problems,$students) = @_; my $c = $r->connection(); - my ($resource,$respid,$partid) = ($problem->{'resource'}, - $problem->{'respid'}, - $problem->{'part'}); - $r->print(''. - &mt('See the status bar above for student answer computation progress'). - '
'); # - if ($ENV{'form.correctans'} eq 'true') { - &Apache::lonstathelpers::GetStudentAnswers($r,$problem,$Students, - 'Statistics', - 'stats_status'); - $r->print(''); - } + $r->print(''.&mt("Unable to create new Excel file. ". - "This error has been logged. ". - "Please alert your LON-CAPA administrator"). - '
'); - return undef; + 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; } # - $workbook->set_tempdir('/home/httpd/perl/tmp'); - # - my $format = &Apache::loncommon::define_excel_formats($workbook); - my $worksheet = $workbook->addworksheet('Student Submission Data'); - # - # Make sure we get new weight data instead of data on a 10 minute delay - &Apache::lonnet::clear_EXT_cache_status(); - # - # Put on the standard headers and whatnot - my $rows_output=0; - $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, - [map {$_->{'display'}} @Columns], - $format->{'bold'}); + # Compute the number of columns per response + my @response_headers = ('Submission'); + if ($ENV{'form.correctans'} eq 'true') { + push(@response_headers,'Correct'); + } + if ($ENV{'form.prob_status'} eq 'true') { + push(@response_headers,'Award Detail'); + push(@response_headers,'Time'); + push(@response_headers,'Attempt'); + push(@response_headers,'Awarded'); + } + my $response_multiplier = scalar(@response_headers); + # + # Create the table header + my @student_columns = ('username','domain','id'); + # + my %headers; + push(@{$headers{'student'}},@student_columns); + # Pad for the student data + foreach my $row ('problem','part','response') { + foreach (@student_columns) { + push(@{$headers{$row}},''); + } + } # - # Populate the worksheet with the student data - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin - ($r,'Excel File Compilation Status', - 'Excel File Compilation Progress', - scalar(@$Students),'inline',undef,'Statistics','stats_status'); - foreach my $student (@$Students) { - last if ($c->aborted()); - - my $results = &Apache::loncoursedata::get_response_data_by_student - ($student,$resource->{'symb'},$respid); - 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'}, - undef,undef,undef); - if (! defined($results) || ref($results) ne 'ARRAY') { - $row{'score'} = '='. - &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell - ($rows_output,$awarded_col) - .'*'. - &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell - ($rows_output,$weight_col); - my $cols_output = 0; - foreach my $col (@Columns) { - if (! exists($row{$col->{'name'}})) { - $cols_output++; - next; + # we put the headers into the %headers hash + my $prob_start_idx = 0; + foreach my $prob (@$problems) { + $headers{'problem'}->[$prob_start_idx] = $prob->compTitle; + my $part_start_idx = $prob_start_idx; + foreach my $partid (@{$prob->parts}) { + $headers{'part'}->[$part_start_idx] = $prob->part_display($partid); + my $responses = [$prob->responseIds($partid)]; + for (my $i=0;$i'. - &mt('Your Excel spreadsheet.'). - '
'."\n"); - $r->print(''); + # Tell the user where to get their csv file + $r->print('