| … | |
… | |
| 32 | use WeBWorK::Utils qw(readDirectory max); |
32 | use WeBWorK::Utils qw(readDirectory max); |
| 33 | use WeBWorK::Utils::Tasks qw(renderProblems); |
33 | use WeBWorK::Utils::Tasks qw(renderProblems); |
| 34 | |
34 | |
| 35 | require WeBWorK::Utils::ListingDB; |
35 | require WeBWorK::Utils::ListingDB; |
| 36 | |
36 | |
| 37 | |
|
|
| 38 | use constant MAX_SHOW => 20; |
37 | use constant MAX_SHOW => 20; |
|
|
38 | |
|
|
39 | ## Flags for operations on files |
|
|
40 | |
|
|
41 | use constant ADDED => 1; |
|
|
42 | use constant HIDDEN => (1 << 1); |
|
|
43 | use constant SUCCESS => (1 << 2); |
|
|
44 | |
|
|
45 | ## Maybe this should be in ContentGenerator.pm |
|
|
46 | |
|
|
47 | sub adderrmsg { |
|
|
48 | my $self = shift; |
|
|
49 | my $msg = shift; |
|
|
50 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, $msg)); |
|
|
51 | } |
|
|
52 | |
|
|
53 | sub addgoodmsg { |
|
|
54 | my $self = shift; |
|
|
55 | my $msg = shift; |
|
|
56 | $self->addmessage(CGI::div({class=>"ResultsWithoutError"}, $msg)); |
|
|
57 | } |
|
|
58 | |
| 39 | |
59 | |
| 40 | ## This is for searching the disk for directories containing pg files. |
60 | ## This is for searching the disk for directories containing pg files. |
| 41 | ## to make the recursion work, this returns an array where the first |
61 | ## to make the recursion work, this returns an array where the first |
| 42 | ## item is 1 or 0 depending on whether or not the current |
62 | ## item is 1 or 0 depending on whether or not the current |
| 43 | ## directory has any pg files. The second is a list of directories |
63 | ## directory has any pg files. The second is a list of directories |
| … | |
… | |
| 83 | sub get_past_problem_files { |
103 | sub get_past_problem_files { |
| 84 | my $r = shift; |
104 | my $r = shift; |
| 85 | my @found=(); |
105 | my @found=(); |
| 86 | my $count =1; |
106 | my $count =1; |
| 87 | while (defined($r->param("filetrial$count"))) { |
107 | while (defined($r->param("filetrial$count"))) { |
|
|
108 | my $val = 0; |
|
|
109 | $val |= ADDED if($r->param("trial$count")); |
|
|
110 | $val |= HIDDEN if($r->param("hideme$count")); |
| 88 | push @found, [$r->param("filetrial$count"), |
111 | push @found, [$r->param("filetrial$count"), $val]; |
| 89 | defined($r->param("trial$count")) ? $r->param("trial$count"):0, |
|
|
| 90 | defined($r->param("hideme$count")) ?$r->param("hideme$count"):0]; |
|
|
| 91 | $count++; |
112 | $count++; |
| 92 | } |
113 | } |
| 93 | return(@found); |
114 | return(\@found); |
| 94 | } |
115 | } |
| 95 | |
116 | |
| 96 | #### For adding new problems |
117 | #### For adding new problems |
| 97 | |
118 | |
| 98 | sub add_selected { |
119 | sub add_selected { |
| 99 | my $self = shift; |
120 | my $self = shift; |
| 100 | my $db = shift; |
121 | my $db = shift; |
| 101 | my $setName = shift; |
122 | my $setName = shift; |
|
|
123 | my @past_problems = @{$self->{past_problems}}; |
| 102 | my @selected = @_; |
124 | my @selected = @past_problems; |
| 103 | my (@path, $file, $selected, $freeProblemID); |
125 | my (@path, $file, $selected, $freeProblemID); |
| 104 | $freeProblemID = max($db->listGlobalProblems($setName)) + 1; |
126 | $freeProblemID = max($db->listGlobalProblems($setName)) + 1; |
|
|
127 | my $addedcount=0; |
| 105 | |
128 | |
| 106 | for $selected (@selected) { |
129 | for $selected (@selected) { |
|
|
130 | if($selected->[1] & ADDED) { |
| 107 | $file = $selected; |
131 | $file = $selected->[0]; |
| 108 | @path = split "/", $selected; |
132 | @path = split "/", $selected->[0]; |
| 109 | pop @path; # Remove the file name from the path |
133 | pop @path; # Remove the file name from the path |
| 110 | shift @path if $path[0] eq ""; # remove the null element from the begining |
134 | shift @path if $path[0] eq ""; # remove the null element from the begining |
| 111 | my $problemRecord = $db->newGlobalProblem(); |
135 | my $problemRecord = $db->newGlobalProblem(); |
| 112 | $problemRecord->problem_id($freeProblemID++); |
136 | $problemRecord->problem_id($freeProblemID++); |
| 113 | $problemRecord->set_id($setName); |
137 | $problemRecord->set_id($setName); |
| 114 | $problemRecord->source_file($file); |
138 | $problemRecord->source_file($file); |
| 115 | $problemRecord->value("1"); |
139 | $problemRecord->value("1"); |
| 116 | $problemRecord->max_attempts("-1"); |
140 | $problemRecord->max_attempts("-1"); |
| 117 | $db->addGlobalProblem($problemRecord); |
141 | $db->addGlobalProblem($problemRecord); |
| 118 | $self->assignProblemToAllSetUsers($problemRecord); |
142 | $self->assignProblemToAllSetUsers($problemRecord); |
|
|
143 | $selected->[1] &= SUCCESS; |
|
|
144 | $addedcount++; |
| 119 | } |
145 | } |
|
|
146 | } |
|
|
147 | return($addedcount); |
| 120 | } |
148 | } |
| 121 | |
149 | |
| 122 | |
150 | |
| 123 | ############# List of sets of problems in templates directory |
151 | ############# List of sets of problems in templates directory |
| 124 | |
152 | |
| … | |
… | |
| 212 | for the Problem Library to function. It should be a link pointing to |
240 | for the Problem Library to function. It should be a link pointing to |
| 213 | <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>. |
241 | <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>. |
| 214 | I tried to make the link for you, but that failed. Check the permissions |
242 | I tried to make the link for you, but that failed. Check the permissions |
| 215 | in your <code>templates</code> directory. |
243 | in your <code>templates</code> directory. |
| 216 | HERE |
244 | HERE |
| 217 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, $msg)); |
245 | $self->adderrmsg($msg); |
| 218 | } |
246 | } |
| 219 | } |
247 | } |
| 220 | |
248 | |
| 221 | my $default_chap = "All Chapters"; |
249 | my $default_chap = "All Chapters"; |
| 222 | my $default_sect = "All Sections"; |
250 | my $default_sect = "All Sections"; |
| … | |
… | |
| 422 | my $urlpath = $r->urlpath; |
450 | my $urlpath = $r->urlpath; |
| 423 | my $db = $r->db; |
451 | my $db = $r->db; |
| 424 | my $checkset = $db->getGlobalSet($r->param('local_sets')); |
452 | my $checkset = $db->getGlobalSet($r->param('local_sets')); |
| 425 | if (not defined($checkset)) { |
453 | if (not defined($checkset)) { |
| 426 | $self->{error} = 1; |
454 | $self->{error} = 1; |
| 427 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, 'You need to select a "Current Set" before you can edit it.')); |
455 | $self->adderrmsg('You need to select a "Current Set" before you can edit it.'); |
| 428 | } else { |
456 | } else { |
| 429 | my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetEditor', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID")); |
457 | my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetEditor', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID")); |
| 430 | my $url = $self->systemLink($page); |
458 | my $url = $self->systemLink($page); |
| 431 | $self->reply_with_redirect($url); |
459 | $self->reply_with_redirect($url); |
| 432 | } |
460 | } |
| … | |
… | |
| 434 | |
462 | |
| 435 | ## Next, lots of set up so that errors can be reported with message() |
463 | ## Next, lots of set up so that errors can be reported with message() |
| 436 | |
464 | |
| 437 | ############# List of problems we have already printed |
465 | ############# List of problems we have already printed |
| 438 | |
466 | |
| 439 | my @past_problems = get_past_problem_files($r); |
467 | $self->{past_problems} = get_past_problem_files($r); |
|
|
468 | my $none_shown = scalar(@{$self->{past_problems}})==0; |
| 440 | my @pg_files=(); |
469 | my @pg_files=(); |
| 441 | my $use_previous_problems = 1; |
470 | my $use_previous_problems = 1; |
| 442 | my $first_shown = $r->param('first_shown') || 0; |
471 | my $first_shown = $r->param('first_shown') || 0; |
| 443 | my $last_shown = $r->param('last_shown'); |
472 | my $last_shown = $r->param('last_shown'); |
| 444 | if (not defined($last_shown)) { |
473 | if (not defined($last_shown)) { |
| … | |
… | |
| 474 | ##### Change the seed value |
503 | ##### Change the seed value |
| 475 | |
504 | |
| 476 | } elsif ($r->param('rerandomize')) { |
505 | } elsif ($r->param('rerandomize')) { |
| 477 | $problem_seed++; |
506 | $problem_seed++; |
| 478 | $r->param('problem_seed', $problem_seed); |
507 | $r->param('problem_seed', $problem_seed); |
|
|
508 | $self->adderrmsg('Changing the problem seed for display, but there are no problems showing.') if $none_shown; |
| 479 | |
509 | |
| 480 | ##### Clear the display |
510 | ##### Clear the display |
| 481 | |
511 | |
| 482 | } elsif ($r->param('cleardisplay')) { |
512 | } elsif ($r->param('cleardisplay')) { |
| 483 | @pg_files = (); |
513 | @pg_files = (); |
| 484 | $use_previous_problems=0; |
514 | $use_previous_problems=0; |
|
|
515 | $self->adderrmsg('The display was already cleared.') if $none_shown; |
| 485 | |
516 | |
| 486 | ##### View problems selected from the local list |
517 | ##### View problems selected from the local list |
| 487 | |
518 | |
| 488 | } elsif ($r->param('view_local_set')) { |
519 | } elsif ($r->param('view_local_set')) { |
| 489 | |
520 | |
| 490 | my $set_to_display = $r->param('library_sets'); |
521 | my $set_to_display = $r->param('library_sets'); |
| 491 | if (not defined($set_to_display) or $set_to_display eq "Select a Local Problem Collection" or $set_to_display eq "Found no directories containing problems") { |
522 | if (not defined($set_to_display) or $set_to_display eq "Select a Local Problem Collection" or $set_to_display eq "Found no directories containing problems") { |
| 492 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, |
523 | $self->adderrmsg('You need to select a set to view.'); |
| 493 | 'You need to select a set to view.')); |
|
|
| 494 | } else { |
524 | } else { |
| 495 | $set_to_display = '.' if $set_to_display eq ' -- Top -- '; |
525 | $set_to_display = '.' if $set_to_display eq ' -- Top -- '; |
| 496 | @pg_files = list_pg_files($ce->{courseDirs}->{templates}, |
526 | @pg_files = list_pg_files($ce->{courseDirs}->{templates}, |
| 497 | "$set_to_display"); |
527 | "$set_to_display"); |
| 498 | $use_previous_problems=0; |
528 | $use_previous_problems=0; |
| … | |
… | |
| 504 | |
534 | |
| 505 | my $set_to_display = $r->param('library_sets'); |
535 | my $set_to_display = $r->param('library_sets'); |
| 506 | if (not defined($set_to_display) |
536 | if (not defined($set_to_display) |
| 507 | or $set_to_display eq "Select a Problem Set" |
537 | or $set_to_display eq "Select a Problem Set" |
| 508 | or $set_to_display eq 'There are no local sets yet') { |
538 | or $set_to_display eq 'There are no local sets yet') { |
| 509 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, |
|
|
| 510 | "You need to select a set from this course to view.")); |
539 | $self->adderrmsg("You need to select a set from this course to view."); |
| 511 | } else { |
540 | } else { |
| 512 | my @problemList = $db->listGlobalProblems($set_to_display); |
541 | my @problemList = $db->listGlobalProblems($set_to_display); |
| 513 | my $problem; |
542 | my $problem; |
| 514 | @pg_files=(); |
543 | @pg_files=(); |
| 515 | for $problem (@problemList) { |
544 | for $problem (@problemList) { |
| … | |
… | |
| 551 | |
580 | |
| 552 | ##### Make a new local problem set |
581 | ##### Make a new local problem set |
| 553 | |
582 | |
| 554 | } elsif ($r->param('new_local_set')) { |
583 | } elsif ($r->param('new_local_set')) { |
| 555 | if ($r->param('new_set_name') !~ /^[\w.-]*$/) { |
584 | if ($r->param('new_set_name') !~ /^[\w.-]*$/) { |
| 556 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, |
|
|
| 557 | "The name ".$r->param('new_set_name')." is not a valid set name. Use only letters, digits, -, _, and .")); |
585 | $self->adderrmsg("The name ".$r->param('new_set_name')." is not a valid set name. Use only letters, digits, -, _, and ."); |
| 558 | } else { |
586 | } else { |
| 559 | my $newSetName = $r->param('new_set_name'); |
587 | my $newSetName = $r->param('new_set_name'); |
| 560 | $newSetName =~ s/^set//; |
588 | $newSetName =~ s/^set//; |
| 561 | $newSetName =~ s/\.def$//; |
589 | $newSetName =~ s/\.def$//; |
| 562 | $r->param('local_sets',$newSetName); |
590 | $r->param('local_sets',$newSetName); |
| 563 | my $newSetRecord = $db->getGlobalSet($newSetName); |
591 | my $newSetRecord = $db->getGlobalSet($newSetName); |
| 564 | if (defined($newSetRecord)) { |
592 | if (defined($newSetRecord)) { |
| 565 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, "The set name $newSetName is already in use. Pick a different name if you would like to start a new set.")); |
593 | $self->adderrmsg("The set name $newSetName is already in use. Pick a different name if you would like to start a new set."); |
| 566 | } else { # Do it! |
594 | } else { # Do it! |
| 567 | $newSetRecord = $db->{set}->{record}->new(); |
595 | $newSetRecord = $db->{set}->{record}->new(); |
| 568 | $newSetRecord->set_id($newSetName); |
596 | $newSetRecord->set_id($newSetName); |
| 569 | $newSetRecord->set_header(""); |
597 | $newSetRecord->set_header(""); |
| 570 | $newSetRecord->problem_header(""); |
598 | $newSetRecord->problem_header(""); |
| … | |
… | |
| 579 | |
607 | |
| 580 | } elsif ($r->param('update')) { |
608 | } elsif ($r->param('update')) { |
| 581 | ## first handle problems to be added before we hide them |
609 | ## first handle problems to be added before we hide them |
| 582 | my($localSet, @selected); |
610 | my($localSet, @selected); |
| 583 | |
611 | |
| 584 | @pg_files = grep {$_->[1] != 0 } @past_problems; |
612 | @pg_files = grep {($_->[1] & ADDED) != 0 } @{$self->{past_problems}}; |
| 585 | @selected = map {$_->[0]} @pg_files; |
613 | @selected = map {$_->[0]} @pg_files; |
|
|
614 | |
|
|
615 | my @action_files = grep {$_->[1] > 0 } @{$self->{past_problems}}; |
|
|
616 | if(scalar(@action_files) == 0) { |
|
|
617 | $self->adderrmsg('Act on marked problems requested, but no problems were marked.'); |
|
|
618 | } |
| 586 | |
619 | |
| 587 | if (scalar(@selected)>0) { # if some are to be added, they need a place to go |
620 | if (scalar(@selected)>0) { # if some are to be added, they need a place to go |
| 588 | $localSet = $r->param('local_sets'); |
621 | $localSet = $r->param('local_sets'); |
| 589 | if (not defined($localSet)) { |
622 | if (not defined($localSet)) { |
| 590 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, |
|
|
| 591 | 'You are trying to add problems to something, but you did not select a "Current Set" name as a target.')); |
623 | $self->adderrmsg('You are trying to add problems to something, but you did not select a "Current Set" name as a target.'); |
| 592 | } else { |
624 | } else { |
| 593 | my $newSetRecord = $db->getGlobalSet($localSet); |
625 | my $newSetRecord = $db->getGlobalSet($localSet); |
| 594 | if (not defined($newSetRecord)) { |
626 | if (not defined($newSetRecord)) { |
| 595 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, |
627 | $self->adderrmsg("You are trying to add problems to $localSet, but that set does not seem to exist! I bet you used your \"Back\" button."); |
| 596 | 'You are trying to add problems to something, but you did not select a "Current Set" name as a target.')); |
|
|
| 597 | } else { |
628 | } else { |
| 598 | add_selected($self, $db, $localSet, @selected); |
629 | my $addcount = add_selected($self, $db, $localSet); |
|
|
630 | if($addcount > 0) { |
|
|
631 | $self->adderrmsg("Successfully added $addcount problem".(($addcount>1)?'s':''). |
|
|
632 | " to $localSet."); |
|
|
633 | } |
| 599 | } |
634 | } |
| 600 | } |
635 | } |
| 601 | } |
636 | } |
| 602 | ## now handle problems to be hidden |
637 | ## now handle problems to be hidden |
| 603 | |
638 | |
|
|
639 | ## only keep the ones which are not hidden |
| 604 | @pg_files = grep {$_->[2]==0 } @past_problems; |
640 | @pg_files = grep {($_->[1] & HIDDEN) ==0 } @{$self->{past_problems}}; |
| 605 | @pg_files = map {$_->[0]} @pg_files; |
641 | @pg_files = map {$_->[0]} @pg_files; |
| 606 | @all_past_list = (@all_past_list[0..($first_shown-1)], |
642 | @all_past_list = (@all_past_list[0..($first_shown-1)], |
| 607 | @pg_files, |
643 | @pg_files, |
| 608 | @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]); |
644 | @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]); |
| 609 | $last_shown = $first_shown+MAX_SHOW -1; |
645 | $last_shown = $first_shown+MAX_SHOW -1; |