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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.2305  
changed lines
  Added in v.3908

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9