--- loncom/interface/statistics/lonstudentsubmissions.pm 2004/08/31 15:22:51 1.13
+++ loncom/interface/statistics/lonstudentsubmissions.pm 2004/09/15 21:08:50 1.18
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonstudentsubmissions.pm,v 1.13 2004/08/31 15:22:51 matthew Exp $
+# $Id: lonstudentsubmissions.pm,v 1.18 2004/09/15 21:08:50 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -38,15 +38,10 @@ 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 Spreadsheet'},
+ text => 'Generate Report'},
);
sub BuildStudentSubmissionsPage {
@@ -90,108 +85,797 @@ sub BuildStudentSubmissionsPage {
$r->print($html.(' 'x5));
}
#
- $r->print('
');
+ $r->print(' '.$/);
$r->rflush();
#
- # Determine which problem we are to analyze
- my $current_problem = &Apache::lonstathelpers::get_target_from_id
- ($ENV{'form.problemchoice'});
- #
- my ($prev,$curr,$next) =
- &Apache::lonstathelpers::get_prev_curr_next($current_problem,
- '.',
- 'response',
- );
- if (exists($ENV{'form.PrevProblem'}) && defined($prev)) {
- $current_problem = $prev;
- } elsif (exists($ENV{'form.NextProblem'}) && defined($next)) {
- $current_problem = $next;
- } else {
- $current_problem = $curr;
+ # Determine which problems we are to analyze
+ my @Symbs =
+ &Apache::lonstathelpers::get_selected_symbs('problemchoice');
+ foreach my $selected (@Symbs) {
+ $r->print(' '.$/);
}
#
- # Store the current problem choice and send it out in the form
- $ENV{'form.problemchoice'} =
- &Apache::lonstathelpers::make_target_id($current_problem);
- $r->print(' ');
+ # Get resource objects
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (!defined($navmap)) {
+ $r->print(''.&mt("Internal error").' ');
+ return;
+ }
+ my %already_seen;
+ my @Problems;
+ foreach my $symb (@Symbs) {
+ my $resource = $navmap->getBySymb($symb);
+ push(@Problems,$resource);
+ }
#
- if (! defined($current_problem->{'resource'})) {
+ if (! scalar(@Problems) || ! defined($Problems[0])) {
$r->print('resource is undefined');
} else {
- my $resource = $current_problem->{'resource'};
- $r->print(''.$resource->{'title'}.' ');
- $r->print(''.$resource->{'src'}.' ');
- $r->print(&Apache::lonstathelpers::render_resource($resource));
- $r->rflush();
- my %Data = &Apache::lonstathelpers::get_problem_data
- ($resource->{'src'});
- my $ProblemData = $Data{$current_problem->{'part'}.
- '.'.
- $current_problem->{'respid'}};
- &prepare_excel_output($r,$current_problem,
- $ProblemData,\@Students);
+ if (scalar(@Problems) == 1) {
+ my $resource = $Problems[0];
+ $r->print(''.$resource->title.' ');
+ $r->print(''.$resource->src.' ');
+ if ($ENV{'form.renderprob'} eq 'true') {
+ $r->print(
+ &Apache::lonstathelpers::render_resource({src => $resource->src})
+ );
+ $r->rflush();
+ }
+ }
+ my %Data;
+ if (scalar(@Problems) > 5) {
+ # progress window
+ my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
+ ($r,'Problem Analysis Status',
+ 'Problem Analysis Progress',
+ scalar(@Problems),
+ 'inline',undef,'Statistics','stats_status');
+ foreach my $problem (@Problems) {
+ $Data{$problem->symb} =
+ {&Apache::lonstathelpers::get_problem_data
+ ($problem->src)};
+ &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
+ 'last problem');
+
+ }
+ &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+ } else {
+ foreach my $problem (@Problems) {
+ $Data{$problem->symb} =
+ {&Apache::lonstathelpers::get_problem_data
+ ($problem->src)};
+ }
+ }
+ &new_excel_output($r,\@Problems,\@Students,\%Data);
}
$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('.'));
+ $r->print(&Apache::lonstathelpers::MultipleProblemSelector
+ (undef,'.','problemchoice','Statistics'));
+ }
+}
+
+#########################################################
+#########################################################
+
+sub new_excel_output {
+ my ($r,$Problems,$Students,$ProblemData) = @_;
+ my $c = $r->connection();
+ #
+ if (scalar(@$Problems) > 1) {
+ $r->print(''.
+ &mt('Preparing Excel spreadsheet of student responses to [_1] problems',
+ scalar(@$Problems)).
+ ' ');
+ } else {
+ $r->print(''.
+ &mt('Preparing Excel spreadsheet of student responses').
+ ' ');
+ }
+ $r->rflush();
+ #
+ # Create the excel spreadsheet
+ my $filename = '/prtspool/'.
+ $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
+ time.'_'.rand(1000000000).'.xls';
+ my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
+ if (! defined($workbook)) {
+ $r->log_error("Error creating excel spreadsheet $filename: $!");
+ $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');
+ #
+ # 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++,$_,$format->{'bold'});
+ }
+ # Problem headers
+ foreach my $prob (@$Problems) {
+ my $title = &get_title($prob->title,$prob->src);
+ $worksheet->write($title_row,$cols_output,
+ $title,$format->{'h3'});
+ foreach my $partid (@{$prob->parts}) {
+ $worksheet->write($partid_row,$cols_output,$partid);
+ my $responses = [$prob->responseIds($partid)];
+ my $resptypes = [$prob->responseType($partid)];
+ for (my $i=0;$iwrite($respid_row,$cols_output,
+ $resptypes->[$i].', '.$responses->[$i]);
+ $worksheet->write($header_row,$cols_output,'Submission');
+ $cols_output++;
+ }
+ }
+ }
+ #
+ # 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());
+ $cols_output = 0;
+ foreach my $field (@StudentColumns) {
+ $worksheet->write($rows_output,$cols_output++,
+ $student->{$field});
+ }
+ foreach my $prob (@$Problems) {
+ foreach my $partid (@{$prob->parts}) {
+ my @Response = $prob->responseIds($partid);
+ my @ResponseType = $prob->responseType($partid);
+ for (my $i=0;$i<=$#Response;$i++) {
+ my $respid = $Response[$i];
+ my $resptype = $ResponseType[$i];
+ my $results =
+ &Apache::loncoursedata::get_response_data_by_student
+ ($student,$prob->symb(),$respid);
+ my $final_response = $results->[-1];
+ my $submission =
+ $final_response->[
+ &Apache::loncoursedata::RDs_submission()
+ ];
+ $submission=&excel_format_response($submission,$resptype);
+ $worksheet->write($rows_output,$cols_output++,
+ $submission);
+ }
+ }
+ }
+ $rows_output++;
+ &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
+ 'last student');
+ }
+ &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+ #
+ # Close the excel file
+ $workbook->close();
+ #
+ # Write a link to allow them to download it
+ $r->print(''.
+ &mt('Your Excel spreadsheet.').
+ '
'."\n");
+ $r->print('');
+ $r->rflush();
+ return;
+}
+
+sub get_title {
+ my ($title,$src) = @_;
+ if ($title eq '') {
+ ($title) = ($src =~ m|/([^/]+)$|);
+ } else {
+ $title =~ s/\:/:/g;
+ }
+ return $title;
+}
+
+sub excel_format_response {
+ my ($answer,$responsetype) = @_;
+ if ($responsetype eq 'radiobutton') {
+ $answer =~ s/=([^=])$//;
+ } elsif ($responsetype eq 'option') {
+ $answer = join("\n",
+ map {
+ &Apache::lonnet::unescape($_) ;
+ } sort split('&',$answer)
+ );
+ }
+ if ($answer =~ m/^=/) {
+ $answer = ' '.$answer;
}
+ return $answer;
}
+
+=pod
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#########################################################
+#########################################################
+
+my @DefaultColumns =
+ (
+ {name=>'username',
+ display=>'Student'},
+ {name=>'domain',
+ display=>'Domain'},
+ {name => 'id',
+ display => 'Id'},
+ # FIXME: Probably need to add score
+ );
+
+my @PartColumns =
+ (
+ {name => 'time',
+ display =>'Time'},
+ {name => 'attempt',
+ display =>'Attempt'},
+ {name => 'awarded',
+ display =>'Award'},
+ {name => 'weight',
+ display =>'Part Weight'},
+ {name => 'score',
+ display =>'Score'},
+ );
+
+my @ResponseColumns =
+ (
+ {name => 'submission',
+ display =>'Submission'},
+ {name => 'answer',
+ display =>'Correct Answer'},
+ {name => 'awarddetail',
+ display =>'Awarddetail'},
+ );
+
+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;
+}
+
+
#########################################################
#########################################################
##
-## Excel output of student answers and correct answers
+## prepare_html_output
##
#########################################################
#########################################################
-sub prepare_excel_output {
- my ($r,$problem,$ProblemData,$Students) = @_;
+sub prepare_html_output {
+ my ($r,$Problems,$Students) = @_;
+ my $problem;
my $c = $r->connection();
my ($resource,$respid,$partid) = ($problem->{'resource'},
$problem->{'respid'},
$problem->{'part'});
- $r->print(''.
- &mt('Preparing Excel spreadsheet of student responses').
- ' '.
- ''.
- &mt('See the status bar above for student answer computation progress').
- '
');
#
if ($ENV{'form.correctans'} eq 'true') {
+ $r->print(''.&mt('Generating Correct Answers').' ');
&Apache::lonstathelpers::GetStudentAnswers($r,$problem,$Students,
'Statistics',
'stats_status');
}
#
- $r->print('');
+ $r->print(''.&mt('Student Responses').' ');
+ #
$r->rflush();
+ my $response_type = &get_response_type($resource,$partid,$respid);
+ if (! defined($response_type)) {
+ $r->print(''.&mt('Unable to determine response type').' ');
+ return;
+ }
+ my $count = 0;
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');
- push(@Columns,'weight');
- push(@Columns,'score');
- my ($awarded_col,$weight_col);
+ 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();
+ }
+ $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()];
+ $data->{'weight'} = &Apache::lonnet::EXT
+ ('resource.'.$partid.'.weight',$resource->{'symb'},
+ undef,undef,undef);
+ $data->{'score'} = $data->{'weight'} * $data->{'awarded'};
+ 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(''.$/);
+ return;
+}
+
+#####################################################
+##
+## HTML helper routines
+##
+#####################################################
+sub html_headers {
+ my ($Columns) = @_;
+ my $Str;
+ foreach my $column (@$Columns) {
+ $Str .= ''.$column->{'display'}.' ';
+ }
+ return $Str;
+}
+
+sub html_essay {
+ my ($submission,$correct,$tablewidth,$rowextra)=@_;
+ #
+ $submission =~ s|\\r\\n|$/|g;
+ $submission = &HTML::Entities::encode($submission,'<>&"');
+ $submission =~ s|$/\s*$/|$/$/|g;
+ $submission =~ s|\\||g;
+ $submission = '
'.$submission.'
';
+ #
+ my $Str = ''.
+ ''.$submission.' ';
+ if ($ENV{'form.correctans'} eq 'true') {
+ $Str .= ' ';
+ if (defined($correct) && $correct !~ /^\s*$/) {
+ $Str .= ''.
+ ''.&mt('Correct Answer:').' '.$correct.' ';
+ }
+ }
+ $Str .= ' ';
+ #
+ return $Str;
+}
+
+sub html_essay_headers {
+ return '';
+}
+
+sub html_generic_headers {
+ my $header =''.&mt('Submission').' ';
+ if ($ENV{'form.correctans'} eq 'true') {
+ $header .= ''.&mt('Correct').' ';
+ }
+ return $header;
+}
+
+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_results {
+ my ($submission,$correct,$tablewidth,$rowclass)=@_;
+ my $Str .= ''.$submission.' ';
+ if ($ENV{'form.correctans'} eq 'true') {
+ $Str .= ''.$correct.' ';
+ }
+ $Str .= '';
+ return $Str;
+}
+
+sub html_option_results {
+ my ($submission,$correct,$tablewidth,$rowclass)=@_;
+ $submission =
+ ''.
+ ''.join(' ',
+ map {
+ &Apache::lonnet::unescape($_) ;
+ } sort split('&',$submission)
+ ).
+ '