[system] / branches / rel-2-2-dev / webwork2 / lib / WeBWorK / ContentGenerator / Instructor / PGProblemEditor.pm Repository:
ViewVC logotype

View of /branches/rel-2-2-dev/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3667 - (download) (as text) (annotate)
Thu Sep 29 01:57:56 2005 UTC (7 years, 7 months ago) by gage
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm
File size: 50560 byte(s)
Allow making a local copy of a library problem with a single button push.

The user interface is still cluttered.  I think I'll rewrite the bottom button rows
using radio buttons and a 'Take action' submit button as on the Classlist and Homework set editor
pages.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v 1.56 2005/07/30 17:26:45 gage Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 package WeBWorK::ContentGenerator::Instructor::PGProblemEditor;
   18 use base qw(WeBWorK::ContentGenerator::Instructor);
   19 
   20 
   21 =head1 NAME
   22 
   23 WeBWorK::ContentGenerator::Instructor::PGProblemEditor - Edit a pg file
   24 
   25 =cut
   26 
   27 use strict;
   28 use warnings;
   29 use CGI qw();
   30 use WeBWorK::Utils qw(readFile surePathToFile);
   31 use Apache::Constants qw(:common REDIRECT);
   32 use HTML::Entities;
   33 use URI::Escape;
   34 use WeBWorK::Utils;
   35 use WeBWorK::Utils::Tasks qw(fake_set fake_problem);
   36 
   37 ###########################################################
   38 # This editor will edit problem files or set header files or files, such as course_info
   39 # whose name is defined in the global.conf database
   40 #
   41 # Only files under the template directory ( or linked to this location) can be edited.
   42 #
   43 # The course information and problems are located in the course templates directory.
   44 # Course information has the name  defined by courseFiles->{course_info}
   45 #
   46 # Only files under the template directory ( or linked to this location) can be edited.
   47 #
   48 # editMode = temporaryFile    (view the temp file defined by course_info.txt.user_name.tmp
   49 #                              instead of the file course_info.txt)
   50 #            this flag is read by Problem.pm and ProblemSet.pm, perhaps others
   51 # The TEMPFILESUFFIX is "user_name.tmp" by default.  It's definition should be moved to Instructor.pm #FIXME
   52 ###########################################################
   53 
   54 ###########################################################
   55 # The behavior of this module is essentially defined
   56 # by the values of $file_type and the submit button which is placed in $action
   57 #############################################################
   58 #  File types which can be edited
   59 #
   60 #  file_type  eq 'problem'
   61 #                 this is the most common type -- this editor can be called by an instructor when viewing any problem.
   62 #                 the information for retrieving the source file is found using the problemID in order to look
   63 #                 look up the source file path.
   64 #
   65 #  file_type  eq 'problem_with_source'
   66 #                 This is the same as the 'problem' file type except that the source for the problem is found in
   67 #                 the parameter $r->param('sourceFilePath').
   68 #
   69 #  file_type  eq 'set_header'
   70 #                 This is a special case of editing the problem.  The set header is often listed as problem 0 in the set's list of problems.
   71 #
   72 #  file_type  eq 'hardcopy_header'
   73 #                  This is a special case of editing the problem.  The hardcopy_header is often listed as problem 0 in the set's list of problems.
   74 #                  But it is used instead of set_header when producing a hardcopy of the problem set in the TeX format, instead of producing HTML
   75 #                  formatted version for use on the computer screen.
   76 #
   77 #  filte_type eq 'course_info
   78 #                 This allows editing of the course_info.txt file which gives general information about the course.  It is called from the
   79 #                 ProblemSets.pm module.
   80 #
   81 #  file_type  eq 'blank_problem'
   82 #                 This is a special call which allows one to create and edit a new PG problem.  The "stationery" source for this problem is
   83 #                 stored in the conf/snippets directory and defined in global.conf by $webworkFiles{screenSnippets}{blankProblem}
   84 #############################################################
   85 # submit button actions  -- these and the file_type determine the state of the module
   86 #      Save                       ---- action = save
   87 #      Save as                    ---- action = save_as
   88 #      View Problem               ---- action = refresh
   89 #      Add this problem to:       ---- action = add_problem_to_set
   90 #      Make this set header for:  ---- action = add_set_header_to_set
   91 #      Revert                     ---- action = revert
   92 #      no submit button defined   ---- action = fresh_edit
   93 ###################################################
   94 #
   95 # Determining which is the correct path to the file is a mess!!! FIXME
   96 # The path to the file to be edited is eventually put in tempFilePath
   97 #
   98 # $problemPath is also used as is editFilePath.  let's try to regularize these.
   99 #(sourceFile) (problemPath)(tempFilePath)(editFilePath)(forcedSourceFile)(problemPath)
  100 #input parameter can be:  sourceFilePath
  101 #################################################################
  102 # params read
  103 # user
  104 # effectiveUser
  105 # submit
  106 # file_type
  107 # problemSeed
  108 # displayMode
  109 # edit_level
  110 # make_local_copy
  111 # sourceFilePath
  112 # problemContents
  113 # save_to_new_file
  114 #
  115 
  116 #our $libraryName;
  117 #our $rowheight;
  118 our $TEMPFILESUFFIX;
  119 
  120 sub pre_header_initialize {
  121   my ($self)         = @_;
  122   my $r              = $self->r;
  123   my $ce             = $r->ce;
  124   my $urlpath        = $r->urlpath;
  125   my $authz          = $r->authz;
  126   my $user           = $r->param('user');
  127   $TEMPFILESUFFIX    = $user.'.tmp';
  128 
  129   my $submit_button   = $r->param('submit');  # obtain submit command from form
  130   my $file_type       = $r->param("file_type") || '';
  131   my $setName         = $r->urlpath->arg("setID") ;  # using $r->urlpath->arg("setID")  ||'' causes trouble with set 0!!!
  132   my $problemNumber   = $r->urlpath->arg("problemID");
  133 
  134   # Check permissions
  135   return unless ($authz->hasPermissions($user, "access_instructor_tools"));
  136   return unless ($authz->hasPermissions($user, "modify_problem_sets"));
  137 
  138     #############################################################################
  139   # Save file to permanent or temporary file, then redirect for viewing
  140   #############################################################################
  141   #
  142   #  Any file "saved as" should be assigned to "Undefined_Set" and redirectoed to be viewed again in the editor
  143   #
  144   #  Problems "saved" or 'refreshed' are to be redirected to the Problem.pm module
  145   #  Set headers which are "saved" are to be redirected to the ProblemSet.pm page
  146   #  Hardcopy headers which are "saved" are aso to be redirected to the ProblemSet.pm page
  147   #  Course_info files are redirected to the ProblemSets.pm page
  148   ##############################################################################
  149 
  150 
  151 
  152   ######################################
  153     # Insure that file_type is defined
  154   ######################################
  155   # We have already read in the file_type parameter from the form
  156   #
  157   # If this has not been defined we are  dealing with a set header
  158   # or regular problem
  159   if (defined($file_type) and ($file_type =~/\S/)) { #file_type is defined and is not blank
  160     # file type is already defined -- do nothing
  161   } else {
  162       # if "sourcFilePath" is defined in the form, then we are getting the path directly.
  163     # if the problem number is defined and is 0
  164     # then we are dealing with some kind of
  165     # header file.  The default is 'set_header' which prints properly
  166     # to the screen.
  167     # If the problem number is not zero, we are dealing with a real problem
  168     ######################################
  169     if ( defined($r->param('sourceFilePath') and $r->param('sourceFilePath') =~/\S/) ) {
  170       $file_type ='source_path_for_problem_file';
  171     } elsif ( defined($problemNumber) ) {
  172        if ( $problemNumber =~/^\d+$/ and $problemNumber == 0 ) {  # if problem number is numeric and zero
  173                 $file_type = 'set_header' unless $file_type eq 'set_header'
  174                                                or $file_type eq 'hardcopy_header';
  175              } else {
  176               $file_type = 'problem';
  177              }
  178 
  179     }
  180   }
  181   die "The file_type variable has not been defined or is blank." unless defined($file_type) and $file_type =~/\S/;
  182   $self->{file_type} = $file_type;
  183 
  184   ##########################################
  185   # File type is one of:     blank_problem course_info  problem set_header hardcopy_header problem_with_source
  186     ##########################################
  187     #
  188     # Determine the path to the file
  189     #
  190     ###########################################
  191       $self->getFilePaths($setName, $problemNumber, $file_type,$TEMPFILESUFFIX);
  192       # result stored in $self->{editFilePath}, and $self->{tempFilePath}
  193     ##########################################
  194     #
  195     # Determine action
  196     #
  197     ###########################################
  198     # Submit button is one of: "add this problem to" , "add this set header to ", "Refresh"  "Revert" "Save" "Save As"
  199     $submit_button = $r->param('submit');
  200     SUBMIT_CASE: {
  201       (! defined($submit_button) ) and do {   # fresh problem to edit
  202         $self->{action} = 'fresh_edit';
  203         last SUBMIT_CASE;
  204       };
  205 
  206       ($submit_button eq 'Add this problem to: ') and do {
  207         $self->{action} = 'add_problem_to_set';
  208         last SUBMIT_CASE;
  209       };
  210 
  211       ($submit_button eq 'Make this the set header for: ') and do {
  212         $self->{action} = 'add_set_header_to_set';
  213         last SUBMIT_CASE;
  214       };
  215 
  216       ($submit_button eq 'View  problem') and  do {
  217         $self->{action} ='refresh';
  218         last SUBMIT_CASE;
  219       };
  220 
  221       ($submit_button eq 'Revert') and do {
  222         $self->{action} = 'revert';
  223         last SUBMIT_CASE;
  224       };
  225 
  226       ($submit_button eq 'Save') and do {
  227         $self->{action} = 'save';
  228         last SUBMIT_CASE;
  229       };
  230 
  231       ($submit_button eq 'Save as') and do {
  232         $self->{action} = 'save_as';
  233         last SUBMIT_CASE;
  234       };
  235 
  236       ($submit_button eq 'Add problem to: ') and do {
  237         $self->{action} = 'add_problem_to_set';
  238         last SUBMIT_CASE;
  239       };
  240       ($submit_button eq 'Make local copy at: ') and do {
  241         $self->{action} = 'make_local_copy';
  242         last SUBMIT_CASE;
  243       };
  244       # else
  245       die "Unrecognized submit command: |$submit_button|";
  246 
  247     } # END SUBMIT_CASE
  248 
  249 
  250     ###########################################
  251     # Save file
  252     ######################################
  253 
  254     # The subroutine below writes the necessary files and obtains the appropriate seed.
  255     # and returns
  256     #         $self->{problemPath}   --- file path for viewing problem in $self->{problemPath}
  257     #         $self->{failure}
  258 
  259 
  260     $self->saveFileChanges($setName, $problemNumber, $file_type,$TEMPFILESUFFIX);
  261 
  262   ##############################################################################
  263   # displayMode   and problemSeed
  264   #
  265   # Determine the display mode
  266   # If $self->{problemSeed} was obtained within saveFileChanges from the problem_record
  267   # then it can be overridden by the value obtained from the form.
  268   # Insure that $self->{problemSeed} has some non-empty value
  269   # displayMode and problemSeed
  270   # will be needed for viewing the problem via redirect.
  271   # They are also two of the parameters which can be set by the editor
  272   ##############################################################################
  273 
  274   if (defined $r->param('displayMode')) {
  275     $self->{displayMode} = $r->param('displayMode');
  276   } else {
  277     $self->{displayMode} = $ce->{pg}->{options}->{displayMode};
  278   }
  279 
  280   # form version of problemSeed overrides version obtained from the the problem_record
  281   # inside saveFileChanges
  282   $self->{problemSeed} = $r->param('problemSeed') if (defined $r->param('problemSeed'));
  283   # Make sure that the problem seed has some value
  284   $self->{problemSeed} = '123456' unless defined $self->{problemSeed} and $self->{problemSeed} =~/\S/;
  285 
  286   ##############################################################################
  287   # Return
  288   #   If  file saving fails or
  289   #   if no redirects are required. No further processing takes place in this subroutine.
  290   #   Redirects are required only for the following submit values
  291   #        'Save'
  292   #        'Save as'
  293   #        'Refresh'
  294   #        add problem to set
  295   #        add set header to set
  296   #
  297     #########################################
  298 
  299     return if $self->{failure};
  300     # FIXME: even with an error we still open a new page because of the target specified in the form
  301 
  302 
  303   # Some cases do not need a redirect: save, refresh, save_as, add_problem_to_set, add_header_to_set,make_local_copy
  304   my $action = $self->{action};
  305 
  306     return unless $action eq 'save'
  307              or $action eq 'refresh'
  308              or $action eq 'save_as'
  309              or $action eq 'add_problem_to_set'
  310              or $action eq 'make_local_copy'
  311              or $action eq 'add_set_header_to_set';
  312 
  313 
  314   ######################################
  315   # calculate redirect URL based on file type
  316   ######################################
  317   my $courseName  = $urlpath->arg("courseID");
  318   my $problemSeed = ($r->param('problemSeed')) ? $r->param('problemSeed') : '';
  319   my $displayMode = ($r->param('displayMode')) ? $r->param('displayMode') : '';
  320 
  321   my $viewURL = '';
  322 
  323   ######################################
  324   # problem file_type
  325   #     redirect to Problem.pm with setID = "Undefined_Set if "Save As" option is chosen
  326   #     redirect to Problem.pm with setID = current $setID if "Save" or "Revert" or "Refresh is chosen"
  327   ######################################
  328   REDIRECT_CASES: {
  329     ($file_type eq 'problem' or $file_type eq 'source_path_for_problem_file' or $file_type eq 'blank_problem') and do {
  330       my $sourceFilePath = $self->{problemPath};
  331       # strip off template directory prefix
  332       $sourceFilePath =~ s|^$ce->{courseDirs}->{templates}/||;
  333       if ($action eq 'save_as') { # redirect to myself
  334         my $edit_level = $r->param("edit_level") || 0;
  335         $edit_level++;
  336 
  337         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
  338           courseID => $courseName, setID => 'Undefined_Set', problemID => 'Undefined_Problem'
  339         );
  340         $viewURL = $self->systemLink($problemPage,
  341                                      params=>{
  342                                          sourceFilePath     => $sourceFilePath,
  343                                          edit_level         => $edit_level,
  344                                          file_type          => 'source_path_for_problem_file',
  345                          status_message     => uri_escape($self->{status_message})
  346 
  347                                      }
  348         );
  349 
  350 
  351       } elsif ( $action eq 'add_problem_to_set') {
  352 
  353         my $targetSetName = $r->param('target_set');
  354         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
  355           courseID => $courseName, setID => $targetSetName,
  356           problemID => WeBWorK::Utils::max( $r->db->listGlobalProblems($targetSetName))
  357         );
  358         $viewURL = $self->systemLink($problemPage,
  359             params => {
  360               displayMode     => $displayMode,
  361               problemSeed     => $problemSeed,
  362               editMode        => "savedFile",
  363               sourceFilePath  => $sourceFilePath,
  364               status_message     => uri_escape($self->{status_message})
  365 
  366             }
  367         );
  368       } elsif ($action eq 'make_local_copy') { # redirect to myself
  369         my $edit_level = $r->param("edit_level") || 0;
  370         $edit_level++;
  371 
  372         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
  373           courseID => $courseName, setID => $setName, problemID => $problemNumber
  374         );
  375         $viewURL = $self->systemLink($problemPage,
  376                                      params=>{
  377                                          sourceFilePath     => $sourceFilePath,
  378                                          edit_level         => $edit_level,
  379                                          file_type          => 'source_path_for_problem_file',
  380                          status_message     => uri_escape($self->{status_message})
  381 
  382                                      }
  383         );
  384 
  385 
  386       } elsif ( $action eq 'add_set_header_to_set') {
  387         my $targetSetName = $r->param('target_set');
  388         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
  389           courseID => $courseName, setID => $targetSetName
  390         );
  391         $viewURL = $self->systemLink($problemPage,
  392             params => {
  393               displayMode     => $displayMode,
  394               editMode        => "savedFile",
  395               status_message     => uri_escape($self->{status_message})
  396             }
  397         );
  398       } else { # saved problems and refreshed  problems redirect to Problem.pm
  399         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
  400           courseID => $courseName, setID => $setName, problemID => $problemNumber
  401         );
  402         $viewURL = $self->systemLink($problemPage,
  403           params => {
  404             displayMode     => $displayMode,
  405             problemSeed     => $problemSeed,
  406             editMode        => ($action eq "save" ? "savedFile" : "temporaryFile"),
  407             sourceFilePath  => $sourceFilePath,
  408             status_message     => uri_escape($self->{status_message})
  409 
  410           }
  411         );
  412       }
  413       last REDIRECT_CASES;
  414     };
  415     ######################################
  416     # blank_problem file_type
  417     #          redirect to Problem.pm
  418     ######################################
  419 
  420     $file_type eq 'blank_problem' and do {
  421       return;  # no redirect is needed
  422     };
  423 
  424     ######################################
  425     # set headers file_type
  426     #          redirect to ProblemSet.pm
  427     ######################################
  428 
  429     ($file_type eq 'set_header' or $file_type eq 'hardcopy_header' ) and do {
  430       if ($action eq 'save_as') { # redirect to myself
  431           my $sourceFilePath = $self->{problemPath};
  432         # strip off template directory prefix
  433         $sourceFilePath =~ s|^$ce->{courseDirs}->{templates}/||;
  434 
  435         my $edit_level = $r->param("edit_level") || 0;
  436         $edit_level++;
  437 
  438         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
  439           courseID => $courseName, setID => 'Undefined_Set', problemID => 'Undefined_Problem'
  440         );
  441         $viewURL = $self->systemLink($problemPage,
  442                                      params=>{
  443                                          sourceFilePath  => $sourceFilePath,
  444                                          edit_level      => $edit_level,
  445                                          file_type       => 'source_path_for_problem_file',
  446                          status_message     => uri_escape($self->{status_message})
  447                                      }
  448         );
  449       } elsif ( $action eq 'add_set_header_to_set') {
  450         my $targetSetName = $r->param('target_set');
  451         my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
  452           courseID => $courseName, setID => $targetSetName
  453         );
  454         $viewURL = $self->systemLink($problemPage,
  455             params => {
  456               displayMode     => $displayMode,
  457               editMode        => "savedFile",
  458               status_message     => uri_escape($self->{status_message})
  459             }
  460         );
  461       } else {
  462         my $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
  463           courseID => $courseName, setID => $setName);
  464         $viewURL = $self->systemLink($problemSetPage,
  465           params => {
  466             displayMode        => $displayMode,
  467             problemSeed        => $problemSeed,
  468             editMode           => ($action eq "save" ? "savedFile" : "temporaryFile"),
  469             status_message     => uri_escape($self->{status_message})
  470           }
  471         );
  472       }
  473       last REDIRECT_CASES;
  474     };
  475     ######################################
  476     # course_info file type
  477     #            redirect to ProblemSets.pm
  478     ######################################
  479     $file_type eq 'course_info' and do {
  480       my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
  481         courseID => $courseName);
  482       $viewURL = $self->systemLink($problemSetsPage,
  483         params => {
  484           editMode => ($action eq "save" ? "savedFile" : "temporaryFile"),
  485           status_message     => uri_escape($self->{status_message})
  486         }
  487       );
  488       last REDIRECT_CASES;
  489     };
  490     # else if no redirect needed -- there must be an error.
  491     die "The file_type $file_type does not have a defined redirect procedure.";
  492   } # End REDIRECT_CASES
  493 
  494   if ($viewURL) {
  495     $self->reply_with_redirect($viewURL);
  496   } else {
  497     die "Invalid file_type $file_type specified by saveFileChanges";
  498   }
  499 }
  500 
  501 
  502 sub initialize  {
  503   my ($self) = @_;
  504   my $r = $self->r;
  505   my $authz = $r->authz;
  506   my $user = $r->param('user');
  507 
  508   # Check permissions
  509   return unless ($authz->hasPermissions($user, "access_instructor_tools"));
  510   return unless ($authz->hasPermissions($user, "modify_problem_sets"));
  511 
  512   my $tempFilePath    = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file)
  513   my $inputFilePath   = $self->{inputFilePath};   # path to the file for input, (might be a .tmp file)
  514   my $protected_file = (not -w $inputFilePath ) and -e $inputFilePath;  #FIXME -- let's try to insure that the input file always exists, even for revert.
  515 
  516   $self->addmessage($r->param('status_message') ||'');  # record status messages carried over if this is a redirect
  517   $self->addbadmessage("Changes in this file have not yet been permanently saved.") if -r $tempFilePath;
  518 
  519     $self->addbadmessage("This file '$inputFilePath' is protected! ".CGI::br()."To edit this text you must either 'Make a local copy' of this problem, or
  520                            use 'Save As' to save it to another file.") if $protected_file;
  521 
  522 }
  523 
  524 sub path {
  525   my ($self, $args) = @_;
  526   my $r = $self->r;
  527   my $urlpath = $r->urlpath;
  528   my $courseName  = $urlpath->arg("courseID");
  529   my $setName = $r->urlpath->arg("setID") || '';
  530   my $problemNumber = $r->urlpath->arg("problemID") || '';
  531 
  532   # we need to build a path to the problem being edited by hand, since it is not the same as the urlpath
  533   # For this page the bread crum path leads back to the problem being edited, not to the Instructor tool.
  534   my @path = ( 'WeBWork', $r->location,
  535             "$courseName", $r->location."/$courseName",
  536             "$setName",    $r->location."/$courseName/$setName",
  537             "$problemNumber", $r->location."/$courseName/$setName/$problemNumber",
  538             "Editor", ""
  539   );
  540 
  541   #print "\n<!-- BEGIN " . __PACKAGE__ . "::path -->\n";
  542   print $self->pathMacro($args, @path);
  543   #print "<!-- END " . __PACKAGE__ . "::path -->\n";
  544 
  545   return "";
  546 }
  547 sub title {
  548   my $self = shift;
  549   my $r = $self->r;
  550   my $problemNumber = $r->urlpath->arg("problemID");
  551   my $file_type = $self->{'file_type'} || '';
  552   return "Set Header" if ($file_type eq 'set_header');
  553   return "Hardcopy Header" if ($file_type eq 'hardcopy_header');
  554   return "Course Information" if($file_type eq 'course_info');
  555   return 'Problem ' . $r->{urlpath}->name;
  556 }
  557 
  558 sub body {
  559   my ($self) = @_;
  560   my $r = $self->r;
  561   my $db = $r->db;
  562   my $ce = $r->ce;
  563   my $authz = $r->authz;
  564   my $user = $r->param('user');
  565   my $make_local_copy = $r->param('make_local_copy');
  566 
  567   # Check permissions
  568   return CGI::div({class=>"ResultsWithError"}, "You are not authorized to access the Instructor tools.")
  569     unless $authz->hasPermissions($user, "access_instructor_tools");
  570 
  571   return CGI::div({class=>"ResultsWithError"}, "You are not authorized to modify problems.")
  572     unless $authz->hasPermissions($user, "modify_student_data");
  573 
  574 
  575   # Gathering info
  576   my $editFilePath    = $self->{editFilePath}; # path to the permanent file to be edited
  577   my $tempFilePath    = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file)
  578   my $inputFilePath   = $self->{inputFilePath};   # path to the file for input, (might be a .tmp file)
  579   my $setName         = $r->urlpath->arg("setID") ;
  580   my $problemNumber   = $r->urlpath->arg("problemID") ;
  581     $setName            = defined($setName) ? $setName : '';  # we need this instead of using the || construction
  582                                                               # to keep set 0 from being set to the
  583                                                               # empty string.
  584     $problemNumber      = defined($problemNumber) ? $problemNumber : '';
  585 
  586 
  587   #########################################################################
  588   # Find the text for the problem, either in the tmp file, if it exists
  589   # or in the original file in the template directory
  590   # or in the problem contents gathered in the initialization phase.
  591   #########################################################################
  592 
  593   my $problemContents = ${$self->{r_problemContents}};
  594 
  595   unless ( $problemContents =~/\S/)   { # non-empty contents
  596     if (-r $tempFilePath and not -d $tempFilePath) {
  597       eval { $problemContents = WeBWorK::Utils::readFile($tempFilePath) };
  598       $problemContents = $@ if $@;
  599       $inputFilePath = $tempFilePath;
  600     } elsif  (-r $editFilePath and not -d $editFilePath) {
  601       eval { $problemContents = WeBWorK::Utils::readFile($editFilePath) };
  602       $problemContents = $@ if $@;
  603       $inputFilePath = $editFilePath;
  604     } else { # file not existing is not an error
  605         #warn "No file exists";
  606       $problemContents = '';
  607     }
  608   } else {
  609     #warn "obtaining input from r_problemContents";
  610   }
  611 
  612   my $protected_file = not -w $inputFilePath;
  613   my $header = CGI::i("Editing problem".CGI::b("set $setName/ problem $problemNumber</emphasis>").CGI::br()." in file $inputFilePath");
  614   $header = ($inputFilePath =~ /$TEMPFILESUFFIX/) ? CGI::div({class=>'temporaryFile'},$header) : $header;  # use colors if temporary file
  615 
  616   #########################################################################
  617   # Format the page
  618   #########################################################################
  619 
  620   # Define parameters for textarea
  621   # FIXME
  622   # Should the seed be set from some particular user instance??
  623   my $rows            = 20;
  624   my $columns         = 80;
  625   my $mode_list       = $ce->{pg}->{displayModes};
  626   my $displayMode     = $self->{displayMode};
  627   my $problemSeed     = $self->{problemSeed};
  628   my $uri             = $r->uri;
  629   my $edit_level      = $r->param('edit_level') || 0;
  630   my $file_type        = $self->{file_type};
  631 
  632   my $force_field = defined($r->param('sourceFilePath')) ?
  633     CGI::hidden(-name=>'sourceFilePath',
  634                 -default=>$r->param('sourceFilePath')) : '';
  635 
  636   my @allSetNames = sort $db->listGlobalSets;
  637   for (my $j=0; $j<scalar(@allSetNames); $j++) {
  638     $allSetNames[$j] =~ s|^set||;
  639     $allSetNames[$j] =~ s|\.def||;
  640   }
  641   my $target = "problem$edit_level";
  642   # Prepare Preview button
  643     my $view_problem_form = CGI::start_form({method=>"POST", name=>"editor", action=>"$uri", target=>$target, enctype=>"application/x-www-form-urlencoded"}).
  644     $self->hidden_authen_fields.
  645     $force_field.
  646     CGI::hidden(-name=>'file_type',-default=>$self->{file_type}).
  647     CGI::hidden(-name=>'problemSeed',-default=>$problemSeed).
  648     CGI::hidden(-name=>'displayMode',-default=>$displayMode).
  649     CGI::hidden(-name=>'problemContents',-default=>$problemContents).
  650     CGI::submit(-value=>'View  problem',-name=>'submit').
  651     CGI::end_form();
  652   # Prepare add to set  buttons
  653     my $add_files_to_set_buttons = '';
  654   if ($file_type eq 'problem' or $file_type eq 'source_path_for_problem_file' or $file_type eq 'blank_problem' ) {
  655     $add_files_to_set_buttons .= CGI::submit(-value=>'Add problem to: ',-name=>'submit' ) ;
  656   }
  657   if ($file_type eq 'set_header'      # set header or the problem number is not a regular positive number
  658         or ( $file_type =~ /problem/ and ($problemNumber =~ /\D|^0$|^$/ )) ){
  659     $add_files_to_set_buttons .=CGI::submit(-value=>'Make this the set header for: ',-name=>'submit' );
  660   }
  661   # Add pop-up menu for the target set if either of these buttons has been revealed.
  662   $add_files_to_set_buttons .= CGI::popup_menu(-name=>'target_set',-values=>\@allSetNames, -default=>$setName) if $add_files_to_set_buttons;
  663 
  664 
  665   return CGI::p($header),
  666     CGI::start_form({method=>"POST", name=>"editor", action=>"$uri", target=>$target, enctype=>"application/x-www-form-urlencoded"}),
  667     $self->hidden_authen_fields,
  668     $force_field,
  669     CGI::hidden(-name=>'file_type',-default=>$self->{file_type}),
  670     CGI::div(
  671       'Seed: ',
  672       CGI::textfield(-name=>'problemSeed',-value=>$problemSeed),
  673       'Mode: ',
  674       CGI::popup_menu(-name=>'displayMode', -values=>$mode_list, -default=>$displayMode),
  675       CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"},
  676         '&nbsp;Manpages&nbsp;',
  677       ),
  678       CGI::a({-href=>'http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/PGmacrosByFile',-target=>"manpage_window"},
  679         '&nbsp;macro list&nbsp;',
  680       ),
  681       CGI::a({-href=>'http://devel.webwork.rochester.edu/doc/cvs/pg_HEAD/',-target=>"manpage_window"},
  682         '&nbsp;pod docs&nbsp;',
  683       ),
  684     ),
  685     CGI::p(
  686       CGI::textarea(
  687         -name => 'problemContents', -default => $problemContents,
  688         -rows => $rows, -columns => $columns, -override => 1,
  689       ),
  690     ),
  691     CGI::p(
  692             $add_files_to_set_buttons,
  693       CGI::br(),
  694       CGI::submit(-value=>'View  problem',-name=>'submit'),
  695       $protected_file ? CGI::submit(-value=>'Save',-name=>'submit', -disabled=>1) : CGI::submit(-value=>'Save',-name=>'submit'),
  696       CGI::submit(-value=>'Revert', -name=>'submit'),
  697       CGI::submit(-value=>'Save as',-name=>'submit'),
  698       CGI::textfield(-name=>'save_to_new_file', -size=>40, -value=>""),
  699 
  700     ),
  701     # allow one to make a local copy if the viewed file can't be edited.  #FIXME the method for determining the localfilePath needs work
  702     (-w $editFilePath) ? "" : CGI::p(CGI::hr(),
  703             CGI::submit(-value=>'Make local copy at: ',-name=>'submit'), "[TMPL]/".determineLocalFilePath($editFilePath),
  704             CGI::hidden(-name=>'local_copy_file_path', -value=>determineLocalFilePath($editFilePath) )
  705     ),
  706     CGI::end_form();
  707 
  708 
  709 }
  710 
  711 ################################################################################
  712 # Utilities
  713 ################################################################################
  714 
  715 # determineLocalFilePath   constructs a local file path parallel to a library file path
  716 # This is a subroutine, not a method
  717 #
  718 sub determineLocalFilePath {
  719   my $path = shift;
  720   if ($path =~ /Library/) {
  721     $path =~ s|^.*?Library/||;  # truncate the url up to a segment such as ...rochesterLibrary/.......
  722   } else { # if its not in a library we'll just save it locally
  723     $path = "new_problem_".rand(40);  #l hope there aren't any collisions.
  724   }
  725     $path;
  726 
  727 }
  728 sub getFilePaths {
  729   my ($self, $setName, $problemNumber, $file_type, $TEMPFILESUFFIX) = @_;
  730   my $r = $self->r;
  731   my $ce = $r->ce;
  732   my $db = $r->db;
  733   my $urlpath = $r->urlpath;
  734   my $courseName = $urlpath->arg("courseID");
  735   my $user = $r->param('user');
  736   my $effectiveUserName = $r->param('effectiveUser');
  737 
  738   $setName = '' unless defined $setName;
  739   $problemNumber = '' unless defined $problemNumber;
  740   die 'Internal error to PGProblemEditor -- file type is not defined'  unless defined $file_type;
  741 
  742   ##########################################################
  743   # Determine path to the input file to be edited.
  744   # set EditFilePath to this value
  745   #
  746   # There are potentially four files in play
  747   #   The permanent path of the input file  == $editFilePath == $self->{problemPath}
  748   #   A temporary path to the input file    == $tempFilePath== "$editFilePath.$TEMPFILESUFFIX"== $self->{problemPath}
  749   ##########################################################
  750   # Relevant parameters
  751   #     $r->param("displayMode")
  752   #     $r->param('problemSeed')
  753   #     $r->param('submit')
  754   #     $r->param('make_local_copy')
  755   #     $r->param('sourceFilePath')
  756   #     $r->param('problemContents')
  757   #     $r->param('save_to_new_file')
  758   ##########################################################################
  759   # Define the following  variables
  760   #   path to regular file -- $self->{problemPath} = $editFilePath;
  761   #     path to file being read (temporary or permanent)
  762   #               --- $self->{problemPath} = $problemPath;
  763   #       contents of the file being read  --- $problemContents
  764   #         $self->{r_problemContents}        =   \$problemContents;
  765   #       $self->{TEMPFILESUFFIX}           =   $TEMPFILESUFFIX;
  766     ###########################################################################
  767 
  768   my $editFilePath = $ce->{courseDirs}->{templates};
  769 
  770     ##########################################################################
  771     # Determine path to regular file, place it in $editFilePath
  772     # problemSeed is defined for the file_type = 'problem' and 'source_path_to_problem'
  773     ##########################################################################
  774   CASE:
  775   {
  776     ($file_type eq 'course_info') and do {
  777       # we are editing the course_info file
  778       # value of courseFiles::course_info is relative to templates directory
  779       $editFilePath           .= '/' . $ce->{courseFiles}->{course_info};
  780       last CASE;
  781     };
  782 
  783     ($file_type eq 'blank_problem') and do {
  784       $editFilePath = $ce->{webworkFiles}->{screenSnippets}->{blankProblem};
  785       $self->addbadmessage("$editFilePath is blank problem template file and should not be edited directly. "
  786                            ."First use 'Save as' to make a local copy, then add the file to the current problem set, then edit the file."
  787       );
  788       last CASE;
  789     };
  790 
  791     ($file_type eq 'set_header' or $file_type eq 'hardcopy_header') and do {
  792       # first try getting the merged set for the effective user
  793       my $set_record = $db->getMergedSet($effectiveUserName, $setName); # checked
  794       # if that doesn't work (the set is not yet assigned), get the global record
  795       $set_record = $db->getGlobalSet($setName); # checked
  796       # bail if no set is found
  797       die "Cannot find a set record for set $setName" unless defined($set_record);
  798 
  799       my $header_file = "";
  800       $header_file = $set_record->{$file_type};
  801       if ($header_file && $header_file ne "") {
  802           $editFilePath .= '/' . $header_file;
  803       } else {
  804           # if the set record doesn't specify the filename
  805           # then the set uses the default from snippets
  806           # so we'll load that file, but change where it will be saved
  807           # to and grey out the "Save" button
  808           # FIXME why does the make_local_copy variable need to be checked?
  809           # Isn't it automatic that a local copy has to be made?
  810           #if ($r->param('make_local_copy')) {
  811             $editFilePath = $ce->{webworkFiles}->{screenSnippets}->{setHeader} if $file_type eq 'set_header';
  812             $editFilePath = $ce->{webworkFiles}->{hardcopySnippets}->{setHeader} if $file_type eq 'hardcopy_header';
  813             $self->addbadmessage("$editFilePath is the default header file and cannot be edited directly.");
  814             $self->addbadmessage("Any changes you make will have to be saved as another file.");
  815           #}
  816       }
  817       last CASE;
  818     }; #end 'set_header, hardcopy_header' case
  819 
  820     ($file_type eq 'problem') and do {
  821 
  822       # first try getting the merged problem for the effective user
  823       my $problem_record = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked
  824 
  825       # if that doesn't work (the problem is not yet assigned), get the global record
  826       $problem_record = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem_record); # checked
  827       # bail if no source path for the problem is found ;
  828         die "Cannot find a problem record for set $setName / problem $problemNumber" unless defined($problem_record);
  829       $editFilePath .= '/' . $problem_record->source_file;
  830       # define the problem seed for later use
  831       $self->{problemSeed}= $problem_record->problem_seed if  defined($problem_record) and  $problem_record->can('problem_seed') ;
  832       last CASE;
  833     };  # end 'problem' case
  834 
  835     ($file_type eq 'source_path_for_problem_file') and do {
  836       my $forcedSourceFile = $r->param('sourceFilePath');
  837       # bail if no source path for the problem is found ;
  838       die "Cannot find a file path to save to" unless( defined($forcedSourceFile) and ($forcedSourceFile =~ /\S/)  );
  839       $self->{problemSeed} = 1234;
  840       $editFilePath .= '/' . $forcedSourceFile;
  841       last CASE;
  842     }; # end 'source_path_for_problem_file' case
  843   }  # end CASE: statement
  844 
  845 
  846   # if a set record or problem record contains an empty blank for a header or problem source_file
  847   # we could find ourselves trying to edit /blah/templates/.toenail.tmp or something similar
  848   # which is almost undoubtedly NOT desirable
  849 
  850   if (-d $editFilePath) {
  851     my $msg = "The file $editFilePath is a directory!";
  852     $self->{failure} = 1;
  853     $self->addbadmessage($msg);
  854   }
  855   if (-e $editFilePath and not -r $editFilePath) {   #it's ok if the file doesn't exist, perhaps we're going to create it
  856                                                     # with save as
  857     my $msg = "The file $editFilePath cannot be read!";
  858     $self->{failure} = 1;
  859     $self->addbadmessage($msg);
  860   }
  861     #################################################
  862   # The path to the permanent file is now verified and stored in $editFilePath
  863   # Whew!!!
  864   #################################################
  865 
  866   my $tempFilePath = "$editFilePath.$TEMPFILESUFFIX";
  867   $self->{editFilePath}   = $editFilePath;
  868   $self->{tempFilePath}   = $tempFilePath;
  869   $self->{inputFilePath}  = (-r "$editFilePath.$TEMPFILESUFFIX") ? $tempFilePath : $editFilePath;
  870 
  871 }
  872 
  873 ################################################################################
  874 # saveFileChanges does most of the work. it is a separate method so that it can
  875 # be called from either pre_header_initialize() or initilize(), depending on
  876 # whether a redirect is needed or not.
  877 #
  878 # it actually does a lot more than save changes to the file being edited, and
  879 # sometimes less.
  880 ################################################################################
  881 sub saveFileChanges {
  882   my ($self, $setName, $problemNumber, $file_type, $TEMPFILESUFFIX) = @_;
  883   my $r = $self->r;
  884   my $ce = $r->ce;
  885   my $db = $r->db;
  886   my $urlpath = $r->urlpath;
  887 
  888   my $courseName = $urlpath->arg("courseID");
  889   my $user = $r->param('user');
  890   my $effectiveUserName = $r->param('effectiveUser');
  891 
  892   $setName       = '' unless defined $setName;
  893   $problemNumber = '' unless defined $problemNumber;
  894   $file_type     = '' unless defined $file_type;
  895 
  896   my $action        = $self->{action};
  897   my $editFilePath  = $self->{editFilePath};
  898   my $tempFilePath  = $self->{tempFilePath};
  899   ##############################################################################
  900   # read and update the targetFile and targetFile.tmp files in the directory
  901   # if a .tmp file already exists use that, unless the revert button has been pressed.
  902   # These .tmp files are
  903   # removed when the file is finally saved.
  904   # Place the path of the file to be read in $problemPath.
  905   ##############################################################################
  906 
  907 
  908   my $problemContents = '';
  909   my $outputFilePath = undef;   # this is actually the output file for this subroutine
  910                                 # it is then read in as source in the body of this module
  911   my $do_not_save    = 0;       # flag to prevent saving of file
  912   my $editErrors = '';
  913 
  914   ##########################################################################
  915   # For each of the actions define the following  variables:
  916   #
  917   #   path to permanent file -- $self->{problemPath} = $editFilePath;
  918   #     path to file being read (temporary or permanent)
  919   #               --- $self->{problemPath} = $problemPath;
  920   #       contents of the file being read  --- $problemContents
  921   #         $self->{r_problemContents}        =   \$problemContents;
  922   #
  923   #################################
  924   # handle button clicks #####
  925   # Read contents of file
  926   #################################
  927   ACTION_CASES: {
  928     ($action eq 'fresh_edit') and do {
  929       # this is a fresh editing job
  930             # the original file will be read in the body
  931       last ACTION_CASES;
  932     };
  933 
  934       ($action eq 'revert') and do {
  935       # this is also fresh editing job
  936       $outputFilePath = undef;
  937       $self->addgoodmessage("Reverting to original file $editFilePath");
  938       $self->{problemPath} = $editFilePath;
  939       $self->{inputFilePath}=$editFilePath;
  940       last ACTION_CASES;
  941     };
  942 
  943     ($action eq 'refresh') and do {
  944       # grab the problemContents from the form in order to save it to the tmp file
  945       # store tmp file name in the $self->problemPath for use in body
  946 
  947       $problemContents = $r->param('problemContents');
  948       $outputFilePath = "$editFilePath.$TEMPFILESUFFIX";
  949       $self->{problemPath} = $outputFilePath;
  950       last ACTION_CASES;
  951     };
  952 
  953     ($action eq 'save') and do {
  954       # grab the problemContents from the form in order to save it to the permanent file
  955       # later we will unlink (delete) the temporary file
  956       # store permanent file name in the $self->problemPath for use in body
  957       $problemContents = $r->param('problemContents');
  958       $outputFilePath = "$editFilePath";
  959       $self->{problemPath} = $outputFilePath;
  960       #$self->addgoodmessage("Saving to file $outputFilePath");
  961       last ACTION_CASES;
  962     };
  963 
  964     ($action eq 'save_as') and do {
  965       my $new_file_name =$r->param('save_to_new_file') || '';
  966       #################################################
  967       #bail unless this new file name has been defined
  968       #################################################
  969       if ( $new_file_name !~ /\S/) { # need a non-blank file name
  970           # setting $self->{failure} stops saving and any redirects
  971           $do_not_save = 1;
  972           warn "new file name is $new_file_name";
  973           $self->addbadmessage(CGI::p("Please specify a file to save to."));
  974           last ACTION_CASES;  #stop processing
  975       }
  976       #################################################
  977       # grab the problemContents from the form in order to save it to a new permanent file
  978       # later we will unlink (delete) the current temporary file
  979       # store new permanent file name in the $self->problemPath for use in body
  980       #################################################
  981       $problemContents = $r->param('problemContents');
  982 
  983       #################################################
  984       # Rescue the user in case they forgot to end the file name with .pg
  985       #################################################
  986       if($self->{file_type} eq 'problem'
  987         or $self->{file_type} eq 'blank_problem'
  988         or $self->{file_type} eq 'set_header') {
  989           $new_file_name =~ s/\.pg$//; # remove it if it is there
  990           $new_file_name .= '.pg'; # put it there
  991 
  992       }
  993 
  994       #################################################
  995       # check to prevent overwrites:
  996       #################################################
  997       $outputFilePath = $ce->{courseDirs}->{templates} . '/' .
  998                      $new_file_name;
  999 
 1000       if (defined $outputFilePath and -e $outputFilePath) {
 1001         # setting $do_not_save stops saving and any redirects
 1002         $do_not_save = 1;
 1003         $self->addbadmessage(CGI::p("File $outputFilePath exists.  File not saved."));
 1004       } else {
 1005         #$self->addgoodmessage("Saving to file $outputFilePath.");
 1006       }
 1007       $self->{problemPath} = $outputFilePath;
 1008       last ACTION_CASES;
 1009     };
 1010     ($action eq 'make_local_copy') and do {
 1011       my $new_file_name =$r->param('local_copy_file_path') || '';
 1012       #################################################
 1013       #bail unless this new file name has been defined
 1014       #################################################
 1015       if ( $new_file_name !~ /\S/) { # need a non-blank file name
 1016           # setting $self->{failure} stops saving and any redirects
 1017           $do_not_save = 1;
 1018           warn "new file name is $new_file_name";
 1019           $self->addbadmessage(CGI::p("Please specify a file to save to."));
 1020           last ACTION_CASES;  #stop processing
 1021       }
 1022       #################################################
 1023       # grab the problemContents from the form in order to save it to a new permanent file
 1024       # later we will unlink (delete) the current temporary file
 1025       # store new permanent file name in the $self->problemPath for use in body
 1026       #################################################
 1027       $problemContents = $r->param('problemContents');
 1028 
 1029       #################################################
 1030       # Rescue the user in case they forgot to end the file name with .pg
 1031       #################################################
 1032       if($self->{file_type} eq 'problem'
 1033         or $self->{file_type} eq 'blank_problem'
 1034         or $self->{file_type} eq 'set_header') {
 1035           $new_file_name =~ s/\.pg$//; # remove it if it is there
 1036           $new_file_name .= '.pg'; # put it there
 1037 
 1038       }
 1039 
 1040       #################################################
 1041       # check to prevent overwrites:
 1042       #################################################
 1043       $outputFilePath = $ce->{courseDirs}->{templates} . '/' .
 1044                      $new_file_name;
 1045 
 1046       if (defined $outputFilePath and -e $outputFilePath) {
 1047         # setting $do_not_save stops saving and any redirects
 1048         $do_not_save = 1;
 1049         $self->addbadmessage(CGI::p("There is already a file at [TMPL]/$new_file_name.  File not saved."));
 1050       } else {
 1051         $self->addgoodmessage("A local copy of $editFilePath is being made...") ;
 1052       }
 1053       $self->{problemPath} = $outputFilePath;
 1054       #################################################
 1055       # if new file has been successfully saved change the file path name for the problem
 1056       #################################################
 1057       unless ($do_not_save) {
 1058         my $problemRecord = $db->getGlobalProblem($setName,$problemNumber);
 1059         $problemRecord->source_file($new_file_name);
 1060         if  ( $db->putGlobalProblem($problemRecord)  ) {
 1061           $self->addgoodmessage("A local, editable, copy of $new_file_name has been made for problem $problemNumber.") ;
 1062           $self->{problemPath} = $outputFilePath;   # define the file path for redirect
 1063         } else {
 1064           $self->addbadmessage("Unable to change the source file path for set $setName, problem $problemNumber. Unknown error.");
 1065         }
 1066       }
 1067 
 1068 
 1069 
 1070       last ACTION_CASES;
 1071     };
 1072     ($action eq 'add_problem_to_set') and do {
 1073         my $sourceFile = $editFilePath;
 1074         my $targetSetName  = $r->param('target_set');
 1075         my $freeProblemID  = WeBWorK::Utils::max($db->listGlobalProblems($targetSetName)) + 1;
 1076         $sourceFile    =~ s|^$ce->{courseDirs}->{templates}/||;
 1077         my $problemRecord  = $self->addProblemToSet(
 1078                      setName        => $targetSetName,
 1079                      sourceFile     => $sourceFile,
 1080                      problemID      => $freeProblemID
 1081         );
 1082         $self->assignProblemToAllSetUsers($problemRecord);
 1083         $self->addgoodmessage("Added $sourceFile to ". $targetSetName. " as problem $freeProblemID") ;
 1084         $outputFilePath = undef;   # don't save any files
 1085         $self->{problemPath} = $editFilePath;
 1086 
 1087     };
 1088     ($action eq 'add_set_header_to_set') and do {
 1089         my $sourceFile = $editFilePath;
 1090         my $targetSetName  = $r->param('target_set');
 1091         $sourceFile    =~ s|^$ce->{courseDirs}->{templates}/||;
 1092         my $setRecord  = $db->getGlobalSet($targetSetName);
 1093         $setRecord->set_header($sourceFile);
 1094         if(  $db->putGlobalSet($setRecord) ) {
 1095           $self->addgoodmessage("Added $sourceFile to ". $targetSetName. " as new set header ") ;
 1096         } else {
 1097           $do_not_save = 1 ;
 1098           $self->addbadmessage("Unable to make $sourceFile the set header for $targetSetName");
 1099         }
 1100         # change file type to set_header if it not already so
 1101         $self->{file_type} = 'set_header';
 1102         $outputFilePath = undef;   # don't save any files
 1103         $self->{problemPath} = $editFilePath;
 1104 
 1105     };
 1106       last ACTION_CASES;
 1107 
 1108     die "Unrecognized action command: $action";
 1109   }; # end ACTION_CASES
 1110 
 1111 
 1112 
 1113   ##############################################################################
 1114   # write changes to the approriate files
 1115   # FIXME  make sure that the permissions are set correctly!!!
 1116   # Make sure that the warning is being transmitted properly.
 1117   ##############################################################################
 1118 
 1119   my $writeFileErrors;
 1120   if ( defined($outputFilePath) and $outputFilePath =~/\S/ and ! $do_not_save ) {   # save file
 1121       # Handle the problem of line endings.
 1122     # Make sure that all of the line endings are of unix type.
 1123     # Convert \r\n to \n
 1124     $problemContents =~ s/\r\n/\n/g;
 1125     $problemContents =~ s/\r/\n/g;
 1126 
 1127     # make sure any missing directories are created
 1128     $outputFilePath = WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates},
 1129                                                             $outputFilePath);
 1130 
 1131     eval {
 1132       local *OUTPUTFILE;
 1133       open OUTPUTFILE, ">", $outputFilePath
 1134           or die "Failed to open $outputFilePath";
 1135       print OUTPUTFILE $problemContents;
 1136       close OUTPUTFILE;
 1137     };  # any errors are caught in the next block
 1138 
 1139     $writeFileErrors = $@ if $@;
 1140   }
 1141 
 1142   ###########################################################
 1143   # Catch errors in saving files,  clean up temp files
 1144   ###########################################################
 1145 
 1146   $self->{failure} = $do_not_save;    # don't do redirects if the file was not saved.
 1147                                       # don't unlink files or send success messages
 1148 
 1149   if ($writeFileErrors) {
 1150       # get the current directory from the outputFilePath
 1151     $outputFilePath =~ m|^(/.*?/)[^/]+$|;
 1152     my $currentDirectory = $1;
 1153 
 1154     my $errorMessage;
 1155     # check why we failed to give better error messages
 1156     if ( not -w $ce->{courseDirs}->{templates} ) {
 1157       $errorMessage = "Write permissions have not been enabled in the templates directory.  No changes can be made.";
 1158     } elsif ( not -w $currentDirectory ) {
 1159       $errorMessage = "Write permissions have not been enabled in $currentDirectory.  Changes must be saved to a different directory for viewing.";
 1160     } elsif ( -e $outputFilePath and not -w $outputFilePath ) {
 1161       $errorMessage = "Write permissions have not been enabled for $outputFilePath.  Changes must be saved to another file for viewing.";
 1162     } else {
 1163       $errorMessage = "Unable to write to $outputFilePath: $writeFileErrors";
 1164     }
 1165 
 1166     $self->{failure} = 1;
 1167     $self->addbadmessage(CGI::p($errorMessage));
 1168 
 1169   }
 1170   unless( $writeFileErrors or $do_not_save) {  # everything worked!  unlink and announce success!
 1171     # unlink the temporary file if there are no errors and the save button has been pushed
 1172     if ($action eq 'save' or $action eq 'save_as' or $action eq 'revert') {
 1173                  unlink($self->{tempFilePath}) ;
 1174     }
 1175     if ( defined($outputFilePath) and ! $self->{failure} )  {
 1176       my $msg = "Saved to file: $outputFilePath";
 1177       $self->addgoodmessage($msg);
 1178     }
 1179 
 1180   }
 1181 
 1182   # return values for use in the body subroutine
 1183   #  The path to the current permanent file being edited:
 1184   #           $self->{problemPath} = $editFilePath;
 1185   #  The path to the current temporary file (if any). If no temporary file this the same
 1186   #  as the permanent file path:
 1187   #       $self->{outputFilePath} = $outputFilePath;
 1188   #
 1189 
 1190   $self->{r_problemContents}        =   \$problemContents;
 1191 }  # end saveFileChanges
 1192 
 1193 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9