Parent Directory
|
Revision Log
Now you can save changes to problems -dennis
1 package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor; 2 use base qw(WeBWorK::ContentGenerator::Instructor); 3 use WeBWorK::Utils qw(readFile formatDateTime parseDateTime); 4 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 our $rowheight = 20; #controls the length of the popup menus. 16 our $libraryName; #library directory name 17 18 sub getSetName { 19 my ($self, $pathSetName) = @_; 20 if (ref $pathSetName eq "HASH") { 21 $pathSetName = undef; 22 } 23 return $pathSetName; 24 } 25 26 sub title { 27 my ($self, @components) = @_; 28 return "Problem Set Editor - ".$self->{ce}->{courseName}." : ".$self->getSetName(@components); 29 } 30 31 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 if (defined($r->param('submit_set_changes'))) { 39 my $changed = 0; 40 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 $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 } 66 } 67 } 68 69 sub body { 70 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 my @editForUser = $r->param('editForUser'); 76 my $forUser = scalar(@editForUser); 77 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 print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"}); 128 print CGI::end_form(); 129 130 print CGI::h2({}, "Problems"); 131 132 my @problemList = $db->listGlobalProblems($setName); 133 134 print CGI::start_form({method=>"POST", action=>$r->uri}); 135 print CGI::start_table({}); 136 print CGI::Tr({}, CGI::th({}, ["Problem", "Max. Attempts", "Weight", "Source File"])); 137 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 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 171 return ""; 172 } 173 174 sub mike_body { 175 my $self = shift; 176 177 # test area 178 my $r = $self->{r}; 179 my $db = $self->{db}; 180 181 my $user = $r->param('user'); 182 my $key = $db->getKey($user)->key(); 183 184 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 # $problemName -- the name of the library problem (in the previous library directory) 194 # $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 ######################################################################### 202 # Determine a name for this set 203 ######################################################################### 204 # Determine the set number, if there is one. Otherwise make setName = "new set". 205 # FIXME: 206 # my ($path_info,@components) = $self->gatherInfo(); 207 # my $setName = $components[0]; # get GET address for set name 208 209 # Override the setName if it is defined in a form. 210 # $setName = $r->param('setName') if defined($r->param('setName')); 211 212 213 ######################################################################### 214 # determine the library set directory 215 ######################################################################### 216 # $libraryName = $self->{ce}->{courseDirs}->{templates}; 217 # my $setDirectory = $r->param('setDirectory'); 218 # my $oldSetDirectory = $r->param('oldSetDirectory'); 219 220 #FIXME: 221 # 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 # Determine values for strings 230 ######################################################################### 231 #text area region, adding problems to the list 232 ######################################################################### 233 234 my $textAreaString; 235 #FIXME: -- this does not handle multiple problem selections correctly. 236 # my $problemName = $r->param('pgProblem'); 237 # my $problemList = $r->param('problemList'); 238 239 # Initialize the textarea string if it is empty or hasn't been defined. 240 $problemList = $self->gatherProblemList($setName) unless defined($problemList) and $problemList =~/\S/; 241 242 my $problemEntry = $oldSetDirectory.'/'.$problemName.", 1, -1 \r\n"; 243 # add the new problem entry if the address is complete. (still buggy -- how do insure that oldSetDirectory is not empty? 244 $problemList .= $problemEntry unless $problemEntry =~ m|^/|; # don't print if oldSetDirectory name is empy (FIXME: -- more checks are needed?) 245 # format the complete textArea string 246 $textAreaString = CGI::textarea({"name"=>"problemList", "cols"=>"40", "rows"=>$rowheight, "default"=>$problemList}); 247 248 #Determine the headline for the page 249 250 251 #FIXME: Debugging code 252 # my $header = "Choose problems from $libraryName directory" . 253 # "<p>This form is not yet operational. 254 # <p>SetDirectory is $setDirectory. 255 # <p>formURL is $formURL 256 # <p>path_info is $path_info"; 257 my $header = ''; 258 259 260 ######################################################################### 261 # Define the popup strings used for selecting the library set directory, and the problem from that directory 262 #FIXME: 263 # he problem of multiple selections needs to be handled properly. 264 ######################################################################### 265 my $popUpSetDirectoryString = $self->fetchSetDirectories($setDirectory); #pass default choice as current directory 266 my $popUpPGProblemString = $self->fetchPGproblems($setDirectory); 267 268 269 ######################################################################### 270 # Define a link to view the problem 271 #FIXME: 272 # Currently this link used the webwork problem library, which might be out of 273 # sync with the local library 274 ######################################################################### 275 276 277 my $viewProblemLink; 278 if ( (defined($oldSetDirectory) and defined($problemName)) ) { 279 $viewProblemLink = "View: " 280 . CGI::a({ 281 "href"=>"http://webhost.math.rochester.edu/webworkdocs/ww/pgView/$oldSetDirectory/$problemName", 282 "target"=>"_probwindow" 283 }, "$oldSetDirectory/$problemName"); 284 } else { 285 $viewProblemLink = ''; 286 287 } 288 ######################################################################### 289 # Format the page 290 ######################################################################### 291 292 return CGI::p($header) 293 #CGI::start_form(-action=>"/webwork/mth143/instructor/problemSetEditor/"), 294 . CGI::start_form(-action=>$formURL) 295 . CGI::table( {-border=>2}, 296 CGI::Tr({-align=>'CENTER',-valign=>'TOP'}, 297 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 # "<p> the parameters passed are " #FIXME: -- debugging code 332 # . join("<BR>", %{$r->param()}) . $self->gatherProblemList($setName)."setName is $setName"; 333 ; 334 335 } 336 337 sub gatherInfo { 338 #FIXME: This is very much hacked together. In particular can we pass the key inside the post? 339 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 $remaining_path =~ s/^.*problemSetEditor//; 347 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 # FIXME:?? -- this insures backward compatibility with the old file naming convention. 351 $setName = "set$setName" unless $setName =~/^set/; 352 353 # 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 #FIXME -- this does not handle multiple problem selections correctly. 366 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 } 381 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 sub fetchSetDirectories { 405 406 my $self = shift; 407 my $defaultChoice = shift; 408 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 return "$libraryName/" . CGI::br(). CGI::popup_menu(-name=>'setDirectory', -size=>$rowheight, 425 -values=>\@sortedNames, -default=>$defaultChoice ) .CGI::br() ; 426 } 427 428 sub fetchPGproblems { 429 430 my $self = shift; 431 my $setDirectory = shift; 432 433 # Handle default for setDirectory 434 # FIXME -- this is not bullet proof 435 $setDirectory = "set0" unless defined($setDirectory); 436 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 return "$setDirectory ". CGI::br() . 454 CGI::popup_menu(-name=>'pgProblem', -size=>$rowheight, -multiple=>undef, -values=>\@sortedNames, ) . 455 CGI::br() ; 456 } 457 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |