Parent Directory
|
Revision Log
Provide mechanism for adding extra problem library buttons to the Library Browser. These changes allow you to specify (via course.conf or global.conf) that certain subdirectories of the templates directory are to have separate buttons in the top panel of the Set Maker. These buttons only appear if the directories actually exist, and any other directories are listed in the "Local Problems" button as usual. If the list of these directories is empty (the default), then the results are just like they currently are, but it allows one more level of separation of the hierarchy for those who want it. The idea is to make symbolic links to the problem libraries from Rochester, ASU, etc., and have separate buttons for these. This avoids having one monster menu with all the problems in it. (Of course, you could make buttons for any directories you want.) There are instructions in global.conf.dist that exmplain how to do configure this.
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.20 2004/06/09 02:51:57 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 me 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 me 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->problem_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 for ($j=0; $j<scalar(@all_set_defs); $j++) { 769 $all_set_defs[$j] =~ s|^set||; 770 $all_set_defs[$j] =~ s|\.def||; 771 } 772 773 if ($use_previous_problems) { 774 @pg_files = @all_past_list; 775 } else { 776 $first_shown = 0; 777 $last_shown = scalar(@pg_files)<$maxShown ? scalar(@pg_files) : $maxShown; 778 $last_shown--; # to make it an array index 779 @past_marks = (); 780 } 781 ############# Now store data in self for retreival by body 782 $self->{first_shown} = $first_shown; 783 $self->{last_shown} = $last_shown; 784 $self->{browse_which} = $browse_which; 785 $self->{problem_seed} = $problem_seed; 786 $self->{pg_files} = \@pg_files; 787 $self->{past_marks} = \@past_marks; 788 $self->{all_set_defs} = \@all_set_defs; 789 790 } 791 792 793 sub title { 794 return "Problem Set Maker"; 795 } 796 797 sub body { 798 my ($self) = @_; 799 800 my $r = $self->r; 801 my $ce = $r->ce; # course environment 802 my $db = $r->db; # database 803 my $j; # garden variety counter 804 805 my $userName = $r->param('user'); 806 807 my $user = $db->getUser($userName); # checked 808 die "record for user $userName (real user) does not exist." 809 unless defined $user; 810 811 ### Check that this is a professor 812 my $authz = $r->authz; 813 unless ($authz->hasPermissions($userName, "modify_problem_sets")) { 814 print "User $userName returned " . 815 $authz->hasPermissions($user, "modify_problem_sets") . 816 " for permission"; 817 return(CGI::div({class=>'ResultsWithError'}, 818 CGI::em("You are not authorized to access the Instructor tools."))); 819 } 820 821 ########## Extract information computed in pre_header_initialize 822 823 my $first_shown = $self->{first_shown}; 824 my $last_shown = $self->{last_shown}; 825 my $browse_which = $self->{browse_which}; 826 my $problem_seed = $self->{problem_seed}; 827 my @pg_files = @{$self->{pg_files}}; 828 my @all_set_defs = @{$self->{all_set_defs}}; 829 830 my @pg_html=($last_shown>=$first_shown) ? 831 renderProblems(r=> $r, 832 user => $user, 833 problem_list => [@pg_files[$first_shown..$last_shown]], 834 displayMode => $r->param('mydisplayMode')) : (); 835 836 ########## Top part 837 print CGI::startform({-method=>"POST", -action=>$r->uri, -name=>'mainform'}), 838 $self->hidden_authen_fields, 839 '<div align="center">', 840 CGI::start_table({-border=>2}); 841 $self->make_top_row('all_set_defs'=>\@all_set_defs, 842 'browse_which'=> $browse_which); 843 print CGI::hidden(-name=>'browse_which', -default=>[$browse_which]), 844 CGI::hidden(-name=>'problem_seed', -default=>[$problem_seed]); 845 for ($j = 0 ; $j < scalar(@pg_files) ; $j++) { 846 print CGI::hidden(-name=>"all_past_list$j", -default=>$pg_files[$j]); 847 } 848 849 print CGI::hidden(-name=>'first_shown', -default=>[$first_shown]); 850 print CGI::hidden(-name=>'last_shown', -default=>[$last_shown]); 851 852 853 ########## Now print problems 854 my $jj; 855 for ($jj=0; $jj<scalar(@pg_html); $jj++) { 856 $pg_files[$jj] =~ s|^$ce->{courseDirs}->{templates}/?||; 857 $self->make_data_row($pg_files[$jj+$first_shown], $pg_html[$jj], $jj+1, $self->{past_marks}->[$jj]); 858 } 859 860 ########## Finish things off 861 print CGI::end_table(); 862 print '</div>'; 863 # if($first_shown>0 or (1+$last_shown)<scalar(@pg_files)) { 864 my ($next_button, $prev_button) = ("", ""); 865 if ($first_shown > 0) { 866 $prev_button = CGI::submit(-name=>"prev_page", -style=>"width:15ex", 867 -value=>"Previous page"); 868 } 869 if ((1+$last_shown)<scalar(@pg_files)) { 870 $next_button = CGI::submit(-name=>"next_page", -style=>"width:15ex", 871 -value=>"Next page"); 872 } 873 if (scalar(@pg_files)>0) { 874 print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files). 875 " shown.", $prev_button, " ", $next_button); 876 } 877 # } 878 print CGI::endform(), "\n"; 879 880 return ""; 881 } 882 883 ############################################## End of Body 884 885 # SKEL: To emit your own HTTP header, uncomment this: 886 # 887 #sub header { 888 # my ($self) = @_; 889 # 890 # # Generate your HTTP header here. 891 # 892 # # If you return something, it will be used as the HTTP status code for this 893 # # request. The Apache::Constants module might be useful for gerating status 894 # # codes. If you don't return anything, the status code "OK" will be used. 895 # return ""; 896 #} 897 898 # SKEL: If you need to do any processing after the HTTP header is sent, but before 899 # any template processing occurs, or you need to calculate values that will be 900 # used in multiple methods, do it in this method: 901 # 902 #sub initialize { 903 #my ($self) = @_; 904 #} 905 906 # SKEL: If you need to add tags to the document <HEAD>, uncomment this method: 907 # 908 #sub head { 909 # my ($self) = @_; 910 # 911 # # You can print head tags here, like <META>, <SCRIPT>, etc. 912 # 913 # return ""; 914 #} 915 916 # SKEL: To fill in the "info" box (to the right of the main body), use this 917 # method: 918 # 919 #sub info { 920 # my ($self) = @_; 921 # 922 # # Print HTML here. 923 # 924 # return ""; 925 #} 926 927 # SKEL: To provide navigation links, use this method: 928 # 929 #sub nav { 930 # my ($self, $args) = @_; 931 # 932 # # See the documentation of path() and pathMacro() in 933 # # WeBWorK::ContentGenerator for more information. 934 # 935 # return ""; 936 #} 937 938 # SKEL: For a little box for display options, etc., use this method: 939 # 940 #sub options { 941 # my ($self) = @_; 942 # 943 # # Print HTML here. 944 # 945 # return ""; 946 #} 947 948 # SKEL: For a list of sibling objects, use this method: 949 # 950 #sub siblings { 951 # my ($self, $args) = @_; 952 # 953 # # See the documentation of siblings() and siblingsMacro() in 954 # # WeBWorK::ContentGenerator for more information. 955 # # 956 # # Refer to implementations in ProblemSet and Problem. 957 # 958 # return ""; 959 #} 960 961 =head1 AUTHOR 962 963 Written by John Jones, jj (at) asu.edu. 964 965 =cut 966 967 968 969 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |