Parent Directory
|
Revision Log
Sort lists of set definition files alphabetically.
1 ################################################################################ 2 # WeBWorK Online Homework Delivery System 3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 4 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v 1.23 2004/08/04 17:31:22 jj Exp $ 5 # 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 18 package WeBWorK::ContentGenerator::Instructor::SetMaker; 19 use base qw(WeBWorK::ContentGenerator::Instructor); 20 21 =head1 NAME 22 23 WeBWorK::ContentGenerator::Instructor::SetMaker - Make problem sets. 24 25 =cut 26 27 use strict; 28 use warnings; 29 30 use CGI::Pretty qw(); 31 use WeBWorK::Form; 32 use WeBWorK::Utils qw(readDirectory max); 33 use WeBWorK::Utils::Tasks qw(renderProblems); 34 35 require WeBWorK::Utils::ListingDB; 36 37 use constant MAX_SHOW_DEFAULT => 20; 38 use constant NO_LOCAL_SET_STRING => 'There are no local sets yet'; 39 use constant SELECT_SET_STRING => 'Select a Set for This Course'; 40 use constant SELECT_LOCAL_STRING => 'Select a Problem Collection'; 41 use constant MY_PROBLEMS => ' My Problems '; 42 use constant MAIN_PROBLEMS => ' Main Problems '; 43 44 ## Flags for operations on files 45 46 use constant ADDED => 1; 47 use constant HIDDEN => (1 << 1); 48 use constant SUCCESS => (1 << 2); 49 50 ## for additional problib buttons 51 my %problib; ## filled in in global.conf 52 my %ignoredir = ('.' => 1, '..' => 1, 'Library' => 1); 53 54 ## This is for searching the disk for directories containing pg files. 55 ## to make the recursion work, this returns an array where the first 56 ## item is 1 or 0 depending on whether or not the current 57 ## directory has any pg files. The second is a list of directories 58 ## which contain pg files. 59 sub get_library_sets { 60 my $amtop = shift; 61 my $topdir = shift; 62 my @lis = readDirectory($topdir); 63 my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg/) and -f "$topdir/$_"} @lis; 64 my $havepg = scalar(@pgs)>0 ? 1 : 0; 65 my @mdirs = grep {!defined($ignoredir{$_}) and -d "$topdir/$_"} @lis; 66 if ($amtop) {@mdirs = grep {!defined($problib{$_})} @mdirs} 67 my ($adir, @results, @thisresult); 68 for $adir (@mdirs) { 69 @results = get_library_sets(0, "$topdir/$adir"); 70 my $isadirok = shift @results; 71 @thisresult = (@thisresult, @results); 72 if ($isadirok) { 73 @thisresult = ("$topdir/$adir", @thisresult); 74 } 75 } 76 return(($havepg, @thisresult)); 77 } 78 79 ## List all the pg files in the requested directory 80 sub list_pg_files { 81 my $templatedir = shift; 82 my $topdir = shift; 83 84 my @lis = readDirectory("$templatedir/$topdir"); 85 my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg/) and -f "$templatedir/$topdir/$_"} @lis; 86 @pgs = map { "$topdir/$_" } @pgs; 87 return(@pgs); 88 } 89 90 ## go through past page getting a list of identifiers for the problems 91 ## and whether or not they are selected, and whether or not they should 92 ## be hidden 93 94 sub get_past_problem_files { 95 my $r = shift; 96 my @found=(); 97 my $count =1; 98 while (defined($r->param("filetrial$count"))) { 99 my $val = 0; 100 $val |= ADDED if($r->param("trial$count")); 101 $val |= HIDDEN if($r->param("hideme$count")); 102 push @found, [$r->param("filetrial$count"), $val]; 103 $count++; 104 } 105 return(\@found); 106 } 107 108 #### For adding new problems 109 110 sub add_selected { 111 my $self = shift; 112 my $db = shift; 113 my $setName = shift; 114 my @past_problems = @{$self->{past_problems}}; 115 my @selected = @past_problems; 116 my (@path, $file, $selected, $freeProblemID); 117 $freeProblemID = max($db->listGlobalProblems($setName)) + 1; 118 my $addedcount=0; 119 120 for $selected (@selected) { 121 if($selected->[1] & ADDED) { 122 $file = $selected->[0]; 123 my $problemRecord = $self->addProblemToSet(setName => $setName, 124 sourceFile => $file, problemID => $freeProblemID); 125 $freeProblemID++; 126 $self->assignProblemToAllSetUsers($problemRecord); 127 $selected->[1] |= SUCCESS; 128 $addedcount++; 129 } 130 } 131 return($addedcount); 132 } 133 134 135 ############# List of sets of problems in templates directory 136 137 sub get_problem_directories { 138 my $ce = shift; 139 my $lib = shift; 140 my $source = $ce->{courseDirs}{templates}; 141 my $main = MY_PROBLEMS; my $isTop = 1; 142 if ($lib) {$source .= "/$lib"; $main = MAIN_PROBLEMS; $isTop = 0} 143 my @all_problem_directories = get_library_sets($isTop, $source); 144 my $includetop = shift @all_problem_directories; 145 my $j; 146 for ($j=0; $j<scalar(@all_problem_directories); $j++) { 147 $all_problem_directories[$j] =~ s|^$ce->{courseDirs}->{templates}/?||; 148 } 149 @all_problem_directories = sort @all_problem_directories; 150 unshift @all_problem_directories, $main if($includetop); 151 return (\@all_problem_directories); 152 } 153 154 ############# Everyone has a view problems line. Abstract it 155 sub view_problems_line { 156 my $internal_name = shift; 157 my $label = shift; 158 my $r = shift; # so we can get parameter values 159 my $result = CGI::submit(-name=>"$internal_name", -value=>$label); 160 161 my %display_modes = %{WeBWorK::PG::DISPLAY_MODES()}; 162 my @active_modes = grep { exists $display_modes{$_} } 163 @{$r->ce->{pg}->{displayModes}}; 164 push @active_modes, 'None'; 165 # We have our own displayMode since its value may be None, which is illegal 166 # in other modules. 167 my $mydisplayMode = $r->param('mydisplayMode') || $r->ce->{pg}->{options}->{displayMode}; 168 $result .= ' Display Mode: '.CGI::popup_menu(-name=> 'mydisplayMode', 169 -values=>\@active_modes, 170 -default=> $mydisplayMode); 171 # Now we give a choice of the number of problems to show 172 my $defaultMax = $r->param('max_shown') || MAX_SHOW_DEFAULT; 173 $result .= ' Max. Shown: '. 174 CGI::popup_menu(-name=> 'max_shown', 175 -values=>[5,10,15,20,25,30,50,'All'], 176 -default=> $defaultMax); 177 178 return($result); 179 } 180 181 182 ### The browsing panel has three versions 183 ##### Version 1 is local problems 184 sub browse_local_panel { 185 my $self = shift; 186 my $library_selected = shift; 187 my $lib = shift || ''; $lib =~ s/^browse_//; 188 my $name = ($lib eq '')? 'Local' : $problib{$lib}; 189 190 my $list_of_prob_dirs= get_problem_directories($self->r->ce,$lib); 191 if(scalar(@$list_of_prob_dirs) == 0) { 192 $library_selected = "Found no directories containing problems"; 193 unshift @{$list_of_prob_dirs}, $library_selected; 194 } else { 195 my $default_value = SELECT_LOCAL_STRING; 196 if (not $library_selected or $library_selected eq $default_value) { 197 unshift @{$list_of_prob_dirs}, $default_value; 198 $library_selected = $default_value; 199 } 200 } 201 my $view_problem_line = view_problems_line('view_local_set', 'View Problems', $self->r); 202 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "$name Problems: ", 203 CGI::popup_menu(-name=> 'library_sets', 204 -values=>$list_of_prob_dirs, 205 -default=> $library_selected), 206 CGI::br(), 207 $view_problem_line, 208 )); 209 } 210 211 ##### Version 2 is local problem sets 212 sub browse_mysets_panel { 213 my $self = shift; 214 my $library_selected = shift; 215 my $list_of_local_sets = shift; 216 my $default_value = "Select a Problem Set"; 217 218 if(scalar(@$list_of_local_sets) == 0) { 219 $list_of_local_sets = [NO_LOCAL_SET_STRING]; 220 } elsif (not $library_selected or $library_selected eq $default_value) { 221 unshift @{$list_of_local_sets}, $default_value; 222 $library_selected = $default_value; 223 } 224 225 my $view_problem_line = view_problems_line('view_mysets_set', 'View Problems', $self->r); 226 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ", 227 CGI::popup_menu(-name=> 'library_sets', 228 -values=>$list_of_local_sets, 229 -default=> $library_selected), 230 CGI::br(), 231 $view_problem_line 232 )); 233 } 234 235 ##### Version 3 is the problem library 236 237 238 # There a different levels, and you can pick a new chapter, 239 # pick a new section, pick all from chapter, pick all from section 240 # 241 # Incoming data - current chapter, current section 242 sub browse_library_panel { 243 my $self = shift; 244 my $r = $self->r; 245 my $ce = $r->ce; 246 247 my $libraryRoot = $r->{ce}->{problemLibrary}->{root}; 248 249 unless($libraryRoot) { 250 print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, 251 "The problem library has not been installed."))); 252 return; 253 } 254 # Test if the Library directory exists. If not, try to make it 255 unless(-d "$ce->{courseDirs}->{templates}/Library") { 256 unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) { 257 my $msg = <<"HERE"; 258 You are missing the directory <code>templates/Library</code>, which is needed 259 for the Problem Library to function. It should be a link pointing to 260 <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>. 261 I tried to make the link for you, but that failed. Check the permissions 262 in your <code>templates</code> directory. 263 HERE 264 $self->addbadmessage($msg); 265 } 266 } 267 268 my $default_chap = "All Chapters"; 269 my $default_sect = "All Sections"; 270 271 my @chaps = WeBWorK::Utils::ListingDB::getAllChapters($r->{ce}); 272 unshift @chaps, $default_chap; 273 my $chapter_selected = $r->param('library_chapters') || $default_chap; 274 275 my @sects=(); 276 if ($chapter_selected ne $default_chap) { 277 @sects = WeBWorK::Utils::ListingDB::getAllSections($r->{ce}, $chapter_selected); 278 } 279 280 my @textbooks = ('Textbook info not ready'); 281 282 unshift @sects, $default_sect; 283 my $section_selected = $r->param('library_sections') || $default_sect; 284 my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r); 285 286 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, 287 CGI::start_table(), 288 CGI::Tr( 289 CGI::td(["Chapter:", 290 CGI::popup_menu(-name=> 'library_chapters', 291 -values=>\@chaps, 292 -default=> $chapter_selected, 293 -onchange=>"submit();return true" 294 ), 295 CGI::submit(-name=>"lib_select_chapter", -value=>"Update Section List")])), 296 CGI::Tr( 297 CGI::td("Section:"), 298 CGI::td({-colspan=>2}, 299 CGI::popup_menu(-name=> 'library_sections', 300 -values=>\@sects, 301 -default=> $section_selected 302 ))), 303 304 # CGI::Tr( 305 # CGI::td("Textbook:"), 306 # CGI::td({-colspan=>2}, 307 # CGI::popup_menu(-name=> 'library_textbooks', 308 # -values=>\@textbooks, 309 # # -default=> $section_selected 310 # ))), 311 312 # CGI::Tr( 313 # CGI::td("Keywords:"), 314 # CGI::td({-colspan=>2}, CGI::textfield(-name=>"keywords", 315 # -default=>"Keywords not implemented yet", 316 # -override=>1, -size=>60))), 317 CGI::Tr(CGI::td({-colspan=>3}, 318 $view_problem_line)), 319 CGI::end_table(), 320 )); 321 } 322 323 sub make_top_row { 324 my $self = shift; 325 my $r = $self->r; 326 my $ce = $r->ce; 327 my %data = @_; 328 329 my $list_of_local_sets = $data{all_set_defs}; 330 my $have_local_sets = scalar(@$list_of_local_sets); 331 my $browse_which = $data{browse_which}; 332 my $library_selected = $r->param('library_sets'); 333 my $set_selected = $r->param('local_sets'); 334 335 my ($dis1, $dis2, $dis3) = ("","",""); 336 $dis1 = '-disabled' if($browse_which eq 'browse_library'); 337 $dis2 = '-disabled' if($browse_which eq 'browse_local'); 338 $dis3 = '-disabled' if($browse_which eq 'browse_mysets'); 339 340 ## Make buttons for additional problem libraries 341 my $libs = ''; 342 foreach my $lib (sort(keys(%problib))) { 343 $libs .= ' '. CGI::submit(-name=>"browse_$lib", -value=>$problib{$lib}, 344 ($browse_which eq "browse_$lib")? '-disabled': '') 345 if (-d "$ce->{courseDirs}{templates}/$lib"); 346 } 347 $libs = CGI::br()."or Problems from".$libs if $libs ne ''; 348 349 my $these_widths = "width: 20ex"; 350 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, 351 "Browse ", 352 CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, $dis1), 353 CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, $dis2), 354 CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, $dis3), 355 $libs, 356 )); 357 358 print CGI::Tr(CGI::td({-bgcolor=>"black"})); 359 360 if ($browse_which eq 'browse_local') { 361 $self->browse_local_panel($library_selected); 362 } elsif ($browse_which eq 'browse_mysets') { 363 $self->browse_mysets_panel($library_selected, $list_of_local_sets); 364 } elsif ($browse_which eq 'browse_library') { 365 $self->browse_library_panel(); 366 } else { ## handle other problem libraries 367 $self->browse_local_panel($library_selected,$browse_which); 368 } 369 370 print CGI::Tr(CGI::td({-bgcolor=>"black"})); 371 372 if($have_local_sets ==0) { 373 $list_of_local_sets = [NO_LOCAL_SET_STRING]; 374 } elsif (not $set_selected or $set_selected eq SELECT_SET_STRING) { 375 if ($list_of_local_sets->[0] eq "Select a Problem Set") { 376 shift @{$list_of_local_sets}; 377 } 378 unshift @{$list_of_local_sets}, SELECT_SET_STRING; 379 $set_selected = SELECT_SET_STRING; 380 } 381 my $myjs = 'document.mainform.selfassign.value=confirm("Should I assign the new set to you now?\nUse OK for yes and Cancel for no.");true;'; 382 383 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Adding Problems to ", 384 CGI::b("Target Set: "), 385 CGI::popup_menu(-name=> 'local_sets', 386 -values=>$list_of_local_sets, 387 -default=> $set_selected), 388 CGI::submit(-name=>"edit_local", -value=>"Edit Target Set"), 389 CGI::hidden(-name=>"selfassign", -default=>[0]). 390 CGI::br(), 391 CGI::br(), 392 CGI::submit(-name=>"new_local_set", -value=>"Create a New Set in This Course:", 393 -onclick=>$myjs 394 ), 395 " ", 396 CGI::textfield(-name=>"new_set_name", 397 -default=>"Name for new set here", 398 -override=>1, -size=>30), 399 CGI::br(), 400 )); 401 402 print CGI::Tr(CGI::td({-bgcolor=>"black"})); 403 404 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, 405 CGI::start_table({-border=>"0"}), 406 CGI::Tr( CGI::td({ -align=>"center"}, 407 CGI::submit(-name=>"select_all", -style=>$these_widths, 408 -value=>"Mark All For Adding"), 409 CGI::submit(-name=>"select_none", -style=>$these_widths, 410 -value=>"Clear All Marks"), 411 )), 412 CGI::Tr( CGI::td( 413 CGI::submit(-name=>"update", -style=>$these_widths. "; font-weight:bold", 414 -value=>"Update"), 415 CGI::submit(-name=>"rerandomize", 416 -style=>$these_widths, 417 -value=>"Rerandomize"), 418 CGI::submit(-name=>"cleardisplay", 419 -style=>$these_widths, 420 -value=>"Clear Problem Display") 421 )), 422 CGI::end_table())); 423 424 } 425 426 sub make_data_row { 427 my $self = shift; 428 my $sourceFileName = shift; 429 my $pg = shift; 430 my $cnt = shift; 431 my $mark = shift || 0; 432 433 $sourceFileName =~ s|^./||; # clean up top ugliness 434 435 my $urlpath = $self->r->urlpath; 436 my $problem_output = $pg->{flags}->{error_flag} ? 437 CGI::div({class=>"ResultsWithError"}, CGI::em("This problem produced an error")) 438 : CGI::div({class=>"RenderSolo"}, $pg->{body_text}); 439 440 441 my $edit_link = ''; 442 #if($self->{r}->param('browse_which') ne 'browse_library') { 443 if($sourceFileName !~ /^Library\//) { 444 $edit_link = CGI::a({href=>$self->systemLink($urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", 445 courseID =>$urlpath->arg("courseID"), 446 setID=>"Undefined_Set", 447 problemID=>"1"), 448 params=>{sourceFilePath => "$sourceFileName"} 449 )}, "Edit it" ); 450 } 451 452 my $try_link = CGI::a({href=>$self->systemLink($urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", 453 courseID =>$urlpath->arg("courseID"), 454 setID=>"Undefined_Set", 455 problemID=>"1"), 456 params =>{effectiveUser => $self->r->param('user'), 457 editMode => "SetMaker", 458 sourceFilePath => "$sourceFileName"} )}, "Try it"); 459 460 my %add_box_data = ( -name=>"trial$cnt",-value=>1,-label=>"Add this problem to the current set on the next update"); 461 if($mark & SUCCESS) { 462 $add_box_data{ -label } .= " (just added this problem)"; 463 } elsif($mark & ADDED) { 464 $add_box_data{ -checked } = 1; 465 } 466 467 print CGI::Tr({-align=>"left"}, CGI::td( 468 469 CGI::div({-style=>"background-color: #DDDDDD; margin: 0px auto"}, 470 CGI::span({-style=>"float:left ; text-align: left"},"File name: $sourceFileName "), 471 CGI::span({-style=>"float:right ; text-align: right"}, $edit_link, " ", $try_link) 472 ), CGI::br(), 473 474 475 476 477 CGI::checkbox(-name=>"hideme$cnt",-value=>1,-label=>"Don't show this problem on the next update"), 478 CGI::br(), 479 CGI::checkbox((%add_box_data)), 480 CGI::hidden(-name=>"filetrial$cnt", -default=>[$sourceFileName]). 481 CGI::p($problem_output), 482 )); 483 } 484 485 486 sub pre_header_initialize { 487 my ($self) = @_; 488 my $r = $self->r; 489 ## For all cases, lets set some things 490 $self->{error}=0; 491 my $ce = $r->ce; 492 my $db = $r->db; 493 my $maxShown = $r->param('max_shown') || MAX_SHOW_DEFAULT; 494 $maxShown = 10000000 if($maxShown eq 'All'); # let's hope there aren't more 495 496 ## These directories will have individual buttons 497 %problib = %{$ce->{courseFiles}{problibs}} if $ce->{courseFiles}{problibs}; 498 499 my $userName = $r->param('user'); 500 my $user = $db->getUser($userName); # checked 501 die "record for user $userName (real user) does not exist." 502 unless defined $user; 503 my $authz = $r->authz; 504 unless ($authz->hasPermissions($userName, "modify_problem_sets")) { 505 return(""); # Error message already produced in the body 506 } 507 508 ## Now one action we have to deal with here 509 if ($r->param('edit_local')) { 510 my $urlpath = $r->urlpath; 511 my $db = $r->db; 512 my $checkset = $db->getGlobalSet($r->param('local_sets')); 513 if (not defined($checkset)) { 514 $self->{error} = 1; 515 $self->addbadmessage('You need to select a "Target Set" before you can edit it.'); 516 } else { 517 my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetEditor', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID")); 518 my $url = $self->systemLink($page); 519 $self->reply_with_redirect($url); 520 } 521 } 522 523 ## Next, lots of set up so that errors can be reported with message() 524 525 ############# List of problems we have already printed 526 527 $self->{past_problems} = get_past_problem_files($r); 528 # if we don't end up reusing problems, this will be wiped out 529 # if we do redisplay the same problems, we must adjust this accordingly 530 my @past_marks = map {$_->[1]} @{$self->{past_problems}}; 531 my $none_shown = scalar(@{$self->{past_problems}})==0; 532 my @pg_files=(); 533 my $use_previous_problems = 1; 534 my $first_shown = $r->param('first_shown') || 0; 535 my $last_shown = $r->param('last_shown'); 536 if (not defined($last_shown)) { 537 $last_shown = -1; 538 } 539 my @all_past_list = (); # these are include requested, but not shown 540 my $j = 0; 541 while (defined($r->param("all_past_list$j"))) { 542 push @all_past_list, $r->param("all_past_list$j"); 543 $j++; 544 } 545 546 ############# Default of which problem selector to display 547 548 my $browse_which = $r->param('browse_which') || 'browse_local'; 549 550 my $problem_seed = $r->param('problem_seed') || 0; 551 $r->param('problem_seed', $problem_seed); # if it wasn't defined before 552 553 ## check for problem lib buttons 554 my $browse_lib = ''; 555 foreach my $lib (keys %problib) { 556 if ($r->param("browse_$lib")) { 557 $browse_lib = "browse_$lib"; 558 last; 559 } 560 } 561 562 ########### Start the logic through if elsif elsif ... 563 564 ##### Asked to browse certain problems 565 if ($browse_lib ne '') { 566 $browse_which = $browse_lib; 567 $r->param('library_sets', ""); 568 $use_previous_problems = 0; @pg_files = (); ## clear old problems 569 } elsif ($r->param('browse_library')) { 570 $browse_which = 'browse_library'; 571 $r->param('library_sets', ""); 572 $use_previous_problems = 0; @pg_files = (); ## clear old problems 573 } elsif ($r->param('browse_local')) { 574 $browse_which = 'browse_local'; 575 $r->param('library_sets', ""); 576 $use_previous_problems = 0; @pg_files = (); ## clear old problems 577 } elsif ($r->param('browse_mysets')) { 578 $browse_which = 'browse_mysets'; 579 $r->param('library_sets', ""); 580 $use_previous_problems = 0; @pg_files = (); ## clear old problems 581 582 ##### Change the seed value 583 584 } elsif ($r->param('rerandomize')) { 585 $problem_seed++; 586 $r->param('problem_seed', $problem_seed); 587 $self->addbadmessage('Changing the problem seed for display, but there are no problems showing.') if $none_shown; 588 589 ##### Clear the display 590 591 } elsif ($r->param('cleardisplay')) { 592 @pg_files = (); 593 $use_previous_problems=0; 594 $self->addbadmessage('The display was already cleared.') if $none_shown; 595 596 ##### View problems selected from the local list 597 598 } elsif ($r->param('view_local_set')) { 599 600 my $set_to_display = $r->param('library_sets'); 601 if (not defined($set_to_display) or $set_to_display eq SELECT_LOCAL_STRING or $set_to_display eq "Found no directories containing problems") { 602 $self->addbadmessage('You need to select a set to view.'); 603 } else { 604 $set_to_display = '.' if $set_to_display eq MY_PROBLEMS; 605 $set_to_display = substr($browse_which,7) if $set_to_display eq MAIN_PROBLEMS; 606 @pg_files = list_pg_files($ce->{courseDirs}->{templates}, 607 "$set_to_display"); 608 $use_previous_problems=0; 609 } 610 611 ##### View problems selected from the a set in this course 612 613 } elsif ($r->param('view_mysets_set')) { 614 615 my $set_to_display = $r->param('library_sets'); 616 if (not defined($set_to_display) 617 or $set_to_display eq "Select a Problem Set" 618 or $set_to_display eq NO_LOCAL_SET_STRING) { 619 $self->addbadmessage("You need to select a set from this course to view."); 620 } else { 621 my @problemList = $db->listGlobalProblems($set_to_display); 622 my $problem; 623 @pg_files=(); 624 for $problem (@problemList) { 625 my $problemRecord = $db->getGlobalProblem($set_to_display, $problem); # checked 626 die "global $problem for set $set_to_display not found." unless 627 $problemRecord; 628 push @pg_files, $problemRecord->source_file; 629 630 } 631 $use_previous_problems=0; 632 } 633 634 ##### View whole chapter from the library 635 ## This will change somewhat later 636 637 } elsif ($r->param('lib_view')) { 638 639 @pg_files=(); 640 my $chap = $r->param('library_chapters') || ""; 641 $chap = "" if($chap eq "All Chapters"); 642 my $sect = $r->param('library_sections') || ""; 643 $sect = "" if($sect eq "All Sections"); 644 my @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r->{ce}, "$chap", "$sect"); 645 my ($result, $tolibpath); 646 for $result (@dbsearch) { 647 $tolibpath = "Library/$result->{path}/$result->{filename}"; 648 649 ## Too clunky!!!! 650 push @pg_files, $tolibpath; 651 } 652 $use_previous_problems=0; 653 654 ##### Edit the current local problem set 655 656 } elsif ($r->param('edit_local')) { ## Jump to set edit page 657 658 ; # already handled 659 660 661 ##### Make a new local problem set 662 663 } elsif ($r->param('new_local_set')) { 664 if ($r->param('new_set_name') !~ /^[\w.-]*$/) { 665 $self->addbadmessage("The name ".$r->param('new_set_name')." is not a valid set name. Use only letters, digits, -, _, and ."); 666 } else { 667 my $newSetName = $r->param('new_set_name'); 668 $newSetName =~ s/^set//; 669 $newSetName =~ s/\.def$//; 670 $r->param('local_sets',$newSetName); 671 my $newSetRecord = $db->getGlobalSet($newSetName); 672 if (defined($newSetRecord)) { 673 $self->addbadmessage("The set name $newSetName is already in use. Pick a different name if you would like to start a new set."); 674 } else { # Do it! 675 $newSetRecord = $db->{set}->{record}->new(); 676 $newSetRecord->set_id($newSetName); 677 $newSetRecord->set_header(""); 678 $newSetRecord->hardcopy_header(""); 679 $newSetRecord->open_date(time()+60*60*24*7); # in one week 680 $newSetRecord->due_date(time()+60*60*24*7*2); # in two weeks 681 $newSetRecord->answer_date(time()+60*60*24*7*3); # in three weeks 682 eval {$db->addGlobalSet($newSetRecord)}; 683 $self->addgoodmessage("Set $newSetName has been created."); 684 my $selfassign = $r->param('selfassign') || ""; 685 $selfassign = "" if($selfassign =~ /false/i); # deal with javascript false 686 if($selfassign) { 687 $self->assignSetToUser($userName, $newSetRecord); 688 $self->addgoodmessage("Set $newSetName was assigned to $userName."); 689 } 690 } 691 } 692 693 ##### Add selected problems to the current local set 694 695 } elsif ($r->param('update')) { 696 ## first handle problems to be added before we hide them 697 my($localSet, @selected); 698 699 @pg_files = grep {($_->[1] & ADDED) != 0 } @{$self->{past_problems}}; 700 @selected = map {$_->[0]} @pg_files; 701 702 my @action_files = grep {$_->[1] > 0 } @{$self->{past_problems}}; 703 # There are now good reasons to do an update without selecting anything. 704 #if(scalar(@action_files) == 0) { 705 # $self->addbadmessage('Update requested, but no problems were marked.'); 706 #} 707 708 if (scalar(@selected)>0) { # if some are to be added, they need a place to go 709 $localSet = $r->param('local_sets'); 710 if (not defined($localSet) or 711 $localSet eq SELECT_SET_STRING or 712 $localSet eq NO_LOCAL_SET_STRING) { 713 $self->addbadmessage('You are trying to add problems to something, but you did not select a "Target Set" name as a target.'); 714 } else { 715 my $newSetRecord = $db->getGlobalSet($localSet); 716 if (not defined($newSetRecord)) { 717 $self->addbadmessage("You are trying to add problems to $localSet, but that set does not seem to exist! I bet you used your \"Back\" button."); 718 } else { 719 my $addcount = add_selected($self, $db, $localSet); 720 if($addcount > 0) { 721 $self->addgoodmessage("Added $addcount problem".(($addcount>1)?'s':''). 722 " to $localSet."); 723 } 724 } 725 } 726 } 727 ## now handle problems to be hidden 728 729 ## only keep the ones which are not hidden 730 @pg_files = grep {($_->[1] & HIDDEN) ==0 } @{$self->{past_problems}}; 731 @past_marks = map {$_->[1]} @pg_files; 732 @pg_files = map {$_->[0]} @pg_files; 733 @all_past_list = (@all_past_list[0..($first_shown-1)], 734 @pg_files, 735 @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]); 736 $last_shown = $first_shown+$maxShown -1; 737 $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list)); 738 739 } elsif ($r->param('next_page')) { 740 $first_shown = $last_shown+1; 741 $last_shown = $first_shown+$maxShown-1; 742 $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list)); 743 @past_marks = (); 744 } elsif ($r->param('prev_page')) { 745 $last_shown = $first_shown-1; 746 $first_shown = $last_shown - $maxShown+1; 747 748 $first_shown = 0 if($first_shown<0); 749 @past_marks = (); 750 751 } elsif ($r->param('select_all')) { 752 @past_marks = map {1} @past_marks; 753 } elsif ($r->param('select_none')) { 754 @past_marks = (); 755 756 ##### No action requested, probably our first time here 757 758 } else { 759 #my $c = $r->connection; 760 #print "Debug info: ". $r->get_remote_host ."<p>". $c->remote_ip ; 761 ; 762 } ##### end of the if elsif ... 763 764 765 ############# List of local sets 766 767 my @all_set_defs = $db->listGlobalSets; 768 @all_set_defs = sort @all_set_defs; 769 770 if ($use_previous_problems) { 771 @pg_files = @all_past_list; 772 } else { 773 $first_shown = 0; 774 $last_shown = scalar(@pg_files)<$maxShown ? scalar(@pg_files) : $maxShown; 775 $last_shown--; # to make it an array index 776 @past_marks = (); 777 } 778 ############# Now store data in self for retreival by body 779 $self->{first_shown} = $first_shown; 780 $self->{last_shown} = $last_shown; 781 $self->{browse_which} = $browse_which; 782 $self->{problem_seed} = $problem_seed; 783 $self->{pg_files} = \@pg_files; 784 $self->{past_marks} = \@past_marks; 785 $self->{all_set_defs} = \@all_set_defs; 786 787 } 788 789 790 sub title { 791 return "Problem Set Maker"; 792 } 793 794 sub body { 795 my ($self) = @_; 796 797 my $r = $self->r; 798 my $ce = $r->ce; # course environment 799 my $db = $r->db; # database 800 my $j; # garden variety counter 801 802 my $userName = $r->param('user'); 803 804 my $user = $db->getUser($userName); # checked 805 die "record for user $userName (real user) does not exist." 806 unless defined $user; 807 808 ### Check that this is a professor 809 my $authz = $r->authz; 810 unless ($authz->hasPermissions($userName, "modify_problem_sets")) { 811 print "User $userName returned " . 812 $authz->hasPermissions($user, "modify_problem_sets") . 813 " for permission"; 814 return(CGI::div({class=>'ResultsWithError'}, 815 CGI::em("You are not authorized to access the Instructor tools."))); 816 } 817 818 ########## Extract information computed in pre_header_initialize 819 820 my $first_shown = $self->{first_shown}; 821 my $last_shown = $self->{last_shown}; 822 my $browse_which = $self->{browse_which}; 823 my $problem_seed = $self->{problem_seed}; 824 my @pg_files = @{$self->{pg_files}}; 825 my @all_set_defs = @{$self->{all_set_defs}}; 826 827 my @pg_html=($last_shown>=$first_shown) ? 828 renderProblems(r=> $r, 829 user => $user, 830 problem_list => [@pg_files[$first_shown..$last_shown]], 831 displayMode => $r->param('mydisplayMode')) : (); 832 833 ########## Top part 834 print CGI::startform({-method=>"POST", -action=>$r->uri, -name=>'mainform'}), 835 $self->hidden_authen_fields, 836 '<div align="center">', 837 CGI::start_table({-border=>2}); 838 $self->make_top_row('all_set_defs'=>\@all_set_defs, 839 'browse_which'=> $browse_which); 840 print CGI::hidden(-name=>'browse_which', -default=>[$browse_which]), 841 CGI::hidden(-name=>'problem_seed', -default=>[$problem_seed]); 842 for ($j = 0 ; $j < scalar(@pg_files) ; $j++) { 843 print CGI::hidden(-name=>"all_past_list$j", -default=>$pg_files[$j]); 844 } 845 846 print CGI::hidden(-name=>'first_shown', -default=>[$first_shown]); 847 print CGI::hidden(-name=>'last_shown', -default=>[$last_shown]); 848 849 850 ########## Now print problems 851 my $jj; 852 for ($jj=0; $jj<scalar(@pg_html); $jj++) { 853 $pg_files[$jj] =~ s|^$ce->{courseDirs}->{templates}/?||; 854 $self->make_data_row($pg_files[$jj+$first_shown], $pg_html[$jj], $jj+1, $self->{past_marks}->[$jj]); 855 } 856 857 ########## Finish things off 858 print CGI::end_table(); 859 print '</div>'; 860 # if($first_shown>0 or (1+$last_shown)<scalar(@pg_files)) { 861 my ($next_button, $prev_button) = ("", ""); 862 if ($first_shown > 0) { 863 $prev_button = CGI::submit(-name=>"prev_page", -style=>"width:15ex", 864 -value=>"Previous page"); 865 } 866 if ((1+$last_shown)<scalar(@pg_files)) { 867 $next_button = CGI::submit(-name=>"next_page", -style=>"width:15ex", 868 -value=>"Next page"); 869 } 870 if (scalar(@pg_files)>0) { 871 print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files). 872 " shown.", $prev_button, " ", $next_button); 873 } 874 # } 875 print CGI::endform(), "\n"; 876 877 return ""; 878 } 879 880 ############################################## End of Body 881 882 # SKEL: To emit your own HTTP header, uncomment this: 883 # 884 #sub header { 885 # my ($self) = @_; 886 # 887 # # Generate your HTTP header here. 888 # 889 # # If you return something, it will be used as the HTTP status code for this 890 # # request. The Apache::Constants module might be useful for gerating status 891 # # codes. If you don't return anything, the status code "OK" will be used. 892 # return ""; 893 #} 894 895 # SKEL: If you need to do any processing after the HTTP header is sent, but before 896 # any template processing occurs, or you need to calculate values that will be 897 # used in multiple methods, do it in this method: 898 # 899 #sub initialize { 900 #my ($self) = @_; 901 #} 902 903 # SKEL: If you need to add tags to the document <HEAD>, uncomment this method: 904 # 905 #sub head { 906 # my ($self) = @_; 907 # 908 # # You can print head tags here, like <META>, <SCRIPT>, etc. 909 # 910 # return ""; 911 #} 912 913 # SKEL: To fill in the "info" box (to the right of the main body), use this 914 # method: 915 # 916 #sub info { 917 # my ($self) = @_; 918 # 919 # # Print HTML here. 920 # 921 # return ""; 922 #} 923 924 # SKEL: To provide navigation links, use this method: 925 # 926 #sub nav { 927 # my ($self, $args) = @_; 928 # 929 # # See the documentation of path() and pathMacro() in 930 # # WeBWorK::ContentGenerator for more information. 931 # 932 # return ""; 933 #} 934 935 # SKEL: For a little box for display options, etc., use this method: 936 # 937 #sub options { 938 # my ($self) = @_; 939 # 940 # # Print HTML here. 941 # 942 # return ""; 943 #} 944 945 # SKEL: For a list of sibling objects, use this method: 946 # 947 #sub siblings { 948 # my ($self, $args) = @_; 949 # 950 # # See the documentation of siblings() and siblingsMacro() in 951 # # WeBWorK::ContentGenerator for more information. 952 # # 953 # # Refer to implementations in ProblemSet and Problem. 954 # 955 # return ""; 956 #} 957 958 =head1 AUTHOR 959 960 Written by John Jones, jj (at) asu.edu. 961 962 =cut 963 964 965 966 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |