[system] / trunk / webwork-modperl / lib / WeBWorK / ContentGenerator / Hardcopy.pm Repository:
ViewVC logotype

Diff of /trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/Hardcopy.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.494  
changed lines
  Added in v.502

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9