Parent Directory
|
Revision Log
Allow use of an activity log which logs every click, stored on a
per-course basis. It is turned off by default. It can be turned
on/off for individual courses. The three pieces here:
global.conf.dist: adds a place to define the log file. Here an
empty value signals to not do this logging.
ContentGenerator.pm: check to see if the log file is defined (and
(non-trivial), and if so, write a log entry. We check if it is
defined at this point to both save some time, and because if we
get to writeCourseLog and the log isn't defined, we get a pink
screen.
The bulk of the text of the log entry is performed by a new method
prepare_activity_entry. By default, this gives the url, and a list
of all the cgi parameters (except for key and passwd). This method
can be overridden by individual modules. The default format may
change. It may take some fine tuning to see what is best.
Also, this is one of the first functions called by go. We may want
it to go after the action has taken place if we want instructor
modules to be able to report results of their work through this log.
SetMaker.pm: gives an example of overriding prepare_activity_entry.
SetMaker has lots (and lots and lots) of data stored in cgi
parameters. We probably don't want to log that. We might want to
log a little more in SetMaker than we do here (target set), but
this gives a start.
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.53 2005/08/22 02:40:26 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::Debug; 32 use WeBWorK::Form; 33 use WeBWorK::Utils qw(readDirectory max sortByName); 34 use WeBWorK::Utils::Tasks qw(renderProblems); 35 use File::Find; 36 37 require WeBWorK::Utils::ListingDB; 38 39 use constant MAX_SHOW_DEFAULT => 20; 40 use constant NO_LOCAL_SET_STRING => 'No sets in this course yet'; 41 use constant SELECT_SET_STRING => 'Select a Set from this Course'; 42 use constant SELECT_LOCAL_STRING => 'Select a Problem Collection'; 43 use constant MY_PROBLEMS => ' My Problems '; 44 use constant MAIN_PROBLEMS => ' Main Problems '; 45 use constant CREATE_SET_BUTTON => 'Create New Set'; 46 use constant ALL_CHAPTERS => 'All Chapters'; 47 use constant ALL_SUBJECTS => 'All Subjects'; 48 use constant ALL_SECTIONS => 'All Sections'; 49 use constant ALL_TEXTBOOKS => 'All Textbooks'; 50 51 use constant LIB2_DATA => { 52 'dbchapter' => {name => 'library_chapters', all => 'All Chapters'}, 53 'dbsection' => {name => 'library_sections', all =>'All Sections' }, 54 'dbsubject' => {name => 'library_subjects', all => 'All Subjects' }, 55 'textbook' => {name => 'library_textbook', all => 'All Textbooks'}, 56 'textchapter' => {name => 'library_textchapter', all => 'All Chapters'}, 57 'textsection' => {name => 'library_textsection', all => 'All Sections'}, 58 'keywords' => {name => 'library_keywords', all => '' }, 59 }; 60 61 ## Flags for operations on files 62 63 use constant ADDED => 1; 64 use constant HIDDEN => (1 << 1); 65 use constant SUCCESS => (1 << 2); 66 67 ## for additional problib buttons 68 my %problib; ## filled in in global.conf 69 my %ignoredir = ( 70 '.' => 1, '..' => 1, 'Library' => 1, 71 'headers' => 1, 'macros' => 1, 'email' => 1, 72 ); 73 74 sub prepare_activity_entry { 75 my $self=shift; 76 my $r = $self->r; 77 my $user = $self->r->param('user') || 'NO_USER'; 78 return("In SetMaker as user $user"); 79 } 80 81 ## This is for searching the disk for directories containing pg files. 82 ## to make the recursion work, this returns an array where the first 83 ## item is the number of pg files in the directory. The second is a 84 ## list of directories which contain pg files. 85 ## 86 ## If a directory contains only one pg file and at least one other 87 ## file, the directory is considered to be part of the parent 88 ## directory (it is probably in a separate directory only because 89 ## it has auxiliarly files that want to be kept together with the 90 ## pg file). 91 ## 92 ## If a directory has a file named "=library-ignore", it is never 93 ## included in the directory menu. If a directory contains a file 94 ## called "=library-combine-up", then its pg are included with those 95 ## in the parent directory (and the directory does not appear in the 96 ## menu). If it has a file called "=library-no-combine" then it is 97 ## always listed as a separate directory even if it contains only one 98 ## pg file. 99 100 sub get_library_sets { 101 my $top = shift; my $dir = shift; 102 # ignore directories that give us an error 103 my @lis = eval { readDirectory($dir) }; 104 if ($@) { 105 warn $@; 106 return (0); 107 } 108 return (0) if grep /^=library-ignore$/, @lis; 109 110 my @pgdirs; 111 112 my $pgcount = scalar(grep { m/\.pg$/ and (not m/(Header|-text)\.pg$/) and -f "$dir/$_"} @lis); 113 my $others = scalar(grep { (!m/\.pg$/ || m/(Header|-text)\.pg$/) && 114 !m/(\.(tmp|bak)|~)$/ && -f "$dir/$_" } @lis); 115 116 my @dirs = grep {!$ignoredir{$_} and -d "$dir/$_"} @lis; 117 if ($top == 1) {@dirs = grep {!$problib{$_}} @dirs} 118 foreach my $subdir (@dirs) { 119 my @results = get_library_sets(0, "$dir/$subdir"); 120 $pgcount += shift @results; push(@pgdirs,@results); 121 } 122 123 return ($pgcount, @pgdirs) if $top || $pgcount == 0 || grep /^=library-combine-up$/, @lis; 124 return (0,@pgdirs,$dir) if $pgcount > 1 || $others == 0 || grep /^=library-no-combine$/, @lis; 125 return ($pgcount, @pgdirs); 126 } 127 128 sub get_library_pgs { 129 my $top = shift; my $base = shift; my $dir = shift; 130 my @lis = readDirectory("$base/$dir"); 131 return () if grep /^=library-ignore$/, @lis; 132 return () if !$top && grep /^=library-no-combine$/, @lis; 133 134 my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg$/) and -f "$base/$dir/$_"} @lis; 135 my $others = scalar(grep { (!m/\.pg$/ || m/(Header|-text)\.pg$/) && 136 !m/(\.(tmp|bak)|~)$/ && -f "$base/$dir/$_" } @lis); 137 138 my @dirs = grep {!$ignoredir{$_} and -d "$base/$dir/$_"} @lis; 139 if ($top == 1) {@dirs = grep {!$problib{$_}} @dirs} 140 foreach my $subdir (@dirs) {push(@pgs, get_library_pgs(0,"$base/$dir",$subdir))} 141 142 return () unless $top || (scalar(@pgs) == 1 && $others) || grep /^=library-combine-up$/, @lis; 143 return (map {"$dir/$_"} @pgs); 144 } 145 146 sub list_pg_files { 147 my ($templates,$dir) = @_; 148 my $top = ($dir eq '.')? 1 : 2; 149 my @pgs = get_library_pgs($top,$templates,$dir); 150 return sortByName(undef,@pgs); 151 } 152 153 ## Search for set definition files 154 155 sub get_set_defs { 156 my $topdir = shift; 157 my @found_set_defs; 158 # get_set_defs_wanted is a closure over @found_set_defs 159 my $get_set_defs_wanted = sub { 160 my $fn = $_; 161 my $fdir = $File::Find::dir; 162 return() if($fn !~ /^set.*\.def$/); 163 #return() if(not -T $fn); 164 push @found_set_defs, "$fdir/$fn"; 165 }; 166 find({ wanted => $get_set_defs_wanted, follow_fast=>1}, $topdir); 167 map { $_ =~ s|^$topdir/?|| } @found_set_defs; 168 return @found_set_defs; 169 } 170 171 ## Try to make reading of set defs more flexible. Additional strategies 172 ## for fixing a path can be added here. 173 174 sub munge_pg_file_path { 175 my $self = shift; 176 my $pg_path = shift; 177 my $path_to_set_def = shift; 178 my $end_path = $pg_path; 179 # if the path is ok, don't fix it 180 return($pg_path) if(-e $self->r->ce->{courseDirs}{templates}."/$pg_path"); 181 # if we have followed a link into a self contained course to get 182 # to the set.def file, we need to insert the start of the path to 183 # the set.def file 184 $end_path = "$path_to_set_def/$pg_path"; 185 return($end_path) if(-e $self->r->ce->{courseDirs}{templates}."/$end_path"); 186 # if we got this far, this path is bad, but we let it produce 187 # an error so the user knows there is a troublesome path in the 188 # set.def file. 189 return($pg_path); 190 } 191 192 ## Read a set definition file. This could be abstracted since it happens 193 ## elsewhere. Here we don't have to process so much of the file. 194 195 sub read_set_def { 196 my $self = shift; 197 my $r = $self->r; 198 my $filePathOrig = shift; 199 my $filePath = $r->ce->{courseDirs}{templates}."/$filePathOrig"; 200 $filePathOrig =~ s/set.*\.def$//; 201 $filePathOrig =~ s|/$||; 202 $filePathOrig = "." if ($filePathOrig !~ /\S/); 203 my @pg_files = (); 204 my ($line, $got_to_pgs, $name, @rest) = ("", 0, ""); 205 if ( open (SETFILENAME, "$filePath") ) { 206 while($line = <SETFILENAME>) { 207 chomp($line); 208 $line =~ s|(#.*)||; # don't read past comments 209 if($got_to_pgs) { 210 unless ($line =~ /\S/) {next;} # skip blank lines 211 ($name,@rest) = split (/\s*,\s*/,$line); 212 $name =~ s/\s*//g; 213 push @pg_files, $name; 214 } else { 215 $got_to_pgs = 1 if ($line =~ /problemList\s*=/); 216 } 217 } 218 } else { 219 $self->addbadmessage("Cannot open $filePath"); 220 } 221 # This is where we would potentially munge the pg file paths 222 # One possibility 223 @pg_files = map { $self->munge_pg_file_path($_, $filePathOrig) } @pg_files; 224 return(@pg_files); 225 } 226 227 ## go through past page getting a list of identifiers for the problems 228 ## and whether or not they are selected, and whether or not they should 229 ## be hidden 230 231 sub get_past_problem_files { 232 my $r = shift; 233 my @found=(); 234 my $count =1; 235 while (defined($r->param("filetrial$count"))) { 236 my $val = 0; 237 $val |= ADDED if($r->param("trial$count")); 238 $val |= HIDDEN if($r->param("hideme$count")); 239 push @found, [$r->param("filetrial$count"), $val]; 240 $count++; 241 } 242 return(\@found); 243 } 244 245 #### For adding new problems 246 247 sub add_selected { 248 my $self = shift; 249 my $db = shift; 250 my $setName = shift; 251 my @past_problems = @{$self->{past_problems}}; 252 my @selected = @past_problems; 253 my (@path, $file, $selected, $freeProblemID); 254 $freeProblemID = max($db->listGlobalProblems($setName)) + 1; 255 my $addedcount=0; 256 257 for $selected (@selected) { 258 if($selected->[1] & ADDED) { 259 $file = $selected->[0]; 260 my $problemRecord = $self->addProblemToSet(setName => $setName, 261 sourceFile => $file, problemID => $freeProblemID); 262 $freeProblemID++; 263 $self->assignProblemToAllSetUsers($problemRecord); 264 $selected->[1] |= SUCCESS; 265 $addedcount++; 266 } 267 } 268 return($addedcount); 269 } 270 271 272 ############# List of sets of problems in templates directory 273 274 sub get_problem_directories { 275 my $ce = shift; 276 my $lib = shift; 277 my $source = $ce->{courseDirs}{templates}; 278 my $main = MY_PROBLEMS; my $isTop = 1; 279 if ($lib) {$source .= "/$lib"; $main = MAIN_PROBLEMS; $isTop = 2} 280 my @all_problem_directories = get_library_sets($isTop, $source); 281 my $includetop = shift @all_problem_directories; 282 my $j; 283 for ($j=0; $j<scalar(@all_problem_directories); $j++) { 284 $all_problem_directories[$j] =~ s|^$ce->{courseDirs}->{templates}/?||; 285 } 286 @all_problem_directories = sortByName(undef, @all_problem_directories); 287 unshift @all_problem_directories, $main if($includetop); 288 return (\@all_problem_directories); 289 } 290 291 ############# Everyone has a view problems line. Abstract it 292 sub view_problems_line { 293 my $internal_name = shift; 294 my $label = shift; 295 my $r = shift; # so we can get parameter values 296 my $result = CGI::submit(-name=>"$internal_name", -value=>$label); 297 298 my %display_modes = %{WeBWorK::PG::DISPLAY_MODES()}; 299 my @active_modes = grep { exists $display_modes{$_} } 300 @{$r->ce->{pg}->{displayModes}}; 301 push @active_modes, 'None'; 302 # We have our own displayMode since its value may be None, which is illegal 303 # in other modules. 304 my $mydisplayMode = $r->param('mydisplayMode') || $r->ce->{pg}->{options}->{displayMode}; 305 $result .= ' Display Mode: '.CGI::popup_menu(-name=> 'mydisplayMode', 306 -values=>\@active_modes, 307 -default=> $mydisplayMode); 308 # Now we give a choice of the number of problems to show 309 my $defaultMax = $r->param('max_shown') || MAX_SHOW_DEFAULT; 310 $result .= ' Max. Shown: '. 311 CGI::popup_menu(-name=> 'max_shown', 312 -values=>[5,10,15,20,25,30,50,'All'], 313 -default=> $defaultMax); 314 315 return($result); 316 } 317 318 319 ### The browsing panel has three versions 320 ##### Version 1 is local problems 321 sub browse_local_panel { 322 my $self = shift; 323 my $library_selected = shift; 324 my $lib = shift || ''; $lib =~ s/^browse_//; 325 my $name = ($lib eq '')? 'Local' : $problib{$lib}; 326 327 my $list_of_prob_dirs= get_problem_directories($self->r->ce,$lib); 328 if(scalar(@$list_of_prob_dirs) == 0) { 329 $library_selected = "Found no directories containing problems"; 330 unshift @{$list_of_prob_dirs}, $library_selected; 331 } else { 332 my $default_value = SELECT_LOCAL_STRING; 333 if (not $library_selected or $library_selected eq $default_value) { 334 unshift @{$list_of_prob_dirs}, $default_value; 335 $library_selected = $default_value; 336 } 337 } 338 my $view_problem_line = view_problems_line('view_local_set', 'View Problems', $self->r); 339 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "$name Problems: ", 340 CGI::popup_menu(-name=> 'library_sets', 341 -values=>$list_of_prob_dirs, 342 -default=> $library_selected), 343 CGI::br(), 344 $view_problem_line, 345 )); 346 } 347 348 ##### Version 2 is local problem sets 349 sub browse_mysets_panel { 350 my $self = shift; 351 my $library_selected = shift; 352 my $list_of_local_sets = shift; 353 my $default_value = "Select a Homework Set"; 354 355 if(scalar(@$list_of_local_sets) == 0) { 356 $list_of_local_sets = [NO_LOCAL_SET_STRING]; 357 } elsif (not $library_selected or $library_selected eq $default_value) { 358 unshift @{$list_of_local_sets}, $default_value; 359 $library_selected = $default_value; 360 } 361 362 my $view_problem_line = view_problems_line('view_mysets_set', 'View Problems', $self->r); 363 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ", 364 CGI::popup_menu(-name=> 'library_sets', 365 -values=>$list_of_local_sets, 366 -default=> $library_selected), 367 CGI::br(), 368 $view_problem_line 369 )); 370 } 371 372 ##### Version 3 is the problem library 373 # 374 # This comes in 3 forms, problem library version 1, and for version 2 there 375 # is the basic, and the advanced interfaces. This function checks what we are 376 # supposed to do, or aborts if the problem library has not been installed. 377 378 sub browse_library_panel { 379 my $self=shift; 380 my $r = $self->r; 381 my $ce = $r->ce; 382 383 # See if the problem library is installed 384 my $libraryRoot = $r->{ce}->{problemLibrary}->{root}; 385 386 unless($libraryRoot) { 387 print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, 388 "The problem library has not been installed."))); 389 return; 390 } 391 # Test if the Library directory link exists. If not, try to make it 392 unless(-d "$ce->{courseDirs}->{templates}/Library") { 393 unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) { 394 my $msg = <<"HERE"; 395 You are missing the directory <code>templates/Library</code>, which is needed 396 for the Problem Library to function. It should be a link pointing to 397 <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>. 398 I tried to make the link for you, but that failed. Check the permissions 399 in your <code>templates</code> directory. 400 HERE 401 $self->addbadmessage($msg); 402 } 403 } 404 405 # Now check what version we are supposed to use 406 my $libraryVersion = $r->{ce}->{problemLibrary}->{version} || 1; 407 if($libraryVersion == 1) { 408 return $self->browse_library_panel1; 409 } elsif($libraryVersion == 2) { 410 return $self->browse_library_panel2 if($self->{library_basic}==1); 411 return $self->browse_library_panel2adv; 412 } else { 413 print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, 414 "The problem library version is set to an illegal value."))); 415 return; 416 } 417 } 418 419 sub browse_library_panel1 { 420 my $self = shift; 421 my $r = $self->r; 422 my $ce = $r->ce; 423 424 my @chaps = WeBWorK::Utils::ListingDB::getAllChapters($r->{ce}); 425 unshift @chaps, LIB2_DATA->{dbchapter}{all}; 426 my $chapter_selected = $r->param('library_chapters') || LIB2_DATA->{dbchapter}->{all}; 427 428 my @sects=(); 429 if ($chapter_selected ne LIB2_DATA->{dbchapter}{all}) { 430 @sects = WeBWorK::Utils::ListingDB::getAllSections($r->{ce}, $chapter_selected); 431 } 432 433 unshift @sects, ALL_SECTIONS; 434 my $section_selected = $r->param('library_sections') || LIB2_DATA->{dbsection}{all}; 435 436 my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r); 437 438 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, 439 CGI::start_table(), 440 CGI::Tr( 441 CGI::td(["Chapter:", 442 CGI::popup_menu(-name=> 'library_chapters', 443 -values=>\@chaps, 444 -default=> $chapter_selected, 445 -onchange=>"submit();return true" 446 ), 447 CGI::submit(-name=>"lib_select_chapter", -value=>"Update Section List")])), 448 CGI::Tr( 449 CGI::td("Section:"), 450 CGI::td({-colspan=>2}, 451 CGI::popup_menu(-name=> 'library_sections', 452 -values=>\@sects, 453 -default=> $section_selected 454 ))), 455 456 CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)), 457 CGI::end_table(), 458 )); 459 } 460 461 sub browse_library_panel2 { 462 my $self = shift; 463 my $r = $self->r; 464 my $ce = $r->ce; 465 466 my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r); 467 unshift @subjs, LIB2_DATA->{dbsubject}{all}; 468 469 my @chaps = WeBWorK::Utils::ListingDB::getAllDBchapters($r); 470 unshift @chaps, LIB2_DATA->{dbchapter}{all}; 471 472 my @sects=(); 473 @sects = WeBWorK::Utils::ListingDB::getAllDBsections($r); 474 unshift @sects, LIB2_DATA->{dbsection}{all}; 475 476 my $subject_selected = $r->param('library_subjects') || LIB2_DATA->{dbsubject}{all}; 477 my $chapter_selected = $r->param('library_chapters') || LIB2_DATA->{dbchapter}{all}; 478 my $section_selected = $r->param('library_sections') || LIB2_DATA->{dbsection}{all}; 479 480 my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r); 481 482 my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); 483 if($count_line==0) { 484 $count_line = "There are no matching pg files"; 485 } else { 486 $count_line = "There are $count_line matching WeBWorK problem files"; 487 } 488 489 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, 490 CGI::hidden(-name=>"library_is_basic", -default=>[1]), 491 CGI::start_table({-width=>"100%"}), 492 CGI::Tr( 493 CGI::td(["Subject:", 494 CGI::popup_menu(-name=> 'library_subjects', 495 -values=>\@subjs, 496 -default=> $subject_selected, 497 -onchange=>"submit();return true" 498 )]), 499 CGI::td({-colspan=>2, -align=>"right"}, 500 CGI::submit(-name=>"lib_select_subject", -value=>"Update Chapter/Section Lists")) 501 ), 502 CGI::Tr( 503 CGI::td(["Chapter:", 504 CGI::popup_menu(-name=> 'library_chapters', 505 -values=>\@chaps, 506 -default=> $chapter_selected, 507 -onchange=>"submit();return true" 508 )]), 509 CGI::td({-colspan=>2, -align=>"right"}, 510 CGI::submit(-name=>"library_advanced", -value=>"Advanced Search")) 511 ), 512 CGI::Tr( 513 CGI::td(["Section:", 514 CGI::popup_menu(-name=> 'library_sections', 515 -values=>\@sects, 516 -default=> $section_selected, 517 -onchange=>"submit();return true" 518 )]), 519 ), 520 CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)), 521 CGI::Tr(CGI::td({-colspan=>3, -align=>"center"}, $count_line)), 522 CGI::end_table(), 523 )); 524 525 } 526 527 sub browse_library_panel2adv { 528 my $self = shift; 529 my $r = $self->r; 530 my $ce = $r->ce; 531 my $right_button_style = "width: 18ex"; 532 533 my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r); 534 if(! grep { $_ eq $r->param('library_subjects') } @subjs) { 535 $r->param('library_subjects', ''); 536 } 537 unshift @subjs, LIB2_DATA->{dbsubject}{all}; 538 539 my @chaps = WeBWorK::Utils::ListingDB::getAllDBchapters($r); 540 if(! grep { $_ eq $r->param('library_chapters') } @chaps) { 541 $r->param('library_chapters', ''); 542 } 543 unshift @chaps, LIB2_DATA->{dbchapter}{all}; 544 545 my @sects = WeBWorK::Utils::ListingDB::getAllDBsections($r); 546 if(! grep { $_ eq $r->param('library_sections') } @sects) { 547 $r->param('library_sections', ''); 548 } 549 unshift @sects, LIB2_DATA->{dbsection}{all}; 550 551 my $texts = WeBWorK::Utils::ListingDB::getDBTextbooks($r); 552 my @textarray = map { $_->[0] } @{$texts}; 553 my %textlabels = (); 554 for my $ta (@{$texts}) { 555 $textlabels{$ta->[0]} = $ta->[1]." by ".$ta->[2]." (edition ".$ta->[3].")"; 556 } 557 if(! grep { $_ eq $r->param('library_textbook') } @textarray) { 558 $r->param('library_textbook', ''); 559 } 560 unshift @textarray, LIB2_DATA->{textbook}{all}; 561 my $atb = LIB2_DATA->{textbook}{all}; $textlabels{$atb} = LIB2_DATA->{textbook}{all}; 562 563 my $textchap_ref = WeBWorK::Utils::ListingDB::getDBTextbooks($r, 'textchapter'); 564 my @textchaps = map { $_->[0] } @{$textchap_ref}; 565 if(! grep { $_ eq $r->param('library_textchapter') } @textchaps) { 566 $r->param('library_textchapter', ''); 567 } 568 unshift @textchaps, LIB2_DATA->{textchapter}{all}; 569 570 my $textsec_ref = WeBWorK::Utils::ListingDB::getDBTextbooks($r, 'textsection'); 571 my @textsecs = map { $_->[0] } @{$textsec_ref}; 572 if(! grep { $_ eq $r->param('library_textsection') } @textsecs) { 573 $r->param('library_textsection', ''); 574 } 575 unshift @textsecs, LIB2_DATA->{textsection}{all}; 576 577 my %selected = (); 578 for my $j (qw( dbsection dbchapter dbsubject textbook textchapter textsection )) { 579 $selected{$j} = $r->param(LIB2_DATA->{$j}{name}) || LIB2_DATA->{$j}{all}; 580 } 581 582 my $text_popup = CGI::popup_menu(-name => 'library_textbook', 583 -values =>\@textarray, 584 -labels => \%textlabels, 585 -default=>$selected{textbook}, 586 -onchange=>"submit();return true"); 587 588 589 my $library_keywords = $r->param('library_keywords') || ''; 590 591 my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r); 592 593 my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); 594 if($count_line==0) { 595 $count_line = "There are no matching pg files"; 596 } else { 597 $count_line = "There are $count_line matching WeBWorK problem files"; 598 } 599 600 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, 601 CGI::hidden(-name=>"library_is_basic", -default=>[2]), 602 CGI::start_table({-width=>"100%"}), 603 # Html done by hand since it is temporary 604 CGI::Tr(CGI::td({-colspan=>4, -align=>"center"}, 'All Selected Constraints Joined by "And"')), 605 CGI::Tr( 606 CGI::td(["Subject:", 607 CGI::popup_menu(-name=> 'library_subjects', 608 -values=>\@subjs, 609 -default=> $selected{dbsubject}, 610 -onchange=>"submit();return true" 611 )]), 612 CGI::td({-colspan=>2, -align=>"right"}, 613 CGI::submit(-name=>"lib_select_subject", -value=>"Update Menus", 614 -style=> $right_button_style))), 615 CGI::Tr( 616 CGI::td(["Chapter:", 617 CGI::popup_menu(-name=> 'library_chapters', 618 -values=>\@chaps, 619 -default=> $selected{dbchapter}, 620 -onchange=>"submit();return true" 621 )]), 622 CGI::td({-colspan=>2, -align=>"right"}, 623 CGI::submit(-name=>"library_reset", -value=>"Reset", 624 -style=>$right_button_style)) 625 ), 626 CGI::Tr( 627 CGI::td(["Section:", 628 CGI::popup_menu(-name=> 'library_sections', 629 -values=>\@sects, 630 -default=> $selected{dbsection}, 631 -onchange=>"submit();return true" 632 )]), 633 CGI::td({-colspan=>2, -align=>"right"}, 634 CGI::submit(-name=>"library_basic", -value=>"Basic Search", 635 -style=>$right_button_style)) 636 ), 637 CGI::Tr( 638 CGI::td(["Textbook:", $text_popup]), 639 ), 640 CGI::Tr( 641 CGI::td(["Text chapter:", 642 CGI::popup_menu(-name=> 'library_textchapter', 643 -values=>\@textchaps, 644 -default=> $selected{textchapter}, 645 -onchange=>"submit();return true" 646 )]), 647 ), 648 CGI::Tr( 649 CGI::td(["Text section:", 650 CGI::popup_menu(-name=> 'library_textsection', 651 -values=>\@textsecs, 652 -default=> $selected{textsection}, 653 -onchange=>"submit();return true" 654 )]), 655 ), 656 CGI::Tr(CGI::td("Keywords:"),CGI::td({-colspan=>2}, 657 CGI::textfield(-name=>"library_keywords", 658 -default=>$library_keywords, 659 -override=>1, 660 -size=>40))), 661 CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)), 662 CGI::Tr(CGI::td({-colspan=>3, -align=>"center"}, $count_line)), 663 CGI::end_table(), 664 )); 665 666 } 667 668 669 ##### Version 4 is the set definition file panel 670 671 sub browse_setdef_panel { 672 my $self = shift; 673 my $r = $self->r; 674 my $ce = $r->ce; 675 my $library_selected = shift; 676 my $default_value = "Select a Set Definition File"; 677 my @list_of_set_defs = get_set_defs($ce->{courseDirs}{templates}); 678 if(scalar(@list_of_set_defs) == 0) { 679 @list_of_set_defs = (NO_LOCAL_SET_STRING); 680 } elsif (not $library_selected or $library_selected eq $default_value) { 681 unshift @list_of_set_defs, $default_value; 682 $library_selected = $default_value; 683 } 684 my $view_problem_line = view_problems_line('view_setdef_set', 'View Problems', $self->r); 685 my $popupetc = CGI::popup_menu(-name=> 'library_sets', 686 -values=>\@list_of_set_defs, 687 -default=> $library_selected). 688 CGI::br(). $view_problem_line; 689 if($list_of_set_defs[0] eq NO_LOCAL_SET_STRING) { 690 $popupetc = "there are no set definition files in this course to look at." 691 } 692 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ", 693 $popupetc 694 )); 695 } 696 697 sub make_top_row { 698 my $self = shift; 699 my $r = $self->r; 700 my $ce = $r->ce; 701 my %data = @_; 702 703 my $list_of_local_sets = $data{all_db_sets}; 704 my $have_local_sets = scalar(@$list_of_local_sets); 705 my $browse_which = $data{browse_which}; 706 my $library_selected = $r->param('library_sets'); 707 my $set_selected = $r->param('local_sets'); 708 709 my ($dis1, $dis2, $dis3, $dis4) = ("","","", ""); 710 $dis1 = '-disabled' if($browse_which eq 'browse_library'); 711 $dis2 = '-disabled' if($browse_which eq 'browse_local'); 712 $dis3 = '-disabled' if($browse_which eq 'browse_mysets'); 713 $dis4 = '-disabled' if($browse_which eq 'browse_setdefs'); 714 715 ## Make buttons for additional problem libraries 716 my $libs = ''; 717 foreach my $lib (sort(keys(%problib))) { 718 $libs .= ' '. CGI::submit(-name=>"browse_$lib", -value=>$problib{$lib}, 719 ($browse_which eq "browse_$lib")? '-disabled': '') 720 if (-d "$ce->{courseDirs}{templates}/$lib"); 721 } 722 $libs = CGI::br()."or Problems from".$libs if $libs ne ''; 723 724 my $these_widths = "width: 23ex"; 725 726 if($have_local_sets ==0) { 727 $list_of_local_sets = [NO_LOCAL_SET_STRING]; 728 } elsif (not $set_selected or $set_selected eq SELECT_SET_STRING) { 729 unshift @{$list_of_local_sets}, SELECT_SET_STRING; 730 $set_selected = SELECT_SET_STRING; 731 } 732 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;'; 733 734 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Add problems to ", 735 CGI::b("Target Set: "), 736 CGI::popup_menu(-name=> 'local_sets', 737 -values=>$list_of_local_sets, 738 -default=> $set_selected), 739 CGI::submit(-name=>"edit_local", -value=>"Edit Target Set"), 740 CGI::hidden(-name=>"selfassign", -default=>[0]). 741 CGI::br(), 742 CGI::br(), 743 CGI::submit(-name=>"new_local_set", -value=>"Create a New Set in This Course:", 744 -onclick=>$myjs 745 ), 746 " ", 747 CGI::textfield(-name=>"new_set_name", 748 -default=>"Name for new set here", 749 -override=>1, -size=>30), 750 )); 751 752 print CGI::Tr(CGI::td({-bgcolor=>"black"})); 753 754 # Tidy this list up since it is used in two different places 755 if ($list_of_local_sets->[0] eq SELECT_SET_STRING) { 756 shift @{$list_of_local_sets}; 757 } 758 759 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, 760 "Browse ", 761 CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, $dis1), 762 CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, $dis2), 763 CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, $dis3), 764 CGI::submit(-name=>"browse_setdefs", -value=>"Set Definition Files", -style=>$these_widths, $dis4), 765 $libs, 766 )); 767 768 #print CGI::Tr(CGI::td({-bgcolor=>"black"})); 769 print CGI::hr(); 770 771 if ($browse_which eq 'browse_local') { 772 $self->browse_local_panel($library_selected); 773 } elsif ($browse_which eq 'browse_mysets') { 774 $self->browse_mysets_panel($library_selected, $list_of_local_sets); 775 } elsif ($browse_which eq 'browse_library') { 776 $self->browse_library_panel(); 777 } elsif ($browse_which eq 'browse_setdefs') { 778 $self->browse_setdef_panel($library_selected); 779 } else { ## handle other problem libraries 780 $self->browse_local_panel($library_selected,$browse_which); 781 } 782 783 print CGI::Tr(CGI::td({-bgcolor=>"black"})); 784 785 print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, 786 CGI::start_table({-border=>"0"}), 787 CGI::Tr( CGI::td({ -align=>"center"}, 788 CGI::submit(-name=>"select_all", -style=>$these_widths, 789 -value=>"Mark All For Adding"), 790 CGI::submit(-name=>"select_none", -style=>$these_widths, 791 -value=>"Clear All Marks"), 792 )), 793 CGI::Tr(CGI::td( 794 CGI::submit(-name=>"update", -style=>$these_widths. "; font-weight:bold", 795 -value=>"Update Set"), 796 CGI::submit(-name=>"rerandomize", 797 -style=>$these_widths, 798 -value=>"Rerandomize"), 799 CGI::submit(-name=>"cleardisplay", 800 -style=>$these_widths, 801 -value=>"Clear Problem Display") 802 )), 803 CGI::end_table())); 804 } 805 806 sub make_data_row { 807 my $self = shift; 808 my $sourceFileName = shift; 809 my $pg = shift; 810 my $cnt = shift; 811 my $mark = shift || 0; 812 813 $sourceFileName =~ s|^./||; # clean up top ugliness 814 815 my $urlpath = $self->r->urlpath; 816 my $problem_output = $pg->{flags}->{error_flag} ? 817 CGI::div({class=>"ResultsWithError"}, CGI::em("This problem produced an error")) 818 : CGI::div({class=>"RenderSolo"}, $pg->{body_text}); 819 $problem_output .= $pg->{flags}->{comment} if($pg->{flags}->{comment}); 820 821 822 #if($self->{r}->param('browse_which') ne 'browse_library') { 823 my $problem_seed = $self->{r}->param('problem_seed') || 0; 824 my $edit_link = CGI::a({href=>$self->systemLink( 825 $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", 826 courseID =>$urlpath->arg("courseID"), 827 setID=>"Undefined_Set", 828 problemID=>"1"), 829 params=>{sourceFilePath => "$sourceFileName", problemSeed=> $problem_seed} 830 )}, "Edit it" ); 831 832 my $displayMode = $self->r->param("mydisplayMode"); 833 $displayMode = $self->r->ce->{pg}->{options}->{displayMode} 834 if not defined $displayMode or $displayMode eq "None"; 835 my $try_link = CGI::a({href=>$self->systemLink( 836 $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", 837 courseID =>$urlpath->arg("courseID"), 838 setID=>"Undefined_Set", 839 problemID=>"1"), 840 params =>{ 841 effectiveUser => scalar($self->r->param('user')), 842 editMode => "SetMaker", 843 problemSeed=> $problem_seed, 844 sourceFilePath => "$sourceFileName", 845 displayMode => $displayMode, 846 } 847 )}, "Try it"); 848 849 my %add_box_data = ( -name=>"trial$cnt",-value=>1,-label=>"Add this problem to the target set on the next update"); 850 if($mark & SUCCESS) { 851 $add_box_data{ -label } .= " (just added this problem)"; 852 } elsif($mark & ADDED) { 853 $add_box_data{ -checked } = 1; 854 } 855 856 print CGI::Tr({-align=>"left"}, CGI::td( 857 CGI::div({-style=>"background-color: #DDDDDD; margin: 0px auto"}, 858 CGI::span({-style=>"float:left ; text-align: left"},"File name: $sourceFileName "), 859 CGI::span({-style=>"float:right ; text-align: right"}, $edit_link, " ", $try_link) 860 ), CGI::br(), 861 CGI::checkbox(-name=>"hideme$cnt",-value=>1,-label=>"Don't show this problem on the next update"), 862 CGI::br(), 863 CGI::checkbox((%add_box_data)), 864 CGI::hidden(-name=>"filetrial$cnt", -default=>[$sourceFileName]). 865 CGI::p($problem_output), 866 )); 867 } 868 869 sub clear_default { 870 my $r = shift; 871 my $param = shift; 872 my $default = shift; 873 my $newvalue = $r->param($param) || ''; 874 $newvalue = '' if($newvalue eq $default); 875 $r->param($param, $newvalue); 876 } 877 878 sub pre_header_initialize { 879 my ($self) = @_; 880 my $r = $self->r; 881 ## For all cases, lets set some things 882 $self->{error}=0; 883 my $ce = $r->ce; 884 my $db = $r->db; 885 my $maxShown = $r->param('max_shown') || MAX_SHOW_DEFAULT; 886 $maxShown = 10000000 if($maxShown eq 'All'); # let's hope there aren't more 887 my $library_basic = $r->param('library_is_basic') || 1; 888 889 ## Fix some parameters 890 clear_default($r,'library_subjects', ALL_SUBJECTS); 891 clear_default($r,'library_chapters', ALL_CHAPTERS); 892 clear_default($r,'library_sections', ALL_SECTIONS); 893 clear_default($r,'library_textbook', ALL_TEXTBOOKS); 894 895 ## These directories will have individual buttons 896 %problib = %{$ce->{courseFiles}{problibs}} if $ce->{courseFiles}{problibs}; 897 898 my $userName = $r->param('user'); 899 my $user = $db->getUser($userName); # checked 900 die "record for user $userName (real user) does not exist." 901 unless defined $user; 902 my $authz = $r->authz; 903 unless ($authz->hasPermissions($userName, "modify_problem_sets")) { 904 return(""); # Error message already produced in the body 905 } 906 907 ## Now one action we have to deal with here 908 if ($r->param('edit_local')) { 909 my $urlpath = $r->urlpath; 910 my $db = $r->db; 911 my $checkset = $db->getGlobalSet($r->param('local_sets')); 912 if (not defined($checkset)) { 913 $self->{error} = 1; 914 $self->addbadmessage('You need to select a "Target Set" before you can edit it.'); 915 } else { 916 my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetDetail', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID")); 917 my $url = $self->systemLink($page); 918 $self->reply_with_redirect($url); 919 } 920 } 921 922 ## Next, lots of set up so that errors can be reported with message() 923 924 ############# List of problems we have already printed 925 926 $self->{past_problems} = get_past_problem_files($r); 927 # if we don't end up reusing problems, this will be wiped out 928 # if we do redisplay the same problems, we must adjust this accordingly 929 my @past_marks = map {$_->[1]} @{$self->{past_problems}}; 930 my $none_shown = scalar(@{$self->{past_problems}})==0; 931 my @pg_files=(); 932 my $use_previous_problems = 1; 933 my $first_shown = $r->param('first_shown') || 0; 934 my $last_shown = $r->param('last_shown'); 935 if (not defined($last_shown)) { 936 $last_shown = -1; 937 } 938 my @all_past_list = (); # these are include requested, but not shown 939 my $j = 0; 940 while (defined($r->param("all_past_list$j"))) { 941 push @all_past_list, $r->param("all_past_list$j"); 942 $j++; 943 } 944 945 ############# Default of which problem selector to display 946 947 my $browse_which = $r->param('browse_which') || 'browse_local'; 948 949 my $problem_seed = $r->param('problem_seed') || 0; 950 $r->param('problem_seed', $problem_seed); # if it wasn't defined before 951 952 ## check for problem lib buttons 953 my $browse_lib = ''; 954 foreach my $lib (keys %problib) { 955 if ($r->param("browse_$lib")) { 956 $browse_lib = "browse_$lib"; 957 last; 958 } 959 } 960 961 ########### Start the logic through if elsif elsif ... 962 963 ##### Asked to browse certain problems 964 if ($browse_lib ne '') { 965 $browse_which = $browse_lib; 966 $r->param('library_sets', ""); 967 $use_previous_problems = 0; @pg_files = (); ## clear old problems 968 } elsif ($r->param('browse_library')) { 969 $browse_which = 'browse_library'; 970 $r->param('library_sets', ""); 971 $use_previous_problems = 0; @pg_files = (); ## clear old problems 972 } elsif ($r->param('browse_local')) { 973 $browse_which = 'browse_local'; 974 $r->param('library_sets', ""); 975 $use_previous_problems = 0; @pg_files = (); ## clear old problems 976 } elsif ($r->param('browse_mysets')) { 977 $browse_which = 'browse_mysets'; 978 $r->param('library_sets', ""); 979 $use_previous_problems = 0; @pg_files = (); ## clear old problems 980 } elsif ($r->param('browse_setdefs')) { 981 $browse_which = 'browse_setdefs'; 982 $r->param('library_sets', ""); 983 $use_previous_problems = 0; @pg_files = (); ## clear old problems 984 985 ##### Change the seed value 986 987 } elsif ($r->param('rerandomize')) { 988 $problem_seed++; 989 $r->param('problem_seed', $problem_seed); 990 $self->addbadmessage('Changing the problem seed for display, but there are no problems showing.') if $none_shown; 991 992 ##### Clear the display 993 994 } elsif ($r->param('cleardisplay')) { 995 @pg_files = (); 996 $use_previous_problems=0; 997 $self->addbadmessage('The display was already cleared.') if $none_shown; 998 999 ##### View problems selected from the local list 1000 1001 } elsif ($r->param('view_local_set')) { 1002 1003 my $set_to_display = $r->param('library_sets'); 1004 if (not defined($set_to_display) or $set_to_display eq SELECT_LOCAL_STRING or $set_to_display eq "Found no directories containing problems") { 1005 $self->addbadmessage('You need to select a set to view.'); 1006 } else { 1007 $set_to_display = '.' if $set_to_display eq MY_PROBLEMS; 1008 $set_to_display = substr($browse_which,7) if $set_to_display eq MAIN_PROBLEMS; 1009 @pg_files = list_pg_files($ce->{courseDirs}->{templates}, 1010 "$set_to_display"); 1011 $use_previous_problems=0; 1012 } 1013 1014 ##### View problems selected from the a set in this course 1015 1016 } elsif ($r->param('view_mysets_set')) { 1017 1018 my $set_to_display = $r->param('library_sets'); 1019 if (not defined($set_to_display) 1020 or $set_to_display eq "Select a Homework Set" 1021 or $set_to_display eq NO_LOCAL_SET_STRING) { 1022 $self->addbadmessage("You need to select a set from this course to view."); 1023 } else { 1024 my @problemList = $db->listGlobalProblems($set_to_display); 1025 my $problem; 1026 @pg_files=(); 1027 for $problem (@problemList) { 1028 my $problemRecord = $db->getGlobalProblem($set_to_display, $problem); # checked 1029 die "global $problem for set $set_to_display not found." unless 1030 $problemRecord; 1031 push @pg_files, $problemRecord->source_file; 1032 1033 } 1034 $use_previous_problems=0; 1035 } 1036 1037 ##### View from the library database 1038 1039 } elsif ($r->param('lib_view')) { 1040 1041 @pg_files=(); 1042 my @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r); 1043 my ($result, $tolibpath); 1044 for $result (@dbsearch) { 1045 $tolibpath = "Library/$result->{path}/$result->{filename}"; 1046 1047 ## Too clunky!!!! 1048 push @pg_files, $tolibpath; 1049 } 1050 $use_previous_problems=0; 1051 1052 ##### View a set from a set*.def 1053 1054 } elsif ($r->param('view_setdef_set')) { 1055 1056 my $set_to_display = $r->param('library_sets'); 1057 if (not defined($set_to_display) 1058 or $set_to_display eq "Select a Set Definition File" 1059 or $set_to_display eq NO_LOCAL_SET_STRING) { 1060 $self->addbadmessage("You need to select a set from this course to view."); 1061 } else { 1062 @pg_files= $self->read_set_def($set_to_display); 1063 } 1064 $use_previous_problems=0; 1065 1066 ##### Edit the current local problem set 1067 1068 } elsif ($r->param('edit_local')) { ## Jump to set edit page 1069 1070 ; # already handled 1071 1072 1073 ##### Make a new local problem set 1074 1075 } elsif ($r->param('new_local_set')) { 1076 if ($r->param('new_set_name') !~ /^[\w .-]*$/) { 1077 $self->addbadmessage("The name ".$r->param('new_set_name')." is not a valid set name. Use only letters, digits, -, _, and ."); 1078 } else { 1079 my $newSetName = $r->param('new_set_name'); 1080 # if we want to munge the input set name, do it here 1081 $newSetName =~ s/\s/_/g; 1082 $r->param('local_sets',$newSetName); 1083 my $newSetRecord = $db->getGlobalSet($newSetName); 1084 if (defined($newSetRecord)) { 1085 $self->addbadmessage("The set name $newSetName is already in use. Pick a different name if you would like to start a new set."); 1086 } else { # Do it! 1087 $newSetRecord = $db->{set}->{record}->new(); 1088 $newSetRecord->set_id($newSetName); 1089 $newSetRecord->set_header(""); 1090 $newSetRecord->hardcopy_header(""); 1091 $newSetRecord->open_date(time()+60*60*24*7); # in one week 1092 $newSetRecord->due_date(time()+60*60*24*7*2); # in two weeks 1093 $newSetRecord->answer_date(time()+60*60*24*7*3); # in three weeks 1094 eval {$db->addGlobalSet($newSetRecord)}; 1095 if ($@) { 1096 $self->addbadmessage("Problem creating set $newSetName<br> $@"); 1097 } else { 1098 $self->addgoodmessage("Set $newSetName has been created."); 1099 my $selfassign = $r->param('selfassign') || ""; 1100 $selfassign = "" if($selfassign =~ /false/i); # deal with javascript false 1101 if($selfassign) { 1102 $self->assignSetToUser($userName, $newSetRecord); 1103 $self->addgoodmessage("Set $newSetName was assigned to $userName."); 1104 } 1105 } 1106 } 1107 } 1108 1109 ##### Add selected problems to the current local set 1110 1111 } elsif ($r->param('update')) { 1112 ## first handle problems to be added before we hide them 1113 my($localSet, @selected); 1114 1115 @pg_files = grep {($_->[1] & ADDED) != 0 } @{$self->{past_problems}}; 1116 @selected = map {$_->[0]} @pg_files; 1117 1118 my @action_files = grep {$_->[1] > 0 } @{$self->{past_problems}}; 1119 # There are now good reasons to do an update without selecting anything. 1120 #if(scalar(@action_files) == 0) { 1121 # $self->addbadmessage('Update requested, but no problems were marked.'); 1122 #} 1123 1124 if (scalar(@selected)>0) { # if some are to be added, they need a place to go 1125 $localSet = $r->param('local_sets'); 1126 if (not defined($localSet) or 1127 $localSet eq SELECT_SET_STRING or 1128 $localSet eq NO_LOCAL_SET_STRING) { 1129 $self->addbadmessage('You are trying to add problems to something, but you did not select a "Target Set" name as a target.'); 1130 } else { 1131 my $newSetRecord = $db->getGlobalSet($localSet); 1132 if (not defined($newSetRecord)) { 1133 $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."); 1134 } else { 1135 my $addcount = add_selected($self, $db, $localSet); 1136 if($addcount > 0) { 1137 $self->addgoodmessage("Added $addcount problem".(($addcount>1)?'s':''). 1138 " to $localSet."); 1139 } 1140 } 1141 } 1142 } 1143 ## now handle problems to be hidden 1144 1145 ## only keep the ones which are not hidden 1146 @pg_files = grep {($_->[1] & HIDDEN) ==0 } @{$self->{past_problems}}; 1147 @past_marks = map {$_->[1]} @pg_files; 1148 @pg_files = map {$_->[0]} @pg_files; 1149 @all_past_list = (@all_past_list[0..($first_shown-1)], 1150 @pg_files, 1151 @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]); 1152 $last_shown = $first_shown+$maxShown -1; 1153 $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list)); 1154 1155 } elsif ($r->param('next_page')) { 1156 $first_shown = $last_shown+1; 1157 $last_shown = $first_shown+$maxShown-1; 1158 $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list)); 1159 @past_marks = (); 1160 } elsif ($r->param('prev_page')) { 1161 $last_shown = $first_shown-1; 1162 $first_shown = $last_shown - $maxShown+1; 1163 1164 $first_shown = 0 if($first_shown<0); 1165 @past_marks = (); 1166 1167 } elsif ($r->param('select_all')) { 1168 @past_marks = map {1} @past_marks; 1169 } elsif ($r->param('library_basic')) { 1170 $library_basic = 1; 1171 for my $jj (qw(textchapter textsection textbook)) { 1172 $r->param('library_'.$jj,''); 1173 } 1174 } elsif ($r->param('library_advanced')) { 1175 $library_basic = 2; 1176 } elsif ($r->param('library_reset')) { 1177 for my $jj (qw(chapters sections subjects textbook keywords)) { 1178 $r->param('library_'.$jj,''); 1179 } 1180 } elsif ($r->param('select_none')) { 1181 @past_marks = (); 1182 1183 ##### No action requested, probably our first time here 1184 1185 } else { 1186 #my $c = $r->connection; 1187 #print "Debug info: ". $r->get_remote_host ."<p>". $c->remote_ip ; 1188 ; 1189 } ##### end of the if elsif ... 1190 1191 1192 ############# List of local sets 1193 1194 my @all_db_sets = $db->listGlobalSets; 1195 @all_db_sets = sortByName(undef, @all_db_sets); 1196 1197 if ($use_previous_problems) { 1198 @pg_files = @all_past_list; 1199 } else { 1200 $first_shown = 0; 1201 $last_shown = scalar(@pg_files)<$maxShown ? scalar(@pg_files) : $maxShown; 1202 $last_shown--; # to make it an array index 1203 @past_marks = (); 1204 } 1205 ############# Now store data in self for retreival by body 1206 $self->{first_shown} = $first_shown; 1207 $self->{last_shown} = $last_shown; 1208 $self->{browse_which} = $browse_which; 1209 $self->{problem_seed} = $problem_seed; 1210 $self->{pg_files} = \@pg_files; 1211 $self->{past_marks} = \@past_marks; 1212 $self->{all_db_sets} = \@all_db_sets; 1213 $self->{library_basic} = $library_basic; 1214 } 1215 1216 1217 sub title { 1218 return "Library Browser"; 1219 } 1220 1221 # hide view options panel since it distracts from SetMaker's built-in view options 1222 sub options { 1223 return ""; 1224 } 1225 1226 sub body { 1227 my ($self) = @_; 1228 1229 my $r = $self->r; 1230 my $ce = $r->ce; # course environment 1231 my $db = $r->db; # database 1232 my $j; # garden variety counter 1233 1234 my $userName = $r->param('user'); 1235 1236 my $user = $db->getUser($userName); # checked 1237 die "record for user $userName (real user) does not exist." 1238 unless defined $user; 1239 1240 ### Check that this is a professor 1241 my $authz = $r->authz; 1242 unless ($authz->hasPermissions($userName, "modify_problem_sets")) { 1243 print "User $userName returned " . 1244 $authz->hasPermissions($user, "modify_problem_sets") . 1245 " for permission"; 1246 return(CGI::div({class=>'ResultsWithError'}, 1247 CGI::em("You are not authorized to access the Instructor tools."))); 1248 } 1249 1250 ########## Extract information computed in pre_header_initialize 1251 1252 my $first_shown = $self->{first_shown}; 1253 my $last_shown = $self->{last_shown}; 1254 my $browse_which = $self->{browse_which}; 1255 my $problem_seed = $self->{problem_seed}; 1256 my @pg_files = @{$self->{pg_files}}; 1257 my @all_db_sets = @{$self->{all_db_sets}}; 1258 1259 my @pg_html=($last_shown>=$first_shown) ? 1260 renderProblems(r=> $r, 1261 user => $user, 1262 problem_list => [@pg_files[$first_shown..$last_shown]], 1263 displayMode => $r->param('mydisplayMode')) : (); 1264 1265 ########## Top part 1266 print CGI::startform({-method=>"POST", -action=>$r->uri, -name=>'mainform'}), 1267 $self->hidden_authen_fields, 1268 '<div align="center">', 1269 CGI::start_table({-border=>2}); 1270 $self->make_top_row('all_db_sets'=>\@all_db_sets, 1271 'browse_which'=> $browse_which); 1272 print CGI::hidden(-name=>'browse_which', -default=>[$browse_which]), 1273 CGI::hidden(-name=>'problem_seed', -default=>[$problem_seed]); 1274 for ($j = 0 ; $j < scalar(@pg_files) ; $j++) { 1275 print CGI::hidden(-name=>"all_past_list$j", -default=>$pg_files[$j]); 1276 } 1277 1278 print CGI::hidden(-name=>'first_shown', -default=>[$first_shown]); 1279 print CGI::hidden(-name=>'last_shown', -default=>[$last_shown]); 1280 1281 1282 ########## Now print problems 1283 my $jj; 1284 for ($jj=0; $jj<scalar(@pg_html); $jj++) { 1285 $pg_files[$jj] =~ s|^$ce->{courseDirs}->{templates}/?||; 1286 $self->make_data_row($pg_files[$jj+$first_shown], $pg_html[$jj], $jj+1, $self->{past_marks}->[$jj]); 1287 } 1288 1289 ########## Finish things off 1290 print CGI::end_table(); 1291 print '</div>'; 1292 # if($first_shown>0 or (1+$last_shown)<scalar(@pg_files)) { 1293 my ($next_button, $prev_button) = ("", ""); 1294 if ($first_shown > 0) { 1295 $prev_button = CGI::submit(-name=>"prev_page", -style=>"width:15ex", 1296 -value=>"Previous page"); 1297 } 1298 if ((1+$last_shown)<scalar(@pg_files)) { 1299 $next_button = CGI::submit(-name=>"next_page", -style=>"width:15ex", 1300 -value=>"Next page"); 1301 } 1302 if (scalar(@pg_files)>0) { 1303 print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files). 1304 " shown.", $prev_button, " ", $next_button); 1305 } 1306 # } 1307 print CGI::endform(), "\n"; 1308 1309 return ""; 1310 } 1311 1312 =head1 AUTHOR 1313 1314 Written by John Jones, jj (at) asu.edu. 1315 1316 =cut 1317 1318 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |