[system] / branches / rel-2-1-a1 / webwork2 / lib / WeBWorK / ContentGenerator / Instructor.pm Repository:
ViewVC logotype

View of /branches/rel-2-1-a1/webwork2/lib/WeBWorK/ContentGenerator/Instructor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2555 - (download) (as text) (annotate)
Tue Jul 27 22:36:57 2004 UTC (8 years, 10 months ago) by gage
File size: 17299 byte(s)
Allows .html, .gif, .png, .txt as well as .pg files to be uploaded and downloaded from
the template directory and files under it.  Still can't upload/download to the html directory

This is not a final solution, but a hack that make workarounds for many operations possible
for those who do not have direct unix access.  It's still too clunky, but it's a start.

--Mike

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader$
    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::Instructor;
   18 use base qw(WeBWorK::ContentGenerator);
   19 
   20 =head1 NAME
   21 
   22 WeBWorK::ContentGenerator::Instructor - Abstract superclass for the Instructor
   23 tools, providing useful utility functions.
   24 
   25 =cut
   26 
   27 use strict;
   28 use warnings;
   29 use CGI qw();
   30 use File::Find;
   31 use WeBWorK::DB::Utils qw(initializeUserProblem);
   32 use WeBWorK::Utils;
   33 
   34 =head1 METHODS
   35 
   36 =cut
   37 
   38 ################################################################################
   39 # Primary assignment methods
   40 ################################################################################
   41 
   42 =head2 Primary assignment methods
   43 
   44 =over
   45 
   46 =item assignSetToUser($userID, $GlobalSet)
   47 
   48 Assigns the given set and all problems contained therein to the given user. If
   49 the set (or any problems in the set) are already assigned to the user, a list of
   50 failure messages is returned.
   51 
   52 =cut
   53 
   54 sub assignSetToUser {
   55   my ($self, $userID, $GlobalSet) = @_;
   56   my $setID = $GlobalSet->set_id;
   57   my $db = $self->{db};
   58 
   59   my $UserSet = $db->newUserSet;
   60   $UserSet->user_id($userID);
   61   $UserSet->set_id($setID);
   62 
   63   my @results;
   64   my $set_assigned = 0;
   65 
   66   eval { $db->addUserSet($UserSet) };
   67   if ($@) {
   68     if ($@ =~ m/user set exists/) {
   69       push @results, "set $setID is already assigned to user $userID.";
   70       $set_assigned = 1;
   71     } else {
   72       die $@;
   73     }
   74   }
   75 
   76   my @GlobalProblems = grep { defined $_ } $db->getAllGlobalProblems($setID);
   77   foreach my $GlobalProblem (@GlobalProblems) {
   78     my @result = $self->assignProblemToUser($userID, $GlobalProblem);
   79     push @results, @result if @result and not $set_assigned;
   80   }
   81 
   82   return @results;
   83 }
   84 
   85 sub assignSetVersionToUser {
   86     my ( $self, $userID, $GlobalSet ) = @_;
   87 # in:  ($self,) $userID = the userID of the user to which to assign the set,
   88 #      $GlobalSet = the global set object.
   89 # out: a new set version is assigned to the user.
   90 # note: we assume that the global set and user are well defined.  I think this
   91 #    is a safe assumption.  it would be nice to just call assignSetToUser,
   92 #    but we run into trouble doing that because of the distinction between
   93 #    the setID and the setVersionID
   94 
   95     my $setID = $GlobalSet->set_id;
   96     my $db = $self->{db};
   97 
   98 # figure out what version we're on, reset setID, get a new user set
   99     my $setVersionNum = $db->getUserSetVersionNumber( $userID, $setID );
  100     $setVersionNum++;
  101     my $setVersionID = "$setID,v$setVersionNum";
  102     my $userSet = $db->newUserSet;
  103     $userSet->user_id( $userID );
  104     $userSet->set_id( $setVersionID );
  105 
  106     my @results = ();
  107     my $set_assigned = 0;
  108 
  109 # add the set to the database
  110     eval( $db->addVersionedUserSet( $userSet ) );
  111     if ( $@ ) {
  112   if ( $@ =~ m/user set exists/ ) {
  113       push( @results, "set $setVersionID is already assigned to user " .
  114       "$userID" );
  115       $set_assigned = 1;
  116   } else {
  117       die $@;
  118   }
  119     }
  120 
  121 # populate set with problems
  122     my @GlobalProblems = grep { defined $_ } $db->getAllGlobalProblems($setID);
  123 
  124     foreach my $GlobalProblem ( @GlobalProblems ) {
  125   $GlobalProblem->set_id( $setVersionID );
  126 # this is getting called from within ContentGenerator, so that $self
  127 #    isn't an Instructor object---therefore, calling $self->assign...
  128 #    doesn't work.  the following is an ugly workaround that works b/c
  129 #    both Instructor and ContentGenerator objects have $self->{db}
  130 # FIXME  it would be nice to have a better solution to this
  131 # my @result =
  132 #     $self->assignProblemToUser( $userID, $GlobalProblem );
  133   my @result =
  134       assignProblemToUserSetVersion( $self, $userID, $userSet,
  135                        $GlobalProblem );
  136   push( @results, @result ) if ( @result && not $set_assigned );
  137     }
  138 
  139     return @results;
  140 }
  141 
  142 =item unassignSetFromUser($userID, $setID, $problemID)
  143 
  144 Unassigns the given set and all problems therein from the given user.
  145 
  146 =cut
  147 
  148 sub unassignSetFromUser {
  149   my ($self, $userID, $setID) = @_;
  150   my $db = $self->{db};
  151 
  152   $db->deleteUserSet($userID, $setID);
  153 }
  154 
  155 =item assignProblemToUser($userID, $GlobalProblem)
  156 
  157 Assigns the given problem to the given user. If the problem is already assigned
  158 to the user, an error string is returned.
  159 
  160 =cut
  161 
  162 sub assignProblemToUser {
  163   my ($self, $userID, $GlobalProblem) = @_;
  164   my $db = $self->{db};
  165 
  166   my $UserProblem = $db->newUserProblem;
  167   $UserProblem->user_id($userID);
  168   $UserProblem->set_id($GlobalProblem->set_id);
  169   $UserProblem->problem_id($GlobalProblem->problem_id);
  170   initializeUserProblem($UserProblem);
  171 
  172   eval { $db->addUserProblem($UserProblem) };
  173   if ($@) {
  174     if ($@ =~ m/user problem exists/) {
  175       return "problem " . $GlobalProblem->problem_id
  176         . " in set " . $GlobalProblem->set_id
  177         . " is already assigned to user $userID.";
  178     } else {
  179       die $@;
  180     }
  181   }
  182 
  183   return ();
  184 }
  185 
  186 sub assignProblemToUserSetVersion {
  187   my ($self, $userID, $userSet, $GlobalProblem) = @_;
  188   my $db = $self->{db};
  189 
  190   my $UserProblem = $db->newUserProblem;
  191   $UserProblem->user_id($userID);
  192   $UserProblem->set_id($userSet->set_id);
  193   $UserProblem->problem_id($GlobalProblem->problem_id);
  194   initializeUserProblem($UserProblem);
  195 
  196   eval { $db->addUserProblem($UserProblem) };
  197   if ($@) {
  198     if ($@ =~ m/user problem exists/) {
  199       return "problem " . $GlobalProblem->problem_id
  200         . " in set " . $GlobalProblem->set_id
  201         . " is already assigned to user $userID.";
  202     } else {
  203       die $@;
  204     }
  205   }
  206 
  207   return();
  208 }
  209 
  210 =item unassignProblemFromUser($userID, $setID, $problemID)
  211 
  212 Unassigns the given problem from the given user.
  213 
  214 =cut
  215 
  216 sub unassignProblemFromUser {
  217   my ($self, $userID, $setID, $problemID) = @_;
  218   my $db = $self->{db};
  219 
  220   $db->deleteUserProblem($userID, $setID, $problemID);
  221 }
  222 
  223 =back
  224 
  225 =cut
  226 
  227 ################################################################################
  228 # Secondary set assignment methods
  229 ################################################################################
  230 
  231 =head2 Secondary assignment methods
  232 
  233 =over
  234 
  235 =item assignSetToAllUsers($setID)
  236 
  237 Assigns the set specified and all problems contained therein to all users in
  238 the course. This is more efficient than repeatedly calling assignSetToUser().
  239 If any assignments fail, a list of failure messages is returned.
  240 
  241 =cut
  242 
  243 sub assignSetToAllUsers {
  244   my ($self, $setID) = @_;
  245   my $db = $self->{db};
  246   my @userIDs = $db->listUsers;
  247 
  248   $WeBWorK::timer->continue("$setID: getting user list") if defined $WeBWorK::timer;
  249   my @userRecords = $db->getUsers(@userIDs);
  250   $WeBWorK::timer->continue("$setID: (done with that)") if defined $WeBWorK::timer;
  251 
  252   $WeBWorK::timer->continue("$setID: getting problem list") if defined $WeBWorK::timer;
  253   my @GlobalProblems = grep { defined $_ } $db->getAllGlobalProblems($setID);
  254   $WeBWorK::timer->continue("$setID: (done with that)") if defined $WeBWorK::timer;
  255 
  256   my @results;
  257 
  258   foreach my $User (@userRecords) {
  259     next if grep /$User->{status}/, @{$self->{r}->{ce}->{siteDefaults}->{statusDrop}};
  260     my $UserSet = $db->newUserSet;
  261     my $userID = $User->user_id;
  262     $UserSet->user_id($userID);
  263     $UserSet->set_id($setID);
  264     $WeBWorK::timer->continue("$setID: adding UserSet for $userID") if defined $WeBWorK::timer;
  265     eval { $db->addUserSet($UserSet) };
  266     if ($@) {
  267       next if $@ =~ m/user set exists/;
  268       die $@;
  269     }
  270     $WeBWorK::timer->continue("$setID: (done with that)") if defined $WeBWorK::timer;
  271 
  272     $WeBWorK::timer->continue("$setID: adding UserProblems for $userID") if defined $WeBWorK::timer;
  273     foreach my $GlobalProblem (@GlobalProblems) {
  274       my @result = $self->assignProblemToUser($userID, $GlobalProblem);
  275       push @results, @result if @result;
  276     }
  277     $WeBWorK::timer->continue("$setID: (done with that)") if defined $WeBWorK::timer;
  278   }
  279 
  280   return @results;
  281 }
  282 
  283 =item unassignSetFromAllUsers($setID)
  284 
  285 Unassigns the specified sets and all problems contained therein from all users.
  286 
  287 =cut
  288 
  289 sub unassignSetFromAllUsers {
  290   my ($self, $setID) = @_;
  291   my $db = $self->{db};
  292 
  293   my @userIDs = $db->listSetUsers($setID);
  294 
  295   foreach my $userID (@userIDs) {
  296     $self->unassignSetFromUser($userID, $setID);
  297   }
  298 }
  299 
  300 =item assignAllSetsToUser($userID)
  301 
  302 Assigns all sets in the course and all problems contained therein to the
  303 specified user. This is more efficient than repeatedly calling
  304 assignSetToUser(). If any assignments fail, a list of failure messages is
  305 returned.
  306 
  307 =cut
  308 
  309 sub assignAllSetsToUser {
  310   my ($self, $userID) = @_;
  311   my $db = $self->{db};
  312 
  313   # assign only sets that are not already assigned
  314   #my %userSetIDs = map { $_ => 1 } $db->listUserSets($userID);
  315   #my @globalSetIDs = grep { not exists $userSetIDs{$_} } $db->listGlobalSets;
  316   #my @GlobalSets = $db->getGlobalSets(@globalSetIDs);
  317   # FIXME: i don't think we need to do the above, since asignSetToUser fails
  318   # silently if a UserSet already exists. instead we do this:
  319   my @globalSetIDs = $db->listGlobalSets;
  320   my @GlobalSets = $db->getGlobalSets(@globalSetIDs);
  321 
  322   my @results;
  323 
  324   my $i = 0;
  325   foreach my $GlobalSet (@GlobalSets) {
  326     if (not defined $GlobalSet) {
  327       warn "record not found for global set $globalSetIDs[$i]";
  328     } else {
  329       my @result = $self->assignSetToUser($userID, $GlobalSet);
  330       push @results, @result if @result;
  331     }
  332     $i++;
  333   }
  334 
  335   return @results;
  336 }
  337 
  338 =item unassignAllSetsFromUser($userID)
  339 
  340 Unassigns all sets and all problems contained therein from the specified user.
  341 
  342 =cut
  343 
  344 sub unassignAllSetsFromUser {
  345   my ($self, $userID) = @_;
  346   my $db = $self->{db};
  347 
  348   my @setIDs = $db->listUserSets($userID);
  349 
  350   foreach my $setID (@setIDs) {
  351     $self->unassignSetFromUser($userID, $setID);
  352   }
  353 }
  354 
  355 =back
  356 
  357 =cut
  358 
  359 ################################################################################
  360 # Utility assignment methods
  361 ################################################################################
  362 
  363 =head2 Utility assignment methods
  364 
  365 =over
  366 
  367 =item assignSetsToUsers($setIDsRef, $userIDsRef)
  368 
  369 Assign each of the given sets to each of the given users. If any assignments
  370 fail, a list of failure messages is returned.
  371 
  372 =cut
  373 
  374 sub assignSetsToUsers {
  375   my ($self, $setIDsRef, $userIDsRef) = @_;
  376   my $db = $self->{db};
  377 
  378   my @setIDs = @$setIDsRef;
  379   my @userIDs = @$userIDsRef;
  380   my @GlobalSets = $db->getGlobalSets(@setIDs);
  381 
  382   my @results;
  383 
  384   foreach my $GlobalSet (@GlobalSets) {
  385     foreach my $userID (@userIDs) {
  386       my @result = $self->assignSetToUser($userID, $GlobalSet);
  387       push @results, @result if @result;
  388     }
  389   }
  390 
  391   return @results;
  392 }
  393 
  394 =item unassignSetsFromUsers($setIDsRef, $userIDsRef)
  395 
  396 Unassign each of the given sets from each of the given users.
  397 
  398 =cut
  399 
  400 sub unassignSetsFromUsers {
  401   my ($self, $setIDsRef, $userIDsRef) = @_;
  402   my @setIDs = $setIDsRef;
  403   my @userIDs = $userIDsRef;
  404 
  405   foreach my $setID (@setIDs) {
  406     foreach my $userID (@userIDs) {
  407       $self->unassignSetFromUser($userID, $setID);
  408     }
  409   }
  410 }
  411 
  412 =item assignProblemToAllSetUsers($GlobalProblem)
  413 
  414 Assigns the problem specified to all users to whom the problem's set is
  415 assigned. If any assignments fail, a list of failure messages is returned.
  416 
  417 =cut
  418 
  419 sub assignProblemToAllSetUsers {
  420   my ($self, $GlobalProblem) = @_;
  421   my $db = $self->{db};
  422   my $setID = $GlobalProblem->set_id;
  423   my @userIDs = $db->listSetUsers($setID);
  424 
  425   my @results;
  426 
  427   foreach my $userID (@userIDs) {
  428     my @result = $self->assignProblemToUser($userID, $GlobalProblem);
  429     push @results, @result if @result;
  430   }
  431 
  432   return @results;
  433 }
  434 
  435 =back
  436 
  437 =cut
  438 
  439 ################################################################################
  440 # Utility method for adding problems to a set
  441 ################################################################################
  442 
  443 =head2 Utility method for adding problems to a set
  444 
  445 =over
  446 
  447 =cut
  448 
  449 sub addProblemToSet {
  450   my ($self, %args) = @_;
  451   my $db = $self->r->db;
  452 
  453   die "addProblemToSet called without specifying the set name." if $args{setName} eq "";
  454   my $setName = $args{setName};
  455 
  456   my $sourceFile = $args{sourceFile} or
  457     die "addProblemToSet called without specifying the sourceFile.";
  458 
  459   # The rest of the arguments are optional
  460   my $value = $args{value} || 1;
  461   my $maxAttempts = $args{maxAttempts} || -1;
  462   my $problemID = $args{problemID};
  463 
  464   unless ($problemID) {
  465     $problemID = WeBWorK::Utils::max($db->listGlobalProblems($setName)) + 1;
  466   }
  467 
  468   my $problemRecord = $db->newGlobalProblem;
  469   $problemRecord->problem_id($problemID);
  470   $problemRecord->set_id($setName);
  471   $problemRecord->source_file($sourceFile);
  472   $problemRecord->value($value);
  473   $problemRecord->max_attempts($maxAttempts);
  474   $db->addGlobalProblem($problemRecord);
  475 
  476   return $problemRecord;
  477 }
  478 
  479 ################################################################################
  480 # Utility methods
  481 ################################################################################
  482 
  483 =head2 Utility methods
  484 
  485 =over
  486 
  487 =cut
  488 
  489 sub hiddenEditForUserFields {
  490   my ($self, @editForUser) = @_;
  491   my $return = "";
  492   foreach my $editUser (@editForUser) {
  493     $return .= CGI::input({type=>"hidden", name=>"editForUser", value=>$editUser});
  494   }
  495 
  496   return $return;
  497 }
  498 
  499 sub userCountMessage {
  500   my ($self, $count, $numUsers) = @_;
  501 
  502   my $message;
  503   if ($count == 0) {
  504     $message = CGI::em("no users");
  505   } elsif ($count == $numUsers) {
  506     $message = "all users";
  507   } elsif ($count == 1) {
  508     $message = "1 user";
  509   } elsif ($count > $numUsers || $count < 0) {
  510     $message = CGI::em("an impossible number of users: $count out of $numUsers");
  511   } else {
  512     $message = "$count users";
  513   }
  514 
  515   return $message;
  516 }
  517 
  518 sub read_dir {  # read a directory
  519   my $self      = shift;
  520   my $directory = shift;
  521   my $pattern   = shift;
  522   my @files = grep /$pattern/, WeBWorK::Utils::readDirectory($directory);
  523   return sort @files;
  524 }
  525 
  526 sub read_scoring_file    { # used in SendMail and ....?
  527   my $self            = shift;
  528   my $fileName        = shift;
  529   my $delimiter       = shift;
  530   $delimiter          = ',' unless defined($delimiter);
  531   my $scoringDirectory= $self->{ce}->{courseDirs}->{scoring};
  532   my $filePath        = "$scoringDirectory/$fileName";
  533         #       Takes a delimited file as a parameter and returns an
  534         #       associative array with the first field as the key.
  535         #       Blank lines are skipped. White space is removed
  536     my(@dbArray,$key,$dbString);
  537     my %assocArray = ();
  538     my $file_string;
  539     if ($fileName eq 'None') {
  540       # do nothing
  541     } elsif ( $file_string = WeBWorK::Utils::readFile($filePath)  ) {
  542         my @file_lines = split "\n",$file_string;
  543     my $index=0;
  544     foreach my $line (@file_lines){
  545       unless ($line =~ /\S/)  {next;}               ## skip blank lines
  546       chomp($line);
  547       @{$dbArray[$index]} =$self->getRecord($line,$delimiter);
  548       $key    =$dbArray[$index][0];
  549       $assocArray{$key}=$dbArray[$index];
  550       $index++;
  551     }
  552     close(FILE);
  553      } else {
  554       warn "Couldn't read file $filePath";
  555      }
  556      return \%assocArray;
  557 }
  558 
  559 =back
  560 
  561 =cut
  562 
  563 ################################################################################
  564 # Methods for listing various types of files
  565 ################################################################################
  566 
  567 =head2 Methods for listing various types of files
  568 
  569 =over
  570 
  571 =cut
  572 
  573 # list classlist files
  574 sub getCSVList {
  575   my ($self) = @_;
  576   my $ce = $self->{ce};
  577   my $dir = $ce->{courseDirs}->{templates};
  578   return grep { not m/^\./ and m/\.lst$/ and -f "$dir/$_" } WeBWorK::Utils::readDirectory($dir);
  579 }
  580 
  581 sub getDefList {
  582   my ($self) = @_;
  583   my $ce = $self->{ce};
  584   my $dir = $ce->{courseDirs}->{templates};
  585   return $self->read_dir($dir, qr/.*\.def/);
  586 }
  587 
  588 sub getScoringFileList {
  589   my ($self) = @_;
  590   my $ce = $self->{ce};
  591   my $dir = $ce->{courseDirs}->{scoring};
  592   return $self->read_dir($dir, qr/.*\.csv/);
  593 }
  594 
  595 sub getTemplateFileList {  # find all .pg files under the template tree (time consuming)
  596   my ($self) = shift;
  597   my $subDir = shift;
  598   my $ce = $self->{ce};
  599   $subDir = '' unless defined $subDir;
  600   my $dir = $ce->{courseDirs}->{templates}."/$subDir";
  601   # FIXME  currently allows one to see most files in the templates directory.
  602   # a better facility for handling auxiliary files would be nice.
  603   return $self->read_dir($dir, qr/\.pg$|.*\.html|\.png|\.gif|\.txt|\.pl/);
  604 }
  605 sub getTemplateDirList {  # find all .pg files under the template tree (time consuming)
  606   my ($self) = @_;
  607   my $ce = $self->{ce};
  608   my $dir = $ce->{courseDirs}->{templates};
  609   my @list = ();
  610   my $wanted = sub { if (-d $_ ) {
  611                           my $current = $_;
  612                           return if $current =~/CVS/;
  613                           return if -l $current;   # don't list links
  614                           my $name = $File::Find::name;
  615                           $name = " Top" if $current =/^\./; #  top directory
  616               $name =~ s/^$dir\///;
  617               push @list, $name
  618              }
  619   };
  620   File::Find::find($wanted, $dir);
  621   return sort @list;
  622 }
  623 
  624 =back
  625 
  626 =cut
  627 
  628 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9