[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / Instructor / ProblemSetEditor.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 983 - (download) (as text) (annotate)
Tue Jun 3 17:48:35 2003 UTC (10 years ago) by malsyned
File size: 12949 byte(s)
Changed explicit references to "/webwork" to the abstract
$ce->{webworkURLs}->{root}.  If you've been hardcoding "/webwork" into
your URLs, you should take a look at the diff to this update to learn
the prefered method.
-Dennis

    1 package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor;
    2 use base qw(WeBWorK::ContentGenerator::Instructor);
    3 
    4 =head1 NAME
    5 
    6 WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list
    7 
    8 =cut
    9 
   10 use strict;
   11 use warnings;
   12 use CGI qw();
   13 use WeBWorK::DB::Record::Problem;
   14 use WeBWorK::Utils qw(readFile formatDateTime parseDateTime list2hash readDirectory max);
   15 
   16 our $rowheight = 20;  #controls the length of the popup menus.
   17 our $libraryName;  #library directory name
   18 
   19 use constant SET_FIELDS => [qw(open_date due_date answer_date set_header problem_header)];
   20 use constant PROBLEM_FIELDS =>[qw(source_file value max_attempts)];
   21 use constant PROBLEM_USER_FIELDS => [qw(problem_seed status num_correct num_incorrect)];
   22 
   23 sub getSetName {
   24   my ($self, $pathSetName) = @_;
   25   if (ref $pathSetName eq "HASH") {
   26     $pathSetName = undef;
   27   }
   28   return $pathSetName;
   29 }
   30 
   31 # One wrinkle here: if $override is undefined, do the global thing, otherwise, it's truth value determines the checkbox.
   32 sub setRowHTML {
   33   my ($description, $fieldName, $fieldValue, $size, $override, $overrideValue) = @_;
   34 
   35   my $attributeHash = {type=>"text", name=>$fieldName, value=>$fieldValue};
   36   $attributeHash->{size} = $size if defined $size;
   37 
   38   my $html = CGI::td({}, [$description, CGI::input($attributeHash)]);
   39 
   40   if (defined $override) {
   41     $attributeHash->{name}="${fieldName}_override";
   42     $attributeHash->{value}=($override ? $overrideValue : "" );
   43 
   44     $html .= CGI::td({}, [
   45       CGI::checkbox({
   46         type=>"checkbox",
   47         name=>"override",
   48         label=>"override with:",
   49         value=>$fieldName,
   50         checked=>($override ? 1 : 0)
   51       }),
   52       CGI::input($attributeHash)
   53     ]);
   54   }
   55 
   56   return $html;
   57 
   58 }
   59 
   60 sub hiddenEditForUserFields {
   61   my @editForUser = @_;
   62   my $return = "";
   63   foreach my $editUser (@editForUser) {
   64     $return .= CGI::input({type=>"hidden", name=>"editForUser", value=>$editUser});
   65   }
   66 
   67   return $return;
   68 }
   69 
   70 sub problemElementHTML {
   71   my ($fieldName, $fieldValue, $size, $override, $overrideValue) = @_;
   72   my $attributeHash = {type=>"text",name=>$fieldName,value=>$fieldValue};
   73   $attributeHash->{size} = $size if defined $size;
   74 
   75   my $html = CGI::input($attributeHash);
   76   if (defined $override) {
   77     $attributeHash->{name} = "${fieldName}_override";
   78     $attributeHash->{value} = ($override ? $overrideValue : "");
   79     $html = "default:".CGI::br().$html.CGI::br()
   80       . CGI::checkbox({
   81         type => "checkbox",
   82         name => "override",
   83         label => "override:",
   84         value => $fieldName,
   85         checked => ($override ? 1 : 0)
   86       })
   87       . CGI::br()
   88       . CGI::input($attributeHash);
   89   }
   90 
   91   return $html;
   92 }
   93 
   94 
   95 # pay no attention to the argument list.  Here's what you pass:
   96 # directoryListHTML($level, $selected, $libraryRoot, @path)
   97 sub directoryListHTML {
   98   my ($level, $selected, @path) = @_;
   99   $selected = [$selected] unless ref $selected eq "ARRAY";
  100   my $dirName = join "/", @path[0..$level];
  101   my @contents = sort grep {m/\.pg$/ or -d $dirName.'/'.$_ and not m/^\.{1,2}$/} readDirectory($dirName);
  102   my %contentsPretty = map {$_ => (-d $dirName.'/'.$_ ? $_.'/' : $_)} @contents;
  103 
  104   my $html = ($level eq "0" ? "problem library" : $path[$level]) . CGI::br();
  105   $html .= CGI::scrolling_list({
  106     name=>"directory_level_$level",
  107     values=>\@contents,
  108     labels=>\%contentsPretty,
  109     default=>$selected,
  110     multiple=>'true',
  111     size=>"20",
  112   });
  113   $html .= CGI::br()
  114     . CGI::input({type=>"submit", name=>"open_add_$level", value=>"Open/Add"});
  115 }
  116 
  117 sub title {
  118   my ($self, @components) = @_;
  119   return "Problem Set Editor - ".$self->{ce}->{courseName}." : ".$self->getSetName(@components);
  120 }
  121 
  122 # Initialize does all of the form processing.  It's extensive, and could probably be cleaned up and
  123 # consolidated with a little abstraction.
  124 sub initialize {
  125   my ($self, @components) = @_;
  126   my $r = $self->{r};
  127   my $db = $self->{db};
  128   my $ce = $self->{ce};
  129   my $setName = $self->getSetName(@components);
  130   my $setRecord = $db->getGlobalSet($setName);
  131   my @editForUser = $r->param('editForUser');
  132   # some useful booleans
  133   my $forUsers = scalar(@editForUser);
  134   my $forOneUser = $forUsers == 1;
  135 
  136   # build a quick lookup table
  137   my %overrides = list2hash $r->param('override');
  138 
  139   # The set form was submitted
  140   if (defined($r->param('submit_set_changes'))) {
  141     foreach (@{SET_FIELDS()}) {
  142       if (defined($r->param($_))) {
  143         if (m/_date$/) {
  144           $setRecord->$_(parseDateTime($r->param($_)));
  145         } else {
  146           $setRecord->$_($r->param($_));
  147         }
  148       }
  149     }
  150     $db->putGlobalSet($setRecord);
  151 
  152     if ($forOneUser) {
  153 
  154       my $userSetRecord = $db->getUserSet($editForUser[0], $setName);
  155       foreach my $field (@{SET_FIELDS()}) {
  156         if (defined $r->param("${field}_override")) {
  157           if (exists $overrides{$field}) {
  158             if ($field =~ m/_date$/) {
  159               $userSetRecord->$field(parseDateTime($r->param("${field}_override")));
  160             } else {
  161               $userSetRecord->$field($r->param("${field}_override"));
  162             }
  163           } else {
  164             $userSetRecord->$field(undef);
  165           }
  166 
  167           $db->putUserSet($userSetRecord);
  168         }
  169       }
  170     }
  171   }
  172   # the Problem form was submitted
  173   elsif (defined($r->param('submit_problem_changes'))) {
  174     foreach my $problem ($r->param('deleteProblem')) {
  175       $db->deleteGlobalProblem($setName, $problem);
  176     }
  177     my @problemList = $db->listGlobalProblems($setName);
  178     foreach my $problem (@problemList) {
  179       my $problemRecord = $db->getGlobalProblem($setName, $problem);
  180       foreach my $field (@{PROBLEM_FIELDS()}) {
  181         my $paramName = "problem_${problem}_${field}";
  182         if (defined($r->param($paramName))) {
  183           $problemRecord->$field($r->param($paramName));
  184         }
  185       }
  186       $db->putGlobalProblem($problemRecord);
  187 
  188       if ($forOneUser) {
  189         my $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem);
  190         foreach my $field (@{PROBLEM_USER_FIELDS()}) {
  191           my $paramName = "problem_${problem}_${field}";
  192           if (defined($r->param($paramName))) {
  193             $userProblemRecord->$field($r->param($paramName));
  194           }
  195         }
  196         $userProblemRecord->attempted($userProblemRecord->num_correct + $userProblemRecord->num_incorrect);
  197         foreach my $field (@{PROBLEM_FIELDS()}) {
  198           my $paramName = "problem_${problem}_${field}";
  199           if (defined($r->param("${paramName}_override"))) {
  200             if (exists $overrides{$paramName}) {
  201               $userProblemRecord->$field($r->param("${paramName}_override"));
  202             } else {
  203               $userProblemRecord->$field(undef);
  204             }
  205 
  206             $db->putUserProblem($userProblemRecord);
  207           }
  208         }
  209 
  210       }
  211     }
  212   } elsif (defined $r->param('fileBrowsing')) {
  213     my $libraryRoot = $ce->{courseDirs}->{templates};
  214     my $count = 0;
  215     my $done = 0;
  216     my @path = ();
  217     my $freeProblemID = max($db->listGlobalProblems($setName)) + 1;
  218     while (defined $r->param("directory_level_$count") and not $done) {
  219       my @selected = $r->param("directory_level_$count");
  220       my $dirFound = 0;
  221       # If any directories are selected, "cd" into the first one and stop processing this level.
  222       foreach my $selected (@selected) {
  223         if (-d join "/", $libraryRoot, @path, $selected) {
  224           push @path, $selected;
  225           $dirFound = 1;
  226           last;
  227         }
  228       }
  229       # Otherwise, create a new global problem for each of the files selected
  230       unless ($dirFound) {
  231         foreach my $selected (@selected) {
  232           my $file = join "/", @path, $selected;
  233           my $problemRecord = new WeBWorK::DB::Record::Problem;
  234           $problemRecord->problem_id($freeProblemID++);
  235           $problemRecord->set_id($setName);
  236           $problemRecord->source_file($file);
  237           $problemRecord->value("1");
  238           $problemRecord->max_attempts("-1");
  239           $db->addGlobalProblem($problemRecord);
  240         }
  241         $done = 1;
  242       }
  243 
  244       if (defined $r->param("open_add_$count")) {
  245         $done = 1;
  246       }
  247       $count++;
  248     }
  249     $self->{path} = [@path];
  250   }
  251 }
  252 
  253 
  254 sub body {
  255   my ($self, @components) = @_;
  256   my $r = $self->{r};
  257   my $db = $self->{db};
  258   my $ce = $self->{ce};
  259   my $courseName = $ce->{courseName};
  260   my $setName = $self->getSetName(@components);
  261   my $setRecord = $db->getGlobalSet($setName);
  262   my @editForUser = $r->param('editForUser');
  263   # some useful booleans
  264   my $forUsers = scalar(@editForUser);
  265   my $forOneUser = $forUsers == 1;
  266 
  267   ## Set Form ##
  268   my $userSetRecord;
  269   my %overrideArgs;
  270   if ($forOneUser) {
  271     $userSetRecord = $db->getUserSet($editForUser[0], $setName);
  272     foreach my $field (@{SET_FIELDS()}) {
  273       $overrideArgs{$field} = [defined $userSetRecord->$field, ($field =~ /_date$/ ? formatDateTime($userSetRecord->$field) : $userSetRecord->$field)];
  274     }
  275   } else {
  276     foreach my $field (@{SET_FIELDS()}) {
  277       $overrideArgs{$field} = [undef, undef];
  278     }
  279   }
  280 
  281   print CGI::h2({}, "Set Data"), "\n";
  282   print CGI::start_form({method=>"post", action=>$r->uri}), "\n";
  283   print CGI::table({},
  284     CGI::Tr({}, [
  285       setRowHTML("Open Date:", "open_date", formatDateTime($setRecord->open_date), undef, @{$overrideArgs{open_date}})."\n",
  286       setRowHTML("Due Date:", "due_date", formatDateTime($setRecord->due_date), undef, @{$overrideArgs{due_date}})."\n",
  287       setRowHTML("Answer Date:", "answer_date", formatDateTime($setRecord->answer_date), undef, @{$overrideArgs{answer_date}})."\n",
  288       setRowHTML("Set Header:", "set_header", $setRecord->set_header, undef, @{$overrideArgs{set_header}})."\n",
  289       setRowHTML("Problem Header:", "problem_header", $setRecord->problem_header, undef, @{$overrideArgs{problem_header}})."\n"
  290     ])
  291   );
  292 
  293   print hiddenEditForUserFields(@editForUser);
  294   print $self->hidden_authen_fields;
  295   print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"});
  296   print CGI::end_form();
  297 
  298   ## Problems Form ##
  299   my @problemList = $db->listGlobalProblems($setName);
  300   print CGI::a({name=>"problems"});
  301   print CGI::h2({}, "Problems");
  302   if (scalar(@problemList)) {
  303     print CGI::start_form({method=>"POST", action=>$r->uri.'#problems'});
  304     print CGI::start_table({border=>1, cellpadding=>4});
  305     print CGI::Tr({}, CGI::th({}, [
  306       ($forUsers ? () : ("Delete?")),
  307       "Problem",
  308       ($forUsers ? ("Status", "Problem Seed") : ()),
  309       "Source File", "Max. Attempts", "Weight",
  310       ($forUsers ? ("Number Correct", "Number Incorrect") : ())
  311     ]));
  312     foreach my $problem (sort {$a <=> $b} @problemList) {
  313       my $problemRecord = $db->getGlobalProblem($setName, $problem);
  314       my $problemID = $problemRecord->problem_id;
  315       my $userProblemRecord;
  316       my %problemOverrideArgs;
  317 
  318       if ($forOneUser) {
  319         $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem);
  320         foreach my $field (@{PROBLEM_FIELDS()}) {
  321           $problemOverrideArgs{$field} = [defined $userProblemRecord->$field, $userProblemRecord->$field];
  322         }
  323   #   } elsif ($forUsers) {
  324   #     foreach my $field (@{PROBLEM_FIELDS()}) {
  325   #       $problemOverrideArgs{$field} = ["", ""];
  326   #     }
  327       } else {
  328         foreach my $field (@{PROBLEM_FIELDS()}) {
  329           $problemOverrideArgs{$field} = [undef, undef];
  330         }
  331       }
  332 
  333       print CGI::Tr({},
  334         CGI::td({}, [
  335           ($forUsers ? () : (CGI::input({type=>"checkbox", name=>"deleteProblem", value=>$problemID}))),
  336           CGI::a({href=>$ce->{webworkURLs}->{root}."/$courseName/instructor/pgProblemEditor/".$setName.'/'.$problemID.'?'.$self->url_authen_args}, $problemID),
  337           ($forUsers ? (
  338             problemElementHTML("problem_${problemID}_status", $userProblemRecord->status, "7"),
  339             problemElementHTML("problem_${problemID}_problem_seed", $userProblemRecord->problem_seed, "7"),
  340           ) : ()),
  341           problemElementHTML("problem_${problemID}_source_file", $problemRecord->source_file, "40", @{$problemOverrideArgs{source_file}}),
  342           problemElementHTML("problem_${problemID}_max_attempts",$problemRecord->max_attempts,"7", @{$problemOverrideArgs{max_attempts}}),
  343           problemElementHTML("problem_${problemID}_value",$problemRecord->value,"7", @{$problemOverrideArgs{value}}),
  344           ($forUsers ? (
  345             problemElementHTML("problem_${problemID}_num_correct", $userProblemRecord->num_correct, "7"),
  346             problemElementHTML("problem_${problemID}_num_incorrect", $userProblemRecord->num_incorrect, "7")
  347           ) : ())
  348         ])
  349 
  350       )
  351     }
  352     print CGI::end_table();
  353     print hiddenEditForUserFields(@editForUser);
  354     print $self->hidden_authen_fields;
  355     print CGI::input({type=>"submit", name=>"submit_problem_changes", value=>"Save Problem Changes"});
  356     print CGI::end_form();
  357   } else {
  358     print CGI::p("This set doesn't contain any problems yet.");
  359   }
  360 
  361   unless ($forUsers) {
  362     my $libraryRoot = $ce->{courseDirs}->{templates};
  363     my @path = defined $self->{path} ? @{$self->{path}} : ();
  364     unshift @path, $libraryRoot;
  365     print CGI::a({name=>"addProblem"});
  366     print CGI::h3({}, "Add Problem(s)");
  367     print CGI::start_form({method=>"post", action=>$r->uri.'#addProblem'});
  368     print CGI::input({type=>"hidden", name=>"fileBrowsing", value=>"Yes"});
  369     print CGI::start_table();
  370     my $columns = "";
  371     for (my $counter = 0; $counter < scalar(@path); $counter++) {
  372       $columns .= CGI::td(directoryListHTML ($counter, (exists $path[$counter+1] ? $path[$counter+1] : []), @path));
  373     }
  374     print CGI::Tr($columns);
  375     print CGI::end_table();
  376     print $self->hidden_authen_fields;
  377     print CGI::end_form();
  378   }
  379   return "";
  380 }
  381 
  382 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9