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