From: Mike G. v. a. <we...@ma...> - 2005-10-17 03:43:28
|
Log Message: ----------- Refactored much of the action in PGProblemEditor.pm This allows a user inteface which mimics the interface for the Hmwk sets editor and for the Classlist editor. It also allows all of the temporary edit files to be placed in one location. This allows one to "temporarily" edit a library file to try to see what is wrong with it. It is also now much easier to make a local copy of a library file for your current problem set so that you can tweak it. It has been fairly well tested by one person (me) but there may still be bugs. -- Mike Modified Files: -------------- webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor: PGProblemEditor.pm Revision Data ------------- Index: PGProblemEditor.pm =================================================================== RCS file: /webwork/cvs/system/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v retrieving revision 1.57 retrieving revision 1.58 diff -Llib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm -Llib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm -u -r1.57 -r1.58 --- lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm +++ lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm @@ -18,6 +18,7 @@ use base qw(WeBWorK::ContentGenerator::Instructor); + =head1 NAME WeBWorK::ContentGenerator::Instructor::PGProblemEditor - Edit a pg file @@ -62,9 +63,9 @@ # the information for retrieving the source file is found using the problemID in order to look # look up the source file path. # -# file_type eq 'problem_with_source' +# file_type eq 'source_path_for_problem_file' # This is the same as the 'problem' file type except that the source for the problem is found in -# the parameter $r->param('sourceFilePath'). +# the parameter $r->param('sourceFilePath'). This path is relative to the templates directory # # file_type eq 'set_header' # 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. @@ -82,12 +83,12 @@ # This is a special call which allows one to create and edit a new PG problem. The "stationery" source for this problem is # stored in the conf/snippets directory and defined in global.conf by $webworkFiles{screenSnippets}{blankProblem} ############################################################# -# submit button actions -- these and the file_type determine the state of the module +# Requested actions -- these and the file_type determine the state of the module # Save ---- action = save # Save as ---- action = save_as -# View Problem ---- action = refresh -# Add this problem to: ---- action = add_problem_to_set -# Make this set header for: ---- action = add_set_header_to_set +# View Problem ---- action = view +# Add this problem to: ---- action = add_problem +# Make this set header for: ---- action = add_problem # Revert ---- action = revert # no submit button defined ---- action = fresh_edit ################################################### @@ -95,9 +96,8 @@ # Determining which is the correct path to the file is a mess!!! FIXME # The path to the file to be edited is eventually put in tempFilePath # -# $problemPath is also used as is editFilePath. let's try to regularize these. -#(sourceFile) (problemPath)(tempFilePath)(editFilePath)(forcedSourceFile)(problemPath) -#input parameter can be: sourceFilePath +# (tempFilePath)(editFilePath)(forcedSourceFile) +#input parameter is: sourceFilePath ################################################################# # params read # user @@ -113,9 +113,18 @@ # save_to_new_file # -#our $libraryName; -#our $rowheight; -our $TEMPFILESUFFIX; +use constant ACTION_FORMS => [qw(view add_problem make_local_copy save save_as revert)]; #[qw(view save save_as revert add_problem add_header make_local_copy)]; + +# permissions needed to perform a given action +use constant FORM_PERMS => { + view => "modify_student_data", + add_problem => "modify_student_data", + make_local_copy => "modify_student_data", + save => "modify_student_data", + save_as => "modify_student_data", + revert => "modify_student_data", +}; + sub pre_header_initialize { my ($self) = @_; @@ -124,17 +133,45 @@ my $urlpath = $r->urlpath; my $authz = $r->authz; my $user = $r->param('user'); - $TEMPFILESUFFIX = $user.'.tmp'; + $self->{courseID} = $urlpath->arg("courseID"); + $self->{setID} = $r->urlpath->arg("setID") ; # using $r->urlpath->arg("setID") ||'' causes trouble with set 0!!! + $self->{problemID} = $r->urlpath->arg("problemID"); my $submit_button = $r->param('submit'); # obtain submit command from form + my $actionID = $r->param('action'); my $file_type = $r->param("file_type") || ''; - my $setName = $r->urlpath->arg("setID") ; # using $r->urlpath->arg("setID") ||'' causes trouble with set 0!!! - my $problemNumber = $r->urlpath->arg("problemID"); + my $setName = $self->{setID}; + my $problemNumber = $self->{problemID}; # Check permissions return unless ($authz->hasPermissions($user, "access_instructor_tools")); return unless ($authz->hasPermissions($user, "modify_problem_sets")); + ############################################################################## + # displayMode and problemSeed + # + # Determine the display mode + # If $self->{problemSeed} was obtained within saveFileChanges from the problem_record + # then it can be overridden by the value obtained from the form. + # Insure that $self->{problemSeed} has some non-empty value + # displayMode and problemSeed + # will be needed for viewing the problem via redirect. + # They are also two of the parameters which can be set by the editor + ############################################################################## + + if (defined $r->param('displayMode')) { + $self->{displayMode} = $r->param('displayMode'); + } else { + $self->{displayMode} = $ce->{pg}->{options}->{displayMode}; + } + + # form version of problemSeed overrides version obtained from the the problem_record + # inside saveFileChanges + $self->{problemSeed} = $r->param('problemSeed') if (defined $r->param('problemSeed')); + # Make sure that the problem seed has some value + $self->{problemSeed} = '123456' unless defined $self->{problemSeed} and $self->{problemSeed} =~/\S/; + + ############################################################################## ############################################################################# # Save file to permanent or temporary file, then redirect for viewing ############################################################################# @@ -159,7 +196,7 @@ if (defined($file_type) and ($file_type =~/\S/)) { #file_type is defined and is not blank # file type is already defined -- do nothing } else { - # if "sourcFilePath" is defined in the form, then we are getting the path directly. + # if "sourceFilePath" is defined in the form, then we are getting the path directly. # if the problem number is defined and is 0 # then we are dealing with some kind of # header file. The default is 'set_header' which prints properly @@ -179,85 +216,71 @@ } } die "The file_type variable has not been defined or is blank." unless defined($file_type) and $file_type =~/\S/; + # clean up sourceFilePath, just in case + # double check that sourceFilePath is relative to the templates file + if ($file_type eq 'source_path_for_problem_file' ) { + my $templatesDirectory = $ce->{courseDirs}->{templates}; + my $sourceFilePath = $r->param('sourceFilePath'); + $sourceFilePath =~ s/$templatesDirectory//; + $sourceFilePath =~ s|^/||; # remove intial / + $self->{sourceFilePath} = $sourceFilePath; + } $self->{file_type} = $file_type; ########################################## - # File type is one of: blank_problem course_info problem set_header hardcopy_header problem_with_source + # File type is one of: blank_problem course_info problem set_header hardcopy_header source_path_for_problem_file ########################################## # # Determine the path to the file # ########################################### - $self->getFilePaths($setName, $problemNumber, $file_type,$TEMPFILESUFFIX); - # result stored in $self->{editFilePath}, and $self->{tempFilePath} - ########################################## - # - # Determine action - # - ########################################### - # Submit button is one of: "add this problem to" , "add this set header to ", "Refresh" "Revert" "Save" "Save As" - $submit_button = $r->param('submit'); - SUBMIT_CASE: { - (! defined($submit_button) ) and do { # fresh problem to edit - $self->{action} = 'fresh_edit'; - last SUBMIT_CASE; - }; + $self->getFilePaths($setName, $problemNumber, $file_type); + #defines $self->{editFilePath} # path to the permanent file to be edited + # $self->{tempFilePath} # path to the permanent file to be edited has .tmp suffix + # $self->{inputFilePath} # path to the file for input, (might be a .tmp file) - ($submit_button eq 'Add this problem to: ') and do { - $self->{action} = 'add_problem_to_set'; - last SUBMIT_CASE; - }; - ($submit_button eq 'Make this the set header for: ') and do { - $self->{action} = 'add_set_header_to_set'; - last SUBMIT_CASE; - }; - ($submit_button eq 'View problem') and do { - $self->{action} ='refresh'; - last SUBMIT_CASE; - }; - - ($submit_button eq 'Revert') and do { - $self->{action} = 'revert'; - last SUBMIT_CASE; - }; - - ($submit_button eq 'Save') and do { - $self->{action} = 'save'; - last SUBMIT_CASE; - }; - - ($submit_button eq 'Save as') and do { - $self->{action} = 'save_as'; - last SUBMIT_CASE; - }; - - ($submit_button eq 'Add problem to: ') and do { - $self->{action} = 'add_problem_to_set'; - last SUBMIT_CASE; - }; - ($submit_button eq 'Make local copy at: ') and do { - $self->{action} = 'make_local_copy'; - last SUBMIT_CASE; - }; - # else - die "Unrecognized submit command: |$submit_button|"; - - } # END SUBMIT_CASE + ########################################## + # Default problem contents + ########################################## + $self->{r_problemContents}= undef; - + ########################################## + # + # Determine action + # ########################################### - # Save file - ###################################### - - # The subroutine below writes the necessary files and obtains the appropriate seed. - # and returns - # $self->{problemPath} --- file path for viewing problem in $self->{problemPath} - # $self->{failure} - - $self->saveFileChanges($setName, $problemNumber, $file_type,$TEMPFILESUFFIX); + if ($actionID) { + unless (grep { $_ eq $actionID } @{ ACTION_FORMS() } ) { + die "Action $actionID not found"; + } + # Check permissions + if (not FORM_PERMS()->{$actionID} or $authz->hasPermissions($user, FORM_PERMS()->{$actionID})) { + my $actionHandler = "${actionID}_handler"; + my %genericParams =(); +# foreach my $param (qw(selected_users)) { +# $genericParams{$param} = [ $r->param($param) ]; +# } + my %actionParams = $self->getActionParams($actionID); + my %tableParams = (); # $self->getTableParams(); + $self->{action}= $actionID; + $self->$actionHandler(\%genericParams, \%actionParams, \%tableParams); + } else { + $self->addbadmessage( "You are not authorized to perform this action."); + } + } else { + $self->{action}='fresh_edit'; + my $actionHandler = "fresh_edit_handler"; + my %genericParams; + my %actionParams = (); #$self->getActionParams($actionID); + my %tableParams = (); # $self->getTableParams(); + my $problemContents = ''; + $self->{r_problemContents}=\$problemContents; + $self->$actionHandler(\%genericParams, \%actionParams, \%tableParams); + } + ############################################################################## # displayMode and problemSeed @@ -302,200 +325,8 @@ # Some cases do not need a redirect: save, refresh, save_as, add_problem_to_set, add_header_to_set,make_local_copy my $action = $self->{action}; + return ; - return unless $action eq 'save' - or $action eq 'refresh' - or $action eq 'save_as' - or $action eq 'add_problem_to_set' - or $action eq 'make_local_copy' - or $action eq 'add_set_header_to_set'; - - - ###################################### - # calculate redirect URL based on file type - ###################################### - my $courseName = $urlpath->arg("courseID"); - my $problemSeed = ($r->param('problemSeed')) ? $r->param('problemSeed') : ''; - my $displayMode = ($r->param('displayMode')) ? $r->param('displayMode') : ''; - - my $viewURL = ''; - - ###################################### - # problem file_type - # redirect to Problem.pm with setID = "Undefined_Set if "Save As" option is chosen - # redirect to Problem.pm with setID = current $setID if "Save" or "Revert" or "Refresh is chosen" - ###################################### - REDIRECT_CASES: { - ($file_type eq 'problem' or $file_type eq 'source_path_for_problem_file' or $file_type eq 'blank_problem') and do { - my $sourceFilePath = $self->{problemPath}; - # strip off template directory prefix - $sourceFilePath =~ s|^$ce->{courseDirs}->{templates}/||; - if ($action eq 'save_as') { # redirect to myself - my $edit_level = $r->param("edit_level") || 0; - $edit_level++; - - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", - courseID => $courseName, setID => 'Undefined_Set', problemID => 'Undefined_Problem' - ); - $viewURL = $self->systemLink($problemPage, - params=>{ - sourceFilePath => $sourceFilePath, - edit_level => $edit_level, - file_type => 'source_path_for_problem_file', - status_message => uri_escape($self->{status_message}) - - } - ); - - - } elsif ( $action eq 'add_problem_to_set') { - - my $targetSetName = $r->param('target_set'); - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", - courseID => $courseName, setID => $targetSetName, - problemID => WeBWorK::Utils::max( $r->db->listGlobalProblems($targetSetName)) - ); - $viewURL = $self->systemLink($problemPage, - params => { - displayMode => $displayMode, - problemSeed => $problemSeed, - editMode => "savedFile", - sourceFilePath => $sourceFilePath, - status_message => uri_escape($self->{status_message}) - - } - ); - } elsif ($action eq 'make_local_copy') { # redirect to myself - my $edit_level = $r->param("edit_level") || 0; - $edit_level++; - - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", - courseID => $courseName, setID => $setName, problemID => $problemNumber - ); - $viewURL = $self->systemLink($problemPage, - params=>{ - sourceFilePath => $sourceFilePath, - edit_level => $edit_level, - file_type => 'source_path_for_problem_file', - status_message => uri_escape($self->{status_message}) - - } - ); - - - } elsif ( $action eq 'add_set_header_to_set') { - my $targetSetName = $r->param('target_set'); - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", - courseID => $courseName, setID => $targetSetName - ); - $viewURL = $self->systemLink($problemPage, - params => { - displayMode => $displayMode, - editMode => "savedFile", - status_message => uri_escape($self->{status_message}) - } - ); - } else { # saved problems and refreshed problems redirect to Problem.pm - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", - courseID => $courseName, setID => $setName, problemID => $problemNumber - ); - $viewURL = $self->systemLink($problemPage, - params => { - displayMode => $displayMode, - problemSeed => $problemSeed, - editMode => ($action eq "save" ? "savedFile" : "temporaryFile"), - sourceFilePath => $sourceFilePath, - status_message => uri_escape($self->{status_message}) - - } - ); - } - last REDIRECT_CASES; - }; - ###################################### - # blank_problem file_type - # redirect to Problem.pm - ###################################### - - $file_type eq 'blank_problem' and do { - return; # no redirect is needed - }; - - ###################################### - # set headers file_type - # redirect to ProblemSet.pm - ###################################### - - ($file_type eq 'set_header' or $file_type eq 'hardcopy_header' ) and do { - if ($action eq 'save_as') { # redirect to myself - my $sourceFilePath = $self->{problemPath}; - # strip off template directory prefix - $sourceFilePath =~ s|^$ce->{courseDirs}->{templates}/||; - - my $edit_level = $r->param("edit_level") || 0; - $edit_level++; - - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", - courseID => $courseName, setID => 'Undefined_Set', problemID => 'Undefined_Problem' - ); - $viewURL = $self->systemLink($problemPage, - params=>{ - sourceFilePath => $sourceFilePath, - edit_level => $edit_level, - file_type => 'source_path_for_problem_file', - status_message => uri_escape($self->{status_message}) - } - ); - } elsif ( $action eq 'add_set_header_to_set') { - my $targetSetName = $r->param('target_set'); - my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", - courseID => $courseName, setID => $targetSetName - ); - $viewURL = $self->systemLink($problemPage, - params => { - displayMode => $displayMode, - editMode => "savedFile", - status_message => uri_escape($self->{status_message}) - } - ); - } else { - my $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", - courseID => $courseName, setID => $setName); - $viewURL = $self->systemLink($problemSetPage, - params => { - displayMode => $displayMode, - problemSeed => $problemSeed, - editMode => ($action eq "save" ? "savedFile" : "temporaryFile"), - status_message => uri_escape($self->{status_message}) - } - ); - } - last REDIRECT_CASES; - }; - ###################################### - # course_info file type - # redirect to ProblemSets.pm - ###################################### - $file_type eq 'course_info' and do { - my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", - courseID => $courseName); - $viewURL = $self->systemLink($problemSetsPage, - params => { - editMode => ($action eq "save" ? "savedFile" : "temporaryFile"), - status_message => uri_escape($self->{status_message}) - } - ); - last REDIRECT_CASES; - }; - # else if no redirect needed -- there must be an error. - die "The file_type $file_type does not have a defined redirect procedure."; - } # End REDIRECT_CASES - - if ($viewURL) { - $self->reply_with_redirect($viewURL); - } else { - die "Invalid file_type $file_type specified by saveFileChanges"; - } } @@ -511,13 +342,16 @@ my $tempFilePath = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file) my $inputFilePath = $self->{inputFilePath}; # path to the file for input, (might be a .tmp file) - my $protected_file = (not -w $inputFilePath ) and -e $inputFilePath; #FIXME -- let's try to insure that the input file always exists, even for revert. $self->addmessage($r->param('status_message') ||''); # record status messages carried over if this is a redirect $self->addbadmessage("Changes in this file have not yet been permanently saved.") if -r $tempFilePath; - - $self->addbadmessage("This file '$inputFilePath' is protected! ".CGI::br()."To edit this text you must either 'Make a local copy' of this problem, or - use 'Save As' to save it to another file.") if $protected_file; + if ( not( -e $inputFilePath) ) { + $self->addbadmessage("This file: $inputFilePath, cannot be found."); + } elsif (not -w $inputFilePath ) { + $self->addbadmessage("This file '$inputFilePath' is protected! ".CGI::br()."To edit this text you must either 'Make a local copy' of this problem, or + use 'Save As' to save it to another file."); + } + } @@ -576,14 +410,13 @@ my $editFilePath = $self->{editFilePath}; # path to the permanent file to be edited my $tempFilePath = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file) my $inputFilePath = $self->{inputFilePath}; # path to the file for input, (might be a .tmp file) - my $setName = $r->urlpath->arg("setID") ; - my $problemNumber = $r->urlpath->arg("problemID") ; + my $setName = $self->{setID} ; + my $problemNumber = $self->{problemID} ; $setName = defined($setName) ? $setName : ''; # we need this instead of using the || construction # to keep set 0 from being set to the # empty string. $problemNumber = defined($problemNumber) ? $problemNumber : ''; - ######################################################################### # Find the text for the problem, either in the tmp file, if it exists # or in the original file in the template directory @@ -591,7 +424,7 @@ ######################################################################### my $problemContents = ${$self->{r_problemContents}}; - + unless ( $problemContents =~/\S/) { # non-empty contents if (-r $tempFilePath and not -d $tempFilePath) { eval { $problemContents = WeBWorK::Utils::readFile($tempFilePath) }; @@ -611,7 +444,7 @@ my $protected_file = not -w $inputFilePath; my $header = CGI::i("Editing problem".CGI::b("set $setName/ problem $problemNumber</emphasis>").CGI::br()." in file $inputFilePath"); - $header = ($inputFilePath =~ /$TEMPFILESUFFIX/) ? CGI::div({class=>'temporaryFile'},$header) : $header; # use colors if temporary file + $header = ($self->isTempFilePath($inputFilePath) ) ? CGI::div({class=>'temporaryFile'},$header) : $header; # use colors if temporary file ######################################################################### # Format the page @@ -629,49 +462,24 @@ my $edit_level = $r->param('edit_level') || 0; my $file_type = $self->{file_type}; - my $force_field = defined($r->param('sourceFilePath')) ? + my $force_field = (defined($self->{sourceFilePath}) and $self->{sourceFilePath} ne "") ? CGI::hidden(-name=>'sourceFilePath', - -default=>$r->param('sourceFilePath')) : ''; + -default=>$self->{sourceFilePath}) : ''; my @allSetNames = sort $db->listGlobalSets; for (my $j=0; $j<scalar(@allSetNames); $j++) { $allSetNames[$j] =~ s|^set||; $allSetNames[$j] =~ s|\.def||; } - my $target = "problem$edit_level"; - # Prepare Preview button - my $view_problem_form = CGI::start_form({method=>"POST", name=>"editor", action=>"$uri", target=>$target, enctype=>"application/x-www-form-urlencoded"}). - $self->hidden_authen_fields. - $force_field. - CGI::hidden(-name=>'file_type',-default=>$self->{file_type}). - CGI::hidden(-name=>'problemSeed',-default=>$problemSeed). - CGI::hidden(-name=>'displayMode',-default=>$displayMode). - CGI::hidden(-name=>'problemContents',-default=>$problemContents). - CGI::submit(-value=>'View problem',-name=>'submit'). - CGI::end_form(); - # Prepare add to set buttons - my $add_files_to_set_buttons = ''; - if ($file_type eq 'problem' or $file_type eq 'source_path_for_problem_file' or $file_type eq 'blank_problem' ) { - $add_files_to_set_buttons .= CGI::submit(-value=>'Add problem to: ',-name=>'submit' ) ; - } - if ($file_type eq 'set_header' # set header or the problem number is not a regular positive number - or ( $file_type =~ /problem/ and ($problemNumber =~ /\D|^0$|^$/ )) ){ - $add_files_to_set_buttons .=CGI::submit(-value=>'Make this the set header for: ',-name=>'submit' ); - } - # Add pop-up menu for the target set if either of these buttons has been revealed. - $add_files_to_set_buttons .= CGI::popup_menu(-name=>'target_set',-values=>\@allSetNames, -default=>$setName) if $add_files_to_set_buttons; - + my $target = "problem$edit_level"; # increasing edit_level gives you a new window with each edit. + - return CGI::p($header), + print CGI::p($header), CGI::start_form({method=>"POST", name=>"editor", action=>"$uri", target=>$target, enctype=>"application/x-www-form-urlencoded"}), $self->hidden_authen_fields, $force_field, CGI::hidden(-name=>'file_type',-default=>$self->{file_type}), CGI::div( - 'Seed: ', - CGI::textfield(-name=>'problemSeed',-value=>$problemSeed), - 'Mode: ', - CGI::popup_menu(-name=>'displayMode', -values=>$mode_list, -default=>$displayMode), CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"}, ' Manpages ', ), @@ -687,24 +495,43 @@ -name => 'problemContents', -default => $problemContents, -rows => $rows, -columns => $columns, -override => 1, ), - ), - CGI::p( - $add_files_to_set_buttons, - CGI::br(), - CGI::submit(-value=>'View problem',-name=>'submit'), - $protected_file ? CGI::submit(-value=>'Save',-name=>'submit', -disabled=>1) : CGI::submit(-value=>'Save',-name=>'submit'), - CGI::submit(-value=>'Revert', -name=>'submit'), - CGI::submit(-value=>'Save as',-name=>'submit'), - CGI::textfield(-name=>'save_to_new_file', -size=>40, -value=>""), - - ), - # allow one to make a local copy if the viewed file can't be edited. #FIXME the method for determining the localfilePath needs work - (-w $editFilePath) ? "" : CGI::p(CGI::hr(), - CGI::submit(-value=>'Make local copy at: ',-name=>'submit'), "[TMPL]/".determineLocalFilePath($editFilePath), - CGI::hidden(-name=>'local_copy_file_path', -value=>determineLocalFilePath($editFilePath) ) - ), - CGI::end_form(); + ); + + + +######### print action forms + print CGI::start_table({}); + #print CGI::Tr({}, CGI::td({-colspan=>2}, "Select an action to perform:")); + + my @formsToShow = @{ ACTION_FORMS() }; + my $default_choice = $formsToShow[0]; + my $i = 0; + foreach my $actionID (@formsToShow) { + # Check permissions + #next if FORM_PERMS()->{$actionID} and not $authz->hasPermissions($user, FORM_PERMS()->{$actionID}); + my $actionForm = "${actionID}_form"; + my $onChange = "document.userlist.action[$i].checked=true"; + my %actionParams = $self->getActionParams($actionID); + my $line_contents = $self->$actionForm($onChange, %actionParams); + my $radio_params = {-type=>"radio", -name=>"action", -value=>$actionID}; + $radio_params->{checked}=1 if ($actionID eq $default_choice) ; + print CGI::Tr({-valign=>"top"}, + CGI::td({}, CGI::input($radio_params)), + CGI::td({}, $line_contents) + ) if $line_contents; + + $i++; + } + print CGI::Tr({}, CGI::td({-align=>"right"}, "Select above then:"), + CGI::td({-align=>"left"}, CGI::submit(-name=>'submit', -value=>"Take Action!")), + ); + print CGI::end_table(); + + + print CGI::end_form(); + return ""; + } @@ -720,13 +547,46 @@ if ($path =~ /Library/) { $path =~ s|^.*?Library/||; # truncate the url up to a segment such as ...rochesterLibrary/....... } else { # if its not in a library we'll just save it locally - $path = "new_problem_".rand(40); #l hope there aren't any collisions. + $path = "new_problem_".rand(40).".pg"; #l hope there aren't any collisions. } $path; } + +sub determineTempFilePath { # this does not create the path to the file + my $self = shift; die "determineTempFilePath is a method" unless ref($self); + my $path =shift; + my $user = $self->r->param("user"); + $user = rand(1000) unless defined $user; + my $courseDirectory = $self->r->ce->{courseDirs}; + #FIXME -- we can put all of the temp files in a special directory + # so that even library files can viewed. + ############### + # Calculate the location of the temporary file + ############### + my $templatesDirectory = $courseDirectory->{templates}; + if ($path =~ /^$templatesDirectory/ ) { + $path =~ s|^$templatesDirectory||; + $path =~ s|^/||; # remove the initial slash if any + } else { + die "determineTempFilePath should only be used on paths within the templates directory, not on $path"; + } + my $tmpEditFileDirectory = (defined ($courseDirectory->{tmpEditFileDir}) ) ? $courseDirectory->{tmpEditFileDir} : "$templatesDirectory/tmpEdit"; + $path = "$tmpEditFileDirectory/$path.$user.tmp"; + #$path .= ".$user.tmp"; + #WeBWorK::Utils::surePathToFile($templatesDirectory, $path); + $path; +} +sub isTempFilePath { + my $self = shift; + my $path = shift; + my $courseDirectory = $self->r->ce->{courseDirs}; + my $templatesDirectory = $courseDirectory->{templates}; + my $tmpEditFileDirectory = (defined ($courseDirectory->{tmpEditFileDir}) ) ? $courseDirectory->{tmpEditFileDir} : "$templatesDirectory/tmpEdit"; + ($path =~/^$tmpEditFileDirectory/) ? 1: 0; +} sub getFilePaths { - my ($self, $setName, $problemNumber, $file_type, $TEMPFILESUFFIX) = @_; + my ($self, $setName, $problemNumber, $file_type) = @_; my $r = $self->r; my $ce = $r->ce; my $db = $r->db; @@ -741,11 +601,8 @@ ########################################################## # Determine path to the input file to be edited. - # set EditFilePath to this value - # - # There are potentially four files in play - # The permanent path of the input file == $editFilePath == $self->{problemPath} - # A temporary path to the input file == $tempFilePath== "$editFilePath.$TEMPFILESUFFIX"== $self->{problemPath} + # The permanent path of the input file == $editFilePath + # A temporary path to the input file == $tempFilePath ########################################################## # Relevant parameters # $r->param("displayMode") @@ -757,12 +614,10 @@ # $r->param('save_to_new_file') ########################################################################## # Define the following variables - # path to regular file -- $self->{problemPath} = $editFilePath; - # path to file being read (temporary or permanent) - # --- $self->{problemPath} = $problemPath; + # path to regular file -- $editFilePath; + # path to file being read (temporary or permanent) # contents of the file being read --- $problemContents - # $self->{r_problemContents} = \$problemContents; - # $self->{TEMPFILESUFFIX} = $TEMPFILESUFFIX; + # $self->{r_problemContents} = \$problemContents; ########################################################################### my $editFilePath = $ce->{courseDirs}->{templates}; @@ -782,7 +637,7 @@ ($file_type eq 'blank_problem') and do { $editFilePath = $ce->{webworkFiles}->{screenSnippets}->{blankProblem}; - $self->addbadmessage("$editFilePath is blank problem template file and should not be edited directly. " + $self->addbadmessage("$editFilePath is blank problem template file and can not be edited directly. " ."First use 'Save as' to make a local copy, then add the file to the current problem set, then edit the file." ); last CASE; @@ -833,7 +688,7 @@ }; # end 'problem' case ($file_type eq 'source_path_for_problem_file') and do { - my $forcedSourceFile = $r->param('sourceFilePath'); + my $forcedSourceFile = $self->{sourceFilePath}; # bail if no source path for the problem is found ; die "Cannot find a file path to save to" unless( defined($forcedSourceFile) and ($forcedSourceFile =~ /\S/) ); $self->{problemSeed} = 1234; @@ -863,279 +718,77 @@ # Whew!!! ################################################# - my $tempFilePath = "$editFilePath.$TEMPFILESUFFIX"; + my $tempFilePath = $self->determineTempFilePath($editFilePath); #"$editFilePath.$TEMPFILESUFFIX"; $self->{editFilePath} = $editFilePath; $self->{tempFilePath} = $tempFilePath; - $self->{inputFilePath} = (-r "$editFilePath.$TEMPFILESUFFIX") ? $tempFilePath : $editFilePath; - + $self->{inputFilePath} = (-r $tempFilePath) ? $tempFilePath : $editFilePath; + #warn "editfile path is $editFilePath and tempFile is $tempFilePath and inputFilePath is ". $self->{inputFilePath}; } +sub new_saveFileChanges { ################################################################################ -# saveFileChanges does most of the work. it is a separate method so that it can +# new_saveFileChanges does most of the work. it is a separate method so that it can # be called from either pre_header_initialize() or initilize(), depending on # whether a redirect is needed or not. # # it actually does a lot more than save changes to the file being edited, and # sometimes less. ################################################################################ -sub saveFileChanges { - my ($self, $setName, $problemNumber, $file_type, $TEMPFILESUFFIX) = @_; - my $r = $self->r; - my $ce = $r->ce; - my $db = $r->db; - my $urlpath = $r->urlpath; - - my $courseName = $urlpath->arg("courseID"); - my $user = $r->param('user'); - my $effectiveUserName = $r->param('effectiveUser'); - $setName = '' unless defined $setName; - $problemNumber = '' unless defined $problemNumber; - $file_type = '' unless defined $file_type; + my ($self, $outputFilePath, $problemContents ) = @_; + my $r = $self->r; + my $ce = $r->ce; - my $action = $self->{action}; + my $action = $self->{action}||'no action'; my $editFilePath = $self->{editFilePath}; my $tempFilePath = $self->{tempFilePath}; + + if (defined($problemContents) and ref($problemContents) ) { + $problemContents = ${$problemContents}; + } elsif( not defined($problemContents) or $problemContents =~/\S/ ) { + $problemContents = ${$self->{r_problemContents}}; + } ############################################################################## # read and update the targetFile and targetFile.tmp files in the directory # if a .tmp file already exists use that, unless the revert button has been pressed. - # These .tmp files are - # removed when the file is finally saved. - # Place the path of the file to be read in $problemPath. + # The .tmp files are removed when the file is or when the revert occurs. ############################################################################## - my $problemContents = ''; - my $outputFilePath = undef; # this is actually the output file for this subroutine - # it is then read in as source in the body of this module - my $do_not_save = 0; # flag to prevent saving of file + unless (defined($outputFilePath) and $outputFilePath =~/\S/ ) { + $self->addbadmessage("You must specify an file name in order to save a new file."); + return ""; + } + my $do_not_save = 0 ; # flag to prevent saving of file my $editErrors = ''; - ########################################################################## - # For each of the actions define the following variables: - # - # path to permanent file -- $self->{problemPath} = $editFilePath; - # path to file being read (temporary or permanent) - # --- $self->{problemPath} = $problemPath; - # contents of the file being read --- $problemContents - # $self->{r_problemContents} = \$problemContents; - # - ################################# - # handle button clicks ##### - # Read contents of file - ################################# - ACTION_CASES: { - ($action eq 'fresh_edit') and do { - # this is a fresh editing job - # the original file will be read in the body - last ACTION_CASES; - }; - - ($action eq 'revert') and do { - # this is also fresh editing job - $outputFilePath = undef; - $self->addgoodmessage("Reverting to original file $editFilePath"); - $self->{problemPath} = $editFilePath; - $self->{inputFilePath}=$editFilePath; - last ACTION_CASES; - }; - - ($action eq 'refresh') and do { - # grab the problemContents from the form in order to save it to the tmp file - # store tmp file name in the $self->problemPath for use in body - - $problemContents = $r->param('problemContents'); - $outputFilePath = "$editFilePath.$TEMPFILESUFFIX"; - $self->{problemPath} = $outputFilePath; - last ACTION_CASES; - }; - - ($action eq 'save') and do { - # grab the problemContents from the form in order to save it to the permanent file - # later we will unlink (delete) the temporary file - # store permanent file name in the $self->problemPath for use in body - $problemContents = $r->param('problemContents'); - $outputFilePath = "$editFilePath"; - $self->{problemPath} = $outputFilePath; - #$self->addgoodmessage("Saving to file $outputFilePath"); - last ACTION_CASES; - }; - - ($action eq 'save_as') and do { - my $new_file_name =$r->param('save_to_new_file') || ''; - ################################################# - #bail unless this new file name has been defined - ################################################# - if ( $new_file_name !~ /\S/) { # need a non-blank file name - # setting $self->{failure} stops saving and any redirects - $do_not_save = 1; - warn "new file name is $new_file_name"; - $self->addbadmessage(CGI::p("Please specify a file to save to.")); - last ACTION_CASES; #stop processing - } - ################################################# - # grab the problemContents from the form in order to save it to a new permanent file - # later we will unlink (delete) the current temporary file - # store new permanent file name in the $self->problemPath for use in body - ################################################# - $problemContents = $r->param('problemContents'); - - ################################################# - # Rescue the user in case they forgot to end the file name with .pg - ################################################# - if($self->{file_type} eq 'problem' - or $self->{file_type} eq 'blank_problem' - or $self->{file_type} eq 'set_header') { - $new_file_name =~ s/\.pg$//; # remove it if it is there - $new_file_name .= '.pg'; # put it there - - } - - ################################################# - # check to prevent overwrites: - ################################################# - $outputFilePath = $ce->{courseDirs}->{templates} . '/' . - $new_file_name; - - if (defined $outputFilePath and -e $outputFilePath) { - # setting $do_not_save stops saving and any redirects - $do_not_save = 1; - $self->addbadmessage(CGI::p("File $outputFilePath exists. File not saved.")); - } else { - #$self->addgoodmessage("Saving to file $outputFilePath."); - } - $self->{problemPath} = $outputFilePath; - last ACTION_CASES; - }; - ($action eq 'make_local_copy') and do { - my $new_file_name =$r->param('local_copy_file_path') || ''; - ################################################# - #bail unless this new file name has been defined - ################################################# - if ( $new_file_name !~ /\S/) { # need a non-blank file name - # setting $self->{failure} stops saving and any redirects - $do_not_save = 1; - warn "new file name is $new_file_name"; - $self->addbadmessage(CGI::p("Please specify a file to save to.")); - last ACTION_CASES; #stop processing - } - ################################################# - # grab the problemContents from the form in order to save it to a new permanent file - # later we will unlink (delete) the current temporary file - # store new permanent file name in the $self->problemPath for use in body - ################################################# - $problemContents = $r->param('problemContents'); - - ################################################# - # Rescue the user in case they forgot to end the file name with .pg - ################################################# - if($self->{file_type} eq 'problem' - or $self->{file_type} eq 'blank_problem' - or $self->{file_type} eq 'set_header') { - $new_file_name =~ s/\.pg$//; # remove it if it is there - $new_file_name .= '.pg'; # put it there - - } - - ################################################# - # check to prevent overwrites: - ################################################# - $outputFilePath = $ce->{courseDirs}->{templates} . '/' . - $new_file_name; - - if (defined $outputFilePath and -e $outputFilePath) { - # setting $do_not_save stops saving and any redirects - $do_not_save = 1; - $self->addbadmessage(CGI::p("There is already a file at [TMPL]/$new_file_name. File not saved.")); - } else { - $self->addgoodmessage("A local copy of $editFilePath is being made...") ; - } - $self->{problemPath} = $outputFilePath; - ################################################# - # if new file has been successfully saved change the file path name for the problem - ################################################# - unless ($do_not_save) { - my $problemRecord = $db->getGlobalProblem($setName,$problemNumber); - $problemRecord->source_file($new_file_name); - if ( $db->putGlobalProblem($problemRecord) ) { - $self->addgoodmessage("A local, editable, copy of $new_file_name has been made for problem $problemNumber.") ; - $self->{problemPath} = $outputFilePath; # define the file path for redirect - } else { - $self->addbadmessage("Unable to change the source file path for set $setName, problem $problemNumber. Unknown error."); - } - } - - - - last ACTION_CASES; - }; - ($action eq 'add_problem_to_set') and do { - my $sourceFile = $editFilePath; - my $targetSetName = $r->param('target_set'); - my $freeProblemID = WeBWorK::Utils::max($db->listGlobalProblems($targetSetName)) + 1; - $sourceFile =~ s|^$ce->{courseDirs}->{templates}/||; - my $problemRecord = $self->addProblemToSet( - setName => $targetSetName, - sourceFile => $sourceFile, - problemID => $freeProblemID - ); - $self->assignProblemToAllSetUsers($problemRecord); - $self->addgoodmessage("Added $sourceFile to ". $targetSetName. " as problem $freeProblemID") ; - $outputFilePath = undef; # don't save any files - $self->{problemPath} = $editFilePath; - - }; - ($action eq 'add_set_header_to_set') and do { - my $sourceFile = $editFilePath; - my $targetSetName = $r->param('target_set'); - $sourceFile =~ s|^$ce->{courseDirs}->{templates}/||; - my $setRecord = $db->getGlobalSet($targetSetName); - $setRecord->set_header($sourceFile); - if( $db->putGlobalSet($setRecord) ) { - $self->addgoodmessage("Added $sourceFile to ". $targetSetName. " as new set header ") ; - } else { - $do_not_save = 1 ; - $self->addbadmessage("Unable to make $sourceFile the set header for $targetSetName"); - } - # change file type to set_header if it not already so - $self->{file_type} = 'set_header'; - $outputFilePath = undef; # don't save any files - $self->{problemPath} = $editFilePath; - - }; - last ACTION_CASES; - - die "Unrecognized action command: $action"; - }; # end ACTION_CASES - - - ############################################################################## # write changes to the approriate files # FIXME make sure that the permissions are set correctly!!! # Make sure that the warning is being transmitted properly. ############################################################################## - + my $writeFileErrors; - if ( defined($outputFilePath) and $outputFilePath =~/\S/ and ! $do_not_save ) { # save file + if ( defined($outputFilePath) and $outputFilePath =~/\S/ ) { # save file # Handle the problem of line endings. # Make sure that all of the line endings are of unix type. # Convert \r\n to \n - $problemContents =~ s/\r\n/\n/g; - $problemContents =~ s/\r/\n/g; + #$problemContents =~ s/\r\n/\n/g; + #$problemContents =~ s/\r/\n/g; # make sure any missing directories are created - $outputFilePath = WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates}, + WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates}, $outputFilePath); eval { local *OUTPUTFILE; - open OUTPUTFILE, ">", $outputFilePath + open OUTPUTFILE, ">$outputFilePath" or die "Failed to open $outputFilePath"; print OUTPUTFILE $problemContents; - close OUTPUTFILE; - }; # any errors are caught in the next block - + close OUTPUTFILE; + # any errors are caught in the next block + }; + $writeFileErrors = $@ if $@; } @@ -1143,7 +796,7 @@ # Catch errors in saving files, clean up temp files ########################################################### - $self->{failure} = $do_not_save; # don't do redirects if the file was not saved. + $self->{saveError} = $do_not_save; # don't do redirects if the file was not saved. # don't unlink files or send success messages if ($writeFileErrors) { @@ -1167,27 +820,592 @@ $self->addbadmessage(CGI::p($errorMessage)); } + ########################################################### + # clean up temp files on revert, save and save_as + ########################################################### unless( $writeFileErrors or $do_not_save) { # everything worked! unlink and announce success! # unlink the temporary file if there are no errors and the save button has been pushed if ($action eq 'save' or $action eq 'save_as' or $action eq 'revert') { unlink($self->{tempFilePath}) ; } if ( defined($outputFilePath) and ! $self->{failure} ) { - my $msg = "Saved to file: $outputFilePath"; + my $msg = "Saved to file: |$outputFilePath|"; $self->addgoodmessage($msg); } } + + +} # end new_saveFileChanges + + + + + +sub getActionParams { + my ($self, $actionID) = @_; + my $r = $self->{r}; + + my %actionParams=(); + foreach my $param ($r->param) { + next unless $param =~ m/^action\.$actionID\./; + $actionParams{$param} = [ $r->param($param) ]; + } + return %actionParams; +} + +sub fixProblemContents { + #NOT a method + my $problemContents = shift; + # Handle the problem of line endings. + # Make sure that all of the line endings are of unix type. + # Convert \r\n to \n + $problemContents =~ s/\r\n/\n/g; + $problemContents =~ s/\r/\n/g; + $problemContents; +} + +sub fresh_edit_handler { + my ($self, $genericParams, $actionParams, $tableParams) = @_; + $self->addgoodmessage("fresh_edit_handler called"); +} +sub view_form { + my ($self, $onChange, %actionParams) = @_; + my $output_string = "View"; + unless ($self->{file_type} eq 'course_info') { + $output_string .= join(" ", + " problem using seed ", + CGI::textfield(-name=>'action.view.seed',-value=>$self->{problemSeed}), + "and display mode ", + CGI::popup_menu(-name=>'action.view.displayMode', -values=>$self->r->ce->{pg}->{displayModes}, + -default=>$self->{displayMode} + ), ".", + ); + } + + return $output_string; #FIXME add -lables to the pop up menu +} + +sub view_handler { + my ($self, $genericParams, $actionParams, $tableParams) = @_; + my $courseName = $self->{courseID}; + my $setName = $self->{setID}; + my $problemNumber = $self->{problemID}; + my $problemSeed = ($actionParams->{'action.view.seed'}) ? + $actionParams->{'action.view.seed'}->[0] + : 1234; + my $displayMode = ($actionParams->{'action.view.displayMode'}) ? + $actionParams->{'action.view.displayMode'}->[0] + : $self->r->ce->{pg}->{options}->{displayMode}; + + my $editFilePath = $self->{editFilePath}; + my $tempFilePath = $self->{tempFilePath}; + ######################################################## + # grab the problemContents from the form in order to save it to the tmp file + ######################################################## + my $problemContents = fixProblemContents($self->r->param('problemContents')); + $self->{r_problemContents} = \$problemContents; + + + my $do_not_save = 0; + my $file_type = $self->{file_type}; + $self->new_saveFileChanges($tempFilePath,); + + ######################################################## + # construct redirect URL and redirect + ######################################################## + my $edit_level = $self->r->param("edit_level") || 0; + $edit_level++; + my $viewURL; + + if ($file_type eq 'problem' ) { # redirect to Problem.pm + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", + courseID => $courseName, setID => $setName, problemID => $problemNumber + ); - # return values for use in the body subroutine - # The path to the current permanent file being edited: - # $self->{problemPath} = $editFilePath; - # The path to the current temporary file (if any). If no temporary file this the same - # as the permanent file path: - # $self->{outputFilePath} = $outputFilePath; - # + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + problemSeed => $problemSeed, + editMode => "temporaryFile", + edit_level => $edit_level, + sourceFilePath => $tempFilePath, + status_message => uri_escape($self->{status_message}) - $self->{r_problemContents} = \$problemContents; -} # end saveFileChanges + } + ); + } elsif ($file_type eq 'set_header' or $file_type eq 'hardcopy_header') { # redirect to ProblemSet + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", + courseID => $courseName, setID => $setName, + ); + + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + problemSeed => $problemSeed, + editMode => "temporaryFile", + edit_level => $edit_level, + status_message => uri_escape($self->{status_message}) + + } + ); + + + } elsif ($file_type eq 'course_info') { # redirecto to ProblemSets.pm + my $problemSetsPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", + courseID => $courseName); + $viewURL = $self->systemLink($problemSetsPage, + params => { + editMode => ("temporaryFile"), + edit_level => $edit_level, + status_message => uri_escape($self->{status_message}) + } + ); + } elsif ($file_type eq 'source_path_for_problem_file') { # redirect to Problem.pm + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", + courseID => $courseName, setID => $setName, problemID => $problemNumber + ); + + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + problemSeed => $problemSeed, + editMode => "temporaryFile", + edit_level => $edit_level, + sourceFilePath => $tempFilePath, + status_message => uri_escape($self->{status_message}) + + } + ); + } else { + die "I don't know how to redirect this file type $file_type "; + } + + $self->reply_with_redirect($viewURL); +} + +sub add_problem_form { + my $self = shift; + my ($onChange, %actionParams) = @_; + my $r = $self->r; + my $setName = $self->{setID} ; + my $problemNumber = $self->{problemID} ; + $setName = defined($setName) ? $setName : ''; # we need this instead of using the || construction + # to keep set 0 from being set to the + # empty string. + $setName =~ s|^set||; + my @allSetNames = sort $r->db->listGlobalSets; + for (my $j=0; $j<scalar(@allSetNames); $j++) { + $allSetNames[$j] =~ s|^set||; + $allSetNames[$j] =~ s|\.def||; + } + return "" if $self->{file_type} eq 'course_info'; + return join(" ", + "Add problem to set " , + CGI::popup_menu(-name=>'action.add_problem.target_set', -values=>\@allSetNames, -default=>$setName), + " as ", + CGI::popup_menu(-name=>'action.add_problem.file_type', -values=>['problem','set_header'], -default=>'problem'), + + ); #FIXME add -lables to the pop up menu + return ""; +} + +sub add_problem_handler { + my ($self, $genericParams, $actionParams, $tableParams) = @_; +# $self->addgoodmessage("add_problem_handler called"); + my $courseName = $self->{courseID}; + my $setName = $self->{setID}; + my $problemNumber = $self->{problemID}; + my $sourceFilePath = $self->{editFilePath}; + my $displayMode = $self->{displayMode}; + my $problemSeed = $self->{problemSeed}; + + my $targetSetName = $actionParams->{'action.add_problem.target_set'}->[0]; + my $targetFileType = $actionParams->{'action.add_problem.file_type'}->[0]; + my $templatesPath = $self->r->ce->{courseDirs}->{templates}; + $sourceFilePath =~ s|^$templatesPath/||; + + my $edit_level = $self->r->param("edit_level") || 0; + $edit_level++; + + my $viewURL =''; + if ($targetFileType eq 'problem') { + my $targetProblemNumber = 1+ WeBWorK::Utils::max( $self->r->db->listGlobalProblems($targetSetName)); + + ################################################# + # Update problem record + ################################################# + my $problemRecord = $self->addProblemToSet( + setName => $targetSetName, + sourceFile => $sourceFilePath, + problemID => $targetProblemNumber, + ); + $self->assignProblemToAllSetUsers($problemRecord); + $self->addgoodmessage("Added $sourceFilePath to ". $targetSetName. " as problem $targetProblemNumber") ; + $self->{file_type} = 'problem'; # change file type to problem -- if it's not already that + + ################################################# + # Set up redirect Problem.pm + ################################################# + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", + courseID => $courseName, + setID => $targetSetName, + problemID => $targetProblemNumber, + ); + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + problemSeed => $problemSeed, + editMode => "savedFile", + edit_level => $edit_level, + sourceFilePath => $sourceFilePath, + status_message => uri_escape($self->{status_message}) + + } + ); + } elsif ($targetFileType eq 'set_header') { + ################################################# + # Update set record + ################################################# + my $setRecord = $self->db->getGlobalSet($targetSetName); + $setRecord->set_header($sourceFilePath); + if( $self->db->putGlobalSet($setRecord) ) { + $self->addgoodmessage("Added $sourceFilePath to ". $targetSetName. " as new set header ") ; + } else { + $self->addbadmessage("Unable to make $sourceFilePath the set header for $targetSetName"); + } + $self->{file_type} = 'set_header'; # change file type to set_header if it not already so + ################################################# + # Set up redirect + ################################################# + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", + courseID => $courseName, setID => $targetSetName + ); + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + editMode => "savedFile", + edit_level => $edit_level, + status_message => uri_escape($self->{status_message}) + } + ); + } else { + die "Don't know what to do with target file type $targetFileType"; + } + + $self->reply_with_redirect($viewURL); +} + + +sub save_form { + my ($self, $onChange, %actionParams) = @_; + my $r => $self->r; + if (-w $self->{editFilePath}) { + return "Save"; + } else { + return ""; #"Can't save -- No write permission"; + } + +} + +sub save_handler { + my ($self, $genericParams, $actionParams, $tableParams) = @_; + $self->addgoodmessage("save_handler called"); + my $courseName = $self->{courseID}; + my $setName = $self->{setID}; + my $problemNumber = $self->{problemID}; + my $displayMode = $self->{displayMode}; + my $problemSeed = $self->{problemSeed}; + + ################################################# + # grab the problemContents from the form in order to save it to a new permanent file + # later we will unlink (delete) the current temporary file + ################################################# + my $problemContents = fixProblemContents($self->r->param('problemContents')); + $self->{r_problemContents} = \$problemContents; + + ################################################# + # Construct the output file path + ################################################# + my $editFilePath = $self->{editFilePath}; + my $outputFilePath = $editFilePath; + + my $do_not_save = 0; + my $file_type = $self->{file_type}; + $self->new_saveFileChanges($outputFilePath); + ################################################# + # Set up redirect to Problem.pm + ################################################# + my $viewURL; + ######################################################## + # construct redirect URL and redirect + ######################################################## + if ($file_type eq 'problem' ) { # redirect to Problem.pm + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", + courseID => $courseName, setID => $setName, problemID => $problemNumber + ); + + $viewURL = $self->systemLink($problemPage, + params => { + displayMode => $displayMode, + problemSeed => $problemSeed, + editMode => "savedFile", + edit_level => 0, + sourceFilePath => $editFilePath, + status_message => uri_escape($self->{status_message}) + + } + ); + } elsif ($file_type eq 'set_header' or $file_type eq 'hardcopy_header') { # redirect to ProblemSet + my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", + courseID => $courseName, setID => $setName, + ); + + $viewURL = $self->systemLink($p... [truncated message content] |