From: Gavin L. v. a. <we...@ma...> - 2005-06-09 15:01:51
|
Log Message: ----------- Gateway bugfixes/feature additions - added test time to student progress display - corrected bugs from overtime proctored tests - corrected behavior for closed tests - added restrictions to prevent gateways from being taken as regular assignments - updated problem set lists to better deal with gateways Tags: ---- rel-2-1-a1 Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator: GatewayQuiz.pm Problem.pm ProblemSet.pm webwork2/lib/WeBWorK/ContentGenerator/Instructor: ProblemSetEditor.pm ProblemSetList.pm StudentProgress.pm Revision Data ------------- Index: Problem.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm,v retrieving revision 1.143.2.4 retrieving revision 1.143.2.5 diff -Llib/WeBWorK/ContentGenerator/Problem.pm -Llib/WeBWorK/ContentGenerator/Problem.pm -u -r1.143.2.4 -r1.143.2.5 --- lib/WeBWorK/ContentGenerator/Problem.pm +++ lib/WeBWorK/ContentGenerator/Problem.pm @@ -84,6 +84,9 @@ # # ($self, $User, $PermissionLevel, $EffectiveUser, $Set, $Problem) +# *** GatewayQuiz note: +# *** The "can" routines are excerpted with few changes to GatewayQuiz.pm + sub can_showOldAnswers { #my ($self, $User, $PermissionLevel, $EffectiveUser, $Set, $Problem) = @_; @@ -167,6 +170,10 @@ sub after { return time >= $_[0] } sub between { my $t = time; return $t > $_[0] && $t < $_[1] } +# *** GatewayQuiz note: +# *** output utilities are transcribed verbatim to GatewayQuiz.pm, though +# *** we may change the summary message in attemptResults at some point + ################################################################################ # output utilities ################################################################################ @@ -390,10 +397,23 @@ # obtain the merged set for $effectiveUser my $set = $db->getMergedSet($effectiveUserName, $setName); # checked + +# gateway check here: we want to be sure that someone isn't trying to take +# a GatewayQuiz through the regular problem/homework mechanism, thereby +# circumventing the versioning, time limits, etc. + $self->{invalidSet} = 'The "Problem" ContentGenerator was called for ' . + 'a GatewayQuiz' if ( defined( $set->assignment_type() ) && + $set->assignment_type() =~ /gateway/ ); # obtain the merged problem for $effectiveUser my $problem = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked + # this shouldn't happen, but we're happy to have a check to preent people + # from gaming the system + die "Set $setName is a gateway test. Error in ContentGenerator call." + if ( defined($set) && defined( $set->assignment_type ) && + $set->assignment_type =~ /gateway/ ); + my $editMode = $r->param("editMode"); if ($authz->hasPermissions($userName, "modify_problem_sets")) { @@ -857,6 +877,11 @@ ##### answer processing ##### $WeBWorK::timer->continue("begin answer processing") if defined($WeBWorK::timer); + +# *** GatewayQuiz note: +# *** this conditional through to the output section of this subroutine is +# *** duplicated almost verbatim in GatewayQuiz.pm, after wrapping it in a loop. + # if answers were submitted: my $scoreRecordedMessage; my $pureProblem; Index: GatewayQuiz.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm,v retrieving revision 1.9.4.9 retrieving revision 1.9.4.10 diff -Llib/WeBWorK/ContentGenerator/GatewayQuiz.pm -Llib/WeBWorK/ContentGenerator/GatewayQuiz.pm -u -r1.9.4.9 -r1.9.4.10 --- lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -19,21 +19,11 @@ =head1 NAME -WeBWorK::ContentGenerator::GatewayQuiz - display a quiz of problems on one page, +WeBWorK::ContentGenerator::GatewayQuiz - display a quiz of problems on one page, deal with versioning sets =cut -# ASSUMPTIONS ABOUT DATABASE DATA -# set data includes the new entries: -# assignment_type -# attempts_per_version -# time_interval -# versions_per_interval -# version_time_limit -# version_creation_time -# problem_randorder - use strict; use warnings; use CGI qw(); @@ -205,7 +195,7 @@ # gateway change here: we allow an optional additional argument to use as the # time to check rather than time() sub before { return (@_==2) ? $_[1] <= $_[0] : time <= $_[0] } -sub after { return (@_==2) ? $_[1] <= $_[0] : time >= $_[0] } +sub after { return (@_==2) ? $_[1] >= $_[0] : time >= $_[0] } sub between { my $t = (@_==3) ? $_[2] : time; return $t > $_[0] && $t < $_[1] } ################################################################################ @@ -691,6 +681,9 @@ $versionIsOpen = 1; } else { $versionIsOpen = 0; # redundant; default is 0 + $self->{invalidSet} = "No new versions of this assignment" . + "are available,\nbecause the set is not open or its" . + "time limit has expired.\n"; } } elsif ( $versionsPerInterval && @@ -744,15 +737,21 @@ } # set isn't available. - } else { + } elsif ( ! $isOpen ) { # die("No available set version is available for $userName, and " . # "none can be created after the due date.") $self->{invalidSet} = "This assignment is not open."; - if ( $isClosed) { - $self->{invalidSet} .= "\nPreviously completed versions " . - "may be available for practice,\n but no new versions " . - "may be obtained at this time.\n"; - } +# the following isn't what we want, because ! isOpen -> before open date, +# while isClosed -> after closed date, which takes care of itself (we +# aren't allowed to save answers, etc.) so that we don't need any error message +# if ( $isClosed) { +# $self->{invalidSet} .= "\nPreviously completed versions " . +# "may be available for practice,\n but no new versions " . +# "may be obtained at this time.\n"; +# } + } elsif ( ! $requestedVersion ) { # closed set, with attempt at a new one + $self->{invalidSet} = "This set is closed. No new set versions may " . + "be taken."; } @@ -1017,6 +1016,7 @@ my $setVersionName = $set->set_id; my ( $setName ) = ( $setVersionName =~ /(.*),v\d+$/ ); + my ( $versionNumber ) = ( $setVersionName =~ /.*,v(\d+)$/ ); # translation errors -- we use the same output routine as Problem.pm, but # play around to allow for errors on multiple translations because we @@ -1185,44 +1185,37 @@ } } # end loop through problems -# additional set-level submitAnswers database manipulation: this is all -# for versioned sets/gateway tests +# warn("in submitanswers conditional\n"); + + } # end if submitAnswers conditional + $WeBWorK::timer->continue("end answer processing") + if defined( $WeBWorK::timer ); + +# additional set-level database manipulation: this is all for versioned +# sets/gateway tests # we want to save the time that a set was submitted, and for proctored # tests we want to reset the assignment type after a set is submitted -# for the last time so that it's possible to look at it without getting -# proctor authorization - if ( $will{recordAnswers} || ( ! $can{recordAnswersNextTime} && - $set->assignment_type() eq 'proctored_gateway' ) ) { +# for the last time so that it's possible to look at it later without +# getting proctor authorization + if ( ( $submitAnswers && $will{recordAnswers} ) || + ( ! $can{recordAnswersNextTime} && + $set->assignment_type() eq 'proctored_gateway' ) ) { + # warn("in put set conditional\n"); - my $setName = $set->set_id(); -# I started out getting the set back out of the database, but I don't think -# this is needed here. the only manipulation of the $set object is internal, -# so I think it's safe to just use the $set that we have -# # note that getMergedVersionedSet returns the requested set if the set name is -# # versioned ("name,vN"), or the latest set if no version is specified (that -# # is, it gives us the set we're working with) -# my $cleanSet = $db->getMergedVersionedSet($user,$setName); - - if ( $will{recordAnswers} ) { -# $cleanSet->version_last_attempt_time( $timeNow ); - $set->version_last_attempt_time( $timeNow ); -# warn("set last attempt time in clean set " . $set->set_id() . " to $timeNow\n"); - } - if ( ! $can{recordAnswersNextTime} && - $set->assignment_type() eq 'proctored_gateway' ) { -# $cleanSet->assignment_type( 'gateway' ); - $set->assignment_type( 'gateway' ); - } -# $db->putVersionedUserSet( $cleanSet ); - $db->putVersionedUserSet( $set ); + my $setName = $set->set_id(); + + if ( $submitAnswers && $will{recordAnswers} ) { + $set->version_last_attempt_time( $timeNow ); + } + if ( ! $can{recordAnswersNextTime} && + $set->assignment_type() eq 'proctored_gateway' ) { + $set->assignment_type( 'gateway' ); } + $db->putVersionedUserSet( $set ); + } -# warn("in submitanswers conditional\n"); - } # end if submitAnswers conditional - $WeBWorK::timer->continue("end answer processing") - if defined( $WeBWorK::timer ); #################################### # output @@ -1261,7 +1254,8 @@ } print CGI::div({class=>"$divClass"}, - CGI::strong("Score on this attempt = " . + CGI::strong("Score on this attempt (test number " . + "$versionNumber) = " . "$overallScore / $totPossible"), CGI::br(), CGI::strong("$recdMsg")),"\n\n"; @@ -1276,8 +1270,9 @@ "because its time limit has expired.\n" . "To attempt the set again, please try again after the time " . "limit between versions has expired.\n"; - print CGI::p(CGI::strong("Note: this set version can no longer be " . - "submitted for a grade"),"\n",$mesg,"\n", + print CGI::p(CGI::strong("Note: this set version (number " . + "$versionNumber) can no longer be submitted for a" . + " grade"),"\n",$mesg,"\n", "You may, however, check your answers to see what you did" . " right or wrong."), "\n\n"; print CGI::end_div(); @@ -1476,6 +1471,18 @@ print CGI::endform(); +# debugging verbiage +# if ( $can{checkAnswersNextTime} ) { +# print "Can check answers next time\n"; +# } else { +# print "Can NOT check answers next time\n"; +# } +# if ( $can{recordAnswersNextTime} ) { +# print "Can record answers next time\n"; +# } else { +# print "Can NOT record answers next time\n"; +# } + # we exclude the feedback form from gateway tests. they can use the feedback # button on the preceding or following pages # my $ce = $r->ce; Index: ProblemSet.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm,v retrieving revision 1.54.2.4 retrieving revision 1.54.2.5 diff -Llib/WeBWorK/ContentGenerator/ProblemSet.pm -Llib/WeBWorK/ContentGenerator/ProblemSet.pm -u -r1.54.2.4 -r1.54.2.5 --- lib/WeBWorK/ContentGenerator/ProblemSet.pm +++ lib/WeBWorK/ContentGenerator/ProblemSet.pm @@ -48,6 +48,9 @@ die "user $user (real user) not found." unless $user; die "effective user $effectiveUserName not found. One 'acts as' the effective user." unless $effectiveUser; + die "set $setName is a GatewayQuiz. Enter through the GatewayQuiz " . + "module." if ( defined( $set->assignment_type() ) && + $set->assignment_type() =~ /gateway/ ); # A set is valid if it is defined and if it is either published or the user is privileged. $self->{invalidSet} = !(defined $set && ($set->published || $authz->hasPermissions($userName, "view_unpublished_sets"))); @@ -102,7 +105,7 @@ my @setIDs = sortByName(undef, $db->listUserSets($eUserID)); # do not show unpublished siblings unless user is allowed to view unpublished sets unless ($authz->hasPermissions($user, "view_unpublished_sets") ) { - @setIDs = grep {my $vset = $db->getGlobalSet($_); my $visible = defined($vset) ? $vset->published : 0; (defined($visible))? $visible : 1} + @setIDs = grep {my $visible = $db->getGlobalSet( $_)->published; (defined($visible))? $visible : 1} @setIDs; } print CGI::start_ul({class=>"LinksMenu"}); Index: ProblemSetEditor.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm,v retrieving revision 1.57.2.4 retrieving revision 1.57.2.5 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm -u -r1.57.2.4 -r1.57.2.5 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm @@ -415,7 +415,7 @@ my $timeInterval = ( defined( $setRecord->time_interval ) && $setRecord->time_interval ne '' ) ? int(($setRecord->time_interval() + 0.5)/60) : - 7200; # default is 12 hours + 720; # default is 12 hours print CGI::table( {}, CGI::Tr( {}, [ CGI::td( {}, " ", @@ -448,7 +448,7 @@ CGI::td( {}, " ", setRowHTML( "Order problems randomly in set (0|1)", "problem_randorder", - $setRecord->problem_randorder ? + $setRecord->problem_randorder ne '' ? $setRecord->problem_randorder : 1, 3, @{$overrideArgs{problem_randorder}}) . Index: StudentProgress.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm,v retrieving revision 1.4.2.5 retrieving revision 1.4.2.6 diff -Llib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm -Llib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm -u -r1.4.2.5 -r1.4.2.6 --- lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm +++ lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm @@ -269,8 +269,9 @@ # 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 ); + 'date' => 0, 'testtime' => 1, 'index' => 1, + 'problems' => 1, 'section' => 1, 'recit' => 1, + 'login' => 1 ); my $showBestOnly = 0; my @index_list = (); # list of all student index @@ -307,6 +308,7 @@ # the returning parameter lets us set defaults for versioned sets my $ret = $r->param('returning'); $showColumns{'date'} = $ret ? $r->param('show_date') : 1; + $showColumns{'testtime'} = $ret ? $r->param('show_testtime') : 0; $showColumns{'index'} = $ret ? $r->param('show_index') : 0; $showColumns{'problems'} = $ret ? $r->param('show_problems') : 0; $showColumns{'section'} = $ret? $r->param('show_section') : 0; @@ -455,16 +457,30 @@ } - # for versioned tests we might be displaying the test date + # for versioned tests we might be displaying the test date and test time my $dateOfTest = ''; + my $testTime = ''; # annoyingly, this is a set property, so get the set - if ( $setIsVersioned && $showColumns{'date'} ) { + if ( $setIsVersioned && + ( $showColumns{'date'} || $showColumns{'testtime'} ) ) { 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() ); + $dateOfTest = + localtime( $userSet[0]->version_creation_time() ); + my $gradeTime = ''; + if ( defined( $userSet[0]->version_last_attempt_time() ) && + $userSet[0]->version_last_attempt_time() ) { + $testTime = ( $userSet[0]->version_last_attempt_time() - + $userSet[0]->version_creation_time() ) / + 60; + $testTime = sprintf("%3.1f min", $testTime); + } else { + $testTime = 'time limit exceeded'; + } } else { $dateOfTest = '???'; + $testTime = '???'; } } @@ -500,6 +516,7 @@ email_address => $studentRecord->email_address, problemData => {%h_problemData}, date => $dateOfTest, + testtime => $testTime, }; # keep track of best score @@ -579,6 +596,9 @@ CGI::checkbox(-name=>'show_date', -value=>'1', -checked=>$showColumns{'date'}, -label=>' test date; '), + CGI::checkbox(-name=>'show_testtime', -value=>'1', + -checked=>$showColumns{'testtime'}, + -label=>' test time; '), CGI::checkbox(-name=>'show_problems', -value=>'1', -checked=>$showColumns{'problems'}, -label=>'problems;'), "\n", CGI::br(), "\n", @@ -607,6 +627,7 @@ 'show_best_only' => $showBestOnly, 'show_index' => $showColumns{'index'}, 'show_date' => $showColumns{'date'}, + 'show_testtime' => $showColumns{'testtime'}, 'show_problems' => $showColumns{'problems'}, 'show_section' => $showColumns{'section'}, 'show_recitation' => $showColumns{'recit'}, @@ -616,6 +637,7 @@ push(@columnHdrs, (! defined($sort_method_name) || $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, 'TestTime') if ( $showColumns{'testtime'} ); push(@columnHdrs, (! defined($sort_method_name) || $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, (! defined($sort_method_name) || $sort_method_name ne 'section') ? CGI::a({"href"=>$self->systemLink($setStatsPage,params=>{'sort'=>'section', %paramList})},'Section') : 'Section') if ( $showColumns{'section'} ); @@ -671,6 +693,7 @@ 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, $self->nbsp($rec->{testtime})) if ($showColumns{'testtime'}); 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'}); Index: ProblemSetList.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm,v retrieving revision 1.60.2.4 retrieving revision 1.60.2.5 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -u -r1.60.2.4 -r1.60.2.5 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm @@ -1437,8 +1437,10 @@ $problemRandOrder =~ s/(.*?)\s*/$1/; # convert times into seconds - $timeInterval = WeBWorK::Utils::timeToSec( $timeInterval ); - $versionTimeLimit = WeBWorK::Utils::timeToSec( $versionTimeLimit ); + $timeInterval = WeBWorK::Utils::timeToSec( $timeInterval ) + if ( $timeInterval ); + $versionTimeLimit = WeBWorK::Utils::timeToSec( $versionTimeLimit ) + if ( $versionTimeLimit ); ##################################################################### # Read and check list of problems for the set |