Parent Directory
|
Revision Log
took out some old commented out lines in PG.pm. -sam
1 ################################################################################ 2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project 3 # $Id$ 4 ################################################################################ 5 6 package WeBWorK::PG; 7 8 =head1 NAME 9 10 WeBWorK::PG - Wrap the action of the PG Translator in an easy-to-use API. 11 12 =cut 13 14 use strict; 15 use warnings; 16 use File::Path qw(rmtree); 17 use File::Temp qw(tempdir); 18 use WeBWorK::DB::Classlist; 19 use WeBWorK::DB::WW; 20 use WeBWorK::PG::Translator; 21 use WeBWorK::Problem; 22 use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry); 23 24 sub new($$$$$$$$) { 25 my $invocant = shift; 26 my $class = ref($invocant) || $invocant; 27 my ( 28 $courseEnv, 29 $user, 30 $key, 31 $set, 32 $problem, 33 $psvn, 34 $formFields, # in CGI::Vars format 35 $translationOptions, # hashref containing options for the 36 # translator, such as whether to show 37 # hints and the display mode to use 38 ) = @_; 39 40 # write timing log entry 41 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", 42 "user=".$user->id.",problem=".$courseEnv->{courseName}."/".$set->id."/".$problem->id.",mode=".$translationOptions->{displayMode}, 43 "begin"); 44 45 # install a local warn handler to collect warnings 46 my $warnings = ""; 47 local $SIG{__WARN__} = sub { $warnings .= shift } 48 if $courseEnv->{pg}->{options}->{catchWarnings}; 49 50 # create a Translator 51 #warn "PG: creating a Translator\n"; 52 my $translator = WeBWorK::PG::Translator->new; 53 54 # set the directory hash 55 #warn "PG: setting the directory hash\n"; 56 $translator->rh_directories({ 57 courseScriptsDirectory => $courseEnv->{webworkDirs}->{macros}, 58 macroDirectory => $courseEnv->{courseDirs}->{macros}, 59 templateDirectory => $courseEnv->{courseDirs}->{templates}, 60 tempDirectory => $courseEnv->{courseDirs}->{html_temp}, 61 }); 62 63 # evaluate modules and "extra packages" 64 #warn "PG: evaluating modules and \"extra packages\"\n"; 65 my @modules = @{ $courseEnv->{pg}->{modules} }; 66 foreach my $module_packages_ref (@modules) { 67 my ($module, @extra_packages) = @$module_packages_ref; 68 # the first item is the main package 69 $translator->evaluate_modules($module); 70 # the remaining items are "extra" packages 71 $translator->load_extra_packages(@extra_packages); 72 } 73 74 # set the environment (from defineProblemEnvir) 75 #warn "PG: setting the environment (from defineProblemEnvir)\n"; 76 my $envir = defineProblemEnvir( 77 $courseEnv, 78 $user, 79 $key, 80 $set, 81 $problem, 82 $psvn, 83 $formFields, 84 $translationOptions, 85 ); 86 $translator->environment($envir); 87 88 # initialize the Translator 89 #warn "PG: initializing the Translator\n"; 90 $translator->initialize(); 91 92 # load IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load 93 # i'd like to change this at some point to have the same sort of interface to global.conf 94 # that the module loading does -- have a list of macros to load unrestrictedly. 95 #warn "PG: loading IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load\n"; 96 foreach (qw(IO.pl PG.pl dangerousMacros.pl)) { 97 my $macroPath = $courseEnv->{webworkDirs}->{macros} . "/$_"; 98 my $err = $translator->unrestricted_load($macroPath); 99 warn "Error while loading $macroPath: $err" if $err; 100 } 101 102 # set the opcode mask (using default values) 103 #warn "PG: setting the opcode mask (using default values)\n"; 104 $translator->set_mask(); 105 106 # store the problem source 107 #warn "PG: storing the problem source\n"; 108 my $sourceFile = $problem->source_file; 109 $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$sourceFile 110 unless ($sourceFile =~ /^\//); 111 eval { $translator->source_string(readFile($sourceFile)) }; 112 if ($@) { 113 # well, we couldn't get the problem source, for some reason. 114 return bless { 115 translator => $translator, 116 head_text => "", 117 body_text => <<EOF, 118 WeBWorK::Utils::readFile($sourceFile) says: 119 $@ 120 EOF 121 answers => {}, 122 result => {}, 123 state => {}, 124 errors => "Failed to read the problem source file.", 125 warnings => $warnings, 126 flags => {error_flag => 1}, 127 }, $class; 128 } 129 130 # install a safety filter (&safetyFilter) 131 #warn "PG: installing a safety filter\n"; 132 $translator->rf_safety_filter(\&safetyFilter); 133 134 # write timing log entry -- the translator is now all set up 135 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", 136 "initialized", 137 "intermediate"); 138 139 # translate the PG source into text 140 #warn "PG: translating the PG source into text\n"; 141 $translator->translate(); 142 143 # after we're done translating, we may have to clean up after the translator. 144 # for example, 'images' mode uses a tempdir for dvipng's temp files. We have 145 # to remove it. 146 if ($translationOptions->{displayMode} eq 'images' && $envir->{dvipngTempDir}) { 147 rmtree($envir->{dvipngTempDir}, 0, 0); 148 } 149 150 my ($result, $state); # we'll need these on the other side of the if block! 151 if ($translationOptions->{processAnswers}) { 152 153 # process student answers 154 #warn "PG: processing student answers\n"; 155 $translator->process_answers($formFields); 156 157 # retrieve the problem state and give it to the translator 158 #warn "PG: retrieving the problem state and giving it to the translator\n"; 159 $translator->rh_problem_state({ 160 recorded_score => $problem->status, 161 num_of_correct_ans => $problem->num_correct, 162 num_of_incorrect_ans => $problem->num_incorrect, 163 }); 164 165 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by 166 # the PG macro package (PG.pl) 167 #warn "PG: determining an entry order\n"; 168 my @answerOrder = 169 $translator->rh_flags->{ANSWER_ENTRY_ORDER} 170 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} } 171 : keys %{ $translator->rh_evaluated_answers }; 172 173 # install a grader -- use the one specified in the problem, 174 # or fall back on the default from the course environment. 175 # (two magic strings are accepted, to avoid having to 176 # reference code when it would be difficult.) 177 #warn "PG: installing a grader\n"; 178 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE} 179 || $courseEnv->{pg}->{options}->{grader}; 180 $grader = $translator->rf_std_problem_grader 181 if $grader eq "std_problem_grader"; 182 $grader = $translator->rf_avg_problem_grader 183 if $grader eq "avg_problem_grader"; 184 die "Problem grader $grader is not a CODE reference." 185 unless ref $grader eq "CODE"; 186 $translator->rf_problem_grader($grader); 187 188 # grade the problem 189 #warn "PG: grading the problem\n"; 190 ($result, $state) = $translator->grade_problem( 191 answers_submitted => $translationOptions->{processAnswers}, 192 ANSWER_ENTRY_ORDER => \@answerOrder, 193 ); 194 195 } 196 197 # write timing log entry 198 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", "", "end"); 199 200 # return an object which contains the translator and the results of 201 # the translation process. this is DIFFERENT from the "format expected 202 # by Webwork.pm (and I believe processProblem8, but check.)" 203 return bless { 204 translator => $translator, 205 head_text => ${ $translator->r_header }, 206 body_text => ${ $translator->r_text }, 207 answers => $translator->rh_evaluated_answers, 208 result => $result, 209 state => $state, 210 errors => $translator->errors, 211 warnings => $warnings, 212 flags => $translator->rh_flags, 213 }, $class; 214 } 215 216 # ----- 217 218 sub defineProblemEnvir($$$$$$$) { 219 my ( 220 $courseEnv, 221 $user, 222 $key, 223 $set, 224 $problem, 225 $psvn, 226 $formFields, 227 $options, 228 ) = @_; 229 230 my %envir; 231 232 # PG environment variables 233 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 234 # any changes are noted by "ADDED:" or "REMOVED:" 235 236 # Vital state information 237 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img, 238 # texDisposition 239 240 $envir{psvn} = $psvn; 241 $envir{psvnNumber} = $envir{psvn}; 242 $envir{probNum} = $problem->id; 243 $envir{questionNumber} = $envir{probNum}; 244 $envir{fileName} = $problem->source_file; 245 $envir{probFileName} = $envir{fileName}; 246 $envir{problemSeed} = $problem->problem_seed; 247 $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); 248 $envir{languageMode} = $envir{displayMode}; 249 $envir{outputMode} = $envir{displayMode}; 250 $envir{displayHintsQ} = $options->{showHints}; 251 $envir{displaySolutionsQ} = $options->{showSolutions}; 252 $envir{refreshMath2img} = $options->{refreshMath2img}; 253 $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex 254 255 # Problem Information 256 # ADDED: courseName, formatedDueDate 257 258 $envir{openDate} = $set->open_date; 259 $envir{formattedOpenDate} = formatDateTime($envir{openDate}); 260 $envir{dueDate} = $set->due_date; 261 $envir{formattedDueDate} = formatDateTime($envir{dueDate}); 262 $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files 263 $envir{answerDate} = $set->answer_date; 264 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}); 265 $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); 266 $envir{problemValue} = $problem->value; 267 $envir{sessionKey} = $key; 268 $envir{courseName} = $courseEnv->{courseName}; 269 270 # Student Information 271 # ADDED: studentID 272 273 $envir{sectionName} = $user->section; 274 $envir{sectionNumber} = $envir{sectionName}; 275 $envir{recitationName} = $user->recitation; 276 $envir{recitationNumber} = $envir{recitationName}; 277 $envir{setNumber} = $set->id; 278 $envir{studentLogin} = $user->id; 279 $envir{studentName} = $user->first_name . " " . $user->last_name; 280 $envir{studentID} = $user->student_id; 281 282 # Answer Information 283 # REMOVED: refSubmittedAnswers 284 285 $envir{inputs_ref} = $formFields; 286 287 # External Programs 288 # ADDED: externalLaTeXPath, externalDvipngPath, 289 # externalGif2EpsPath, externalPng2EpsPath 290 291 $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth}; 292 $envir{externalLaTeXPath} = $courseEnv->{externalPrograms}->{latex}; 293 $envir{externalDvipngPath} = $courseEnv->{externalPrograms}->{dvipng}; 294 $envir{externalGif2EpsPath} = $courseEnv->{externalPrograms}->{gif2eps}; 295 $envir{externalPng2EpsPath} = $courseEnv->{externalPrograms}->{png2eps}; 296 $envir{externalGif2PngPath} = $courseEnv->{externalPrograms}->{gif2png}; 297 298 # Directories and URLs 299 # REMOVED: courseName 300 # ADDED: dvipngTempDir 301 302 $envir{cgiDirectory} = undef; 303 $envir{cgiURL} = undef; 304 $envir{classDirectory} = undef; 305 $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/"; 306 $envir{htmlDirectory} = $courseEnv->{courseDirs}->{html}."/"; 307 $envir{htmlURL} = $courseEnv->{courseURLs}->{html}."/"; 308 $envir{macroDirectory} = $courseEnv->{courseDirs}->{macros}."/"; 309 $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/"; 310 $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/"; 311 $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}."/"; 312 $envir{scriptDirectory} = undef; 313 $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}."/"; 314 $envir{dvipngTempDir} = $options->{displayMode} eq 'images' 315 ? tempdir("webwork-dvipng-XXXXXXXX", DIR => $envir{tempDirectory}) 316 : undef; 317 318 # Information for sending mail 319 320 $envir{mailSmtpServer} = $courseEnv->{mail}->{smtpServer}; 321 $envir{mailSmtpSender} = $courseEnv->{mail}->{smtpSender}; 322 323 # Default values for evaluating answers 324 325 my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults}; 326 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); 327 328 # Other things... 329 330 $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader}; 331 $envir{ALLOW_MAIL_TO} = $courseEnv->{email}->{allowedRecipients}; 332 333 return \%envir; 334 } 335 336 sub translateDisplayModeNames($) { 337 my $name = shift; 338 return { 339 tex => "TeX", 340 plainText => "HTML", 341 formattedText => "HTML_tth", 342 images => "HTML_img" 343 }->{$name}; 344 } 345 346 sub safetyFilter { 347 my $answer = shift; # accepts one answer and checks it 348 my $submittedAnswer = $answer; 349 $answer = '' unless defined $answer; 350 my ($errorno); 351 $answer =~ tr/\000-\037/ /; 352 # Return if answer field is empty 353 unless ($answer =~ /\S/) { 354 #$errorno = "<BR>No answer was submitted."; 355 $errorno = 0; ## don't report blank answer as error 356 return ($answer,$errorno); 357 } 358 # replace ^ with ** (for exponentiation) 359 # $answer =~ s/\^/**/g; 360 # Return if forbidden characters are found 361 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ ) { 362 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; 363 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; 364 return ($answer,$errorno); 365 } 366 $errorno = 0; 367 return($answer, $errorno); 368 } 369 370 1; 371 372 __END__ 373 374 =head1 SYNOPSIS 375 376 $pg = WeBWorK::PG->new( 377 $courseEnv, # a WeBWorK::CourseEnvironment object 378 $user, # a WeBWorK::User object 379 $sessionKey, 380 $set, # a WeBWorK::Set object 381 $problem, # a WeBWorK::Problem object 382 $psvn, 383 $formFields # in &WeBWorK::Form::Vars format 384 { # translation options 385 displayMode => "images", # (plainText|formattedText|images) 386 showHints => 1, # (0|1) 387 showSolutions => 0, # (0|1) 388 refreshMath2img => 0, # (0|1) 389 processAnswers => 1, # (0|1) 390 }, 391 ); 392 393 $translator = $pg->{translator}; # WeBWorK::PG::Translator 394 $body = $pg->{body_text}; # text string 395 $header = $pg->{head_text}; # text string 396 $answerHash = $pg->{answers}; # WeBWorK::PG::AnswerHash 397 $result = $pg->{result}; # hash reference 398 $state = $pg->{state}; # hash reference 399 $errors = $pg->{errors}; # text string 400 $warnings = $pg->{warnings}; # text string 401 $flags = $pg->{flags}; # hash reference 402 403 =head1 DESCRIPTION 404 405 WeBWorK::PG encapsulates the PG translation process, making multiple calls to 406 WeBWorK::PG::Translator. Much of the flexibility of the Translator is hidden, 407 instead making choices that are appropriate for the webwork-modperl system. 408 409 =head1 CONSTRUCTION 410 411 =over 412 413 =item new (ENVIRONMENT, USER, KEY, SET, PROBLEM, PSVN, FIELDS, OPTIONS) 414 415 The C<new> method creates a translator, initializes it using the parameters 416 specified, translates a PG file, and processes answers. It returns a reference 417 to a blessed hash containing the results of the translation process. 418 419 =back 420 421 =head2 Parameters 422 423 =over 424 425 =item ENVIRONMENT 426 427 a WeBWorK::CourseEnvironment object 428 429 =item USER 430 431 a WeBWorK::User object 432 433 =item KEY 434 435 the session key of the current session 436 437 =item SET 438 439 a WeBWorK::Set object 440 441 =item PROBLEM 442 443 a WeBWorK::Problem object. The contents of the source_file field can specify a 444 PG file either by absolute path or path relative to the "templates" directory. 445 I<The caller should remove taint from this value before passing!> 446 447 =item PSVN 448 449 the problem set version number 450 451 =item FIELDS 452 453 a reference to a hash (as returned by &WeBWorK::Form::Vars) containing form 454 fields submitted by a problem processor. The translator will look for fields 455 like "AnSwEr[0-9]" containing submitted student answers. 456 457 =item OPTIONS 458 459 a reference to a hash containing the following data: 460 461 =over 462 463 =item displayMode 464 465 one of "plainText", "formattedText", or "images" 466 467 =item showHints 468 469 boolean, render hints 470 471 =item showSolutions 472 473 boolean, render solutions 474 475 =item refreshMath2img 476 477 boolean, force images created by math2img (in "images" mode) to be recreated, 478 even if the PG source has not been updated. 479 480 =item processAnswers 481 482 boolean, call answer evaluators and graders 483 484 =back 485 486 =back 487 488 =head2 RETURN VALUE 489 490 The C<new> method returns a blessed hash reference containing the following 491 fields. More information can be found in the documentation for 492 WeBWorK::PG::Translator. 493 494 =over 495 496 =item translator 497 498 The WeBWorK::PG::Translator object used to render the problem. 499 500 =item head_text 501 502 HTML code for the E<lt>headE<gt> block of an resulting web page. Used for 503 JavaScript features. 504 505 =item body_text 506 507 HTML code for the E<lt>bodyE<gt> block of an resulting web page. 508 509 =item answers 510 511 An C<AnswerHash> object containing submitted answers, and results of answer 512 evaluation. 513 514 =item result 515 516 A hash containing the results of grading the problem. 517 518 =item state 519 520 A hash containing the new problem state. 521 522 =item errors 523 524 A string containing any errors encountered while rendering the problem. 525 526 =item warnings 527 528 A string containing any warnings encountered while rendering the problem. 529 530 =item flags 531 532 A hash containing PG_flags (see the Translator docs). 533 534 =back 535 536 =head1 OPERATION 537 538 WeBWorK::PG goes through the following operations when constructed: 539 540 =over 541 542 =item Get database information 543 544 Retrieve information about the current user, set, and problem from the 545 database. 546 547 =item Create a translator 548 549 Instantiate a WeBWorK::PG::Translator object. 550 551 =item Set the directory hash 552 553 Set the translator's directory hash (courseScripts, macros, templates, and temp 554 directories) from the course environment. 555 556 =item Evaluate PG modules 557 558 Using the module list from the course environment (pg->modules), perform a 559 "use"-like operation to evaluate modules at runtime. 560 561 =item Set the problem environment 562 563 Use data from the user, set, and problem, as well as the course environemnt and 564 translation options, to set the problem environment. 565 566 =item Initialize the translator 567 568 Call &WeBWorK::PG::Translator::initialize. What more do you want? 569 570 =item Load PG.pl and dangerousMacros.pl 571 572 These macros must be loaded without opcode masking, so they are loaded here. 573 574 =item Set the opcode mask 575 576 Set the opcode mask to the default specified by WeBWorK::PG::Translator. 577 578 =item Load the problem source 579 580 Give the problem source to the translator. 581 582 =item Install a safety filter 583 584 The safety filter is used to preprocess student input before evaluation. The 585 default safety filter, &WeBWorK::PG::safetyFilter, is used. 586 587 =item Translate the problem source 588 589 Call &WeBWorK::PG::Translator::translate to render the problem source into the 590 format given by the display mode. 591 592 =item Process student answers 593 594 Use form field inputs to evaluate student answers. 595 596 =item Load the problem state 597 598 Use values from the database to initialize the problem state, so that the 599 grader will have a point of reference. 600 601 =item Determine an entry order 602 603 Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the 604 problem. This is important for problems with dependancies among parts. 605 606 =item Install a grader 607 608 Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment, 609 to install a grader. 610 611 =item Grade the problem 612 613 Use the selected grader to grade the problem. 614 615 =back 616 617 =head1 AUTHOR 618 619 Written by Sam Hathaway, sh002i (at) math.rochester.edu. 620 621 =cut
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |