Parent Directory
|
Revision Log
Revision 2103 -
(view)
(download)
(as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm
| 1 : | sh002i | 1663 | ################################################################################ |
| 2 : | # WeBWorK Online Homework Delivery System | ||
| 3 : | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ | ||
| 4 : | toenail | 2103 | # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm,v 1.50 2004/05/13 16:02:55 toenail Exp $ |
| 5 : | sh002i | 1663 | # |
| 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 : | gage | 860 | package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor; |
| 18 : | use base qw(WeBWorK::ContentGenerator::Instructor); | ||
| 19 : | |||
| 20 : | =head1 NAME | ||
| 21 : | |||
| 22 : | WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list | ||
| 23 : | |||
| 24 : | =cut | ||
| 25 : | |||
| 26 : | use strict; | ||
| 27 : | use warnings; | ||
| 28 : | use CGI qw(); | ||
| 29 : | jj | 2038 | use File::Copy; |
| 30 : | malsyned | 976 | use WeBWorK::DB::Record::Problem; |
| 31 : | use WeBWorK::Utils qw(readFile formatDateTime parseDateTime list2hash readDirectory max); | ||
| 32 : | gage | 860 | |
| 33 : | gage | 869 | our $rowheight = 20; #controls the length of the popup menus. |
| 34 : | gage | 875 | our $libraryName; #library directory name |
| 35 : | malsyned | 935 | |
| 36 : | toenail | 2097 | use constant SET_FIELDS => [qw(open_date due_date answer_date set_header problem_header published)]; |
| 37 : | malsyned | 957 | use constant PROBLEM_FIELDS =>[qw(source_file value max_attempts)]; |
| 38 : | malsyned | 959 | use constant PROBLEM_USER_FIELDS => [qw(problem_seed status num_correct num_incorrect)]; |
| 39 : | malsyned | 947 | |
| 40 : | malsyned | 935 | sub getSetName { |
| 41 : | my ($self, $pathSetName) = @_; | ||
| 42 : | if (ref $pathSetName eq "HASH") { | ||
| 43 : | $pathSetName = undef; | ||
| 44 : | } | ||
| 45 : | return $pathSetName; | ||
| 46 : | } | ||
| 47 : | |||
| 48 : | toenail | 1997 | # One wrinkle here: if $override is undefined, do the global thing, |
| 49 : | # otherwise, it's truth value determines the checkbox and the current fieldValue is not directly editable | ||
| 50 : | malsyned | 967 | sub setRowHTML { |
| 51 : | my ($description, $fieldName, $fieldValue, $size, $override, $overrideValue) = @_; | ||
| 52 : | |||
| 53 : | my $attributeHash = {type=>"text", name=>$fieldName, value=>$fieldValue}; | ||
| 54 : | $attributeHash->{size} = $size if defined $size; | ||
| 55 : | |||
| 56 : | toenail | 1997 | my $input = (defined $override) ? $fieldValue : CGI::input($attributeHash); |
| 57 : | toenail | 2103 | |
| 58 : | toenail | 1997 | my $html = CGI::td({}, [$description, $input]); |
| 59 : | |||
| 60 : | malsyned | 967 | if (defined $override) { |
| 61 : | $attributeHash->{name}="${fieldName}_override"; | ||
| 62 : | $attributeHash->{value}=($override ? $overrideValue : "" ); | ||
| 63 : | |||
| 64 : | $html .= CGI::td({}, [ | ||
| 65 : | CGI::checkbox({ | ||
| 66 : | type=>"checkbox", | ||
| 67 : | name=>"override", | ||
| 68 : | label=>"override with:", | ||
| 69 : | value=>$fieldName, | ||
| 70 : | checked=>($override ? 1 : 0) | ||
| 71 : | }), | ||
| 72 : | CGI::input($attributeHash) | ||
| 73 : | ]); | ||
| 74 : | } | ||
| 75 : | |||
| 76 : | return $html; | ||
| 77 : | |||
| 78 : | } | ||
| 79 : | |||
| 80 : | gage | 860 | |
| 81 : | toenail | 2103 | # FIXME: this or something similar could get pulled up to Instructor.pm |
| 82 : | sub recurseDirectory { | ||
| 83 : | gage | 1295 | |
| 84 : | toenail | 2103 | my ($self, $dir, $pattern) = @_; |
| 85 : | |||
| 86 : | my @dirs = grep {$_ ne "." and $_ ne ".." and $_ ne "Library" and $_ ne "CVS" and -d "$dir/$_"} readDirectory($dir); | ||
| 87 : | |||
| 88 : | my @files = map { "$dir/$_" } $self->read_dir($dir, $pattern); | ||
| 89 : | |||
| 90 : | foreach (@dirs) { | ||
| 91 : | push (@files, $self->recurseDirectory("$dir/$_", $pattern)); | ||
| 92 : | } | ||
| 93 : | |||
| 94 : | return @files; | ||
| 95 : | } | ||
| 96 : | |||
| 97 : | |||
| 98 : | |||
| 99 : | malsyned | 960 | # Initialize does all of the form processing. It's extensive, and could probably be cleaned up and |
| 100 : | # consolidated with a little abstraction. | ||
| 101 : | malsyned | 935 | sub initialize { |
| 102 : | gage | 1928 | my ($self) = @_; |
| 103 : | my $r = $self->r; | ||
| 104 : | my $db = $r->db; | ||
| 105 : | my $ce = $r->ce; | ||
| 106 : | my $authz = $r->authz; | ||
| 107 : | gage | 1295 | my $user = $r->param('user'); |
| 108 : | gage | 1928 | #my $setName = $self->getSetName(@components); |
| 109 : | my $setName = $r->urlpath->arg("setID"); | ||
| 110 : | gage | 1667 | my $setRecord = $db->getGlobalSet($setName); #checked |
| 111 : | die "global set $setName not found." unless $setRecord; | ||
| 112 : | |||
| 113 : | gage | 1295 | $self->{set} = $setRecord; |
| 114 : | malsyned | 957 | my @editForUser = $r->param('editForUser'); |
| 115 : | # some useful booleans | ||
| 116 : | gage | 1295 | my $forUsers = scalar(@editForUser); |
| 117 : | my $forOneUser = $forUsers == 1; | ||
| 118 : | malsyned | 935 | |
| 119 : | malsyned | 983 | # build a quick lookup table |
| 120 : | malsyned | 967 | my %overrides = list2hash $r->param('override'); |
| 121 : | malsyned | 959 | |
| 122 : | malsyned | 1017 | unless ($authz->hasPermissions($user, "modify_problem_sets")) { |
| 123 : | toenail | 2091 | $self->addmessage(CGI::div({class=>"ResultsWithError"}, CGI::p("You are not authorized to modify problem sets"))); |
| 124 : | malsyned | 1017 | return; |
| 125 : | } | ||
| 126 : | gage | 1428 | |
| 127 : | ################################################### | ||
| 128 : | # The set form was submitted with the save button pressed | ||
| 129 : | # Save changes to the set | ||
| 130 : | ################################################### | ||
| 131 : | gage | 1686 | |
| 132 : | toenail | 2103 | if (defined($r->param('submit_set_changes'))) { |
| 133 : | |||
| 134 : | if (!$forUsers) { | ||
| 135 : | foreach (@{SET_FIELDS()}) { | ||
| 136 : | if (defined($r->param($_))) { | ||
| 137 : | if (m/_date$/) { | ||
| 138 : | $setRecord->$_(parseDateTime($r->param($_))); | ||
| 139 : | } else { | ||
| 140 : | $setRecord->$_($r->param($_)); | ||
| 141 : | if($_ eq 'set_header') { | ||
| 142 : | # be nice and copy the default file here if it doesn't exist yet | ||
| 143 : | # empty set headers lead to trouble | ||
| 144 : | my $newheaderpath = $r->{ce}->{courseDirs}->{templates} . '/'. $r->param('set_header'); | ||
| 145 : | unless(($r->param('set_header') !~ /\S/) or -e $newheaderpath) { | ||
| 146 : | my $default_header = $ce->{webworkFiles}->{screenSnippets}->{setHeader}; | ||
| 147 : | File::Copy::copy($default_header, $newheaderpath); | ||
| 148 : | } | ||
| 149 : | jj | 2038 | } |
| 150 : | } | ||
| 151 : | toenail | 2103 | } else { |
| 152 : | if (m/published$/) { | ||
| 153 : | $setRecord->$_(0); | ||
| 154 : | } | ||
| 155 : | malsyned | 935 | } |
| 156 : | } | ||
| 157 : | toenail | 2097 | |
| 158 : | |||
| 159 : | |||
| 160 : | |||
| 161 : | toenail | 2103 | ################################################### |
| 162 : | # Check that the open, due and answer dates are in increasing order. | ||
| 163 : | # Bail if this is not correct. | ||
| 164 : | ################################################### | ||
| 165 : | if ($setRecord->open_date > $setRecord->due_date) { | ||
| 166 : | $self->addmessage(CGI::div({class=>'ResultsWithError'},'Error: Due date must come after open date')); | ||
| 167 : | return; | ||
| 168 : | } | ||
| 169 : | if ($setRecord->due_date > $setRecord->answer_date) { | ||
| 170 : | $self->addmessage(CGI::div({class=>'ResultsWithError'},'Error: Answer date must come after due date')); | ||
| 171 : | return; | ||
| 172 : | } | ||
| 173 : | ################################################### | ||
| 174 : | # End date check section. | ||
| 175 : | ################################################### | ||
| 176 : | $self->addmessage(CGI::div({class=>'ResultsWithoutError'}, "Changes to set $setName were successfully saved.")); | ||
| 177 : | $db->putGlobalSet($setRecord); | ||
| 178 : | } else { | ||
| 179 : | malsyned | 959 | |
| 180 : | gage | 1667 | my $userSetRecord = $db->getUserSet($editForUser[0], $setName); #checked |
| 181 : | die "set $setName not found for $editForUser[0]." unless $userSetRecord; | ||
| 182 : | malsyned | 959 | foreach my $field (@{SET_FIELDS()}) { |
| 183 : | if (defined $r->param("${field}_override")) { | ||
| 184 : | if (exists $overrides{$field}) { | ||
| 185 : | if ($field =~ m/_date$/) { | ||
| 186 : | $userSetRecord->$field(parseDateTime($r->param("${field}_override"))); | ||
| 187 : | } else { | ||
| 188 : | $userSetRecord->$field($r->param("${field}_override")); | ||
| 189 : | } | ||
| 190 : | } else { | ||
| 191 : | $userSetRecord->$field(undef); | ||
| 192 : | } | ||
| 193 : | } | ||
| 194 : | } | ||
| 195 : | gage | 1686 | ################################################### |
| 196 : | # Check that the open, due and answer dates are in increasing order. | ||
| 197 : | # Bail if this is not correct. | ||
| 198 : | ################################################### | ||
| 199 : | my $active_open_date = $userSetRecord->open_date ? $userSetRecord->open_date : $setRecord->open_date; | ||
| 200 : | my $active_due_date = $userSetRecord->due_date ? $userSetRecord->due_date : $setRecord->due_date; | ||
| 201 : | my $active_answer_date = $userSetRecord->answer_date ? $userSetRecord->answer_date : $setRecord->answer_date; | ||
| 202 : | toenail | 2103 | if ( $active_open_date > $active_due_date ) { |
| 203 : | toenail | 2091 | $self->addmessage(CGI::div({class=>'ResultsWithError'},'Error: Due date override must come after open date')); |
| 204 : | return; | ||
| 205 : | gage | 1686 | } |
| 206 : | if ( $active_due_date > $active_answer_date ) { | ||
| 207 : | toenail | 2091 | $self->addmessage(CGI::div({class=>'ResultsWithError'},'Error: Answer date override must come after due date')); |
| 208 : | return; | ||
| 209 : | gage | 1686 | } |
| 210 : | ################################################### | ||
| 211 : | # End date check section. | ||
| 212 : | ################################################### | ||
| 213 : | toenail | 2097 | $self->addmessage(CGI::div({class=>'ResultsWithoutError'}, "Changes to set $setName for user ",CGI::b($editForUser[0]) ,"were successfully saved.")); |
| 214 : | gage | 1686 | $db->putUserSet($userSetRecord); |
| 215 : | malsyned | 959 | } |
| 216 : | gage | 1686 | |
| 217 : | malsyned | 936 | } |
| 218 : | gage | 1428 | |
| 219 : | ################################################### | ||
| 220 : | # The set form was submitted with the export button pressed | ||
| 221 : | # Export the set structure to a set definition file | ||
| 222 : | ################################################### | ||
| 223 : | |||
| 224 : | if ( defined($r->param('export_set')) ) { | ||
| 225 : | my $fileName = $r->param('export_file_name'); | ||
| 226 : | die "Please specify a file name for saving the set definition" unless $fileName; | ||
| 227 : | $fileName .= '.def' unless $fileName =~ /\.def$/; | ||
| 228 : | my $filePath = $ce->{courseDirs}->{templates}.'/'.$fileName; | ||
| 229 : | # back up existing file | ||
| 230 : | jj | 1978 | if(-e $filePath) { |
| 231 : | rename($filePath,"$filePath.bak") or | ||
| 232 : | gage | 1428 | die "Can't rename $filePath to $filePath.bak ", |
| 233 : | "Check permissions for webserver on directories. $!"; | ||
| 234 : | jj | 1978 | } |
| 235 : | gage | 1428 | my $openDate = formatDateTime($setRecord->open_date); |
| 236 : | my $dueDate = formatDateTime($setRecord->due_date); | ||
| 237 : | my $answerDate = formatDateTime($setRecord->answer_date); | ||
| 238 : | my $setHeader = $setRecord->set_header; | ||
| 239 : | |||
| 240 : | my @problemList = $db->listGlobalProblems($setName); | ||
| 241 : | my $problemList = ''; | ||
| 242 : | foreach my $prob (sort {$a <=> $b} @problemList) { | ||
| 243 : | gage | 1667 | my $problemRecord = $db->getGlobalProblem($setName, $prob); # checked |
| 244 : | die "global problem $prob for set $setName not found" unless defined($problemRecord); | ||
| 245 : | gage | 1428 | my $source_file = $problemRecord->source_file(); |
| 246 : | my $value = $problemRecord->value(); | ||
| 247 : | my $max_attempts = $problemRecord->max_attempts(); | ||
| 248 : | $problemList .= "$source_file, $value, $max_attempts \n"; | ||
| 249 : | } | ||
| 250 : | my $fileContents = <<EOF; | ||
| 251 : | |||
| 252 : | openDate = $openDate | ||
| 253 : | dueDate = $dueDate | ||
| 254 : | answerDate = $answerDate | ||
| 255 : | paperHeaderFile = $setHeader | ||
| 256 : | screenHeaderFile = $setHeader | ||
| 257 : | problemList = | ||
| 258 : | |||
| 259 : | $problemList | ||
| 260 : | |||
| 261 : | |||
| 262 : | |||
| 263 : | EOF | ||
| 264 : | |||
| 265 : | |||
| 266 : | $self->saveProblem($fileContents, $filePath); | ||
| 267 : | toenail | 2091 | $self->addmessage(CGI::div({class=>"ResultsWithoutError"}, CGI::p("Set definition saved to $filePath"))); |
| 268 : | gage | 1428 | |
| 269 : | } | ||
| 270 : | malsyned | 935 | } |
| 271 : | |||
| 272 : | malsyned | 947 | |
| 273 : | gage | 860 | sub body { |
| 274 : | malsyned | 935 | my ($self, @components) = @_; |
| 275 : | gage | 1928 | my $r = $self->r; |
| 276 : | gage | 1930 | my $urlpath = $r->urlpath; |
| 277 : | gage | 1928 | my $db = $r->db; |
| 278 : | my $ce = $r->ce; | ||
| 279 : | my $authz = $r->authz; | ||
| 280 : | my $user = $r->param('user'); | ||
| 281 : | gage | 1930 | my $courseName = $urlpath->arg("courseID"); |
| 282 : | my $setName = $urlpath->arg("setID"); | ||
| 283 : | gage | 1928 | my $setRecord = $db->getGlobalSet($setName); # checked |
| 284 : | gage | 1667 | die "global set $setName not found." unless $setRecord; |
| 285 : | gage | 1930 | my @editForUser = $r->param('editForUser'); |
| 286 : | malsyned | 947 | # some useful booleans |
| 287 : | gage | 1930 | my $forUsers = scalar(@editForUser); |
| 288 : | my $forOneUser = $forUsers == 1; | ||
| 289 : | malsyned | 1017 | |
| 290 : | return CGI::em("You are not authorized to access the Instructor tools.") unless $authz->hasPermissions($user, "access_instructor_tools"); | ||
| 291 : | |||
| 292 : | malsyned | 959 | ## Set Form ## |
| 293 : | malsyned | 947 | my $userSetRecord; |
| 294 : | my %overrideArgs; | ||
| 295 : | if ($forOneUser) { | ||
| 296 : | gage | 1667 | $userSetRecord = $db->getUserSet($editForUser[0], $setName); #checked |
| 297 : | die "set $setName not found for user $editForUser[0]." unless $userSetRecord; | ||
| 298 : | malsyned | 947 | foreach my $field (@{SET_FIELDS()}) { |
| 299 : | malsyned | 959 | $overrideArgs{$field} = [defined $userSetRecord->$field, ($field =~ /_date$/ ? formatDateTime($userSetRecord->$field) : $userSetRecord->$field)]; |
| 300 : | malsyned | 947 | } |
| 301 : | } else { | ||
| 302 : | foreach my $field (@{SET_FIELDS()}) { | ||
| 303 : | $overrideArgs{$field} = [undef, undef]; | ||
| 304 : | } | ||
| 305 : | } | ||
| 306 : | malsyned | 1460 | print CGI::h2({}, "Set Data"), "\n"; |
| 307 : | if (@editForUser) { | ||
| 308 : | print CGI::p("Editing user-specific overrides for ". CGI::b(join ", ", @editForUser)); | ||
| 309 : | } | ||
| 310 : | toenail | 2103 | |
| 311 : | my @headers = $self->recurseDirectory($self->{ce}->{courseDirs}->{templates}, '(?i)header.*?\\.pg$'); | ||
| 312 : | map { s|^$self->{ce}->{courseDirs}->{templates}/?|| } @headers; | ||
| 313 : | @headers = sort @headers; | ||
| 314 : | |||
| 315 : | malsyned | 959 | print CGI::start_form({method=>"post", action=>$r->uri}), "\n"; |
| 316 : | malsyned | 935 | print CGI::table({}, |
| 317 : | CGI::Tr({}, [ | ||
| 318 : | gage | 1348 | setRowHTML( "Open Date:", |
| 319 : | "open_date", | ||
| 320 : | formatDateTime($setRecord->open_date), | ||
| 321 : | undef, | ||
| 322 : | @{$overrideArgs{open_date}})."\n", | ||
| 323 : | setRowHTML( "Due Date:", | ||
| 324 : | "due_date", | ||
| 325 : | formatDateTime($setRecord->due_date), | ||
| 326 : | undef, | ||
| 327 : | @{$overrideArgs{due_date}})."\n", | ||
| 328 : | setRowHTML( "Answer Date:", | ||
| 329 : | "answer_date", | ||
| 330 : | formatDateTime($setRecord->answer_date), | ||
| 331 : | undef, | ||
| 332 : | @{$overrideArgs{answer_date}})."\n", | ||
| 333 : | toenail | 2103 | # setRowHTML( "Set Header:", "set_header", |
| 334 : | # $setRecord->set_header, | ||
| 335 : | # 32, | ||
| 336 : | # @{$overrideArgs{set_header}})."\n", | ||
| 337 : | gage | 1348 | # FIXME we're not using this right at the moment as far as I know. There may someday be a use for it, so don't take this out yet. |
| 338 : | # setRowHTML( "Problem Header:", | ||
| 339 : | # "problem_header", | ||
| 340 : | # $setRecord->problem_header, | ||
| 341 : | # undef, | ||
| 342 : | toenail | 2097 | # @{$overrideArgs{problem_header}})."\n", |
| 343 : | toenail | 2103 | CGI::td({}, ["Set Header:" , ($forOneUser) ? $setRecord->set_header |
| 344 : | : CGI::popup_menu(-name=>'set_header', | ||
| 345 : | -values=>\@headers, | ||
| 346 : | -default=>$setRecord->set_header)]) . "\n", | ||
| 347 : | malsyned | 935 | ]) |
| 348 : | ); | ||
| 349 : | toenail | 2103 | |
| 350 : | toenail | 2097 | if (@editForUser) { |
| 351 : | my $publishedColor = ($setRecord->published) ? "Published" : "Unpublished"; | ||
| 352 : | print CGI::p("This set is currently", CGI::font({class=>$publishedColor}, (($setRecord->published) ? "Published" : "Unpublished")), CGI::br(), "(You cannot publish/unpublish a set for specific users.)"); | ||
| 353 : | } else { | ||
| 354 : | print CGI::checkbox({type=>"checkbox", name=>"published", label=>"Published", value=>"1", checked=>(($setRecord->published) ? 1 : 0)}), CGI::br(); | ||
| 355 : | |||
| 356 : | } | ||
| 357 : | |||
| 358 : | gage | 1428 | print $self->hiddenEditForUserFields(@editForUser), |
| 359 : | $self->hidden_authen_fields, | ||
| 360 : | jj | 2038 | CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set", style=>"{width: 13ex}"}), |
| 361 : | gage | 1428 | ' '; |
| 362 : | gage | 1348 | |
| 363 : | gage | 1428 | #### link to edit setHeader |
| 364 : | gage | 1930 | my $PGProblemEditor = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", |
| 365 : | courseID => $courseName, | ||
| 366 : | setID => $setName, | ||
| 367 : | problemID => '0' | ||
| 368 : | ); | ||
| 369 : | my $setHeaderEditLink = $self->systemLink($PGProblemEditor); | ||
| 370 : | gage | 1348 | if (defined($setRecord) and $setRecord->set_header) { |
| 371 : | gage | 1930 | print CGI::a({-href=>$setHeaderEditLink},'Edit set header: '.$setRecord->set_header); |
| 372 : | gage | 1348 | } |
| 373 : | gage | 1428 | |
| 374 : | print CGI::br(), | ||
| 375 : | jj | 2038 | CGI::submit({ name=>"export_set", label=>"Export Set", style=>"{width: 13ex}"} ), |
| 376 : | gage | 1428 | ' as ', |
| 377 : | jj | 1979 | CGI::input({type=>'text',name=>'export_file_name',value=>"set$setName.def",size=>32}); |
| 378 : | gage | 1428 | |
| 379 : | toenail | 2091 | print CGI::br(); |
| 380 : | gage | 1428 | |
| 381 : | |||
| 382 : | |||
| 383 : | malsyned | 935 | print CGI::end_form(); |
| 384 : | |||
| 385 : | malsyned | 1005 | my $problemCount = $db->listGlobalProblems($setName); |
| 386 : | print CGI::h2({}, "Problems"), "\n"; | ||
| 387 : | print CGI::p({}, "This set contains $problemCount problem" . ($problemCount == 1 ? "" : "s")."."); | ||
| 388 : | gage | 1930 | #FIXME |
| 389 : | # the code below doesn't work --- | ||
| 390 : | # get message | ||
| 391 : | #no type matches module WeBWorK::ContentGenerator::Instructor::SetsAssignedToUser with args at | ||
| 392 : | # /home/gage/webwork/webwork-modperl/lib/WeBWorK/URLPath.pm line 497. | ||
| 393 : | # error in URLPath.pm?????? | ||
| 394 : | gage | 1934 | my $problemSetListPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::ProblemList", |
| 395 : | courseID => $courseName, | ||
| 396 : | setID => $setName | ||
| 397 : | ); | ||
| 398 : | |||
| 399 : | my $editProblemsURL = $self->systemLink($problemSetListPage, | ||
| 400 : | params => ['editForUser'] # include all editForUser parameters | ||
| 401 : | ); | ||
| 402 : | my $usersAssignedToSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::UsersAssignedToSet", | ||
| 403 : | courseID => $courseName, | ||
| 404 : | setID => $setName | ||
| 405 : | ); | ||
| 406 : | |||
| 407 : | my $editUsersAssignedToSetURL = $self->systemLink($usersAssignedToSetPage, | ||
| 408 : | |||
| 409 : | ); | ||
| 410 : | print CGI::a({href=>$editProblemsURL}, | ||
| 411 : | gage | 1928 | (@editForUser) ? "Edit the list of problems in this set for ". CGI::b(join ", ", @editForUser) : |
| 412 : | "Edit the list of problems in this set"); | ||
| 413 : | |||
| 414 : | gage | 1930 | unless (@editForUser) { # this is not needed when we are editing details for a user |
| 415 : | my $userCount = $db->listUsers; | ||
| 416 : | my $usersOfSet = $db->countSetUsers($setName); | ||
| 417 : | print CGI::h2({}, "Users"), "\n"; | ||
| 418 : | print CGI::p({}, "This set is assigned to ".$self->userCountMessage($usersOfSet, $userCount)."."); | ||
| 419 : | gage | 1934 | print CGI::a({href=>$editUsersAssignedToSetURL}, "Determine who this set is assigned to"); |
| 420 : | gage | 1930 | } |
| 421 : | malsyned | 935 | |
| 422 : | return ""; | ||
| 423 : | } | ||
| 424 : | gage | 1428 | ########################################################################### |
| 425 : | # utility | ||
| 426 : | ########################################################################### | ||
| 427 : | sub saveProblem { | ||
| 428 : | my $self = shift; | ||
| 429 : | my ($body, $probFileName)= @_; | ||
| 430 : | local(*PROBLEM); | ||
| 431 : | open (PROBLEM, ">$probFileName") || | ||
| 432 : | $self->submission_error("Could not open $probFileName for writing. | ||
| 433 : | Check that the permissions for this problem are 660 (-rw-rw----)"); | ||
| 434 : | print PROBLEM $body; | ||
| 435 : | close PROBLEM; | ||
| 436 : | chmod 0660, "$probFileName" || | ||
| 437 : | $self->submission_error(" | ||
| 438 : | CAN'T CHANGE PERMISSIONS ON FILE $probFileName"); | ||
| 439 : | } | ||
| 440 : | gage | 860 | 1; |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |