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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5318 - (view) (download) (as text)

1 : sh002i 1663 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 : sh002i 5318 # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
4 :     # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v 1.90 2006/09/25 22:14:53 sh002i Exp $
5 : sh002i 1663 #
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 : gage 889 package WeBWorK::ContentGenerator::Instructor::PGProblemEditor;
18 :     use base qw(WeBWorK::ContentGenerator::Instructor);
19 :    
20 :    
21 : gage 3718
22 : gage 889 =head1 NAME
23 :    
24 : toenail 2288 WeBWorK::ContentGenerator::Instructor::PGProblemEditor - Edit a pg file
25 : gage 889
26 :     =cut
27 :    
28 :     use strict;
29 :     use warnings;
30 : gage 4234 #use CGI qw(-nosticky );
31 :     use WeBWorK::CGI;
32 : sh002i 4057 use WeBWorK::Utils qw(readFile surePathToFile path_is_subdir);
33 : gage 1980 use HTML::Entities;
34 : gage 3037 use URI::Escape;
35 : gage 3175 use WeBWorK::Utils;
36 : gage 4167 use File::Copy;
37 : jj 2016 use WeBWorK::Utils::Tasks qw(fake_set fake_problem);
38 : gage 889
39 : sh002i 1924 ###########################################################
40 :     # This editor will edit problem files or set header files or files, such as course_info
41 :     # whose name is defined in the global.conf database
42 :     #
43 :     # Only files under the template directory ( or linked to this location) can be edited.
44 :     #
45 :     # The course information and problems are located in the course templates directory.
46 :     # Course information has the name defined by courseFiles->{course_info}
47 :     #
48 : gage 3175 # Only files under the template directory ( or linked to this location) can be edited.
49 : sh002i 1924 #
50 :     # editMode = temporaryFile (view the temp file defined by course_info.txt.user_name.tmp
51 :     # instead of the file course_info.txt)
52 : gage 3037 # this flag is read by Problem.pm and ProblemSet.pm, perhaps others
53 :     # The TEMPFILESUFFIX is "user_name.tmp" by default. It's definition should be moved to Instructor.pm #FIXME
54 : sh002i 1924 ###########################################################
55 : gage 925
56 : gage 3037 ###########################################################
57 :     # The behavior of this module is essentially defined
58 :     # by the values of $file_type and the submit button which is placed in $action
59 :     #############################################################
60 :     # File types which can be edited
61 :     #
62 :     # file_type eq 'problem'
63 :     # this is the most common type -- this editor can be called by an instructor when viewing any problem.
64 :     # the information for retrieving the source file is found using the problemID in order to look
65 :     # look up the source file path.
66 :     #
67 : gage 3718 # file_type eq 'source_path_for_problem_file'
68 : gage 3037 # This is the same as the 'problem' file type except that the source for the problem is found in
69 : gage 3718 # the parameter $r->param('sourceFilePath'). This path is relative to the templates directory
70 : gage 3037 #
71 :     # file_type eq 'set_header'
72 :     # 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.
73 :     #
74 :     # file_type eq 'hardcopy_header'
75 :     # 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.
76 :     # But it is used instead of set_header when producing a hardcopy of the problem set in the TeX format, instead of producing HTML
77 :     # formatted version for use on the computer screen.
78 :     #
79 : gage 3883 # file_type eq 'course_info
80 : gage 3037 # This allows editing of the course_info.txt file which gives general information about the course. It is called from the
81 :     # ProblemSets.pm module.
82 :     #
83 : gage 3883 # file_type eq 'options_info
84 :     # This allows editing of the options_info.txt file which gives general information about the course. It is called from the
85 :     # Options.pm module.
86 :     #
87 : gage 3037 # file_type eq 'blank_problem'
88 :     # This is a special call which allows one to create and edit a new PG problem. The "stationery" source for this problem is
89 :     # stored in the conf/snippets directory and defined in global.conf by $webworkFiles{screenSnippets}{blankProblem}
90 :     #############################################################
91 : gage 3718 # Requested actions -- these and the file_type determine the state of the module
92 : gage 3037 # Save ---- action = save
93 :     # Save as ---- action = save_as
94 : gage 3718 # View Problem ---- action = view
95 :     # Add this problem to: ---- action = add_problem
96 :     # Make this set header for: ---- action = add_problem
97 : gage 3037 # Revert ---- action = revert
98 :     # no submit button defined ---- action = fresh_edit
99 :     ###################################################
100 :     #
101 :     # Determining which is the correct path to the file is a mess!!! FIXME
102 :     # The path to the file to be edited is eventually put in tempFilePath
103 :     #
104 : gage 3718 # (tempFilePath)(editFilePath)(forcedSourceFile)
105 :     #input parameter is: sourceFilePath
106 : gage 3037 #################################################################
107 :     # params read
108 :     # user
109 :     # effectiveUser
110 :     # submit
111 :     # file_type
112 :     # problemSeed
113 :     # displayMode
114 :     # edit_level
115 :     # make_local_copy
116 :     # sourceFilePath
117 :     # problemContents
118 :     # save_to_new_file
119 :     #
120 :    
121 : gage 3790 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)];
122 : gage 889
123 : gage 3718 # permissions needed to perform a given action
124 :     use constant FORM_PERMS => {
125 :     view => "modify_student_data",
126 :     add_problem => "modify_student_data",
127 :     make_local_copy => "modify_student_data",
128 :     save => "modify_student_data",
129 :     save_as => "modify_student_data",
130 : gage 3790 # rename => "modify_student_data",
131 : gage 3718 revert => "modify_student_data",
132 :     };
133 :    
134 : gage 3790 our $BLANKPROBLEM = 'blankProblem.pg';
135 :     # use constant BLANKPROBLEM => 'blankProblem.pg'; # doesn't work because this constant needs to be used inside a match.
136 : gage 1747 sub pre_header_initialize {
137 : gage 3037 my ($self) = @_;
138 :     my $r = $self->r;
139 :     my $ce = $r->ce;
140 :     my $urlpath = $r->urlpath;
141 :     my $authz = $r->authz;
142 :     my $user = $r->param('user');
143 : gage 3718 $self->{courseID} = $urlpath->arg("courseID");
144 :     $self->{setID} = $r->urlpath->arg("setID") ; # using $r->urlpath->arg("setID") ||'' causes trouble with set 0!!!
145 :     $self->{problemID} = $r->urlpath->arg("problemID");
146 : sh002i 1924
147 : gage 3037 my $submit_button = $r->param('submit'); # obtain submit command from form
148 : gage 3718 my $actionID = $r->param('action');
149 : gage 3037 my $file_type = $r->param("file_type") || '';
150 : gage 3718 my $setName = $self->{setID};
151 :     my $problemNumber = $self->{problemID};
152 : gage 3883
153 : toenail 2305 # Check permissions
154 :     return unless ($authz->hasPermissions($user, "access_instructor_tools"));
155 :     return unless ($authz->hasPermissions($user, "modify_problem_sets"));
156 : gage 3037
157 : gage 3718 ##############################################################################
158 :     # displayMode and problemSeed
159 :     #
160 :     # Determine the display mode
161 :     # If $self->{problemSeed} was obtained within saveFileChanges from the problem_record
162 :     # then it can be overridden by the value obtained from the form.
163 :     # Insure that $self->{problemSeed} has some non-empty value
164 :     # displayMode and problemSeed
165 :     # will be needed for viewing the problem via redirect.
166 :     # They are also two of the parameters which can be set by the editor
167 :     ##############################################################################
168 :    
169 :     if (defined $r->param('displayMode')) {
170 :     $self->{displayMode} = $r->param('displayMode');
171 :     } else {
172 :     $self->{displayMode} = $ce->{pg}->{options}->{displayMode};
173 :     }
174 :    
175 :     # form version of problemSeed overrides version obtained from the the problem_record
176 :     # inside saveFileChanges
177 :     $self->{problemSeed} = $r->param('problemSeed') if (defined $r->param('problemSeed'));
178 :     # Make sure that the problem seed has some value
179 :     $self->{problemSeed} = '123456' unless defined $self->{problemSeed} and $self->{problemSeed} =~/\S/;
180 :    
181 :     ##############################################################################
182 : gage 3037 #############################################################################
183 :     # Save file to permanent or temporary file, then redirect for viewing
184 :     #############################################################################
185 :     #
186 :     # Any file "saved as" should be assigned to "Undefined_Set" and redirectoed to be viewed again in the editor
187 :     #
188 :     # Problems "saved" or 'refreshed' are to be redirected to the Problem.pm module
189 :     # Set headers which are "saved" are to be redirected to the ProblemSet.pm page
190 : gage 3883 # Hardcopy headers which are "saved" are also to be redirected to the ProblemSet.pm page
191 : gage 3037 # Course_info files are redirected to the ProblemSets.pm page
192 : gage 3883 # Options_info files are redirected to the Options.pm page
193 : gage 3037 ##############################################################################
194 :    
195 : toenail 2305
196 : gage 3037
197 :     ######################################
198 :     # Insure that file_type is defined
199 :     ######################################
200 :     # We have already read in the file_type parameter from the form
201 :     #
202 :     # If this has not been defined we are dealing with a set header
203 :     # or regular problem
204 :     if (defined($file_type) and ($file_type =~/\S/)) { #file_type is defined and is not blank
205 :     # file type is already defined -- do nothing
206 : gage 3876 #warn "file type already defined as $file_type" #FIXME debug
207 : gage 3037 } else {
208 : gage 3718 # if "sourceFilePath" is defined in the form, then we are getting the path directly.
209 : gage 3037 # if the problem number is defined and is 0
210 :     # then we are dealing with some kind of
211 :     # header file. The default is 'set_header' which prints properly
212 :     # to the screen.
213 :     # If the problem number is not zero, we are dealing with a real problem
214 :     ######################################
215 :     if ( defined($r->param('sourceFilePath') and $r->param('sourceFilePath') =~/\S/) ) {
216 :     $file_type ='source_path_for_problem_file';
217 : gage 3883 $file_type = 'set_header' if $r->param('sourceFilePath') =~ m!/headers/|Header\.pg$!; #FIXME this need to be cleaned up
218 : gage 3037 } elsif ( defined($problemNumber) ) {
219 :     if ( $problemNumber =~/^\d+$/ and $problemNumber == 0 ) { # if problem number is numeric and zero
220 : gage 3876 $file_type = 'set_header' unless $file_type eq 'set_header'
221 : gage 3037 or $file_type eq 'hardcopy_header';
222 :     } else {
223 : gage 3876 $file_type = 'problem';
224 :     #warn "setting file type to 'problem'\n"; #FIXME debug
225 : gage 3037 }
226 :    
227 :     }
228 :     }
229 :     die "The file_type variable has not been defined or is blank." unless defined($file_type) and $file_type =~/\S/;
230 : gage 3718 # clean up sourceFilePath, just in case
231 :     # double check that sourceFilePath is relative to the templates file
232 :     if ($file_type eq 'source_path_for_problem_file' ) {
233 :     my $templatesDirectory = $ce->{courseDirs}->{templates};
234 :     my $sourceFilePath = $r->param('sourceFilePath');
235 :     $sourceFilePath =~ s/$templatesDirectory//;
236 :     $sourceFilePath =~ s|^/||; # remove intial /
237 :     $self->{sourceFilePath} = $sourceFilePath;
238 :     }
239 : gage 3037 $self->{file_type} = $file_type;
240 : gage 3876 # $self->addgoodmessage("file type is $file_type"); #FIXME debug
241 :     # warn "file type is $file_type\n parameter is ".$self->r->param("file_type");
242 : gage 3037 ##########################################
243 : gage 3883 # File type is one of: blank_problem course_info options_info problem set_header hardcopy_header source_path_for_problem_file
244 : gage 3037 ##########################################
245 :     #
246 :     # Determine the path to the file
247 :     #
248 :     ###########################################
249 : gage 3718 $self->getFilePaths($setName, $problemNumber, $file_type);
250 :     #defines $self->{editFilePath} # path to the permanent file to be edited
251 :     # $self->{tempFilePath} # path to the permanent file to be edited has .tmp suffix
252 :     # $self->{inputFilePath} # path to the file for input, (might be a .tmp file)
253 :    
254 :    
255 :    
256 : gage 3037 ##########################################
257 : gage 3718 # Default problem contents
258 :     ##########################################
259 :     $self->{r_problemContents}= undef;
260 :    
261 :     ##########################################
262 : gage 3037 #
263 :     # Determine action
264 :     #
265 :     ###########################################
266 :    
267 : gage 3718 if ($actionID) {
268 :     unless (grep { $_ eq $actionID } @{ ACTION_FORMS() } ) {
269 :     die "Action $actionID not found";
270 :     }
271 :     # Check permissions
272 :     if (not FORM_PERMS()->{$actionID} or $authz->hasPermissions($user, FORM_PERMS()->{$actionID})) {
273 :     my $actionHandler = "${actionID}_handler";
274 :     my %genericParams =();
275 :     # foreach my $param (qw(selected_users)) {
276 :     # $genericParams{$param} = [ $r->param($param) ];
277 :     # }
278 :     my %actionParams = $self->getActionParams($actionID);
279 :     my %tableParams = (); # $self->getTableParams();
280 :     $self->{action}= $actionID;
281 :     $self->$actionHandler(\%genericParams, \%actionParams, \%tableParams);
282 :     } else {
283 :     $self->addbadmessage( "You are not authorized to perform this action.");
284 :     }
285 :     } else {
286 :     $self->{action}='fresh_edit';
287 :     my $actionHandler = "fresh_edit_handler";
288 :     my %genericParams;
289 :     my %actionParams = (); #$self->getActionParams($actionID);
290 :     my %tableParams = (); # $self->getTableParams();
291 :     my $problemContents = '';
292 :     $self->{r_problemContents}=\$problemContents;
293 :     $self->$actionHandler(\%genericParams, \%actionParams, \%tableParams);
294 :     }
295 :    
296 : gage 3037
297 :     ##############################################################################
298 :     # displayMode and problemSeed
299 :     #
300 :     # Determine the display mode
301 :     # If $self->{problemSeed} was obtained within saveFileChanges from the problem_record
302 :     # then it can be overridden by the value obtained from the form.
303 :     # Insure that $self->{problemSeed} has some non-empty value
304 :     # displayMode and problemSeed
305 :     # will be needed for viewing the problem via redirect.
306 :     # They are also two of the parameters which can be set by the editor
307 :     ##############################################################################
308 :    
309 :     if (defined $r->param('displayMode')) {
310 :     $self->{displayMode} = $r->param('displayMode');
311 :     } else {
312 :     $self->{displayMode} = $ce->{pg}->{options}->{displayMode};
313 :     }
314 :    
315 :     # form version of problemSeed overrides version obtained from the the problem_record
316 :     # inside saveFileChanges
317 :     $self->{problemSeed} = $r->param('problemSeed') if (defined $r->param('problemSeed'));
318 :     # Make sure that the problem seed has some value
319 :     $self->{problemSeed} = '123456' unless defined $self->{problemSeed} and $self->{problemSeed} =~/\S/;
320 :    
321 :     ##############################################################################
322 :     # Return
323 :     # If file saving fails or
324 :     # if no redirects are required. No further processing takes place in this subroutine.
325 :     # Redirects are required only for the following submit values
326 :     # 'Save'
327 :     # 'Save as'
328 :     # 'Refresh'
329 :     # add problem to set
330 :     # add set header to set
331 :     #
332 :     #########################################
333 :    
334 :     return if $self->{failure};
335 :     # FIXME: even with an error we still open a new page because of the target specified in the form
336 :    
337 :    
338 : gage 3667 # Some cases do not need a redirect: save, refresh, save_as, add_problem_to_set, add_header_to_set,make_local_copy
339 : gage 3037 my $action = $self->{action};
340 : gage 3718 return ;
341 : gage 3037
342 : gage 925 }
343 :    
344 : gage 3037
345 : gage 1747 sub initialize {
346 : sh002i 1924 my ($self) = @_;
347 :     my $r = $self->r;
348 : toenail 2305 my $authz = $r->authz;
349 :     my $user = $r->param('user');
350 : sh002i 1924
351 : toenail 2305 # Check permissions
352 :     return unless ($authz->hasPermissions($user, "access_instructor_tools"));
353 :     return unless ($authz->hasPermissions($user, "modify_problem_sets"));
354 : gage 3037
355 : dpvc 4163 my $file_type = $r->param('file_type') || "";
356 : gage 3037 my $tempFilePath = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file)
357 :     my $inputFilePath = $self->{inputFilePath}; # path to the file for input, (might be a .tmp file)
358 : gage 3667
359 :     $self->addmessage($r->param('status_message') ||''); # record status messages carried over if this is a redirect
360 : gage 3037 $self->addbadmessage("Changes in this file have not yet been permanently saved.") if -r $tempFilePath;
361 : gage 3718 if ( not( -e $inputFilePath) ) {
362 : gage 3883 $self->addbadmessage("The file '".$self->shortPath($inputFilePath)."' cannot be found.");
363 : dpvc 4163 } elsif ((not -w $inputFilePath) && $file_type ne 'blank_problem' ) {
364 : gage 3883
365 :     $self->addbadmessage("The file '".$self->shortPath($inputFilePath)."' is protected! ".CGI::br().
366 : dpvc 4161 "To edit this text you must make a copy of this file using the 'make local editable copy at ...' action below.");
367 : gage 3883
368 : gage 3718 }
369 : dpvc 4163 if ($inputFilePath =~/$BLANKPROBLEM$/ && $file_type ne 'blank_problem') {
370 : gage 3883 # $self->addbadmessage("This file '$inputFilePath' is a blank problem! ".CGI::br()."To edit this text you must
371 :     $self->addbadmessage("The file '".$self->shortPath($inputFilePath)."' is a blank problem! ".CGI::br()."To edit this text you must
372 : dpvc 4164 use 'Create a copy' below to save it to another file.");
373 : gage 3790 }
374 : gage 3037
375 : sh002i 1924 }
376 : gage 1747
377 : gage 2456 sub path {
378 :     my ($self, $args) = @_;
379 :     my $r = $self->r;
380 :     my $urlpath = $r->urlpath;
381 :     my $courseName = $urlpath->arg("courseID");
382 : gage 2474 my $setName = $r->urlpath->arg("setID") || '';
383 :     my $problemNumber = $r->urlpath->arg("problemID") || '';
384 : gage 2456
385 :     # we need to build a path to the problem being edited by hand, since it is not the same as the urlpath
386 :     # For this page the bread crum path leads back to the problem being edited, not to the Instructor tool.
387 :     my @path = ( 'WeBWork', $r->location,
388 :     "$courseName", $r->location."/$courseName",
389 :     "$setName", $r->location."/$courseName/$setName",
390 :     "$problemNumber", $r->location."/$courseName/$setName/$problemNumber",
391 :     "Editor", ""
392 :     );
393 :    
394 :     #print "\n<!-- BEGIN " . __PACKAGE__ . "::path -->\n";
395 :     print $self->pathMacro($args, @path);
396 :     #print "<!-- END " . __PACKAGE__ . "::path -->\n";
397 :    
398 :     return "";
399 :     }
400 : jj 2029 sub title {
401 :     my $self = shift;
402 :     my $r = $self->r;
403 : gage 3888 my $courseName = $r->urlpath->arg("courseID");
404 :     my $setID = $r->urlpath->arg("setID");
405 : jj 2029 my $problemNumber = $r->urlpath->arg("problemID");
406 :     my $file_type = $self->{'file_type'} || '';
407 : gage 3888
408 :     return "Set Header for set $setID" if ($file_type eq 'set_header');
409 :     return "Hardcopy Header for set $setID" if ($file_type eq 'hardcopy_header');
410 :     return "Course Information for course $courseName" if ($file_type eq 'course_info');
411 : gage 3883 return "Options Information" if ($file_type eq 'options_info');
412 : gage 3888
413 : jj 2029 return 'Problem ' . $r->{urlpath}->name;
414 :     }
415 :    
416 : sh002i 1924 sub body {
417 :     my ($self) = @_;
418 :     my $r = $self->r;
419 :     my $db = $r->db;
420 :     my $ce = $r->ce;
421 : toenail 2305 my $authz = $r->authz;
422 :     my $user = $r->param('user');
423 : toenail 2809 my $make_local_copy = $r->param('make_local_copy');
424 : gage 3037
425 : toenail 2305 # Check permissions
426 :     return CGI::div({class=>"ResultsWithError"}, "You are not authorized to access the Instructor tools.")
427 : gage 3040 unless $authz->hasPermissions($user, "access_instructor_tools");
428 : sh002i 1924
429 : toenail 2305 return CGI::div({class=>"ResultsWithError"}, "You are not authorized to modify problems.")
430 : gage 3040 unless $authz->hasPermissions($user, "modify_student_data");
431 : toenail 2305
432 :    
433 : gage 3736
434 :    
435 : sh002i 1924 # Gathering info
436 : gage 3037 my $editFilePath = $self->{editFilePath}; # path to the permanent file to be edited
437 :     my $tempFilePath = $self->{tempFilePath}; # path to the file currently being worked with (might be a .tmp file)
438 :     my $inputFilePath = $self->{inputFilePath}; # path to the file for input, (might be a .tmp file)
439 : gage 3718 my $setName = $self->{setID} ;
440 :     my $problemNumber = $self->{problemID} ;
441 : gage 3062 $setName = defined($setName) ? $setName : ''; # we need this instead of using the || construction
442 :     # to keep set 0 from being set to the
443 :     # empty string.
444 :     $problemNumber = defined($problemNumber) ? $problemNumber : '';
445 :    
446 : gage 3736 #########################################################################
447 :     # Construct url for reporting bugs:
448 : sh002i 1924 #########################################################################
449 : gage 3736
450 : gage 3779 # $editFilePath =~ m|([^/]*)Library|; #find the path to the file
451 :     # my $libraryName = $1; # find the library, if any exists in the path name (first library is picked)
452 :     # $libraryName ='rochester' unless defined($libraryName) and $libraryName =~/\S/; # default library
453 :     my $libraryName = '';
454 :     if ($editFilePath =~ m|([^/]*)Library|) { #find the path to the file
455 :     # find the library, if any exists in the path name (first library is picked)
456 :     my $tempLibraryName = $1;
457 :     $libraryName = ( defined($tempLibraryName) and $tempLibraryName =~/\S/ ) ?
458 :     $tempLibraryName : "Library";
459 :     # things that start /Library/setFoo/probBar are labeled as component "Library"
460 :     # which refers to the SQL based problem library. (is nationalLibrary a better name?)
461 :     } else {
462 :     $libraryName = 'rochester'; # make sure there is some default component defined.
463 :     }
464 :    
465 :     my $BUGZILLA = "http://bugs.webwork.rochester.edu/enter_bug.cgi?product=Problem%20libraries".
466 :     "&component=$libraryName&bug_file_loc=${editFilePath}_with_problemSeed=".$self->{problemSeed};
467 : gage 3736 #FIXME # The construction of this URL is somewhat fragile. A separate module could be devoted to intelligent reporting of bugs.
468 :    
469 :     #########################################################################
470 : sh002i 1924 # Find the text for the problem, either in the tmp file, if it exists
471 :     # or in the original file in the template directory
472 : gage 3037 # or in the problem contents gathered in the initialization phase.
473 : sh002i 1924 #########################################################################
474 :    
475 :     my $problemContents = ${$self->{r_problemContents}};
476 : gage 3718
477 : gage 3037 unless ( $problemContents =~/\S/) { # non-empty contents
478 :     if (-r $tempFilePath and not -d $tempFilePath) {
479 : sh002i 4057 die "tempFilePath is unsafe!" unless path_is_subdir($tempFilePath, $ce->{courseDirs}->{templates}, 1); # 1==path can be relative to dir
480 : gage 3037 eval { $problemContents = WeBWorK::Utils::readFile($tempFilePath) };
481 :     $problemContents = $@ if $@;
482 :     $inputFilePath = $tempFilePath;
483 :     } elsif (-r $editFilePath and not -d $editFilePath) {
484 : dpvc 4162 die "editFilePath is unsafe!" unless path_is_subdir($editFilePath, $ce->{courseDirs}->{templates}, 1) # 1==path can be relative to dir
485 :     || $editFilePath eq $ce->{webworkFiles}{screenSnippets}{setHeader}
486 : dpvc 4163 || $editFilePath eq $ce->{webworkFiles}{hardcopySnippets}{setHeader}
487 :     || $editFilePath eq $ce->{webworkFiles}{screenSnippets}{blankProblem};
488 : gage 3037 eval { $problemContents = WeBWorK::Utils::readFile($editFilePath) };
489 :     $problemContents = $@ if $@;
490 :     $inputFilePath = $editFilePath;
491 :     } else { # file not existing is not an error
492 :     #warn "No file exists";
493 :     $problemContents = '';
494 :     }
495 :     } else {
496 :     #warn "obtaining input from r_problemContents";
497 :     }
498 : gage 3062
499 : gage 3037 my $protected_file = not -w $inputFilePath;
500 : gage 3883
501 :     my $file_type = $self->{file_type};
502 :     my %titles = (
503 : dpvc 4163 problem => CGI::b("set $setName/problem $problemNumber"),
504 :     blank_problem => "blank problem",
505 : gage 3883 set_header => "header file",
506 :     hardcopy_header => "hardcopy header file",
507 :     course_info => "course information",
508 :     options_info => "options information",
509 :     '' => 'Unknown file type',
510 :     source_path_for_problem_file => " unassigned problem file: ".CGI::b("set $setName/problem $problemNumber"),
511 :     );
512 :     my $header = CGI::i("Editing $titles{$file_type} in file '".$self->shortPath($inputFilePath)."'");
513 : gage 3876 $header = ($self->isTempEditFilePath($inputFilePath) ) ? CGI::div({class=>'temporaryFile'},$header) : $header; # use colors if temporary file
514 : gage 3037
515 : sh002i 1924 #########################################################################
516 :     # Format the page
517 :     #########################################################################
518 :    
519 :     # Define parameters for textarea
520 :     # FIXME
521 :     # Should the seed be set from some particular user instance??
522 : gage 3037 my $rows = 20;
523 :     my $columns = 80;
524 :     my $mode_list = $ce->{pg}->{displayModes};
525 :     my $displayMode = $self->{displayMode};
526 :     my $problemSeed = $self->{problemSeed};
527 :     my $uri = $r->uri;
528 :     my $edit_level = $r->param('edit_level') || 0;
529 : jj 2016
530 : gage 3718 my $force_field = (defined($self->{sourceFilePath}) and $self->{sourceFilePath} ne "") ?
531 : jj 2016 CGI::hidden(-name=>'sourceFilePath',
532 : gage 3718 -default=>$self->{sourceFilePath}) : '';
533 : toenail 2305
534 : sh002i 4518 # FIXME this isn't used at all! --sam
535 : toenail 2305 my @allSetNames = sort $db->listGlobalSets;
536 : jj 2291 for (my $j=0; $j<scalar(@allSetNames); $j++) {
537 :     $allSetNames[$j] =~ s|^set||;
538 :     $allSetNames[$j] =~ s|\.def||;
539 :     }
540 : gage 3883 my $target = 'WW_View'; #"problem$edit_level"; # increasing edit_level gives you a new window with each edit.
541 : gage 3718
542 : gage 3883 print CGI::script(<<EOF);
543 :     function setTarget(inWindow) {
544 :     document.getElementById("newWindow").checked = inWindow;
545 :     updateTarget();
546 :     }
547 :     function updateTarget() {
548 :     var inWindow = document.getElementById("newWindow").checked;
549 :     document.getElementById("editor").target = (inWindow? "WW_View": "");
550 :     }
551 :     function setRadio(i,nw) {
552 :     document.getElementById('action'+i).checked = true;
553 :     setTarget(nw);
554 :     }
555 :     EOF
556 : gage 3037
557 : gage 3718 print CGI::p($header),
558 : gage 3883
559 :     CGI::start_form({method=>"POST", id=>"editor", name=>"editor", action=>"$uri", enctype=>"application/x-www-form-urlencoded"}),
560 :    
561 : sh002i 1924 $self->hidden_authen_fields,
562 : jj 2016 $force_field,
563 : sh002i 1924 CGI::hidden(-name=>'file_type',-default=>$self->{file_type}),
564 : gage 4272 CGI::div({}," | ",
565 : sh002i 1924 CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"},
566 : gage 3433 '&nbsp;Manpages&nbsp;',
567 : gage 3736 )," | ",
568 : gage 3433 CGI::a({-href=>'http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/PGmacrosByFile',-target=>"manpage_window"},
569 :     '&nbsp;macro list&nbsp;',
570 : gage 3736 )," | ",
571 : gage 3433 CGI::a({-href=>'http://devel.webwork.rochester.edu/doc/cvs/pg_HEAD/',-target=>"manpage_window"},
572 :     '&nbsp;pod docs&nbsp;',
573 : gage 3736 )," | ",
574 :     CGI::a({-href=>$BUGZILLA,-target=>"bugs_window"},
575 :     '&nbsp;report problem bugs&nbsp;',
576 :     )," | ",
577 : sh002i 1924 ),
578 :     CGI::p(
579 :     CGI::textarea(
580 :     -name => 'problemContents', -default => $problemContents,
581 : gage 4234 -rows => $rows, -cols => $columns, -override => 1,
582 : gage 3883 ),
583 : gage 3718 );
584 :    
585 :    
586 :    
587 :     ######### print action forms
588 :    
589 :     print CGI::start_table({});
590 :     #print CGI::Tr({}, CGI::td({-colspan=>2}, "Select an action to perform:"));
591 : gage 3037
592 : gage 3718 my @formsToShow = @{ ACTION_FORMS() };
593 :     my $default_choice = $formsToShow[0];
594 :     my $i = 0;
595 :     foreach my $actionID (@formsToShow) {
596 :     # Check permissions
597 :     #next if FORM_PERMS()->{$actionID} and not $authz->hasPermissions($user, FORM_PERMS()->{$actionID});
598 :     my $actionForm = "${actionID}_form";
599 : dpvc 3905 my $newWindow = ($actionID =~ m/^(view|add_problem|save)$/)? 1: 0;
600 :     my $onChange = "setRadio($i,$newWindow)";
601 : gage 3718 my %actionParams = $self->getActionParams($actionID);
602 :     my $line_contents = $self->$actionForm($onChange, %actionParams);
603 :     my $radio_params = {-type=>"radio", -name=>"action", -value=>$actionID};
604 :     $radio_params->{checked}=1 if ($actionID eq $default_choice) ;
605 : dpvc 3905 $radio_params->{onclick} = "setTarget($newWindow)";
606 :     $radio_params->{id} = "action$i";
607 : gage 3718 print CGI::Tr({-valign=>"top"},
608 :     CGI::td({}, CGI::input($radio_params)),
609 :     CGI::td({}, $line_contents)
610 :     ) if $line_contents;
611 :    
612 :     $i++;
613 :     }
614 : gage 3883 my $checkbox = CGI::input({-type=>"checkbox", -id=>"newWindow", -checked=>"checked",
615 :     -onchange=>"updateTarget()"});
616 :     $checkbox =~ s/\n//; # remove unwanted linebreak
617 :     print CGI::Tr({}, CGI::td({-colspan=>2}, "Select above then:",
618 :     CGI::submit(-name=>'submit', -value=>"Take Action!"),
619 : dpvc 3905 CGI::script("document.write('$checkbox in another window')")));
620 : gage 3718 print CGI::end_table();
621 :    
622 :    
623 :     print CGI::end_form();
624 : gage 3883
625 :     print CGI::script("updateTarget()");
626 : gage 3718 return "";
627 : gage 3037
628 : gage 3718
629 : sh002i 1924 }
630 : gage 1747
631 : gage 3883 #
632 :     # Convert long paths to [TMPL], etc.
633 :     #
634 :     sub shortPath {
635 :     my $self = shift; my $file = shift;
636 :     my $tmpl = $self->r->ce->{courseDirs}{templates};
637 :     my $root = $self->r->ce->{courseDirs}{root};
638 :     my $ww = $self->r->ce->{webworkDirs}{root};
639 :     $file =~ s|^$tmpl|[TMPL]|; $file =~ s|^$root|[COURSE]|; $file =~ s|^$ww|[WW]|;
640 :     return $file;
641 :     }
642 :    
643 : sh002i 1924 ################################################################################
644 :     # Utilities
645 :     ################################################################################
646 : gage 3667
647 : sh002i 4061 sub getRelativeSourceFilePath {
648 :     my ($self, $sourceFilePath) = @_;
649 :    
650 :     my $templatesDir = $self->r->ce->{courseDirs}->{templates};
651 :     $sourceFilePath =~ s|^$templatesDir/*||; # remove templates path and any slashes that follow
652 :    
653 :     return $sourceFilePath;
654 :     }
655 :    
656 : gage 3667 # determineLocalFilePath constructs a local file path parallel to a library file path
657 : gage 4167
658 : gage 3667 #
659 :     sub determineLocalFilePath {
660 : gage 3726 my $self= shift; die "determineLocalFilePath is a method" unless ref($self);
661 : gage 3667 my $path = shift;
662 : gage 3876 my $default_screen_header_path = $self->r->ce->{webworkFiles}->{hardcopySnippets}->{setHeader};
663 :     my $default_hardcopy_header_path = $self->r->ce->{webworkFiles}->{screenSnippets}->{setHeader};
664 :     my $setID = $self->{setID};
665 :     $setID = int(rand(1000)) unless $setID =~/\S/; # setID can be 0
666 : gage 3667 if ($path =~ /Library/) {
667 :     $path =~ s|^.*?Library/||; # truncate the url up to a segment such as ...rochesterLibrary/.......
668 : gage 3876 } elsif ($path eq $default_screen_header_path) {
669 :     $path = "set$setID/setHeader.pg";
670 :     } elsif ($path eq $default_hardcopy_header_path) {
671 :     $path = "set$setID/hardcopyHeader.tex";
672 : gage 3667 } else { # if its not in a library we'll just save it locally
673 : gage 3719 $path = "new_problem_".int(rand(1000)).".pg"; #l hope there aren't any collisions.
674 : gage 3667 }
675 :     $path;
676 :    
677 :     }
678 : gage 3718
679 : gage 3876 sub determineTempEditFilePath { # this does not create the directories in the path to the file
680 :     # it returns an absolute path to the file
681 :     my $self = shift; die "determineTempEditFilePath is a method" unless ref($self);
682 :     my $path =shift; # this should be an absolute path to the file
683 : gage 3718 my $user = $self->r->param("user");
684 : gage 3719 $user = int(rand(1000)) unless defined $user;
685 :     my $setID = $self->{setID} || int(rand(1000));
686 : gage 3718 my $courseDirectory = $self->r->ce->{courseDirs};
687 :     ###############
688 :     # Calculate the location of the temporary file
689 :     ###############
690 : gage 3876 my $templatesDirectory = $courseDirectory->{templates};
691 : gage 3726 my $blank_file_path = $self->r->ce->{webworkFiles}->{screenSnippets}->{blankProblem};
692 :     my $default_screen_header_path = $self->r->ce->{webworkFiles}->{hardcopySnippets}->{setHeader};
693 :     my $default_hardcopy_header_path = $self->r->ce->{webworkFiles}->{screenSnippets}->{setHeader};
694 : gage 3876 my $tmpEditFileDirectory = $self->getTempEditFileDirectory();
695 :     $self->addbadmessage("The path to the original file should be absolute") unless $path =~m|^/|; # debug
696 :     if ($path =~/^$tmpEditFileDirectory/) {
697 :     $self->addbadmessage("Error: This path is already in the temporary edit directory -- no new temporary file is created. path = $path");
698 :    
699 : gage 3718 } else {
700 : gage 3876 if ($path =~ /^$templatesDirectory/ ) {
701 :     $path =~ s|^$templatesDirectory||;
702 :     $path =~ s|^/||; # remove the initial slash if any
703 :     $path = "$tmpEditFileDirectory/$path.$user.tmp";
704 :     } elsif ($path eq $blank_file_path) {
705 :     $path = "$tmpEditFileDirectory/blank.$setID.$user.tmp"; # handle the case of the blank problem
706 :     } elsif ($path eq $default_screen_header_path) {
707 :     $path = "$tmpEditFileDirectory/screenHeader.$setID.$user.tmp"; # handle the case of the screen header in snippets
708 :     } elsif ($path eq $default_hardcopy_header_path) {
709 :     $path = "$tmpEditFileDirectory/hardcopyHeader.$setID.$user.tmp"; # handle the case of the hardcopy header in snippets
710 :     } else {
711 :     die "determineTempEditFilePath should only be used on paths within the templates directory, not on $path";
712 :     }
713 : gage 3718 }
714 :     $path;
715 :     }
716 : gage 3888
717 : gage 3876 sub determineOriginalEditFilePath { # determine the original path to a file corresponding to a temporary edit file
718 :     # returns path relative to the template directory
719 : gage 3718 my $self = shift;
720 :     my $path = shift;
721 : gage 3876 my $user = $self->r->param("user");
722 :     $self->addbadmessage("Can't determine user of temporary edit file $path.") unless defined($user);
723 :     my $templatesDirectory = $self->r->ce->{courseDirs} ->{templates};
724 :     my $tmpEditFileDirectory = $self->getTempEditFileDirectory();
725 :     # unless path is absolute assume that it is relative to the template directory
726 :     my $newpath = $path;
727 :     unless ($path =~ m|^/| ) {
728 :     $newpath = "$templatesDirectory/$path";
729 :     }
730 :     if ($self->isTempEditFilePath($newpath) ) {
731 :     $newpath =~ s|^$tmpEditFileDirectory/||; # delete temp edit directory
732 :     if ($newpath =~m|blank\.[^/]*$|) { # handle the case of the blank problem
733 :     $newpath = $self->r->ce->{webworkFiles}->{screenSnippets}->{blankProblem};
734 :     } elsif (($newpath =~m|hardcopyHeader\.[^/]*$|)) { # handle the case of the hardcopy header in snippets
735 :     $newpath = $self->r->ce->{webworkFiles}->{hardcopySnippets}->{setHeader};
736 :     } elsif (($newpath =~m|screenHeader\.[^/]*$|)) { # handle the case of the screen header in snippets
737 :     $newpath = $self->r->ce->{webworkFiles}->{screenSnippets}->{setHeader};
738 :     } else {
739 :     $newpath =~ s|\.$user\.tmp$||; # delete suffix
740 :    
741 :     }
742 :     #$self->addgoodmessage("Original file path is $newpath"); #FIXME debug
743 :     } else {
744 :     $self->addbadmessage("This path |$newpath| is not the path to a temporary edit file.");
745 :     # returns original path
746 :     }
747 :     $newpath;
748 :     }
749 :    
750 :     sub getTempEditFileDirectory {
751 :     my $self = shift;
752 :     my $courseDirectory = $self->r->ce->{courseDirs};
753 :     my $templatesDirectory = $courseDirectory->{templates};
754 :     my $tmpEditFileDirectory = (defined ($courseDirectory->{tmpEditFileDir}) ) ? $courseDirectory->{tmpEditFileDir} : "$templatesDirectory/tmpEdit";
755 :     $tmpEditFileDirectory;
756 :     }
757 :     sub isTempEditFilePath {
758 :     my $self = shift;
759 :     my $path = shift;
760 :     my $templatesDirectory = $self->r->ce->{courseDirs} ->{templates};
761 :     # unless path is absolute assume that it is relative to the template directory
762 :     unless ($path =~ m|^/| ) {
763 :     $path = "$templatesDirectory/$path";
764 :     }
765 :     my $tmpEditFileDirectory = $self->getTempEditFileDirectory();
766 : gage 3888
767 : gage 3718 ($path =~/^$tmpEditFileDirectory/) ? 1: 0;
768 :     }
769 : gage 3037 sub getFilePaths {
770 : gage 3718 my ($self, $setName, $problemNumber, $file_type) = @_;
771 : sh002i 1924 my $r = $self->r;
772 :     my $ce = $r->ce;
773 :     my $db = $r->db;
774 :     my $urlpath = $r->urlpath;
775 :     my $courseName = $urlpath->arg("courseID");
776 :     my $user = $r->param('user');
777 :     my $effectiveUserName = $r->param('effectiveUser');
778 : gage 3037
779 : sh002i 1924 $setName = '' unless defined $setName;
780 :     $problemNumber = '' unless defined $problemNumber;
781 : gage 3037 die 'Internal error to PGProblemEditor -- file type is not defined' unless defined $file_type;
782 : gage 3876 #$self->addgoodmessage("file type is $file_type"); #FIXME remove
783 : gage 3037 ##########################################################
784 :     # Determine path to the input file to be edited.
785 : gage 3718 # The permanent path of the input file == $editFilePath
786 :     # A temporary path to the input file == $tempFilePath
787 : gage 3037 ##########################################################
788 :     # Relevant parameters
789 :     # $r->param("displayMode")
790 :     # $r->param('problemSeed')
791 :     # $r->param('submit')
792 :     # $r->param('make_local_copy')
793 :     # $r->param('sourceFilePath')
794 :     # $r->param('problemContents')
795 :     # $r->param('save_to_new_file')
796 :     ##########################################################################
797 :     # Define the following variables
798 : gage 3718 # path to regular file -- $editFilePath;
799 :     # path to file being read (temporary or permanent)
800 : gage 3037 # contents of the file being read --- $problemContents
801 : gage 3718 # $self->{r_problemContents} = \$problemContents;
802 : gage 3037 ###########################################################################
803 :    
804 : sh002i 1924 my $editFilePath = $ce->{courseDirs}->{templates};
805 : gage 1348
806 : gage 3037 ##########################################################################
807 :     # Determine path to regular file, place it in $editFilePath
808 :     # problemSeed is defined for the file_type = 'problem' and 'source_path_to_problem'
809 :     ##########################################################################
810 :     CASE:
811 :     {
812 :     ($file_type eq 'course_info') and do {
813 :     # we are editing the course_info file
814 :     # value of courseFiles::course_info is relative to templates directory
815 :     $editFilePath .= '/' . $ce->{courseFiles}->{course_info};
816 :     last CASE;
817 :     };
818 : sh002i 1924
819 : gage 3883 ($file_type eq 'options_info') and do {
820 :     # we are editing the options_info file
821 :     # value of courseFiles::options_info is relative to templates directory
822 :     $editFilePath .= '/' . $ce->{courseFiles}->{options_info};
823 :     last CASE;
824 :     };
825 :    
826 : gage 3037 ($file_type eq 'blank_problem') and do {
827 :     $editFilePath = $ce->{webworkFiles}->{screenSnippets}->{blankProblem};
828 : dpvc 4163 $self->addbadmessage("This is a blank problem template file and can not be edited directly. "
829 : dpvc 4164 ."First use 'Create a copy' below to make a local copy, then add the file to the current problem set, then edit the file."
830 : gage 3667 );
831 : gage 3037 last CASE;
832 :     };
833 : sh002i 1924
834 : gage 3037 ($file_type eq 'set_header' or $file_type eq 'hardcopy_header') and do {
835 :     # first try getting the merged set for the effective user
836 : sh002i 4518 # FIXME merged set is overwritten immediately with global value... WTF? --sam
837 : gage 3037 my $set_record = $db->getMergedSet($effectiveUserName, $setName); # checked
838 :     # if that doesn't work (the set is not yet assigned), get the global record
839 :     $set_record = $db->getGlobalSet($setName); # checked
840 :     # bail if no set is found
841 :     die "Cannot find a set record for set $setName" unless defined($set_record);
842 :    
843 :     my $header_file = "";
844 :     $header_file = $set_record->{$file_type};
845 :     if ($header_file && $header_file ne "") {
846 : gage 3876 if ( $header_file =~ m|^/| ) { # if absolute address
847 :     $editFilePath = $header_file;
848 :     } else {
849 :     $editFilePath .= '/' . $header_file;
850 :     }
851 : gage 3037 } else {
852 : gage 3876 # if the set record doesn't specify the filename for a header
853 : gage 3037 # then the set uses the default from snippets
854 : gage 3876
855 : gage 3037 $editFilePath = $ce->{webworkFiles}->{screenSnippets}->{setHeader} if $file_type eq 'set_header';
856 :     $editFilePath = $ce->{webworkFiles}->{hardcopySnippets}->{setHeader} if $file_type eq 'hardcopy_header';
857 : gage 3883
858 :     # $self->addbadmessage("'".$self->shortPath($editFilePath)."' is the default header file and cannot be edited directly.".CGI::br()."Any changes you make will have to be saved as another file.");
859 :     #}
860 :    
861 : gage 3037 }
862 :     last CASE;
863 :     }; #end 'set_header, hardcopy_header' case
864 :    
865 :     ($file_type eq 'problem') and do {
866 :    
867 :     # first try getting the merged problem for the effective user
868 :     my $problem_record = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked
869 :    
870 :     # if that doesn't work (the problem is not yet assigned), get the global record
871 :     $problem_record = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem_record); # checked
872 :     # bail if no source path for the problem is found ;
873 :     die "Cannot find a problem record for set $setName / problem $problemNumber" unless defined($problem_record);
874 :     $editFilePath .= '/' . $problem_record->source_file;
875 :     # define the problem seed for later use
876 :     $self->{problemSeed}= $problem_record->problem_seed if defined($problem_record) and $problem_record->can('problem_seed') ;
877 :     last CASE;
878 :     }; # end 'problem' case
879 :    
880 :     ($file_type eq 'source_path_for_problem_file') and do {
881 : gage 3718 my $forcedSourceFile = $self->{sourceFilePath};
882 : gage 3876 # if the source file is in the temporary edit directory find the original source file
883 :     # the source file is relative to the templates directory.
884 :     if ($self->isTempEditFilePath($forcedSourceFile) ) {
885 :     $forcedSourceFile = $self->determineOriginalEditFilePath($forcedSourceFile); # original file path
886 :     $self->addgoodmessage("the original path to the file is $forcedSourceFile"); #FIXME debug
887 :     }
888 :     # bail if no source path for the problem is found ;
889 : gage 3037 die "Cannot find a file path to save to" unless( defined($forcedSourceFile) and ($forcedSourceFile =~ /\S/) );
890 :     $self->{problemSeed} = 1234;
891 :     $editFilePath .= '/' . $forcedSourceFile;
892 :     last CASE;
893 :     }; # end 'source_path_for_problem_file' case
894 :     } # end CASE: statement
895 : jj 2016
896 : gage 1348
897 : toenail 2809 # if a set record or problem record contains an empty blank for a header or problem source_file
898 :     # we could find ourselves trying to edit /blah/templates/.toenail.tmp or something similar
899 :     # which is almost undoubtedly NOT desirable
900 :    
901 :     if (-d $editFilePath) {
902 : gage 3883 my $msg = "The file '".$self->shortPath($editFilePath)."' is a directory!";
903 : gage 3037 $self->{failure} = 1;
904 :     $self->addbadmessage($msg);
905 : toenail 2809 }
906 : gage 3037 if (-e $editFilePath and not -r $editFilePath) { #it's ok if the file doesn't exist, perhaps we're going to create it
907 :     # with save as
908 : gage 3883 my $msg = "The file '".$self->shortPath($editFilePath)."' cannot be read!";
909 : gage 3037 $self->{failure} = 1;
910 :     $self->addbadmessage($msg);
911 : sh002i 1924 }
912 : gage 3037 #################################################
913 :     # The path to the permanent file is now verified and stored in $editFilePath
914 :     # Whew!!!
915 :     #################################################
916 : sh002i 1924
917 : gage 3876 my $tempFilePath = $self->determineTempEditFilePath($editFilePath); #"$editFilePath.$TEMPFILESUFFIX";
918 : gage 3037 $self->{editFilePath} = $editFilePath;
919 :     $self->{tempFilePath} = $tempFilePath;
920 : gage 3718 $self->{inputFilePath} = (-r $tempFilePath) ? $tempFilePath : $editFilePath;
921 :     #warn "editfile path is $editFilePath and tempFile is $tempFilePath and inputFilePath is ". $self->{inputFilePath};
922 : gage 3037 }
923 : gage 3876 sub saveFileChanges {
924 : gage 3315
925 :     ################################################################################
926 : gage 3876 # saveFileChanges does most of the work. it is a separate method so that it can
927 : gage 3315 # be called from either pre_header_initialize() or initilize(), depending on
928 :     # whether a redirect is needed or not.
929 :     #
930 :     # it actually does a lot more than save changes to the file being edited, and
931 :     # sometimes less.
932 :     ################################################################################
933 : gage 3037
934 : gage 3718 my ($self, $outputFilePath, $problemContents ) = @_;
935 :     my $r = $self->r;
936 :     my $ce = $r->ce;
937 : gage 3037
938 : gage 3718 my $action = $self->{action}||'no action';
939 : gage 4167 # my $editFilePath = $self->{editFilePath}; # not used??
940 :     my $sourceFilePath = $self->{sourceFilePath};
941 : gage 3037 my $tempFilePath = $self->{tempFilePath};
942 : gage 3718
943 :     if (defined($problemContents) and ref($problemContents) ) {
944 :     $problemContents = ${$problemContents};
945 :     } elsif( not defined($problemContents) or $problemContents =~/\S/ ) {
946 :     $problemContents = ${$self->{r_problemContents}};
947 :     }
948 : gage 1747 ##############################################################################
949 :     # read and update the targetFile and targetFile.tmp files in the directory
950 :     # if a .tmp file already exists use that, unless the revert button has been pressed.
951 : gage 3718 # The .tmp files are removed when the file is or when the revert occurs.
952 : gage 1747 ##############################################################################
953 :    
954 : gage 3037
955 : gage 3718 unless (defined($outputFilePath) and $outputFilePath =~/\S/ ) {
956 :     $self->addbadmessage("You must specify an file name in order to save a new file.");
957 :     return "";
958 :     }
959 :     my $do_not_save = 0 ; # flag to prevent saving of file
960 : gage 1591 my $editErrors = '';
961 : gage 3037
962 : gage 1747 ##############################################################################
963 :     # write changes to the approriate files
964 : malsyned 980 # FIXME make sure that the permissions are set correctly!!!
965 :     # Make sure that the warning is being transmitted properly.
966 : gage 1747 ##############################################################################
967 : gage 3718
968 : gage 3037 my $writeFileErrors;
969 : gage 3718 if ( defined($outputFilePath) and $outputFilePath =~/\S/ ) { # save file
970 : gage 3037 # Handle the problem of line endings.
971 :     # Make sure that all of the line endings are of unix type.
972 :     # Convert \r\n to \n
973 : gage 3718 #$problemContents =~ s/\r\n/\n/g;
974 :     #$problemContents =~ s/\r/\n/g;
975 : gage 3037
976 : toenail 2134 # make sure any missing directories are created
977 : gage 3718 WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates},
978 : gage 3037 $outputFilePath);
979 : sh002i 4057 die "outputFilePath is unsafe!" unless path_is_subdir($outputFilePath, $ce->{courseDirs}->{templates}, 1); # 1==path can be relative to dir
980 : gage 3037
981 : gage 1750 eval {
982 :     local *OUTPUTFILE;
983 : gage 3718 open OUTPUTFILE, ">$outputFilePath"
984 : gage 3037 or die "Failed to open $outputFilePath";
985 : gage 1750 print OUTPUTFILE $problemContents;
986 : gage 3718 close OUTPUTFILE;
987 :     # any errors are caught in the next block
988 :     };
989 :    
990 : gage 3037 $writeFileErrors = $@ if $@;
991 :     }
992 : gage 4167
993 : gage 1980 ###########################################################
994 :     # Catch errors in saving files, clean up temp files
995 :     ###########################################################
996 : gage 3037
997 : gage 3718 $self->{saveError} = $do_not_save; # don't do redirects if the file was not saved.
998 : gage 3037 # don't unlink files or send success messages
999 : gage 1980
1000 : gage 3037 if ($writeFileErrors) {
1001 :     # get the current directory from the outputFilePath
1002 :     $outputFilePath =~ m|^(/.*?/)[^/]+$|;
1003 : toenail 2288 my $currentDirectory = $1;
1004 :    
1005 :     my $errorMessage;
1006 :     # check why we failed to give better error messages
1007 :     if ( not -w $ce->{courseDirs}->{templates} ) {
1008 :     $errorMessage = "Write permissions have not been enabled in the templates directory. No changes can be made.";
1009 :     } elsif ( not -w $currentDirectory ) {
1010 : gage 3883 $errorMessage = "Write permissions have not been enabled in '".$self->shortPath($currentDirectory)."'. Changes must be saved to a different directory for viewing.";
1011 : gage 3037 } elsif ( -e $outputFilePath and not -w $outputFilePath ) {
1012 : gage 3883 $errorMessage = "Write permissions have not been enabled for '".$self->shortPath($outputFilePath)."'. Changes must be saved to another file for viewing.";
1013 : toenail 2288 } else {
1014 : gage 3883 $errorMessage = "Unable to write to '".$self->shortPath($outputFilePath)."': $writeFileErrors";
1015 : toenail 2288 }
1016 :    
1017 : gage 3037 $self->{failure} = 1;
1018 : toenail 2288 $self->addbadmessage(CGI::p($errorMessage));
1019 :    
1020 : gage 3037 }
1021 : gage 3718 ###########################################################
1022 : gage 4167 # FIXME if the file is accompanied by auxiliary files transfer them as well
1023 :     # if the filepath ends in foobar/foobar.pg then we assume there are auxiliary files
1024 :     # copy the contents of the original foobar directory to the new one
1025 :     #
1026 :     ###########################################################
1027 :     # If things have worked so far determine if the file might be accompanied by auxiliary files
1028 : gage 4415 # a path ending in foo/foo.pg is assumed to contain auxilliary files
1029 :     #
1030 : gage 4245 my $auxiliaryFilesExist = 0;
1031 : gage 4415 if (defined($outputFilePath) and $outputFilePath) {
1032 :     my ($dir, $prob) = $outputFilePath =~ m|([^/]+)/([^/]+)\.pg$|; # must be a problem file ending in .pg
1033 :     $auxiliaryFilesExist = 1 if (defined($dir) and defined ($prob) and $dir eq $prob);
1034 :     }
1035 :    
1036 : gage 4168 if ($auxiliaryFilesExist and not $do_not_save ) {
1037 : gage 4167 my $sourceDirectory = $sourceFilePath;
1038 :     my $outputDirectory = $outputFilePath;
1039 :     $sourceDirectory =~ s|/[^/]+\.pg$||;
1040 :     $outputDirectory =~ s|/[^/]+\.pg$||;
1041 : gage 4234 ##############
1042 :     # Transfer this to Utils::copyAuxiliaryFiles($sourceDirectory, $destinationDirectory)
1043 :     ##############
1044 : gage 4167 my @filesToCopy;
1045 :     @filesToCopy = WeBWorK::Utils::readDirectory($sourceDirectory) if -d $sourceDirectory;
1046 :     foreach my $file (@filesToCopy) {
1047 :     next if $file =~ /\.pg$/; # .pg file should already be transferred
1048 :     my $fromPath = "$sourceDirectory/$file";
1049 :     my $toPath = "$outputDirectory/$file";
1050 :     if (-f $fromPath and -r $fromPath and not -e $toPath) { # don't copy directories, don't copy files that have already been copied
1051 :     copy($fromPath, $toPath) or $writeFileErrors.= "<br> Error copying $fromPath to $toPath";
1052 :     # need to use binary transfer for gif files. File::Copy does this.
1053 :     #warn "copied from $fromPath to $toPath";
1054 :     #warn "files are different ",system("diff $fromPath $toPath");
1055 :     }
1056 :     $self->addbadmessage($writeFileErrors) if defined($writeFileErrors) and $writeFileErrors;
1057 :    
1058 :    
1059 :     }
1060 : gage 4234 $self->addgoodmessage("Copied auxiliary files from $sourceDirectory to new location at $outputDirectory");
1061 :    
1062 : gage 4167 }
1063 : gage 4234 ##############
1064 :     ##############
1065 : gage 4167
1066 :     ###########################################################
1067 : gage 3718 # clean up temp files on revert, save and save_as
1068 :     ###########################################################
1069 : gage 3037 unless( $writeFileErrors or $do_not_save) { # everything worked! unlink and announce success!
1070 : gage 981 # unlink the temporary file if there are no errors and the save button has been pushed
1071 : gage 3883 if (($action eq 'save' or $action eq 'save_as') and (-w $self->{tempFilePath}) ) {
1072 : gage 3876
1073 : gage 3883 $self->addgoodmessage("Deleting temp file at " . $self->shortPath($self->{tempFilePath}));
1074 : sh002i 4057 die "tempFilePath is unsafe!" unless path_is_subdir($self->{tempFilePath}, $ce->{courseDirs}->{templates}, 1); # 1==path can be relative to dir
1075 : gage 3037 unlink($self->{tempFilePath}) ;
1076 :     }
1077 : gage 3883
1078 : gage 3876 if ( defined($outputFilePath) and ! $self->{failure} and not $self->isTempEditFilePath($outputFilePath) ) {
1079 :     # don't announce saving of temporary editing files
1080 : gage 3883 my $msg = "Saved to file '".$self->shortPath($outputFilePath)."'.";
1081 :    
1082 : gage 3037 $self->addgoodmessage($msg);
1083 : gage 3883 #$self->{inputFilePath} = $outputFilePath; ## DPVC -- avoid file-not-found message
1084 : gage 3037 }
1085 :    
1086 : sh002i 1924 }
1087 : gage 3718
1088 :    
1089 : gage 3876 } # end saveFileChanges
1090 : gage 3718
1091 :    
1092 :    
1093 :    
1094 :    
1095 :     sub getActionParams {
1096 :     my ($self, $actionID) = @_;
1097 :     my $r = $self->{r};
1098 :    
1099 :     my %actionParams=();
1100 :     foreach my $param ($r->param) {
1101 :     next unless $param =~ m/^action\.$actionID\./;
1102 :     $actionParams{$param} = [ $r->param($param) ];
1103 :     }
1104 :     return %actionParams;
1105 :     }
1106 :    
1107 :     sub fixProblemContents {
1108 :     #NOT a method
1109 :     my $problemContents = shift;
1110 :     # Handle the problem of line endings.
1111 :     # Make sure that all of the line endings are of unix type.
1112 :     # Convert \r\n to \n
1113 :     $problemContents =~ s/\r\n/\n/g;
1114 :     $problemContents =~ s/\r/\n/g;
1115 :     $problemContents;
1116 :     }
1117 :    
1118 :     sub fresh_edit_handler {
1119 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1120 : gage 3811 #$self->addgoodmessage("fresh_edit_handler called");
1121 : gage 3718 }
1122 :     sub view_form {
1123 :     my ($self, $onChange, %actionParams) = @_;
1124 : gage 3888 my $file_type = $self->{file_type};
1125 :     return "" if $file_type eq 'hardcopy_header'; # these can't yet be edited from temporary files #FIXME
1126 : gage 3718 my $output_string = "View";
1127 : gage 3888 unless ($file_type eq 'course_info' || $file_type eq 'options_info') {
1128 :    
1129 : gage 3718 $output_string .= join(" ",
1130 : gage 3883 " using seed ",
1131 :     CGI::textfield(-name=>'action.view.seed',-value=>$self->{problemSeed},-onfocus=>$onChange),
1132 : gage 3718 "and display mode ",
1133 :     CGI::popup_menu(-name=>'action.view.displayMode', -values=>$self->r->ce->{pg}->{displayModes},
1134 : dpvc 3907 -default=>$self->{displayMode}, -onmousedown=>$onChange)
1135 : gage 3718 );
1136 :     }
1137 :    
1138 : dpvc 4161 return $output_string; #FIXME add -labels to the pop up menu
1139 : gage 3718 }
1140 :    
1141 :     sub view_handler {
1142 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1143 :     my $courseName = $self->{courseID};
1144 :     my $setName = $self->{setID};
1145 :     my $problemNumber = $self->{problemID};
1146 :     my $problemSeed = ($actionParams->{'action.view.seed'}) ?
1147 :     $actionParams->{'action.view.seed'}->[0]
1148 :     : 1234;
1149 :     my $displayMode = ($actionParams->{'action.view.displayMode'}) ?
1150 :     $actionParams->{'action.view.displayMode'}->[0]
1151 :     : $self->r->ce->{pg}->{options}->{displayMode};
1152 :    
1153 :     my $editFilePath = $self->{editFilePath};
1154 :     my $tempFilePath = $self->{tempFilePath};
1155 :     ########################################################
1156 :     # grab the problemContents from the form in order to save it to the tmp file
1157 :     ########################################################
1158 :     my $problemContents = fixProblemContents($self->r->param('problemContents'));
1159 :     $self->{r_problemContents} = \$problemContents;
1160 :    
1161 :    
1162 :     my $do_not_save = 0;
1163 :     my $file_type = $self->{file_type};
1164 : gage 3876 $self->saveFileChanges($tempFilePath,);
1165 : gage 3718
1166 :     ########################################################
1167 :     # construct redirect URL and redirect
1168 :     ########################################################
1169 :     my $edit_level = $self->r->param("edit_level") || 0;
1170 :     $edit_level++;
1171 :     my $viewURL;
1172 :    
1173 : sh002i 4061 my $relativeTempFilePath = $self->getRelativeSourceFilePath($tempFilePath);
1174 :    
1175 : sh002i 3815 if ($file_type eq 'problem' or $file_type eq 'source_path_for_problem_file') { # redirect to Problem.pm
1176 : gage 3718 my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
1177 :     courseID => $courseName, setID => $setName, problemID => $problemNumber
1178 :     );
1179 : malsyned 980
1180 : gage 3718 $viewURL = $self->systemLink($problemPage,
1181 :     params => {
1182 :     displayMode => $displayMode,
1183 :     problemSeed => $problemSeed,
1184 :     editMode => "temporaryFile",
1185 :     edit_level => $edit_level,
1186 : sh002i 4061 sourceFilePath => $relativeTempFilePath,
1187 : gage 3718 status_message => uri_escape($self->{status_message})
1188 : gage 3037
1189 : gage 3718 }
1190 :     );
1191 : gage 3888 } elsif ($file_type eq 'set_header' ) { # redirect to ProblemSet
1192 : gage 3718 my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
1193 :     courseID => $courseName, setID => $setName,
1194 :     );
1195 :    
1196 :     $viewURL = $self->systemLink($problemPage,
1197 :     params => {
1198 : gage 3883 set_header => $tempFilePath,
1199 : gage 3718 displayMode => $displayMode,
1200 :     problemSeed => $problemSeed,
1201 :     editMode => "temporaryFile",
1202 :     edit_level => $edit_level,
1203 : sh002i 4061 sourceFilePath => $relativeTempFilePath,
1204 : gage 3718 status_message => uri_escape($self->{status_message})
1205 :    
1206 :     }
1207 :     );
1208 : gage 3888 } elsif ($file_type eq 'hardcopy_header') { # redirect to ProblemSet?? # it's difficult to view temporary changes for hardcopy headers
1209 :     my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
1210 :     courseID => $courseName, setID => $setName,
1211 :     );
1212 :    
1213 :     $viewURL = $self->systemLink($problemPage,
1214 :     params => {
1215 :     set_header => $tempFilePath,
1216 :     displayMode => $displayMode,
1217 :     problemSeed => $problemSeed,
1218 :     editMode => "temporaryFile",
1219 :     edit_level => $edit_level,
1220 : sh002i 4061 sourceFilePath => $relativeTempFilePath,
1221 : gage 3888 status_message => uri_escape($self->{status_message})
1222 : gage 3718
1223 : gage 3888 }
1224 :     );
1225 : gage 3718
1226 : gage 3883 } elsif ($file_type eq 'course_info') { # redirec to ProblemSets.pm
1227 : gage 3718 my $problemSetsPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
1228 :     courseID => $courseName);
1229 :     $viewURL = $self->systemLink($problemSetsPage,
1230 :     params => {
1231 : gage 3888
1232 : gage 3883 course_info => $tempFilePath,
1233 : gage 3876 editMode => "temporaryFile",
1234 : gage 3718 edit_level => $edit_level,
1235 : sh002i 4061 sourceFilePath => $relativeTempFilePath,
1236 : gage 3718 status_message => uri_escape($self->{status_message})
1237 :     }
1238 :     );
1239 : gage 3883 } elsif ($file_type eq 'options_info') { # redirec to Options.pm
1240 :     my $optionsPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Options",
1241 :     courseID => $courseName);
1242 :     $viewURL = $self->systemLink($optionsPage,
1243 :     params => {
1244 : gage 3888 options_info => $tempFilePath,
1245 : gage 3883 editMode => "temporaryFile",
1246 :     edit_level => $edit_level,
1247 : sh002i 4061 sourceFilePath => $relativeTempFilePath,
1248 : gage 3883 status_message => uri_escape($self->{status_message})
1249 :     }
1250 :     );
1251 : gage 3718 } else {
1252 :     die "I don't know how to redirect this file type $file_type ";
1253 :     }
1254 : malsyned 980
1255 : gage 3718 $self->reply_with_redirect($viewURL);
1256 :     }
1257 :    
1258 :     sub add_problem_form {
1259 :     my $self = shift;
1260 :     my ($onChange, %actionParams) = @_;
1261 :     my $r = $self->r;
1262 :     my $setName = $self->{setID} ;
1263 :     my $problemNumber = $self->{problemID} ;
1264 :     $setName = defined($setName) ? $setName : ''; # we need this instead of using the || construction
1265 :     # to keep set 0 from being set to the
1266 :     # empty string.
1267 : gage 3883 my $filePath = $self->{inputFilePath};
1268 : gage 3718 $setName =~ s|^set||;
1269 :     my @allSetNames = sort $r->db->listGlobalSets;
1270 :     for (my $j=0; $j<scalar(@allSetNames); $j++) {
1271 :     $allSetNames[$j] =~ s|^set||;
1272 :     $allSetNames[$j] =~ s|\.def||;
1273 :     }
1274 : gage 3883 my $labels = {
1275 :     problem => 'problem',
1276 :     set_header => 'set header',
1277 :     hardcopy_header => 'hardcopy header',
1278 :     };
1279 :     return "" if $self->{file_type} eq 'course_info' || $self->{file_type} eq 'options_info';
1280 : gage 3718 return join(" ",
1281 : gage 3883 "Add to set " ,
1282 :     CGI::popup_menu({name=>'action.add_problem.target_set', values=>\@allSetNames, default=>$setName, onmousedown=>$onChange}),
1283 : gage 3718 " as ",
1284 : gage 3883 CGI::popup_menu({name=>'action.add_problem.file_type', values=>['problem','set_header', 'hardcopy_header'], labels=>$labels, default=>$self->{file_type}, onmousedown=>$onChange}),
1285 : gage 3718
1286 :     ); #FIXME add -lables to the pop up menu
1287 :     return "";
1288 :     }
1289 :    
1290 :     sub add_problem_handler {
1291 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1292 : gage 3811 #$self->addgoodmessage("add_problem_handler called");
1293 : gage 3718 my $courseName = $self->{courseID};
1294 :     my $setName = $self->{setID};
1295 :     my $problemNumber = $self->{problemID};
1296 :     my $sourceFilePath = $self->{editFilePath};
1297 :     my $displayMode = $self->{displayMode};
1298 :     my $problemSeed = $self->{problemSeed};
1299 :    
1300 :     my $targetSetName = $actionParams->{'action.add_problem.target_set'}->[0];
1301 :     my $targetFileType = $actionParams->{'action.add_problem.file_type'}->[0];
1302 :     my $templatesPath = $self->r->ce->{courseDirs}->{templates};
1303 :     $sourceFilePath =~ s|^$templatesPath/||;
1304 :    
1305 :     my $edit_level = $self->r->param("edit_level") || 0;
1306 :     $edit_level++;
1307 :    
1308 :     my $viewURL ='';
1309 :     if ($targetFileType eq 'problem') {
1310 :     my $targetProblemNumber = 1+ WeBWorK::Utils::max( $self->r->db->listGlobalProblems($targetSetName));
1311 :    
1312 :     #################################################
1313 :     # Update problem record
1314 :     #################################################
1315 :     my $problemRecord = $self->addProblemToSet(
1316 :     setName => $targetSetName,
1317 :     sourceFile => $sourceFilePath,
1318 : gage 3719 problemID => $targetProblemNumber, #added to end of set
1319 : gage 3718 );
1320 :     $self->assignProblemToAllSetUsers($problemRecord);
1321 :     $self->addgoodmessage("Added $sourceFilePath to ". $targetSetName. " as problem $targetProblemNumber") ;
1322 :     $self->{file_type} = 'problem'; # change file type to problem -- if it's not already that
1323 :    
1324 :     #################################################
1325 :     # Set up redirect Problem.pm
1326 :     #################################################
1327 :     my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
1328 :     courseID => $courseName,
1329 :     setID => $targetSetName,
1330 :     problemID => $targetProblemNumber,
1331 :     );
1332 : sh002i 4061 my $relativeSourceFilePath = $self->getRelativeSourceFilePath($sourceFilePath);
1333 : gage 3718 $viewURL = $self->systemLink($problemPage,
1334 :     params => {
1335 :     displayMode => $displayMode,
1336 :     problemSeed => $problemSeed,
1337 :     editMode => "savedFile",
1338 :     edit_level => $edit_level,
1339 : sh002i 4061 sourceFilePath => $relativeSourceFilePath,
1340 : gage 3718 status_message => uri_escape($self->{status_message})
1341 :    
1342 :     }
1343 :     );
1344 :     } elsif ($targetFileType eq 'set_header') {
1345 :     #################################################
1346 :     # Update set record
1347 :     #################################################
1348 : gage 3726 my $setRecord = $self->r->db->getGlobalSet($targetSetName);
1349 : gage 3718 $setRecord->set_header($sourceFilePath);
1350 : gage 3726 if( $self->r->db->putGlobalSet($setRecord) ) {
1351 : gage 3883 $self->addgoodmessage("Added '".$self->shortPath($sourceFilePath)."' to ". $targetSetName. " as new set header ") ;
1352 : gage 3718 } else {
1353 : gage 3883 $self->addbadmessage("Unable to make '".$self->shortPath($sourceFilePath)."' the set header for $targetSetName");
1354 : gage 3718 }
1355 :     $self->{file_type} = 'set_header'; # change file type to set_header if it not already so
1356 :     #################################################
1357 :     # Set up redirect
1358 :     #################################################
1359 :     my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
1360 :     courseID => $courseName, setID => $targetSetName
1361 :     );
1362 :     $viewURL = $self->systemLink($problemPage,
1363 :     params => {
1364 :     displayMode => $displayMode,
1365 :     editMode => "savedFile",
1366 :     edit_level => $edit_level,
1367 :     status_message => uri_escape($self->{status_message})
1368 :     }
1369 :     );
1370 :     } else {
1371 :     die "Don't know what to do with target file type $targetFileType";
1372 :     }
1373 :    
1374 :     $self->reply_with_redirect($viewURL);
1375 :     }
1376 :    
1377 :    
1378 :     sub save_form {
1379 :     my ($self, $onChange, %actionParams) = @_;
1380 :     my $r => $self->r;
1381 : gage 3883 #return "" unless defined($self->{tempFilePath}) and -e $self->{tempFilePath};
1382 : gage 3790 if ($self->{editFilePath} =~ /$BLANKPROBLEM$/ ) {
1383 :     return ""; #Can't save blank problems without changing names
1384 :     } elsif (-w $self->{editFilePath}) {
1385 : gage 3883
1386 : dpvc 4165 return "Save to ".CGI::b($self->shortPath($self->{editFilePath}))." and View";
1387 : gage 3883
1388 : gage 3718 } else {
1389 :     return ""; #"Can't save -- No write permission";
1390 :     }
1391 :    
1392 :     }
1393 :    
1394 :     sub save_handler {
1395 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1396 : gage 3811 #$self->addgoodmessage("save_handler called");
1397 : gage 3718 my $courseName = $self->{courseID};
1398 :     my $setName = $self->{setID};
1399 :     my $problemNumber = $self->{problemID};
1400 :     my $displayMode = $self->{displayMode};
1401 :     my $problemSeed = $self->{problemSeed};
1402 :    
1403 :     #################################################
1404 :     # grab the problemContents from the form in order to save it to a new permanent file
1405 :     # later we will unlink (delete) the current temporary file
1406 :     #################################################
1407 :     my $problemContents = fixProblemContents($self->r->param('problemContents'));
1408 :     $self->{r_problemContents} = \$problemContents;
1409 :    
1410 :     #################################################
1411 :     # Construct the output file path
1412 :     #################################################
1413 :     my $editFilePath = $self->{editFilePath};
1414 :     my $outputFilePath = $editFilePath;
1415 :    
1416 :     my $do_not_save = 0;
1417 :     my $file_type = $self->{file_type};
1418 : gage 3876 $self->saveFileChanges($outputFilePath);
1419 : gage 3718 #################################################
1420 :     # Set up redirect to Problem.pm
1421 :     #################################################
1422 :     my $viewURL;
1423 :     ########################################################
1424 :     # construct redirect URL and redirect
1425 :     ########################################################
1426 : gage 3883 if ($file_type eq 'problem' || $file_type eq 'source_path_for_problem_file') { # redirect to Problem.pm
1427 : gage 3718 my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
1428 :     courseID => $courseName, setID => $setName, problemID => $problemNumber
1429 :     );
1430 :    
1431 : sh002i 4061 my $relativeEditFilePath = $self->getRelativeSourceFilePath($editFilePath);
1432 :    
1433 : gage 3718 $viewURL = $self->systemLink($problemPage,
1434 :     params => {
1435 :     displayMode => $displayMode,
1436 :     problemSeed => $problemSeed,
1437 :     editMode => "savedFile",
1438 :     edit_level => 0,
1439 : sh002i 4061 sourceFilePath => $relativeEditFilePath,
1440 : gage 3718 status_message => uri_escape($self->{status_message})
1441 :    
1442 :     }
1443 :     );
1444 : gage 3888 } elsif ($file_type eq 'set_header' ) { # redirect to ProblemSet
1445 : gage 3718 my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
1446 :     courseID => $courseName, setID => $setName,
1447 :     );
1448 :    
1449 :     $viewURL = $self->systemLink($problemPage,
1450 :     params => {
1451 :     displayMode => $displayMode,
1452 :     problemSeed => $problemSeed,
1453 :     editMode => "savedFile",
1454 :     edit_level => 0,
1455 :     status_message => uri_escape($self->{status_message})
1456 :    
1457 :     }
1458 :     );
1459 : gage 3888 } elsif ( $file_type eq 'hardcopy_header') { # redirect to ProblemSet
1460 :     my $problemPage = $self->r->urlpath->newFromModule('WeBWorK::ContentGenerator::Hardcopy',
1461 :     courseID => $courseName, setID => $setName,
1462 :     );
1463 :    
1464 :     $viewURL = $self->systemLink($problemPage,
1465 :     params => {
1466 :     displayMode => $displayMode,
1467 :     problemSeed => $problemSeed,
1468 :     editMode => "savedFile",
1469 :     edit_level => 0,
1470 :     status_message => uri_escape($self->{status_message})
1471 : gage 3718
1472 : gage 3888 }
1473 :     );
1474 : gage 3718
1475 :     } elsif ($file_type eq 'course_info') { # redirect to ProblemSets.pm
1476 :     my $problemSetsPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
1477 :     courseID => $courseName);
1478 :     $viewURL = $self->systemLink($problemSetsPage,
1479 :     params => {
1480 :     editMode => ("savedFile"),
1481 :     edit_level => 0,
1482 :     status_message => uri_escape($self->{status_message})
1483 :     }
1484 :     );
1485 : gage 3883 } elsif ($file_type eq 'options_info') { # redirect to Options.pm
1486 :     my $optionsPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Options",
1487 :     courseID => $courseName);
1488 :     $viewURL = $self->systemLink($optionsPage,
1489 :     params => {
1490 :     editMode => ("savedFile"),
1491 :     edit_level => 0,
1492 :     status_message => uri_escape($self->{status_message})
1493 :     }
1494 :     );
1495 : gage 3724 } elsif ($file_type eq 'source_path_for_problem_file') { # redirect to ProblemSets.pm
1496 :     my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
1497 :     courseID => $courseName, setID => $setName, problemID => $problemNumber
1498 :     );
1499 :     my $viewURL = $self->systemLink($problemPage,
1500 :     params=>{
1501 :     displayMode => $displayMode,
1502 :     problemSeed => $problemSeed,
1503 :     editMode => "savedFile",
1504 :     edit_level => 0,
1505 :     sourceFilePath => $outputFilePath, #The path relative to the templates directory is required.
1506 :     file_type => 'source_path_for_problem_file',
1507 :     status_message => uri_escape($self->{status_message})
1508 : gage 3718
1509 : gage 3724 }
1510 :     );
1511 :    
1512 : gage 3718 } else {
1513 :     die "I don't know how to redirect this file type $file_type ";
1514 :     }
1515 :    
1516 :     $self->reply_with_redirect($viewURL);
1517 :     }
1518 :    
1519 : gage 3883
1520 : gage 3888
1521 : gage 3883 sub make_local_copy_form {
1522 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1523 :     my $editFilePath = $self->{editFilePath}; # path to the permanent file to be edited
1524 :     #warn "editFilePath $editFilePath inputFilePath",$self->{inputFilePath};
1525 :     return "" unless -e $editFilePath;
1526 :     return "" if -w $editFilePath;
1527 :     return "" unless $self->{file_type} eq 'problem' # need problem structure to make local copy in most cases
1528 : dpvc 4165 or $self->{file_type} eq 'blank_problem' # $editFilePath eq $self->r->cr->{webworkFiles}{screenSnippets}{blankProblem}
1529 :     or $self->{file_type} eq 'set_header' # $editFilePath eq $self->r->ce->{webworkFiles}->{hardcopySnippets}->{setHeader} # special case to make copy of screen header
1530 :     or $self->{file_type} eq 'hardcopy_header'; # $editFilePath eq $self->r->ce->{webworkFiles}->{screenSnippets}->{setHeader} ; # special case to make copy of hardcopy header
1531 : gage 3883 # or $self->{file_type} eq 'source_path_for_problem_file'; # need setID and problemID to make local copy -- can't be done in this case.
1532 :     return join ("",
1533 :     "Make local editable copy at: [TMPL]/".($self->determineLocalFilePath($editFilePath)),
1534 :     CGI::hidden(-name=>'action.make_local_copy.target_file', -value=>$self->determineLocalFilePath($editFilePath) ),
1535 :     CGI::hidden(-name=>'action.make_local_copy.source_file', -value=>$editFilePath ),
1536 :     CGI::hidden(-name=>'action.make_local_copy.file_type',-value=>$self->{file_type}),
1537 :     CGI::hidden(-name=>'action.make_local_copy.saveMode',-value=>'rename')
1538 :     );
1539 :    
1540 :     }
1541 :    
1542 :    
1543 :    
1544 :    
1545 :    
1546 :    
1547 :    
1548 :    
1549 :    
1550 :    
1551 :     sub make_local_copy_handler {
1552 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1553 :     foreach my $key (qw(target_file file_type saveMode source_file)) {
1554 :     $actionParams->{"action.save_as.$key"}->[0] = $actionParams->{"action.make_local_copy.$key"}->[0];
1555 :     #warn "action.make_local_copy.$key", @{$actionParams->{"action.make_local_copy.$key"}}
1556 :     }
1557 :     save_as_handler($self, $genericParams, $actionParams, $tableParams);
1558 :    
1559 : gage 3888
1560 : gage 3883 }
1561 :     sub save_as_form { # calls the save_as_handler
1562 : gage 3718 my ($self, $onChange, %actionParams) = @_;
1563 : gage 3883 my $editFilePath = $self->{editFilePath};
1564 : dpvc 4165 # return "" unless -w $editFilePath; ## DPVC -- we don't need to be able to write the original in order to make a copy
1565 : gage 3883
1566 : gage 4167
1567 : gage 3876 my $templatesDir = $self->r->ce->{courseDirs}->{templates};
1568 : gage 3883 my $setID = $self->{setID};
1569 : gage 4167
1570 :    
1571 :     my $shortFilePath = $editFilePath;
1572 : gage 3883 $shortFilePath =~ s|^$templatesDir/||;
1573 : dpvc 4165 $shortFilePath =~ s|^.*/|| if $shortFilePath =~ m|^/|; # if it is still an absolute path don't suggest that you save to it.
1574 : gage 4167
1575 : dpvc 4165 ### --- old menu-based apparoach ---
1576 :     # my $allowedActions = (defined($setID) && $setID =~/\S/ && $setID ne 'Undefined_Set') ? ['save_a_copy','rename' ] : ['save_a_copy'];
1577 :    
1578 :     # return CGI::popup_menu(
1579 :     # -name=>'action.save_as.saveMode', -values=>$allowedActions,
1580 :     # -default=>'rename',-labels=>{save_a_copy=>'Create a copy of file at ', rename=>'Rename file path to'},
1581 :     # -onmousedown=>$onChange
1582 :     # ). " [TMPL]/".
1583 :     ###
1584 :    
1585 :     my $probNum = ($self->{file_type} eq 'problem')? "/problem $self->{problemID}" : "";
1586 :     my $andRelink = '';
1587 :     $andRelink = ' and '.CGI::checkbox(
1588 :     -name => "action.save_as.saveMode",
1589 :     -value => "rename",
1590 :     -label => "",
1591 :     -checked => 1,
1592 :     -onclick=>$onChange
1593 :     ).
1594 :     " use in ".CGI::b("set $setID$probNum")
1595 :     if defined($setID) && $setID =~ m/\S/ && $setID ne 'Undefined_Set' &&
1596 :     $self->{file_type} ne 'blank_problem';
1597 :     return 'Create a copy at [TMPL]/'.
1598 : gage 3883 CGI::textfield(
1599 : gage 4167 -name=>'action.save_as.target_file', -size=>30, -value=>"$shortFilePath", #FIXME -- you might not be able to save to this default filepath
1600 : gage 3883 -onfocus=>$onChange
1601 :     ).
1602 :     CGI::hidden(-name=>'action.save_as.source_file', -value=>$editFilePath ).
1603 : dpvc 4165 CGI::hidden(-name=>'action.save_as.file_type',-value=>$self->{file_type}).
1604 :     $andRelink;
1605 : gage 3718 }
1606 : gage 4168
1607 : gage 3718 sub save_as_handler {
1608 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1609 : gage 3811 #$self->addgoodmessage("save_as_handler called");
1610 : dpvc 3905 $self->{status_message} = ''; ## DPVC -- remove bogus old messages
1611 : gage 3718 my $courseName = $self->{courseID};
1612 :     my $setName = $self->{setID};
1613 :     my $problemNumber = $self->{problemID};
1614 :     my $displayMode = $self->{displayMode};
1615 :     my $problemSeed = $self->{problemSeed};
1616 :    
1617 :     my $do_not_save = 0;
1618 : dpvc 4165 my $saveMode = $actionParams->{'action.save_as.saveMode'}->[0] || 'save_a_copy';
1619 : gage 3883 my $new_file_name = $actionParams->{'action.save_as.target_file'}->[0] || '';
1620 :     my $sourceFilePath = $actionParams->{'action.save_as.source_file'}->[0] || '';
1621 :     my $file_type = $actionParams->{'action.save_as.file_type'}->[0] || '';
1622 : gage 4167 $self ->{sourceFilePath} = $sourceFilePath; # store for use in saveFileChanges
1623 : gage 3718 $new_file_name =~ s/^\s*//; #remove initial and final white space
1624 :     $new_file_name =~ s/\s*$//;
1625 :     if ( $new_file_name !~ /\S/) { # need a non-blank file name
1626 :     # setting $self->{failure} stops saving and any redirects
1627 :     $do_not_save = 1;
1628 :     $self->addbadmessage(CGI::p("Please specify a file to save to."));
1629 :     }
1630 :    
1631 :     #################################################
1632 :     # grab the problemContents from the form in order to save it to a new permanent file
1633 :     # later we will unlink (delete) the current temporary file
1634 :     #################################################
1635 :     my $problemContents = fixProblemContents($self->r->param('problemContents'));
1636 :     $self->{r_problemContents} = \$problemContents;
1637 : gage 3883 warn "problem contents is empty" unless $problemContents;
1638 : gage 3718 #################################################
1639 :     # Rescue the user in case they forgot to end the file name with .pg
1640 :     #################################################
1641 : gage 3883
1642 :     if($file_type eq 'problem'
1643 :     or $file_type eq 'blank_problem'
1644 :     or $file_type eq 'set_header') {
1645 : gage 3718 $new_file_name =~ s/\.pg$//; # remove it if it is there
1646 :     $new_file_name .= '.pg'; # put it there
1647 :    
1648 :     }
1649 :     #################################################
1650 :     # Construct the output file path
1651 :     #################################################
1652 :     my $outputFilePath = $self->r->ce->{courseDirs}->{templates} . '/' .
1653 :     $new_file_name;
1654 :     if (defined $outputFilePath and -e $outputFilePath) {
1655 :     # setting $do_not_save stops saving and any redirects
1656 :     $do_not_save = 1;
1657 : gage 3883 $self->addbadmessage(CGI::p("File '".$self->shortPath($outputFilePath)."' exists.
1658 :     File not saved. No changes have been made.
1659 :     You can change the file path for this problem manually from the 'Hmwk Sets Editor' page"));
1660 : gage 3718 } else {
1661 :     $self->{editFilePath} = $outputFilePath;
1662 :     $self->{tempFilePath} = ''; # nothing needs to be unlinked.
1663 :     $self->{inputFilePath} = '';
1664 :     }
1665 :    
1666 :    
1667 :     unless ($do_not_save ) {
1668 : gage 3883 $self->saveFileChanges($outputFilePath);
1669 : gage 3790
1670 : gage 3883 if ($saveMode eq 'rename' and -r $outputFilePath) {
1671 :     #################################################
1672 : gage 4167 # Modify source file path in problem
1673 : gage 3883 #################################################
1674 :     if ($file_type eq 'set_header' ) {
1675 :     my $setRecord = $self->r->db->getGlobalSet($setName);
1676 :     $setRecord->set_header($new_file_name);
1677 :     if ($self->r->db->putGlobalSet($setRecord)) {
1678 :     $self->addgoodmessage("The set header for set $setName has been renamed to '".$self->shortPath($outputFilePath)."'.") ;
1679 :     } else {
1680 :     $self->addbadmessage("Unable to change the set header for set $setName. Unknown error.");
1681 :     }
1682 :     } elsif ($file_type eq 'hardcopy_header' ) {
1683 :     my $setRecord = $self->r->db->getGlobalSet($setName);
1684 :     $setRecord->hardcopy_header($new_file_name);
1685 :     if ($self->r->db->putGlobalSet($setRecord)) {
1686 :     $self->addgoodmessage("The hardcopy header for set $setName has been renamed to '".$self->shortPath($outputFilePath)."'.") ;
1687 :     } else {
1688 :     $self->addbadmessage("Unable to change the hardcopy header for set $setName. Unknown error.");
1689 :     }
1690 : gage 3790 } else {
1691 : gage 3883 my $problemRecord = $self->r->db->getGlobalProblem($setName,$problemNumber);
1692 :     $problemRecord->source_file($new_file_name);
1693 :     if ( $self->r->db->putGlobalProblem($problemRecord) ) {
1694 :     $self->addgoodmessage("The source file for 'set $setName / problem $problemNumber' has been changed from ".
1695 :     $self->shortPath($sourceFilePath)." to '".$self->shortPath($outputFilePath)."'.") ;
1696 :     } else {
1697 :     $self->addbadmessage("Unable to change the source file path for set $setName, problem $problemNumber. Unknown error.");
1698 :     }
1699 : gage 3790 }
1700 :     } elsif ($saveMode eq 'save_a_copy') {
1701 : gage 3883 #################################################
1702 : gage 4167 # Don't modify source file path in problem -- just report
1703 : gage 3883 #################################################
1704 :    
1705 :     #$self->{status_message} = ''; ## DPVC remove old messages
1706 :     $self->addgoodmessage("A new file has been created at '".$self->shortPath($outputFilePath).
1707 :     "' with the contents below. No changes have been made to set $setName.");
1708 : gage 3790 } else {
1709 :     $self->addbadmessage("Don't recognize saveMode: |$saveMode|. Unknown error.");
1710 :     }
1711 : gage 3883
1712 : gage 3718 }
1713 :     my $edit_level = $self->r->param("edit_level") || 0;
1714 :     $edit_level++;
1715 :    
1716 :     #################################################
1717 :     # Set up redirect
1718 :     # The redirect gives the server time to detect that the new file exists.
1719 :     #################################################
1720 : gage 3790 my $problemPage;
1721 : gage 3883 my $new_file_type;
1722 : gage 3790 if ($saveMode eq 'save_a_copy' ) {
1723 :     $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
1724 :     courseID => $courseName, setID => 'Undefined_Set', problemID => 'Undefined_Set'
1725 :     );
1726 : gage 3883 $new_file_type = 'source_path_for_problem_file';
1727 : gage 3790 } elsif ($saveMode eq 'rename') {
1728 :     $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
1729 :     courseID => $courseName, setID => $setName, problemID => $problemNumber
1730 :     );
1731 : gage 3883 $new_file_type = $file_type;
1732 : gage 3790 } else {
1733 :     $self->addbadmessage("Don't recognize saveMode: |$saveMode|. Unknown error.");
1734 : gage 3883 die "Don't recognize saveMode: |$saveMode|. Unknown error."
1735 : gage 3790 }
1736 : gage 3888
1737 :     #warn "save mode is $saveMode";
1738 :    
1739 : sh002i 4061 my $relativeOutputFilePath = $self->getRelativeSourceFilePath($outputFilePath);
1740 :    
1741 : gage 3718 my $viewURL = $self->systemLink($problemPage,
1742 :     params=>{
1743 : sh002i 4061 sourceFilePath => $relativeOutputFilePath, #The path relative to the templates directory is required.
1744 : gage 3718 edit_level => $edit_level,
1745 : gage 3883 file_type => $new_file_type,
1746 : gage 3718 status_message => uri_escape($self->{status_message})
1747 :    
1748 :     }
1749 :     );
1750 :    
1751 :     $self->reply_with_redirect($viewURL);
1752 :     return ""; # no redirect needed
1753 :     }
1754 :     sub revert_form {
1755 :     my ($self, $onChange, %actionParams) = @_;
1756 : gage 3883 my $editFilePath = $self->{editFilePath};
1757 :     return "Error: The original file $editFilePath cannot be read." unless -r $editFilePath;
1758 :     return "" unless defined($self->{tempFilePath}) and -e $self->{tempFilePath} ;
1759 :     return "Revert to ".$self->shortPath($editFilePath) ;
1760 : gage 3718
1761 :     }
1762 :     sub revert_handler {
1763 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1764 : sh002i 4059 my $ce = $self->r->ce;
1765 : gage 3883 #$self->addgoodmessage("revert_handler called");
1766 : gage 3718 my $editFilePath = $self->{editFilePath};
1767 :     $self->{inputFilePath} = $editFilePath;
1768 :     # unlink the temp files;
1769 : sh002i 4057 die "tempFilePath is unsafe!" unless path_is_subdir($self->{tempFilePath}, $ce->{courseDirs}->{templates}, 1); # 1==path can be relative to dir
1770 : gage 3718 unlink($self->{tempFilePath});
1771 : gage 3883 $self->addgoodmessage("Deleting temp file at " . $self->shortPath($self->{tempFilePath}));
1772 : gage 3876 $self->{tempFilePath} = '';
1773 : gage 3718 my $problemContents ='';
1774 :     $self->{r_problemContents} = \$problemContents;
1775 : gage 3883 $self->addgoodmessage("Reverting to original file '".$self->shortPath($editFilePath)."'");
1776 : gage 3718 # no redirect is needed
1777 :     }
1778 :    
1779 :    
1780 : gage 3888
1781 :    
1782 : gage 3883 # sub make_local_copy_handler {
1783 :     # my ($self, $genericParams, $actionParams, $tableParams) = @_;
1784 :     # #$self->addgoodmessage("make_local_copy_handler called");
1785 :     #
1786 :     # my $courseName = $self->{courseID};
1787 :     # my $setName = $self->{setID};
1788 :     # my $problemNumber = $self->{problemID};
1789 :     #
1790 :     # my $displayMode = $self->{displayMode};
1791 :     # my $problemSeed = $self->{problemSeed};
1792 :     # my $do_not_save = 0; #error flag
1793 :     #
1794 :     # my $new_file_name = $actionParams->{'action.make_local_copy.target_file'}->[0] || '';
1795 :     # my $sourceFilePath = $actionParams->{'action.make_local_copy.source_file'}->[0] || '';
1796 :     # my $file_type = $actionParams->{'action.make_local_copy.file_type'}->[0] ||'';
1797 :     #
1798 :     # my $templatesPath = $self->r->ce->{courseDirs}->{templates};
1799 :     # $sourceFilePath =~ s|^$templatesPath/||; # make sure path relative to templates directory
1800 :     #
1801 :     # if ( $new_file_name !~ /\S/) { # need a non-blank file name
1802 :     # # setting $self->{failure} stops saving and any redirects
1803 :     # $do_not_save = 1;
1804 :     # #warn "new file name is $new_file_name";
1805 :     # $self->addbadmessage(CGI::p("Error: File to save to not specified."));
1806 :     # }
1807 :     #
1808 :     # #################################################
1809 :     # # grab the problemContents from the form in order to save it to a new permanent file
1810 :     # # later we will unlink (delete) the current temporary file
1811 :     # #################################################
1812 :     #
1813 :     # my $problemContents = fixProblemContents($self->r->param('problemContents'));
1814 :     # $self->{r_problemContents} = \$problemContents;
1815 :     # warn "problem contents is empty" unless $problemContents;
1816 :     # #################################################
1817 :     # # Construct the output file path
1818 :     # #################################################
1819 :     # my $outputFilePath = $self->r->ce->{courseDirs}->{templates} . '/' .
1820 :     # $new_file_name;
1821 :     # if (defined $outputFilePath and -e $outputFilePath) {
1822 :     # # setting $do_not_save stops saving and any redirects
1823 :     # $do_not_save = 1;
1824 :     # $self->addbadmessage(CGI::p("File '".$self->shortPath($outputFilePath)."' exists.
1825 :     # File not saved. No changes have been made.
1826 :     # You can change the file path for this problem manually from the 'Hmwk Sets Editor' page"));
1827 :     # } else {
1828 :     # #$self->addgoodmessage("Saving to file '".$self->shortPath($outputFilePath)."'.");
1829 :     # }
1830 :     #
1831 :     # unless ($do_not_save ) {
1832 :     # $self->saveFileChanges($outputFilePath);
1833 :     # #################################################
1834 :     # # Modify source file in problem
1835 :     # #################################################
1836 :     # if ($file_type eq 'set_header') {
1837 :     # my $setRecord = $self->r->db->getGlobalSet($setName);
1838 :     # $setRecord->set_header($new_file_name);
1839 :     # if ($self->r->db->putGlobalSet($setRecord)) {
1840 :     # $self->addgoodmessage("The set header for set $setName has been renamed to '".$self->shortPath($outputFilePath)."'.") ;
1841 :     # } else {
1842 :     # $self->addbadmessage("Unable to change the header for set $setName. Unknown error.");
1843 :     # }
1844 :     # } else {
1845 :     # my $problemRecord = $self->r->db->getGlobalProblem($setName,$problemNumber);
1846 :     # $problemRecord->source_file($new_file_name);
1847 :     # if ( $self->r->db->putGlobalProblem($problemRecord) ) {
1848 :     # $self->addgoodmessage("The current source file for problem $problemNumber has been renamed to '".$self->shortPath($outputFilePath)."'.") ;
1849 :     # } else {
1850 :     # $self->addbadmessage("Unable to change the source file path for set $setName, problem $problemNumber. Unknown error.");
1851 :     # }
1852 :     # }
1853 :     #
1854 :     # }
1855 :     # my $edit_level = $self->r->param("edit_level") || 0;
1856 :     # $edit_level++;
1857 :     # #################################################
1858 :     # # Set up redirect
1859 :     # #################################################
1860 :     #
1861 :     # my $problemPage = $self->r->urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
1862 :     # courseID => $courseName, setID => $setName, problemID => $problemNumber
1863 :     # );
1864 :     # my $viewURL = $self->systemLink($problemPage,
1865 :     # params=>{
1866 :     # sourceFilePath => $new_file_name,
1867 :     # edit_level => $edit_level,
1868 :     # file_type => $self->{file_type},
1869 :     # status_message => uri_escape($self->{status_message})
1870 :     #
1871 :     # }
1872 :     # );
1873 :     # $self->reply_with_redirect($viewURL);
1874 :     # }
1875 : gage 3718
1876 : gage 3876 # sub rename_form { # see the save_as form
1877 :     # # my ($self, $onChange, %actionParams) = @_;
1878 :     # # my $problemPath = $self->{editFilePath};
1879 :     # # my $templatesDir = $self->r->ce->{courseDirs}->{templates};
1880 :     # # #warn "problemPath $problemPath $templatesDir";
1881 :     # # $problemPath =~ s|^$templatesDir/||;
1882 :     # # $problemPath = '' if $problemPath =~ m|^/|; # if it is still an absolute path don't suggest that you save to it.
1883 :     # # $self->addbadmessage("problem Path is $problemPath");
1884 :     # # return join("",
1885 :     # # "Rename problem file to : [TMPL]/".CGI::textfield(-name=>'action.rename.target_file', -size=>40, -value=>$problemPath),
1886 :     # # CGI::hidden(-name=>'action.make_local_copy.source_file', -value=>$self->{editFilePath} ),
1887 :     # # );
1888 :     #
1889 :     #
1890 :     # }
1891 : gage 3718
1892 : gage 3883 # sub rename_handler {
1893 :     # my ($self, $genericParams, $actionParams, $tableParams) = @_;
1894 :     # $actionParams->{'action.make_local_copy.target_file'}->[0] = $actionParams->{'action.rename.target_file'}->[0];
1895 :     # make_local_copy_handler($self, $genericParams, $actionParams, $tableParams);
1896 :     # }
1897 : gage 3790
1898 :    
1899 : gage 3888
1900 : gage 889 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9