|
|
1 | ################################################################################ |
|
|
2 | # WeBWorK Online Homework Delivery System |
|
|
3 | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ |
|
|
4 | # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v 1.41 2004/05/27 22:28:21 jj Exp $ |
|
|
5 | # |
|
|
6 | # This program is free software; you can redistribute it and/or modify it under |
|
|
7 | # the terms of either: (a) the GNU General Public License as published by the |
|
|
8 | # Free Software Foundation; either version 2, or (at your option) any later |
|
|
9 | # version, or (b) the "Artistic License" which comes with this package. |
|
|
10 | # |
|
|
11 | # This program is distributed in the hope that it will be useful, but WITHOUT |
|
|
12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
|
13 | # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the |
|
|
14 | # Artistic License for more details. |
|
|
15 | ################################################################################ |
|
|
16 | |
| 1 | package WeBWorK::ContentGenerator::Instructor::PGProblemEditor; |
17 | package WeBWorK::ContentGenerator::Instructor::PGProblemEditor; |
| 2 | use base qw(WeBWorK::ContentGenerator::Instructor); |
18 | use base qw(WeBWorK::ContentGenerator::Instructor); |
| 3 | |
19 | |
| 4 | |
20 | |
| 5 | =head1 NAME |
21 | =head1 NAME |
| … | |
… | |
| 9 | =cut |
25 | =cut |
| 10 | |
26 | |
| 11 | use strict; |
27 | use strict; |
| 12 | use warnings; |
28 | use warnings; |
| 13 | use CGI qw(); |
29 | use CGI qw(); |
| 14 | use WeBWorK::Utils qw(readFile); |
30 | use WeBWorK::Utils qw(readFile surePathToFile); |
|
|
31 | use Apache::Constants qw(:common REDIRECT); |
|
|
32 | use HTML::Entities; |
|
|
33 | use WeBWorK::Utils::Tasks qw(fake_set fake_problem); |
| 15 | |
34 | |
|
|
35 | ########################################################### |
|
|
36 | # 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 |
|
|
38 | # |
|
|
39 | # Only files under the template directory ( or linked to this location) can be edited. |
|
|
40 | # |
|
|
41 | # The course information and problems are located in the course templates directory. |
|
|
42 | # Course information has the name defined by courseFiles->{course_info} |
|
|
43 | # |
|
|
44 | # Only files under the template directory ( or linked to this location) can be edited. |
|
|
45 | # |
|
|
46 | # editMode = temporaryFile (view the temp file defined by course_info.txt.user_name.tmp |
|
|
47 | # instead of the file course_info.txt) |
|
|
48 | # The editFileSuffix is "user_name.tmp" by default. It's definition should be moved to Instructor.pm #FIXME |
|
|
49 | ########################################################### |
|
|
50 | |
| 16 | our $libraryName; |
51 | #our $libraryName; |
| 17 | our $rowheight; |
52 | #our $rowheight; |
|
|
53 | |
|
|
54 | sub pre_header_initialize { |
|
|
55 | my ($self) = @_; |
|
|
56 | my $r = $self->r; |
|
|
57 | my $ce = $r->ce; |
|
|
58 | my $urlpath = $r->urlpath; |
|
|
59 | |
|
|
60 | my $submit_button = $r->param('submit'); # obtain submit command from form |
|
|
61 | my $file_type = $r->param("file_type") || ''; |
|
|
62 | |
|
|
63 | # Save problem to permanent or temporary file, then redirect for viewing |
|
|
64 | if (defined($submit_button) and |
|
|
65 | ($submit_button eq 'Save' or $submit_button eq 'Refresh' |
|
|
66 | or ($submit_button eq 'Save as' and $file_type eq 'problem'))) { |
|
|
67 | my $setName = $r->urlpath->arg("setID"); |
|
|
68 | my $problemNumber = $r->urlpath->arg("problemID"); |
|
|
69 | |
|
|
70 | # write the necessary files |
|
|
71 | # return file path for viewing problem in $self->{currentSourceFilePath} |
|
|
72 | # obtain the appropriate seed |
|
|
73 | $self->saveFileChanges($setName, $problemNumber); |
|
|
74 | |
|
|
75 | ##### calculate redirect URL based on file type ##### |
|
|
76 | |
|
|
77 | # get some information |
|
|
78 | #my $hostname = $r->hostname(); |
|
|
79 | #my $port = $r->get_server_port(); |
|
|
80 | #my $uri = $r->uri; |
|
|
81 | my $courseName = $urlpath->arg("courseID"); |
|
|
82 | my $problemSeed = ($r->param('problemSeed')) ? $r->param('problemSeed') : ''; |
|
|
83 | my $displayMode = ($r->param('displayMode')) ? $r->param('displayMode') : ''; |
|
|
84 | |
|
|
85 | my $viewURL = ''; |
|
|
86 | |
|
|
87 | if($self->{file_type} eq 'problem') { |
|
|
88 | if($submit_button eq 'Save as') { # redirect to myself |
|
|
89 | my $sourceFile = $self->{problemPath}; |
|
|
90 | # strip off template directory prefix |
|
|
91 | my $edit_level = $r->param("edit_level") || 0; |
|
|
92 | $edit_level++; |
|
|
93 | $sourceFile =~ s|^$ce->{courseDirs}->{templates}/||; |
|
|
94 | my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", |
|
|
95 | courseID => $courseName, setID => 'Undefined_Set', problemID => $problemNumber); |
|
|
96 | $viewURL = $self->systemLink($problemPage, params=>{sourceFilePath => $sourceFile, edit_level=>$edit_level}); |
|
|
97 | } else { # other problems redirect to Problem.pm |
|
|
98 | my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", |
|
|
99 | courseID => $courseName, setID => $setName, problemID => $problemNumber); |
|
|
100 | $self->{currentSourceFilePath} =~ s|^$ce->{courseDirs}->{templates}/||; |
|
|
101 | $viewURL = $self->systemLink($problemPage, |
|
|
102 | params => { |
|
|
103 | displayMode => $displayMode, |
|
|
104 | problemSeed => $problemSeed, |
|
|
105 | editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"), |
|
|
106 | sourceFilePath => $self->{currentSourceFilePath}, |
|
|
107 | success => $self->{sucess}, |
|
|
108 | failure => $self->{failure}, |
|
|
109 | } |
|
|
110 | ); |
|
|
111 | } |
|
|
112 | } |
|
|
113 | |
|
|
114 | # set headers redirect to ProblemSet.pm |
|
|
115 | $self->{file_type} eq 'set_header' and do { |
|
|
116 | my $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", |
|
|
117 | courseID => $courseName, setID => $setName); |
|
|
118 | $viewURL = $self->systemLink($problemSetPage, |
|
|
119 | params => { |
|
|
120 | displayMode => $displayMode, |
|
|
121 | problemSeed => $problemSeed, |
|
|
122 | editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"), |
|
|
123 | } |
|
|
124 | ); |
|
|
125 | }; |
|
|
126 | |
|
|
127 | # course info redirects to ProblemSets.pm |
|
|
128 | $self->{file_type} eq 'course_info' and do { |
|
|
129 | my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", |
|
|
130 | courseID => $courseName); |
|
|
131 | $viewURL = $self->systemLink($problemSetsPage, |
|
|
132 | params => { |
|
|
133 | editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"), |
|
|
134 | } |
|
|
135 | ); |
|
|
136 | }; |
|
|
137 | |
|
|
138 | # don't redirect on bad save attempts |
|
|
139 | # FIXME: even with an error we still open a new page because of the target specified in the form |
|
|
140 | return if $self->{failure}; |
|
|
141 | |
|
|
142 | if ($viewURL) { |
|
|
143 | $self->reply_with_redirect($viewURL); |
|
|
144 | } else { |
|
|
145 | die "Invalid file_type ", $self->{file_type}, " specified by saveFileChanges"; |
|
|
146 | } |
|
|
147 | } |
|
|
148 | } |
|
|
149 | |
|
|
150 | sub initialize { |
|
|
151 | my ($self) = @_; |
|
|
152 | my $r = $self->r; |
|
|
153 | |
|
|
154 | my $setName = $r->urlpath->arg("setID"); |
|
|
155 | my $problemNumber = $r->urlpath->arg("problemID"); |
|
|
156 | |
|
|
157 | # if we got to initialize(), then saveFileChanges was not called in pre_header_initialize(). |
|
|
158 | # therefore we call it here unless there has been an error already: |
|
|
159 | $self->saveFileChanges($setName, $problemNumber) unless $self->{failure}; |
|
|
160 | } |
| 18 | |
161 | |
| 19 | sub title { |
162 | sub title { |
| 20 | my $self = shift; |
163 | my $self = shift; |
| 21 | #FIXME don't need the entire path ?? |
164 | my $r = $self->r; |
| 22 | return "Instructor Tools - PG Problem Editor for ". $self->{ce}->{problemPath}; |
165 | my $problemNumber = $r->urlpath->arg("problemID"); |
|
|
166 | my $file_type = $self->{'file_type'} || ''; |
|
|
167 | return "Set Header" if($file_type eq 'set_header'); |
|
|
168 | return "Course Information" if($file_type eq 'course_info'); |
|
|
169 | return 'Problem ' . $r->{urlpath}->name; |
| 23 | } |
170 | } |
| 24 | |
171 | |
| 25 | sub body { |
172 | sub body { |
| 26 | my $self = shift; |
173 | my ($self) = @_; |
| 27 | |
|
|
| 28 | # test area |
|
|
| 29 | my $r = $self->{r}; |
174 | my $r = $self->r; |
| 30 | my $db = $self->{db}; |
175 | my $db = $r->db; |
| 31 | my $ce = $self->{ce}; |
176 | my $ce = $r->ce; |
| 32 | my $user = $r->param('user'); |
|
|
| 33 | my $key = $db->getKey($user)->key(); |
|
|
| 34 | |
177 | |
| 35 | |
|
|
| 36 | ################ |
|
|
| 37 | # Gathering info |
178 | # Gathering info |
| 38 | # What is needed |
179 | my $editFilePath = $self->{problemPath}; # path to the permanent file to be edited |
| 39 | # $problemPath -- |
180 | my $inputFilePath = $self->{inputFilePath}; # path to the file currently being worked with (might be a .tmp file) |
| 40 | # $formURL -- given by $r->uri |
|
|
| 41 | # $tmpProblemPath |
|
|
| 42 | #my ($problemPath,$formURL,$tmpProblemPath) = $self->initialize(); |
|
|
| 43 | my $problemPath = $ce->{problemPath}; |
|
|
| 44 | |
|
|
| 45 | my $tmpProblemPath = $ce->{tmpProblemPath}; |
|
|
| 46 | |
181 | |
|
|
182 | my $header = CGI::i("Editing problem: $inputFilePath"); |
| 47 | |
183 | |
| 48 | |
|
|
| 49 | |
|
|
| 50 | |
|
|
| 51 | |
|
|
| 52 | my $header = 'Problem Editor'; |
|
|
| 53 | |
|
|
| 54 | ######################################################################### |
184 | ######################################################################### |
| 55 | # Find the text for the problem, either in the tmp file, if it exists |
185 | # Find the text for the problem, either in the tmp file, if it exists |
| 56 | # or in the original file in the template directory |
186 | # or in the original file in the template directory |
| 57 | ######################################################################### |
187 | ######################################################################### |
| 58 | my $problemContents = ''; |
|
|
| 59 | my $editMode = (defined($r->param('problemContents')))? |
|
|
| 60 | 'tmpMode':'stdMode'; |
|
|
| 61 | |
188 | |
| 62 | if ( $editMode eq 'tmpMode') { |
189 | my $problemContents = ${$self->{r_problemContents}}; |
| 63 | $problemContents = $r->param('problemContents'); |
|
|
| 64 | |
|
|
| 65 | } else { |
|
|
| 66 | eval { |
|
|
| 67 | $problemContents = WeBWorK::Utils::readFile($problemPath); |
|
|
| 68 | }; |
|
|
| 69 | $problemContents = $@ if $@; |
|
|
| 70 | |
190 | |
| 71 | # create tmp file version for later use |
|
|
| 72 | # So that you don't need duplicate information in forms |
|
|
| 73 | # FIXME |
|
|
| 74 | # open(FILE,">$tmpProblemPath") || die "Failed to open $tmpProblemPath"; |
|
|
| 75 | # print FILE "tmpfileVersion\n\n" . $problemContents; |
|
|
| 76 | # close(FILE); |
|
|
| 77 | } |
|
|
| 78 | |
|
|
| 79 | # Define parameters for textarea |
|
|
| 80 | my $rows = 40; |
|
|
| 81 | my $columns = 80; |
|
|
| 82 | |
|
|
| 83 | ######################################################################### |
|
|
| 84 | # Define a link to view the problem |
|
|
| 85 | #fix me: |
|
|
| 86 | # Currently this link used the webwork problem library, which might be out of |
|
|
| 87 | # sync with the local library |
|
|
| 88 | ######################################################################### |
|
|
| 89 | |
|
|
| 90 | |
|
|
| 91 | |
|
|
| 92 | ######################################################################### |
191 | ######################################################################### |
| 93 | # Format the page |
192 | # Format the page |
| 94 | ######################################################################### |
193 | ######################################################################### |
| 95 | |
194 | |
|
|
195 | # Define parameters for textarea |
|
|
196 | # FIXME |
|
|
197 | # Should the seed be set from some particular user instance?? |
|
|
198 | my $rows = 20; |
|
|
199 | my $columns = 80; |
|
|
200 | my $mode_list = $ce->{pg}->{displayModes}; |
|
|
201 | my $displayMode = $self->{displayMode}; |
|
|
202 | my $problemSeed = $self->{problemSeed}; |
|
|
203 | my $uri = $r->uri; |
|
|
204 | my $edit_level = $r->param('edit_level') || 0; |
|
|
205 | |
|
|
206 | my $force_field = defined($r->param('sourceFilePath')) ? |
|
|
207 | CGI::hidden(-name=>'sourceFilePath', |
|
|
208 | -default=>$r->param('sourceFilePath')) : ''; |
|
|
209 | |
| 96 | return CGI::p($header), |
210 | return CGI::p($header), |
| 97 | CGI::startform("POST",$r->uri), |
211 | #CGI::start_form("POST",$r->uri,-target=>'_problem'), doesn't pass on the target parameter??? |
|
|
212 | # THIS IS BECAUSE TARGET IS NOT A PARAMETER OF <FORM>!!!!!!!! |
|
|
213 | qq!<form method="POST" action="$uri" enctype="application/x-www-form-urlencoded", target="problem$edit_level">!, |
| 98 | $self->hidden_authen_fields, |
214 | $self->hidden_authen_fields, |
| 99 | CGI::textarea(-name => 'problemContents', -default => $problemContents, |
215 | $force_field, |
| 100 | -rows => $rows, -columns => $columns, -override => 1, |
216 | CGI::hidden(-name=>'file_type',-default=>$self->{file_type}), |
|
|
217 | CGI::div( |
|
|
218 | 'Seed: ', |
|
|
219 | CGI::textfield(-name=>'problemSeed',-value=>$problemSeed), |
|
|
220 | 'Mode: ', |
|
|
221 | CGI::popup_menu(-name=>'displayMode', -values=>$mode_list, -default=>$displayMode), |
|
|
222 | CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"}, |
|
|
223 | 'Manpages', |
|
|
224 | ) |
| 101 | ), |
225 | ), |
| 102 | "<p> the parameters passed are " #FIXME -- debugging code |
226 | CGI::p( |
| 103 | . join("<BR>", %{$r->param()}) . |
227 | CGI::textarea( |
| 104 | "</p> and the gatheredInfo is ", |
228 | -name => 'problemContents', -default => $problemContents, |
| 105 | "problemPath=$problemPath<br> formURL=".$r->uri . "<br> tmpProblemPath=$tmpProblemPath<br>" , |
229 | -rows => $rows, -columns => $columns, -override => 1, |
| 106 | |
230 | ), |
| 107 | ; |
231 | ), |
| 108 | |
232 | CGI::p( |
|
|
233 | CGI::submit(-value=>'Refresh',-name=>'submit'), |
|
|
234 | CGI::submit(-value=>'Save', -name=>'submit'), |
|
|
235 | CGI::submit(-value=>'Revert', -name=>'submit'), |
|
|
236 | CGI::submit(-value=>'Save as',-name=>'submit'), |
|
|
237 | CGI::textfield(-name=>'save_to_new_file', -size=>40, -value=>""), |
|
|
238 | ), |
|
|
239 | CGI::end_form(), |
| 109 | } |
240 | } |
| 110 | |
241 | |
| 111 | sub initialize { |
242 | ################################################################################ |
| 112 | #fix me. This is very much hacked together. In particular can we pass the key inside the post? |
243 | # Utilities |
| 113 | my ($self, @path_components) = @_; |
244 | ################################################################################ |
| 114 | my $ce = $self->{ce}; |
245 | |
|
|
246 | # saveFileChanges does most of the work. it is a separate method so that it can |
|
|
247 | # be called from either pre_header_initialize() or initilize(), depending on |
|
|
248 | # whether a redirect is needed or not. |
|
|
249 | # |
|
|
250 | # it actually does a lot more than save changes to the file being edited, and |
|
|
251 | # sometimes less. |
|
|
252 | |
|
|
253 | sub saveFileChanges { |
|
|
254 | my ($self, $setName, $problemNumber) = @_; |
| 115 | my $r = $self->{r}; |
255 | my $r = $self->r; |
| 116 | my $path_info = $r->path_info || ""; |
256 | my $ce = $r->ce; |
|
|
257 | my $db = $r->db; |
|
|
258 | my $urlpath = $r->urlpath; |
| 117 | |
259 | |
|
|
260 | my $courseName = $urlpath->arg("courseID"); |
|
|
261 | my $user = $r->param('user'); |
|
|
262 | my $effectiveUserName = $r->param('effectiveUser'); |
|
|
263 | |
|
|
264 | $setName = '' unless defined $setName; |
|
|
265 | $problemNumber = '' unless defined $problemNumber; |
|
|
266 | |
| 118 | ## Determine relative path to the file to be edited |
267 | ##### Determine path to the file to be edited. ##### |
| 119 | |
268 | |
| 120 | my $templateDirectory = $self->{ce}->{courseDirs}->{templates}; |
269 | my $editFilePath = $ce->{courseDirs}->{templates}; |
| 121 | my $problemPath = join("/",$templateDirectory,@path_components) .'.pg'; |
270 | my $problem_record = undef; |
| 122 | |
271 | |
|
|
272 | my $file_type = $r->param("file_type") || ''; |
| 123 | |
273 | |
| 124 | # find path to the temporary file |
274 | if ($file_type eq 'course_info') { |
| 125 | my $tmpDirectory = $ce->{courseDirs}->{html_temp}; |
275 | # we are editing the course_info file |
| 126 | my $fileName = join("-", $r->param('user'),@path_components).'.pg'; |
276 | $self->{file_type} = 'course_info'; |
| 127 | my $tmpProblemPath = "$tmpDirectory/$fileName"; |
277 | |
|
|
278 | # value of courseFiles::course_info is relative to templates directory |
|
|
279 | $editFilePath .= '/' . $ce->{courseFiles}->{course_info}; |
|
|
280 | } else { |
|
|
281 | # we are editing a problem file or a set header file |
|
|
282 | |
|
|
283 | # FIXME there is a discrepancy in the way that the problems are found. |
|
|
284 | # FIXME more error checking is needed in case the problem doesn't exist. |
|
|
285 | # (i wonder what the above comments mean... -sam) |
|
|
286 | |
|
|
287 | if (defined $problemNumber) { |
|
|
288 | if ($problemNumber == 0) { |
|
|
289 | # we are editing a header file |
|
|
290 | $self->{file_type} = 'set_header'; |
|
|
291 | |
|
|
292 | # first try getting the merged set for the effective user |
|
|
293 | my $set_record = $db->getMergedSet($effectiveUserName, $setName); # checked |
|
|
294 | |
|
|
295 | # if that doesn't work (the set is not yet assigned), get the global record |
|
|
296 | $set_record = $db->getGlobalSet($setName); # checked |
|
|
297 | |
|
|
298 | # bail if no set is found |
|
|
299 | die "Cannot find a set record for set $setName" unless defined($set_record); |
|
|
300 | |
|
|
301 | $editFilePath .= '/' . $set_record->set_header; |
|
|
302 | } else { |
|
|
303 | # we are editing a "real" problem |
|
|
304 | $self->{file_type} = 'problem'; |
|
|
305 | |
|
|
306 | # first try getting the merged problem for the effective user |
|
|
307 | $problem_record = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked |
|
|
308 | |
|
|
309 | # if that doesn't work (the problem is not yet assigned), get the global record |
|
|
310 | $problem_record = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem_record); # checked |
|
|
311 | |
|
|
312 | |
|
|
313 | if(not defined($problem_record)) { |
|
|
314 | my $forcedSourceFile = $r->param('sourceFilePath'); |
|
|
315 | # bail if no problem is found and we aren't faking it |
|
|
316 | die "Cannot find a problem record for set $setName / problem $problemNumber" unless defined($forcedSourceFile); |
|
|
317 | $problem_record = fake_problem($db); |
|
|
318 | $problem_record->problem_id($problemNumber); |
|
|
319 | $problem_record->source_file($forcedSourceFile); |
|
|
320 | } |
|
|
321 | |
|
|
322 | |
|
|
323 | $editFilePath .= '/' . $problem_record->source_file; |
|
|
324 | } |
|
|
325 | } |
|
|
326 | } |
|
|
327 | |
|
|
328 | my $editFileSuffix = $user.'.tmp'; |
|
|
329 | my $submit_button = $r->param('submit'); |
|
|
330 | |
|
|
331 | ############################################################################## |
|
|
332 | # Determine the display mode |
|
|
333 | # try to get problem seed from the input parameter, or from the problem record |
|
|
334 | # This will be needed for viewing the problem via redirect. |
|
|
335 | # They are also two of the parameters which can be set by the editor |
|
|
336 | ############################################################################## |
|
|
337 | |
|
|
338 | my $displayMode; |
|
|
339 | if (defined $r->param('displayMode')) { |
|
|
340 | $displayMode = $r->param('displayMode'); |
|
|
341 | } else { |
|
|
342 | $displayMode = $ce->{pg}->{options}->{displayMode}; |
|
|
343 | } |
|
|
344 | |
|
|
345 | my $problemSeed; |
|
|
346 | if (defined $r->param('problemSeed')) { |
|
|
347 | $problemSeed = $r->param('problemSeed'); |
|
|
348 | } elsif (defined($problem_record) and $problem_record->can('problem_seed')) { |
|
|
349 | $problemSeed = $problem_record->problem_seed; |
|
|
350 | } |
|
|
351 | |
|
|
352 | # make absolutely sure that the problem seed is defined, if it hasn't been. |
|
|
353 | $problemSeed = '123456' unless defined $problemSeed and $problemSeed =~/\S/; |
|
|
354 | |
|
|
355 | ############################################################################## |
|
|
356 | # read and update the targetFile and targetFile.tmp files in the directory |
|
|
357 | # if a .tmp file already exists use that, unless the revert button has been pressed. |
|
|
358 | # These .tmp files are |
|
|
359 | # removed when the file is finally saved. |
|
|
360 | ############################################################################## |
|
|
361 | |
|
|
362 | my $problemContents = ''; |
|
|
363 | my $currentSourceFilePath = ''; |
|
|
364 | my $editErrors = ''; |
|
|
365 | |
|
|
366 | my $inputFilePath; |
|
|
367 | if (-r "$editFilePath.$editFileSuffix") { |
|
|
368 | $inputFilePath = "$editFilePath.$editFileSuffix"; |
|
|
369 | } else { |
|
|
370 | $inputFilePath = $editFilePath; |
|
|
371 | } |
|
|
372 | |
|
|
373 | $inputFilePath = $editFilePath if defined($submit_button) and $submit_button eq 'Revert'; |
|
|
374 | |
|
|
375 | ##### handle button clicks ##### |
|
|
376 | |
|
|
377 | if (not defined $submit_button or $submit_button eq 'Revert' ) { |
|
|
378 | # this is a fresh editing job |
|
|
379 | # copy the pg file to a new file with the same name with .tmp added |
|
|
380 | # store this name in the $self->currentSourceFilePath for use in body |
|
|
381 | |
|
|
382 | # try to read file |
|
|
383 | if(-e $inputFilePath) { |
|
|
384 | eval { $problemContents = WeBWorK::Utils::readFile($inputFilePath) }; |
|
|
385 | $problemContents = $@ if $@; |
|
|
386 | } else { # file not existing is not an error |
|
|
387 | $problemContents = ''; |
|
|
388 | } |
|
|
389 | |
|
|
390 | $currentSourceFilePath = "$editFilePath.$editFileSuffix"; |
|
|
391 | $self->{currentSourceFilePath} = $currentSourceFilePath; |
| 128 | $ce->{problemPath} = $problemPath; |
392 | $self->{problemPath} = $editFilePath; |
| 129 | $ce->{tmpProblemPath} = $tmpProblemPath; |
393 | } elsif ($submit_button eq 'Refresh') { |
|
|
394 | # grab the problemContents from the form in order to save it to the tmp file |
|
|
395 | # store tmp file name in the $self->currentSourceFilePath for use in body |
|
|
396 | $problemContents = $r->param('problemContents'); |
|
|
397 | |
|
|
398 | $currentSourceFilePath = "$editFilePath.$editFileSuffix"; |
|
|
399 | $self->{currentSourceFilePath} = $currentSourceFilePath; |
|
|
400 | $self->{problemPath} = $editFilePath; |
|
|
401 | } elsif ($submit_button eq 'Save') { |
|
|
402 | # grab the problemContents from the form in order to save it to the permanent file |
|
|
403 | # later we will unlink (delete) the temporary file |
|
|
404 | # store permanent file name in the $self->currentSourceFilePath for use in body |
|
|
405 | $problemContents = $r->param('problemContents'); |
|
|
406 | |
|
|
407 | $currentSourceFilePath = "$editFilePath"; |
|
|
408 | $self->{currentSourceFilePath} = $currentSourceFilePath; |
|
|
409 | $self->{problemPath} = $editFilePath; |
|
|
410 | } elsif ($submit_button eq 'Save as') { |
|
|
411 | # grab the problemContents from the form in order to save it to a new permanent file |
|
|
412 | # later we will unlink (delete) the current temporary file |
|
|
413 | # store new permanent file name in the $self->currentSourceFilePath for use in body |
|
|
414 | $problemContents = $r->param('problemContents'); |
|
|
415 | # Save the user in case they forgot to end the file with .pg |
|
|
416 | if($self->{file_type} eq 'problem') { |
|
|
417 | my $save_to_new_file = $r->param('save_to_new_file'); |
|
|
418 | $save_to_new_file =~ s/\.pg$//; # remove it if it is there |
|
|
419 | $save_to_new_file .= '.pg'; # put it there |
|
|
420 | $r->param('save_to_new_file', $save_to_new_file); |
|
|
421 | } |
|
|
422 | $currentSourceFilePath = $ce->{courseDirs}->{templates} . '/' . $r->param('save_to_new_file'); |
|
|
423 | $self->{currentSourceFilePath} = $currentSourceFilePath; |
|
|
424 | $self->{problemPath} = $currentSourceFilePath; |
|
|
425 | } else { |
|
|
426 | die "Unrecognized submit command: $submit_button"; |
|
|
427 | } |
|
|
428 | |
|
|
429 | # Handle the problem of line endings. Make sure that all of the line endings. Convert \r\n to \n |
|
|
430 | $problemContents =~ s/\r\n/\n/g; |
|
|
431 | $problemContents =~ s/\r/\n/g; |
|
|
432 | |
|
|
433 | # FIXME convert all double returns to paragraphs for .txt files |
|
|
434 | # instead of doing this here, it should be done n the PLACE WHERE THE FILE IS DISPLAYED!!! |
|
|
435 | #if ($self->{file_type} eq 'course_info' ) { |
|
|
436 | # $problemContents =~ s/\n\n/\n<p>\n/g; |
|
|
437 | #} |
|
|
438 | |
|
|
439 | |
|
|
440 | ############################################################################## |
|
|
441 | # write changes to the approriate files |
|
|
442 | # FIXME make sure that the permissions are set correctly!!! |
|
|
443 | # Make sure that the warning is being transmitted properly. |
|
|
444 | ############################################################################## |
|
|
445 | |
|
|
446 | # FIXME set a local state rather continue to call on the submit button. |
|
|
447 | if (defined $submit_button and $submit_button eq 'Save as' and $r->param('save_to_new_file') !~ /\w/) { |
|
|
448 | # setting $self->{failure} stops any future redirects |
|
|
449 | $self->{failure} = "Please specify a file to save to."; |
|
|
450 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("Please specify a file to save to."))); |
|
|
451 | } elsif (defined $submit_button and $submit_button eq 'Save as' and defined $currentSourceFilePath and -e $currentSourceFilePath) { |
|
|
452 | # setting $self->{failure} stops any future redirects |
|
|
453 | $self->{failure} = "File $currentSourceFilePath exists. File not saved."; |
|
|
454 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("File $currentSourceFilePath exists. File not saved."))); |
|
|
455 | } else { |
|
|
456 | # make sure any missing directories are created |
|
|
457 | $currentSourceFilePath = WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates},$currentSourceFilePath); |
|
|
458 | eval { |
|
|
459 | local *OUTPUTFILE; |
|
|
460 | open OUTPUTFILE, ">", $currentSourceFilePath |
|
|
461 | or die "Failed to open $currentSourceFilePath"; |
|
|
462 | print OUTPUTFILE $problemContents; |
|
|
463 | close OUTPUTFILE; |
|
|
464 | }; # any errors are caught in the next block |
|
|
465 | } |
|
|
466 | |
|
|
467 | ########################################################### |
|
|
468 | # Catch errors in saving files, clean up temp files |
|
|
469 | ########################################################### |
|
|
470 | |
|
|
471 | my $openTempFileErrors = $@ if $@; |
|
|
472 | |
|
|
473 | if ($openTempFileErrors) { |
|
|
474 | $self->{failure} = "Unable to write to $currentSourceFilePath: It is likely that the permissions in the template directory have not been set correctly. See log for details."; |
|
|
475 | #diagnose errors: |
|
|
476 | # FIXME: these error messages tend to be redundand |
|
|
477 | #$self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("Unable to write to $currentSourceFilePath: $openTempFileErrors"))); |
|
|
478 | #$self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("The file $currentSourceFilePath exists. \n "))) if -e $currentSourceFilePath; #FIXME |
|
|
479 | #$self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("The file $currentSourceFilePath cannot be found. \n "))) unless -e $currentSourceFilePath; |
|
|
480 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("Unable to write to $currentSourceFilePath: It is likely that the permissions in the template directory have not been set correctly."))) |
|
|
481 | if -e $currentSourceFilePath and not -w $currentSourceFilePath; |
|
|
482 | } else { |
|
|
483 | $self->{success} = "Problem saved to: $currentSourceFilePath"; |
|
|
484 | # unlink the temporary file if there are no errors and the save button has been pushed |
|
|
485 | unlink("$editFilePath.$editFileSuffix") |
|
|
486 | if defined $submit_button and ($submit_button eq 'Save' or $submit_button eq 'Save as'); |
|
|
487 | } |
|
|
488 | |
|
|
489 | # return values for use in the body subroutine |
|
|
490 | $self->{inputFilePath} = $inputFilePath; |
|
|
491 | $self->{displayMode} = $displayMode; |
|
|
492 | $self->{problemSeed} = $problemSeed; |
|
|
493 | $self->{r_problemContents} = \$problemContents; |
|
|
494 | $self->{editFileSuffix} = $editFileSuffix; |
| 130 | } |
495 | } |
| 131 | |
496 | |
| 132 | # sub gatherProblemList { #workaround for obtaining the definition of a problem set (awaiting implementation of db function) |
|
|
| 133 | # my $self = shift; |
|
|
| 134 | # my $setName = shift; |
|
|
| 135 | # my $output = ""; |
|
|
| 136 | # if ( defined($setName) and $setName ne "" ) { |
|
|
| 137 | # my $templateDirectory = $self->{ce}->{courseDirs}->{templates}; |
|
|
| 138 | # my $fileName = "$templateDirectory/$setName.def"; |
|
|
| 139 | # my @output = split("\n",WeBWorK::Utils::readFile($fileName) ); |
|
|
| 140 | # @output = grep /\.pg/, @output; # only get the .pg files |
|
|
| 141 | # @output = grep !/Header/, @output; # eliminate header files |
|
|
| 142 | # $output = join("\n",@output); |
|
|
| 143 | # } else { |
|
|
| 144 | # $output = "No set name |$setName| is defined"; |
|
|
| 145 | # } |
|
|
| 146 | # |
|
|
| 147 | # |
|
|
| 148 | # return $output |
|
|
| 149 | # |
|
|
| 150 | # |
|
|
| 151 | # |
|
|
| 152 | # |
|
|
| 153 | # } |
|
|
| 154 | # sub fetchSetDirectories { |
|
|
| 155 | # |
|
|
| 156 | # my $self = shift; |
|
|
| 157 | # my $defaultChoice = shift; |
|
|
| 158 | # my $templateDirectory = $self->{ce}->{courseDirs}->{templates}; |
|
|
| 159 | # opendir SETDEFDIR, $templateDirectory |
|
|
| 160 | # or return "Can't open directory $templateDirectory"; |
|
|
| 161 | # |
|
|
| 162 | # my @allFiles = grep !/^\./, readdir SETDEFDIR; |
|
|
| 163 | # closedir SETDEFDIR; |
|
|
| 164 | # |
|
|
| 165 | # ## filter to find only the set directories |
|
|
| 166 | # ## -- it is assumed that these directories don't contain a period in their names |
|
|
| 167 | # ## and that all other files do. Directories names must also begin with "set". |
|
|
| 168 | # ## A better plan would be to read only the names of directories, not files. |
|
|
| 169 | # |
|
|
| 170 | # ## sort the directories |
|
|
| 171 | # my @setDefFiles = grep /^set[^\.]*$/, @allFiles; |
|
|
| 172 | # my @sortedNames = sort @setDefFiles; |
|
|
| 173 | # |
|
|
| 174 | # return "$libraryName/" . CGI::br(). CGI::popup_menu(-name=>'setDirectory', -size=>$rowheight, |
|
|
| 175 | # -values=>\@sortedNames, -default=>$defaultChoice ) .CGI::br() ; |
|
|
| 176 | # } |
|
|
| 177 | # |
|
|
| 178 | # sub fetchPGproblems { |
|
|
| 179 | # |
|
|
| 180 | # my $self = shift; |
|
|
| 181 | # my $setDirectory = shift; |
|
|
| 182 | # |
|
|
| 183 | # # Handle default for setDirectory |
|
|
| 184 | # # fix me -- this is not bullet proof |
|
|
| 185 | # $setDirectory = "set0" unless defined($setDirectory); |
|
|
| 186 | # my $templateDirectory = $self->{ce}->{courseDirs}->{templates}; |
|
|
| 187 | # |
|
|
| 188 | # ## |
|
|
| 189 | # opendir SETDEFDIR, "$templateDirectory/$setDirectory" |
|
|
| 190 | # or return "Can't open directory $templateDirectory/$setDirectory"; |
|
|
| 191 | # |
|
|
| 192 | # my @allFiles = grep !/^\./, readdir SETDEFDIR; |
|
|
| 193 | # closedir SETDEFDIR; |
|
|
| 194 | # |
|
|
| 195 | # ## filter to find only pg problems |
|
|
| 196 | # ## Some problems are themselves in directories (if they have auxiliary |
|
|
| 197 | # ## .png's for example. This eventuallity needs to be handled. |
|
|
| 198 | # |
|
|
| 199 | # ## sort the directories |
|
|
| 200 | # my @pgFiles = grep /\.pg$/, @allFiles; |
|
|
| 201 | # my @sortedNames = sort @pgFiles; |
|
|
| 202 | # |
|
|
| 203 | # return "$setDirectory ". CGI::br() . |
|
|
| 204 | # CGI::popup_menu(-name=>'pgProblem', -size=>$rowheight, -multiple=>undef, -values=>\@sortedNames, ) . |
|
|
| 205 | # CGI::br() ; |
|
|
| 206 | # } |
|
|
| 207 | |
|
|
| 208 | 1; |
497 | 1; |