From: Gavin L. v. a. <we...@ma...> - 2005-02-01 18:05:35
|
Log Message: ----------- Gateway update of StudentProgress.pm to allow selection of columns shown for versioned sets, and allow showing of only the version with the best score. Tags: ---- rel-2-1-a1 Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: StudentProgress.pm Revision Data ------------- Index: StudentProgress.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm,v retrieving revision 1.4.2.3 retrieving revision 1.4.2.4 diff -Llib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm -Llib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm -u -r1.4.2.3 -r1.4.2.4 --- lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm +++ lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm @@ -262,6 +262,16 @@ my $setStatsPage = $urlpath->newFromModule($urlpath->module,courseID=>$courseName,statType=>'sets',setID=>$setName); my $sort_method_name = $r->param('sort'); my @studentList = $db->listUsers; + +# another versioning/gateway change. in many cases we don't want or need +# all of the columns that are put in here by default, so we add a set of +# flags for which columns to show. for versioned sets we may also want to +# only see the best score, so we include that as an option also. +# defaults: + my %showColumns = ( 'name' => 1, 'score' => 1, 'outof' => 1, + 'date' => 0, 'index' => 1, 'problems' => 1, + 'section' => 1, 'recit' => 1, 'login' => 1 ); + my $showBestOnly = 0; my @index_list = (); # list of all student index my @score_list = (); # list of all student total percentage scores @@ -291,6 +301,20 @@ ( defined($GlobalSet->assignment_type()) && $GlobalSet->assignment_type() =~ /gateway/ ) ? 1 : 0; +# reset column view options based on whether the set is versioned and, if so, +# input parameters + if ( $setIsVersioned ) { + # the returning parameter lets us set defaults for versioned sets + my $ret = $r->param('returning'); + $showColumns{'date'} = $ret ? $r->param('show_date') : 1; + $showColumns{'index'} = $ret ? $r->param('show_index') : 0; + $showColumns{'problems'} = $ret ? $r->param('show_problems') : 0; + $showColumns{'section'} = $ret? $r->param('show_section') : 0; + $showColumns{'recit'} = $ret ? $r->param('show_recitation') : 0; + $showColumns{'login'} = $ret ? $r->param('show_login') : 0; + $showBestOnly = $ret ? $r->param('show_best_only') : 0; + } + ############################################################### # Print tables ############################################################### @@ -326,6 +350,11 @@ } } else {@myUsers = @userRecords;} + + # for versioned sets, if we're keeping track of only the high score + # then we need to know when we change student records + my $prevStuName = 'none'; + foreach my $studentRecord (@myUsers) { next unless ref($studentRecord); my $student = $studentRecord->user_id; @@ -344,6 +373,12 @@ @allSetNames = ( "$setName" ); } + # for versioned sets, we might be keeping only the high score + my $maxScore = -1; + my $max_hash = {}; + # make this global to the student loop + my $act_as_student_url = ''; + foreach my $sN ( @allSetNames ) { my $status = 0; @@ -386,7 +421,12 @@ $longStatus = 'C '; } else { - $longStatus = &threeSpaceFill($longStatus); + # change here to give a more reasonable output for gateways, + # and other versioned sets with only one attempt per version + # FIXME this isn't good in general, when versioned sets might + # FIXME allow multiple submissions + $longStatus = ($setIsVersioned)?'X ': + &threeSpaceFill($longStatus); } } else { @@ -418,13 +458,36 @@ } } + + # for versioned tests we might be displaying the test date + my $dateOfTest = ''; + # annoyingly, this is a set property, so get the set + if ( $setIsVersioned && $showColumns{'date'} ) { + my @userSet = + $db->getMergedVersionedSets( [ $studentRecord->user_id, $setName, $sN ] ); + if ( defined( $userSet[0] ) ) { # if this isn't defined, something's wrong + $dateOfTest = localtime( $userSet[0]->version_creation_time() ); + } else { + $dateOfTest = '???'; + } + } - - my $act_as_student_url = $self->systemLink($urlpath->new(type=>'set_list',args=>{courseID=>$courseName}), + $act_as_student_url = $self->systemLink($urlpath->new(type=>'set_list',args=>{courseID=>$courseName}), params=>{effectiveUser => $studentRecord->user_id} ); + # update for versioned sets +# if ( $setIsVersioned ) { +# $act_as_student_url =~ s/\/$courseName/\/$courseName\/quiz_mode/; +# } + my $email = $studentRecord->email_address; # FIXME this needs formatting + + # change to give better output for gateways + # FIXME this assumes that all versioned sets only allow one attempt + # FIXME per version, which is the case for gateways but probably not others + my $longtwo = ( $setIsVersioned ) ? $string : + "$string\n$twoString"; my $avg_num_attempts = ($num_of_problems) ? $num_of_attempts/$num_of_problems : 0; my $successIndicator = ($avg_num_attempts) ? ($totalRight/$total)**2/$avg_num_attempts : 0 ; @@ -436,19 +499,57 @@ index => $successIndicator, section => $studentRecord->section, recitation => $studentRecord->recitation, - problemString => "<pre>$string\n$twoString</pre>", + problemString => "<pre>$longtwo</pre>", act_as_student => $act_as_student_url, email_address => $studentRecord->email_address, problemData => {%h_problemData}, + date => $dateOfTest, }; + + # keep track of best score + if ( $totalRight > $maxScore ) { + $maxScore = $totalRight; + $max_hash = { %$temp_hash }; + } + + # if we're showing all records, add it in to the list + if ( ! $showBestOnly ) { # add this data to the list of total scores (out of 100) # add this data to the list of success indices. push( @index_list, $temp_hash->{index}); push( @score_list, ($temp_hash->{total}) ?$temp_hash->{score}/$temp_hash->{total} : 0 ) ; push( @augmentedUserRecords, $temp_hash ); - } - } + } + # if we're showing only the best score, add the best score now + if ( $showBestOnly ) { + if ( ! %$max_hash ) { # then we have no tests---e.g., for proctors + next; # if we could exclude proctors, etc., we + # might want to keep these: + $max_hash = { user_id => $studentRecord->user_id(), + last_name => $studentRecord->last_name(), + first_name => $studentRecord->first_name(), + score => 0, + total => 'n/a', + index => 0, + section => $studentRecord->section(), + recitation => $studentRecord->recitation(), + problemString => 'no attempt recorded', + act_as_student => $act_as_student_url, + email_address => $studentRecord->email_address(), + problemData => {}, + date => 'none', + } + } + push( @index_list, $max_hash->{index} ); + push( @score_list, + ($max_hash->{total} && $max_hash->{total} ne 'n/a') ? + $max_hash->{score}/$max_hash->{total} : 0 ); + push( @augmentedUserRecords, $max_hash ); + } + + } + $WeBWorK::timer->continue("end mainloop") if defined($WeBWorK::timer); @augmentedUserRecords = sort { &$sort_method($a,$b) @@ -458,7 +559,66 @@ ##################################################################################### # construct header my $problem_header = ''; - + +# changes for gateways/versioned sets here. in this case we allow instructors +# to modify the appearance of output, which we do with a form. so paste in the +# form header here, and make appropriate modifications + my $verSelectors = ''; + if ( $setIsVersioned ) { + print CGI::start_form({'method' => 'post', + 'action' => $self->systemLink($urlpath, + authen=>0), + 'name' => 'StudentProgress'}); + print $self->hidden_authen_fields(); + + $verSelectors = CGI::p({'style'=>'background-color:#eeeeee;color:black;'}, + "Display options: Show ", + CGI::hidden(-name=>'returning', -value=>'1'), + CGI::checkbox(-name=>'show_best_only', -value=>'1', + -checked=>$showBestOnly, + -label=>' only best scores; '), + CGI::checkbox(-name=>'show_index', -value=>'1', + -checked=>$showColumns{'index'}, + -label=>' success indicator; '), + CGI::checkbox(-name=>'show_date', -value=>'1', + -checked=>$showColumns{'date'}, + -label=>' test date; '), + CGI::checkbox(-name=>'show_problems', -value=>'1', + -checked=>$showColumns{'problems'}, + -label=>'problems;'), "\n", CGI::br(), "\n", + CGI::checkbox(-name=>'show_section', -value=>'1', + -checked=>$showColumns{'section'}, + -label=>' section #; '), + CGI::checkbox(-name=>'show_recitation', -value=>'1', + -checked=>$showColumns{'recit'}, + -label=>' recitation #; '), + CGI::checkbox(-name=>'show_login', -value=>'1', + -checked=>$showColumns{'login'}, + -label=>'login'), "\n", CGI::br(), "\n", + CGI::submit(-value=>'Update Display') + ); + } + +# set up a column header variable to allow us to drop certain columns +# for versioned set viewing + my @columnHdrs = (); +# define this for use on all of the sorts + my @paramList = ( 'returning', $r->param('returning'), 'show_best_only', + $showBestOnly, 'show_index', $showColumns{'index'}, + 'show_date', $showColumns{'date'}, + 'show_problems', $showColumns{'problems'}, + 'show_section', $showColumns{'section'}, + 'show_recitation', $showColumns{'recit'}, + 'show_login', $showColumns{'login'} ); + push(@columnHdrs, ($sort_method_name ne 'name' && $sort_method_name ne '') ? CGI::a({'href'=>$self->systemLink($setStatsPage,params=>{sort=>'name', @paramList})},'Name') : 'Name') if ( $showColumns{'name'} ); + push(@columnHdrs, $sort_method_name ne 'score' ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'score', @paramList})},'Score') : 'Score') if ( $showColumns{'score'} ); + push(@columnHdrs, 'Out'.CGI::br().'Of') if ( $showColumns{'outof'} ); + push(@columnHdrs, 'Date') if ( $showColumns{'date'} ); + push(@columnHdrs, $sort_method_name ne 'index' ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'index', @paramList})},'Ind') : 'Ind') if ( $showColumns{'index'} ); + push(@columnHdrs, 'Problems'.CGI::br().$problem_header) if ( $showColumns{'problems'} ); + push(@columnHdrs, $sort_method_name ne 'section' ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'section', @paramList})},'Section') : 'Section') if ( $showColumns{'section'} ); + push(@columnHdrs, $sort_method_name ne 'recitation' ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'recitation', @paramList})},'Recitation'):'Recitation') if ( $showColumns{'recit'} ); + push(@columnHdrs, $sort_method_name ne 'user_id' ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'user_id', @paramList})},'Login Name'):'Login Name') if ( $showColumns{'login'} ); print CGI::br(), @@ -476,21 +636,11 @@ "Click on student's name to see the student's version of the problem set; Click heading to sort table. ", CGI::br(), + $verSelectors, CGI::br(), defined($sort_method_name) ?" sort method is $sort_method_name":"", CGI::start_table({-border=>5,style=>'font-size:smaller'}), - CGI::Tr(CGI::td( {-align=>'left'}, - [CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'name' })},'Name'), - CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'score'})},'Score'), - 'Out'.CGI::br().'Of', - CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'index'})},'Ind'), - 'Problems'.CGI::br().$problem_header, - CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'section'})},'Section'), - CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'recitation'})},'Recitation'), - CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{sort=>'user_id'})},'Login Name'), - ]) - - ); + CGI::Tr(CGI::td( {-align=>'left'}, [ @columnHdrs ])); my $prevFullName = ''; my $vNum = 1; @@ -503,25 +653,31 @@ my $nameEntry = ''; if ( $fullName eq $prevFullName ) { $vNum++; - $nameEntry = CGI::td({-align=>"right"}, "(v$vNum)"); + $nameEntry = CGI::span({-style=>"text-align:right;"}, + "(v$vNum)"); } else { - $nameEntry = CGI::td(CGI::a({-href=>$rec->{act_as_student}},$fullName), ($setIsVersioned ? ' (v1)' : ''), CGI::br(), CGI::a({-href=>"mailto:$email"},$email)); + $nameEntry = + CGI::a({-href=>$rec->{act_as_student}},$fullName) . + ($setIsVersioned && ! $showBestOnly ? ' (v1)' : ' ') . + CGI::br() . CGI::a({-href=>"mailto:$email"},$email); $vNum = 1; $prevFullName = $fullName; } + # build set of columns that we want + my @cols = (); + push(@cols, $nameEntry) if ($showColumns{'name'}); + push(@cols, sprintf("%0.2f",$rec->{score})) if ($showColumns{'score'}); + push(@cols, $rec->{total}) if ( $showColumns{'outof'} ); + push(@cols, $self->nbsp($rec->{date})) if ($showColumns{'date'}); + push(@cols, sprintf("%0.0f",100*($rec->{index}))) if ($showColumns{'index'}); + push(@cols, $rec->{problemString}) if ($showColumns{'problems'}); + push(@cols, $self->nbsp($rec->{section})) if ($showColumns{'section'}); + push(@cols, $self->nbsp($rec->{recitation})) if ($showColumns{'recit'}); + push(@cols, $rec->{user_id}) if ($showColumns{'login'}); - print CGI::Tr( + print CGI::Tr( CGI::td( [ @cols ] ) ); # CGI::td(CGI::a({-href=>$rec->{act_as_student}},$fullName), CGI::br(), CGI::a({-href=>"mailto:$email"},$email)), - $nameEntry, - CGI::td( sprintf("%0.2f",$rec->{score}) ), # score - CGI::td($rec->{total}), # out of - CGI::td(sprintf("%0.0f",100*($rec->{index}) )), # indicator - CGI::td($rec->{problemString}), # problems - CGI::td($self->nbsp($rec->{section})), - CGI::td($self->nbsp($rec->{recitation})), - CGI::td($rec->{user_id}), - - ); + } print CGI::end_table(); |