[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / GatewayQuiz.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1149 - (download) (as text) (annotate)
Thu Jun 12 20:06:20 2003 UTC (9 years, 11 months ago) by sh002i
File size: 20567 byte(s)
replaced tempdir() with makeTempDirectory()
-sam

    1 ################################################################################
    2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
    3 # $Id$
    4 ################################################################################
    5 
    6 package WeBWorK::ContentGenerator::GatewayQuiz;
    7 use base qw(WeBWorK::ContentGenerator);
    8 use File::Path qw(rmtree);
    9 use WeBWorK::Form;
   10 use WeBWorK::PG;
   11 use WeBWorK::PG::IO;
   12 use WeBWorK::Utils qw(writeLog encodeAnswers decodeAnswers ref2string makeTempDirectory);
   13 use WeBWorK::DB::Utils qw(global2user user2global findDefaults);
   14 
   15 =head1 NAME
   16 
   17 WeBWorK::ContentGenerator::GatewayQuiz - display an index of the problems in a
   18 problem set. (modifying this from ProblemSet.pm)
   19 
   20 =cut
   21 
   22 use strict;
   23 use warnings;
   24 use CGI qw();
   25 
   26 sub pre_header_initialize {
   27   my ($self, $setName)     = @_;
   28   my $r                    = $self->{r};
   29   my $courseEnv            = $self->{ce};
   30   my $db                   = $self->{db};
   31   my $userName             = $r->param('user');
   32   my $effectiveUserName    = $r->param('effectiveUser');
   33   my $key          = $r->param('key');
   34   my $user                 = $db->getUser($userName);
   35   my $effectiveUser        = $db->getUser($effectiveUserName);
   36 
   37   # obtain the effective user set, or if that is not yet defined obtain global set
   38   my $set                  = $db->getMergedSet($effectiveUserName, $setName);
   39   unless (defined $set) {
   40     my $userSetClass     = $courseEnv->{dbLayout}->{set_user}->{record};
   41     $set                 = global2user($userSetClass, $db->getGlobalSet($setName));
   42     $set->psvn('000');
   43   }
   44 
   45   # FIXME obtain first problem for recording number of attempts FIXME
   46   my $problem = $db->getMergedProblem($effectiveUser->user_id, $setName, 1);
   47 
   48   my  $psvn                = $set->psvn();
   49 
   50   $self->{set}             = $set;
   51   $self->{problem}         = $problem;
   52 
   53     ##### get and save permission levels #####
   54 
   55   my $permissionLevel = $db->getPermissionLevel($userName)->permission();
   56 
   57   $self->{userName}        = $userName;
   58   $self->{user}            = $user;
   59   $self->{effectiveUser}   = $effectiveUser;
   60   $self->{permissionLevel} = $permissionLevel;
   61 
   62     ##### form processing #####
   63 
   64   # set options from form fields (see comment at top of file for names)
   65   my $displayMode        = $r->param("displayMode") || $courseEnv->{pg}->{options}->{displayMode};
   66   my $redisplay          = $r->param("redisplay");
   67   my $submitAnswers      = $r->param("submitAnswers");
   68   my $checkAnswers       = $r->param("checkAnswers");
   69   my $previewAnswers     = $r->param("previewAnswers");
   70 
   71 
   72   # coerce form fields into CGI::Vars format
   73   my $formFields = { WeBWorK::Form->new_from_paramable($r)->Vars };
   74 
   75   $self->{displayMode}    = $displayMode;
   76   $self->{redisplay}      = $redisplay;
   77   $self->{submitAnswers}  = $submitAnswers;
   78   $self->{checkAnswers}   = $checkAnswers;
   79   $self->{previewAnswers} = $previewAnswers;
   80   $self->{formFields}     = $formFields;
   81 
   82   ##### permissions #####
   83 
   84   # are we allowed to view this quiz?
   85   $self->{isOpen} = time >= $set->open_date || $permissionLevel > 0;
   86   return unless $self->{isOpen};
   87 
   88   # what does the user want to do?
   89   my %want = (
   90     showOldAnswers     => $r->param("showOldAnswers")     || $courseEnv->{pg}->{options}->{showOldAnswers},
   91     showCorrectAnswers => $r->param("showCorrectAnswers") || $courseEnv->{pg}->{options}->{showCorrectAnswers},
   92     showHints          => $r->param("showHints")          || $courseEnv->{pg}->{options}->{showHints},
   93     showSolutions      => $r->param("showSolutions")      || $courseEnv->{pg}->{options}->{showSolutions},
   94     recordAnswers      => defined($submitAnswers),
   95   );
   96 
   97   # are certain options enforced?
   98   my %must = (
   99     showOldAnswers     => 0,
  100     showCorrectAnswers => 0,
  101     showHints          => 0,
  102     showSolutions      => 0,
  103     recordAnswers      => mustRecordAnswers($permissionLevel),
  104     checkAnswers       => 1,
  105   );
  106 
  107   # does the user have permission to use certain options?
  108   # QUIZ MAX ATTEMPTS should be set quiz wide FIXME
  109   my $QUIZ_MAX_ATTEMPTS=100;
  110   my %can = (
  111     showOldAnswers     => 1,
  112     showCorrectAnswers => canShowCorrectAnswers($permissionLevel, $set->answer_date),
  113     showHints          => 1,
  114     showSolutions      => canShowSolutions($permissionLevel, $set->answer_date),
  115     recordAnswers      => canRecordAnswers($permissionLevel, $set->open_date, $set->due_date,
  116       $QUIZ_MAX_ATTEMPTS, $problem->num_correct + $problem->num_incorrect + 1),
  117       # attempts=num_correct+num_incorrect+1, as this happens before updating $problem
  118     checkAnswers       => canCheckAnswers($permissionLevel, $set->answer_date),
  119   );
  120 
  121   # final values for options
  122   my %will;
  123   foreach (keys %must) {
  124     $will{$_} = $must{$_} || ($can{$_} && $want{$_}) ;
  125   }
  126 #   warn "\n want";
  127 #   WeBWorK::Utils::pretty_print_rh(\%want);
  128 #   warn "can";
  129 #   WeBWorK::Utils::pretty_print_rh(\%can);
  130 #   warn "must";
  131 #   WeBWorK::Utils::pretty_print_rh(\%must);
  132 #   warn "will";
  133 #   WeBWorK::Utils::pretty_print_rh(\%will);
  134 
  135     ##### store fields #####
  136 
  137   $self->{want} = \%want;
  138   $self->{must} = \%must;
  139   $self->{can}  = \%can;
  140   $self->{will} = \%will;
  141 
  142 
  143 #
  144 #   #### sticky answers #####   FIXME
  145 #
  146 #   if (not $submitAnswers and $will{showOldAnswers}) {
  147 #     do this only if new answers are NOT being submitted
  148 #     my %oldAnswers = decodeAnswers($problem->last_answer);
  149 #     $formFields->{$_} = $oldAnswers{$_} foreach keys %oldAnswers;
  150 #   }
  151 
  152    ######### translate problems ############
  153   my @problemNumbers = $db->listUserProblems($effectiveUserName, $setName);
  154 
  155     my @pg_results = ();
  156   foreach my $problemNumber (sort {$a<=> $b } @problemNumbers) {
  157     my $problem = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber);
  158     my $pg = $self->getProblemHTML($self->{effectiveUser}, $setName, $problemNumber);
  159     push(@pg_results, $pg);
  160   }
  161   $self->{ra_pg_results}=\@pg_results;
  162 
  163 
  164 }
  165 sub initialize {
  166   my ($self, $setName) = @_;
  167   my $courseEnvironment = $self->{ce};
  168   my $r = $self->{r};
  169   my $db = $self->{db};
  170   my $userName = $r->param("user");
  171   my $effectiveUserName = $r->param("effectiveUser");
  172 
  173   my $user            = $db->getUser($userName);
  174   my $effectiveUser   = $db->getUser($effectiveUserName);
  175   my $set             = $db->getMergedSet($effectiveUserName, $setName);
  176   my $permissionLevel = $db->getPermissionLevel($userName)->permission();
  177 
  178   $self->{userName}        = $userName;
  179   $self->{user}            = $user;
  180   $self->{effectiveUser}   = $effectiveUser;
  181   $self->{set}             = $set;
  182   $self->{permissionLevel} = $permissionLevel;
  183 
  184   ##### permissions #####
  185 
  186   $self->{isOpen} = time >= $set->open_date || $permissionLevel > 0;
  187 }
  188 
  189 sub path {
  190   my ($self, $setName, $args) = @_;
  191 
  192   my $ce = $self->{ce};
  193   my $root = $ce->{webworkURLs}->{root};
  194   my $courseName = $ce->{courseName};
  195   return $self->pathMacro($args,
  196     "Home" => "$root",
  197     $courseName => "$root/$courseName",
  198     $setName => "",
  199   );
  200 }
  201 
  202 sub nav {
  203   my ($self, $setName, $args) = @_;
  204 
  205   my $ce = $self->{ce};
  206   my $root = $ce->{webworkURLs}->{root};
  207   my $courseName = $ce->{courseName};
  208   my @links = ("Problem Sets" , "$root/$courseName", "navUp");
  209   my $tail = "";
  210 
  211   return $self->navMacro($args, $tail, @links);
  212 }
  213 
  214 
  215 sub siblings {
  216   my ($self, $setName) = @_;
  217   return "";
  218 }
  219 
  220 sub title {
  221   my ($self, $setName) = @_;
  222 
  223   return $setName;
  224 }
  225 
  226 
  227 
  228 sub body {
  229   my $self      = shift;
  230 
  231     return CGI::p(CGI::font({-color=>"red"}, "This problem is not available because the problem set that contains it is not yet open."))
  232     unless $self->{isOpen};
  233 
  234   # unpack some useful variables
  235 
  236   my $r               = $self->{r};
  237   my $db              = $self->{db};
  238   my $set             = $self->{set};
  239   my $problem         = $self->{problem};
  240   my $permissionLevel = $self->{permissionLevel};
  241   my $submitAnswers   = $self->{submitAnswers};
  242   my $checkAnswers    = $self->{checkAnswers};
  243   my $previewAnswers  = $self->{previewAnswers};
  244   my %want            = %{ $self->{want} };
  245   my %can             = %{ $self->{can} };
  246   my %must            = %{ $self->{must} };
  247   my %will            = %{ $self->{will} };
  248 
  249   # coerce form fields into CGI::Vars format
  250 
  251   return CGI::p(CGI::font({-color=>"red"}, "This problem set is not available because it is not yet open."))
  252     unless ($self->{isOpen});
  253 
  254   print CGI::h3("This is an experimental gateway quiz format");
  255 
  256   print "Number of attempts is ". ($problem->num_correct + $problem->num_incorrect + 1);
  257 
  258   print
  259     CGI::startform("POST", $r->uri),
  260     $self->hidden_authen_fields;
  261 
  262   #my $set = $db->getMergedSet($effectiveUserName, $setName);
  263   #my @problemNumbers = $db->listUserProblems($effectiveUserName, $setName);
  264     my @pg_results = @{ $self->{ra_pg_results} };
  265     my $problemNumber = 0;
  266   foreach my $pg (@pg_results) {
  267     $problemNumber++;
  268     print CGI::p("Problem $problemNumber");
  269     # FIXME determine when to see correct answers etc.
  270     print $self->attemptResults($pg, 1,1,1, 1, 1 ) if $submitAnswers or $checkAnswers;
  271     print CGI::p( $pg->{body_text});
  272     print "\n\n", CGI::hr(),CGI::hr(),"\n\n";
  273 
  274 
  275 
  276   }
  277   print CGI::p( #FIXME
  278       ($will{recordAnswers})
  279         ? CGI::submit(-name=>"submitAnswers",
  280           -label=>"Submit Quiz")
  281         : "",
  282       (not $will{recordAnswers})
  283         ? CGI::submit(-name=>"checkAnswers",
  284           -label=>"Check Answers")
  285         : "",
  286       CGI::submit(-name=>"previewAnswers",
  287         -label=>"Preview Answers"),
  288     );
  289 # print CGI::end_table();
  290 
  291   # feedback form
  292   my $ce = $self->{ce};
  293   my $root = $ce->{webworkURLs}->{root};
  294   my $courseName = $ce->{courseName};
  295   my $feedbackURL = "$root/$courseName/feedback/";
  296   print
  297     CGI::startform("POST", $feedbackURL),
  298     $self->hidden_authen_fields,
  299     CGI::hidden("module", __PACKAGE__),
  300     CGI::hidden("set",    $self->{set}->set_id),
  301     CGI::p({-align=>"right"},
  302       CGI::submit(-name=>"feedbackForm", -label=>"Send Feedback")
  303     ),
  304     CGI::endform();
  305 
  306   return "";
  307 }
  308 
  309 sub viewOptions($) {
  310   my $self = shift;
  311   my $displayMode = $self->{displayMode};
  312   my %must = %{ $self->{must} };
  313   my %can  = %{ $self->{can}  };
  314   my %will = %{ $self->{will} };
  315 
  316   my $optionLine;
  317   $can{showOldAnswers} and $optionLine .= join "",
  318     "Show: &nbsp;".CGI::br(),
  319     CGI::checkbox(
  320       -name    => "showOldAnswers",
  321       -checked => $will{showOldAnswers},
  322       -label   => "Saved answers",
  323     ), "&nbsp;&nbsp;".CGI::br();
  324   $can{showCorrectAnswers} and $optionLine .= join "",
  325     CGI::checkbox(
  326       -name    => "showCorrectAnswers",
  327       -checked => $will{showCorrectAnswers},
  328       -label   => "Correct answers",
  329     ), "&nbsp;&nbsp;".CGI::br();
  330   $can{showHints} and $optionLine .= join "",
  331     CGI::checkbox(
  332       -name    => "showHints",
  333       -checked => $will{showHints},
  334       -label   => "Hints",
  335     ), "&nbsp;&nbsp;".CGI::br();
  336   $can{showSolutions} and $optionLine .= join "",
  337     CGI::checkbox(
  338       -name    => "showSolutions",
  339       -checked => $will{showSolutions},
  340       -label   => "Solutions",
  341     ), "&nbsp;&nbsp;".CGI::br();
  342   $optionLine and $optionLine .= join "", CGI::br();
  343 
  344   return CGI::div({-style=>"border: thin groove; padding: 1ex; margin: 2ex align: left"},
  345       "View&nbsp;equations&nbsp;as:&nbsp;&nbsp;&nbsp;&nbsp;".CGI::br(),
  346     CGI::radio_group(
  347       -name    => "displayMode",
  348       -values  => ['plainText', 'formattedText', 'images'],
  349       -default => $displayMode,
  350       -linebreak=>'true',
  351       -labels  => {
  352         plainText     => "plain",
  353         formattedText => "formatted",
  354         images        => "images",
  355       }
  356     ), CGI::br(),CGI::hr(),
  357     $optionLine,
  358     CGI::submit(-name=>"redisplay", -label=>"Save Options"),
  359   );
  360 }
  361 sub options {
  362   my $self = shift;
  363   return join("",
  364     CGI::start_form("POST", $self->{r}->uri),
  365     $self->hidden_authen_fields,
  366     CGI::hr(),
  367     CGI::start_div({class=>"viewOptions"}),
  368     $self->viewOptions(),
  369     CGI::end_div(),
  370     CGI::end_form()
  371   );
  372 }
  373 
  374 
  375 
  376 ###########################################################################
  377 # Evaluation utilties
  378 ############################################################################
  379 sub getProblemHTML {
  380   my ($self, $effectiveUser, $setName, $problemNumber, $pgFile) = @_;
  381   my $r = $self->{r};
  382   my $ce = $self->{ce};
  383   my $db = $self->{db};
  384   my $key =  $r->param('key');
  385   # Should we provide a default user ? I think not FIXME
  386   # $effectiveUser = $self->{effectiveUser} unless defined($effectiveUser);
  387 
  388   my $formFields = { WeBWorK::Form->new_from_paramable($r)->Vars };
  389 
  390   my $permissionLevel = $self->{permissionLevel};
  391   my $set  = $db->getMergedSet($effectiveUser->user_id, $setName);
  392   my $psvn = $set->psvn();
  393 
  394   # decide what to do about problem number
  395   my $problem;
  396   if ($problemNumber) {
  397     $problem = $db->getMergedProblem($effectiveUser->user_id, $setName, $problemNumber);
  398   } elsif ($pgFile) {
  399     $problem = WeBWorK::DB::Record::UserProblem->new(
  400       set_id => $set->set_id,
  401       problem_id => 0,
  402       login_id => $effectiveUser->user_id,
  403       source_file => $pgFile,
  404       # the rest of Problem's fields are not needed, i think
  405     );
  406   }
  407 
  408   # figure out if we're allowed to get solutions and call PG->new accordingly.
  409   my $showCorrectAnswers = $self->{will}->{showCorrectAnswers};
  410   my $showHints          = $self->{will}->{showHints};
  411   my $showSolutions      = $self->{will}->{showSolutions};
  412   my $processAnswers     = $self->{will}->{checkAnswers};
  413 
  414   unless ($permissionLevel > 0 or time > $set->answer_date) {
  415     $showCorrectAnswers = 0;
  416     $showSolutions      = 0;
  417   }
  418 
  419   # FIXME WeBWorK::Utils::pretty_print_rh($formFields);
  420   my $pg = WeBWorK::PG->new(
  421     $ce,
  422     $effectiveUser,
  423     $key,
  424     $set,
  425     $problem,
  426     $psvn,
  427     $formFields,
  428     { # translation options
  429       displayMode     => "images",
  430       showHints       => $showHints,
  431       showSolutions   => $showSolutions,
  432       refreshMath2img => $showHints || $showSolutions,
  433       processAnswers  => 1,
  434       QUIZ_PREFIX     => 'Q'.sprintf("%04d",$problemNumber).'_',
  435     },
  436   );
  437 
  438   if ($pg->{warnings} ne "") {
  439     push @{$self->{warnings}}, {
  440       set     => $setName,
  441       problem => $problemNumber,
  442       message => $pg->{warnings},
  443     };
  444   }
  445 
  446   if ($pg->{flags}->{error_flag}) {
  447     push @{$self->{errors}}, {
  448       set     => $setName,
  449       problem => $problemNumber,
  450       message => $pg->{errors},
  451       context => $pg->{body_text},
  452     };
  453     # if there was an error, body_text contains
  454     # the error context, not TeX code
  455     $pg->{body_text} = undef;
  456   }
  457 
  458   #return '<br>hi FIXME'."effective User $effectiveUser, setName $setName, probNum $problemNumber, file: $pgFile".
  459   return    $pg;
  460 }
  461 ##### output utilities #####
  462 sub problemListRow($$$) {
  463   my $self = shift;
  464   my $set = shift;
  465   my $problem = shift;
  466 
  467   my $name = $problem->problem_id;
  468   my $interactiveURL = "$name/?" . $self->url_authen_args;
  469   my $interactive = CGI::a({-href=>$interactiveURL}, "Problem $name");
  470   my $attempts = $problem->num_correct + $problem->num_incorrect;
  471   my $remaining = $problem->max_attempts < 0
  472     ? "unlimited"
  473     : $problem->max_attempts - $attempts;
  474   my $status = sprintf("%.0f%%", $problem->status * 100); # round to whole number
  475 
  476   return CGI::Tr(CGI::td({-nowrap=>1}, [
  477     $interactive,
  478     $attempts,
  479     $remaining,
  480     $status,
  481   ]));
  482 }
  483 sub nbsp {
  484   my $str = shift;
  485   ($str) ? $str : '&nbsp;';  # returns non-breaking space for empty strings
  486 }
  487 sub previewAnswer($$) {
  488   my ($self, $answerResult) = @_;
  489   my $ce            = $self->{ce};
  490   my $effectiveUser = $self->{effectiveUser};
  491   my $set           = $self->{set};
  492   my $problem       = $self->{problem};
  493   my $displayMode   = $self->{displayMode};
  494 
  495   # note: right now, we have to do things completely differently when we are
  496   # rendering math from INSIDE the translator and from OUTSIDE the translator.
  497   # so we'll just deal with each case explicitly here. there's some code
  498   # duplication that can be dealt with later by abstracting out tth/dvipng/etc.
  499 
  500   my $tex = $answerResult->{preview_latex_string}; #FIXME
  501 
  502   return "" if not defined($tex) or $tex eq "" ;
  503 
  504   if ($displayMode eq "plainText") {
  505     return $tex;
  506   } elsif ($displayMode eq "formattedText") {
  507     my $tthCommand = $ce->{externalPrograms}->{tth}
  508       . " -L -f5 -r 2> /dev/null <<END_OF_INPUT; echo > /dev/null\n"
  509       . "\\(".$tex."\\)\n"
  510       . "END_OF_INPUT\n";
  511 
  512     # call tth
  513     my $result = `$tthCommand`;
  514     if ($?) {
  515       return "<b>[tth failed: $? $@]</b>";
  516     }
  517     return $result;
  518   } elsif ($displayMode eq "images") {
  519     # how are we going to name this?
  520     my $targetPathCommon = "/m2i/"
  521       . $effectiveUser->user_id . "."
  522       . $set->set_id . "."
  523       . $problem->problem_id . "."
  524       . $answerResult->{ans_name} . ".png";
  525 
  526     # figure out where to put things
  527     my $wd = makeTempDirectory($ce->{courseDirs}->{html_temp}, "webwork-dvipng");
  528     my $latex = $ce->{externalPrograms}->{latex};
  529     my $dvipng = $ce->{externalPrograms}->{dvipng};
  530     my $targetPath = $ce->{courseDirs}->{html_temp} . $targetPathCommon;
  531         # should use surePathToTmpFile, but we have to
  532         # isolate it from the problem enivronment first
  533     my $targetURL = $ce->{courseURLs}->{html_temp} . $targetPathCommon;
  534 
  535     # call dvipng to generate a preview
  536     dvipng($wd, $latex, $dvipng, $tex, $targetPath);
  537     rmtree($wd, 0, 0);
  538     if (-e $targetPath) {
  539       return "<img src=\"$targetURL\" alt=\"$tex\" />";
  540     } else {
  541       return "<b>[math2img failed]</b>";
  542     }
  543   }
  544 }
  545 
  546 
  547 
  548 sub attemptResults($$$$$$) {
  549   my $self = shift;
  550   my $pg = shift;
  551   my $showAttemptAnswers = shift;
  552   my $showCorrectAnswers = shift;
  553   my $showAttemptResults = $showAttemptAnswers && shift;
  554   my $showSummary = shift;
  555   my $showAttemptPreview = shift || 0;
  556   my $problemResult = $pg->{result}; # the overall result of the problem
  557   my @answerNames = @{ $pg->{flags}->{ANSWER_ENTRY_ORDER} };
  558 
  559   my $showMessages = $showAttemptAnswers && grep { $pg->{answers}->{$_}->{ans_message} } @answerNames;
  560 
  561   my $header = CGI::th("Part");
  562   $header .= $showAttemptAnswers ? CGI::th("Entered")  : "";
  563   $header .= $showAttemptPreview ? CGI::th("Answer Preview")  : "";
  564   $header .= $showCorrectAnswers ? CGI::th("Correct")  : "";
  565   $header .= $showAttemptResults ? CGI::th("Result")   : "";
  566   $header .= $showMessages       ? CGI::th("messages") : "";
  567   my @tableRows = ( $header );
  568   my $numCorrect;
  569   foreach my $name (@answerNames) {
  570     my $answerResult  = $pg->{answers}->{$name};
  571 
  572     my $studentAnswer = $answerResult->{student_ans}; # original_student_ans
  573 
  574     my $preview       = ($showAttemptPreview
  575                           ? $self->previewAnswer($answerResult)
  576           : "");
  577     my $correctAnswer = $answerResult->{correct_ans};
  578     my $answerScore   = $answerResult->{score};
  579     my $answerMessage = $showMessages ? $answerResult->{ans_message} : "";
  580 
  581     $numCorrect += $answerScore > 0;
  582     my $resultString = $answerScore ? "correct" : "incorrect";
  583 
  584     # get rid of the goofy prefix on the answer names (supposedly, the format
  585     # of the answer names is changeable. this only fixes it for "AnSwEr"
  586     $name =~ s/^AnSwEr//;
  587 
  588     my $row = CGI::td($name);
  589     $row .= $showAttemptAnswers ? CGI::td(nbsp($studentAnswer)) : "";
  590     $row .= $showAttemptPreview ? CGI::td(nbsp($preview))       : "";
  591     $row .= $showCorrectAnswers ? CGI::td(nbsp($correctAnswer)) : "";
  592     $row .= $showAttemptResults ? CGI::td(nbsp($resultString))  : "";
  593     $row .= $answerMessage      ? CGI::td(nbsp($answerMessage)) : "";
  594     push @tableRows, $row;
  595   }
  596 
  597   my $numIncorrectNoun = scalar @answerNames == 1 ? "question" : "questions";
  598   my $scorePercent = sprintf("%.0f%%", $problemResult->{score} * 100);
  599   my $summary = "On this attempt, you answered $numCorrect out of "
  600     . scalar @answerNames . " $numIncorrectNoun correct, for a score of $scorePercent.";
  601   return CGI::table({-class=>"attemptResults"}, CGI::Tr(\@tableRows)) . ($showSummary ? CGI::p($summary) : "");
  602 }
  603 
  604 ##### logging subroutine ####
  605 
  606 
  607 
  608 ##### permission queries #####
  609 
  610 # this stuff should be abstracted out into the permissions system
  611 # however, the permission system only knows about things in the
  612 # course environment and the username. hmmm...
  613 
  614 # also, i should fix these so that they have a consistent calling
  615 # format -- perhaps:
  616 #   canPERM($courseEnv, $user, $set, $problem, $permissionLevel)
  617 
  618 sub canShowCorrectAnswers($$) {
  619   my ($permissionLevel, $answerDate) = @_;
  620   return $permissionLevel > 0 || time > $answerDate;
  621 }
  622 
  623 sub canShowSolutions($$) {
  624   my ($permissionLevel, $answerDate) = @_;
  625   return canShowCorrectAnswers($permissionLevel, $answerDate);
  626 }
  627 
  628 sub canRecordAnswers($$$$$) {
  629   my ($permissionLevel, $openDate, $dueDate, $maxAttempts, $attempts) = @_;
  630   my $permHigh = $permissionLevel > 0;
  631   my $timeOK = time >= $openDate && time <= $dueDate;
  632   my $attemptsOK = $maxAttempts == -1 || $attempts <= $maxAttempts;
  633   my $recordAnswers = $permHigh || ($timeOK && $attemptsOK);
  634   return $recordAnswers;
  635 }
  636 
  637 sub canCheckAnswers($$) {
  638   my ($permissionLevel, $answerDate) = @_;
  639   my $permHigh = $permissionLevel > 0;
  640   my $timeOK = time >= $answerDate;
  641   my $recordAnswers = $permHigh || $timeOK;
  642   return $recordAnswers;
  643 }
  644 
  645 sub mustRecordAnswers($) {
  646   my ($permissionLevel) = @_;
  647   return $permissionLevel == 0;
  648 }
  649 
  650 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9