Parent Directory
|
Revision Log
added HiRes timing data to WeBWorK::Debug, removed WeBWorK::Timing. all existing calls to the WeBWorK::Timing methods now pass the same messages to debug(). added an option to WeBWorK::Debug to allow only certain subroutines to log debug messages, in addition to the existing option to bar certain subroutines from doing so.
1 ################################################################################ 2 # WeBWorK Online Homework Delivery System 3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 4 # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm,v 1.65 2005/08/11 22:11:53 sh002i 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 package WeBWorK::ContentGenerator::ProblemSet; 18 use base qw(WeBWorK::ContentGenerator); 19 20 =head1 NAME 21 22 WeBWorK::ContentGenerator::ProblemSet - display an index of the problems in a 23 problem set. 24 25 =cut 26 27 use strict; 28 use warnings; 29 use CGI qw(*ul *li); 30 use WeBWorK::PG; 31 use URI::Escape; 32 use WeBWorK::Debug; 33 use WeBWorK::Utils qw(sortByName); 34 35 sub initialize { 36 my ($self) = @_; 37 my $r = $self->r; 38 my $db = $r->db; 39 my $urlpath = $r->urlpath; 40 my $authz = $r->authz; 41 42 my $setName = $urlpath->arg("setID"); 43 my $userName = $r->param("user"); 44 my $effectiveUserName = $r->param("effectiveUser"); 45 46 my $user = $db->getUser($userName); # checked 47 my $effectiveUser = $db->getUser($effectiveUserName); # checked 48 my $set = $db->getMergedSet($effectiveUserName, $setName); # checked 49 50 die "user $user (real user) not found." unless $user; 51 die "effective user $effectiveUserName not found. One 'acts as' the effective user." unless $effectiveUser; 52 53 # FIXME: some day it would be nice to take out this code and consolidate the two checks 54 55 # get result and send to message 56 my $status_message = $r->param("status_message"); 57 $self->addmessage(CGI::p("$status_message")) if $status_message; 58 59 # because of the database fix, we have to split our invalidSet check into two parts 60 # First, if $set is undefined then $setName was never valid 61 $self->{invalidSet} = not defined $set; 62 return if $self->{invalidSet}; 63 64 # now that the set is valid, make sure that GatewayQuiz assignments don't get 65 # entered through this module 66 die "set $setName is a GatewayQuiz. Enter through the GatewayQuiz " . 67 "module." if ( defined( $set->assignment_type() ) && 68 $set->assignment_type() =~ /gateway/ ); 69 70 # Database fix (in case of undefined published values) 71 # this is only necessary because some people keep holding to ww1.9 which did not have a published field 72 # make sure published is set to 0 or 1 73 if ($set->published ne "0" and $set->published ne "1") { 74 my $globalSet = $db->getGlobalSet($set->set_id); 75 $globalSet->published("1"); # defaults to published 76 $db->putGlobalSet($globalSet); 77 $set = $db->getMergedSet($effectiveUserName, $set->set_id); 78 } 79 80 # Second, a set is invalid if it is still unpublished and the user does not have the right permissions 81 $self->{invalidSet} = !($set->published || $authz->hasPermissions($userName, "view_unpublished_sets")); 82 return if $self->{invalidSet}; 83 84 my $publishedText = ($set->published) ? "visible to students." : "hidden from students."; 85 my $publishedClass = ($set->published) ? "Published" : "Unpublished"; 86 $self->addmessage(CGI::p("This set is " . CGI::font({class=>$publishedClass}, $publishedText))) if $authz->hasPermissions($userName, "view_unpublished_sets"); 87 88 $self->{userName} = $userName; 89 $self->{user} = $user; 90 $self->{effectiveUser} = $effectiveUser; 91 $self->{set} = $set; 92 93 ##### permissions ##### 94 95 $self->{isOpen} = time >= $set->open_date || $authz->hasPermissions($userName, "view_unopened_sets"); 96 } 97 98 sub nav { 99 my ($self, $args) = @_; 100 my $r = $self->r; 101 my $urlpath = $r->urlpath; 102 103 my $courseID = $urlpath->arg("courseID"); 104 #my $problemSetsPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", courseID => $courseID); 105 my $problemSetsPage = $urlpath->parent; 106 107 my @links = ("Homework Sets" , $r->location . $problemSetsPage->path, "navUp"); 108 # CRAP ALERT: this line relies on the hacky options() implementation in ContentGenerator. 109 # we need to find a better way to do this -- long range dependencies like this are dangerous! 110 #my $tail = "&displayMode=".$self->{displayMode}."&showOldAnswers=".$self->{will}->{showOldAnswers}; 111 # here is a hack to get some functionality back, but I don't even think it's that important to 112 # have this, since there are SO MANY PLACES where we lose the displayMode, etc. 113 # (oh boy, do we need a session table in the database!) 114 my $displayMode = $r->param("displayMode") || ""; 115 my $showOldAnswers = $r->param("showOldAnswers") || ""; 116 my $tail = "&displayMode=$displayMode&showOldAnswers=$showOldAnswers"; 117 return $self->navMacro($args, $tail, @links); 118 } 119 120 sub siblings { 121 my ($self) = @_; 122 my $r = $self->r; 123 my $db = $r->db; 124 my $authz = $r->authz; 125 my $urlpath = $r->urlpath; 126 127 128 my $courseID = $urlpath->arg("courseID"); 129 my $user = $r->param('user'); 130 my $eUserID = $r->param("effectiveUser"); 131 my @allsetIDs = sortByName(undef, $db->listUserSets($eUserID)); 132 # exclude versioned set IDs from the listing of global sets 133 my @setIDs = grep { $_ !~ /,v\d+$/ } @allsetIDs; 134 135 # do not show unpublished siblings unless user is allowed to view unpublished sets, and 136 # exclude gateway tests 137 unless ($authz->hasPermissions($user, "view_unpublished_sets") ) { 138 # @setIDs = grep {my $visible = $db->getGlobalSet( $_)->published; (defined($visible))? $visible : 1} 139 @setIDs = grep {my $gs = $db->getGlobalSet( $_ ); 140 $gs->assignment_type() !~ /gateway/ && 141 ( defined($gs->published()) ? $gs->published() : 1 )} 142 @setIDs; 143 } 144 print CGI::start_ul({class=>"LinksMenu"}); 145 print CGI::start_li(); 146 print CGI::span({style=>"font-size:larger"}, "Homework Sets"); 147 print CGI::start_ul(); 148 149 # FIXME: setIDs contain no info on published/unpublished so unpublished sets are still printed 150 debug("Begin printing sets from listUserSets()"); 151 foreach my $setID (@setIDs) { 152 my $setPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", 153 courseID => $courseID, setID => $setID); 154 print CGI::li(CGI::a({href=>$self->systemLink($setPage), 155 params=>{ displayMode => $self->{displayMode}, 156 showOldAnswers => $self->{will}->{showOldAnswers} 157 }}, $setID) 158 ) ; 159 } 160 debug("End printing sets from listUserSets()"); 161 162 # FIXME: when database calls are faster, this will get rid of unpublished sibling links 163 #debug("Begin printing sets from getMergedSets()"); 164 #my @userSetIDs = map {[$eUserID, $_]} @setIDs; 165 #my @sets = $db->getMergedSets(@userSetIDs); 166 #foreach my $set (@sets) { 167 # my $setPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet", courseID => $courseID, setID => $set->set_id); 168 # print CGI::li(CGI::a({href=>$self->systemLink($setPage)}, $set->set_id)) unless !(defined $set && ($set->published || $authz->hasPermissions($user, "view_unpublished_sets")); 169 #} 170 #debug("Begin printing sets from getMergedSets()"); 171 172 print CGI::end_ul(); 173 print CGI::end_li(); 174 print CGI::end_ul(); 175 176 return ""; 177 } 178 179 sub info { 180 my ($self) = @_; 181 my $r = $self->r; 182 my $ce = $r->ce; 183 my $db = $r->db; 184 my $authz = $r->authz; 185 my $urlpath = $r->urlpath; 186 187 return "" unless $self->{isOpen}; 188 189 my $courseID = $urlpath->arg("courseID"); 190 my $setID = $r->urlpath->arg("setID"); 191 192 my $userID = $r->param("user"); 193 my $eUserID = $r->param("effectiveUser"); 194 195 my $effectiveUser = $db->getUser($eUserID); # checked 196 my $set = $db->getMergedSet($eUserID, $setID); # checked 197 198 die "effective user $eUserID not found. One 'acts as' the effective user." unless $effectiveUser; 199 # FIXME: this was already caught in initialize() 200 die "set $setID for effectiveUser $eUserID not found." unless $set; 201 202 my $psvn = $set->psvn(); 203 204 my $screenSetHeader = $set->set_header || $ce->{webworkFiles}->{screenSnippets}->{setHeader}; 205 my $displayMode = $r->param("displayMode") || $ce->{pg}->{options}->{displayMode}; 206 207 if (defined $r->param("editMode") and $r->param("editMode") eq "temporaryFile") { 208 $screenSetHeader = "$screenSetHeader.$userID.tmp"; 209 $displayMode = $r->param("displayMode") if $r->param("displayMode"); 210 } 211 212 return "" unless defined $screenSetHeader and $screenSetHeader; 213 214 # decide what to do about problem number 215 my $problem = WeBWorK::DB::Record::UserProblem->new( 216 problem_id => 0, 217 set_id => $set->set_id, 218 login_id => $effectiveUser->user_id, 219 source_file => $screenSetHeader, 220 # the rest of Problem's fields are not needed, i think 221 ); 222 223 my $pg = WeBWorK::PG->new( 224 $ce, 225 $effectiveUser, 226 $r->param('key'), 227 $set, 228 $problem, 229 $psvn, 230 {}, # no form fields! 231 { # translation options 232 displayMode => $displayMode, 233 showHints => 0, 234 showSolutions => 0, 235 processAnswers => 0, 236 }, 237 ); 238 239 if (defined($set) and $authz->hasPermissions($userID, "modify_problem_sets")) { 240 #FIXME ? can't edit the default set header this way 241 my $editorPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", 242 courseID => $courseID, setID => $set->set_id, problemID => 0); 243 my $editorURL = $self->systemLink($editorPage, params => { file_type => 'set_header'}); 244 245 print CGI::p(CGI::b("Set Info"), " ", 246 CGI::a({href=>$editorURL}, "[edit]")); 247 } else { 248 print CGI::p(CGI::b("Set Info")); 249 } 250 251 if ($pg->{flags}->{error_flag}) { 252 print CGI::div({class=>"ResultsWithError"}, $self->errorOutput($pg->{errors}, $pg->{body_text})); 253 } else { 254 print $pg->{body_text}; 255 } 256 257 return ""; 258 } 259 260 sub options { shift->optionsMacro } 261 262 sub body { 263 my ($self) = @_; 264 my $r = $self->r; 265 my $ce = $r->ce; 266 my $db = $r->db; 267 my $urlpath = $r->urlpath; 268 269 my $courseID = $urlpath->arg("courseID"); 270 my $setName = $urlpath->arg("setID"); 271 my $effectiveUser = $r->param('effectiveUser'); 272 273 my $set = $db->getMergedSet($effectiveUser, $setName); # checked 274 # FIXME: this was already caught in initialize() 275 # die "set $setName for user $effectiveUser not found" unless $set; 276 277 if ($self->{invalidSet}) { 278 return CGI::div({class=>"ResultsWithError"}, 279 CGI::p("The selected homework set ($setName) is not a valid set for $effectiveUser.")); 280 } 281 282 unless ($self->{isOpen}) { 283 return CGI::div({class=>"ResultsWithError"}, 284 CGI::p("This homework set is not available because it is not yet open.")); 285 } 286 287 #my $hardcopyURL = 288 # $ce->{webworkURLs}->{root} . "/" 289 # . $ce->{courseName} . "/" 290 # . "hardcopy/$setName/?" . $self->url_authen_args; 291 292 my $hardcopyPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Hardcopy", 293 courseID => $courseID, setID => $setName); 294 my $hardcopyURL = $self->systemLink($hardcopyPage); 295 296 print CGI::p(CGI::a({href=>$hardcopyURL}, "Download a hardcopy of this homework set.")); 297 298 my @problemNumbers = $db->listUserProblems($effectiveUser, $setName); 299 300 if (@problemNumbers) { 301 print CGI::start_table(); 302 print CGI::Tr( 303 CGI::th("Name"), 304 CGI::th("Attempts"), 305 CGI::th("Remaining"), 306 CGI::th("Worth"), 307 CGI::th("Status"), 308 ); 309 310 foreach my $problemNumber (sort { $a <=> $b } @problemNumbers) { 311 my $problem = $db->getMergedProblem($effectiveUser, $setName, $problemNumber); # checked 312 die "problem $problemNumber in set $setName for user $effectiveUser not found." unless $problem; 313 print $self->problemListRow($set, $problem); 314 } 315 316 print CGI::end_table(); 317 } else { 318 print CGI::p("This homework set contains no problems."); 319 } 320 321 ## feedback form 322 #my $ce = $self->{ce}; 323 #my $root = $ce->{webworkURLs}->{root}; 324 #my $courseName = $ce->{courseName}; 325 #my $feedbackURL = "$root/$courseName/feedback/"; 326 #print 327 # CGI::start_form(-method=>"POST", -action=>$feedbackURL),"\n", 328 # $self->hidden_authen_fields,"\n", 329 # CGI::hidden("module", __PACKAGE__),"\n", 330 # CGI::hidden("set", $self->{set}->set_id),"\n", 331 # CGI::hidden("problem", ""),"\n", 332 # CGI::hidden("displayMode", $self->{displayMode}),"\n", 333 # CGI::hidden("showOldAnswers", ''),"\n", 334 # CGI::hidden("showCorrectAnswers", ''),"\n", 335 # CGI::hidden("showHints", ''),"\n", 336 # CGI::hidden("showSolutions", ''),"\n", 337 # CGI::p({-align=>"left"}, 338 # CGI::submit(-name=>"feedbackForm", -label=>"Email instructor") 339 # ), 340 # CGI::endform(),"\n"; 341 342 # feedback form url 343 my $feedbackPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Feedback", 344 courseID => $courseID); 345 my $feedbackURL = $self->systemLink($feedbackPage, authen => 0); # no authen info for form action 346 347 #print feedback form 348 print 349 CGI::start_form(-method=>"POST", -action=>$feedbackURL),"\n", 350 $self->hidden_authen_fields,"\n", 351 CGI::hidden("module", __PACKAGE__),"\n", 352 CGI::hidden("set", $self->{set}->set_id),"\n", 353 CGI::hidden("problem", ''),"\n", 354 CGI::hidden("displayMode", $self->{displayMode}),"\n", 355 CGI::hidden("showOldAnswers", ''),"\n", 356 CGI::hidden("showCorrectAnswers", ''),"\n", 357 CGI::hidden("showHints", ''),"\n", 358 CGI::hidden("showSolutions", ''),"\n", 359 CGI::p({-align=>"left"}, 360 CGI::submit(-name=>"feedbackForm", -label=>"Email instructor") 361 ), 362 CGI::endform(),"\n"; 363 364 return ""; 365 } 366 367 sub problemListRow($$$) { 368 my ($self, $set, $problem) = @_; 369 my $r = $self->r; 370 my $urlpath = $r->urlpath; 371 372 my $courseID = $urlpath->arg("courseID"); 373 my $setID = $set->set_id; 374 my $problemID = $problem->problem_id; 375 376 my $interactiveURL = $self->systemLink( 377 $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem", 378 courseID => $courseID, setID => $setID, problemID => $problemID 379 ), 380 params=>{ displayMode => $self->{displayMode}, 381 showOldAnswers => $self->{will}->{showOldAnswers} 382 } 383 ); 384 385 my $interactive = CGI::a({-href=>$interactiveURL}, "Problem $problemID"); 386 my $attempts = $problem->num_correct + $problem->num_incorrect; 387 my $remaining = $problem->max_attempts < 0 388 ? "unlimited" 389 : $problem->max_attempts - $attempts; 390 my $rawStatus = $problem->status || 0; 391 my $status; 392 $status = eval{ sprintf("%.0f%%", $rawStatus * 100)}; # round to whole number 393 $status = 'unknown(FIXME)' if $@; # use a blank if problem status was not defined or not numeric. 394 # FIXME -- this may not cover all cases. 395 396 # my $msg = ($problem->value) ? "" : "(This problem will not count towards your grade.)"; 397 398 return CGI::Tr( 399 CGI::td({-nowrap=>1, -align=>"left"},$interactive), 400 CGI::td({-nowrap=>1, -align=>"center"}, 401 [ 402 $attempts, 403 $remaining, 404 $problem->value, 405 $status, 406 ])); 407 } 408 409 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |