Parent Directory
|
Revision Log
set $main::VERSION to 2.2.
1 ################################################################################ 2 # WeBWorK Online Homework Delivery System 3 # Copyright © 2000-2006 The WeBWorK Project, http://openwebwork.sf.net/ 4 # $CVSHeader: webwork2/lib/WeBWorK.pm,v 1.79.2.1 2006/01/25 23:11:58 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; 18 19 =head1 NAME 20 21 WeBWorK - Dispatch requests to the appropriate content generator. 22 23 =head1 SYNOPSIS 24 25 my $r = Apache->request; 26 my $result = eval { WeBWorK::dispatch($r) }; 27 die "something bad happened: $@" if $@; 28 29 =head1 DESCRIPTION 30 31 C<WeBWorK> is the dispatcher for the WeBWorK system. Given an Apache request 32 object, it performs authentication and determines which subclass of 33 C<WeBWorK::ContentGenerator> to call. 34 35 =cut 36 37 BEGIN { $main::VERSION = "2.2"; } 38 39 use strict; 40 use warnings; 41 use Apache::Constants qw(:common REDIRECT DONE); 42 use Time::HiRes qw/time/; 43 44 # load WeBWorK::Constants before anything else 45 # this sets package variables in several packages 46 use WeBWorK::Constants; 47 48 # the rest of these are modules that are acutally used by this one 49 use WeBWorK::Authen; 50 use WeBWorK::Authz; 51 use WeBWorK::CourseEnvironment; 52 use WeBWorK::DB; 53 use WeBWorK::Debug; 54 use WeBWorK::Request; 55 use WeBWorK::Upload; 56 use WeBWorK::URLPath; 57 use WeBWorK::Utils qw(runtime_use writeTimingLogEntry); 58 59 use constant AUTHEN_MODULE => "WeBWorK::ContentGenerator::Login"; 60 use constant PROCTOR_AUTHEN_MODULE => "WeBWorK::ContentGenerator::LoginProctor"; 61 use constant FIXDB_MODULE => "WeBWorK::ContentGenerator::FixDB"; 62 63 our %SeedCE; 64 65 sub dispatch($) { 66 my ($apache) = @_; 67 my $r = new WeBWorK::Request $apache; 68 69 my $method = $r->method; 70 my $location = $r->location; 71 my $uri = $r->uri; 72 my $path_info = $r->path_info | ""; 73 my $args = $r->args || ""; 74 #my $webwork_root = $r->dir_config("webwork_root"); 75 #my $pg_root = $r->dir_config("pg_root"); 76 77 debug("\n\n===> Begin " . __PACKAGE__ . "::dispatch() <===\n\n"); 78 debug("Hi, I'm the new dispatcher!\n"); 79 debug(("-" x 80) . "\n"); 80 81 debug("Okay, I got some basic information:\n"); 82 debug("The apache location is $location\n"); 83 debug("The request method is $method\n"); 84 debug("The URI is $uri\n"); 85 debug("The path-info is $path_info\n"); 86 debug("The argument string is $args\n"); 87 #debug("The WeBWorK root directory is $webwork_root\n"); 88 #debug("The PG root directory is $pg_root\n"); 89 debug(("-" x 80) . "\n"); 90 91 debug("The first thing we need to do is munge the path a little:\n"); 92 93 my ($path) = $uri =~ m/$location(.*)/; 94 $path = "/" if $path eq ""; # no path at all 95 96 debug("We can't trust the path-info, so we make our own path.\n"); 97 debug("path-info claims: $path_info\n"); 98 debug("but it's really: $path\n"); 99 debug("(if it's empty, we set it to \"/\".)\n"); 100 101 $path =~ s|/+|/|g; 102 debug("...and here it is without repeated slashes: $path\n"); 103 104 # lookbehind assertion for "not a slash" 105 # matches the boundary after the last char 106 $path =~ s|(?<=[^/])$|/|; 107 debug("...and here it is with a trailing slash: $path\n"); 108 109 debug(("-" x 80) . "\n"); 110 111 debug("Now we need to look at the path a little to figure out where we are\n"); 112 113 debug("-------------------- call to WeBWorK::URLPath::newFromPath\n"); 114 my $urlPath = WeBWorK::URLPath->newFromPath($path); 115 debug("-------------------- call to WeBWorK::URLPath::newFromPath\n"); 116 117 unless ($urlPath) { 118 debug("This path is invalid... see you later!\n"); 119 die "The path '$path' is not valid.\n"; 120 } 121 122 my $displayModule = $urlPath->module; 123 my %displayArgs = $urlPath->args; 124 125 unless ($displayModule) { 126 debug("The display module is empty, so we can DECLINE here.\n"); 127 die "No display module found for path '$path'."; 128 } 129 130 debug("The display module for this path is: $displayModule\n"); 131 debug("...and here are the arguments we'll pass to it:\n"); 132 foreach my $key (keys %displayArgs) { 133 debug("\t$key => $displayArgs{$key}\n"); 134 } 135 136 my $selfPath = $urlPath->path; 137 my $parent = $urlPath->parent; 138 my $parentPath = $parent ? $parent->path : "<no parent>"; 139 140 debug("Reconstructing the original path gets us: $selfPath\n"); 141 debug("And we can generate the path to our parent, too: $parentPath\n"); 142 debug("(We could also figure out who our children are, but we'd need to supply additional arguments.)\n"); 143 debug(("-" x 80) . "\n"); 144 145 debug("The URLPath looks good, we'll add it to the request.\n"); 146 $r->urlpath($urlPath); 147 148 debug("Now we want to look at the parameters we got.\n"); 149 150 debug("The raw params:\n"); 151 foreach my $key ($r->param) { 152 debug("\t$key\n"); 153 debug("\t\t$_\n") foreach $r->param($key); 154 } 155 156 #mungeParams($r); 157 158 debug("The munged params:\n"); 159 foreach my $key ($r->param) { 160 debug("\t$key\n"); 161 debug("\t\t$_\n") foreach $r->param($key); 162 } 163 164 debug(("-" x 80) . "\n"); 165 166 debug("We need to get a course environment (with or without a courseID!)\n"); 167 my $ce = eval { new WeBWorK::CourseEnvironment({ 168 #webworkRoot => $r->dir_config("webwork_root"), 169 #webworkURLRoot => $location, 170 #pgRoot => $r->dir_config("pg_root"), 171 %SeedCE, 172 courseName => $displayArgs{courseID}, 173 }) }; 174 $@ and die "Failed to initialize course environment: $@\n"; 175 debug("Here's the course environment: $ce\n"); 176 $r->ce($ce); 177 178 my @uploads = $r->upload; 179 foreach my $u (@uploads) { 180 # make sure it's a "real" upload 181 next unless $u->filename; 182 183 # store the upload 184 my $upload = WeBWorK::Upload->store($u, 185 dir => $ce->{webworkDirs}->{uploadCache} 186 ); 187 188 # store the upload ID and hash in the file upload field 189 my $id = $upload->id; 190 my $hash = $upload->hash; 191 $r->param($u->name => "$id $hash"); 192 } 193 194 # create these out here. they should fail if they don't have the right information 195 # this lets us not be so careful about whether these objects are defined when we use them. 196 # instead, we just create the behavior that if they don't have a valid $db they fail. 197 my $authz = new WeBWorK::Authz($r); 198 $r->authz($authz); 199 my $authen = new WeBWorK::Authen($r); 200 $r->authen($authen); 201 202 my $db; 203 204 if ($displayArgs{courseID}) { 205 debug("We got a courseID from the URLPath, now we can do some stuff:\n"); 206 207 unless (-e $ce->{courseDirs}->{root}) { 208 die "Course '$displayArgs{courseID}' not found: $!"; 209 } 210 211 debug("...we can create a database object...\n"); 212 $db = new WeBWorK::DB($ce->{dbLayout}); 213 debug("(here's the DB handle: $db)\n"); 214 $r->db($db); 215 216 debug("Now we check the database...\n"); 217 debug("(we can detect if a hash-style database from WW1 has not be converted properly.)\n"); 218 my ($dbOK, @dbMessages) = $db->hashDatabaseOK(0); # 0 == don't fix 219 if (not $dbOK) { 220 debug("hashDatabaseOK() returned $dbOK -- looks like trouble...\n"); 221 $displayModule = FIXDB_MODULE; 222 debug("set displayModule to $displayModule\n"); 223 } else { 224 debug("hashDatabaseOK() returned $dbOK -- leaving displayModule as-is\n"); 225 } 226 227 my $authenOK = $authen->verify; 228 if ($authenOK) { 229 my $userID = $r->param("user"); 230 debug("Hi, $userID, glad you made it.\n"); 231 232 # tell authorizer to cache this user's permission level 233 $authz->setCachedUser($userID); 234 235 debug("Now we deal with the effective user:\n"); 236 my $eUserID = $r->param("effectiveUser") || $userID; 237 debug("userID=$userID eUserID=$eUserID\n"); 238 if ($userID ne $eUserID) { 239 debug("userID and eUserID differ... seeing if userID has 'become_student' permission.\n"); 240 my $su_authorized = $authz->hasPermissions($userID, "become_student"); 241 if ($su_authorized) { 242 debug("Ok, looks like you're allowed to become $eUserID. Whoopie!\n"); 243 } else { 244 debug("Uh oh, you're not allowed to become $eUserID. Nice try!\n"); 245 #$eUserID = $userID; 246 #$r->notes("authen_error" => "You do not have permission to become another user."); 247 #$displayModule = AUTHEN_MODULE; 248 die "You are not allowed to act as another user.\n"; 249 } 250 } 251 252 # set effectiveUser in case it was changed or not set to begin with 253 $r->param("effectiveUser" => $eUserID); 254 255 # if we're doing a proctored test, after the user has been authenticated 256 # we need to also check on the proctor. note that in the gateway quiz 257 # module we double check this, to be sure that someone isn't taking a 258 # proctored quiz but calling the unproctored ContentGenerator 259 my $urlProducedPath = $urlPath->path(); 260 if ( $urlProducedPath =~ /proctored_quiz_mode/i ) { 261 my $procAuthOK = $authen->verifyProctor(); 262 263 if ($procAuthOK) { 264 my $proctorUserID = $r->param("proctor_user"); 265 my $proctor_authorized = $authz->hasPermissions($proctorUserID, "proctor_quiz"); 266 unless ($proctor_authorized) { 267 $r->notes("authen_error", "User $proctorUserID is not authorized to proctor tests in this course."); 268 $displayModule = PROCTOR_AUTHEN_MODULE; 269 } 270 } else { 271 $displayModule = PROCTOR_AUTHEN_MODULE; 272 } 273 } 274 } else { 275 debug("Bad news: authentication failed!\n"); 276 $displayModule = AUTHEN_MODULE; 277 debug("set displayModule to $displayModule\n"); 278 } 279 } 280 281 # make fake authen/authz objects that just fail 282 $authen = 283 284 # store the time before we invoke the content generator 285 my $cg_start = time; # this is Time::HiRes's time, which gives floating point values 286 287 debug(("-" x 80) . "\n"); 288 debug("Finally, we'll load the display module...\n"); 289 290 runtime_use($displayModule); 291 292 debug("...instantiate it...\n"); 293 294 my $instance = $displayModule->new($r); 295 296 debug("...and call it:\n"); 297 debug("-------------------- call to ${displayModule}::go\n"); 298 299 my $result = $instance->go(); 300 301 debug("-------------------- call to ${displayModule}::go\n"); 302 303 my $cg_end = time; 304 my $cg_duration = $cg_end - $cg_start; 305 writeTimingLogEntry($ce, "[".$r->uri."]", sprintf("runTime = %.3f sec", $cg_duration)." ".$ce->{dbLayoutName}, ""); 306 307 debug("returning result: " . (defined $result ? $result : "UNDEF") . "\n"); 308 309 return $result; 310 } 311 312 sub mungeParams { 313 my ($r) = @_; 314 315 my @paramQueue; 316 317 # remove all the params from the request, and store them in the param queue 318 foreach my $key ($r->param) { 319 push @paramQueue, [ $key => [ $r->param($key) ] ]; 320 $r->parms->unset($key) 321 } 322 323 # exhaust the param queue, decoding encoded params 324 while (@paramQueue) { 325 my ($key, $values) = @{ shift @paramQueue }; 326 327 if ($key =~ m/\,/) { 328 # we have multiple params encoded in a single param 329 # split them up and add them to the end of the queue 330 push @paramQueue, map { [ $_, $values ] } split m/\,/, $key; 331 } elsif ($key =~ m/\:/) { 332 # we have a whole param encoded in a key 333 # split it up and add it to the end of the queue 334 my ($newKey, $newValue) = split m/\:/, $key; 335 push @paramQueue, [ $newKey, [ $newValue ] ]; 336 } else { 337 # this is a "normal" param 338 # add it to the param list 339 if (defined $r->param($key)) { 340 # the param already exists -- append the values we have 341 $r->param($key => [ $r->param($key), @$values ]); 342 } else { 343 # the param doesn't exist -- create it with the values we have 344 $r->param($key => $values); 345 } 346 } 347 } 348 } 349 350 351 =head1 AUTHOR 352 353 Written by Dennis Lambe, malsyned at math.rochester.edu. Modified by Sam 354 Hathaway, sh002i at math.rochester.edu. 355 356 =cut 357 358 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |