[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 562 - (download) (as text) (annotate)
Fri Sep 27 23:53:42 2002 UTC (10 years, 7 months ago) by sh002i
File size: 7054 byte(s)
- created macros/IO.pl, which is loaded with no opmask by PG.pm. It is a copy
  of WeBWorK::PG::IO.pm, with some changes to make it work as a macro package.
  The translator no longer shares IO.pm's functions with the safe compartment.
  This is a BAD THING, and should be reconsidered when the Translator is
  revised.
- Changed many (but not all) checks for HTML or HTML_tth modes to match /^HTML/
  in the macros.
- changed &header to &head in Problem.pm
- Added problem environment variables for gif2eps and png2eps and modified
  &dangerousMacros::alias to use them
- fixed MOST of the harmless warnings in the system. there's still the "Use
  of uninitialized value in null operation" warning in template(), tho.

Still to come:

- make images in PDFs work
- fix TTH mode character encodings on mac (maybe)
- have logout button invalidate key
- Pretty die messages (from outside of the translator)
- Feedback - need nice modular way of sending email
- Options - email address and password

    1 ################################################################################
    2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
    3 # $Id$
    4 ################################################################################
    5 
    6 package WeBWorK::ContentGenerator::Hardcopy;
    7 
    8 =head1 NAME
    9 
   10 WeBWorK::ContentGenerator::Test - generate a PDF version of one or more
   11 problem sets.
   12 
   13 =cut
   14 
   15 use strict;
   16 use warnings;
   17 use base qw(WeBWorK::ContentGenerator);
   18 use Apache::Constants qw(:common);
   19 use CGI qw();
   20 use File::Path qw(rmtree);
   21 use File::Temp qw(tempdir);
   22 use WeBWorK::DB::Classlist;
   23 use WeBWorK::DB::WW;
   24 use WeBWorK::Form;
   25 use WeBWorK::Utils qw(readFile);
   26 
   27 sub texBlockComment { return "\n".("%"x80)."\n%% ".join("", @_)."\n".("%"x80)."\n\n"; }
   28 
   29 sub initialize {
   30   my $self = shift;
   31   my $ce = $self->{courseEnvironment};
   32   $self->{cldb} = WeBWorK::DB::Classlist->new($ce);
   33   $self->{wwdb} = WeBWorK::DB::WW->new($ce);
   34 }
   35 
   36 sub path {
   37   my ($self, undef, $args) = @_;
   38 
   39   my $ce = $self->{courseEnvironment};
   40   my $root = $ce->{webworkURLs}->{root};
   41   my $courseName = $ce->{courseName};
   42   return $self->pathMacro($args,
   43     "Home" => "$root",
   44     $courseName => "$root/$courseName",
   45     "Hardcopy Generator" => "",
   46   );
   47 }
   48 
   49 sub title {
   50   return "Hardcopy Generator";
   51 }
   52 
   53 sub body {
   54   my ($self, $singleSet) = @_;
   55   $singleSet =~ s/^set//;
   56   my $r = $self->{r};
   57   my $ce = $self->{courseEnvironment};
   58   $self->{wwdb} = WeBWorK::DB::WW->new($ce);
   59 
   60   my @sets = $r->param("set");
   61   unshift @sets, $singleSet;
   62   unless (@sets) {
   63     print CGI::p("No problem sets were specified.");
   64     return OK;
   65   }
   66 
   67   #print CGI::pre($self->getMultiSetTeX(@sets));
   68   #return "";
   69 
   70   print CGI::p("Generating your hardcopy...");
   71   my $url = $self->makeHardcopy(@sets);
   72   if ($url) {
   73     print CGI::p("Ok, your hardcopy is ready. Click the following link to download it.");
   74     print CGI::p({-align=>"center"},
   75       CGI::big(CGI::a({-href=>$url}, "Download PDF Hardcopy"))
   76     );
   77   } else {
   78     print CGI::p("Hmm, looks like I was unable to generate the hardcopy you requested. I'm really sorry... :(");
   79   }
   80 
   81   return "";
   82 }
   83 
   84 # -----
   85 
   86 sub makeHardcopy {
   87   my ($self, @sets) = @_;
   88   my $courseName = $self->{courseEnvironment}->{courseName};
   89   my $userName = $self->{r}->param("user");
   90   my $tempDir = $self->{courseEnvironment}->{courseDirs}->{html_temp}
   91     . "/hardcopy";
   92   my $tempURL = $self->{courseEnvironment}->{courseURLs}->{html_temp}
   93     . "/hardcopy";
   94 
   95   # determine name of PDF file
   96   my $fileName;
   97   if (@sets > 1) {
   98     # multiset output
   99     $fileName = "$courseName.$userName.multiset.pdf"
  100   } elsif (@sets == 1) {
  101     # only one set
  102     my $setName = $sets[0];
  103     $fileName = "$courseName.$userName.$setName.pdf";
  104   } else {
  105     $fileName = "$courseName.$userName.pdf";
  106   }
  107   my $tex = $self->getMultiSetTeX(@sets);
  108   #print CGI::pre($tex);
  109   $self->latex2pdf($tex, $tempDir, $fileName) or return;
  110 
  111   return "$tempURL/$fileName";
  112 }
  113 
  114 sub latex2pdf {
  115   # this is a little ad-hoc function which I will replace with a LaTeX
  116   # module at some point (or put it in Utils).
  117   my ($self, $tex, $fileBase, $fileName) = @_;
  118   my $finalFile = "$fileBase/$fileName";
  119   my $ce = $self->{courseEnvironment};
  120 
  121   # create a temporary directory for tex to shit in
  122   my $wd = tempdir("webwork-hardcopy-XXXXXXXX", TMPDIR => 1);
  123   my $texFile = "$wd/hardcopy.tex";
  124   my $pdfFile = "$wd/hardcopy.pdf";
  125   my $logFile = "$wd/hardcopy.log";
  126 
  127   # write the tex file
  128   local *TEX;
  129   open TEX, ">", $texFile;
  130   print TEX $tex;
  131   close TEX;
  132 
  133   # call pdflatex - we don't want to chdir in the mod_perl process, as
  134   # that might step on the feet of other things (esp. in Apache 2.0)
  135   my $pdflatex = $ce->{externalPrograms}->{pdflatex};
  136   system "cd $wd && $pdflatex $texFile";
  137 
  138   if (-e $pdfFile) {
  139     # move resulting PDF file to appropriate location
  140     my $mv = $ce->{externalPrograms}->{mv};
  141     system $mv, $pdfFile, $finalFile and die "Failed to mv: $!\n";
  142   }
  143 
  144   # remove temporary directory
  145   rmtree($wd, 0, 1);
  146 
  147   return -e $finalFile;
  148 }
  149 
  150 # -----
  151 
  152 sub getMultiSetTeX {
  153   my ($self, @sets) = @_;
  154   my $ce = $self->{courseEnvironment};
  155   my $tex = "";
  156 
  157   # the document preamble
  158   $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{preamble});
  159 
  160   while (my $set = shift @sets) {
  161     $tex .= $self->getSetTeX($set);
  162     if (@sets) {
  163       # divide sets, but not after the last set
  164       $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{setDivider});
  165     }
  166   }
  167 
  168   # the document postamble
  169   $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{postamble});
  170 
  171   return $tex;
  172 }
  173 
  174 sub getSetTeX {
  175   my ($self, $setName) = @_;
  176   my $ce = $self->{courseEnvironment};
  177   my $wwdb = $self->{wwdb};
  178   my $user = $self->{r}->param("user");
  179   my @problemNumbers = sort { $a <=> $b } $wwdb->getProblems($user, $setName);
  180 
  181   # get header and footer
  182   my $setHeader = $wwdb->getSet($user, $setName)->set_header
  183     || $ce->{webworkFiles}->{hardcopySnippets}->{setHeader};
  184   # database doesn't support the following yet :(
  185   #my $setFooter = $wwdb->getSet($user, $setName)->set_footer
  186   # || $ce->{webworkFiles}->{hardcopySnippets}->{setFooter};
  187   # so we don't allow per-set customization, which is probably okay :)
  188   my $setFooter = $ce->{webworkFiles}->{hardcopySnippets}->{setFooter};
  189 
  190   my $tex = "";
  191 
  192   # render header
  193   $tex .= texBlockComment("BEGIN $setName : $setHeader");
  194   $tex .= $self->getProblemTeX($setName, 0, $setHeader);
  195 
  196   # render each problem
  197   while (my $problemNumber = shift @problemNumbers) {
  198     $tex .= texBlockComment("BEGIN $setName : $problemNumber");
  199     $tex .= $self->getProblemTeX($setName, $problemNumber);
  200     if (@problemNumbers) {
  201       # divide problems, but not after the last problem
  202       $tex .= $self->texInclude($ce->{webworkFiles}->{hardcopySnippets}->{problemDivider});
  203     }
  204   }
  205 
  206   # render footer
  207   $tex .= texBlockComment("BEGIN $setName : $setFooter");
  208   $tex .= $self->getProblemTeX($setName, 0, $setFooter);
  209 
  210   return $tex;
  211 }
  212 
  213 sub getProblemTeX {
  214   my ($self, $setName, $problemNumber, $pgFile) = @_;
  215   my $r = $self->{r};
  216   my $ce = $self->{courseEnvironment};
  217 
  218   my $wwdb = $self->{wwdb};
  219   my $cldb = $self->{cldb};
  220   my $user            = $cldb->getUser($r->param("user"));
  221   my $set             = $wwdb->getSet($user->id, $setName);
  222   my $psvn            = $wwdb->getPSVN($user->id, $setName);
  223 
  224   # decide what to do about problem number
  225   my $problem;
  226   if ($problemNumber) {
  227     $problem = $wwdb->getProblem($user->id, $setName, $problemNumber);
  228   } elsif ($pgFile) {
  229     $problem = WeBWorK::Problem->new(
  230       id => 0,
  231       set_id => $set->id,
  232       login_id => $user->id,
  233       source_file => $pgFile,
  234       # the rest of Problem's fields are not needed, i think
  235     );
  236   }
  237 
  238   my $pg = WeBWorK::PG->new(
  239     $ce,
  240     $user,
  241     $r->param('key'),
  242     $set,
  243     $problem,
  244     $psvn,
  245     {}, # no form fields!
  246     { # translation options
  247       displayMode     => "tex",
  248       showHints       => 0,
  249       showSolutions   => 0,
  250       processAnswers  => 0,
  251     },
  252   );
  253 
  254   return $pg->{body_text};
  255 }
  256 
  257 sub texInclude {
  258   my ($self, $texFile) = @_;
  259   my $tex = "";
  260 
  261   $tex .= texBlockComment("BEGIN: $texFile");
  262   eval {
  263     $tex .= readFile($texFile)
  264   };
  265   if ($@) {
  266     $tex .= texBlockComment($@);
  267   }
  268 
  269   return $tex;
  270 }
  271 
  272 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9