[system] / trunk / webwork-modperl / lib / WeBWorK / ContentGenerator / Instructor / SetMaker.pm Repository:
ViewVC logotype

Diff of /trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.2024  
changed lines
  Added in v.2734

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9