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

View of /branches/rel-2-3-dev/webwork-modperl/lib/WeBWorK/ContentGenerator/ProblemSet.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4396 - (download) (as text) (annotate)
Thu Aug 24 21:07:52 2006 UTC (6 years, 9 months ago)
File size: 15247 byte(s)
This commit was manufactured by cvs2svn to create branch 'rel-2-3-dev'.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9