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

View of /branches/rel-2-3-dev/webwork-modperl/lib/WeBWorK/ContentGenerator/ProblemSets.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: 15563 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: webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm,v 1.79 2006/07/14 21:25:11 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::ProblemSets;
   18 use base qw(WeBWorK::ContentGenerator);
   19 
   20 =head1 NAME
   21 
   22 WeBWorK::ContentGenerator::ProblemSets - Display a list of built problem sets.
   23 
   24 =cut
   25 
   26 use strict;
   27 use warnings;
   28 #use CGI qw(-nosticky );
   29 use WeBWorK::CGI;
   30 use WeBWorK::Debug;
   31 use WeBWorK::Utils qw(readFile sortByName path_is_subdir);
   32 
   33 # what do we consider a "recent" problem set?
   34 use constant RECENT => 2*7*24*60*60 ; # Two-Weeks in seconds
   35 
   36 sub info {
   37   my ($self) = @_;
   38   my $r = $self->r;
   39   my $ce = $r->ce;
   40   my $db = $r->db;
   41   my $urlpath = $r->urlpath;
   42   my $authz = $r->authz;
   43 
   44   my $courseID = $urlpath->arg("courseID");
   45   my $user = $r->param("user");
   46 
   47   my $course_info = $ce->{courseFiles}->{course_info};
   48 
   49   if (defined $course_info and $course_info) {
   50     my $course_info_path = $ce->{courseDirs}->{templates} . "/$course_info";
   51 
   52     print CGI::start_div({class=>"info-box", id=>"InfoPanel"});
   53 
   54     # deal with instructor crap
   55     my $editorURL;
   56     if ($authz->hasPermissions($user, "access_instructor_tools")) {
   57       if (defined $r->param("editMode") and $r->param("editMode") eq "temporaryFile") {
   58         $course_info_path = $r->param("sourceFilePath");
   59         $course_info_path = $ce->{courseDirs}{templates}.'/'.$course_info_path unless $course_info_path =~ m!^/!;
   60         die "sourceFilePath is unsafe!" unless path_is_subdir($course_info_path, $ce->{courseDirs}->{templates});
   61         $self->addmessage(CGI::div({class=>'temporaryFile'}, "Viewing temporary file: ", $course_info_path));
   62       }
   63 
   64       my $editorPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor", courseID => $courseID);
   65       $editorURL = $self->systemLink($editorPage, params => { file_type => "course_info" });
   66     }
   67 
   68     if ($editorURL) {
   69       print CGI::h2("Course Info", CGI::a({href=>$editorURL, target=>"WW_Editor"}, "[edit]"));
   70     } else {
   71       print CGI::h2("Course Info");
   72     }
   73 
   74     if (-f $course_info_path) { #check that it's a plain  file
   75       my $text = eval { readFile($course_info_path) };
   76       if ($@) {
   77         print CGI::div({class=>"ResultsWithError"},
   78           CGI::p("$@"),
   79         );
   80       } else {
   81         print $text;
   82       }
   83     }
   84 
   85     print CGI::end_div();
   86 
   87     return "";
   88   }
   89 }
   90 sub help {   # non-standard help, since the file path includes the course name
   91   my $self = shift;
   92   my $args = shift;
   93   my $name = $args->{name};
   94   $name = lc('course home') unless defined($name);
   95   $name =~ s/\s/_/g;
   96   $self->helpMacro($name);
   97 }
   98 sub initialize {
   99 
  100 
  101 
  102 # get result and send to message
  103   my ($self) = @_;
  104   my $r = $self->r;
  105   my $authz = $r->authz;
  106   my $urlpath = $r->urlpath;
  107 
  108   my $user               = $r->param("user");
  109   my $effectiveUser      = $r->param("effectiveUser");
  110   if ($authz->hasPermissions($user, "access_instructor_tools")) {
  111     # get result and send to message
  112     my $status_message = $r->param("status_message");
  113     $self->addmessage(CGI::p("$status_message")) if $status_message;
  114 
  115 
  116   }
  117 }
  118 sub body {
  119   my ($self) = @_;
  120   my $r = $self->r;
  121   my $ce = $r->ce;
  122   my $db = $r->db;
  123   my $authz = $r->authz;
  124   my $urlpath = $r->urlpath;
  125 
  126   my $user            = $r->param("user");
  127   my $effectiveUser   = $r->param("effectiveUser");
  128   my $sort            = $r->param("sort") || "status";
  129 
  130   my $courseName      = $urlpath->arg("courseID");
  131 
  132   my $hardcopyPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Hardcopy", courseID => $courseName);
  133   my $actionURL = $self->systemLink($hardcopyPage, authen => 0); # no authen info for form action
  134 
  135 # we have to get sets and versioned sets separately
  136   my @setIDs = $db->listUserSets($effectiveUser);
  137   my @vSetIDs = $db->listUserSetVersions($effectiveUser);
  138 
  139   my @userSetIDs = map {[$effectiveUser, $_]} @setIDs;
  140   my @vUserSetIDs = map {[$effectiveUser, /(.*),v\d+$/, $_]} @vSetIDs;
  141   debug("Begin collecting merged sets");
  142   my @sets = $db->getMergedSets( @userSetIDs );
  143   my @vSets = (@vSetIDs) ? $db->getMergedVersionedSets(@vUserSetIDs) : ();
  144 
  145   debug("Begin fixing merged sets");
  146 
  147   # Database fix (in case of undefined published values)
  148   # this may take some extra time the first time but should NEVER need to be run twice
  149   # this is only necessary because some people keep holding to ww1.9 which did not have a published field
  150   foreach my $set (@sets) {
  151     # make sure published is set to 0 or 1
  152     if ( $set and $set->published ne "0" and $set->published ne "1") {
  153       my $globalSet = $db->getGlobalSet($set->set_id);
  154       $globalSet->published("1"); # defaults to published
  155       $db->putGlobalSet($globalSet);
  156       $set = $db->getMergedSet($effectiveUser, $set->set_id);
  157     } else {
  158       die "set $set not defined" unless $set;
  159     }
  160   }
  161 
  162 # gateways/versioned sets require dealing with output data slightly
  163 # differently, so check for those here
  164   debug("Begin set-type check");
  165   my $existVersions = 0;
  166   my @gwSets = ();
  167   my @nonGWsets = ();
  168   foreach ( @sets ) {
  169       if ( defined( $_->assignment_type() ) &&
  170      $_->assignment_type() =~ /gateway/ ) {
  171     $existVersions = 1;
  172     push( @gwSets, $_ )
  173         if ( $_->assignment_type() !~ /proctored/ ||
  174        $authz->hasPermissions($user,"view_proctored_tests") );
  175       } else {
  176     push( @nonGWsets, $_ );
  177       }
  178   }
  179 
  180 # set sort method
  181   $sort = "status" unless $sort eq "status" or $sort eq "name";
  182 
  183 # now set the headers for the table
  184   my $nameHeader = $sort eq "name"
  185     ? CGI::u("Name")
  186     : CGI::a({href=>$self->systemLink($urlpath, params=>{sort=>"name"})}, "Name");
  187   my $statusHeader = $sort eq "status"
  188     ? CGI::u("Status")
  189     : CGI::a({href=>$self->systemLink($urlpath, params=>{sort=>"status"})}, "Status");
  190 # print the start of the form
  191 
  192     print CGI::start_form(-method=>"POST",-action=>$actionURL),
  193           $self->hidden_authen_fields;
  194 
  195 # and send the start of the table
  196   print CGI::start_table();
  197   if ( ! $existVersions ) {
  198       print CGI::Tr({},
  199         CGI::th("Sel."),
  200         CGI::th($nameHeader),
  201         CGI::th($statusHeader),
  202           );
  203   } else {
  204       print CGI::Tr(
  205         CGI::th("Sel."),
  206         CGI::th($nameHeader),
  207         CGI::th("Score"),
  208         CGI::th("Date"),
  209         CGI::th($statusHeader),
  210           );
  211   }
  212 
  213   debug("Begin sorting merged sets");
  214 
  215   if ( $sort eq 'name' ) {
  216       @nonGWsets = sortByName("set_id", @nonGWsets);
  217       @gwSets = sortByName("set_id", @gwSets);
  218   } elsif ( $sort eq 'status' ) {
  219       @nonGWsets = sort byUrgency  @nonGWsets;
  220       @gwSets = sort byUrgency @gwSets;
  221   }
  222 # we sort set versions by name; this at least in part relies on versions
  223 # being finished by the time they show up on the list here.
  224   @vSets = sortByName("set_id", @vSets);
  225 
  226 # put together a complete list of sorted sets to consider
  227   @sets = (@nonGWsets, @gwSets, @vSets);
  228 
  229   debug("End preparing merged sets");
  230 
  231   foreach my $set (@sets) {
  232     die "set $set not defined" unless $set;
  233 
  234     if ($set->published || $authz->hasPermissions($user, "view_unpublished_sets")) {
  235       print $self->setListRow($set, $authz->hasPermissions($user, "view_multiple_sets"), $authz->hasPermissions($user, "view_unopened_sets"),$existVersions,$db);
  236     }
  237   }
  238 
  239   print CGI::end_table();
  240   my $pl = ($authz->hasPermissions($user, "view_multiple_sets") ? "s" : "");
  241   print CGI::p(CGI::submit(-name=>"hardcopy", -label=>"Download Hardcopy for Selected Set$pl"));
  242   print CGI::endform();
  243 
  244   ## feedback form url
  245   #my $feedbackPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::Feedback", courseID => $courseName);
  246   #my $feedbackURL = $self->systemLink($feedbackPage, authen => 0); # no authen info for form action
  247   #
  248   ##print feedback form
  249   #print
  250   # CGI::start_form(-method=>"POST", -action=>$feedbackURL),"\n",
  251   # $self->hidden_authen_fields,"\n",
  252   # CGI::hidden("module",             __PACKAGE__),"\n",
  253   # CGI::hidden("set",                ''),"\n",
  254   # CGI::hidden("problem",            ''),"\n",
  255   # CGI::hidden("displayMode",        ''),"\n",
  256   # CGI::hidden("showOldAnswers",     ''),"\n",
  257   # CGI::hidden("showCorrectAnswers", ''),"\n",
  258   # CGI::hidden("showHints",          ''),"\n",
  259   # CGI::hidden("showSolutions",      ''),"\n",
  260   # CGI::p({-align=>"left"},
  261   #   CGI::submit(-name=>"feedbackForm", -label=>"Email instructor")
  262   # ),
  263   # CGI::endform(),"\n";
  264 
  265   print $self->feedbackMacro(
  266     module => __PACKAGE__,
  267     set => "",
  268     problem => "",
  269     displayMode => "",
  270     showOldAnswers => "",
  271     showCorrectAnswers => "",
  272     showHints => "",
  273     showSolutions => "",
  274   );
  275 
  276   return "";
  277 }
  278 
  279 sub setListRow {
  280   my ($self, $set, $multiSet, $preOpenSets, $existVersions, $db) = @_;
  281   my $r = $self->r;
  282   my $ce = $r->ce;
  283   my $urlpath = $r->urlpath;
  284 
  285   my $name = $set->set_id;
  286   my $courseName      = $urlpath->arg("courseID");
  287 
  288   my $problemSetPage;
  289 
  290   if ( ! defined( $set->assignment_type() ) ||
  291        $set->assignment_type() !~ /gateway/ ) {
  292       $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSet",
  293               courseID => $courseName, setID => $name);
  294   } elsif( $set->assignment_type() !~ /proctored/ ) {
  295 
  296       $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::GatewayQuiz",
  297               courseID => $courseName, setID => $name);
  298   } else {
  299 
  300       $problemSetPage = $urlpath->newFromModule("WeBWorK::ContentGenerator::GatewayQuiz",
  301               courseID => $courseName, setID => $name);
  302   }
  303 
  304   my $interactiveURL = $self->systemLink($problemSetPage,
  305                                          params=>{  displayMode => $self->{displayMode},
  306                             showOldAnswers => $self->{will}->{showOldAnswers}
  307                        }
  308   );
  309   # check for gateway and template gateway assignments
  310   my $gwtype = 0;
  311   if ( defined( $set->assignment_type() ) &&
  312        $set->assignment_type() =~ /gateway/ ) {
  313       if ( $name =~ /,v\d+$/ ) {
  314     $gwtype = 1;
  315       } else {
  316     $gwtype = 2;
  317       }
  318   }
  319 
  320   # the conditional here should be redundant.  ah well.
  321   $interactiveURL =~ s|/quiz_mode/|/proctored_quiz_mode/| if
  322       ( defined( $set->assignment_type() ) &&
  323         $set->assignment_type() eq 'proctored_gateway' );
  324 
  325   my $control = "";
  326   if ($multiSet) {
  327     if ( $gwtype < 2 ) {
  328       $control = CGI::checkbox(
  329         -name=>"selected_sets",
  330         -value=>$name,
  331         -label=>"",
  332       );
  333     } else {
  334       $control = '&nbsp;';
  335     }
  336   } else {
  337     if ( $gwtype < 2 ) {
  338       $control = CGI::radio_group(
  339         -name=>"selected_sets",
  340         -values=>[$name],
  341         -default=>"-",
  342         -labels=>{$name => ""},
  343       );
  344     } else {
  345       $control = '&nbsp;';
  346     }
  347   }
  348 
  349   $name =~ s/_/&nbsp;/g;
  350   my $interactive = CGI::a({-href=>$interactiveURL}, "$name");
  351 # edit this a bit for gateways
  352   if ( $gwtype ) {
  353       if ( $gwtype == 1 ) {
  354     my $sname = $name;
  355     $sname =~ s/,v(\d+)$//;
  356     $interactive = CGI::a({-href=>$interactiveURL},
  357               "$sname (test$1)");
  358       } else {  # this is the case of a template URL
  359     $interactive = CGI::a({-href=>$interactiveURL},
  360               "Take new $name test");
  361       }
  362   }
  363 
  364 # for gateways, we aren't as verbose about open/closed status, because
  365 #    there's only one attempt and we default to showing answers once the
  366 #    test is done.
  367   my $status;
  368   if ( $gwtype ) {
  369       if ( $gwtype == 1 ) {
  370     $status = ' ';  # for g/w, we only give one attempt per version,
  371                                 #    so by the time we're here it's closed
  372       } else {
  373     my $t = time();
  374     if ( $t < $set->open_date() ) {
  375         $status = "will open on " . $self->formatDateTime($set->open_date);
  376         $control = "" unless $preOpenSets;
  377         $interactive = $name unless $preOpenSets;
  378     } elsif ( $t < $set->due_date() ) {
  379         $status = "open, due " . $self->formatDateTime($set->due_date);
  380     } else {
  381         $status = "closed";
  382     }
  383       }
  384 # old conditional
  385   } elsif (time < $set->open_date) {
  386     $status = "will open on " . $self->formatDateTime($set->open_date);
  387     $control = "" unless $preOpenSets;
  388     $interactive = $name unless $preOpenSets;
  389   } elsif (time < $set->due_date) {
  390            if ( $set->set_id() !~ /,v\d+$/ ) {
  391           $status = "now open, due " . $self->formatDateTime($set->due_date);
  392       } else {
  393     $status = "now open (if version attempts remain), due " . $self->formatDateTime($set->due_date);
  394       }
  395   } elsif (time < $set->answer_date) {
  396     $status = "closed, answers on " . $self->formatDateTime($set->answer_date);
  397   } elsif ($set->answer_date <= time and time < $set->answer_date +RECENT ) {
  398     $status = "closed, answers recently available";
  399   } else {
  400     $status = "closed, answers available";
  401   }
  402 
  403   my $publishedClass = ($set->published) ? "Published" : "Unpublished";
  404 
  405   $status = CGI::font({class=>$publishedClass}, $status) if $preOpenSets;
  406 
  407 # check to see if we need to return a score and a date column
  408   if ( ! $existVersions ) {
  409       return CGI::Tr(CGI::td([
  410            $control,
  411                              $interactive,
  412                  $status,
  413       ]));
  414   } else {
  415       my ( $startTime, $score );
  416 
  417     if ( defined( $set->assignment_type() ) &&
  418      $set->assignment_type() =~ /gateway/ &&
  419      $set->set_id() =~ /,v\d+$/ ) {
  420       $startTime = localtime( $set->version_creation_time() );
  421 
  422       # find score
  423       my @problemRecords = $db->getAllUserProblems( $set->user_id(),
  424                     $set->set_id() );
  425       my $possible = 0;
  426       $score = 0;
  427       foreach my $pRec ( @problemRecords ) {
  428         if ( defined( $pRec ) && $score ne 'undef' ) {
  429           $score += $pRec->status() || 0;
  430         } else {
  431           $score = 'undef';
  432         }
  433         $possible++;
  434       }
  435       $score = "$score/$possible";
  436     } else {
  437       $startTime = '&nbsp;';
  438       $score = $startTime;
  439     }
  440     return CGI::Tr(CGI::td([
  441                          $control,
  442                          $interactive,
  443                          $score,
  444                          $startTime,
  445                          $status,
  446     ]));
  447   }
  448 }
  449 
  450 sub byname { $a->set_id cmp $b->set_id; }
  451 
  452 sub byUrgency {
  453   my $mytime = time;
  454   my @a_parts = ($a->answer_date + RECENT <= $mytime) ?  (4, $a->open_date, $a->due_date, $a->set_id)
  455     : ($a->answer_date <= $mytime and $mytime < $a->answer_date + RECENT) ? (3, $a-> answer_date, $a-> due_date, $a->set_id)
  456     : ($a->due_date <= $mytime and $mytime < $a->answer_date ) ? (2, $a->answer_date, $a->due_date, $a->set_id)
  457     : ($mytime < $a->open_date) ? (1, $a->open_date, $a->due_date, $a->set_id)
  458     : (0, $a->due_date, $a->open_date, $a->set_id);
  459   my @b_parts = ($b->answer_date + RECENT <= $mytime) ?  (4, $b->open_date, $b->due_date, $b->set_id)
  460     : ($b->answer_date <= $mytime and $mytime < $b->answer_date + RECENT) ? (3, $b-> answer_date, $b-> due_date, $b->set_id)
  461     : ($b->due_date <= $mytime and $mytime < $b->answer_date ) ? (2, $b->answer_date, $b->due_date, $b->set_id)
  462     : ($mytime < $b->open_date) ? (1, $b->open_date, $b->due_date, $b->set_id)
  463     : (0, $b->due_date, $b->open_date, $b->set_id);
  464   my $returnIt=0;
  465   while (scalar(@a_parts) > 1) {
  466     if ($returnIt = ( (shift @a_parts) <=> (shift @b_parts) ) ) {
  467       return($returnIt);
  468     }
  469   }
  470   return (  $a_parts[0] cmp  $b_parts[0] );
  471 }
  472 
  473 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9