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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1156 - (download) (as text) (annotate)
Fri Jun 13 13:53:19 2003 UTC (9 years, 11 months ago) by gage
File size: 20898 byte(s)
This is a fairly stable version of Hardcopy.  It reports
part of the TeX log errors along with whater pdf was
produced.  This partially satisfies the requests in
bug #82
--Mike

    1 ################################################################################
    2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
    3 # $Id$
    4 ################################################################################
    5 
    6 package WeBWorK::ContentGenerator::Hardcopy;
    7 use base qw(WeBWorK::ContentGenerator);
    8 
    9 =head1 NAME
   10 
   11 WeBWorK::ContentGenerator::Hardcopy - generate a PDF version of one or more
   12 problem sets.
   13 
   14 =cut
   15 
   16 use strict;
   17 use warnings;
   18 use CGI qw();
   19 use File::Path qw(rmtree);
   20 use WeBWorK::Form;
   21 use WeBWorK::Utils qw(readFile makeTempDirectory);
   22 
   23 sub go {
   24   my ($self, $singleSet) = @_;
   25 
   26   my $r = $self->{r};
   27   my $ce = $self->{ce};
   28   my $db = $self->{db};
   29   my @sets = $r->param("hcSet");
   30   my @users = $r->param("hcUser");
   31 
   32   # add singleSet to the list of sets
   33   if (length $singleSet > 0) {
   34     $singleSet =~ s/^set//;
   35     unshift @sets, $singleSet unless grep { $_ eq $singleSet } @sets;
   36   }
   37 
   38   # default user is the effectiveUser
   39   unless (@users) {
   40     unshift @users, $r->param("effectiveUser");
   41   }
   42 
   43   $self->{user}            = $db->getUser($r->param("user"));
   44   $self->{permissionLevel} = $db->getPermissionLevel($r->param("user"))->permission();
   45   $self->{effectiveUser}   = $db->getUser($r->param("effectiveUser"));
   46   $self->{sets}  = \@sets;
   47   $self->{users} = \@users;
   48   $self->{errors}   = [];
   49   $self->{warnings} = [];
   50 
   51   # security checks
   52   my $multiSet = $self->{permissionLevel} > 0;
   53   my $multiUser = $self->{permissionLevel} > 0;
   54   if (@sets > 1 and not $multiSet) {
   55     $self->{generationError} = ["SIMPLE", "You are not permitted to generate hardcopy for multiple sets. Please select a single set and try again."];
   56   }
   57   if (@users > 1 and not $multiUser) {
   58     $self->{generationError} = ["SIMPLE", "You are not permitted to generate hardcopy for multiple users. Please select a single user and try again."];
   59   }
   60   if ($users[0] ne $self->{effectiveUser}->user_id and not $multiUser) {
   61     $self->{generationError} = ["SIMPLE", "You are not permitted to generate hardcopy for other users."];
   62   }
   63 
   64   unless ($self->{generationError}) {
   65     if ($r->param("generateHardcopy")) {
   66       my ($tempDir, $fileName,$errors) = eval { $self->generateHardcopy() };
   67       warn "tempDir $tempDir fileName $fileName ";
   68       if ($@) {
   69         $self->{generationError} = $@;
   70         # In this case no correct pdf file was generated.
   71         # there is not much more that can be done
   72         # throw the error up higher.
   73         # The error is reported in body.
   74         # the tempDir was removed in generateHardcopy
   75 
   76 
   77       } else {
   78         my $filePath = "$tempDir/$fileName";
   79         # FIXME this is taking up server time
   80         # why not move the file to the tempDir and let the browser pick it up on redirect?
   81         # my $hardcopyFilePath     =  $self->{hardcopyFilePath};
   82         # my $hardcopyFileURL      =  $self->{hardcopyFileURL};
   83         if ($errors eq '') {
   84           $r->content_type("application/x-pdf");
   85           # as per RFC2183:
   86           $r->header_out("Content-Disposition", "attachment; filename=$fileName");
   87           $r->send_http_header();
   88 
   89           local *INPUTFILE;
   90           open INPUTFILE, "<", $filePath
   91             or die "Failed to read $filePath: $!";
   92           my $buf;
   93           while (read INPUTFILE, $buf, 16384) {
   94             print $buf;
   95           }
   96           close INPUTFILE;
   97 
   98           rmtree($tempDir);
   99         } else {
  100 
  101         }
  102 
  103         return;
  104       }
  105     }
  106   }
  107 
  108   $r->content_type("text/html");
  109   $r->send_http_header();
  110   $self->template($ce->{templates}->{system}, $singleSet);
  111 }
  112 
  113 # -----
  114 
  115 sub path {
  116   my ($self, undef, $args) = @_;
  117 
  118   my $ce = $self->{ce};
  119   my $root = $ce->{webworkURLs}->{root};
  120   my $courseName = $ce->{courseName};
  121   return $self->pathMacro($args,
  122     "Home" => "$root",
  123     $courseName => "$root/$courseName",
  124     "Hardcopy Generator" => "",
  125   );
  126 }
  127 
  128 sub title {
  129   return "Hardcopy Generator";
  130 }
  131 
  132 sub body {
  133   my $self = shift;
  134 
  135   if ($self->{generationError}) {
  136     if (ref $self->{generationError} eq "ARRAY") {
  137       my ($disposition, @rest) = @{$self->{generationError}};
  138       if ($disposition eq "PGFAIL") {
  139         $self->multiErrorOutput(@{$self->{errors}});
  140         return "";
  141       } elsif ($disposition eq "FAIL") {
  142         print $self->errorOutput(@rest);
  143         return "";
  144       } elsif ($disposition eq "RETRY") {
  145         print $self->errorOutput(@rest);
  146       } else { # a "simple" error
  147         print CGI::p(CGI::font({-color=>"red"}, @rest));
  148       }
  149     } else {
  150       # not something we were expecting...
  151       die $self->{generationError};
  152     }
  153   }
  154   if (@{$self->{warnings}}) {
  155     # FIXME: this code will only be reached if there was also a
  156     # generation error, because otherwise the module will send
  157     # the PDF instead. DAMN!
  158     $self->multiWarningOutput(@{$self->{warnings}});
  159   }
  160   $self->displayForm();
  161 }
  162 
  163 sub multiErrorOutput($@) {
  164   my ($self, @errors) = @_;
  165 
  166   print CGI::h2("Software Errors");
  167   print CGI::p(<<EOF);
  168 WeBWorK has encountered one or more software errors while attempting to process
  169 these problem sets. It is likely that there are errors in the problems
  170 themselves. If you are a student, contact your professor to have the errors
  171 corrected. If you are a professor, please consut the error output below for
  172 more informaiton.
  173 EOF
  174   foreach my $error (@errors) {
  175     print CGI::h3("Set: ", $error->{set}, ", Problem: ", $error->{problem});
  176     print CGI::h4("Error messages"), CGI::blockquote(CGI::pre($error->{message}));
  177     print CGI::h4("Error context"), CGI::blockquote(CGI::pre($error->{context}));
  178   }
  179 }
  180 
  181 sub multiWarningOutput($@) {
  182   my ($self, @warnings) = @_;
  183 
  184   print CGI::h2("Software Warnings");
  185   print CGI::p(<<EOF);
  186 WeBWorK has encountered one or more warnings while attempting to process these
  187 problem sets. It is likely that this indicates errors or ambiguitiees in the
  188 problems themselves. If you are a student, contact your professor to have the
  189 problems corrected. If you are a professor, please consut the warning output
  190 below for more informaiton.
  191 EOF
  192   foreach my $warning (@warnings) {
  193     print CGI::h3("Set: ", $warning->{set}, ", Problem: ", $warning->{problem});
  194     print CGI::h4("Error messages"), CGI::blockquote(CGI::pre($warning->{message}));
  195   }
  196 }
  197 
  198 # -----
  199 
  200 sub displayForm($) {
  201   my $self = shift;
  202   my $r = $self->{r};
  203   my $db = $self->{db};
  204 
  205   print CGI::start_p(), "Select the problem sets for which to generate hardcopy versions.";
  206   if ($self->{permissionLevel} > 0) {
  207     print "You may also select multiple users from the users list. You will receive hardcopy for each (set, user) pair.";
  208   }
  209   print CGI::end_p();
  210 
  211   print CGI::start_form(-method=>"POST", -action=>$r->uri);
  212   print $self->hidden_authen_fields();
  213   print CGI::h3("Options");
  214   print CGI::p("You may choose to show any of the following data. Correct answers and solutions are only available to privileged users or after the answer date of the problem set.");
  215   print CGI::p(
  216     CGI::checkbox(
  217       -name    => "showCorrectAnswers",
  218       -checked => $r->param("showCorrectAnswers") || 0,
  219       -label   => "Correct answers",
  220     ), CGI::br(),
  221     CGI::checkbox(
  222       -name    => "showHints",
  223       -checked => $r->param("showHints") || 0,
  224       -label   => "Hints",
  225     ), CGI::br(),
  226     CGI::checkbox(
  227       -name    => "showSolutions",
  228       -checked => $r->param("showSolutions") || 0,
  229       -label   => "Solutions",
  230     ),
  231   );
  232   print CGI::start_table({-width=>"100%"}), CGI::start_Tr({-valign=>"top"});
  233 
  234   my $multiSet = $self->{permissionLevel} > 0;
  235   my $multiUser = $self->{permissionLevel} > 0;
  236   my $preOpenSets = $self->{permissionLevel} > 0;
  237 
  238   # set selection menu
  239   {
  240     print CGI::start_td();
  241     print CGI::h3("Sets");
  242     print CGI::start_table();
  243     my @sets;
  244     push @sets, $db->getMergedSet($self->{effectiveUser}->user_id, $_)
  245       foreach ($db->listUserSets($self->{effectiveUser}->user_id));
  246     @sets = sort { $a->set_id cmp $b->set_id } @sets;
  247     foreach my $set (@sets) {
  248       my $checked = grep { $_ eq $set->set_id } @{$self->{sets}};
  249       my $control;
  250       if (time < $set->open_date and not $preOpenSets) {
  251         $control = "";
  252       } else {
  253         if ($multiSet) {
  254           $control = CGI::checkbox(
  255             -name=>"hcSet",
  256             -value=>$set->set_id,
  257             -label=>"",
  258             -checked=>$checked
  259           );
  260         } else {
  261           $control = CGI::radio_group(
  262             -name=>"hcSet",
  263             -values=>[$set->set_id],
  264             -default=>($checked ? $set->set_id : "-"),
  265             -labels=>{$set->set_id => ""}
  266           );
  267         }
  268       }
  269       print CGI::Tr(CGI::td([
  270         $control,
  271         $set->set_id,
  272       ]));
  273     }
  274     print CGI::end_table();
  275     print CGI::end_td();
  276   }
  277 
  278   # user selection menu
  279   if ($multiUser) {
  280     print CGI::start_td();
  281     print CGI::h3("Users");
  282     print CGI::start_table();
  283     #print CGI::Tr(
  284     # CGI::td(CGI::checkbox(-name=>"hcAllUsers", -value=>"1", -label=>"")),
  285     # CGI::td({-colspan=>"2"}, "All Users"),
  286     #);
  287     #print CGI::Tr(CGI::td({-colspan=>"3"}, "&nbsp;"));
  288     my @users;
  289     push @users, $self->{db}->getUser($_)
  290       foreach ($self->{db}->listUsers());
  291     @users = sort { $a->last_name cmp $b->last_name } @users;
  292     foreach my $user (@users) {
  293       my $checked = grep { $_ eq $user->user_id } @{$self->{users}};
  294       print CGI::Tr(CGI::td([
  295         CGI::checkbox(-name=>"hcUser", -value=>$user->user_id, -label=>"", -checked=>$checked),
  296         $user->user_id,
  297         $user->last_name.", ".$user->first_name,
  298       ]));
  299     }
  300     print CGI::end_table();
  301     print CGI::end_td();
  302   }
  303 
  304   print CGI::end_Tr(), CGI::end_table();
  305   print CGI::p({-align=>"center"},
  306     CGI::submit(-name=>"generateHardcopy", -label=>"Generate Hardcopy"));
  307   print CGI::end_form();
  308 
  309   return "";
  310 }
  311 
  312 sub generateHardcopy($) {
  313   my $self = shift;
  314   my $ce = $self->{ce};
  315   my @sets = @{$self->{sets}};
  316   my @users = @{$self->{users}};
  317   my $multiSet = $self->{permissionLevel} > 0;
  318   my $multiUser = $self->{permissionLevel} > 0;
  319   # sanity checks
  320   unless (@sets) {
  321     die ["RETRY", "No sets were specified."];
  322   }
  323   unless (@users) {
  324     die ["RETRY", "No users were specified."];
  325   }
  326 
  327   # determine where hardcopy is going to go
  328   my $tempDir = makeTempDirectory($ce->{webworkDirs}->{tmp}, "webwork-hardcopy");
  329 
  330   # determine name of PDF file  #FIXME it might be best to have the effective user in here somewhere
  331   my $courseName = $self->{ce}->{courseName};
  332   my $fileNameSet = (@sets > 1 ? "multiset" : $sets[0]);
  333   my $fileNameUser = (@users > 1 ? "multiuser" : $users[0]);
  334   my $fileName = "$courseName.$fileNameUser.$fileNameSet.pdf";
  335 
  336   # for each user ... generate TeX for each set
  337   my $tex;
  338   #
  339   # the document tex preamble
  340   $tex .= $self->texInclude($self->{ce}->{webworkFiles}->{hardcopySnippets}->{preamble});
  341   # separate users by page break, or something
  342   foreach my $user (@users) {
  343     $tex .=  $self->getMultiSetTeX($user, @sets);
  344       if (@users) {
  345       # separate users, but not after the last set
  346       $tex .= $self->texInclude($self->{ce}->{webworkFiles}->{hardcopySnippets}->{userDivider});
  347     }
  348 
  349   }
  350   # the document postamble
  351   $tex .= $self->texInclude($self->{ce}->{webworkFiles}->{hardcopySnippets}->{postamble});
  352 
  353   # deal with PG errors
  354   if (@{$self->{errors}}) {
  355     die ["PGFAIL"];
  356   }
  357 
  358   # FIXME: add something like:
  359   #if (@{$self->{warnings}}) {
  360   # $self->{generationWarnings} = 1;
  361   #}
  362   # ???????
  363 
  364   # "try" to generate pdf
  365   my $errors = '';
  366   eval { $self->latex2pdf($tex, $tempDir, $fileName) };
  367   if ($@) {
  368       $errors = $@;
  369       #$errors =~ s/\n/<br>/g;  # make this readable on HTML FIXME make this a Utils. filter (Error2HTML)
  370       # clean up temp directory
  371       rmtree($tempDir);
  372     die ["FAIL", "Failed to generate PDF from tex", $errors]; #throw error to subroutine body
  373   }
  374 
  375   return $tempDir, $fileName;
  376 }
  377 
  378 # -----
  379 
  380 sub latex2pdf {
  381   # this is a little ad-hoc function which I will replace with a LaTeX
  382   # module at some point (or put it in Utils).
  383   my ($self, $tex, $tempDir, $fileName) = @_;
  384   my $finalFile = "$tempDir/$fileName";
  385   my $ce = $self->{ce};
  386 
  387   # Location for hardcopy file to be downloaded
  388   # FIXME  this should use surePathToTmpFile
  389   my $hardcopyTempDirectory = $ce->{courseDirs}->{html_temp}."/hardcopy";
  390   mkdir ($hardcopyTempDirectory)  or die "Unable to make $hardcopyTempDirectory" unless -e $hardcopyTempDirectory;
  391   my $hardcopyFilePath        =  "$hardcopyTempDirectory/$fileName";
  392   my $hardcopyFileURL         =  $ce->{courseURLs}->{html_temp}."/hardcopy/$fileName";
  393   $self->{hardcopyFilePath}   =  $hardcopyFilePath;
  394   $self->{hardcopyFileURL}    =  $hardcopyFileURL;
  395   ## create a temporary directory for tex to shit in
  396   #my $wd = tempdir("webwork-hardcopy-XXXXXXXX", TMPDIR => 1);
  397   # - we're using the existing temp dir. now
  398 
  399   my $wd = $tempDir;
  400   my $texFile = "$wd/hardcopy.tex";
  401   my $pdfFile = "$wd/hardcopy.pdf";
  402   my $logFile = "$wd/hardcopy.log";
  403 
  404   # write the tex file
  405   local *TEX;
  406   open TEX, ">", $texFile or die "Failed to open $texFile: $!\n".CGI::br();
  407   print TEX $tex;
  408   close TEX;
  409 
  410   # call pdflatex - we don't want to chdir in the mod_perl process, as
  411   # that might step on the feet of other things (esp. in Apache 2.0)
  412   my $pdflatex = $ce->{externalPrograms}->{pdflatex};
  413   my $pdflatexResult = system "cd $wd && $pdflatex $texFile";
  414 
  415   # Even with errors there may be a valid pdfFile.  Move it to where we can get it.
  416   if (-e $pdfFile) {
  417     # move resulting PDF file to appropriate location
  418     # FIXME don't fix everything at once :-)
  419     system "/bin/mv", $pdfFile, $finalFile
  420       and die "Failed to mv: $pdfFile to $finalFile<br>\n  Quite likely this means that there ".
  421               "is not sufficient write permission for some directory.<br>$!<br>\n";
  422        # moving to course tmp/hardcopy directory
  423 #       system "/bin/mv", $pdfFile, $hardcopyFilePath
  424 #       and die "Failed to mv: $pdfFile to  $hardcopyFilePath<br> Quite likely this means that there ".
  425 #               "is not sufficient write permission for some directory.<br>$!\n".CGI::br();
  426   }
  427   # Alert the world that the tex file did not process perfectly.
  428   if ($pdflatexResult) {
  429     # something bad happened
  430     my $textErrorMessage = "Call to $pdflatex failed: $!\n".CGI::br();
  431 
  432     # move what output there is to someplace where it can be read
  433     system "/bin/mv", $finalFile, $hardcopyFilePath
  434           and die "Failed to mv: $pdfFile to  $hardcopyFilePath<br> Quite likely this means that there ".
  435                   "is not sufficient write permission for some directory.<br>$!\n".CGI::br();
  436     if (-e $hardcopyFilePath ) {
  437        # FIXME  Misuse of html tags!!!
  438       $textErrorMessage.= "<h4>Some pdf output was produced and is available ". CGI::a({-href=>$hardcopyFileURL},"here.</h4>").CGI::hr();
  439     }
  440     # report logfile
  441     if (-e $logFile) {
  442       $textErrorMessage .= "pdflatex ran, but did not succeed. This suggests an error in the TeX\n".CGI::br();
  443       $textErrorMessage .= "version of one of the problems, or a problem with the pdflatex system.\n".CGI::br();
  444       my $logFileContents = eval { readTexErrorLog($logFile) };
  445       if ($@) {
  446         $textErrorMessage .= "Additionally, the pdflatex log file could not be read, though it exists.\n".CGI::br();
  447       } else {
  448         $textErrorMessage .= "The essential contents of the TeX log are as follows:\n".CGI::hr().CGI::br();
  449         $textErrorMessage .= "$logFileContents\n".CGI::br().CGI::br();
  450       }
  451     } else {
  452       $textErrorMessage .= "No log file was created, suggesting that pdflatex never ran. Check the WeBWorK\n".CGI::br();
  453       $textErrorMessage .= "configuration to ensure that the path to pdflatex is correct.\n".CGI::br();
  454     }
  455     die $textErrorMessage;
  456   }
  457 
  458 
  459 
  460   ## remove temporary directory
  461   ##FIXME  rmtree is commented out only for debugging purposes.
  462   ##print STDERR "tex temp directory at $wd";
  463   #rmtree($wd, 0, 0);
  464   # - not creating the temp dir here anymore
  465 
  466   -e $finalFile or die "Failed to create $finalFile for no apparent reason.\n";
  467 }
  468 
  469 # -----
  470 # FIXME move to Utils? probably not
  471 sub readTexErrorLog {
  472   my $filePath = shift;
  473   my $print_error_switch = 0;
  474   my $line='';
  475   my @message=();
  476   #local($/ ) = "\n";
  477     open(LOGFILE,"<$filePath") or die "Can't read $filePath";
  478     while (<LOGFILE>) {
  479       $line = $_;
  480       $print_error_switch = 1  if $line =~ /^!/;  # after a fatal error start printing messages
  481     push(@message, protect_HTML($line)) if $print_error_switch;
  482     }
  483     close($filePath);
  484     join("<br>\n",@message);
  485 }
  486 sub protect_HTML {
  487   my $line = shift;
  488   chomp($line);
  489   $line =~s/\&/&amp;/g;
  490   $line =~s/</&lt;/g;
  491   $line =~s/>/&gt;/g;
  492   $line;
  493 }
  494 sub texBlockComment(@) { return "\n".("%"x80)."\n%% ".join("", @_)."\n".("%"x80)."\n\n"; }
  495 
  496 sub getMultiSetTeX {
  497   my ($self, $effectiveUserName,@sets) = @_;
  498   my $ce = $self->{ce};
  499   my $tex = "";
  500 
  501 
  502 
  503   while (defined (my $setName = shift @sets)) {
  504     $tex .= $self->getSetTeX($effectiveUserName, $setName);
  505     if (@sets) {
  506       # divide sets, but not after the last set
  507       $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{setDivider});
  508     }
  509   }
  510 
  511 
  512 
  513   return $tex;
  514 }
  515 
  516 sub getSetTeX {
  517   my ($self, $effectiveUserName,$setName) = @_;
  518   my $ce = $self->{ce};
  519   my $db = $self->{db};
  520 
  521   # FIXME (debug code line next)
  522   # print STDERR "Creating set $setName for $effectiveUserName \n";
  523 
  524   # FIXME We could define a default for the effective user if no correct name is passed in.
  525   # I'm not sure that it is wise.
  526   my $effectiveUser = $db->getUser($effectiveUserName);
  527 
  528   my @problemNumbers = sort { $a <=> $b }
  529     $db->listUserProblems($effectiveUserName, $setName);
  530 
  531   # get header and footer
  532   my $setHeader = $db->getMergedSet($effectiveUserName, $setName)->set_header
  533     || $ce->{webworkFiles}->{hardcopySnippets}->{setHeader};
  534   # database doesn't support the following yet :(
  535   #my $setFooter = $wwdb->getMergedSet($effectiveUserName, $setName)->set_footer
  536   # || $ce->{webworkFiles}->{hardcopySnippets}->{setFooter};
  537   # so we don't allow per-set customization, which is probably okay :)
  538   my $setFooter = $ce->{webworkFiles}->{hardcopySnippets}->{setFooter};
  539 
  540   my $tex = "";
  541 
  542   # render header
  543   $tex .= texBlockComment("BEGIN $setName : $setHeader");
  544   $tex .= $self->getProblemTeX($effectiveUser,$setName, 0, $setHeader);
  545 
  546   # render each problem
  547   while (my $problemNumber = shift @problemNumbers) {
  548     $tex .= texBlockComment("BEGIN $setName : $problemNumber");
  549     $tex .= $self->getProblemTeX($effectiveUser,$setName, $problemNumber);
  550     if (@problemNumbers) {
  551       # divide problems, but not after the last problem
  552       $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{problemDivider});
  553     }
  554   }
  555 
  556   # render footer
  557   $tex .= texBlockComment("BEGIN $setName : $setFooter");
  558   $tex .= $self->getProblemTeX($effectiveUser,$setName, 0, $setFooter);
  559 
  560   return $tex;
  561 }
  562 
  563 sub getProblemTeX {
  564   my ($self, $effectiveUser, $setName, $problemNumber, $pgFile) = @_;
  565   my $r = $self->{r};
  566   my $ce = $self->{ce};
  567   my $db = $self->{db};
  568 
  569   # Should we provide a default user ? I think not FIXME
  570 
  571   # $effectiveUser = $self->{effectiveUser} unless defined($effectiveUser);
  572   my $permissionLevel = $self->{permissionLevel};
  573   my $set  = $db->getMergedSet($effectiveUser->user_id, $setName);
  574   my $psvn = $set->psvn();
  575 
  576   # decide what to do about problem number
  577   my $problem;
  578   if ($problemNumber) {
  579     $problem = $db->getMergedProblem($effectiveUser->user_id, $setName, $problemNumber);
  580   } elsif ($pgFile) {
  581     $problem = WeBWorK::DB::Record::UserProblem->new(
  582       set_id => $set->set_id,
  583       problem_id => 0,
  584       login_id => $effectiveUser->user_id,
  585       source_file => $pgFile,
  586       # the rest of Problem's fields are not needed, i think
  587     );
  588   }
  589 
  590   # figure out if we're allowed to get solutions and call PG->new accordingly.
  591   my $showCorrectAnswers = $r->param("showCorrectAnswers") || 0;
  592   my $showHints          = $r->param("showHints") || 0;
  593   my $showSolutions      = $r->param("showSolutions") || 0;
  594   unless ($permissionLevel > 0 or time > $set->answer_date) {
  595     $showCorrectAnswers = 0;
  596     $showSolutions      = 0;
  597   }
  598 
  599   my $pg = WeBWorK::PG->new(
  600     $ce,
  601     $effectiveUser,
  602     $r->param('key'),
  603     $set,
  604     $problem,
  605     $psvn,
  606     {}, # no form fields!
  607     { # translation options
  608       displayMode     => "tex",
  609       showHints       => $showHints,
  610       showSolutions   => $showSolutions,
  611       processAnswers  => $showCorrectAnswers,
  612     },
  613   );
  614 
  615   if ($pg->{warnings} ne "") {
  616     push @{$self->{warnings}}, {
  617       set     => $setName,
  618       problem => $problemNumber,
  619       message => $pg->{warnings},
  620     };
  621   }
  622 
  623   if ($pg->{flags}->{error_flag}) {
  624     push @{$self->{errors}}, {
  625       set     => $setName,
  626       problem => $problemNumber,
  627       message => $pg->{errors},
  628       context => $pg->{body_text},
  629     };
  630     # if there was an error, body_text contains
  631     # the error context, not TeX code
  632     $pg->{body_text} = undef;
  633   } else {
  634     # append list of correct answers to body text
  635     if ($showCorrectAnswers && $problemNumber != 0) {
  636       my $correctTeX = "Correct Answers:\\par\\begin{itemize}\n";
  637       foreach my $ansName (@{$pg->{flags}->{ANSWER_ENTRY_ORDER}}) {
  638         my $correctAnswer = $pg->{answers}->{$ansName}->{correct_ans};
  639         $correctAnswer =~ s/\^/\\\^\{\}/g;
  640         $correctAnswer =~ s/\_/\\\_/g;
  641         $correctTeX .= "\\item $correctAnswer\n";
  642       }
  643       $correctTeX .= "\\end{itemize} \\par\n";
  644       $pg->{body_text} .= $correctTeX;
  645     }
  646   }
  647   return $pg->{body_text};
  648 }
  649 
  650 sub texInclude {
  651   my ($self, $texFile) = @_;
  652   my $tex = "";
  653 
  654   $tex .= texBlockComment("BEGIN: $texFile");
  655   eval {
  656     $tex .= readFile($texFile)
  657   };
  658   if ($@) {
  659     $tex .= texBlockComment($@);
  660   }
  661 
  662   return $tex;
  663 }
  664 
  665 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9