Parent Directory
|
Revision Log
Changed explicit references to "/webwork" to the abstract
$ce->{webworkURLs}->{root}. If you've been hardcoding "/webwork" into
your URLs, you should take a look at the diff to this update to learn
the prefered method.
-Dennis
1 package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor; 2 use base qw(WeBWorK::ContentGenerator::Instructor); 3 4 =head1 NAME 5 6 WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list 7 8 =cut 9 10 use strict; 11 use warnings; 12 use CGI qw(); 13 use WeBWorK::DB::Record::Problem; 14 use WeBWorK::Utils qw(readFile formatDateTime parseDateTime list2hash readDirectory max); 15 16 our $rowheight = 20; #controls the length of the popup menus. 17 our $libraryName; #library directory name 18 19 use constant SET_FIELDS => [qw(open_date due_date answer_date set_header problem_header)]; 20 use constant PROBLEM_FIELDS =>[qw(source_file value max_attempts)]; 21 use constant PROBLEM_USER_FIELDS => [qw(problem_seed status num_correct num_incorrect)]; 22 23 sub getSetName { 24 my ($self, $pathSetName) = @_; 25 if (ref $pathSetName eq "HASH") { 26 $pathSetName = undef; 27 } 28 return $pathSetName; 29 } 30 31 # One wrinkle here: if $override is undefined, do the global thing, otherwise, it's truth value determines the checkbox. 32 sub setRowHTML { 33 my ($description, $fieldName, $fieldValue, $size, $override, $overrideValue) = @_; 34 35 my $attributeHash = {type=>"text", name=>$fieldName, value=>$fieldValue}; 36 $attributeHash->{size} = $size if defined $size; 37 38 my $html = CGI::td({}, [$description, CGI::input($attributeHash)]); 39 40 if (defined $override) { 41 $attributeHash->{name}="${fieldName}_override"; 42 $attributeHash->{value}=($override ? $overrideValue : "" ); 43 44 $html .= CGI::td({}, [ 45 CGI::checkbox({ 46 type=>"checkbox", 47 name=>"override", 48 label=>"override with:", 49 value=>$fieldName, 50 checked=>($override ? 1 : 0) 51 }), 52 CGI::input($attributeHash) 53 ]); 54 } 55 56 return $html; 57 58 } 59 60 sub hiddenEditForUserFields { 61 my @editForUser = @_; 62 my $return = ""; 63 foreach my $editUser (@editForUser) { 64 $return .= CGI::input({type=>"hidden", name=>"editForUser", value=>$editUser}); 65 } 66 67 return $return; 68 } 69 70 sub problemElementHTML { 71 my ($fieldName, $fieldValue, $size, $override, $overrideValue) = @_; 72 my $attributeHash = {type=>"text",name=>$fieldName,value=>$fieldValue}; 73 $attributeHash->{size} = $size if defined $size; 74 75 my $html = CGI::input($attributeHash); 76 if (defined $override) { 77 $attributeHash->{name} = "${fieldName}_override"; 78 $attributeHash->{value} = ($override ? $overrideValue : ""); 79 $html = "default:".CGI::br().$html.CGI::br() 80 . CGI::checkbox({ 81 type => "checkbox", 82 name => "override", 83 label => "override:", 84 value => $fieldName, 85 checked => ($override ? 1 : 0) 86 }) 87 . CGI::br() 88 . CGI::input($attributeHash); 89 } 90 91 return $html; 92 } 93 94 95 # pay no attention to the argument list. Here's what you pass: 96 # directoryListHTML($level, $selected, $libraryRoot, @path) 97 sub directoryListHTML { 98 my ($level, $selected, @path) = @_; 99 $selected = [$selected] unless ref $selected eq "ARRAY"; 100 my $dirName = join "/", @path[0..$level]; 101 my @contents = sort grep {m/\.pg$/ or -d $dirName.'/'.$_ and not m/^\.{1,2}$/} readDirectory($dirName); 102 my %contentsPretty = map {$_ => (-d $dirName.'/'.$_ ? $_.'/' : $_)} @contents; 103 104 my $html = ($level eq "0" ? "problem library" : $path[$level]) . CGI::br(); 105 $html .= CGI::scrolling_list({ 106 name=>"directory_level_$level", 107 values=>\@contents, 108 labels=>\%contentsPretty, 109 default=>$selected, 110 multiple=>'true', 111 size=>"20", 112 }); 113 $html .= CGI::br() 114 . CGI::input({type=>"submit", name=>"open_add_$level", value=>"Open/Add"}); 115 } 116 117 sub title { 118 my ($self, @components) = @_; 119 return "Problem Set Editor - ".$self->{ce}->{courseName}." : ".$self->getSetName(@components); 120 } 121 122 # Initialize does all of the form processing. It's extensive, and could probably be cleaned up and 123 # consolidated with a little abstraction. 124 sub initialize { 125 my ($self, @components) = @_; 126 my $r = $self->{r}; 127 my $db = $self->{db}; 128 my $ce = $self->{ce}; 129 my $setName = $self->getSetName(@components); 130 my $setRecord = $db->getGlobalSet($setName); 131 my @editForUser = $r->param('editForUser'); 132 # some useful booleans 133 my $forUsers = scalar(@editForUser); 134 my $forOneUser = $forUsers == 1; 135 136 # build a quick lookup table 137 my %overrides = list2hash $r->param('override'); 138 139 # The set form was submitted 140 if (defined($r->param('submit_set_changes'))) { 141 foreach (@{SET_FIELDS()}) { 142 if (defined($r->param($_))) { 143 if (m/_date$/) { 144 $setRecord->$_(parseDateTime($r->param($_))); 145 } else { 146 $setRecord->$_($r->param($_)); 147 } 148 } 149 } 150 $db->putGlobalSet($setRecord); 151 152 if ($forOneUser) { 153 154 my $userSetRecord = $db->getUserSet($editForUser[0], $setName); 155 foreach my $field (@{SET_FIELDS()}) { 156 if (defined $r->param("${field}_override")) { 157 if (exists $overrides{$field}) { 158 if ($field =~ m/_date$/) { 159 $userSetRecord->$field(parseDateTime($r->param("${field}_override"))); 160 } else { 161 $userSetRecord->$field($r->param("${field}_override")); 162 } 163 } else { 164 $userSetRecord->$field(undef); 165 } 166 167 $db->putUserSet($userSetRecord); 168 } 169 } 170 } 171 } 172 # the Problem form was submitted 173 elsif (defined($r->param('submit_problem_changes'))) { 174 foreach my $problem ($r->param('deleteProblem')) { 175 $db->deleteGlobalProblem($setName, $problem); 176 } 177 my @problemList = $db->listGlobalProblems($setName); 178 foreach my $problem (@problemList) { 179 my $problemRecord = $db->getGlobalProblem($setName, $problem); 180 foreach my $field (@{PROBLEM_FIELDS()}) { 181 my $paramName = "problem_${problem}_${field}"; 182 if (defined($r->param($paramName))) { 183 $problemRecord->$field($r->param($paramName)); 184 } 185 } 186 $db->putGlobalProblem($problemRecord); 187 188 if ($forOneUser) { 189 my $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem); 190 foreach my $field (@{PROBLEM_USER_FIELDS()}) { 191 my $paramName = "problem_${problem}_${field}"; 192 if (defined($r->param($paramName))) { 193 $userProblemRecord->$field($r->param($paramName)); 194 } 195 } 196 $userProblemRecord->attempted($userProblemRecord->num_correct + $userProblemRecord->num_incorrect); 197 foreach my $field (@{PROBLEM_FIELDS()}) { 198 my $paramName = "problem_${problem}_${field}"; 199 if (defined($r->param("${paramName}_override"))) { 200 if (exists $overrides{$paramName}) { 201 $userProblemRecord->$field($r->param("${paramName}_override")); 202 } else { 203 $userProblemRecord->$field(undef); 204 } 205 206 $db->putUserProblem($userProblemRecord); 207 } 208 } 209 210 } 211 } 212 } elsif (defined $r->param('fileBrowsing')) { 213 my $libraryRoot = $ce->{courseDirs}->{templates}; 214 my $count = 0; 215 my $done = 0; 216 my @path = (); 217 my $freeProblemID = max($db->listGlobalProblems($setName)) + 1; 218 while (defined $r->param("directory_level_$count") and not $done) { 219 my @selected = $r->param("directory_level_$count"); 220 my $dirFound = 0; 221 # If any directories are selected, "cd" into the first one and stop processing this level. 222 foreach my $selected (@selected) { 223 if (-d join "/", $libraryRoot, @path, $selected) { 224 push @path, $selected; 225 $dirFound = 1; 226 last; 227 } 228 } 229 # Otherwise, create a new global problem for each of the files selected 230 unless ($dirFound) { 231 foreach my $selected (@selected) { 232 my $file = join "/", @path, $selected; 233 my $problemRecord = new WeBWorK::DB::Record::Problem; 234 $problemRecord->problem_id($freeProblemID++); 235 $problemRecord->set_id($setName); 236 $problemRecord->source_file($file); 237 $problemRecord->value("1"); 238 $problemRecord->max_attempts("-1"); 239 $db->addGlobalProblem($problemRecord); 240 } 241 $done = 1; 242 } 243 244 if (defined $r->param("open_add_$count")) { 245 $done = 1; 246 } 247 $count++; 248 } 249 $self->{path} = [@path]; 250 } 251 } 252 253 254 sub body { 255 my ($self, @components) = @_; 256 my $r = $self->{r}; 257 my $db = $self->{db}; 258 my $ce = $self->{ce}; 259 my $courseName = $ce->{courseName}; 260 my $setName = $self->getSetName(@components); 261 my $setRecord = $db->getGlobalSet($setName); 262 my @editForUser = $r->param('editForUser'); 263 # some useful booleans 264 my $forUsers = scalar(@editForUser); 265 my $forOneUser = $forUsers == 1; 266 267 ## Set Form ## 268 my $userSetRecord; 269 my %overrideArgs; 270 if ($forOneUser) { 271 $userSetRecord = $db->getUserSet($editForUser[0], $setName); 272 foreach my $field (@{SET_FIELDS()}) { 273 $overrideArgs{$field} = [defined $userSetRecord->$field, ($field =~ /_date$/ ? formatDateTime($userSetRecord->$field) : $userSetRecord->$field)]; 274 } 275 } else { 276 foreach my $field (@{SET_FIELDS()}) { 277 $overrideArgs{$field} = [undef, undef]; 278 } 279 } 280 281 print CGI::h2({}, "Set Data"), "\n"; 282 print CGI::start_form({method=>"post", action=>$r->uri}), "\n"; 283 print CGI::table({}, 284 CGI::Tr({}, [ 285 setRowHTML("Open Date:", "open_date", formatDateTime($setRecord->open_date), undef, @{$overrideArgs{open_date}})."\n", 286 setRowHTML("Due Date:", "due_date", formatDateTime($setRecord->due_date), undef, @{$overrideArgs{due_date}})."\n", 287 setRowHTML("Answer Date:", "answer_date", formatDateTime($setRecord->answer_date), undef, @{$overrideArgs{answer_date}})."\n", 288 setRowHTML("Set Header:", "set_header", $setRecord->set_header, undef, @{$overrideArgs{set_header}})."\n", 289 setRowHTML("Problem Header:", "problem_header", $setRecord->problem_header, undef, @{$overrideArgs{problem_header}})."\n" 290 ]) 291 ); 292 293 print hiddenEditForUserFields(@editForUser); 294 print $self->hidden_authen_fields; 295 print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"}); 296 print CGI::end_form(); 297 298 ## Problems Form ## 299 my @problemList = $db->listGlobalProblems($setName); 300 print CGI::a({name=>"problems"}); 301 print CGI::h2({}, "Problems"); 302 if (scalar(@problemList)) { 303 print CGI::start_form({method=>"POST", action=>$r->uri.'#problems'}); 304 print CGI::start_table({border=>1, cellpadding=>4}); 305 print CGI::Tr({}, CGI::th({}, [ 306 ($forUsers ? () : ("Delete?")), 307 "Problem", 308 ($forUsers ? ("Status", "Problem Seed") : ()), 309 "Source File", "Max. Attempts", "Weight", 310 ($forUsers ? ("Number Correct", "Number Incorrect") : ()) 311 ])); 312 foreach my $problem (sort {$a <=> $b} @problemList) { 313 my $problemRecord = $db->getGlobalProblem($setName, $problem); 314 my $problemID = $problemRecord->problem_id; 315 my $userProblemRecord; 316 my %problemOverrideArgs; 317 318 if ($forOneUser) { 319 $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem); 320 foreach my $field (@{PROBLEM_FIELDS()}) { 321 $problemOverrideArgs{$field} = [defined $userProblemRecord->$field, $userProblemRecord->$field]; 322 } 323 # } elsif ($forUsers) { 324 # foreach my $field (@{PROBLEM_FIELDS()}) { 325 # $problemOverrideArgs{$field} = ["", ""]; 326 # } 327 } else { 328 foreach my $field (@{PROBLEM_FIELDS()}) { 329 $problemOverrideArgs{$field} = [undef, undef]; 330 } 331 } 332 333 print CGI::Tr({}, 334 CGI::td({}, [ 335 ($forUsers ? () : (CGI::input({type=>"checkbox", name=>"deleteProblem", value=>$problemID}))), 336 CGI::a({href=>$ce->{webworkURLs}->{root}."/$courseName/instructor/pgProblemEditor/".$setName.'/'.$problemID.'?'.$self->url_authen_args}, $problemID), 337 ($forUsers ? ( 338 problemElementHTML("problem_${problemID}_status", $userProblemRecord->status, "7"), 339 problemElementHTML("problem_${problemID}_problem_seed", $userProblemRecord->problem_seed, "7"), 340 ) : ()), 341 problemElementHTML("problem_${problemID}_source_file", $problemRecord->source_file, "40", @{$problemOverrideArgs{source_file}}), 342 problemElementHTML("problem_${problemID}_max_attempts",$problemRecord->max_attempts,"7", @{$problemOverrideArgs{max_attempts}}), 343 problemElementHTML("problem_${problemID}_value",$problemRecord->value,"7", @{$problemOverrideArgs{value}}), 344 ($forUsers ? ( 345 problemElementHTML("problem_${problemID}_num_correct", $userProblemRecord->num_correct, "7"), 346 problemElementHTML("problem_${problemID}_num_incorrect", $userProblemRecord->num_incorrect, "7") 347 ) : ()) 348 ]) 349 350 ) 351 } 352 print CGI::end_table(); 353 print hiddenEditForUserFields(@editForUser); 354 print $self->hidden_authen_fields; 355 print CGI::input({type=>"submit", name=>"submit_problem_changes", value=>"Save Problem Changes"}); 356 print CGI::end_form(); 357 } else { 358 print CGI::p("This set doesn't contain any problems yet."); 359 } 360 361 unless ($forUsers) { 362 my $libraryRoot = $ce->{courseDirs}->{templates}; 363 my @path = defined $self->{path} ? @{$self->{path}} : (); 364 unshift @path, $libraryRoot; 365 print CGI::a({name=>"addProblem"}); 366 print CGI::h3({}, "Add Problem(s)"); 367 print CGI::start_form({method=>"post", action=>$r->uri.'#addProblem'}); 368 print CGI::input({type=>"hidden", name=>"fileBrowsing", value=>"Yes"}); 369 print CGI::start_table(); 370 my $columns = ""; 371 for (my $counter = 0; $counter < scalar(@path); $counter++) { 372 $columns .= CGI::td(directoryListHTML ($counter, (exists $path[$counter+1] ? $path[$counter+1] : []), @path)); 373 } 374 print CGI::Tr($columns); 375 print CGI::end_table(); 376 print $self->hidden_authen_fields; 377 print CGI::end_form(); 378 } 379 return ""; 380 } 381 382 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |