Parent Directory
|
Revision Log
Efforts towards doing the Right Thing with the instructor URLs. -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 if ($forOneUser) { 152 153 my $userSetRecord = $db->getUserSet($editForUser[0], $setName); 154 foreach my $field (@{SET_FIELDS()}) { 155 if (defined $r->param("${field}_override")) { 156 if (exists $overrides{$field}) { 157 if ($field =~ m/_date$/) { 158 $userSetRecord->$field(parseDateTime($r->param("${field}_override"))); 159 } else { 160 $userSetRecord->$field($r->param("${field}_override")); 161 } 162 } else { 163 $userSetRecord->$field(undef); 164 } 165 166 $db->putUserSet($userSetRecord); 167 } 168 } 169 } 170 } 171 # the Problem form was submitted 172 elsif (defined($r->param('submit_problem_changes'))) { 173 foreach my $problem ($r->param('deleteProblem')) { 174 $db->deleteGlobalProblem($setName, $problem); 175 } 176 my @problemList = $db->listGlobalProblems($setName); 177 foreach my $problem (@problemList) { 178 my $problemRecord = $db->getGlobalProblem($setName, $problem); 179 foreach my $field (@{PROBLEM_FIELDS()}) { 180 my $paramName = "problem_${problem}_${field}"; 181 if (defined($r->param($paramName))) { 182 $problemRecord->$field($r->param($paramName)); 183 } 184 } 185 $db->putGlobalProblem($problemRecord); 186 187 if ($forOneUser) { 188 my $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem); 189 foreach my $field (@{PROBLEM_USER_FIELDS()}) { 190 my $paramName = "problem_${problem}_${field}"; 191 if (defined($r->param($paramName))) { 192 $userProblemRecord->$field($r->param($paramName)); 193 } 194 } 195 $userProblemRecord->attempted($userProblemRecord->num_correct + $userProblemRecord->num_incorrect); 196 foreach my $field (@{PROBLEM_FIELDS()}) { 197 my $paramName = "problem_${problem}_${field}"; 198 if (defined($r->param("${paramName}_override"))) { 199 if (exists $overrides{$paramName}) { 200 $userProblemRecord->$field($r->param("${paramName}_override")); 201 } else { 202 $userProblemRecord->$field(undef); 203 } 204 205 $db->putUserProblem($userProblemRecord); 206 } 207 } 208 209 } 210 } 211 } elsif (defined $r->param('fileBrowsing')) { 212 my $libraryRoot = $ce->{courseDirs}->{templates}; 213 my $count = 0; 214 my $done = 0; 215 my @path = (); 216 my $freeProblemID = max($db->listGlobalProblems($setName)) + 1; 217 while (defined $r->param("directory_level_$count") and not $done) { 218 my @selected = $r->param("directory_level_$count"); 219 my $dirFound = 0; 220 # If any directories are selected, "cd" into the first one and stop processing this level. 221 foreach my $selected (@selected) { 222 if (-d join "/", $libraryRoot, @path, $selected) { 223 push @path, $selected; 224 $dirFound = 1; 225 last; 226 } 227 } 228 # Otherwise, create a new global problem for each of the files selected 229 unless ($dirFound) { 230 foreach my $selected (@selected) { 231 my $file = join "/", @path, $selected; 232 my $problemRecord = new WeBWorK::DB::Record::Problem; 233 $problemRecord->problem_id($freeProblemID++); 234 $problemRecord->set_id($setName); 235 $problemRecord->source_file($file); 236 $problemRecord->value("1"); 237 $problemRecord->max_attempts("-1"); 238 $db->addGlobalProblem($problemRecord); 239 } 240 $done = 1; 241 } 242 243 if (defined $r->param("open_add_$count")) { 244 $done = 1; 245 } 246 $count++; 247 } 248 $self->{path} = [@path]; 249 } 250 } 251 252 253 sub body { 254 my ($self, @components) = @_; 255 my $r = $self->{r}; 256 my $db = $self->{db}; 257 my $ce = $self->{ce}; 258 my $courseName = $ce->{courseName}; 259 my $setName = $self->getSetName(@components); 260 my $setRecord = $db->getGlobalSet($setName); 261 my @editForUser = $r->param('editForUser'); 262 # some useful booleans 263 my $forUsers = scalar(@editForUser); 264 my $forOneUser = $forUsers == 1; 265 266 ## Set Form ## 267 my $userSetRecord; 268 my %overrideArgs; 269 if ($forOneUser) { 270 $userSetRecord = $db->getUserSet($editForUser[0], $setName); 271 foreach my $field (@{SET_FIELDS()}) { 272 $overrideArgs{$field} = [defined $userSetRecord->$field, ($field =~ /_date$/ ? formatDateTime($userSetRecord->$field) : $userSetRecord->$field)]; 273 } 274 } else { 275 foreach my $field (@{SET_FIELDS()}) { 276 $overrideArgs{$field} = [undef, undef]; 277 } 278 } 279 280 print CGI::h2({}, "Set Data"), "\n"; 281 print CGI::start_form({method=>"post", action=>$r->uri}), "\n"; 282 print CGI::table({}, 283 CGI::Tr({}, [ 284 setRowHTML("Open Date:", "open_date", formatDateTime($setRecord->open_date), undef, @{$overrideArgs{open_date}})."\n", 285 setRowHTML("Due Date:", "due_date", formatDateTime($setRecord->due_date), undef, @{$overrideArgs{due_date}})."\n", 286 setRowHTML("Answer Date:", "answer_date", formatDateTime($setRecord->answer_date), undef, @{$overrideArgs{answer_date}})."\n", 287 setRowHTML("Set Header:", "set_header", $setRecord->set_header, undef, @{$overrideArgs{set_header}})."\n", 288 setRowHTML("Problem Header:", "problem_header", $setRecord->problem_header, undef, @{$overrideArgs{problem_header}})."\n" 289 ]) 290 ); 291 292 print hiddenEditForUserFields(@editForUser); 293 print $self->hidden_authen_fields; 294 print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"}); 295 print CGI::end_form(); 296 297 ## Problems Form ## 298 my @problemList = $db->listGlobalProblems($setName); 299 print CGI::a({name=>"problems"}); 300 print CGI::h2({}, "Problems"); 301 if (scalar(@problemList)) { 302 print CGI::start_form({method=>"POST", action=>$r->uri.'#problems'}); 303 print CGI::start_table({border=>1, cellpadding=>4}); 304 print CGI::Tr({}, CGI::th({}, [ 305 ($forUsers ? () : ("Delete?")), 306 "Problem", 307 ($forUsers ? ("Status", "Problem Seed") : ()), 308 "Source File", "Max. Attempts", "Weight", 309 ($forUsers ? ("Number Correct", "Number Incorrect") : ()) 310 ])); 311 foreach my $problem (sort {$a <=> $b} @problemList) { 312 my $problemRecord = $db->getGlobalProblem($setName, $problem); 313 my $problemID = $problemRecord->problem_id; 314 my $userProblemRecord; 315 my %problemOverrideArgs; 316 317 if ($forOneUser) { 318 $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem); 319 foreach my $field (@{PROBLEM_FIELDS()}) { 320 $problemOverrideArgs{$field} = [defined $userProblemRecord->$field, $userProblemRecord->$field]; 321 } 322 # } elsif ($forUsers) { 323 # foreach my $field (@{PROBLEM_FIELDS()}) { 324 # $problemOverrideArgs{$field} = ["", ""]; 325 # } 326 } else { 327 foreach my $field (@{PROBLEM_FIELDS()}) { 328 $problemOverrideArgs{$field} = [undef, undef]; 329 } 330 } 331 332 print CGI::Tr({}, 333 CGI::td({}, [ 334 ($forUsers ? () : (CGI::input({type=>"checkbox", name=>"deleteProblem", value=>$problemID}))), 335 CGI::a({href=>$ce->{webworkURLs}->{root}."/$courseName/instructor/pgProblemEditor/".$setName.'/'.$problemID.'?'.$self->url_authen_args}, $problemID), 336 ($forUsers ? ( 337 problemElementHTML("problem_${problemID}_status", $userProblemRecord->status, "7"), 338 problemElementHTML("problem_${problemID}_problem_seed", $userProblemRecord->problem_seed, "7"), 339 ) : ()), 340 problemElementHTML("problem_${problemID}_source_file", $problemRecord->source_file, "40", @{$problemOverrideArgs{source_file}}), 341 problemElementHTML("problem_${problemID}_max_attempts",$problemRecord->max_attempts,"7", @{$problemOverrideArgs{max_attempts}}), 342 problemElementHTML("problem_${problemID}_value",$problemRecord->value,"7", @{$problemOverrideArgs{value}}), 343 ($forUsers ? ( 344 problemElementHTML("problem_${problemID}_num_correct", $userProblemRecord->num_correct, "7"), 345 problemElementHTML("problem_${problemID}_num_incorrect", $userProblemRecord->num_incorrect, "7") 346 ) : ()) 347 ]) 348 349 ) 350 } 351 print CGI::end_table(); 352 print hiddenEditForUserFields(@editForUser); 353 print $self->hidden_authen_fields; 354 print CGI::input({type=>"submit", name=>"submit_problem_changes", value=>"Save Problem Changes"}); 355 print CGI::end_form(); 356 } else { 357 print CGI::p("This set doesn't contain any problems yet."); 358 } 359 360 unless ($forUsers) { 361 my $libraryRoot = $ce->{courseDirs}->{templates}; 362 my @path = defined $self->{path} ? @{$self->{path}} : (); 363 unshift @path, $libraryRoot; 364 print CGI::a({name=>"addProblem"}); 365 print CGI::h3({}, "Add Problem(s)"); 366 print CGI::start_form({method=>"post", action=>$r->uri.'#addProblem'}); 367 print CGI::input({type=>"hidden", name=>"fileBrowsing", value=>"Yes"}); 368 print CGI::start_table(); 369 my $columns = ""; 370 for (my $counter = 0; $counter < scalar(@path); $counter++) { 371 $columns .= CGI::td(directoryListHTML ($counter, (exists $path[$counter+1] ? $path[$counter+1] : []), @path)); 372 } 373 print CGI::Tr($columns); 374 print CGI::end_table(); 375 print $self->hidden_authen_fields; 376 print CGI::end_form(); 377 } 378 return ""; 379 } 380 381 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |