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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 936 - (view) (download) (as text)

1 : gage 860 package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor;
2 :     use base qw(WeBWorK::ContentGenerator::Instructor);
3 : malsyned 935 use WeBWorK::Utils qw(readFile formatDateTime parseDateTime);
4 : gage 860
5 :     =head1 NAME
6 :    
7 :     WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list
8 :    
9 :     =cut
10 :    
11 :     use strict;
12 :     use warnings;
13 :     use CGI qw();
14 :    
15 : gage 869 our $rowheight = 20; #controls the length of the popup menus.
16 : gage 875 our $libraryName; #library directory name
17 : malsyned 935
18 :     sub getSetName {
19 :     my ($self, $pathSetName) = @_;
20 :     if (ref $pathSetName eq "HASH") {
21 :     $pathSetName = undef;
22 :     }
23 :     return $pathSetName;
24 :     }
25 :    
26 : gage 860 sub title {
27 : malsyned 935 my ($self, @components) = @_;
28 :     return "Problem Set Editor - ".$self->{ce}->{courseName}." : ".$self->getSetName(@components);
29 : gage 860 }
30 :    
31 : malsyned 935 sub initialize {
32 :     my ($self, @components) = @_;
33 :     my $r = $self->{r};
34 :     my $db = $self->{db};
35 :     my $setName = $self->getSetName(@components);
36 :     my $setRecord = $db->getGlobalSet($setName);
37 :    
38 : malsyned 936 if (defined($r->param('submit_set_changes'))) {
39 :     my $changed = 0;
40 : malsyned 935 foreach (qw(open_date due_date answer_date)) {
41 :     if (defined($r->param($_))) {
42 :     if (m/_date$/) {
43 :     $setRecord->$_(parseDateTime($r->param($_)));
44 :     } else {
45 :     $setRecord->$_($r->param($_));
46 :     }
47 :     $changed = 1;
48 :     }
49 :     }
50 : malsyned 936 $db->putGlobalSet($setRecord) if $changed;
51 :     }
52 :     elsif (defined($r->param('submit_problem_changes'))) {
53 :     my @problemList = $db->listGlobalProblems($setName);
54 :     foreach my $problem (@problemList) {
55 :     my $changed = 0;
56 :     my $problemRecord = $db->getGlobalProblem($setName, $problem);
57 :     foreach (qw(source_file value max_attempts)) {
58 :     my $paramName = "problem_${problem}_$_";
59 :     if (defined($r->param($paramName))) {
60 :     $problemRecord->$_($r->param($paramName));
61 :     $changed = 1;
62 :     }
63 :     }
64 :     $db->putGlobalProblem($problemRecord)
65 : malsyned 935 }
66 :     }
67 :     }
68 :    
69 : gage 860 sub body {
70 : malsyned 935 my ($self, @components) = @_;
71 :     my $r = $self->{r};
72 :     my $db = $self->{db};
73 :     my $setName = $self->getSetName(@components);
74 :     my $setRecord = $db->getGlobalSet($setName);
75 : malsyned 936 my @editForUser = $r->param('editForUser');
76 :     my $forUser = scalar(@editForUser);
77 : malsyned 935
78 :     print CGI::h2({}, "Set Data");
79 :     print CGI::start_form({method=>"post", action=>$r->uri});
80 :     print CGI::table({},
81 :     CGI::Tr({}, [
82 :     CGI::td({}, [
83 :     "Open Date:",
84 :     CGI::input({
85 :     type=>"text",
86 :     name=>"open_date",
87 :     value=>formatDateTime($setRecord->open_date)
88 :     })
89 :     ]),
90 :     CGI::td({}, [
91 :     "Due Date:",
92 :     CGI::input({
93 :     type=>"text",
94 :     name=>"due_date",
95 :     value=>formatDateTime($setRecord->due_date)
96 :     })
97 :     ]),
98 :     CGI::td({}, [
99 :     "Answer Date:",
100 :     CGI::input({
101 :     type=>"text",
102 :     name=>"answer_date",
103 :     value=>formatDateTime($setRecord->answer_date)
104 :     })
105 :     ]),
106 :     CGI::td({}, [
107 :     "Set Header:",
108 :     CGI::input({
109 :     type=>"text",
110 :     name=>"set_header",
111 :     value=>$setRecord->set_header
112 :     })
113 :     ]),
114 :     CGI::td({}, [
115 :     "Problem Header:",
116 :     CGI::input({
117 :     type=>"text",
118 :     name=>"problem_header",
119 :     value=>$setRecord->problem_header
120 :     })
121 :     ])
122 :    
123 :     ])
124 :     );
125 :    
126 :     print $self->hidden_authen_fields;
127 : malsyned 936 print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"});
128 : malsyned 935 print CGI::end_form();
129 :    
130 :     print CGI::h2({}, "Problems");
131 :    
132 :     my @problemList = $db->listGlobalProblems($setName);
133 :    
134 : malsyned 936 print CGI::start_form({method=>"POST", action=>$r->uri});
135 : malsyned 935 print CGI::start_table({});
136 : malsyned 936 print CGI::Tr({}, CGI::th({}, ["Problem", "Max. Attempts", "Weight", "Source File"]));
137 : malsyned 935 foreach my $problem (sort {$a <=> $b} @problemList) {
138 :     my $problemRecord = $db->getGlobalProblem($setName, $problem);
139 :     my $problemID = $problemRecord->problem_id;
140 :    
141 :     print CGI::Tr({},
142 :     CGI::td({}, [
143 :     $problemID,
144 :     CGI::input({
145 :     size=>"7",
146 :     type=>"text",
147 :     name=>"problem_${problemID}_max_attempts",
148 :     value=>$problemRecord->max_attempts
149 :     }), CGI::input({
150 :     size=>"7",
151 :     type=>"text",
152 :     name=>"problem_${problemID}_value",
153 :     value=>$problemRecord->value
154 :     }),
155 :     CGI::input({
156 :     size=>"40",
157 :     type=>"text",
158 :     name=>"problem_${problemID}_source_file",
159 :     value=>$problemRecord->source_file
160 :     }),
161 :    
162 :     ])
163 :    
164 :     )
165 :     }
166 : malsyned 936 print CGI::end_table();
167 :     print $self->hidden_authen_fields;
168 :     print CGI::input({type=>"submit", name=>"submit_problem_changes", value=>"Save Problems"});
169 :     print CGI::end_form();
170 : malsyned 935
171 :     return "";
172 :     }
173 :    
174 :     sub mike_body {
175 : gage 860 my $self = shift;
176 : gage 868
177 :     # test area
178 :     my $r = $self->{r};
179 :     my $db = $self->{db};
180 : gage 869
181 : gage 868 my $user = $r->param('user');
182 :     my $key = $db->getKey($user)->key();
183 :    
184 : gage 875
185 :     ################
186 :     # Gathering info
187 :     # What is needed
188 :     # $setName -- formerly the name of the set definition file
189 :     # $formURL -- the action URL for the form
190 :     # $libraryName -- the name of the available library
191 :     # $setDirectory -- the current library directory
192 :     # $oldSetDirectory -- the previous library directory
193 : malsyned 891 # $problemName -- the name of the library problem (in the previous library directory)
194 : gage 875 # $problemList -- the contents of the textarea form
195 :     # answer dates
196 :     my ($setName,$formURL,
197 :     $libraryName,$setDirectory,$oldSetDirectory,
198 :     $problemName,$problemList,
199 :     $openDate,$dueDate,$answerDate) = $self->gatherInfo();
200 :    
201 : gage 872 #########################################################################
202 : gage 869 # Determine a name for this set
203 : gage 872 #########################################################################
204 : gage 868 # Determine the set number, if there is one. Otherwise make setName = "new set".
205 : malsyned 888 # FIXME:
206 : gage 875 # my ($path_info,@components) = $self->gatherInfo();
207 :     # my $setName = $components[0]; # get GET address for set name
208 : gage 868
209 :     # Override the setName if it is defined in a form.
210 : gage 875 # $setName = $r->param('setName') if defined($r->param('setName'));
211 : gage 868
212 : gage 875
213 : gage 872 #########################################################################
214 :     # determine the library set directory
215 :     #########################################################################
216 : gage 875 # $libraryName = $self->{ce}->{courseDirs}->{templates};
217 :     # my $setDirectory = $r->param('setDirectory');
218 :     # my $oldSetDirectory = $r->param('oldSetDirectory');
219 : gage 868
220 : malsyned 888 #FIXME:
221 : gage 869 # A user can select a new set AND a problem (in the old set) but the problem won't be in the new set!
222 :     # In other words we must prevent the user from changing the problem and the set simultaneously.
223 :     # We solve this by defining a hidden variable oldSetDirectory which matches the currently displayed problem list
224 :     # the problem entry for the textarea element and the viewProblem url are
225 :     # formed using this old version of setDefinition
226 :    
227 :    
228 :    
229 : gage 868 # Determine values for strings
230 : gage 872 #########################################################################
231 :     #text area region, adding problems to the list
232 :     #########################################################################
233 : gage 868
234 : gage 869 my $textAreaString;
235 : malsyned 888 #FIXME: -- this does not handle multiple problem selections correctly.
236 : gage 875 # my $problemName = $r->param('pgProblem');
237 :     # my $problemList = $r->param('problemList');
238 : gage 872
239 :     # Initialize the textarea string if it is empty or hasn't been defined.
240 : gage 884 $problemList = $self->gatherProblemList($setName) unless defined($problemList) and $problemList =~/\S/;
241 :    
242 : gage 875 my $problemEntry = $oldSetDirectory.'/'.$problemName.", 1, -1 \r\n";
243 : gage 872 # add the new problem entry if the address is complete. (still buggy -- how do insure that oldSetDirectory is not empty?
244 : malsyned 888 $problemList .= $problemEntry unless $problemEntry =~ m|^/|; # don't print if oldSetDirectory name is empy (FIXME: -- more checks are needed?)
245 : gage 872 # format the complete textArea string
246 : malsyned 891 $textAreaString = CGI::textarea({"name"=>"problemList", "cols"=>"40", "rows"=>$rowheight, "default"=>$problemList});
247 : gage 868
248 : gage 872 #Determine the headline for the page
249 :    
250 : gage 875
251 : malsyned 888 #FIXME: Debugging code
252 : gage 875 # my $header = "Choose problems from $libraryName directory" .
253 : gage 869 # "<p>This form is not yet operational.
254 :     # <p>SetDirectory is $setDirectory.
255 : gage 875 # <p>formURL is $formURL
256 : gage 869 # <p>path_info is $path_info";
257 :     my $header = '';
258 : gage 868
259 :    
260 : gage 872 #########################################################################
261 :     # Define the popup strings used for selecting the library set directory, and the problem from that directory
262 : malsyned 888 #FIXME:
263 : gage 869 # he problem of multiple selections needs to be handled properly.
264 : gage 872 #########################################################################
265 : gage 868 my $popUpSetDirectoryString = $self->fetchSetDirectories($setDirectory); #pass default choice as current directory
266 :     my $popUpPGProblemString = $self->fetchPGproblems($setDirectory);
267 :    
268 : gage 869
269 : gage 872 #########################################################################
270 : gage 869 # Define a link to view the problem
271 : malsyned 888 #FIXME:
272 : gage 869 # Currently this link used the webwork problem library, which might be out of
273 :     # sync with the local library
274 : gage 872 #########################################################################
275 : gage 869
276 :    
277 :     my $viewProblemLink;
278 : gage 875 if ( (defined($oldSetDirectory) and defined($problemName)) ) {
279 : malsyned 891 $viewProblemLink = "View: "
280 :     . CGI::a({
281 :     "href"=>"http://webhost.math.rochester.edu/webworkdocs/ww/pgView/$oldSetDirectory/$problemName",
282 :     "target"=>"_probwindow"
283 :     }, "$oldSetDirectory/$problemName");
284 : gage 869 } else {
285 :     $viewProblemLink = '';
286 :    
287 :     }
288 : gage 872 #########################################################################
289 :     # Format the page
290 :     #########################################################################
291 : malsyned 891
292 :     return CGI::p($header)
293 : gage 868 #CGI::start_form(-action=>"/webwork/mth143/instructor/problemSetEditor/"),
294 : malsyned 891 . CGI::start_form(-action=>$formURL)
295 :     . CGI::table( {-border=>2},
296 : gage 860 CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
297 : malsyned 891 CGI::th('Editing set : ')
298 :     . CGI::td(CGI::textfield( -name=>'setName',-size=>'20',-value=>$setName,-override=>1))
299 :     . CGI::td(CGI::submit(-name=>'submitButton',-value=>'Save'))
300 :     )
301 :     . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
302 :     CGI::td($textAreaString)
303 :     . CGI::td($popUpSetDirectoryString)
304 :     . CGI::td($popUpPGProblemString)
305 :    
306 :     )
307 :     #(defined($viewProblemLink)) ?
308 :     # CGI::Tr({"align"=>"center","valign"=>"top"}, CGI::th({"colspan"="3"}, $viewProblemLink))
309 :     # : '',
310 :     . CGI::Tr( {-align=>'CENTER',-valign=>'TOP'},
311 :     CGI::th([$viewProblemLink,
312 :     CGI::submit(-name=>'submitButton' , -value =>'Select set'),
313 :     CGI::submit(-name=>'submitButton' , -value =>'Choose problem')
314 :     ])
315 :     )
316 :     . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
317 :     CGI::th(["Open date","Due date", "Answer date"])
318 :     )
319 :     . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
320 :     CGI::td(CGI::textfield( -name=>'open_date', -size=>'20', -value=>$openDate))
321 :     . CGI::td(CGI::textfield(-name=>'due_date', -size=>'20', -value=>$dueDate))
322 :     . CGI::td(CGI::textfield(-name=>'answer_date', -size=>'20', -value=>$answerDate))
323 :     )
324 :     . CGI::Tr({"align"=>"center", "valign"=>"top"},
325 :     CGI::td({"colspan"=>"3"}, "View entire set (pdf format) -- not yet implemented")
326 :     )
327 :     )
328 :     . $self->hidden_authen_fields
329 :     . CGI::hidden(-name=>'oldSetDirectory', -value=>$setDirectory)
330 :     . CGI::end_form()
331 : malsyned 888 # "<p> the parameters passed are " #FIXME: -- debugging code
332 : gage 884 # . join("<BR>", %{$r->param()}) . $self->gatherProblemList($setName)."setName is $setName";
333 : gage 860 ;
334 :    
335 :     }
336 :    
337 : gage 868 sub gatherInfo {
338 : malsyned 887 #FIXME: This is very much hacked together. In particular can we pass the key inside the post?
339 : gage 875 my $self = shift;
340 :     my $ce = $self->{ce};
341 :     my $r = $self->{r};
342 :     my $path_info = $r->path_info || "";
343 :    
344 :     ## Determine the set name
345 :     my $remaining_path = $path_info;
346 : gage 868 $remaining_path =~ s/^.*problemSetEditor//;
347 : gage 875 my($junk, $setName, @components) = split "/", $remaining_path;
348 :     # Override the setName if it is defined in a form.
349 :     $setName = $r->param('setName') if defined($r->param('setName'));
350 : malsyned 888 # FIXME:?? -- this insures backward compatibility with the old file naming convention.
351 : gage 884 $setName = "set$setName" unless $setName =~/^set/;
352 : gage 868
353 : gage 875 # Find the URL for the form
354 :     $path_info =~s|problemSetEditor.*$|problemSetEditor/|; # remove the setName, if any, from the path
355 :     my $formURL = "/webwork$path_info"; # . $setName$self->url_authen_args();
356 :    
357 :     #########################################################################
358 :     # determine the library name and set directory
359 :     #########################################################################
360 :     $libraryName = $ce->{courseDirs}->{templates};
361 :     my $setDirectory = $r->param('setDirectory');
362 :     my $oldSetDirectory = $r->param('oldSetDirectory');
363 :    
364 :     # Determine the problem name
365 : malsyned 888 #FIXME -- this does not handle multiple problem selections correctly.
366 : gage 875 my $problemName = $r->param('pgProblem');
367 :     # Determine the text area string (contents of set definition "file")
368 :     my $problemList = $r->param('problemList');
369 :    
370 :     # get answer dates
371 :    
372 :     my $openDate = $r->param('open_date');
373 :     $openDate = "" unless defined($openDate);
374 :     my $dueDate = $r->param('due_date');
375 :     $dueDate = "" unless defined($dueDate);
376 :     my $answerDate = $r->param('answer_date');
377 :     $answerDate = "" unless defined($answerDate);
378 :    
379 :     ($setName,$formURL,$libraryName,$setDirectory,$oldSetDirectory,$problemName,$problemList,$openDate,$dueDate,$answerDate);
380 : gage 868 }
381 : gage 884
382 :     sub gatherProblemList { #workaround for obtaining the definition of a problem set (awaiting implementation of db function)
383 :     my $self = shift;
384 :     my $setName = shift;
385 :     my $output = "";
386 :     if ( defined($setName) and $setName ne "" ) {
387 :     my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
388 :     my $fileName = "$templateDirectory/$setName.def";
389 :     my @output = split("\n",WeBWorK::Utils::readFile($fileName) );
390 :     @output = grep /\.pg/, @output; # only get the .pg files
391 :     @output = grep !/Header/, @output; # eliminate header files
392 :     $output = join("\n",@output);
393 :     } else {
394 :     $output = "No set name |$setName| is defined";
395 :     }
396 :    
397 :    
398 :     return $output
399 :    
400 :    
401 :    
402 :    
403 :     }
404 : gage 860 sub fetchSetDirectories {
405 :    
406 :     my $self = shift;
407 : gage 868 my $defaultChoice = shift;
408 : gage 860 my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
409 :     opendir SETDEFDIR, $templateDirectory
410 :     or return "Can't open directory $templateDirectory";
411 :    
412 :     my @allFiles = grep !/^\./, readdir SETDEFDIR;
413 :     closedir SETDEFDIR;
414 :    
415 :     ## filter to find only the set directories
416 :     ## -- it is assumed that these directories don't contain a period in their names
417 :     ## and that all other files do. Directories names must also begin with "set".
418 :     ## A better plan would be to read only the names of directories, not files.
419 :    
420 :     ## sort the directories
421 :     my @setDefFiles = grep /^set[^\.]*$/, @allFiles;
422 :     my @sortedNames = sort @setDefFiles;
423 :    
424 : gage 875 return "$libraryName/" . CGI::br(). CGI::popup_menu(-name=>'setDirectory', -size=>$rowheight,
425 : gage 869 -values=>\@sortedNames, -default=>$defaultChoice ) .CGI::br() ;
426 : gage 860 }
427 :    
428 :     sub fetchPGproblems {
429 :    
430 :     my $self = shift;
431 : gage 868 my $setDirectory = shift;
432 :    
433 :     # Handle default for setDirectory
434 : malsyned 888 # FIXME -- this is not bullet proof
435 : gage 868 $setDirectory = "set0" unless defined($setDirectory);
436 : gage 860 my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
437 :    
438 :     ##
439 :     opendir SETDEFDIR, "$templateDirectory/$setDirectory"
440 :     or return "Can't open directory $templateDirectory/$setDirectory";
441 :    
442 :     my @allFiles = grep !/^\./, readdir SETDEFDIR;
443 :     closedir SETDEFDIR;
444 :    
445 :     ## filter to find only pg problems
446 :     ## Some problems are themselves in directories (if they have auxiliary
447 :     ## .png's for example. This eventuallity needs to be handled.
448 :    
449 :     ## sort the directories
450 :     my @pgFiles = grep /\.pg$/, @allFiles;
451 :     my @sortedNames = sort @pgFiles;
452 :    
453 : gage 869 return "$setDirectory ". CGI::br() .
454 : gage 875 CGI::popup_menu(-name=>'pgProblem', -size=>$rowheight, -multiple=>undef, -values=>\@sortedNames, ) .
455 : gage 869 CGI::br() ;
456 : gage 860 }
457 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9