[system] / trunk / webwork / system / cgi / cgi-scripts / processProblem8.pl Repository:
ViewVC logotype

View of /trunk/webwork/system/cgi/cgi-scripts/processProblem8.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1160 - (download) (as text) (annotate)
Fri Jun 13 17:35:35 2003 UTC (9 years, 11 months ago) by gage
File size: 65808 byte(s)
Changes to make processProblem8 work with new version of ImageGenerator
--Mike

    1 #!/usr/local/bin/webwork-perl
    2 
    3 # This file is processProblem8.pl
    4 # This is a special version of processProblem.pl
    5 # made to be used as an editor
    6 
    7 # It is called from a form with inputs
    8 # 'user',
    9 # 'key'
   10 # 'course'
   11 # 'probSetKey' and
   12 # 'probNum'
   13 # and in addition
   14 # 'Mode'   (for either TeX mode or HTML mode or Latex2HTML mode)
   15 # 'show_old_answers'  (whether or not student's old answers should be filled in)
   16 # 'ShowAns'  (asks for answer to be shown -- only available for instructors)
   17 # 'answer$i'  (the answers -- if any --provided to the questions)
   18 # 'showEdit'  (checks if the ShowEditor button should be shown and clicked)
   19 # 'showSol'   (checks if the solution button ishould be shown and clicked)
   20 # as well as
   21 # 'source' when an edited source is provided by a web based editor
   22 # 'seed'   when a new seed is provided by a web based editor
   23 # 'readSourceFromHTMLQ'
   24 # 'action' which can be 'Save updated version' or 'Read problem from disk' or
   25 #    'Submit Answers' or 'Preview Answers' or 'Preview Again'
   26 # 'probFileName'
   27 # 'languageType'
   28 
   29 use strict;
   30 use lib '.'; use webworkInit; # WeBWorKInitLine
   31 
   32 use CGI qw(:standard);
   33 use Net::SMTP;
   34 use Global;
   35 use Auth;
   36 use Safe;
   37 use MIME::Base64 qw( encode_base64 decode_base64) ;
   38 use PGtranslator;
   39 use File::Temp qw(tempdir);
   40 use ImageGenerator;
   41 BEGIN {
   42   # set to 1 to enable timing_log
   43   # (contains debugging info about time taken by scripts to run)
   44   $main::logTimingData = 1;
   45 
   46   # begin Timing code
   47   if( $main::logTimingData == 1 ) {
   48     use Benchmark;
   49     $main::beginTime = new Benchmark;
   50   }
   51   # end Timing code
   52 
   53   $main::TIME_OUT_CONSTANT = 60;                   # one minute wait for on screen problems
   54   $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $!   stopped at $0\n";};
   55   $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $!   stopped at $0\n";  };
   56   $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) };
   57 
   58 # ## ATTENTION:  The handlers PG_floating_point_exception_handler and PG_warnings_handler
   59 # ## have to be installed after CGI::Carp is called since it also
   60 # ## modifes the die and warn labels. Finding the right warning mechanism using these two
   61 # ## methods bears further investigation
   62 # ## They are defined in Global.pm
   63    $SIG{'FPE'}  = \&Global::PG_floating_point_exception_handler;
   64    $SIG{__WARN__}=\&Global::PG_warnings_handler;
   65 
   66    alarm($main::TIME_OUT_CONSTANT);
   67 
   68 };
   69 
   70 
   71 
   72 use vars qw ( $questionNumber $STRINGforOUTPUT $languageMode  $ansCount $openDate $cgiURL
   73   $studentName $pinNumber $submittedAnswers $setNumber $answerDate $dueDate $studentLogin
   74   $problemValue $safeCompartment $psvnNumber $fileName
   75   $probNum $sectionName  $sectionNumber $recitationName $recitationNumber $sessionKey
   76   $courseName $modules_to_evaluate $extra_packages_to_be_loaded
   77   );
   78 
   79 eval {
   80 
   81 # This hardwires access to these modules/objects.
   82 
   83 
   84 ################################################
   85 
   86 #switched to object-oriented interface with CGI
   87 #DME 6/15/2000
   88 my $cgi = new CGI;
   89 
   90 if( $CGI::VERSION < 2.5 ) {
   91   die "This version of WeBWorK requires at least version 2.50 of the CGI.pm library";
   92 }
   93 my %inputs = $cgi -> Vars();
   94 
   95 
   96 # get information from CGI inputs  (see also below for additional information)
   97   my $Course    = $inputs{'course'};
   98   my $User    = $inputs{'user'};
   99   # define these for the timingLogInfo
  100   $main::Course   = $Course;
  101   $main::User   = $User;
  102   $main::Action     = $inputs{'action'};
  103 
  104 
  105   my $Session_key     = $inputs{'key'};
  106   my $randpsvn      = 22222; #int rand(1111,9999);
  107   my $psvn        = $inputs{'probSetKey'};  #psvn stands for Problem Set Version Number
  108   my $probNum       = 1;
  109      $probNum       = $inputs{'probNum'} if defined($inputs{'probNum'});
  110   my $nextProbNum     = $probNum +1 if defined($probNum);
  111   my $previousProbNum   = $probNum -1 if defined($probNum);
  112   my $mode        = "HTML";
  113        $mode        = $inputs{'Mode'} if defined( $inputs{'Mode'} );
  114        $main::display_mode  = $mode;  # this is only used for the timing messages.
  115     my $showEdit      = $inputs{'showEdit'};
  116     my $show_old_answers  = 0;
  117      $show_old_answers  = $inputs{'show_old_answers'} if defined($inputs{'show_old_answers'});
  118 
  119 # verify that information has been received
  120   unless($Course && $User && $Session_key && $psvn) {
  121       my $error_msg = $cgi -> remote_host() . '   ' .
  122         $cgi -> user_agent() . '   ' . $cgi -> query_string();
  123         &wwerror("$0, missing data",
  124           "The script did not receive the proper input data.
  125           Course is $Course, user is $User, session key is $Session_key, psvn is $psvn",'','',$error_msg
  126     );
  127   }
  128 
  129 
  130 # establish environment for this script
  131   &Global::getCourseEnvironment($Course);
  132   my $macroDirectory      = getCourseMacroDirectory();
  133   my $databaseDirectory     = getCourseDatabaseDirectory();
  134   my $htmlDirectory         = getCourseHtmlDirectory();
  135   my $htmlURL               = getCourseHtmlURL();
  136   my $scriptDirectory       = getWebworkScriptDirectory();
  137   my $templateDirectory     = getCourseTemplateDirectory();
  138     my $courseScriptsDirectory  = getCourseScriptsDirectory();
  139 
  140 
  141 
  142     require "${courseScriptsDirectory}$Global::displayMacros_pl";
  143   require "${scriptDirectory}$Global::DBglue_pl";
  144   require "${scriptDirectory}$Global::classlist_DBglue_pl";
  145   require "${scriptDirectory}$Global::HTMLglue_pl";
  146   require "${scriptDirectory}$Global::FILE_pl";
  147 
  148   my $permissionsFile = &Global::getCoursePermissionsFile($Course);
  149   my $permissions   = &get_permissions($User,$permissionsFile);
  150   my $keyFile     = &Global::getCourseKeyFile($Course);
  151 
  152 ####################################################################
  153 # load the modules to be used in PGtranslator
  154   require "${courseScriptsDirectory}PG_module_list.pl" or
  155     wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl");
  156 ####################################################################
  157 
  158 # log access
  159   &Global::log_info('', $cgi -> query_string);
  160 
  161 unless ($User eq "practice666" ) {
  162   #verify session key
  163     &verify_key($User, $Session_key, "$keyFile", $Course, \%inputs);
  164 }
  165 
  166 
  167 ##right now $probNum cannot possibly be "", because its default is 1
  168 ##is that how it should be?
  169 ###Should problemBank2 be substituted by some Global variable???###
  170   if($probNum eq "" && ($Course ne "problemBank2") )
  171     {
  172     &selectionError;
  173     die "Content-type: text/html\n\n ERROR: in $Global::processProblem_CGI near &selectionError";
  174     }
  175 
  176 
  177 # get the rest of the information from the CGI script
  178     # get language type
  179     my $displayMode = defined($inputs{'languageType'}) ?$inputs{'languageType'}:'pg';
  180 
  181     # get answers
  182 
  183     # Decide whether answers have been submitted.
  184     my $answers_submitted =0;
  185     $answers_submitted = 1 if defined($inputs{answer_form_submitted}) and 1 == $inputs{answer_form_submitted};
  186     $answers_submitted = 0 if defined($inputs{'action'}) and
  187       ( $inputs{'action'} =~ /Paste Answer/ );
  188 
  189     # Decide whether preview_mode has been selected
  190     my $preview_mode =0;
  191     $preview_mode = 1 if defined($inputs{'action'}) and
  192       (( $inputs{'action'} =~ /Preview Answer/ ) or ( $inputs{'action'} =~ /Preview Again/ ));
  193 
  194 
  195     my $answersRequestedQ = 0;
  196   $answersRequestedQ=  $inputs{'ShowAns'} if defined($inputs{'ShowAns'});
  197 
  198   my $solutionsRequestedQ= 0;
  199     $solutionsRequestedQ= $inputs{'ShowSol'} if defined($inputs{'ShowSol'});
  200 
  201   my $hintsRequestedQ= 0;
  202     $hintsRequestedQ= $inputs{'ShowHint'} if defined($inputs{'ShowHint'});
  203 
  204     my $doNotRecordAnsRequestedQ= 0;
  205     $doNotRecordAnsRequestedQ= $inputs{'doNotRecordAns'} if defined($inputs{'doNotRecordAns'});
  206 
  207 
  208 #
  209 # # cache information about the problem set (from the webwork-database)
  210 # and begin constructing the environment for constructing and displaying the problem
  211   &attachProbSetRecord($psvn);
  212   &attachCLRecord(&getStudentLogin($psvn));
  213 
  214 
  215 # Get information from database
  216   my  ($currentTime,$odts,$ddts,$adts);
  217   $currentTime  = time;
  218   $odts     = &getOpenDate($psvn);
  219   $ddts     = &getDueDate($psvn);
  220   $adts     = &getAnswerDate($psvn);
  221 
  222 
  223   my  ($setNumber,$numberOfProblems);
  224   $setNumber      = &getSetNumber($psvn);
  225   $numberOfProblems     = &getAllProblemsForProbSetRecord($psvn);
  226   my $setNumber_display = $setNumber;
  227   $setNumber_display =~ s/_/ /g;
  228 
  229 
  230 # If answers have not been submitted and previous answers have been saved, patch them in
  231 # unless $show_old_answers = 0
  232 
  233   unless ($answers_submitted or !$show_old_answers) {
  234     my $student_answers = getProblemStudentAnswer($probNum,$psvn);
  235     if (defined $student_answers) {
  236       my $rh_answer_hash =  decode_submitted_answers($student_answers);
  237       my %answer_hash = %$rh_answer_hash;
  238       my ($label, $value);
  239       foreach $label (keys %answer_hash) {$inputs{$label} = $answer_hash{$label};}
  240     }
  241   }
  242 
  243 
  244 # Determine language from the file extension(e.g.  file.pg  or file.pz)
  245     $displayMode  = &getProblemFileName($probNum,$psvn);
  246   $displayMode   = $inputs{'probFileName'} if defined($inputs{'probFileName'});
  247 
  248   $displayMode  =~ s/^.*\.([^\.]*)$/$1/;
  249 
  250 
  251 # get problem name
  252   my $probFileName      =  &getProblemFileName($probNum,$psvn);
  253      $probFileName  =  $inputs{'probFileName'} if defined($inputs{'probFileName'});
  254 
  255 # determine time status.
  256 
  257 # check that the psvn corresponds to the user and that it is after the open
  258 # date.  This should only fail if someone is trying to break into WeBWorK.
  259 
  260 
  261     if ( ( ( $User ne &getStudentLogin($psvn)) ||($currentTime < $odts) )
  262             and ($permissions != $Global::instructor_permissions)
  263                 and   ($permissions != $Global::TA_permissions)
  264         )   {
  265     &hackerError;
  266     exit;
  267   }
  268 
  269 
  270 
  271 ## check to see if it is after due + answer date, if so, put note by
  272 ## submit answer button (below)
  273   my $dueDateNote = "";
  274   my $answerNote  = "";
  275 
  276   if($currentTime>$ddts)
  277     {$dueDateNote=" <EM>Note: it is after the due date.</EM>\n";}
  278   if($currentTime>$adts)
  279     {$answerNote= " <EM>Answers available.</EM>\n";}
  280 
  281 # determine display defaults
  282   my ($displayCorrectAnswersQ,$displayShowAnswerLineQ);
  283 
  284   $displayShowAnswerLineQ = ($permissions == $Global::instructor_permissions) || ($currentTime > $adts) ;
  285   $displayCorrectAnswersQ = 1 if  $answersRequestedQ && ($currentTime > $adts);
  286   $displayCorrectAnswersQ = 1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions);
  287 
  288 
  289   my $displaySolutionsQ = 0;
  290   $displaySolutionsQ  = 1 if  $solutionsRequestedQ && ($currentTime > $adts);
  291   $displaySolutionsQ  = 1 if $solutionsRequestedQ && ($permissions == $Global::instructor_permissions);
  292 
  293   my $displayHintsQ = 0;
  294   $displayHintsQ  = 1 if  $hintsRequestedQ;
  295 
  296 #check if we need to save the updated version of the text
  297 my $problem_has_been_saved = '';
  298 if ( defined($inputs{'action'}) &&
  299      ( $inputs{'action'} eq 'Save updated version' ) &&
  300      ($permissions == $Global::instructor_permissions) &&
  301      defined($inputs{'source'})  ) {
  302     my $temp_source = decodeSource($inputs{'source'});
  303     $temp_source=~ s/\r\n/\n/g;
  304   #$temp_source = $cgi -> unescape( $temp_source );
  305   saveProblem($temp_source, $probFileName);
  306   $problem_has_been_saved = "<H4>Current version of the problem ${templateDirectory}$probFileName has been saved.</H4>
  307     <b>The original version has been appended to the file ${templateDirectory}$probFileName.bak . </b><br />";
  308 
  309   undef($inputs{'source'});   # make sure that we read input from the saved version
  310 }
  311 
  312 #check if we need to save the updated version of the text as a new problem
  313 
  314 if ( defined($inputs{'action'}) &&
  315      ( $inputs{'action'} eq 'Save as' ) &&
  316      ($permissions == $Global::instructor_permissions) &&
  317      defined($inputs{'source'})  ) {
  318     my $temp_source = decodeSource( $inputs{'source'} );
  319 
  320     $temp_source=~ s/\r\n/\n/g;
  321   #$temp_source = $cgi -> unescape( $temp_source );
  322     my $new_file_name = $inputs{'new file name'};
  323   saveNewProblem($temp_source, $new_file_name);
  324   $problem_has_been_saved = "<H4>The file ${templateDirectory}$new_file_name  has been saved.</H4>
  325     <b>The new problem must be added to the set definition file and the set must be rebuilt before the new problem
  326     will be displayed as part of the regular set.</b><br />";
  327 }
  328 
  329 
  330 # get the text source of the problem
  331 
  332 # first determine whether to load the source (and seed) from the calling HTML form or from the disk
  333  my $readSourceFromHTMLQ =0;
  334  $readSourceFromHTMLQ = 1 if (                            # load source from HTML if these conditions are met:
  335                             ($permissions == $Global::instructor_permissions ||   # only instructors can modify the source
  336                              ($User eq "practice666" )) &&              # practice666 can generate source
  337               defined($inputs{'source'})  &&              # there is a source field in the form
  338               defined($inputs{'seed'})    &&              # you need a seed field as well
  339               defined($inputs{'readSourceFromHTMLQ'}) &&
  340               $inputs{'readSourceFromHTMLQ'} == 1           # and the calling form asks that its source be read
  341               );
  342 
  343  # Over ride button forces reading the source from the disk.
  344    if (defined($inputs{'action'}) and $inputs{'action'} eq 'Read problem from disk') {
  345      $readSourceFromHTMLQ = 0;
  346      $inputs{refreshCachedImages} = 1;   # force the Latex2HTML rendering to be redone
  347    }
  348 
  349  # Determine whether to insert the source into the outgoing form.
  350  my $insertSourceIntoFormQ = 0;
  351  $insertSourceIntoFormQ = 1 if (                            # insert the source field into forms only if these conditions are met:
  352               ($permissions == $Global::instructor_permissions) ||    # only instructors can modify the source
  353                  ($User eq "practice666" )                          # practice666 can also
  354               );
  355 
  356 # Now lets get the source and the seed.
  357     my $source;
  358     my $seed;
  359     if ( $readSourceFromHTMLQ  )  {
  360 #   $source = $inputs{'source'};
  361     $source = decodeSource($inputs{'source'});
  362 #     if ( defined($inputs{'source_encoded_using'}) ) {  # the source has been encoded and we need to decode it first
  363 #       if ( $inputs{'source_encoded_using'} eq 'base64_encode' )  {
  364 #         $source = decode_base64($source);
  365 #       }
  366 #       elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) {
  367 #         $source = $cgi -> unescape($source);
  368 #       }
  369 #       elsif ( $inputs{'source_encoded_using'} eq 'none'  )    {
  370 #         # no action needed
  371 #
  372 #       }
  373 #       elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns'  )    {
  374 #         $source =~s/&#010;/\n/g;  warn "uncoding escaped returns";
  375 #         $source =~s/\r\n/\n/g;
  376 #       }
  377 #       else {
  378 #         warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}";
  379 #       }
  380 #      }
  381       ##substitute carriage return with a newline
  382       ##otherwise EndOfText construction does not work
  383       ##browsers always have \r\n at the end of the line
  384         $source=~ s/\r\n/\n/g;
  385 
  386         # get seed from the appropriate place
  387         $seed = $inputs{'seed'};
  388     }
  389   elsif ($probFileName eq '') {
  390     $probFileName = "New File";
  391     $source = '';
  392     $seed ="11111";  # perhaps we can pick a better initial value for the seed.
  393   }
  394   else {
  395     if (-e "${templateDirectory}$probFileName" ) {
  396       #print "|$probFileName|<BR>";
  397       unless (-r "${templateDirectory}$probFileName") {
  398         wwerror($0, "Can't read ${templateDirectory}$probFileName");
  399       }
  400       open(PROB,"<${templateDirectory}$probFileName");
  401       $source = join('',<PROB>);
  402       close(PROB);
  403     }
  404     else {
  405       wwerror($0, "<H4>Error: The problem ${templateDirectory}$probFileName could not be found!</H4>");
  406     }
  407       $seed = &getProblemSeed($probNum, $psvn);
  408   }
  409 
  410 ##################################################
  411 # begin processing problem
  412 ##################################################
  413 
  414 
  415   my %envir=defineProblemEnvir($mode,$probNum,$psvn,$Course);
  416 # my @envir_array = %envir;
  417 # warn "@envir_array";    #DEBUG
  418   ##Need to check what language is used here
  419   #this comes from createDisplayedProblem in displayMacros
  420   my @printlines;
  421 
  422   #this is no longer used     DME 6/15/2000
  423   #my $refSubmittedAnswers=$envir{'refSubmittedAnswers'};
  424 
  425   # require "${courseScriptsDirectory}PG_module_list.pl";
  426   # (Modules are defined by this require statement found near the top of this file, outside the loop.)
  427   my $pt = new PGtranslator;  #pt stands for problem translator;
  428   $pt -> evaluate_modules( @{main::modules_to_evaluate});
  429   $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded});
  430   # The variables in the two preceding lines are  defined in PG_module_list.pl at Indiana.
  431 
  432   my $imgen="";
  433   my $webworkTempDir = $Global::webworkTempDirectory;  # to prevent warnings.
  434   if($mode eq 'HTML_dpng') {
  435 #     $imgen = new ImageGenerator;
  436 #     $imgen->initialize(\%envir);
  437     $imgen = new ImageGenerator(
  438       tempDir    => "$Global::webworkTempDirectory",
  439       dir      => $envir{tempDirectory},
  440       url      => $envir{tempURL},
  441       basename   => "equation-$envir{psvn}.$envir{probNum}.$envir{problemSeed}",
  442     latex    => $envir{externalLaTeXPath},
  443     dvipng     => $envir{externalDvipngPath},
  444     );
  445   }
  446   $envir{imagegen} = $imgen;
  447 
  448   $pt ->  environment(\%envir);
  449   $pt ->  initialize();
  450   $pt ->  set_mask();
  451   $pt ->  source_string($source);
  452   $pt ->  unrestricted_load("${courseScriptsDirectory}PG.pl");
  453   $pt ->  unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl");
  454   $pt ->  rf_safety_filter( \&safetyFilter);   # install blank safety filter
  455   $pt ->  translate();
  456 
  457 #   Code for logging students's answers to allow inspection of answer history.
  458     logCourseData($User,$setNumber,$probNum,\%inputs,$pt)  if ($answers_submitted);
  459 #     &&
  460 #             ($permissions != $Global::instructor_permissions) and
  461 #             ($permissions != $Global::TA_permissions));
  462 
  463 # $Global::logCourseAnswerData must be 1 in order to activate this subroutine.
  464 #   End student answer logging code.
  465 
  466 
  467   # dereference some flags returned by createPGtext;
  468         if ( defined( $pt ->rh_flags ) ) {
  469           $main::showPartialCorrectAnswers = $pt ->rh_flags->{'showPartialCorrectAnswers'};
  470           $main::recordSubmittedAnswers = $pt ->rh_flags->{'recordSubmittedAnswers'};
  471           $main::refreshCachedImages = $pt ->rh_flags->{'refreshCachedImages'};
  472         }
  473 
  474   if($mode eq 'HTML_dpng') {
  475     my $forceRefresh=0;
  476     if($inputs{'refreshCachedImages'} || $main::refreshCachedImages
  477        || $displaySolutionsQ || $displayHintsQ) {
  478       $forceRefresh=1;
  479     }
  480     $imgen->render('refresh'=>$forceRefresh); # Can force new images
  481   }
  482   # massage problem text if necessary.
  483   if($mode eq "HTML" || $mode eq 'HTML_tth' || $mode eq 'HTML_dpng' || $mode eq 'HTML_img' ||
  484      $pt ->rh_flags->{'error_flag'}) {
  485     @printlines=@{ $pt->ra_text() };
  486   }
  487   elsif ($mode eq 'Latex2HTML') {
  488       my %PG_flags = %{ $pt->rh_flags() };
  489       $PG_flags{'refreshCachedImages'} = $inputs{'refreshCachedImages'};
  490       $PG_flags{'refreshCachedImages'} = 1 if $main::refreshCachedImages;
  491       $PG_flags{'refreshCachedImages'} = 1 if $displaySolutionsQ;
  492       $PG_flags{'refreshCachedImages'} = 1 if $displayHintsQ;
  493     @printlines = &createDisplayedProblem($setNumber,$probNum,$psvn,$pt->ra_text(),\%PG_flags );
  494 
  495     @printlines = &l2h_sticky_answers($envir{'inputs_ref'}, \@printlines, $pt->rh_flags() );
  496 
  497 #   @printlines = &l2h_update_keys($envir{'sessionKey'}, \@printlines);
  498     } elsif ($mode eq "TeX") {   #TEMPORARY KLUDGE
  499       @printlines = @{$pt->ra_text() };
  500 
  501   } else {
  502       @printlines="$0: Error:  Mode |$mode| is not HTML, HTML_tth, HTML_dpng or Latex2HTML.";
  503     }
  504 
  505 
  506 
  507 # Determine the problem_state
  508 
  509 
  510 # Determine the recorded score
  511   my $recorded_score = getProblemStatus($probNum, $psvn);
  512 
  513 
  514 # Initialize the variables reporting the answers
  515   my $rh_answer_results = {};
  516   my $rh_problem_result = {};
  517   my $rh_problem_state = {};
  518   my $record_problem_message = '';
  519   my $answer_line_text = '';
  520   my $preview_text = '';
  521   my $expected_answer_count = keys( %{ $pt -> rh_correct_answers() } ); # count the number of correct answers
  522 
  523 # Determine which problem grader to use
  524   #$pt->rf_problem_grader($pt->rf_std_problem_grader);  #this is the default
  525     my $problem_grader_to_use = $pt->rh_flags->{PROBLEM_GRADER_TO_USE};
  526 
  527     if ( defined($problem_grader_to_use) and $problem_grader_to_use   ) {  # if defined and non-empty
  528       if ($problem_grader_to_use eq 'std_problem_grader') {
  529         # Reset problem grader to standard problem grader.
  530         $pt->rf_problem_grader($pt->rf_std_problem_grader);
  531       }
  532     elsif ($problem_grader_to_use eq 'avg_problem_grader') {
  533         # Reset problem grader to average problem grader.
  534             $pt->rf_problem_grader($pt->rf_avg_problem_grader);
  535       }
  536     elsif (ref($problem_grader_to_use) eq 'CODE') {
  537           # Set problem grader to instructor defined problem grader -- use cautiously.
  538         $pt->rf_problem_grader($problem_grader_to_use)
  539       }
  540     else {
  541           warn "Error:  Could not understand problem grader flag $problem_grader_to_use";
  542         #this is the default set by the translator and used if the flag is not understood
  543         #$pt->rf_problem_grader($pt->rf_std_problem_grader);
  544       }
  545 
  546     }
  547   else {#this is the default set by the translator and used if no flag is set.
  548       #$pt->rf_problem_grader($pt->rf_std_problem_grader);   }
  549     }
  550 
  551 # creates and stores a hash of answer results: $rh_answer_results
  552   if  ($answers_submitted == 1) {
  553     $pt -> process_answers(\%inputs);
  554   }
  555   else {
  556     $pt -> process_answers({});   ## pass a ref to an empty hash to process_answers
  557                     ## so that problem graders messages will be
  558                     ## output even when looking at a problem the
  559                     ## first time
  560   }
  561       ####################################################################
  562       # If preview mode has been selected, build the preview page and exit
  563       ####################################################################
  564 
  565     if  (($preview_mode ==1) and ($answers_submitted ==1)) {
  566 
  567     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  568                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  569 
  570     $preview_text = preview_answers(
  571                                         $pt->rh_evaluated_answers,
  572                                         $rh_problem_result,
  573                                          {
  574                                           ANSWER_ENTRY_ORDER      => $ra_answer_entry_order,
  575                                           ANSWER_PREFIX               => ($pt->{PG_FLAGS_REF}->{ANSWER_PREFIX}) ? $pt->{PG_FLAGS_REF}->{ANSWER_PREFIX} :'AnSwEr'
  576 
  577                                          }
  578                                         );
  579     build_preview_page();
  580     exit(0);
  581   }
  582 
  583 
  584 
  585       ####################################################################
  586       # set the problem state.
  587       # Record the grade and report the answer results
  588       ####################################################################
  589 
  590 
  591     $pt->rh_problem_state({ recorded_score      => $recorded_score ,
  592                 num_of_correct_ans    => &getProblemNumOfCorrectAns($probNum,$psvn) ,
  593                 num_of_incorrect_ans  => &getProblemNumOfIncorrectAns($probNum,$psvn)
  594               } );
  595 
  596     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  597                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  598 
  599     ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted,
  600                                                                  ANSWER_ENTRY_ORDER => $ra_answer_entry_order
  601                                                                );       # grades the problem.
  602 # If there was a syntax error, do not report partial correct answers:
  603    $main::showPartialCorrectAnswers = 0 if defined($rh_problem_result->{show_partial_correct_answers})
  604                                            and  $rh_problem_result->{show_partial_correct_answers} == 0;
  605 
  606   if  ($answers_submitted == 1) {
  607 
  608     # Store the answers an an encoded form in the database
  609 
  610     my $saved_submitted_answers_string = encode_submitted_answers($ra_answer_entry_order);
  611 
  612 
  613 
  614     # If an answer form has been submitted format answer message,
  615       # record problem status and format the record_problem_message
  616       # check if before due date and number of incorrect attempts is
  617       # below limit (if any). If so, record answer
  618 
  619     $record_problem_message = '';
  620     my $attemptsRemaining =  getProblemMaxNumOfIncorrectAttemps($probNum,$psvn)
  621                            - getProblemNumOfCorrectAns($probNum,$psvn)
  622                            - getProblemNumOfIncorrectAns($probNum,$psvn);
  623 
  624     ## Professors and TA's are allowed to submit answers without results being recorded
  625     my $doNotRecordAnswers = 0;
  626     if (($permissions == $Global::instructor_permissions) or ($permissions == $Global::TA_permissions)) {
  627       $doNotRecordAnswers = 1 if $doNotRecordAnsRequestedQ;
  628     }
  629 
  630       if ( (not $doNotRecordAnswers) and ($currentTime<=$ddts) and
  631           ( ( getProblemMaxNumOfIncorrectAttemps($probNum,$psvn) < 0 ) or ( $attemptsRemaining >= 1 )) ) {
  632       &save_problem_state($saved_submitted_answers_string,$rh_problem_state,$probNum,$inputs{'user'},$psvn);
  633     }
  634     else {
  635       if ($doNotRecordAnswers){
  636         $record_problem_message = "<STRONG>Note: Answer not recorded.</STRONG><br />";
  637       }
  638       elsif ($currentTime>$ddts){
  639         $record_problem_message = "<STRONG>Note: Answer not recorded - it is after the due date.</STRONG><br />";
  640       }
  641       else {
  642         $record_problem_message = "<STRONG>Note: Answer not recorded - You have already attempted this problem the maximum allowed number of times.</STRONG><br />";
  643       }
  644     }
  645       ####################################################################
  646       #  Format the answer section of the displayed problem
  647       ####################################################################
  648     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  649                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  650 
  651     $answer_line_text = display_answers(
  652                                         $pt->rh_evaluated_answers,
  653                                         $rh_problem_result,
  654                                          {  displayCorrectAnswersQ    => $displayCorrectAnswersQ,
  655                                           showPartialCorrectAnswers   => $main::showPartialCorrectAnswers,
  656                                           ANSWER_ENTRY_ORDER      => $ra_answer_entry_order,
  657                                           ANSWER_PREFIX               => ($pt->{PG_FLAGS_REF}->{ANSWER_PREFIX}) ? $pt->{PG_FLAGS_REF}->{ANSWER_PREFIX} :'AnSwEr'
  658                                          }
  659                                         );
  660 
  661 
  662 
  663 
  664 
  665 }
  666 
  667 
  668       ####################################################################
  669       ###         format problem status message     ###
  670       ####################################################################
  671 my $status = getProblemStatus($probNum,$psvn);
  672 my $attempted = getProblemAttempted($probNum,$psvn);
  673 
  674 my $problemStatusMessage = '';
  675 if ( !$attempted) {
  676   $problemStatusMessage   = "Our records show problem $probNum of set $setNumber_display has not been attempted.";  # default value
  677 }
  678 elsif ($status >= 0 and $status <=1)  {
  679     my $percentCorr = int(100*$status+.5);
  680     my $problemValue = &getProblemValue($probNum,$psvn);
  681     my $score = round_score($status*$problemValue);
  682     my $pts = 'points';
  683     if ($score == 1) {$pts = 'point';}
  684   $problemStatusMessage     = "Our records show problem $probNum of set $setNumber_display has a score of ${percentCorr}\%  ($score $pts).";
  685 }
  686 else {
  687   $problemStatusMessage   = "Our records show problem $probNum of set $setNumber_display has an unknown status.";
  688 }
  689 ########## end format problem status message #######
  690 
  691 ##########################################################
  692 ###### format messages about number of attempts remaining.
  693 ##########################################################
  694   my  $maxNumOfIncorrectAttempts  = &getProblemMaxNumOfIncorrectAttemps($probNum,$psvn);
  695   my  $numOfCorrectAns    = &getProblemNumOfCorrectAns($probNum,$psvn);
  696   my  $numOfIncorrectAns    = &getProblemNumOfIncorrectAns($probNum,$psvn);
  697   my  $numOfAttempts    = $numOfCorrectAns + $numOfIncorrectAns;
  698   my  $maxAttemptNote   = "";
  699   my  $attemptsRemaining = $maxNumOfIncorrectAttempts -$numOfAttempts;
  700 
  701 
  702 #
  703 
  704 
  705 
  706 #################################################
  707 #  begin printing the HTML text     #
  708 #################################################
  709     my $Edited = '';
  710     my $bg_color = undef;
  711     $bg_color = $Global::bg_color if  $Global::WARNINGS   ;
  712   $Edited = "EDITED " if $readSourceFromHTMLQ;
  713   $Edited = "NEW FILE " if (defined($inputs{'action'}) and ($inputs{'action'} eq 'Save as'));
  714   print &processProblem_htmlTOP("${Edited}Problem $probNum",
  715                                   ${ $pt->r_header },
  716                                  $bg_color    # background color
  717                                 );  #see subroutines at the bottom of this file
  718                                     #this allows the use of a small gif for the webwork logo
  719                                     #and takes up less screen real estate.
  720 
  721   #text in case the problem has been saved
  722   print $problem_has_been_saved;
  723 
  724 ################print Navigation Bar ###########
  725 
  726   print &format_navigation_bar($previousProbNum,$nextProbNum,$numberOfProblems);
  727 
  728 ##############print warning about setting the Encoding properly###############
  729      my $browser = $cgi -> user_agent();
  730      # browser contains a string such as: |Mozilla/4.07 (Macintosh; I; PPC, Nav) |
  731      $browser =~ m|Mozilla/([\d.]+)|;
  732      my $version = $1;
  733        print( qq!<FONT COLOR="#ff0000"><p /> <B>WARNING:</B> Versions of Netscape before 4.0 running on a Macintosh computer
  734                will not be able to display all the math symbols correctly in formatted text mode. Square root and integral
  735                signs may disappear entirely. Please use
  736                another mode.
  737                <p>
  738                 When using Netscape 4 or greater on a Macintosh computer, set your fonts by choosing
  739                <br />View --&gt;Encoding--&gt;Western(MacRoman) from the menu.  This will make square root signs
  740                and integral signs display correctly.
  741                </p></FONT>!) if ($mode eq 'HTML_tth' && $browser =~/Macintosh/ && $version < "4");
  742 
  743 ###############begin Answer Section###########
  744 
  745 if ($answers_submitted ==1) {
  746 # print "<br />Problem grader message is:<br /> " , $rh_problem_result->{msg}    if defined($rh_problem_result->{msg});
  747 
  748   print $answer_line_text,
  749           $record_problem_message;
  750 
  751   print(  "<br />Problem grader errors are " . $rh_problem_result->{errors} ) if $rh_problem_result->{errors};
  752 }
  753 
  754     print "\r\n<!-- BEGIN_PG_PROBLEM_FORM -->\r\n";
  755 
  756 ################begin Problem Text ###########
  757   print "\n",$cgi -> startform(-action=>"$Global::processProblem_CGI"),"\n\n";
  758   print "\r\n<!-- BEGIN_PG_PROBLEM_TEXT -->\r\n";
  759   print @printlines;
  760   print "\r\n<!-- END_PG_PROBLEM_TEXT -->\r\n";
  761   print '<p />';
  762 
  763 
  764 ################print Submit button and display check boxes###########
  765 
  766   print '<EM><B>Note:</B>' . $pt->rh_problem_result->{msg} . '</EM><p />' if ($pt->rh_problem_result->{msg});
  767   my  $s      = '';
  768   if( $expected_answer_count > 1) {
  769     $s = 's'; #makes the Answer button plural (purely cosmetic)
  770   }
  771 
  772 # Decide whether the Do not save answers is visible
  773   if (($User ne &getStudentLogin($psvn)) and
  774     ( ($permissions == $Global::instructor_permissions) or ($permissions == $Global::TA_permissions) ) ) {
  775 
  776     print $cgi -> checkbox(-name=>'doNotRecordAns',
  777             -value=>1,
  778             -label=>"Do Not Record Answer$s",
  779             -checked,
  780             -override => 1), "\n\t";
  781   } else {
  782     print $cgi -> hidden(-name=>'doNotRecordAns',
  783         -value => 0,override => 1), "\n\t";
  784   }
  785 
  786 # Decide whether the showHint line is visible
  787 
  788   if (
  789     defined($pt ->rh_flags->{'hintExists'})
  790     and ($pt ->rh_flags->{'hintExists'} ==1)
  791     and ($numOfAttempts >= $pt ->rh_flags->{'showHintLimit'})
  792   ) {
  793         print $cgi -> checkbox(-name=>'ShowHint',
  794             -value=>1,
  795             -label=>"Show Hint",
  796             -override => 1);
  797   } else {
  798     print $cgi -> hidden(-name=>'ShowHint', -value=>0, -override => 1), "\n\t";
  799   }
  800 
  801 
  802 
  803 # Decide whether the showAnswer line is visible
  804 
  805   if (defined($displayShowAnswerLineQ) and $displayShowAnswerLineQ) {
  806     print $cgi -> checkbox(-name=>'ShowAns',
  807             -value=>1,
  808             -label=>"Show Correct Answer$s",
  809             -override => 1), "\n\t";
  810   } else {
  811     print $cgi -> hidden(-name=>'ShowAns',
  812         -value => 0,-override => 1), "\n\t";
  813   }
  814 
  815 
  816 
  817 # Decide whether the showSolution line is visible
  818 
  819   if (defined($displayShowAnswerLineQ) and $displayShowAnswerLineQ and defined($pt ->rh_flags->{'solutionExists'}) and $pt ->rh_flags->{'solutionExists'} ==1) {
  820       print $cgi -> checkbox(-name=>'ShowSol',
  821             -value=>1,
  822             -label=>"Show Solution$s",
  823             -override => 1);
  824   } else {
  825     print $cgi -> hidden(-name=>'ShowSol',  -value=>0, -override => 1), "\n\t";
  826   }
  827 
  828 
  829 ## check to see if $numOfAttempts is approaching or at the limit
  830 ## $maxNumOfIncorrectAttempts. If so, put note by
  831 ## submit answer button (below)
  832 ##  $maxNumOfIncorrectAttempts = -1 means unlimited attempts
  833   my $plural = '';
  834   $plural = 's'   if $attemptsRemaining > 1;
  835 
  836   if(($maxNumOfIncorrectAttempts >= 0) and ($attemptsRemaining <= 0) and ($currentTime<=$ddts)) {
  837     $maxAttemptNote = " <EM>Note: You have already attempted this problem the
  838                            maximum allowed number of times.</EM>\n";
  839   }
  840   elsif (($maxNumOfIncorrectAttempts >= 0) and
  841          ($attemptsRemaining <= $Global::maxAttemptsWarningLevel) and
  842          ($currentTime<=$ddts)
  843         )  {
  844        $maxAttemptNote = " <B>Note: You are allowed only $attemptsRemaining more
  845                            attempt$plural at this problem.</B>\n";
  846 
  847   }
  848 
  849 ############# print hidden information about problem and set
  850 
  851   print $cgi -> hidden( -name => 'probNum', -value => $probNum ), "\n\t",
  852       $cgi -> hidden( -name => 'probSetKey', -value => $psvn ), "\n\t",
  853       $cgi->hidden( -name=>'show_old_answers', -value=>$show_old_answers), "\n\t",
  854       $cgi -> hidden( -name => 'answer_form_submitted', -value => 1 );   # alerts the problem to show answers.
  855 
  856   my $button_style = 'width: 12em';
  857   #sessionKeyInputs() in scripts/HTMLglue.pl
  858   print &sessionKeyInputs(\%inputs),
  859     "<br />",
  860     qq!$maxAttemptNote $dueDateNote $answerNote!,
  861     "<br />",
  862     $cgi -> submit(  -name => 'action',  -value=>"Submit Answer$s", -style=>$button_style),  # -onClick=>"submitProblem()" # this javaScript call caused problems on some older browsers -- removed temporarily while we find a fix
  863 
  864     "\n\t",
  865     $cgi -> submit(  -name => 'action',  -value=>"Preview Answer$s", -style=>$button_style),"\n\t";
  866     if ($mode ne 'TeX') { #TEMPORARY KLUDGE
  867     my $displayMode_hidden_inputs = displaySelectModeLine_string($mode);
  868     $displayMode_hidden_inputs =~ s/<BR>//g;  # remove returns to get one line display
  869     print "<br />$displayMode_hidden_inputs<br />";
  870   }
  871 
  872 # $source =~ s/([^\r])\n/$1\r\n/g;  # replace any bare \n by \r\n
  873 # $source =~ s/\n/&#010;/g;
  874 #   my $sourceAsHTMLEncodingMethod = 'escaped_returns';  # this makes iCab work properly
  875    my $sourceAsHTMLEncodingMethod = 'base64_encode';
  876    my $sourceAsHTML = encode_base64($source);
  877    if ($readSourceFromHTMLQ ) {   # reading from source is a sticky option.
  878     print $cgi -> hidden(-name  => 'readSourceFromHTMLQ', -value => "1" );
  879     print "<br />\r\n",
  880           $cgi -> hidden(-name  =>  'source_encoded_using',   -value  =>  $sourceAsHTMLEncodingMethod, -override => 1),
  881           "<br />\r\n",
  882           $cgi -> hidden(-name  =>  'source',   -value  =>  $sourceAsHTML, -override => 1),
  883           "<br />\r\n",
  884           $cgi -> hidden(-name  => 'seed',    -value => "$seed" );
  885   }
  886   print "\r\n<!-- BEGIN_PG_READ_FROM_DISK -->\r\n";
  887   if ($readSourceFromHTMLQ ) {
  888     print $cgi -> submit(-name  =>  'action',   -value  => 'Read problem from disk');  # this allows an override about reading from the HTML source
  889 
  890                 # This ensures that we are using the current (possibly changed)
  891                 # seed even if we are resubmitting answers to a question.
  892    }
  893    print $cgi -> endform();
  894    print "\r\n<!-- END_PG_PROBLEM_FORM -->\r\n";
  895 #############################################################
  896 ##  End of main form, containing the problem and answer rules
  897 #############################################################
  898 ##print the form to get the editor in a different window if the
  899 ##person using WeBWorK has professor permissions
  900 
  901 #############################################################
  902 ##  Show editor form
  903 #############################################################
  904 
  905 if ($insertSourceIntoFormQ) {
  906   print "\n\n<!--Source is encoded for more security and to avoid problems with the " .
  907       "conversion from HTML to straight text-->\n";
  908   print "<hr><TABLE ><TR>\n<TD>";
  909   print $cgi -> startform(-action=>"$Global::problemEditor_CGI",
  910     -target=>'editor'),
  911     &sessionKeyInputs(\%inputs),
  912     $cgi -> hidden( -name =>'source_encoded_using',   -value => $sourceAsHTMLEncodingMethod, -override =>1), "\r\n",
  913     $cgi -> hidden( -name =>'source',       -value  =>  $sourceAsHTML, -override =>1), "\r\n",
  914     $cgi -> submit( -name =>'action',       -value  =>  "Show Editor", -style=> $button_style), "\r\n",
  915     $cgi -> hidden( -name =>'probSetKey',     -value  =>  $psvn), "\r\n",
  916     $cgi -> hidden( -name =>'probNum',      -value  =>  $probNum), "\n",
  917     $cgi -> hidden( -name =>'Mode',       -value  =>  $mode, -override =>1), "\r\n",
  918     $cgi -> hidden( -name =>'seed',       -value  =>  $seed, -override =>1), "\r\n",
  919     $cgi -> endform();
  920 
  921   #   Code for logging students's answers to allow inspection of answer history.
  922   if ($Global::logCourseAnswerData) {
  923       print "</TD>\n<TD>";
  924       print $cgi->startform(-action=>"$Global::showPastAnswers_CGI", -target=>'information'),
  925         &sessionKeyInputs(\%inputs),
  926         $cgi->hidden(-name => 'probNum', -value=>$probNum), "\n",
  927         $cgi->hidden(-name => 'setNum',  -value=>$setNumber), "\n",
  928         $cgi->hidden(-name => 'User',    -value=>getStudentLogin($psvn)), "\n",
  929         $cgi->submit(-name => 'action',  -value=>'Show Past Answers', -style=> $button_style), "\n",
  930         $cgi->endform();
  931       print "</TD></TR>\n</TABLE>\n";
  932   }
  933   #   End code for logging students's answers
  934 }
  935 
  936 
  937 
  938 #############################################################
  939 ##  End "Show editor" form
  940 ################################################################
  941   print &htmlBOTTOM($0, \%inputs, 'processProblemHelp.html');
  942 
  943   $main::Course = $Course;
  944   $main::User   = $User;
  945 
  946   exit(0);
  947 
  948 
  949 
  950 
  951 ### DONE ###
  952 ############################################
  953 ## SUBROUTINES specific to processProblem.pl
  954 # this normally loads in macro files -- but for the demo this is done by hand.
  955 
  956 sub save_problem_state {
  957     my ($saved_submitted_answers_string,$rh_problem_state, $num,$user, $psvn)=@_;
  958 
  959     # define constants
  960     my  $DELIM = $Global::delim;
  961     my  $scoreFilePrefix = $Global::scoreFilePrefix;
  962     my  $dash = $Global::dash;
  963     my $numericalID = $Global::numericalGroupID;
  964        $numericalID = $Global::numericalGroupID;
  965     #
  966 
  967     #&attachProbSetRecord($psvn); # (not needed);
  968     my($setNumber)=&getSetNumber($psvn);
  969     my ($scoreFileName)="${databaseDirectory}$scoreFilePrefix$setNumber$dash${psvn}.sco";
  970     unless (-e $scoreFileName) {
  971         &createFile($scoreFileName, $Global::sco_files_permission, $numericalID);
  972     }
  973     open(TEMP_FILE,">>$scoreFileName") || print "Couldn't record answer in $scoreFileName";
  974     my $time = &formatDateAndTime(time);    # add time stamp
  975 
  976     print TEMP_FILE "$num  $DELIM  " . $rh_problem_state->{recorded_score} . " $DELIM " . $rh_problem_state->{num_of_correct_ans} . " $DELIM" . $rh_problem_state->{num_of_incorrect_ans} . " $DELIM $user $DELIM $time\n";
  977     close(TEMP_FILE);
  978 
  979   putProblemStudentAnswer($saved_submitted_answers_string,$num,$psvn) if $main::recordSubmittedAnswers;
  980 
  981     &putProblemNumOfCorrectAns($rh_problem_state->{num_of_correct_ans},$num,$psvn) if defined($rh_problem_state->{num_of_correct_ans}) ;
  982     &putProblemNumOfIncorrectAns($rh_problem_state->{num_of_incorrect_ans},$num,$psvn) if defined($rh_problem_state->{num_of_incorrect_ans});
  983 
  984     &putProblemAttempted(1,$num,$psvn);  ## save_problem_state() is run only if the submit button has been
  985                                          ## hit so that means the problem has been attempted
  986 
  987     if ( defined($rh_problem_state->{recorded_score})  ) {
  988       &putProblemStatus( $rh_problem_state->{recorded_score} ,$num,$psvn);
  989     } else {
  990       warn "Error no recorded_score has been calculated for this problem.";
  991     }
  992 
  993     #my %temp1 = getProbSetRecord($psvn);
  994     #warn "number of correct attempts is pst$num ", $temp1{"pst$num"};
  995     &detachProbSetRecord($psvn);
  996 };
  997 
  998 
  999 sub hackerError  { ## prints hacker error message
 1000 
 1001 
 1002     my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". $cgi -> remote_host()."\n";
 1003     $msg .= $cgi -> query_string();
 1004 #    &Global::log_error('hacker error', $cgi -> query_string);
 1005     &Global::log_error('hacker error', $msg);   ## log attempt
 1006 
 1007     ## notify by email
 1008 
 1009     my $toAdd = $Global::feedbackAddress;
 1010 
 1011     my $emailMsg = "To: $toAdd
 1012 Subject: Attempt to hack into WeBWorK
 1013 
 1014 Here are the details on the attempt to hack into weBWorK:\n
 1015 $msg
 1016 \n";
 1017 
 1018   my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20);
 1019   $smtp->mail($Global::webmaster);
 1020   $smtp->recipient($Global::feedbackAddress);
 1021   $smtp->data($msg);
 1022   $smtp->quit;
 1023 
 1024 
 1025 #    my $SENDMAIL = $Global::SENDMAIL;
 1026 #    open (MAIL,"|$SENDMAIL");
 1027 #    print MAIL "$emailMsg";
 1028 #    close (MAIL);
 1029 
 1030     print   &htmlTOP("Hacker Error"),
 1031                         "<H2>Error:Please do not try to hack into WeBWorK!</H2>",
 1032                         $cgi -> startform(-action=>"${Global::welcomeAction_CGI}"),
 1033                         $cgi ->p ,
 1034                         &sessionKeyInputs(\%inputs),
 1035                         $cgi -> hidden(-name=>'local_psvns', -value=>$psvn),
 1036                         $cgi -> hidden(-name=>'action', -value=>'Do_problem_set'),
 1037                         $cgi -> endform(),
 1038                         &htmlBOTTOM($0, \%inputs);
 1039 }
 1040 
 1041 sub selectionError  ## prints error message
 1042   {
 1043   print   &htmlTOP("Error: need to select problem"),
 1044       "<H2>Error: You must select a problem!</H2>",
 1045       $cgi -> startform(-action=>"${Global::welcomeAction_CGI}"),
 1046       &sessionKeyInputs(\%inputs),
 1047                         $cgi -> hidden(-name=>'local_psvns', -value=>$psvn),
 1048                         $cgi -> hidden(-name=>'action', -value=>'Do_problem_set'),
 1049                         $cgi -> submit(-value=>"Return to Problem Set"),
 1050                         $cgi -> endform(),
 1051       &htmlBOTTOM($0, \%inputs);
 1052   }
 1053 
 1054 
 1055 ###################################################
 1056 sub decodeSource {
 1057   my $source = shift;
 1058   warn "Only source embedded in HTML needs to be decoded" unless defined($inputs{'source'});
 1059   if ( defined($inputs{'source_encoded_using'}) ) {  # the source has been encoded and we need to decode it first
 1060     if ( $inputs{'source_encoded_using'} eq 'base64_encode' )  {
 1061       $source = decode_base64($source);
 1062     }
 1063     elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) {
 1064       $source = $cgi -> unescape($source);
 1065     }
 1066     elsif ( $inputs{'source_encoded_using'} eq 'none'  )    {
 1067       # no action needed
 1068     }
 1069     elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns'  )    {
 1070       $source =~s/&#010;/\n/g;  warn "uncoding escaped returns";
 1071       $source =~s/\r\n/\n/g;
 1072     }
 1073     else {
 1074       warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}";
 1075     }
 1076    }
 1077      $source;
 1078 }
 1079 
 1080 
 1081 sub safetyFilter {
 1082 #   my $answer = shift;  # accepts one answer and checks it
 1083 #   $answer = '' unless defined $answer;
 1084 #   my ($errorno, $answerIsCorrectQ);
 1085 #   $answer =~ tr/\000-\037/ /;
 1086 #   #### Return if answer field is empty ########
 1087 #   unless ($answer =~ /\S/) {
 1088 #     $errorno =1; # "No answer was submitted.";
 1089 #
 1090 #     return ($answer,$errorno);
 1091 #     }
 1092 #   ######### replace ^ with **    (for exponentiation)
 1093 #   #   $answer =~ s/\^/**/g;
 1094 #   ######### Return if  forbidden characters are found
 1095 #   unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)\[\]\{\}]+$/ )  {
 1096 #     $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)\[\]\{\}]/#/c;
 1097 #     $errorno = 2; #  "There are forbidden characters in your answer: $submittedAnswer<BR>";
 1098 #
 1099 #     return ($answer,$errorno);
 1100 #     }
 1101 #
 1102   my $answer = shift @_;
 1103   my $errorno = 0;
 1104 
 1105   return($answer, $errorno);
 1106 }
 1107 
 1108 
 1109 
 1110 sub processProblem_htmlTOP {
 1111       my ($title, $header_text, $bg_url) = @_;
 1112 
 1113       my $bg_color = $bg_url || $Global::bg_color;
 1114 
 1115       $header_text = '' unless defined($header_text);
 1116 #       my $out =  header(-type=>'text/html');
 1117 #     $out .= start_html(-'title'=>$title,
 1118 #                     -script=>$header_text,
 1119 #         -background=>$background_url);
 1120     my $test = $cgi -> user_agent();
 1121 #       determine the proper charset
 1122     my $charset_definition;
 1123     my $browser = $cgi -> user_agent();
 1124     # browser contains a string such as: |Mozilla/4.07 (Macintosh; I; PPC, Nav) |
 1125     if ($browser =~/Macintosh/  or $browser =~/Mac_PowerPC/) {  # do we need to know the mode in order to set this properly??
 1126       $charset_definition = q{charset="x-mac-roman";};
 1127     } else {
 1128       $charset_definition =q{};
 1129     }
 1130 
 1131         my $out = <<ENDhtmlTOP;
 1132 content-type: text/html; $charset_definition
 1133 
 1134 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
 1135 <HTML>
 1136 <HEAD>
 1137 <TITLE>$title</TITLE>
 1138 <style>
 1139   .parsehilight { background: yellow }
 1140 </style>
 1141 $header_text
 1142 </HEAD>
 1143 <BODY BGCOLOR="$bg_color"><p />
 1144 ENDhtmlTOP
 1145     $out;
 1146 }
 1147 
 1148 sub preview_answers_htmlTOP {
 1149       my ($title, $header_text, $bg_url) = @_;
 1150 
 1151       my $bg_color = $bg_url || $Global::bg_color;
 1152 
 1153       $header_text = '' unless defined($header_text);
 1154 
 1155         my $out = <<ENDhtmlTOP;
 1156 content-type: text/html;
 1157 
 1158 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
 1159 <HTML>
 1160 <HEAD>
 1161 <TITLE>$title</TITLE>
 1162 <style>
 1163   .parsehilight { background: yellow }
 1164 </style>
 1165 $header_text
 1166 </HEAD>
 1167 <BODY BGCOLOR="$bg_color"><p />
 1168 ENDhtmlTOP
 1169     $out;
 1170 }
 1171 
 1172 
 1173 
 1174 sub format_navigation_bar {
 1175 my ($previousProbNum, $nextProbNum,$numberOfProblems) = @_;
 1176 
 1177 ## first set up the navigation button forms
 1178 
 1179   my $prev_prob_form = '';
 1180   unless($previousProbNum <= 0) {
 1181     $prev_prob_form = join("\n",
 1182       $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1183       $cgi->input({-type=>'IMAGE', -src=>"$Global::previousImgUrl", -alt=>'<--Previous Problem'}),
 1184       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1185       $cgi->hidden(-name=>'probNum', -value=>"$previousProbNum", -override=>1),
 1186       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1187       $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1188       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1189       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1190       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1191       $cgi->endform()
 1192     );
 1193   }
 1194 
 1195   my $prob_list_form = join("\n",
 1196     $cgi->startform(-method=>'POST', -action=>"$Global::welcomeAction_CGI"),
 1197       $cgi->input({-type=>'IMAGE', -src=>"$Global::problistImgUrl", -alt=>'Problem List'}),
 1198     $cgi->hidden(-name=>'local_psvns', -value=>"$inputs{probSetKey}"),
 1199       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1200       $cgi->hidden(-name=>'action', -value=>"Do_problem_set",-override=>1),
 1201       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1202       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1203       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1204       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1205       $cgi->endform()
 1206     );
 1207 
 1208 
 1209   my $next_prob_form = '';
 1210   unless($nextProbNum > $numberOfProblems) {
 1211     $next_prob_form = join("\n",
 1212       $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1213       $cgi->input({-type=>'IMAGE', -src=>"$Global::nextImgUrl", -alt=>'Next Problem-->'}),
 1214       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1215       $cgi->hidden(-name=>'probNum', -value=>"$nextProbNum", -override=>1),
 1216       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1217       $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1218       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1219       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1220       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1221       $cgi->endform()
 1222     );
 1223   }
 1224 
 1225 ## next set up the inner table
 1226   my $inner_table =
 1227     $cgi->table(
 1228       $cgi->Tr(
 1229         $cgi->td({-align=>'CENTER', -valign=>'MIDDLE'},[$prev_prob_form, $prob_list_form, $next_prob_form])
 1230     )
 1231     );
 1232 
 1233 ## finally set up the main table
 1234   my $navigation_bar =
 1235     $cgi->table({-border=>0,-width=>'100%'},
 1236       $cgi->Tr({-align=>'CENTER', -valign=>'TOP'},
 1237         $cgi->td({-align=>'LEFT', -valign=>'MIDDLE'},$inner_table),
 1238         $cgi->td({-align=>'RIGHT', -valign=>'TOP', -rowspan=>2},
 1239           $cgi->a({-href=>$Global::webworkDocsURL}, $cgi->img({-src=>$Global::squareWebworkGif,-border=>1,-alt=>'WeBWorK Docs'}))
 1240         )
 1241       ),
 1242       $cgi->Tr(
 1243         $cgi->td({-align=>'LEFT', -valign=>'BOTTOM'}, $cgi->h4($problemStatusMessage))
 1244       )
 1245     );
 1246   return $navigation_bar;
 1247 }
 1248 
 1249 
 1250 sub format_preview_navigation_bar {
 1251   my $curentProbNum = shift;
 1252 
 1253 ## first set up the navigation button forms
 1254 
 1255   my $current_prob_form = join("\n",
 1256     $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1257     $cgi->input({-type=>'IMAGE', -src=>"$Global::currentImgUrl", -alt=>'Current Problem'}),
 1258     $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1259     $cgi->hidden(-name=>'probNum', -value=>"$curentProbNum", -override=>1),
 1260     $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1261     $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1262     $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1263     $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1264     $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1265     $cgi->endform()
 1266   );
 1267 
 1268   my $prob_list_form = join("\n",
 1269     $cgi->startform(-method=>'POST', -action=>"$Global::welcomeAction_CGI"),
 1270       $cgi->input({-type=>'IMAGE', -src=>"$Global::problistImgUrl", -alt=>'Problem List'}),
 1271     $cgi->hidden(-name=>'local_psvns', -value=>"$inputs{probSetKey}"),
 1272       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1273       $cgi->hidden(-name=>'action', -value=>"Do_problem_set",-override=>1),
 1274       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1275       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1276       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1277       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1278       $cgi->endform()
 1279     );
 1280 
 1281 
 1282 ## next set up the inner table
 1283   my $inner_table =
 1284     $cgi->table(
 1285       $cgi->Tr(
 1286         $cgi->td({-align=>'CENTER', -valign=>'MIDDLE'},[$current_prob_form, $prob_list_form])
 1287     )
 1288     );
 1289 
 1290 ## finally set up the main table
 1291   my $navigation_bar =
 1292     $cgi->table({-border=>0,-width=>'100%'},
 1293       $cgi->Tr({-align=>'CENTER', -valign=>'TOP'},
 1294         $cgi->td({-align=>'LEFT', -valign=>'MIDDLE'},$inner_table),
 1295         $cgi->td({-align=>'RIGHT', -valign=>'TOP', -width=>'20%', -rowspan=>2},
 1296           $cgi->a({-href=>$Global::webworkDocsURL}, $cgi->img({-src=>$Global::squareWebworkGif,-border=>1,-alt=>'WeBWorK Docs'}))
 1297         )
 1298       ),
 1299       $cgi->Tr(
 1300         $cgi->td({-align=>'LEFT', -valign=>'BOTTOM'}, $cgi->h4("Preview Answers for Problem $probNum of Set $setNumber_display"))
 1301       )
 1302     );
 1303   return $navigation_bar;
 1304 }
 1305 
 1306 
 1307 ##Subroutine saveProblem takes the modified source of the problem and
 1308 ##saves it to the file with the original problem name and appends the
 1309 ##old version of the problem to the file problemname.pg.bak
 1310 
 1311 sub saveProblem {
 1312   my ($source, $probFileName)= @_;
 1313   my $org_source;
 1314  #######get original source of the problem
 1315   if (-e "${templateDirectory}$probFileName" ) {
 1316     unless (-w "${templateDirectory}$probFileName") {
 1317       wwerror($0, "Can't write to ${templateDirectory}$probFileName.\n" .
 1318                    "No changes were saved.\n" .
 1319                    "Check that the  permissions for this problem are 660 (-rw-rw----)\n",
 1320                    "", "", $cgi -> query_string());
 1321     }
 1322     open(PROB,"<${templateDirectory}$probFileName");
 1323     $org_source = join("",<PROB>);
 1324       close(PROB);
 1325   } else {
 1326     wwerror($0, "<H4>Error: The problem ${templateDirectory}$probFileName could not be found!</H4>");
 1327   }
 1328 
 1329  #######append old version to problemfilename.pg.bak:
 1330   open BAKFILE, ">>${templateDirectory}${probFileName}.bak" or
 1331     wwerror($0, "Could not open \n${templateDirectory}${probFileName}.bak for appending.\nNo changes were saved.");
 1332   my ($sec, $min, $hour, $mday, $mon, $year)=localtime(time);
 1333   print BAKFILE "##################################################################\n",
 1334           "##########Date:: $mday-$mon-$year, $hour:$min:$sec################", "\n\n\n";
 1335   print BAKFILE $org_source;
 1336   close BAKFILE;
 1337 
 1338   chmod 0660, "${templateDirectory}${probFileName}.bak" ||
 1339                print "Content-type: text/html\n\n
 1340                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}${probFileName}.bak";
 1341 
 1342 
 1343  #######copy new version to the file problemfilename.pg
 1344   open (PROBLEM, ">${templateDirectory}$probFileName") ||
 1345     wwerror($0, "Could not open ${templateDirectory}$probFileName for writing.
 1346     Check that the  permissions for this problem are 660 (-rw-rw----)");
 1347   print PROBLEM $source;
 1348   close PROBLEM;
 1349   chmod 0660, "${templateDirectory}${probFileName}" ||
 1350                print "Content-type: text/html\n\n
 1351                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}${probFileName}";
 1352 
 1353 }
 1354 
 1355 ##Subroutine saveNewProblem takes the modified source of the problem and
 1356 ##saves it to the file with the $new_file_name
 1357 
 1358 sub saveNewProblem {
 1359   my ($source, $new_file_name)= @_;
 1360 
 1361  #######check that the new file name is legal
 1362   unless ($new_file_name =~ /^\w/ ) {
 1363     wwerror($0, "The file name or path\n".
 1364     "$new_file_name\n".
 1365     "can not begin with a non word character.\n" .
 1366     "<b>The new version was not saved.</b>\n" .
 1367     "Go back and choose a different name.");
 1368   }
 1369 
 1370   if ($new_file_name =~ /\.\./ ) {
 1371     wwerror($0, "The file name or path\n".
 1372     "$new_file_name\n".
 1373     "is illegal.\n" .
 1374     "<b>The new version was not saved.</b>\n" .
 1375     "Go back and choose a different name.");
 1376   }
 1377 
 1378 
 1379  #######check that the new file name doesn't exist
 1380   if (-e "${templateDirectory}$new_file_name" ) {
 1381     wwerror($0, "The file\n".
 1382     "${templateDirectory}$new_file_name\n".
 1383     "already exists.\n" .
 1384     "<b>The new version was not saved.</b>\n" .
 1385     "Go back and choose a different file name or\, if you really want to edit\n".
 1386     "${templateDirectory}$new_file_name\,\n".
 1387     "go back and hit the \&quot;Save updated version\&quot; button.");
 1388   }
 1389 
 1390 
 1391  #######copy new version to the file new_file_name
 1392   open (PROBLEM, ">${templateDirectory}$new_file_name") ||
 1393     wwerror($0, "Could not open ${templateDirectory}$new_file_name for writing.
 1394   Check that the  permissions for the directory ${templateDirectory} are 770 (drwxrwx---)
 1395   Also check permissions for any subdirectories in the path.");
 1396   print PROBLEM $source;
 1397   close PROBLEM;
 1398   chmod 0660, "${templateDirectory}$new_file_name" ||
 1399                print "Content-type: text/html\n\n
 1400                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}$new_file_name";
 1401 
 1402 }
 1403 
 1404 
 1405 sub build_preview_page {
 1406     print preview_answers_htmlTOP("Preview Answers for Problem $probNum", '',$bg_color);
 1407   print format_preview_navigation_bar($probNum);
 1408   print $cgi -> startform(-action=>"$Global::processProblem_CGI");
 1409     print $preview_text;
 1410     ############# print hidden information about problem and set
 1411   $s = '';
 1412   if( $expected_answer_count > 1) {$s = 's'; }
 1413   print   $cgi -> hidden(-name=>'probNum',  -value=>$probNum),
 1414     $cgi -> hidden(-name=>'probSetKey', -value=>$psvn),
 1415     $cgi -> hidden(-name=>'answer_form_submitted', -value=>1),   # alerts the problem to show answers.
 1416     $cgi -> hidden(-name=>'Mode',   -value=>$mode);
 1417     $cgi -> hidden(-name=>'show_old_answers', -value=>$show_old_answers);
 1418   print   &sessionKeyInputs(\%inputs),
 1419     $cgi->br,
 1420     $cgi -> submit(  -name => 'action',  -value=>"Preview Again" ),"\n",
 1421     $cgi -> submit(  -name => 'action',  -value=>"Paste Answer$s" ),"\n",
 1422     $cgi -> submit(  -name => 'action',  -value=>"Submit Answer$s" ),"\n";
 1423 
 1424     print $cgi -> endform();
 1425 
 1426     print &htmlBOTTOM($0, \%inputs, 'previewAnswersHelp.html');
 1427 }
 1428 
 1429 sub encode_submitted_answers { ## returns an encoded string
 1430   my $ra_answer_entry_order = shift;
 1431   my @answer_labels = @$ra_answer_entry_order;
 1432   my %answer_hash =();
 1433   my ($label,$value,$out_string);
 1434 
 1435   ## we will use ## to joint the hash into a string for storage
 1436   ## so first we protect # in all keys and values
 1437   foreach $label (@answer_labels) {
 1438     $value = (defined $inputs{$label}) ? $inputs{$label} : '' ;
 1439     $value = substr($value,0,$Global::maxSizeRecordedAns) if length($value) > $Global::maxSizeRecordedAns;
 1440 #warn "label is |$label| \n";
 1441 #warn "val is |$value| \n";
 1442     $label =~ s/#/\\#\\/g;
 1443     $value =~ s/#/\\#\\/g;
 1444     $answer_hash{$label} = $value;
 1445   }
 1446   $out_string = join '##', %answer_hash;
 1447 
 1448   ## When using flat databases (gdbm, db), we use '&' and '=' to
 1449   ## separate values so we must replace all such occurences. We will
 1450   ## replace then by %% and @@. First we escape any of these.
 1451 
 1452 # this is now handled by protect_string in DBglue8 as it is specific to the database used
 1453 
 1454 # $out_string =~ s/%/\\%\\/g;
 1455 # $out_string =~ s/@/\\@\\/g;
 1456 # $out_string =~ s/&/%%/g;
 1457 # $out_string =~ s/=/@@/g;
 1458 #warn "outstring is |$out_string| \n";
 1459   $out_string;
 1460 }
 1461 
 1462 sub decode_submitted_answers { ## returns a ref to a hash of submitted answers
 1463   my $in_string = shift;
 1464 
 1465   ## reverse encoding process. See comments in encode_submitted_answers
 1466 # this is now handled by unprotect_string in DBglue8 as it is specific to the database used
 1467 
 1468 # $in_string =~ s/@@/=/g;
 1469 # $in_string =~ s/%%/&/g;
 1470 # $in_string =~ s/\\@\\/@/g;
 1471 # $in_string =~ s/\\%\\/%/g;
 1472 
 1473   $in_string =~ s/##$/## /;   # This makes sure that the last element has a value.
 1474                 # It may cause trouble if this value was supposed to be nil instead of a space.
 1475 
 1476   my %saved_answers = split /##/,$in_string;
 1477   my ($label,$value);
 1478   my %answer_hash = ();
 1479 
 1480   foreach $label (keys (%saved_answers)) {
 1481     $value = $saved_answers{$label};
 1482     $label =~ s/\\#\\/#/g;
 1483     $value =~ s/\\#\\/#/g;
 1484     $answer_hash{$label} = $value;
 1485   }
 1486   \%answer_hash;
 1487 }
 1488 
 1489 sub defineProblemEnvir {
 1490     my ($mode,$probNum,$psvn,$courseName)      =   @_;
 1491     my %envir=();
 1492     my $loginName = &getStudentLogin($psvn);
 1493   ##how to put an array submittedAnswers in a hash??
 1494 #    $envir{'refSubmittedAnswers'}    =   $refSubmittedAnswers if defined($refSubmittedAnswers);
 1495     $envir{'psvnNumber'}        =   $psvn;
 1496     $envir{'psvn'}            =   $psvn;
 1497     $envir{'studentName'}       =   &CL_getStudentName($loginName);
 1498   $envir{'studentLogin'}        = &getStudentLogin($psvn);
 1499   $envir{'studentID'}         = &CL_getStudentID($loginName);
 1500   $envir{'sectionName'}       = &CL_getClassSection($loginName);
 1501   $envir{'sectionNumber'}       = &CL_getClassSection($loginName);
 1502   $envir{'recitationName'}      = &CL_getClassRecitation($loginName);
 1503   $envir{'recitationNumber'}      = &CL_getClassRecitation($loginName);
 1504   $envir{'setNumber'}         = &getSetNumber($psvn);
 1505   $envir{'questionNumber'}        = $probNum;
 1506   $envir{'probNum'}           = $probNum;
 1507   $envir{'openDate'}          = &getOpenDate($psvn);
 1508   $envir{'formattedOpenDate'}     = &formatDateAndTime(&getOpenDate($psvn));
 1509   $envir{'dueDate'}           = &getDueDate($psvn);
 1510   $envir{'formattedDueDate'}      = &formatDateAndTime(&getDueDate($psvn));
 1511   $envir{'answerDate'}        = &getAnswerDate($psvn);
 1512   $envir{'formattedAnswerDate'}   = &formatDateAndTime(&getAnswerDate($psvn));
 1513   $envir{'problemValue'}        = &getProblemValue($probNum,$psvn);
 1514   $envir{'fileName'}          = &getProblemFileName($probNum,$psvn);
 1515   $envir{'probFileName'}        = &getProblemFileName($probNum,$psvn);
 1516   $envir{'languageMode'}        = $mode;
 1517   $envir{'displayMode'}       = $mode;
 1518   $envir{'outputMode'}        = $mode;
 1519   $envir{'courseName'}        = $courseName;
 1520   $envir{'sessionKey'}        = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " ";
 1521 
 1522   # initialize constants for PGanswermacros.pl
 1523   $envir{'numRelPercentTolDefault'}   =     getNumRelPercentTolDefault();
 1524   $envir{'numZeroLevelDefault'}   =     getNumZeroLevelDefault();
 1525   $envir{'numZeroLevelTolDefault'}  =     getNumZeroLevelTolDefault();
 1526   $envir{'numAbsTolDefault'}      =     getNumAbsTolDefault();
 1527   $envir{'numFormatDefault'}      =     getNumFormatDefault();
 1528   $envir{'functRelPercentTolDefault'} =     getFunctRelPercentTolDefault();
 1529   $envir{'functZeroLevelDefault'}   =     getFunctZeroLevelDefault();
 1530   $envir{'functZeroLevelTolDefault'}  =     getFunctZeroLevelTolDefault();
 1531   $envir{'functAbsTolDefault'}    =     getFunctAbsTolDefault();
 1532   $envir{'functNumOfPoints'}      =     getFunctNumOfPoints();
 1533   $envir{'functVarDefault'}       =     getFunctVarDefault();
 1534   $envir{'functLLimitDefault'}    =     getFunctLLimitDefault();
 1535   $envir{'functULimitDefault'}    =     getFunctULimitDefault();
 1536   $envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration();
 1537         $envir{'useBaseTenLog'} =     $Global::useBaseTenLog;
 1538   $envir{'defaultDisplayMatrixStyle'} =     $Global::defaultDisplayMatrixStyle;
 1539   #kludge check definition of number of attempts again. The +1 is because this is used before the current answer is evaluated.
 1540   $envir{'numOfAttempts'}             =     &getProblemNumOfCorrectAns($probNum,$psvn)
 1541                                           + &getProblemNumOfIncorrectAns($probNum,$psvn)+1;
 1542 
 1543 
 1544 
 1545   # defining directorys and URLs
 1546   $envir{'templateDirectory'}       = &getCourseTemplateDirectory();
 1547   $envir{'classDirectory'}        = $Global::classDirectory;
 1548   $envir{'cgiDirectory'}        = $Global::cgiDirectory;
 1549   $envir{'cgiURL'}                    =   getWebworkCgiURL();
 1550   $envir{'macroDirectory'}        = getCourseMacroDirectory();
 1551   $envir{'courseScriptsDirectory'}    = getCourseScriptsDirectory();
 1552   $envir{'htmlDirectory'}             =   getCourseHtmlDirectory();
 1553   $envir{'htmlURL'}           = getCourseHtmlURL();
 1554   $envir{'tempDirectory'}             =   getCourseTempDirectory();
 1555   $envir{'tempURL'}                   =   getCourseTempURL();
 1556   $envir{'scriptDirectory'}       = $Global::scriptDirectory;
 1557   $envir{'webworkDocsURL'}        = $Global::webworkDocsURL;
 1558   $envir{'externalTTHPath'}       = $Global::externalTTHPath;
 1559   $envir{'externalGif2EpsPath'}     = $scriptDirectory.'gif2eps';  #compatible with previous standard of storing this script in the scripts directory
 1560   $envir{'externalPng2EpsPath'}     = $scriptDirectory.'png2eps';
 1561   $envir{'externalLatexPath'}       = $Global::externalLaTeX2HTMLPath;
 1562 
 1563   $envir{'externalLaTeXPath'}       = $Global::externalLatexPath;  #used by HTML_img (note capitalizations of T's FIXME
 1564 
 1565   $envir{externalDvipngPath}          =   $Global::externalDvipngPath_img;
 1566   $envir{dvipngTempDir}               =   $mode eq 'HTML_img'
 1567     ? tempdir("webwork-dvipng-XXXXXXXX", DIR => $envir{tempDirectory})
 1568     : undef;
 1569 
 1570 
 1571   $envir{'inputs_ref'}                = \%inputs;
 1572   $envir{'problemSeed'}         =   $seed;
 1573   $envir{'displaySolutionsQ'}     =   $displaySolutionsQ;
 1574   $envir{'displayHintsQ'}       =   $displayHintsQ;
 1575 
 1576   # here is a way to pass environment variables defined in webworkCourse.ph
 1577   my $k;
 1578   foreach $k (keys %Global::PG_environment ) {
 1579     $envir{$k} = $Global::PG_environment{$k};
 1580   }
 1581   %envir;
 1582 }
 1583 
 1584 };  # end eval
 1585 
 1586 print "Content-type:  text/plain\n\n Error in $Global::processProblem_CGI\n$@" if $@;
 1587 
 1588 #### for error checking and debugging purposes
 1589 sub pretty_print_rh {
 1590   my $rh = shift;
 1591   foreach my $key (sort keys %{$rh})  {
 1592     print "  $key => ",$rh->{$key},"\n";
 1593   }
 1594 }
 1595 
 1596 #   Code for logging students's answers to allow inspection of answer history.
 1597 sub logCourseData {
 1598       return unless ($Global::logCourseAnswerData);
 1599 
 1600       my $user = shift;
 1601       my $setNum = shift;
 1602       my $probNum = shift;
 1603       my $inputs = shift;
 1604       my $pt = shift;
 1605       my @answers = (defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER})) ?
 1606     @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} :
 1607     keys %{$pt->rh_evaluated_answers};
 1608       my ($id,$string);
 1609 
 1610       my @ans = ("|$user|$setNum|$probNum|",time());
 1611       foreach $id (@answers) {
 1612       $string = $inputs->{$id}; $string = "" unless defined($string);
 1613       $string =~ s!\t! !g;  # just in case
 1614       push (@ans,$string);
 1615       }
 1616 
 1617       my $answerLog = getCourseLogsDirectory()."answer_log";
 1618       open(LOG, ">>$answerLog") or warn "Can't open course access log $answerLog";
 1619       print LOG join("\t",@ans),"\n";  # data is tab-separated fields
 1620       close(LOG);
 1621 }
 1622 #   End code for logging students's answers
 1623 
 1624 
 1625 
 1626 
 1627 
 1628 END {
 1629    if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) {
 1630       alarm(0);  # turn off the alarm
 1631 
 1632       my $problem_message = qq!Content-type: text/html\n\n<HTML><BODY BGCOLOR = "FF99CC">
 1633         <BLOCKQUOTE><H3>WeBWorK heavy useage time out.</H3>\n
 1634       <H4>Your request for a WeBWorK problem was cancelled because it took more
 1635       than $main::TIME_OUT_CONSTANT seconds.</H4>
 1636       If this occurs for only this problem, it is likely that there is a programing error
 1637       in this problem, maybe an infinite loop.  Please report this to your instructor.<p />\n
 1638       If you get this error on several different problems, it
 1639       is probably because the
 1640       WeBWorK server is extraordinarily busy.<p />\n
 1641       In this case you should be warned that WeBWorK response will be unusually slow.  If possible you should try
 1642       to use WeBWorK at another time when the load is not as high.  The highest useage periods are in the
 1643       evening, particularly in the two hours before assignments are due.<p />\n
 1644           Use the back button to return to the previous page and try again.<p />\n
 1645           If the high useage problem continues you can report this to your instructor using
 1646           the feedback button.
 1647           <p />
 1648           Script: $Global::processProblem_CGI
 1649            </BLOCKQUOTE></BODY></HTML>
 1650       !;
 1651         print $problem_message, "\n";
 1652 
 1653 
 1654 
 1655    }
 1656 
 1657     # begin Timing code
 1658   if( $main::logTimingData == 1 ) {
 1659     my $endTime = new Benchmark;
 1660     my $error_str='';
 1661 
 1662     if ($main::SIGPIPE) {
 1663       $error_str = 'broken PIPE--';
 1664     }
 1665     elsif ($main::SIG_TIME_OUT) {
 1666       $error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --";
 1667     }
 1668 
 1669     &Global::logTimingInfo($main::beginTime,$endTime,$error_str.'processProb8.pl '. "(mode: $main::display_mode, action: $main::Action)",$main::Course,$main::User);
 1670   }
 1671   # end Timing code
 1672 
 1673 }
 1674 

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9