[system] / branches / rel-2-4-dev / webwork-modperl / lib / WeBWorK.pm Repository:
ViewVC logotype

View of /branches/rel-2-4-dev/webwork-modperl/lib/WeBWorK.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1796 - (download) (as text) (annotate)
Thu Feb 12 19:23:43 2004 UTC (9 years, 3 months ago) by toenail
Original Path: trunk/webwork-modperl/lib/WeBWorK.pm
File size: 15816 byte(s)
fixed incorrect error message parsing by Instructor/Index.pm

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK.pm,v 1.43 2004/01/25 19:56:09 gage 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 =head1 REQUEST FORMAT
   36 
   37  FIXME: write this part
   38  summary: the URI controls
   39 
   40 =cut
   41 
   42 BEGIN { $main::VERSION = "2.0"; }
   43 
   44 
   45 my $timingON = 1;
   46 
   47 use strict;
   48 use warnings;
   49 use Apache::Constants qw(:common REDIRECT DONE);
   50 use Apache::Request;
   51 use WeBWorK::Authen;
   52 use WeBWorK::Authz;
   53 use WeBWorK::CourseEnvironment;
   54 use WeBWorK::DB;
   55 use WeBWorK::Timing;
   56 use WeBWorK::Upload;
   57 use WeBWorK::Utils qw(runtime_use);
   58 
   59 =head1 THE C<&dispatch> FUNCTION
   60 
   61 The C<&dispatch> function takes an Apache request object (REQUEST) and returns
   62 an apache status code. Below is an overview of its operation:
   63 
   64 =over
   65 
   66 =cut
   67 
   68 sub dispatch($) {
   69   my ($apache) = @_;
   70   my $r = Apache::Request->new($apache);
   71     # have to deal with unpredictable GET or POST data, and sift
   72     # through it for the key. So use Apache::Request
   73 
   74   # This stuff is pretty much copied out of the O'Reilly mod_perl book.
   75   # It's for figuring out the basepath. I may change this up if I find a
   76   # better way to do it.
   77   my $path_info = $r->path_info || "";
   78   $path_info =~ s!/+!/!g; # strip multiple forward slashes
   79   my $current_uri = $r->uri;
   80   my $args = $r->args;
   81 
   82   my ($urlRoot) = $current_uri =~ m/^(.*)$path_info/;
   83 
   84 =item Ensure that the URI ends with a "/"
   85 
   86 Parts of WeBWorK assume that the current URI of a request ends with a "/". If
   87 this is not the case, a redirection is issued to add the "/". This action will
   88 discard any POST data associated with the request, so it is essential that all
   89 POST requests include a "/" at the end of the URI.
   90 
   91 =cut
   92 
   93   # If it's a valid WeBWorK URI, it ends in a /.  This is assumed
   94   # alllll over the place.
   95   unless (substr($current_uri,-1) eq '/') {
   96     $r->header_out(Location => "$current_uri/" . ($args ? "?$args" : ""));
   97     return REDIRECT;
   98     # *** any post data gets lost here -- fix that.
   99     # (actually, it's not a problem, since all URLs generated
  100     # from within the system have trailing slashes, and we don't
  101     # need POST data from outside the system anyway!)
  102   }
  103 
  104   # Create the @components array, which contains the path specified in the URL
  105   my($junk, @components) = split "/", $path_info;
  106   my $webwork_root = $r->dir_config('webwork_root'); # From a PerlSetVar in httpd.conf
  107   my $pg_root = $r->dir_config('pg_root'); # From a PerlSetVar in httpd.conf
  108   my $course = shift @components;
  109 
  110 =item Read the course environment
  111 
  112 C<WeBWorK::CourseEnvironment> is used to read the F<global.conf> configuration
  113 file. If a course name was given in the request's URI, it is passed to
  114 C<WeBWorK::CourseEnvironment>. In this case, the course-specific configuration
  115 file (usually F<course.conf>) is also read by C<WeBWorK::CourseEnvironment> at
  116 this point.
  117 
  118 See also L<WeBWorK::CourseEnvironment>.
  119 
  120 =cut
  121 
  122   # Try to get the course environment.
  123   my $ce = eval {WeBWorK::CourseEnvironment->new($webwork_root, $urlRoot, $pg_root, $course);};
  124   if ($@) { # If there was an error getting the requested course
  125     die "Failed to read course environment for $course: $@";
  126   }
  127 
  128 =item If no course was given, go to the site home page
  129 
  130 If the URI did not include the name of a course, a redirection is issued to the
  131 site home page, given but the course environemnt variable
  132 C<$ce-E<gt>{webworkURLs}-E<gt>{home}>.
  133 
  134 =cut
  135 
  136   # If no course was specified, redirect to the home URL
  137   unless (defined $course) {
  138     $r->header_out(Location => $ce->{webworkURLs}->{home});
  139     return REDIRECT;
  140   }
  141 
  142 =item If the given course does not exist, fail
  143 
  144 If the URI did include the name of a course, but the course directory was not
  145 found, an exception is thrown.
  146 
  147 =cut
  148 
  149   # Freak out if the requested course doesn't exist.  For now, this is just a
  150   # check to see if the course directory exists.
  151   my $courseDir = $ce->{webworkDirs}->{courses} . "/$course";
  152   unless (-e $courseDir) {
  153     die "Course directory for $course ($courseDir) not found. Perhaps the course does not exist?";
  154   }
  155 
  156 =item Initialize the database system
  157 
  158 A C<WeBWorK::DB> object is created from the current course environment.
  159 
  160 See also L<WeBWorK::DB>.
  161 
  162 =cut
  163 
  164   # Bring up a connection to the database (for Authen/Authz, and eventually
  165   # to be passed to content generators, when we clean this file up).
  166   my $db = WeBWorK::DB->new($ce->{dbLayout});
  167 
  168 =item Capture any uploads
  169 
  170 Before checking authentication, we store any uploads sent by the client
  171 and replace them with parameters referencing the stored uploads.
  172 
  173 =cut
  174 
  175   my @uploads = $r->upload;
  176   foreach my $u (@uploads) {
  177     # make sure it's a "real" upload
  178     next unless $u->filename;
  179 
  180     # store the upload
  181     my $upload = WeBWorK::Upload->store($u,
  182       dir => $ce->{webworkDirs}->{uploadCache}
  183     );
  184 
  185     # store the upload ID and hash in the file upload field
  186     my $id = $upload->id;
  187     my $hash = $upload->hash;
  188     $r->param($u->name => "$id $hash");
  189   }
  190 
  191 =item Check authentication
  192 
  193 Use C<WeBWorK::Authen> to verify that the remote user has authenticated.
  194 
  195 See also L<WeBWorK::Authen>.
  196 
  197 =cut
  198 
  199   ### Begin dispatching ###
  200 
  201   my $contentGenerator = "";
  202   my @arguments = ();
  203 
  204   # WeBWorK::Authen::verify erases the passwd field and sets the key field
  205   # if login is successful.
  206   if (!WeBWorK::Authen->new($r, $ce, $db)->verify) {
  207     $contentGenerator = "WeBWorK::ContentGenerator::Login";
  208     @arguments = ();
  209   }
  210   else {
  211 
  212 =item Determine if the user is allowed to set C<effectiveUser>
  213 
  214 Use C<WeBWorK::Authz> to determine if the user is allowed to set
  215 C<effectiveUser>. If so, set it to the requested value (or set it to the real
  216 user name if no value is supplied). If not, set it to the real user name.
  217 
  218 See also L<WeBWorK::Authz>.
  219 
  220 =cut
  221 
  222     # After we are authenticated, there are some things that need to be
  223     # sorted out, Authorization-wize, before we start dispatching to individual
  224     # content generators.
  225     my $user = $r->param("user");
  226     my $effectiveUser = $r->param("effectiveUser") || $user;
  227     my $authz = WeBWorK::Authz->new($r, $ce, $db);
  228     my $su_authorized = $authz->hasPermissions($user, "become_student", $effectiveUser);
  229     $effectiveUser = $user unless $su_authorized;
  230     $r->param("effectiveUser", $effectiveUser);
  231 
  232 =item Determine the appropriate subclass of C<WeBWorK::ContentGenerator> to call based on the URI.
  233 
  234 The dispatcher implements a virtual heirarchy that looks like this:
  235 
  236  $courseID ($courseID) - list of sets
  237   hardcopy (Hardcopy Generator) - generate hardcopy for user/set pairs
  238   options (User Options) - change email address and password
  239   feedback (Feedback) - send feedback to professor via email
  240   logout (Logout) - expire session and erase authentication tokens
  241   test (Test) - display request information
  242   quiz_mode (Quiz) - "quiz" containing all problems from a set
  243   instructor (Instructor Tools) - main menu for instructor tools
  244     add_users (Add Users) - to be removed
  245     scoring (Scoring Tools) - generate scoring files for problem sets
  246     scoringDownload - send a scoring file to the client
  247       scoring_totals - ???
  248     users (Users) - view/edit users
  249       $userID ($userID) - user detail for given user
  250         sets (Assigned Sets) - view/edit sets assigned to given user
  251     sets (Sets) - list of sets, add new sets, delete existing sets
  252       $setID - view/edit the given set
  253         problems (Problems) - view/edit problems in the given set
  254           $problemID - this is where the pg problem editor SHOULD be
  255         users (Users Assigned) - view/edit users to whom the given set is assigned
  256     pgProblemEditor (Problem Source) - edit the source of a problem
  257     send_mail (Mail Merge) - send mail to users in course
  258     show_answers (Answers Submitted) - show submitted answers
  259     stats (Statistics) - show statistics
  260     files (File Transfer) - transfer files to/from the client
  261   $setID ($setID) - list of problems in the given set
  262     $problemID ($problemID) - interactive display of problem
  263 
  264 =cut
  265 
  266     my $arg = shift @components;
  267     if (not defined $arg) { # We want the list of problem sets
  268       $contentGenerator = "WeBWorK::ContentGenerator::ProblemSets";
  269       @arguments = ();
  270     }
  271     elsif ($arg eq "hardcopy") {
  272       my $setID = shift @components;
  273       $contentGenerator = "WeBWorK::ContentGenerator::Hardcopy";
  274       @arguments = ($setID);
  275     }
  276     elsif ($arg eq "options") {
  277       $contentGenerator = "WeBWorK::ContentGenerator::Options";
  278       @arguments = ();
  279     }
  280     elsif ($arg eq "feedback") {
  281       $contentGenerator = "WeBWorK::ContentGenerator::Feedback";
  282       @arguments = ();
  283     }
  284     elsif ($arg eq "logout") {
  285       $contentGenerator = "WeBWorK::ContentGenerator::Logout";
  286       @arguments = ();
  287     }
  288     elsif ($arg eq "test") {
  289       $contentGenerator = "WeBWorK::ContentGenerator::Test";
  290       @arguments = ();
  291     }
  292     elsif ($arg eq "quiz_mode" ) {
  293       $contentGenerator = "WeBWorK::ContentGenerator::GatewayQuiz";
  294       @arguments = @components;
  295       }
  296       elsif ($arg eq "equation" ) {
  297         $contentGenerator = "WeBWorK::ContentGenerator::EquationDisplay";
  298         @arguments = @components;
  299     }
  300     elsif ($arg eq "instructor") {
  301       my $instructorArgument = shift @components;
  302 
  303       if (not defined $instructorArgument) {
  304         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::Index";
  305         @arguments = ();
  306       }
  307       elsif ($instructorArgument eq "add_users") {
  308         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::AddUsers";
  309         @arguments = ();
  310       }
  311       elsif ($instructorArgument eq "assigner") {
  312         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::Assigner";
  313         @arguments = ();
  314       }
  315       elsif ($instructorArgument eq "scoring") {
  316         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::Scoring";
  317         @arguments = ();
  318       }
  319 #       elsif ($instructorArgument eq "scoring_totals") {
  320 #         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ScoringTotals";
  321 #         @arguments = ();
  322 #       }
  323       elsif ($instructorArgument eq "scoringDownload") {
  324         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ScoringDownload";
  325         @arguments = ();
  326       }
  327       elsif ($instructorArgument eq "users") {
  328         my $userID = shift @components;
  329 
  330         if (defined $userID) {
  331           my $userArg = shift @components;
  332           if (defined $userArg) {
  333             if ($userArg eq "sets") {
  334               $contentGenerator = "WeBWorK::ContentGenerator::Instructor::SetsAssignedToUser";
  335               @arguments = ($userID);
  336             }
  337           }
  338           else {
  339             $contentGenerator = "WeBWorK::ContentGenerator::Instructor::UserDetail";
  340             @arguments = ($userID);
  341           }
  342         }
  343         else {
  344           $contentGenerator = "WeBWorK::ContentGenerator::Instructor::UserList";
  345           @arguments = ();
  346         }
  347       }
  348       elsif ($instructorArgument eq "sets") {
  349         my $setID = shift @components;
  350 
  351         if (defined $setID) {
  352           my $setArg = shift @components;
  353 
  354           if (defined $setArg) {
  355             if ($setArg eq "problems") {
  356               $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ProblemList";
  357               @arguments = ($setID);
  358             }
  359             elsif ($setArg eq "users") {
  360               $contentGenerator = "WeBWorK::ContentGenerator::Instructor::UsersAssignedToSet";
  361               @arguments = ($setID);
  362             }
  363           }
  364           else {
  365             $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ProblemSetEditor";
  366             @arguments = ($setID);
  367           }
  368         }
  369         else {
  370           $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ProblemSetList";
  371           @arguments = ();
  372 
  373         }
  374       }
  375       elsif ($instructorArgument eq "pgProblemEditor") {
  376         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::PGProblemEditor";
  377         @arguments = @components;
  378       }
  379       elsif ($instructorArgument eq "send_mail") {
  380         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::SendMail";
  381         @arguments = @components;
  382       }
  383       elsif ($instructorArgument eq "show_answers") {
  384         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::ShowAnswers";
  385         @arguments = @components;
  386       }
  387       elsif ($instructorArgument eq "stats") {
  388         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::Stats";
  389         @arguments = @components;
  390       }
  391       elsif ($instructorArgument eq "files") {
  392         $contentGenerator = "WeBWorK::ContentGenerator::Instructor::FileXfer";
  393         @arguments = @components;
  394       }
  395     }
  396     else {
  397       # $arg is a set ID
  398       my $setID = $arg;
  399       my $problemID = shift @components;
  400 
  401       # check that the set is valid
  402       if (grep /$setID/, $db->listUserSets($effectiveUser)) {
  403         if (defined $problemID) {
  404           # check that the problem is valid for this set
  405           if (grep /$problemID/, $db->listUserProblems($effectiveUser, $setID)) {
  406             $contentGenerator = "WeBWorK::ContentGenerator::Problem";
  407             @arguments = ($setID, $problemID);
  408           }
  409           else {
  410             $contentGenerator = "WeBWorK::ContentGenerator::Error";
  411             @arguments = ($setID, "$problemID (error)", "Problem $problemID is not a valid problem in set $setID", "The problem number ($problemID) entered in the URL in your web browser does not seem to be a valid problem for the current set ($setID).  Please check to make sure that the problem number was entered correctly.  If you believe this error was generated mistakenly, please report it to your professor.  You can view a list of sets by clicking on the link \"Problem Sets\" on the left.");
  412           }
  413         }
  414         else {
  415           $contentGenerator = "WeBWorK::ContentGenerator::ProblemSet";
  416           @arguments = ($setID);
  417         }
  418 
  419       }
  420       else {
  421         $contentGenerator = "WeBWorK::ContentGenerator::Error";
  422         @arguments = ("$setID (error)", "$problemID (error)", "$setID is not a valid set for user $user", "The set ($setID) entered in the URL in your web browser does not seem to be a valid set for the current user.  Please check to make sure that the set was entered correctly.  If you believe this error was generated mistakenly, please report it to your professor.");
  423       }
  424 
  425     }
  426   }
  427 
  428 =item Call the selected content generator
  429 
  430 Instantiate the selected subclass of content generator and call its C<&go> method. Store the result.
  431 
  432 =cut
  433 
  434   my $result;
  435   if ($contentGenerator) {
  436     runtime_use($contentGenerator);
  437     my $cg = $contentGenerator->new($r, $ce, $db);
  438     @arguments = () unless  @arguments;
  439     $WeBWorK::timer = WeBWorK::Timing->new("${contentGenerator}::go(@arguments)") if $timingON == 1;
  440     $WeBWorK::timer->start if $timingON == 1;
  441 
  442     $result = $cg->go(@arguments);
  443 
  444     $WeBWorK::timer->stop if $timingON == 1;
  445     $WeBWorK::timer->save if $timingON == 1;
  446   } else {
  447     $result = NOT_FOUND;
  448   }
  449 
  450 =item Return the result of calling the content generator
  451 
  452 The return value of the content generator's C<&go> function is returned.
  453 
  454 =cut
  455 
  456   return $result;
  457 }
  458 
  459 =back
  460 
  461 =head1 AUTHOR
  462 
  463 Written by Dennis Lambe, malsyned at math.rochester.edu. Modified by Sam
  464 Hathaway, sh002i at math.rochester.edu.
  465 
  466 =cut
  467 
  468 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9