--- trunk/webwork2/lib/WeBWorK/PG.pm 2002/09/18 19:25:42 555 +++ trunk/webwork2/lib/WeBWorK/PG.pm 2003/01/09 16:41:54 698 @@ -19,7 +19,7 @@ use WeBWorK::DB::WW; use WeBWorK::PG::Translator; use WeBWorK::Problem; -use WeBWorK::Utils qw(readFile formatDateTime); +use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry); sub new($$$$$$$$) { my $invocant = shift; @@ -37,44 +37,22 @@ # hints and the display mode to use ) = @_; -# # get database information -# my $classlist = WeBWorK::DB::Classlist->new($courseEnv); -# my $wwdb = WeBWorK::DB::WW->new($courseEnv); -# my $user = $classlist->getUser($userName); -# my $set = $wwdb->getSet($userName, $setName); -# my $psvn = $wwdb->getPSVN($userName, $setName); -# -# my $problem; -# if ($problemNumber =~ /^\d+$/) { -# $problem = $wwdb->getProblem($userName, $setName, $problemNumber); -# } else { -# # This is the fun part: if $problemNumber is NON-NUMERIC, the -# # user wants to specify a PG file directly. We manufacture a -# # Problem object using fake data and the specified source file. -# # This is potentially dangerous since an untrusted user is -# # allowed to specifiy an arbitrary file to be evaluated as PG. -# # A user of PG.pm MUST MAKE SURE that if $problemNumber is -# # supplied by an untrusted source (i.e. the Apache request), -# # it is numberic. A simple -# # -# # die unless $problemNumber =~ /^\d+$/; -# # -# # should suffice. -# $problem = WeBWorK::Problem->new( -# id => 0, -# set_id => $set->id, -# login_id => $user->id, -# source_file => $problemNumber, -# # the rest of Problem's fields are not needed -# ); -# } + # write timing log entry + writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", + "user=".$user->id.",problem=".$courseEnv->{courseName}."/".$set->id."/".$problem->id.",mode=".$translationOptions->{displayMode}, + "begin"); + + # install a local warn handler to collect warnings + my $warnings = ""; + local $SIG{__WARN__} = sub { $warnings .= shift } + if $courseEnv->{pg}->{options}->{catchWarnings}; # create a Translator - warn "PG: creating a Translator\n"; + #warn "PG: creating a Translator\n"; my $translator = WeBWorK::PG::Translator->new; # set the directory hash - warn "PG: setting the directory hash\n"; + #warn "PG: setting the directory hash\n"; $translator->rh_directories({ courseScriptsDirectory => $courseEnv->{webworkDirs}->{macros}, macroDirectory => $courseEnv->{courseDirs}->{macros}, @@ -83,7 +61,7 @@ }); # evaluate modules and "extra packages" - warn "PG: evaluating modules and \"extra packages\"\n"; + #warn "PG: evaluating modules and \"extra packages\"\n"; my @modules = @{ $courseEnv->{pg}->{modules} }; foreach my $module_packages_ref (@modules) { my ($module, @extra_packages) = @$module_packages_ref; @@ -94,7 +72,7 @@ } # set the environment (from defineProblemEnvir) - warn "PG: setting the environment (from defineProblemEnvir)\n"; + #warn "PG: setting the environment (from defineProblemEnvir)\n"; my $envir = defineProblemEnvir( $courseEnv, $user, @@ -108,26 +86,25 @@ $translator->environment($envir); # initialize the Translator - warn "PG: initializing the Translator\n"; + #warn "PG: initializing the Translator\n"; $translator->initialize(); - # load PG.pl and dangerousMacros.pl using unrestricted_load + # load IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load # i'd like to change this at some point to have the same sort of interface to global.conf # that the module loading does -- have a list of macros to load unrestrictedly. - warn "PG: loading PG.pl and dangerousMacros.pl using unrestricted_load\n"; - my $pg_pl = $courseEnv->{webworkDirs}->{macros} . "/PG.pl"; - my $dangerousMacros_pl = $courseEnv->{webworkDirs}->{macros} . "/dangerousMacros.pl"; - my $err = $translator->unrestricted_load($pg_pl); - warn "Error while loading $pg_pl: $err" if $err; - $err = $translator->unrestricted_load($dangerousMacros_pl); - warn "Error while loading $dangerousMacros_pl: $err" if $err; + #warn "PG: loading IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load\n"; + foreach (qw(IO.pl PG.pl dangerousMacros.pl)) { + my $macroPath = $courseEnv->{webworkDirs}->{macros} . "/$_"; + my $err = $translator->unrestricted_load($macroPath); + warn "Error while loading $macroPath: $err" if $err; + } # set the opcode mask (using default values) - warn "PG: setting the opcode mask (using default values)\n"; + #warn "PG: setting the opcode mask (using default values)\n"; $translator->set_mask(); # store the problem source - warn "PG: storing the problem source\n"; + #warn "PG: storing the problem source\n"; my $sourceFile = $problem->source_file; $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$sourceFile unless ($sourceFile =~ /^\//); @@ -145,35 +122,40 @@ result => {}, state => {}, errors => "Failed to read the problem source file.", - warnings => undef, + warnings => $warnings, flags => {error_flag => 1}, }, $class; } # install a safety filter (&safetyFilter) - warn "PG: installing a safety filter\n"; + #warn "PG: installing a safety filter\n"; $translator->rf_safety_filter(\&safetyFilter); + # write timing log entry -- the translator is now all set up + writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", + "initialized", + "intermediate"); + # translate the PG source into text - warn "PG: translating the PG source into text\n"; + #warn "PG: translating the PG source into text\n"; $translator->translate(); # after we're done translating, we may have to clean up after the translator. # for example, 'images' mode uses a tempdir for dvipng's temp files. We have # to remove it. if ($translationOptions->{displayMode} eq 'images' && $envir->{dvipngTempDir}) { - rmtree($envir->{dvipngTempDir}, 0, 1); + rmtree($envir->{dvipngTempDir}, 0, 0); } my ($result, $state); # we'll need these on the other side of the if block! if ($translationOptions->{processAnswers}) { # process student answers - warn "PG: processing student answers\n"; + #warn "PG: processing student answers\n"; $translator->process_answers($formFields); # retrieve the problem state and give it to the translator - warn "PG: retrieving the problem state and giving it to the translator\n"; + #warn "PG: retrieving the problem state and giving it to the translator\n"; $translator->rh_problem_state({ recorded_score => $problem->status, num_of_correct_ans => $problem->num_correct, @@ -182,7 +164,7 @@ # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by # the PG macro package (PG.pl) - warn "PG: determining an entry order\n"; + #warn "PG: determining an entry order\n"; my @answerOrder = $translator->rh_flags->{ANSWER_ENTRY_ORDER} ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} } @@ -192,7 +174,7 @@ # or fall back on the default from the course environment. # (two magic strings are accepted, to avoid having to # reference code when it would be difficult.) - warn "PG: installing a grader\n"; + #warn "PG: installing a grader\n"; my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE} || $courseEnv->{pg}->{options}->{grader}; $grader = $translator->rf_std_problem_grader @@ -204,7 +186,7 @@ $translator->rf_problem_grader($grader); # grade the problem - warn "PG: grading the problem\n"; + #warn "PG: grading the problem\n"; ($result, $state) = $translator->grade_problem( answers_submitted => $translationOptions->{processAnswers}, ANSWER_ENTRY_ORDER => \@answerOrder, @@ -212,6 +194,9 @@ } + # write timing log entry + writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", "", "end"); + # return an object which contains the translator and the results of # the translation process. this is DIFFERENT from the "format expected # by Webwork.pm (and I believe processProblem8, but check.)" @@ -222,8 +207,8 @@ answers => $translator->rh_evaluated_answers, result => $result, state => $state, - errors => $translator->errors, # *** what is this doing? - warnings => undef, # *** gotta catch warnings eventually... + errors => $translator->errors, + warnings => $warnings, flags => $translator->rh_flags, }, $class; } @@ -249,7 +234,8 @@ # any changes are noted by "ADDED:" or "REMOVED:" # Vital state information - # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img + # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img, + # texDisposition $envir{psvn} = $psvn; $envir{psvnNumber} = $envir{psvn}; @@ -261,20 +247,22 @@ $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); $envir{languageMode} = $envir{displayMode}; $envir{outputMode} = $envir{displayMode}; - $envir{displayHintsQ} = $options->{hints}; - $envir{displaySolutionsQ} = $options->{solutions}; + $envir{displayHintsQ} = $options->{showHints}; + $envir{displaySolutionsQ} = $options->{showSolutions}; $envir{refreshMath2img} = $options->{refreshMath2img}; + $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex # Problem Information - # ADDED: courseName + # ADDED: courseName, formatedDueDate $envir{openDate} = $set->open_date; $envir{formattedOpenDate} = formatDateTime($envir{openDate}); $envir{dueDate} = $set->due_date; $envir{formattedDueDate} = formatDateTime($envir{dueDate}); + $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files $envir{answerDate} = $set->answer_date; $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}); - $envir{numOfAttempts} = $problem->num_correct + $problem->num_incorrect; + $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); $envir{problemValue} = $problem->value; $envir{sessionKey} = $key; $envir{courseName} = $courseEnv->{courseName}; @@ -297,34 +285,41 @@ $envir{inputs_ref} = $formFields; # External Programs - # ADDED: externalLaTeXPath, externalDvipngPath, externalMath2imgPath + # ADDED: externalLaTeXPath, externalDvipngPath, + # externalGif2EpsPath, externalPng2EpsPath $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth}; $envir{externalLaTeXPath} = $courseEnv->{externalPrograms}->{latex}; $envir{externalDvipngPath} = $courseEnv->{externalPrograms}->{dvipng}; - $envir{externalMath2imgPath} = $courseEnv->{externalPrograms}->{math2img}; + $envir{externalGif2EpsPath} = $courseEnv->{externalPrograms}->{gif2eps}; + $envir{externalPng2EpsPath} = $courseEnv->{externalPrograms}->{png2eps}; + $envir{externalGif2PngPath} = $courseEnv->{externalPrograms}->{gif2png}; # Directories and URLs # REMOVED: courseName # ADDED: dvipngTempDir - $envir{cgiDirectory} = undef; $envir{cgiURL} = undef; $envir{classDirectory} = undef; $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/"; $envir{htmlDirectory} = $courseEnv->{courseDirs}->{html}."/"; - $envir{htmlURL} = $courseEnv->{courseURLs}->{html}; + $envir{htmlURL} = $courseEnv->{courseURLs}->{html}."/"; $envir{macroDirectory} = $courseEnv->{courseDirs}->{macros}."/"; $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/"; $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/"; - $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}; + $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}."/"; $envir{scriptDirectory} = undef; - $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}; + $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}."/"; $envir{dvipngTempDir} = $options->{displayMode} eq 'images' - ? tempdir("webwork-dvipng-XXXXXXXX", TMPDIR => 1) + ? tempdir("webwork-dvipng-XXXXXXXX", DIR => $envir{tempDirectory}) : undef; + # Information for sending mail + + $envir{mailSmtpServer} = $courseEnv->{mail}->{smtpServer}; + $envir{mailSmtpSender} = $courseEnv->{mail}->{smtpSender}; + # Default values for evaluating answers my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults}; @@ -333,6 +328,7 @@ # Other things... $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader}; + $envir{ALLOW_MAIL_TO} = $courseEnv->{email}->{allowedRecipients}; return \%envir; } @@ -361,7 +357,7 @@ } # replace ^ with ** (for exponentiation) # $answer =~ s/\^/**/g; - # Return if forbidden characters are found + # Return if forbidden characters are found unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ ) { $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; $errorno = "
There are forbidden characters in your answer: $submittedAnswer
";