#!/usr/local/bin/webwork-perl ##this program creates a web page with an editor for a ##WeBWorK problem. it is called by processProblem8.pl use strict; use lib '.'; use webworkInit; # WeBWorKInitLine use CGI qw(:standard escapeHTML unescapeHTML); use MIME::Base64 qw( encode_base64 decode_base64) ; use Global; use Auth; use Safe; $main::safeCompartment = 0; $main::safeCompartment = new Safe; #Set to 1 to log timing data. Set to 0 to disable log. $main::logTimingData = 0; # begin Timing code if( $main::logTimingData == 1 ) { use Benchmark; $main::beginTime = new Benchmark; } # end Timing code my $cgi = new CGI; my %inputs = $cgi -> Vars(); # get information from CGI inputs (see also below for additional information) my $Course = $inputs{'course'}; my $User = $inputs{'user'}; my $Session_key = $inputs{'key'}; my $randpsvn = 22222; #int rand(1111,9999); my $psvn = $inputs{'probSetKey'}; #psvn stands for Problem Set Version Number my $probNum = 1; $probNum = $inputs{'probNum'} if defined($inputs{'probNum'}); my $nextProbNum = $probNum + 1 if defined($probNum); my $previousProbNum = $probNum - 1 if defined($probNum); my $mode = "HTML"; $mode = $inputs{'Mode'} if defined( $inputs{'Mode'} ); my $showEdit = $inputs{'showEdit'}; my $seed = $inputs{'seed'} if defined( $inputs{'seed'} ); my $Rows = $Global::editor_window_rows; $Rows = $inputs{'Rows'} if defined( $inputs{'Rows'} ); my $Columns = $Global::editor_window_columns; $Columns = $inputs{'Columns'} if defined( $inputs{'Columns'} ); # verify that information has been received unless($Course && $User && $Session_key && $psvn) { &wwerror( "$0, missing data", "The script did not receive the proper input data. course is $Course, user is $User, session key is $Session_key, psvn is $psvn",'','', query_string() ); } # establish environment for this script &Global::getCourseEnvironment($Course); my $macroDirectory = getCourseMacroDirectory(); my $databaseDirectory = getCourseDatabaseDirectory(); my $htmlDirectory = getCourseHtmlDirectory(); my $htmlURL = getCourseHtmlURL(); my $scriptDirectory = getWebworkScriptDirectory(); my $templateDirectory = getCourseTemplateDirectory(); my $courseScriptsDirectory = getCourseScriptsDirectory(); require "${courseScriptsDirectory}$Global::displayMacros_pl"; require "${scriptDirectory}$Global::DBglue_pl"; require "${scriptDirectory}$Global::classlist_DBglue_pl"; require "${scriptDirectory}$Global::HTMLglue_pl"; require "${scriptDirectory}$Global::FILE_pl"; #require "${scriptDirectory}qz2sub.pl"; #require this only if it actually used my $permissionsFile = &Global::getCoursePermissionsFile($Course); my $permissions = &get_permissions($User,$permissionsFile); my $keyFile = &Global::getCourseKeyFile($Course); # log access &Global::log_info('', query_string); unless ($User eq "practice666" ) { #verify session key &verify_key($User, $Session_key, "$keyFile", $Course); } &attachProbSetRecord($psvn); # get problem name my $probFileName = &getProblemFileName($probNum,$psvn); $probFileName = $inputs{'probFileName'} if defined($inputs{'probFileName'}); # get the text source of the problem my $source = ''; my $comment = ''; #print "content-type: text/html\n\ninputs of action is $inputs{action}
" if defined($inputs{action}); if ( ($inputs{'action'} eq 'Revert to original and Resize window') || !(defined($inputs{'source'}) ) ) { $comment = '

Using source from disk

'; if (-e "${templateDirectory}$probFileName" ) { #print "|$probFileName|
"; unless (-r "${templateDirectory}$probFileName") { wwerror($0, "Can't read ${templateDirectory}$probFileName"); } open(PROB,"<${templateDirectory}$probFileName"); $source = join("",); close(PROB); } else { wwerror($0, "

Error: The problem ${templateDirectory}$probFileName could not be found!

"); } } else { #source is coming from HTML hidden tag; should be decoded $source = decodeSource( $inputs{'source'}) ; # if ( defined($inputs{'source_encoded_using'}) ) { # the source has been encoded and we need to decode it first # if ( $inputs{'source_encoded_using'} eq 'base64_encode' ) { # $source = decode_base64($source); # } # elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) { # $source = $cgi -> unescape($source); # } # elsif ( $inputs{'source_encoded_using'} eq 'none' ) { # # no action required # } # elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns' ) { # $source =~ s/ /\n/g; #makes iCab work properly # } # else { # warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}"; # } # } ##substitute carriage return with a newline ##otherwise EndOfText construction does not work ##browsers always have \r\n at the end of the line # $source=~ s/\r\n/\n/g; #$source = unescapeHTML( $source ); #method in CGI.pm } #$source =~ s/ /\n/g; #makes iCab work properly #my $sourceAsHTML = escapeHTML( $source ); my $display_source = $source; $display_source = $source; # Hard to tell what the right method for displaying text in a textarea form is. # #check if we need to save the updated version of the text # my $save=0; # if ( ($inputs{'action'} eq 'Save updated version') && ($permissions == $Global::instructor_permissions) ) { # saveProblem($source, $probFileName); # $save=1; # } #### Beginning of the Editor portion print &processProblem_htmlTOP("Editor for problem $probNum"); print $comment; # #text in case the problem has been saved # if ($save) { # print "

Current version of the problem ${templateDirectory}$probFileName has been saved.

# The original version has been appended to the file ${templateDirectory}$probFileName.bak .
"; # } print "
\r\n", $cgi -> startform(-action=>"$Global::processProblem_CGI", -target=>"problem"), "
\r\n", $cgi -> hidden(-name=>'probNum', -value=>$probNum), $cgi -> hidden(-name=>'probSetKey', -value=>$psvn), # get course, user, key &sessionKeyInputs(\%inputs), qq! Editing file: $probFileName
!, "Seed: ", $cgi -> textfield(-name=>'seed',-value=>$seed), " Mode: "; # Mode button if ($mode eq 'HTML') { print $cgi -> popup_menu(-name=>'Mode', -'values'=>['HTML','HTML_tth','Latex2HTML'], -default=>'HTML'); } elsif ($mode eq 'HTML_tth') { print $cgi -> popup_menu(-name=>'Mode', -'values'=>['HTML','HTML_tth','Latex2HTML'], -default=>'HTML_tth'); } elsif ($mode eq 'Latex2HTML') { print $cgi -> popup_menu(-name=>'Mode', -'values'=>['HTML','HTML_tth','Latex2HTML'], -default=>'Latex2HTML'); } else { print qq! Error: unknown mode: $mode !; } #sticky answers print $cgi->hidden(-name=>'show_old_answers', -value=>1); # Available functions list print "
Available functions: "; print $cgi -> popup_menu( -name => 'availableFunctions', -values => [ qw{ DOCUMENT ENDDOCUMENT loadMacros beginproblem -------------- TEXT BEGIN_TEXT END_TEXT EV3 EV2 -------------- ANS ans_rule -------------- random non_zero_random -------------- spf sspf -------------- begintable endtable row imageRow image caption -------------- new_match_list ADDMORELATER... -------------- OL invert NchooseK shuffle uniq lex_sort num_sort } ] ); print "
Available Constants: "; print $cgi -> popup_menu( -name => 'availableConstants', -values => [ qw{ @ALPHABET $PAR $BR $LQ $RQ $BM $EM $BDM $EDM $LTS $GTS $LTE $GTE $BEGIN_ONE_COLUMN $END_ONE_COLUMN $SOL $HINT $US $SPACE $BBOLD $EBOLD $HR $LBRACE $LBRACE $LB $RB $PI $E } ] ); print "
Answer Evaluators: "; print $cgi -> popup_menu( -name => 'answerEvaluators', -values => [ qw{ std_num_cmp frac_num_cmp arith_num_cmp strict_num_cmp -------------------- std_num_cmp_abs frac_num_cmp_abs arith_num_cmp_abs strict_num_cmp_abs -------------------- std_num_cmp_list frac_num_cmp_list arith_num_cmp_list strict_num_cmp_list -------------------- std_num_cmp_abs_list frac_num_cmp_abs_list arith_num_cmp_abs_list strict_num_cmp_abs_list -------------------- numerical_compare_with_units ------------------------------- std_str_cmp std_cs_str_cmp strict_str_cmp unordered_str_cmp unordered_cs_str_cmp ordered_str_cmp ordered_cs_str_cmp -------------------- std_str_cmp_list std_cs_str_cmp_list strict_str_cmp_list unordered_str_cmp_list unordered_cs_str_cmp_list ordered_str_cmp_list ordered_cs_str_cmp_list -------------------- std_num_str_cmp ------------------------------- function_cmp function_cmp_up_to_constant function_cmp_abs function_cmp_up_to_constant_abs multivar_function_cmp ------------------------------- radio_cmp checkbox_cmp } ] ); # Print text area with the problem print '

', $cgi -> textarea(-name=>'source', -default=>$display_source, -rows=>$Rows, -columns=>$Columns, -override =>1 ), #-wrap=>'virtual' '

', $cgi -> hidden(-name => 'refreshLatex2HTML', -value => 1), $cgi -> hidden(-name => 'readSourceFromHTMLQ', -value => 1 ), '

', $cgi -> submit(-name=>'action', -value=>'Refresh problem'); if ($permissions == $Global::instructor_permissions) { print ' ', $cgi -> submit(-name=>'action', -value=>'Save updated version'); print ' ', $cgi -> submit(-name=>'action', -value=>'Save as'), $cgi -> textfield(-name=>'new file name', -size => 40, -value=> "$probFileName"), '
For "Save as", choose a new file name.'; } print "\r\n",$cgi -> endform(),"\r\n","\r\n",; print "\r\n", $cgi -> startform(-action=>"$Global::problemEditor_CGI"), "\r\n", $cgi -> hidden(-name=>'probNum', -value=>$probNum), $cgi -> hidden(-name=>'probSetKey', -value=>$psvn), # get course, user, key &sessionKeyInputs(\%inputs), $cgi -> hidden(-name=>'Mode', -value=>'HTML'), $cgi -> hidden(-name=>'seed', -value=>$seed), hidden(-name=>'source', -value=>$source), $cgi -> submit(-name=>'action', -value=>'Revert to original and Resize window'), ' Rows: ', $cgi -> textfield(-name=>'Rows', -default=>$Rows, -size => 3), ' Columns: ', $cgi -> textfield(-name=>'Columns', -default=>$Columns, -size => 3), "\r\n",, $cgi -> endform(), &htmlBOTTOM($0, \%inputs); # begin Timing code if( $main::logTimingData == 1 ) { my $endTime = new Benchmark; &Global::logTimingInfo($main::beginTime,$endTime,'problemEditor.pl',$Course,$User); } # end Timing code exit; ############################### ##subroutines ##this subroutine is from processProblem ##why is it called processProblem_htmlTOP? is there a generic htmlTOP? sub processProblem_htmlTOP { my ($title, $bg_url) = @_; my $background_url = $bg_url || $Global::background_plain_url; #my $out = header(-type=>'text/html'); my $out = < EOF $out .= start_html(-'title'=>$title, -background=>$background_url); $out; } sub decodeSource { my $source = shift; warn "Only source embedded in HTML needs to be decoded" unless defined($inputs{'source'}); if ( defined($inputs{'source_encoded_using'}) ) { # the source has been encoded and we need to decode it first if ( $inputs{'source_encoded_using'} eq 'base64_encode' ) { $source = decode_base64($source); } elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) { $source = $cgi -> unescape($source); } elsif ( $inputs{'source_encoded_using'} eq 'none' ) { # no action needed } elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns' ) { $source =~s/ /\n/g; warn "uncoding escaped returns"; $source =~s/\r\n/\n/g; } else { warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}"; } } $source; } ##Subroutine saveProblem takes the modified source of the problem and ##saves it to the file with the original problem name and appends the ##old version of the problem to the file problemname.pg.bak # sub saveProblem { # my ($source, $probFileName)= @_; # my $org_source; # ##get original source of the problem # if (-e "${templateDirectory}$probFileName" ) { # unless (-r "${templateDirectory}$probFileName") { # wwerror($0, "Can't read ${templateDirectory}$probFileName"); # } # open(PROB,"<${templateDirectory}$probFileName"); # $org_source = join("",); # close(PROB); # } else { # wwerror($0, "

Error: The problem ${templateDirectory}$probFileName could not be found!

"); # } # ##append old version to problemfilename.pg.bak: # open BAKFILE, ">>${templateDirectory}${probFileName}.bak" or # wwerror($0, "Could not open ${templateDirectory}${probFileName}.bak for appending."); # my ($sec, $min, $hour, $mday, $mon, $year)=localtime(time); # print BAKFILE "##################################################################\n", # "##########Date:: $mday-$mon-$year, $hour:$min:$sec#########", "\n\n\n"; # print BAKFILE $org_source; # close BAKFILE; # chmod 0660, "${templateDirectory}${probFileName}.bak"; # ##copy new version to the file problemfilename.pg # open PROBLEM, ">${templateDirectory}$probFileName" or die # wwerror($0, "Could not open ${templateDirectory}$probFileName for writing. # Check that the permissions for this problem are 660 (-rw-rw----)"); # print PROBLEM $source; # close PROBLEM; # chmod 0660, "${templateDirectory}${probFileName}"; # # }