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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1980 - (view) (download) (as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm

1 : sh002i 1663 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 1980 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v 1.26 2004/03/23 22:59:53 sh002i Exp $
5 : sh002i 1663 #
6 :     # This program is free software; you can redistribute it and/or modify it under
7 :     # the terms of either: (a) the GNU General Public License as published by the
8 :     # Free Software Foundation; either version 2, or (at your option) any later
9 :     # version, or (b) the "Artistic License" which comes with this package.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 :     ################################################################################
16 :    
17 : gage 889 package WeBWorK::ContentGenerator::Instructor::PGProblemEditor;
18 :     use base qw(WeBWorK::ContentGenerator::Instructor);
19 :    
20 :    
21 :     =head1 NAME
22 :    
23 :     WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list
24 :    
25 :     =cut
26 :    
27 :     use strict;
28 :     use warnings;
29 :     use CGI qw();
30 :     use WeBWorK::Utils qw(readFile);
31 : gage 925 use Apache::Constants qw(:common REDIRECT);
32 : gage 1980 use HTML::Entities;
33 : gage 889
34 : sh002i 1924 ###########################################################
35 :     # This editor will edit problem files or set header files or files, such as course_info
36 :     # whose name is defined in the global.conf database
37 :     #
38 :     # Only files under the template directory ( or linked to this location) can be edited.
39 :     #
40 :     # The course information and problems are located in the course templates directory.
41 :     # Course information has the name defined by courseFiles->{course_info}
42 :     #
43 :     # Only files under the template directory ( or linked to this location) can be edited.
44 :     #
45 :     # editMode = temporaryFile (view the temp file defined by course_info.txt.user_name.tmp
46 :     # instead of the file course_info.txt)
47 :     # The editFileSuffix is "user_name.tmp" by default. It's definition should be moved to Instructor.pm #FIXME
48 :     ###########################################################
49 : gage 925
50 : sh002i 1924 #our $libraryName;
51 :     #our $rowheight;
52 : gage 889
53 : gage 1747 sub pre_header_initialize {
54 : sh002i 1924 my ($self) = @_;
55 :     my $r = $self->r;
56 :     my $ce = $r->ce;
57 :     my $urlpath = $r->urlpath;
58 : gage 925
59 : sh002i 1924 my $submit_button = $r->param('submit'); # obtain submit command from form
60 :    
61 :     # Save problem to permanent or temporary file, then redirect for viewing
62 :     if (defined($submit_button) and ($submit_button eq 'Save' or $submit_button eq 'Refresh')) {
63 :     my $setName = $r->urlpath->arg("setID");
64 :     my $problemNumber = $r->urlpath->arg("problemID");
65 : gage 925
66 : sh002i 1924 # write the necessary files
67 :     # return file path for viewing problem in $self->{currentSourceFilePath}
68 :     # obtain the appropriate seed
69 :     $self->saveFileChanges($setName, $problemNumber);
70 :    
71 :     ##### calculate redirect URL based on file type #####
72 :    
73 :     # get some information
74 :     #my $hostname = $r->hostname();
75 :     #my $port = $r->get_server_port();
76 :     #my $uri = $r->uri;
77 : gage 1980 my $courseName = $urlpath->arg("courseID");
78 : sh002i 1924 my $problemSeed = ($r->param('problemSeed')) ? $r->param('problemSeed') : '';
79 :     my $displayMode = ($r->param('displayMode')) ? $r->param('displayMode') : '';
80 :    
81 :     my $viewURL = '';
82 :    
83 :     # problems redirect to Problem.pm
84 :     $self->{file_type} eq 'problem' and do {
85 :     my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
86 : gage 1980 courseID => $courseName, setID => $setName, problemID => $problemNumber);
87 :     $viewURL = $self->systemLink($problemPage,
88 : sh002i 1924 params => {
89 : gage 1980 displayMode => $displayMode,
90 :     problemSeed => $problemSeed,
91 :     editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"),
92 :     sourceFilePath => $self->{currentSourceFilePath},
93 :     submiterror => $self->{submiterror},
94 : sh002i 1924 }
95 : gage 1980 ); warn "error message is", $self->{submiterror}; # pass along any error messages
96 : sh002i 1924 };
97 : gage 1980 warn "submit error is ",$r->param('submiterror');
98 : sh002i 1924 # set headers redirect to ProblemSet.pm
99 :     $self->{file_type} eq 'set_header' and do {
100 :     my $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
101 :     courseID => $courseName, setID => $setName);
102 :     $viewURL = $self->systemLink($problemSetPage,
103 :     params => {
104 :     displayMode => $displayMode,
105 :     problemSeed => $problemSeed,
106 : gage 1980 editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"),
107 : sh002i 1924 }
108 :     );
109 :     };
110 :    
111 :     # course info redirects to ProblemSets.pm
112 :     $self->{file_type} eq 'course_info' and do {
113 :     my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
114 :     courseID => $courseName);
115 :     $viewURL = $self->systemLink($problemSetsPage,
116 :     params => {
117 :     editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"),
118 :     }
119 :     );
120 :     };
121 :    
122 :     if ($viewURL) {
123 :     $self->reply_with_redirect($viewURL);
124 : gage 1747 } else {
125 : sh002i 1924 die "Invalid file_type ", $self->{file_type}, " specified by saveFileChanges";
126 : sh002i 1198 }
127 : gage 925 }
128 :     }
129 :    
130 : gage 1747 sub initialize {
131 : sh002i 1924 my ($self) = @_;
132 :     my $r = $self->r;
133 :    
134 : sh002i 1841 my $setName = $r->urlpath->arg("setID");
135 :     my $problemNumber = $r->urlpath->arg("problemID");
136 : sh002i 1924
137 :     # if we got to initialize(), then saveFileChanges was not called in pre_header_initialize().
138 :     # therefore we call it here:
139 :     $self->saveFileChanges($setName, $problemNumber);
140 :     }
141 : gage 1747
142 : sh002i 1924 sub body {
143 :     my ($self) = @_;
144 :     my $r = $self->r;
145 :     my $db = $r->db;
146 :     my $ce = $r->ce;
147 :    
148 :     # Gathering info
149 :     my $editFilePath = $self->{problemPath}; # path to the permanent file to be edited
150 :     my $inputFilePath = $self->{inputFilePath}; # path to the file currently being worked with (might be a .tmp file)
151 :    
152 :     my $header = CGI::i("Editing problem: $inputFilePath");
153 :    
154 :     #########################################################################
155 :     # Find the text for the problem, either in the tmp file, if it exists
156 :     # or in the original file in the template directory
157 :     #########################################################################
158 :    
159 :     my $problemContents = ${$self->{r_problemContents}};
160 :    
161 :     #########################################################################
162 :     # Format the page
163 :     #########################################################################
164 :    
165 :     # Define parameters for textarea
166 :     # FIXME
167 :     # Should the seed be set from some particular user instance??
168 :     # The mode list should be obtained from global.conf ultimately
169 :     my $rows = 20;
170 :     my $columns = 80;
171 :     my $mode_list = ['plainText','formattedText','images'];
172 :     my $displayMode = $self->{displayMode};
173 :     my $problemSeed = $self->{problemSeed};
174 :     my $uri = $r->uri;
175 :     return CGI::p($header),
176 :     #CGI::start_form("POST",$r->uri,-target=>'_problem'), doesn't pass on the target parameter???
177 :     # THIS IS BECAUSE TARGET IS NOT A PARAMETER OF <FORM>!!!!!!!!
178 :     qq!<form method="POST" action="$uri" enctype="application/x-www-form-urlencoded", target="_problem">!,
179 :     $self->hidden_authen_fields,
180 :     CGI::hidden(-name=>'file_type',-default=>$self->{file_type}),
181 :     CGI::div(
182 :     'Seed: ',
183 :     CGI::textfield(-name=>'problemSeed',-value=>$problemSeed),
184 :     'Mode: ',
185 :     CGI::popup_menu(-name=>'displayMode', -values=>$mode_list, -default=>$displayMode),
186 :     CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"},
187 :     'Manpages',
188 :     )
189 :     ),
190 :     CGI::p(
191 :     CGI::textarea(
192 :     -name => 'problemContents', -default => $problemContents,
193 :     -rows => $rows, -columns => $columns, -override => 1,
194 :     ),
195 :     ),
196 :     CGI::p(
197 :     CGI::submit(-value=>'Refresh',-name=>'submit'),
198 :     CGI::submit(-value=>'Save', -name=>'submit'),
199 :     CGI::submit(-value=>'Revert', -name=>'submit'),
200 :     CGI::submit(-value=>'Save as',-name=>'submit'),
201 :     CGI::textfield(-name=>'save_to_new_file', -value=>""),
202 :     ),
203 :     CGI::end_form(),
204 :     }
205 : gage 1747
206 : sh002i 1924 ################################################################################
207 :     # Utilities
208 :     ################################################################################
209 : gage 1747
210 : sh002i 1924 # saveFileChanges does most of the work. it is a separate method so that it can
211 :     # be called from either pre_header_initialize() or initilize(), depending on
212 :     # whether a redirect is needed or not.
213 :     #
214 :     # it actually does a lot more than save changes to the file being edited, and
215 :     # sometimes less.
216 : gage 1747
217 :     sub saveFileChanges {
218 : malsyned 980 my ($self, $setName, $problemNumber) = @_;
219 : sh002i 1924 my $r = $self->r;
220 :     my $ce = $r->ce;
221 :     my $db = $r->db;
222 :     my $urlpath = $r->urlpath;
223 :    
224 :     my $courseName = $urlpath->arg("courseID");
225 :     my $user = $r->param('user');
226 :     my $effectiveUserName = $r->param('effectiveUser');
227 : gage 925
228 : sh002i 1924 $setName = '' unless defined $setName;
229 :     $problemNumber = '' unless defined $problemNumber;
230 : malsyned 980
231 : sh002i 1924 ##### Determine path to the file to be edited. #####
232 : malsyned 980
233 : sh002i 1924 my $editFilePath = $ce->{courseDirs}->{templates};
234 :     my $problem_record = undef;
235 : gage 1348
236 : sh002i 1924 my $file_type = $r->param("file_type") || '';
237 : gage 1747
238 : sh002i 1924 if ($file_type eq 'course_info') {
239 :     # we are editing the course_info file
240 :     $self->{file_type} = 'course_info';
241 :    
242 :     # value of courseFiles::course_info is relative to templates directory
243 :     $editFilePath .= '/' . $ce->{courseFiles}->{course_info};
244 :     } else {
245 :     # we are editing a problem file or a set header file
246 :    
247 :     # FIXME there is a discrepancy in the way that the problems are found.
248 :     # FIXME more error checking is needed in case the problem doesn't exist.
249 :     # (i wonder what the above comments mean... -sam)
250 :    
251 :     if (defined $problemNumber) {
252 :     if ($problemNumber == 0) {
253 :     # we are editing a header file
254 :     $self->{file_type} = 'set_header';
255 :    
256 :     # first try getting the merged set for the effective user
257 :     my $set_record = $db->getMergedSet($effectiveUserName, $setName); # checked
258 :    
259 :     # if that doesn't work (the set is not yet assigned), get the global record
260 :     $set_record = $db->getGlobalSet($setName); # checked
261 :    
262 :     # bail if no set is found
263 :     die "Cannot find a set record for set $setName" unless defined($set_record);
264 :    
265 :     $editFilePath .= '/' . $set_record->set_header;
266 :     } else {
267 :     # we are editing a "real" problem
268 :     $self->{file_type} = 'problem';
269 :    
270 :     # first try getting the merged problem for the effective user
271 :     $problem_record = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked
272 :    
273 :     # if that doesn't work (the problem is not yet assigned), get the global record
274 :     $problem_record = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem_record); # checked
275 :    
276 :     # bail if no problem is found
277 :     die "Cannot find a problem record for set $setName / problem $problemNumber"
278 :     unless defined($problem_record);
279 :    
280 :     $editFilePath .= '/' . $problem_record->source_file;
281 :     }
282 : gage 1747 }
283 : gage 1348 }
284 :    
285 : sh002i 1924 my $editFileSuffix = $user.'.tmp';
286 :     my $submit_button = $r->param('submit');
287 : gage 1747
288 :     ##############################################################################
289 :     # Determine the display mode
290 :     # try to get problem seed from the input parameter, or from the problem record
291 :     # This will be needed for viewing the problem via redirect.
292 :     # They are also two of the parameters which can be set by the editor
293 :     ##############################################################################
294 : sh002i 1924
295 :     my $displayMode;
296 :     if (defined $r->param('displayMode')) {
297 :     $displayMode = $r->param('displayMode');
298 :     } else {
299 :     $displayMode = $ce->{pg}->{options}->{displayMode};
300 :     }
301 :    
302 : gage 991 my $problemSeed;
303 : sh002i 1924 if (defined $r->param('problemSeed')) {
304 :     $problemSeed = $r->param('problemSeed');
305 : gage 1348 } elsif (defined($problem_record) and $problem_record->can('problem_seed')) {
306 : sh002i 1924 $problemSeed = $problem_record->problem_seed;
307 : gage 991 }
308 : sh002i 1924
309 : gage 991 # make absolutely sure that the problem seed is defined, if it hasn't been.
310 : sh002i 1924 $problemSeed = '123456' unless defined $problemSeed and $problemSeed =~/\S/;
311 : malsyned 980
312 : gage 1747 ##############################################################################
313 :     # read and update the targetFile and targetFile.tmp files in the directory
314 :     # if a .tmp file already exists use that, unless the revert button has been pressed.
315 :     # These .tmp files are
316 :     # removed when the file is finally saved.
317 :     ##############################################################################
318 :    
319 : sh002i 1924 my $problemContents = '';
320 :     my $currentSourceFilePath = '';
321 : gage 1591 my $editErrors = '';
322 :    
323 : sh002i 1924 my $inputFilePath;
324 :     if (-r "$editFilePath.$editFileSuffix") {
325 :     $inputFilePath = "$editFilePath.$editFileSuffix";
326 :     } else {
327 :     $inputFilePath = $editFilePath;
328 :     }
329 :    
330 :     $inputFilePath = $editFilePath if defined($submit_button) and $submit_button eq 'Revert';
331 :    
332 :     ##### handle button clicks #####
333 :    
334 :     if (not defined $submit_button or $submit_button eq 'Revert' ) {
335 : malsyned 980 # this is a fresh editing job
336 :     # copy the pg file to a new file with the same name with .tmp added
337 : gage 981 # store this name in the $self->currentSourceFilePath for use in body
338 : sh002i 1924
339 : gage 1591 # try to read file
340 : sh002i 1924 eval { $problemContents = WeBWorK::Utils::readFile($inputFilePath) };
341 : malsyned 980 $problemContents = $@ if $@;
342 : sh002i 1924
343 :     $currentSourceFilePath = "$editFilePath.$editFileSuffix";
344 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
345 :     $self->{problemPath} = $editFilePath;
346 :     } elsif ($submit_button eq 'Refresh') {
347 : gage 981 # grab the problemContents from the form in order to save it to the tmp file
348 :     # store tmp file name in the $self->currentSourceFilePath for use in body
349 : sh002i 1924 $problemContents = $r->param('problemContents');
350 : malsyned 980
351 : sh002i 1924 $currentSourceFilePath = "$editFilePath.$editFileSuffix";
352 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
353 :     $self->{problemPath} = $editFilePath;
354 : malsyned 980 } elsif ($submit_button eq 'Save') {
355 : gage 981 # grab the problemContents from the form in order to save it to the permanent file
356 :     # later we will unlink (delete) the temporary file
357 :     # store permanent file name in the $self->currentSourceFilePath for use in body
358 : sh002i 1924 $problemContents = $r->param('problemContents');
359 : malsyned 980
360 : sh002i 1924 $currentSourceFilePath = "$editFilePath";
361 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
362 :     $self->{problemPath} = $editFilePath;
363 : gage 1750 } elsif ($submit_button eq 'Save as') {
364 :     # grab the problemContents from the form in order to save it to a new permanent file
365 :     # later we will unlink (delete) the current temporary file
366 :     # store new permanent file name in the $self->currentSourceFilePath for use in body
367 : sh002i 1924 $problemContents = $r->param('problemContents');
368 :     $currentSourceFilePath = $ce->{courseDirs}->{templates} . '/' .$r->param('save_to_new_file');
369 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
370 :     $self->{problemPath} = $currentSourceFilePath;
371 : malsyned 980 } else {
372 : sh002i 1924 die "Unrecognized submit command: $submit_button";
373 : malsyned 980 }
374 : gage 1105
375 :     # Handle the problem of line endings. Make sure that all of the line endings. Convert \r\n to \n
376 : sh002i 1924 $problemContents =~ s/\r\n/\n/g;
377 :     $problemContents =~ s/\r/\n/g;
378 : gage 1105
379 : gage 1750 # FIXME convert all double returns to paragraphs for .txt files
380 : sh002i 1924 # instead of doing this here, it should be done n the PLACE WHERE THE FILE IS DISPLAYED!!!
381 :     #if ($self->{file_type} eq 'course_info' ) {
382 :     # $problemContents =~ s/\n\n/\n<p>\n/g;
383 :     #}
384 :    
385 : gage 1747 ##############################################################################
386 :     # write changes to the approriate files
387 : malsyned 980 # FIXME make sure that the permissions are set correctly!!!
388 :     # Make sure that the warning is being transmitted properly.
389 : gage 1747 ##############################################################################
390 : sh002i 1924
391 : gage 1750 # FIXME set a local state rather continue to call on the submit button.
392 : sh002i 1924 if (defined $submit_button and $submit_button eq 'Save as' and defined $currentSourceFilePath and -e $currentSourceFilePath) {
393 : gage 1750 warn "File $currentSourceFilePath exists. File not saved.";
394 :     } else {
395 :     eval {
396 :     local *OUTPUTFILE;
397 :     open OUTPUTFILE, ">", $currentSourceFilePath
398 : gage 1980 or die "Failed to open $currentSourceFilePath";
399 : gage 1750 print OUTPUTFILE $problemContents;
400 :     close OUTPUTFILE;
401 : gage 1980 }; # any errors are caught in the next block
402 :    
403 : gage 1750 }
404 : sh002i 1924
405 : gage 1980 ###########################################################
406 :     # Catch errors in saving files, clean up temp files
407 :     ###########################################################
408 :    
409 : gage 1183 my $openTempFileErrors = $@ if $@;
410 :    
411 : sh002i 1924 if ($openTempFileErrors) {
412 : gage 1980 $self->{submiterror} = "Unable to write to $currentSourceFilePath: It is likely that the permissions in the template directory have not been set correctly. See log for details.";
413 : gage 1105 #diagnose errors:
414 : gage 1980 warn "Unable to write to $currentSourceFilePath: $openTempFileErrors";
415 : gage 1183 warn "The file $currentSourceFilePath exists. \n " if -e $currentSourceFilePath; #FIXME
416 : gage 1105 warn "The file $currentSourceFilePath cannot be found. \n " unless -e $currentSourceFilePath;
417 :     warn "The file $currentSourceFilePath does not have write permissions. \n"
418 :     if -e $currentSourceFilePath and not -w $currentSourceFilePath;
419 : gage 1980
420 : gage 981 } else {
421 :     # unlink the temporary file if there are no errors and the save button has been pushed
422 : sh002i 1924 unlink("$editFilePath.$editFileSuffix")
423 :     if defined $submit_button and ($submit_button eq 'Save' or $submit_button eq 'Save as');
424 :     }
425 : malsyned 980
426 : gage 981 # return values for use in the body subroutine
427 : gage 1591 $self->{inputFilePath} = $inputFilePath;
428 :     $self->{displayMode} = $displayMode;
429 :     $self->{problemSeed} = $problemSeed;
430 :     $self->{r_problemContents} = \$problemContents;
431 : gage 1747 $self->{editFileSuffix} = $editFileSuffix;
432 : malsyned 980 }
433 :    
434 : gage 1980
435 : gage 889 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9