[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / Instructor / PGProblemEditor.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2081 - (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 2081 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm,v 1.32 2004/05/08 19:35:21 jj 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 : gage 2081 use WeBWorK::Utils qw(readFile surePathToFile);
31 : gage 925 use Apache::Constants qw(:common REDIRECT);
32 : gage 1980 use HTML::Entities;
33 : jj 2016 use WeBWorK::Utils::Tasks qw(fake_set fake_problem);
34 : gage 889
35 : sh002i 1924 ###########################################################
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 : gage 925
51 : sh002i 1924 #our $libraryName;
52 :     #our $rowheight;
53 : gage 889
54 : gage 1747 sub pre_header_initialize {
55 : sh002i 1924 my ($self) = @_;
56 :     my $r = $self->r;
57 :     my $ce = $r->ce;
58 :     my $urlpath = $r->urlpath;
59 : gage 925
60 : sh002i 1924 my $submit_button = $r->param('submit'); # obtain submit command from form
61 : jj 2054 my $file_type = $r->param("file_type") || '';
62 : sh002i 1924
63 :     # Save problem to permanent or temporary file, then redirect for viewing
64 : jj 2054 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 : sh002i 1924 my $setName = $r->urlpath->arg("setID");
68 :     my $problemNumber = $r->urlpath->arg("problemID");
69 : gage 925
70 : sh002i 1924 # 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 : gage 1980 my $courseName = $urlpath->arg("courseID");
82 : sh002i 1924 my $problemSeed = ($r->param('problemSeed')) ? $r->param('problemSeed') : '';
83 :     my $displayMode = ($r->param('displayMode')) ? $r->param('displayMode') : '';
84 :    
85 :     my $viewURL = '';
86 :    
87 : jj 2054 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,
97 :     params=>{sourceFilePath => $sourceFile, edit_level=>$edit_level});
98 :     } else { # other problems redirect to Problem.pm
99 :     my $problemPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
100 :     courseID => $courseName, setID => $setName, problemID => $problemNumber);
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 :     submiterror => $self->{submiterror},
108 :     }
109 :     );
110 :     }
111 :     }
112 : jj 2016
113 : sh002i 1924 # set headers redirect to ProblemSet.pm
114 :     $self->{file_type} eq 'set_header' and do {
115 :     my $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
116 :     courseID => $courseName, setID => $setName);
117 :     $viewURL = $self->systemLink($problemSetPage,
118 :     params => {
119 :     displayMode => $displayMode,
120 :     problemSeed => $problemSeed,
121 : jj 2016 editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"),
122 : sh002i 1924 }
123 :     );
124 :     };
125 :    
126 :     # course info redirects to ProblemSets.pm
127 :     $self->{file_type} eq 'course_info' and do {
128 :     my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
129 :     courseID => $courseName);
130 :     $viewURL = $self->systemLink($problemSetsPage,
131 :     params => {
132 :     editMode => ($submit_button eq "Save" ? "savedFile" : "temporaryFile"),
133 :     }
134 :     );
135 :     };
136 :    
137 :     if ($viewURL) {
138 :     $self->reply_with_redirect($viewURL);
139 : gage 1747 } else {
140 : sh002i 1924 die "Invalid file_type ", $self->{file_type}, " specified by saveFileChanges";
141 : sh002i 1198 }
142 : gage 925 }
143 :     }
144 :    
145 : gage 1747 sub initialize {
146 : sh002i 1924 my ($self) = @_;
147 :     my $r = $self->r;
148 :    
149 : sh002i 1841 my $setName = $r->urlpath->arg("setID");
150 :     my $problemNumber = $r->urlpath->arg("problemID");
151 : sh002i 1924
152 :     # if we got to initialize(), then saveFileChanges was not called in pre_header_initialize().
153 :     # therefore we call it here:
154 :     $self->saveFileChanges($setName, $problemNumber);
155 :     }
156 : gage 1747
157 : jj 2029 sub title {
158 :     my $self = shift;
159 :     my $r = $self->r;
160 :     my $problemNumber = $r->urlpath->arg("problemID");
161 :     my $file_type = $self->{'file_type'} || '';
162 :     return "Set Header" if($file_type eq 'set_header');
163 :     return "Course Information" if($file_type eq 'course_info');
164 :     return 'Problem ' . $r->{urlpath}->name;
165 :     }
166 :    
167 : sh002i 1924 sub body {
168 :     my ($self) = @_;
169 :     my $r = $self->r;
170 :     my $db = $r->db;
171 :     my $ce = $r->ce;
172 :    
173 :     # Gathering info
174 :     my $editFilePath = $self->{problemPath}; # path to the permanent file to be edited
175 :     my $inputFilePath = $self->{inputFilePath}; # path to the file currently being worked with (might be a .tmp file)
176 :    
177 :     my $header = CGI::i("Editing problem: $inputFilePath");
178 :    
179 :     #########################################################################
180 :     # Find the text for the problem, either in the tmp file, if it exists
181 :     # or in the original file in the template directory
182 :     #########################################################################
183 :    
184 :     my $problemContents = ${$self->{r_problemContents}};
185 :    
186 :     #########################################################################
187 :     # Format the page
188 :     #########################################################################
189 :    
190 :     # Define parameters for textarea
191 :     # FIXME
192 :     # Should the seed be set from some particular user instance??
193 :     # The mode list should be obtained from global.conf ultimately
194 :     my $rows = 20;
195 :     my $columns = 80;
196 :     my $mode_list = ['plainText','formattedText','images'];
197 :     my $displayMode = $self->{displayMode};
198 :     my $problemSeed = $self->{problemSeed};
199 :     my $uri = $r->uri;
200 : jj 2054 my $edit_level = $r->param('edit_level') || 0;
201 : jj 2016
202 :     my $force_field = defined($r->param('sourceFilePath')) ?
203 :     CGI::hidden(-name=>'sourceFilePath',
204 :     -default=>$r->param('sourceFilePath')) : '';
205 : sh002i 1924 return CGI::p($header),
206 :     #CGI::start_form("POST",$r->uri,-target=>'_problem'), doesn't pass on the target parameter???
207 :     # THIS IS BECAUSE TARGET IS NOT A PARAMETER OF <FORM>!!!!!!!!
208 : jj 2054 qq!<form method="POST" action="$uri" enctype="application/x-www-form-urlencoded", target="problem$edit_level">!,
209 : sh002i 1924 $self->hidden_authen_fields,
210 : jj 2016 $force_field,
211 : sh002i 1924 CGI::hidden(-name=>'file_type',-default=>$self->{file_type}),
212 :     CGI::div(
213 :     'Seed: ',
214 :     CGI::textfield(-name=>'problemSeed',-value=>$problemSeed),
215 :     'Mode: ',
216 :     CGI::popup_menu(-name=>'displayMode', -values=>$mode_list, -default=>$displayMode),
217 :     CGI::a({-href=>'http://webwork.math.rochester.edu/docs/docs/pglanguage/manpages/',-target=>"manpage_window"},
218 :     'Manpages',
219 :     )
220 :     ),
221 :     CGI::p(
222 :     CGI::textarea(
223 :     -name => 'problemContents', -default => $problemContents,
224 :     -rows => $rows, -columns => $columns, -override => 1,
225 :     ),
226 :     ),
227 :     CGI::p(
228 :     CGI::submit(-value=>'Refresh',-name=>'submit'),
229 :     CGI::submit(-value=>'Save', -name=>'submit'),
230 :     CGI::submit(-value=>'Revert', -name=>'submit'),
231 :     CGI::submit(-value=>'Save as',-name=>'submit'),
232 :     CGI::textfield(-name=>'save_to_new_file', -value=>""),
233 :     ),
234 :     CGI::end_form(),
235 :     }
236 : gage 1747
237 : sh002i 1924 ################################################################################
238 :     # Utilities
239 :     ################################################################################
240 : gage 1747
241 : sh002i 1924 # saveFileChanges does most of the work. it is a separate method so that it can
242 :     # be called from either pre_header_initialize() or initilize(), depending on
243 :     # whether a redirect is needed or not.
244 :     #
245 :     # it actually does a lot more than save changes to the file being edited, and
246 :     # sometimes less.
247 : gage 1747
248 :     sub saveFileChanges {
249 : malsyned 980 my ($self, $setName, $problemNumber) = @_;
250 : sh002i 1924 my $r = $self->r;
251 :     my $ce = $r->ce;
252 :     my $db = $r->db;
253 :     my $urlpath = $r->urlpath;
254 :    
255 :     my $courseName = $urlpath->arg("courseID");
256 :     my $user = $r->param('user');
257 :     my $effectiveUserName = $r->param('effectiveUser');
258 : gage 925
259 : sh002i 1924 $setName = '' unless defined $setName;
260 :     $problemNumber = '' unless defined $problemNumber;
261 : malsyned 980
262 : sh002i 1924 ##### Determine path to the file to be edited. #####
263 : malsyned 980
264 : sh002i 1924 my $editFilePath = $ce->{courseDirs}->{templates};
265 :     my $problem_record = undef;
266 : gage 1348
267 : sh002i 1924 my $file_type = $r->param("file_type") || '';
268 : gage 1747
269 : sh002i 1924 if ($file_type eq 'course_info') {
270 :     # we are editing the course_info file
271 :     $self->{file_type} = 'course_info';
272 :    
273 :     # value of courseFiles::course_info is relative to templates directory
274 :     $editFilePath .= '/' . $ce->{courseFiles}->{course_info};
275 :     } else {
276 :     # we are editing a problem file or a set header file
277 :    
278 :     # FIXME there is a discrepancy in the way that the problems are found.
279 :     # FIXME more error checking is needed in case the problem doesn't exist.
280 :     # (i wonder what the above comments mean... -sam)
281 :    
282 :     if (defined $problemNumber) {
283 :     if ($problemNumber == 0) {
284 :     # we are editing a header file
285 :     $self->{file_type} = 'set_header';
286 :    
287 :     # first try getting the merged set for the effective user
288 :     my $set_record = $db->getMergedSet($effectiveUserName, $setName); # checked
289 :    
290 :     # if that doesn't work (the set is not yet assigned), get the global record
291 :     $set_record = $db->getGlobalSet($setName); # checked
292 :    
293 :     # bail if no set is found
294 :     die "Cannot find a set record for set $setName" unless defined($set_record);
295 :    
296 :     $editFilePath .= '/' . $set_record->set_header;
297 :     } else {
298 :     # we are editing a "real" problem
299 :     $self->{file_type} = 'problem';
300 :    
301 :     # first try getting the merged problem for the effective user
302 :     $problem_record = $db->getMergedProblem($effectiveUserName, $setName, $problemNumber); # checked
303 :    
304 :     # if that doesn't work (the problem is not yet assigned), get the global record
305 :     $problem_record = $db->getGlobalProblem($setName, $problemNumber) unless defined($problem_record); # checked
306 :    
307 : jj 2016
308 :     if(not defined($problem_record)) {
309 :     my $forcedSourceFile = $r->param('sourceFilePath');
310 :     # bail if no problem is found and we aren't faking it
311 :     die "Cannot find a problem record for set $setName / problem $problemNumber" unless defined($forcedSourceFile);
312 :     $problem_record = fake_problem($db);
313 :     $problem_record->problem_id($problemNumber);
314 :     $problem_record->source_file($forcedSourceFile);
315 :     }
316 :    
317 : sh002i 1924
318 :     $editFilePath .= '/' . $problem_record->source_file;
319 :     }
320 : gage 1747 }
321 : gage 1348 }
322 :    
323 : sh002i 1924 my $editFileSuffix = $user.'.tmp';
324 :     my $submit_button = $r->param('submit');
325 : gage 1747
326 :     ##############################################################################
327 :     # Determine the display mode
328 :     # try to get problem seed from the input parameter, or from the problem record
329 :     # This will be needed for viewing the problem via redirect.
330 :     # They are also two of the parameters which can be set by the editor
331 :     ##############################################################################
332 : sh002i 1924
333 :     my $displayMode;
334 :     if (defined $r->param('displayMode')) {
335 :     $displayMode = $r->param('displayMode');
336 :     } else {
337 :     $displayMode = $ce->{pg}->{options}->{displayMode};
338 :     }
339 :    
340 : gage 991 my $problemSeed;
341 : sh002i 1924 if (defined $r->param('problemSeed')) {
342 :     $problemSeed = $r->param('problemSeed');
343 : gage 1348 } elsif (defined($problem_record) and $problem_record->can('problem_seed')) {
344 : sh002i 1924 $problemSeed = $problem_record->problem_seed;
345 : gage 991 }
346 : sh002i 1924
347 : gage 991 # make absolutely sure that the problem seed is defined, if it hasn't been.
348 : sh002i 1924 $problemSeed = '123456' unless defined $problemSeed and $problemSeed =~/\S/;
349 : malsyned 980
350 : gage 1747 ##############################################################################
351 :     # read and update the targetFile and targetFile.tmp files in the directory
352 :     # if a .tmp file already exists use that, unless the revert button has been pressed.
353 :     # These .tmp files are
354 :     # removed when the file is finally saved.
355 :     ##############################################################################
356 :    
357 : sh002i 1924 my $problemContents = '';
358 :     my $currentSourceFilePath = '';
359 : gage 1591 my $editErrors = '';
360 :    
361 : sh002i 1924 my $inputFilePath;
362 :     if (-r "$editFilePath.$editFileSuffix") {
363 :     $inputFilePath = "$editFilePath.$editFileSuffix";
364 :     } else {
365 :     $inputFilePath = $editFilePath;
366 :     }
367 :    
368 :     $inputFilePath = $editFilePath if defined($submit_button) and $submit_button eq 'Revert';
369 :    
370 :     ##### handle button clicks #####
371 :    
372 :     if (not defined $submit_button or $submit_button eq 'Revert' ) {
373 : malsyned 980 # this is a fresh editing job
374 :     # copy the pg file to a new file with the same name with .tmp added
375 : gage 981 # store this name in the $self->currentSourceFilePath for use in body
376 : sh002i 1924
377 : gage 1591 # try to read file
378 : jj 2032 if(-e $inputFilePath) {
379 :     eval { $problemContents = WeBWorK::Utils::readFile($inputFilePath) };
380 :     $problemContents = $@ if $@;
381 :     } else { # file not existing is not an error
382 :     $problemContents = '';
383 :     }
384 : sh002i 1924
385 :     $currentSourceFilePath = "$editFilePath.$editFileSuffix";
386 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
387 :     $self->{problemPath} = $editFilePath;
388 :     } elsif ($submit_button eq 'Refresh') {
389 : gage 981 # grab the problemContents from the form in order to save it to the tmp file
390 :     # store tmp file name in the $self->currentSourceFilePath for use in body
391 : sh002i 1924 $problemContents = $r->param('problemContents');
392 : malsyned 980
393 : sh002i 1924 $currentSourceFilePath = "$editFilePath.$editFileSuffix";
394 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
395 :     $self->{problemPath} = $editFilePath;
396 : malsyned 980 } elsif ($submit_button eq 'Save') {
397 : gage 981 # grab the problemContents from the form in order to save it to the permanent file
398 :     # later we will unlink (delete) the temporary file
399 :     # store permanent file name in the $self->currentSourceFilePath for use in body
400 : sh002i 1924 $problemContents = $r->param('problemContents');
401 : malsyned 980
402 : sh002i 1924 $currentSourceFilePath = "$editFilePath";
403 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
404 :     $self->{problemPath} = $editFilePath;
405 : gage 1750 } elsif ($submit_button eq 'Save as') {
406 :     # grab the problemContents from the form in order to save it to a new permanent file
407 :     # later we will unlink (delete) the current temporary file
408 :     # store new permanent file name in the $self->currentSourceFilePath for use in body
409 : sh002i 1924 $problemContents = $r->param('problemContents');
410 :     $currentSourceFilePath = $ce->{courseDirs}->{templates} . '/' .$r->param('save_to_new_file');
411 :     $self->{currentSourceFilePath} = $currentSourceFilePath;
412 :     $self->{problemPath} = $currentSourceFilePath;
413 : malsyned 980 } else {
414 : sh002i 1924 die "Unrecognized submit command: $submit_button";
415 : malsyned 980 }
416 : gage 1105
417 :     # Handle the problem of line endings. Make sure that all of the line endings. Convert \r\n to \n
418 : sh002i 1924 $problemContents =~ s/\r\n/\n/g;
419 :     $problemContents =~ s/\r/\n/g;
420 : gage 1105
421 : gage 1750 # FIXME convert all double returns to paragraphs for .txt files
422 : sh002i 1924 # instead of doing this here, it should be done n the PLACE WHERE THE FILE IS DISPLAYED!!!
423 :     #if ($self->{file_type} eq 'course_info' ) {
424 :     # $problemContents =~ s/\n\n/\n<p>\n/g;
425 :     #}
426 :    
427 : gage 1747 ##############################################################################
428 :     # write changes to the approriate files
429 : malsyned 980 # FIXME make sure that the permissions are set correctly!!!
430 :     # Make sure that the warning is being transmitted properly.
431 : gage 1747 ##############################################################################
432 : sh002i 1924
433 : gage 1750 # FIXME set a local state rather continue to call on the submit button.
434 : sh002i 1924 if (defined $submit_button and $submit_button eq 'Save as' and defined $currentSourceFilePath and -e $currentSourceFilePath) {
435 : gage 1750 warn "File $currentSourceFilePath exists. File not saved.";
436 :     } else {
437 : gage 2081 # make sure any missing directories are created
438 :     $currentSourceFilePath = WeBWorK::Utils::surePathToFile($ce->{courseDirs}->{templates},$currentSourceFilePath);
439 : gage 1750 eval {
440 :     local *OUTPUTFILE;
441 :     open OUTPUTFILE, ">", $currentSourceFilePath
442 : gage 1980 or die "Failed to open $currentSourceFilePath";
443 : gage 1750 print OUTPUTFILE $problemContents;
444 :     close OUTPUTFILE;
445 : gage 1980 }; # any errors are caught in the next block
446 :    
447 : gage 1750 }
448 : sh002i 1924
449 : gage 1980 ###########################################################
450 :     # Catch errors in saving files, clean up temp files
451 :     ###########################################################
452 :    
453 : gage 1183 my $openTempFileErrors = $@ if $@;
454 :    
455 : sh002i 1924 if ($openTempFileErrors) {
456 : 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.";
457 : gage 1105 #diagnose errors:
458 : gage 1980 warn "Unable to write to $currentSourceFilePath: $openTempFileErrors";
459 : gage 1183 warn "The file $currentSourceFilePath exists. \n " if -e $currentSourceFilePath; #FIXME
460 : gage 1105 warn "The file $currentSourceFilePath cannot be found. \n " unless -e $currentSourceFilePath;
461 :     warn "The file $currentSourceFilePath does not have write permissions. \n"
462 :     if -e $currentSourceFilePath and not -w $currentSourceFilePath;
463 : gage 981 } else {
464 :     # unlink the temporary file if there are no errors and the save button has been pushed
465 : sh002i 1924 unlink("$editFilePath.$editFileSuffix")
466 :     if defined $submit_button and ($submit_button eq 'Save' or $submit_button eq 'Save as');
467 :     }
468 : malsyned 980
469 : gage 981 # return values for use in the body subroutine
470 : gage 1591 $self->{inputFilePath} = $inputFilePath;
471 :     $self->{displayMode} = $displayMode;
472 :     $self->{problemSeed} = $problemSeed;
473 :     $self->{r_problemContents} = \$problemContents;
474 : gage 1747 $self->{editFileSuffix} = $editFileSuffix;
475 : malsyned 980 }
476 :    
477 : gage 889 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9