--- loncom/interface/statistics/lonstudentassessment.pm 2003/03/03 19:28:29 1.31 +++ loncom/interface/statistics/lonstudentassessment.pm 2003/03/03 22:54:05 1.32 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonstudentassessment.pm,v 1.31 2003/03/03 19:28:29 matthew Exp $ +# $Id: lonstudentassessment.pm,v 1.32 2003/03/03 22:54:05 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -83,7 +83,7 @@ my $Statistics; =item $output_mode 'html', 'excel', or 'csv' for output mode -=item $show 'all' or 'totals' determines how much data is output +=item $show 'all', 'totals', or 'scores' determines how much data is output =cut @@ -270,14 +270,41 @@ sub CreateInterface { ####################################################### ####################################################### +my @OutputOptions = + ({ name => 'HTML, with links', + value => 'html, with links', + description => ''}, + { name => 'HTML, without links', + value => 'html, without links', + description => ''}, + { name => 'HTML, totals', + value => 'html, totals', + description => ''}, + { name => 'HTML, scores only', + value => 'html, scores only', + description => ''}, + { name => 'Excel, totals', + value => 'excel, totals', + description => ''}, + { name => 'Excel, scores only', + value => 'excel, scores only', + description => ''}, + { name => 'CSV, totals', + value => 'csv, totals', + description => ''}, + { name => 'CSV, scores only', + value => 'csv, scores only', + description => ''}, + { name => 'CSV, everything', + value => 'csv, everything', + description => ''} + ); + 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')) { @@ -303,18 +330,20 @@ sub CreateAndParseOutputSelector { } else { $show_links = 'no'; } - if ($restriction eq 'totals only') { + if ($restriction eq 'totals') { $show = 'totals'; + } elsif ($restriction eq 'scores only') { + $show = 'scores'; } else { $show = 'everything'; } # # Build the form element $Str = qq/"; return $Str; @@ -412,6 +441,9 @@ sub html_outputstudent { if ($show eq 'totals') { $performance = ' 'x(length($seq_max)-length($score)).$ratio; $performance .= ' 'x($seq->{'width'}-length($performance)); + } elsif ($show eq 'scores') { + $performance = $score; + $performance .= ' 'x($seq->{'width'}-length($performance)); } else { # Pad with extra spaces $performance .= ' 'x($seq->{'width'}-$seq_max- @@ -475,42 +507,173 @@ sub html_finish { { my $excel_sheet; +my $excel_workbook; + +my $filename; +my $rows_output; +my $cols_output; + +my $num_students; +my $start_time; sub excel_initialize { my ($r) = @_; # - $r->print("

Not implemented yet

"); - return; - my $filename = '/prtspool/'. + $filename = '/prtspool/'. $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. time.'_'.rand(1000000000).'.xls'; - $excel_sheet = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); - if (! defined($excel_sheet)) { + # + $excel_workbook = undef; + $excel_sheet = undef; + # + $rows_output = 0; + $cols_output = 0; + # + $num_students = 0; + $start_time = time; + # + # Create sheet + $excel_workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); + # + # Check for errors + if (! defined($excel_workbook)) { $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; + return ; } # # 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); + $excel_workbook->set_tempdir($Apache::lonnet::tmpdir); + # + # Add a worksheet + $excel_sheet = $excel_workbook->addworksheet + ($ENV{'course.'.$ENV{'request.course.id'}.'.description'}); + # + # Add the student headers + foreach my $field (&get_student_fields_to_show()) { + $excel_sheet->write(1,$cols_output++,$field); + } + # + # Add the Sequence Headers + foreach my $seq (&get_sequences_to_show) { + $excel_sheet->write(0,$cols_output,$seq->{'title'}); + if ($show eq 'totals') { + $excel_sheet->write(1,$cols_output,'score'); + $excel_sheet->write(1,$cols_output+1,'maximum'); + $cols_output += 2; + } else { + $cols_output++; + } + } + # + # Bookkeeping + if ($show eq 'totals') { + $rows_output = 2; + } else { + $rows_output = 1; + } + # + # Let the user know what we are doing + my $studentcount = scalar(@Apache::lonstatistics::Students); + $r->print("

Compiling Excel spreadsheet for ". + $studentcount.' student'); + $r->print('s') if ($studentcount > 1); + $r->print("

\n"); + $r->rflush(); # - # Determine the name to give the worksheet -# $excel_sheet->addworksheet(); - return; } sub excel_outputstudent { my ($r,$student) = @_; + return if (! defined($excel_sheet)); + $cols_output=0; + # + # Write out student data + my @to_show = &get_student_fields_to_show(); + foreach my $field (@to_show) { + $excel_sheet->write($rows_output,$cols_output++,$student->{$field}); + } + # + # Get student assessment data + my %StudentsData; + my @tmp = &Apache::loncoursedata::get_current_state($student->{'username'}, + $student->{'domain'}, + undef, + $ENV{'request.course.id'}); + if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) { + %StudentsData = @tmp; + } + # + # Write out sequence scores and totals data + foreach my $seq (&get_sequences_to_show) { + my ($performance,$score,$seq_max) = + &StudentPerformanceOnSequence($student,\%StudentsData, + $seq,'no'); + if ($show eq 'totals' || $show eq 'scores') { + $excel_sheet->write($rows_output,$cols_output++,$score); + } + if ($show eq 'totals') { + $excel_sheet->write($rows_output,$cols_output++,$seq_max); + } + } + # + # Bookkeeping + $rows_output++; + $cols_output=0; + # + # Time estimate + $num_students++; + if ($num_students % 10 == 0) { + my $time_est = (time - $start_time)/$num_students * + (scalar(@Apache::lonstatistics::Students)-$num_students); + $time_est = int($time_est); + if (int ($time_est/60) > 0) { + my $min = int($time_est/60); + my $sec = $time_est % 60; + $time_est = $min.' minutes'; + if ($sec > 1) { + $time_est.= ', '.$sec.' seconds'; + } elsif ($sec > 0) { + $time_est.= ', '.$sec.' second'; + } + } else { + $time_est .= ' seconds'; + } + $r->print($num_students.' out of '. + (scalar(@Apache::lonstatistics::Students)). + " students processed. ". + $time_est." remain.
\n"); + $r->rflush(); + } + return; } sub excel_finish { my ($r) = @_; + return if (! defined($excel_sheet)); + # + # Write the excel file + $excel_workbook->close(); + my $c = $r->connection(); + # + return if($c->aborted()); + # + # Tell the user where to get their excel file + $r->print('

'. + 'Your Excel spreadsheet.'."\n"); + my $total_time = time - $start_time; + if (int ($total_time / 60) > 0) { + $total_time = int($total_time/60).' minutes, '.($total_time % 60); + } + $r->print('
'.$total_time.' seconds total'); + $r->rflush(); + return; } } @@ -575,8 +738,7 @@ Inputs: ####################################################### ####################################################### sub StudentPerformanceOnSequence { - my ($student,$studentdata,$seq,$links,$totalonly) = @_; - $totalonly = 0 if (! defined($totalonly)); + my ($student,$studentdata,$seq,$links) = @_; $links = 'no' if (! defined($links)); my $Str = ''; my ($sum,$max) = (0,0);