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

Diff of /trunk/webwork2/lib/WeBWorK/PG.pm

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

Revision 562 Revision 1196
12=cut 12=cut
13 13
14use strict; 14use strict;
15use warnings; 15use warnings;
16use File::Path qw(rmtree); 16use File::Path qw(rmtree);
17use File::Temp qw(tempdir); 17use WeBWorK::PG::ImageGenerator;
18use WeBWorK::DB::Classlist;
19use WeBWorK::DB::WW;
20use WeBWorK::PG::Translator; 18use WeBWorK::PG::Translator;
21use WeBWorK::Problem;
22use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry); 19use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry makeTempDirectory);
23 20
24sub new($$$$$$$$) { 21sub new {
25 my $invocant = shift; 22 my $invocant = shift;
26 my $class = ref($invocant) || $invocant; 23 my $class = ref($invocant) || $invocant;
27 my ( 24 my (
28 $courseEnv, 25 $courseEnv,
29 $user, 26 $user,
37 # hints and the display mode to use 34 # hints and the display mode to use
38 ) = @_; 35 ) = @_;
39 36
40 # write timing log entry 37 # write timing log entry
41 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", 38 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new",
42 "user=".$user->id.",problem=".$courseEnv->{courseName}."/".$set->id."/".$problem->id.",mode=".$translationOptions->{displayMode}, 39 "user=".$user->user_id.",problem=".$courseEnv->{courseName}."/".$set->set_id."/".$problem->problem_id.",mode=".$translationOptions->{displayMode},
43 "begin"); 40 "begin");
44 41
45 # install a local warn handler to collect warnings 42 # install a local warn handler to collect warnings
46 my $warnings = ""; 43 my $warnings = "";
47 local $SIG{__WARN__} = sub { $warnings .= shift }; 44 local $SIG{__WARN__} = sub { $warnings .= shift }
45 if $courseEnv->{pg}->{options}->{catchWarnings};
48 46
49 # create a Translator 47 # create a Translator
50 #warn "PG: creating a Translator\n"; 48 #warn "PG: creating a Translator\n";
51 my $translator = WeBWorK::PG::Translator->new; 49 my $translator = WeBWorK::PG::Translator->new;
52 50
86 84
87 # initialize the Translator 85 # initialize the Translator
88 #warn "PG: initializing the Translator\n"; 86 #warn "PG: initializing the Translator\n";
89 $translator->initialize(); 87 $translator->initialize();
90 88
91 # load PG.pl and dangerousMacros.pl using unrestricted_load 89 # load IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load
92 # i'd like to change this at some point to have the same sort of interface to global.conf 90 # i'd like to change this at some point to have the same sort of interface to global.conf
93 # that the module loading does -- have a list of macros to load unrestrictedly. 91 # that the module loading does -- have a list of macros to load unrestrictedly.
94 #warn "PG: loading PG.pl and dangerousMacros.pl using unrestricted_load\n"; 92 #warn "PG: loading IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load\n";
95 my $pg_pl = $courseEnv->{webworkDirs}->{macros} . "/PG.pl"; 93 foreach (qw(IO.pl PG.pl dangerousMacros.pl)) {
96 my $dangerousMacros_pl = $courseEnv->{webworkDirs}->{macros} . "/dangerousMacros.pl";
97 my $io_pl = $courseEnv->{webworkDirs}->{macros} . "/IO.pl"; 94 my $macroPath = $courseEnv->{webworkDirs}->{macros} . "/$_";
98 my $err = $translator->unrestricted_load($pg_pl); 95 my $err = $translator->unrestricted_load($macroPath);
99 warn "Error while loading $pg_pl: $err" if $err;
100 $err = $translator->unrestricted_load($dangerousMacros_pl);
101 warn "Error while loading $dangerousMacros_pl: $err" if $err;
102 $err = $translator->unrestricted_load($io_pl);
103 warn "Error while loading $io_pl: $err" if $err; 96 warn "Error while loading $macroPath: $err" if $err;
97 }
104 98
105 # set the opcode mask (using default values) 99 # set the opcode mask (using default values)
106 #warn "PG: setting the opcode mask (using default values)\n"; 100 #warn "PG: setting the opcode mask (using default values)\n";
107 $translator->set_mask(); 101 $translator->set_mask();
108 102
132 126
133 # install a safety filter (&safetyFilter) 127 # install a safety filter (&safetyFilter)
134 #warn "PG: installing a safety filter\n"; 128 #warn "PG: installing a safety filter\n";
135 $translator->rf_safety_filter(\&safetyFilter); 129 $translator->rf_safety_filter(\&safetyFilter);
136 130
131 # write timing log entry -- the translator is now all set up
132 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new",
133 "initialized",
134 "intermediate");
135
137 # translate the PG source into text 136 # translate the PG source into text
138 #warn "PG: translating the PG source into text\n"; 137 #warn "PG: translating the PG source into text\n";
139 $translator->translate(); 138 $translator->translate();
140 139
141 # after we're done translating, we may have to clean up after the translator. 140 # after we're done translating, we may have to clean up after the
141 # translator:
142
142 # for example, 'images' mode uses a tempdir for dvipng's temp files. We have 143 # for example, HTML_img mode uses a tempdir for dvipng's temp files.\
143 # to remove it. 144 # We have to remove it.
144 if ($translationOptions->{displayMode} eq 'images' && $envir->{dvipngTempDir}) { 145 if ($envir->{dvipngTempDir}) {
145 rmtree($envir->{dvipngTempDir}, 0, 0); 146 rmtree($envir->{dvipngTempDir}, 0, 0);
147 }
148
149 # HTML_dpng, on the other hand, uses an ImageGenerator. We have to
150 # render the queued equations.
151 if ($envir->{imagegen}) {
152 my $sourceFile = $courseEnv->{courseDirs}->{templates} . "/" . $problem->source_file;
153 my %mtimeOption = -e $sourceFile
154 ? (mtime => (stat $sourceFile)[9])
155 : ();
156
157 $envir->{imagegen}->render(
158 refresh => $translationOptions->{refreshMath2img},
159 %mtimeOption,
160 );
146 } 161 }
147 162
148 my ($result, $state); # we'll need these on the other side of the if block! 163 my ($result, $state); # we'll need these on the other side of the if block!
149 if ($translationOptions->{processAnswers}) { 164 if ($translationOptions->{processAnswers}) {
150 165
211 }, $class; 226 }, $class;
212} 227}
213 228
214# ----- 229# -----
215 230
216sub defineProblemEnvir($$$$$$$) { 231sub defineProblemEnvir {
217 my ( 232 my (
218 $courseEnv, 233 $courseEnv,
219 $user, 234 $user,
220 $key, 235 $key,
221 $set, 236 $set,
225 $options, 240 $options,
226 ) = @_; 241 ) = @_;
227 242
228 my %envir; 243 my %envir;
229 244
245 # ----------------------------------------------------------------------
246
230 # PG environment variables 247 # PG environment variables
231 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 248 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002
232 # any changes are noted by "ADDED:" or "REMOVED:" 249 # any changes are noted by "ADDED:" or "REMOVED:"
233 250
234 # Vital state information 251 # Vital state information
235 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img 252 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img,
253 # texDisposition
236 254
237 $envir{psvn} = $psvn; 255 $envir{psvn} = $set->psvn;
238 $envir{psvnNumber} = $envir{psvn}; 256 $envir{psvnNumber} = $envir{psvn};
239 $envir{probNum} = $problem->id; 257 $envir{probNum} = $problem->problem_id;
240 $envir{questionNumber} = $envir{probNum}; 258 $envir{questionNumber} = $envir{probNum};
241 $envir{fileName} = $problem->source_file; 259 $envir{fileName} = $problem->source_file;
242 $envir{probFileName} = $envir{fileName}; 260 $envir{probFileName} = $envir{fileName};
243 $envir{problemSeed} = $problem->problem_seed; 261 $envir{problemSeed} = $problem->problem_seed;
244 $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); 262 $envir{displayMode} = translateDisplayModeNames($options->{displayMode});
245 $envir{languageMode} = $envir{displayMode}; 263 $envir{languageMode} = $envir{displayMode};
246 $envir{outputMode} = $envir{displayMode}; 264 $envir{outputMode} = $envir{displayMode};
247 $envir{displayHintsQ} = $options->{hints}; 265 $envir{displayHintsQ} = $options->{showHints};
248 $envir{displaySolutionsQ} = $options->{solutions}; 266 $envir{displaySolutionsQ} = $options->{showSolutions};
267 # FIXME: this is HTML_img specific
249 $envir{refreshMath2img} = $options->{refreshMath2img}; 268 #$envir{refreshMath2img} = $options->{refreshMath2img};
269 $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex
250 270
251 # Problem Information 271 # Problem Information
252 # ADDED: courseName 272 # ADDED: courseName, formatedDueDate
253 273
254 $envir{openDate} = $set->open_date; 274 $envir{openDate} = $set->open_date;
255 $envir{formattedOpenDate} = formatDateTime($envir{openDate}); 275 $envir{formattedOpenDate} = formatDateTime($envir{openDate});
256 $envir{dueDate} = $set->due_date; 276 $envir{dueDate} = $set->due_date;
257 $envir{formattedDueDate} = formatDateTime($envir{dueDate}); 277 $envir{formattedDueDate} = formatDateTime($envir{dueDate});
278 $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files
258 $envir{answerDate} = $set->answer_date; 279 $envir{answerDate} = $set->answer_date;
259 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}); 280 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate});
260 $envir{numOfAttempts} = $problem->num_correct + $problem->num_incorrect; 281 $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0);
261 $envir{problemValue} = $problem->value; 282 $envir{problemValue} = $problem->value;
262 $envir{sessionKey} = $key; 283 $envir{sessionKey} = $key;
263 $envir{courseName} = $courseEnv->{courseName}; 284 $envir{courseName} = $courseEnv->{courseName};
264 285
265 # Student Information 286 # Student Information
267 288
268 $envir{sectionName} = $user->section; 289 $envir{sectionName} = $user->section;
269 $envir{sectionNumber} = $envir{sectionName}; 290 $envir{sectionNumber} = $envir{sectionName};
270 $envir{recitationName} = $user->recitation; 291 $envir{recitationName} = $user->recitation;
271 $envir{recitationNumber} = $envir{recitationName}; 292 $envir{recitationNumber} = $envir{recitationName};
272 $envir{setNumber} = $set->id; 293 $envir{setNumber} = $set->set_id;
273 $envir{studentLogin} = $user->id; 294 $envir{studentLogin} = $user->user_id;
274 $envir{studentName} = $user->first_name . " " . $user->last_name; 295 $envir{studentName} = $user->first_name . " " . $user->last_name;
275 $envir{studentID} = $user->student_id; 296 $envir{studentID} = $user->student_id;
276 297
277 # Answer Information 298 # Answer Information
278 # REMOVED: refSubmittedAnswers 299 # REMOVED: refSubmittedAnswers
286 $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth}; 307 $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth};
287 $envir{externalLaTeXPath} = $courseEnv->{externalPrograms}->{latex}; 308 $envir{externalLaTeXPath} = $courseEnv->{externalPrograms}->{latex};
288 $envir{externalDvipngPath} = $courseEnv->{externalPrograms}->{dvipng}; 309 $envir{externalDvipngPath} = $courseEnv->{externalPrograms}->{dvipng};
289 $envir{externalGif2EpsPath} = $courseEnv->{externalPrograms}->{gif2eps}; 310 $envir{externalGif2EpsPath} = $courseEnv->{externalPrograms}->{gif2eps};
290 $envir{externalPng2EpsPath} = $courseEnv->{externalPrograms}->{png2eps}; 311 $envir{externalPng2EpsPath} = $courseEnv->{externalPrograms}->{png2eps};
312 $envir{externalGif2PngPath} = $courseEnv->{externalPrograms}->{gif2png};
291 313
292 # Directories and URLs 314 # Directories and URLs
293 # REMOVED: courseName 315 # REMOVED: courseName
294 # ADDED: dvipngTempDir 316 # ADDED: dvipngTempDir
295
296 317
297 $envir{cgiDirectory} = undef; 318 $envir{cgiDirectory} = undef;
298 $envir{cgiURL} = undef; 319 $envir{cgiURL} = undef;
299 $envir{classDirectory} = undef; 320 $envir{classDirectory} = undef;
300 $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/"; 321 $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/";
304 $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/"; 325 $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/";
305 $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/"; 326 $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/";
306 $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}."/"; 327 $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}."/";
307 $envir{scriptDirectory} = undef; 328 $envir{scriptDirectory} = undef;
308 $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}."/"; 329 $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}."/";
330 # FIXME: this is HTML_img mode-specific
309 $envir{dvipngTempDir} = $options->{displayMode} eq 'images' 331 #$envir{dvipngTempDir} = $options->{displayMode} eq 'images'
310 ? tempdir("webwork-dvipng-XXXXXXXX", DIR => $envir{tempDirectory}) 332 # ? makeTempDirectory($envir{tempDirectory}, "webwork-dvipng")
311 : undef; 333 # : undef;
334
335 # Information for sending mail
336
337 $envir{mailSmtpServer} = $courseEnv->{mail}->{smtpServer};
338 $envir{mailSmtpSender} = $courseEnv->{mail}->{smtpSender};
339 $envir{ALLOW_MAIL_TO} = $courseEnv->{mail}->{allowedRecipients};
312 340
313 # Default values for evaluating answers 341 # Default values for evaluating answers
314 342
315 my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults}; 343 my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults};
316 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); 344 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults);
317 345
346 # ----------------------------------------------------------------------
347
348 my $basename = "equation-$envir{psvn}.$envir{probNum}";
349 $basename .= ".$envir{problemSeed}" if $envir{problemSeed};
350
351 # Object for generating equation images
352 $envir{imagegen} = WeBWorK::PG::ImageGenerator->new(
353 tempDir => $courseEnv->{webworkDirs}->{tmp}, # global temp dir
354 dir => $envir{tempDirectory},
355 url => $envir{tempURL},
356 basename => $basename,
357 latex => $envir{externalLaTeXPath},
358 dvipng => $envir{externalDvipngPath},
359 );
360
318 # Other things... 361 # Other things...
319 362 $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes
320 $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader}; 363 $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader};
364 $envir{PRINT_FILE_NAMES_FOR} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR};
365
366 # variables for interpreting capa problems.
367 $envir{CAPA_Tools} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_Tools};
368 $envir{CAPA_MCTools} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_MCTools};
369 $envir{CAPA_Graphics_URL} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_Graphics_URL};
370 $envir{CAPA_GraphicsDirectory} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_GraphicsDirectory};
321 371
322 return \%envir; 372 return \%envir;
323} 373}
324 374
325sub translateDisplayModeNames($) { 375sub translateDisplayModeNames($) {
326 my $name = shift; 376 my $name = shift;
327 return { 377 return {
328 tex => "TeX", 378 tex => "TeX",
329 plainText => "HTML", 379 plainText => "HTML",
330 formattedText => "HTML_tth", 380 formattedText => "HTML_tth",
331 images => "HTML_img" 381 images => "HTML_dpng", # "HTML_img",
332 }->{$name}; 382 }->{$name};
333} 383}
334 384
335sub safetyFilter { 385sub safetyFilter {
336 my $answer = shift; # accepts one answer and checks it 386 my $answer = shift; # accepts one answer and checks it
344 $errorno = 0; ## don't report blank answer as error 394 $errorno = 0; ## don't report blank answer as error
345 return ($answer,$errorno); 395 return ($answer,$errorno);
346 } 396 }
347 # replace ^ with ** (for exponentiation) 397 # replace ^ with ** (for exponentiation)
348 # $answer =~ s/\^/**/g; 398 # $answer =~ s/\^/**/g;
349 # Return if forbidden characters are found 399 # Return if forbidden characters are found
350 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ ) { 400 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\[\]\(\)\,\|]+$/ ) {
351 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; 401 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c;
352 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; 402 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>";
353 return ($answer,$errorno); 403 return ($answer,$errorno);
354 } 404 }
355 $errorno = 0; 405 $errorno = 0;
362 412
363=head1 SYNOPSIS 413=head1 SYNOPSIS
364 414
365 $pg = WeBWorK::PG->new( 415 $pg = WeBWorK::PG->new(
366 $courseEnv, # a WeBWorK::CourseEnvironment object 416 $courseEnv, # a WeBWorK::CourseEnvironment object
367 $user, # a WeBWorK::User object 417 $user, # a WeBWorK::DB::Record::User object
368 $sessionKey, 418 $sessionKey,
369 $set, # a WeBWorK::Set object 419 $set, # a WeBWorK::DB::Record::UserSet object
370 $problem, # a WeBWorK::Problem object 420 $problem, # a WeBWorK::DB::Record::UserProblem object
371 $psvn, 421 $psvn,
372 $formFields # in &WeBWorK::Form::Vars format 422 $formFields # in &WeBWorK::Form::Vars format
373 { # translation options 423 { # translation options
374 displayMode => "images", # (plainText|formattedText|images) 424 displayMode => "images", # (plainText|formattedText|images)
375 showHints => 1, # (0|1) 425 showHints => 1, # (0|1)
427 477
428a WeBWorK::Set object 478a WeBWorK::Set object
429 479
430=item PROBLEM 480=item PROBLEM
431 481
432a WeBWorK::Problem object. The contents of the source_file field can specify a 482a WeBWorK::DB::Record::UserProblem object. The contents of the source_file
433PG file either by absolute path or path relative to the "templates" directory. 483field can specify a PG file either by absolute path or path relative to the
434I<The caller should remove taint from this value before passing!> 484"templates" directory. I<The caller should remove taint from this value before
485passing!>
435 486
436=item PSVN 487=item PSVN
437 488
438the problem set version number 489the problem set version number
439 490
462boolean, render solutions 513boolean, render solutions
463 514
464=item refreshMath2img 515=item refreshMath2img
465 516
466boolean, force images created by math2img (in "images" mode) to be recreated, 517boolean, force images created by math2img (in "images" mode) to be recreated,
467even if the PG source has not been updated. 518even if the PG source has not been updated. FIXME: change the name of this
519option to "refreshEquations" and update the docs accordingly.
468 520
469=item processAnswers 521=item processAnswers
470 522
471boolean, call answer evaluators and graders 523boolean, call answer evaluators and graders
472 524

Legend:
Removed from v.562  
changed lines
  Added in v.1196

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9