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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2431 - (download) (as text) (annotate)
Thu Jul 1 20:31:13 2004 UTC (8 years, 11 months ago) by dpvc
File size: 33057 byte(s)
Provide mechanism for adding extra problem library buttons
to the Library Browser.

These changes allow you to specify (via course.conf or global.conf)
that certain subdirectories of the templates directory are to have
separate buttons in the top panel of the Set Maker.  These buttons
only appear if the directories actually exist, and any other
directories are listed in the "Local Problems" button as usual.  If
the list of these directories is empty (the default), then the results
are just like they currently are, but it allows one more level of
separation of the hierarchy for those who want it.

The idea is to make symbolic links to the problem libraries from
Rochester, ASU, etc., and have separate buttons for these.  This
avoids having one monster menu with all the problems in it.  (Of
course, you could make buttons for any directories you want.)  There
are instructions in global.conf.dist that exmplain how to do configure
this.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v 1.20 2004/06/09 02:51:57 jj 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 
   18 package WeBWorK::ContentGenerator::Instructor::SetMaker;
   19 use base qw(WeBWorK::ContentGenerator::Instructor);
   20 
   21 =head1 NAME
   22 
   23 WeBWorK::ContentGenerator::Instructor::SetMaker - Make problem sets.
   24 
   25 =cut
   26 
   27 use strict;
   28 use warnings;
   29 
   30 use CGI::Pretty qw();
   31 use WeBWorK::Form;
   32 use WeBWorK::Utils qw(readDirectory max);
   33 use WeBWorK::Utils::Tasks qw(renderProblems);
   34 
   35 require WeBWorK::Utils::ListingDB;
   36 
   37 use constant MAX_SHOW_DEFAULT => 20;
   38 use constant NO_LOCAL_SET_STRING => 'There are no local sets yet';
   39 use constant SELECT_SET_STRING => 'Select a Set for This Course';
   40 use constant SELECT_LOCAL_STRING => 'Select a Problem Collection';
   41 use constant MY_PROBLEMS => '  My Problems  ';
   42 use constant MAIN_PROBLEMS => '  Main Problems  ';
   43 
   44 ## Flags for operations on files
   45 
   46 use constant ADDED => 1;
   47 use constant HIDDEN => (1 << 1);
   48 use constant SUCCESS => (1 << 2);
   49 
   50 ##  for additional problib buttons
   51 my %problib;  ## filled in in global.conf
   52 my %ignoredir = ('.' => 1, '..' => 1, 'Library' => 1);
   53 
   54 ## This is for searching the disk for directories containing pg files.
   55 ## to make the recursion work, this returns an array where the first
   56 ## item is 1 or 0 depending on whether or not the current
   57 ## directory has any pg files.  The second is a list of directories
   58 ## which contain pg files.
   59 sub get_library_sets {
   60   my $amtop = shift;
   61   my $topdir =  shift;
   62   my @lis = readDirectory($topdir);
   63   my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg/) and -f "$topdir/$_"} @lis;
   64   my $havepg = scalar(@pgs)>0 ? 1 : 0;
   65   my @mdirs = grep {!defined($ignoredir{$_}) and -d "$topdir/$_"} @lis;
   66   if ($amtop) {@mdirs = grep {!defined($problib{$_})} @mdirs}
   67   my ($adir, @results, @thisresult);
   68   for $adir (@mdirs) {
   69     @results = get_library_sets(0, "$topdir/$adir");
   70     my $isadirok = shift @results;
   71     @thisresult = (@thisresult, @results);
   72     if ($isadirok) {
   73       @thisresult = ("$topdir/$adir", @thisresult);
   74     }
   75   }
   76   return(($havepg, @thisresult));
   77 }
   78 
   79 ## List all the pg files in the requested directory
   80 sub list_pg_files {
   81   my $templatedir = shift;
   82   my $topdir = shift;
   83 
   84   my @lis = readDirectory("$templatedir/$topdir");
   85   my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg/) and -f "$templatedir/$topdir/$_"} @lis;
   86   @pgs = map { "$topdir/$_" } @pgs;
   87   return(@pgs);
   88 }
   89 
   90 ## go through past page getting a list of identifiers for the problems
   91 ## and whether or not they are selected, and whether or not they should
   92 ## be hidden
   93 
   94 sub get_past_problem_files {
   95   my $r = shift;
   96   my @found=();
   97   my $count =1;
   98   while (defined($r->param("filetrial$count"))) {
   99     my $val = 0;
  100     $val |= ADDED if($r->param("trial$count"));
  101     $val |= HIDDEN if($r->param("hideme$count"));
  102     push @found, [$r->param("filetrial$count"), $val];
  103     $count++;
  104   }
  105   return(\@found);
  106 }
  107 
  108 #### For adding new problems
  109 
  110 sub add_selected {
  111   my $self = shift;
  112   my $db = shift;
  113   my $setName = shift;
  114   my @past_problems = @{$self->{past_problems}};
  115   my @selected = @past_problems;
  116   my (@path, $file, $selected, $freeProblemID);
  117   $freeProblemID = max($db->listGlobalProblems($setName)) + 1;
  118   my $addedcount=0;
  119 
  120   for $selected (@selected) {
  121     if($selected->[1] & ADDED) {
  122       $file = $selected->[0];
  123       my $problemRecord = $self->addProblemToSet(setName => $setName,
  124         sourceFile => $file, problemID => $freeProblemID);
  125       $freeProblemID++;
  126       $self->assignProblemToAllSetUsers($problemRecord);
  127       $selected->[1] |= SUCCESS;
  128       $addedcount++;
  129     }
  130   }
  131   return($addedcount);
  132 }
  133 
  134 
  135 ############# List of sets of problems in templates directory
  136 
  137 sub get_problem_directories {
  138   my $ce = shift;
  139   my $lib = shift;
  140   my $source = $ce->{courseDirs}{templates};
  141   my $main = MY_PROBLEMS; my $isTop = 1;
  142   if ($lib) {$source .= "/$lib"; $main = MAIN_PROBLEMS; $isTop = 0}
  143   my @all_problem_directories = get_library_sets($isTop, $source);
  144   my $includetop = shift @all_problem_directories;
  145   my $j;
  146   for ($j=0; $j<scalar(@all_problem_directories); $j++) {
  147     $all_problem_directories[$j] =~ s|^$ce->{courseDirs}->{templates}/?||;
  148   }
  149   @all_problem_directories = sort @all_problem_directories;
  150   unshift @all_problem_directories, $main if($includetop);
  151   return (\@all_problem_directories);
  152 }
  153 
  154 ############# Everyone has a view problems line.  Abstract it
  155 sub view_problems_line {
  156   my $internal_name = shift;
  157   my $label = shift;
  158   my $r = shift; # so we can get parameter values
  159   my $result = CGI::submit(-name=>"$internal_name", -value=>$label);
  160 
  161   my %display_modes = %{WeBWorK::PG::DISPLAY_MODES()};
  162   my @active_modes = grep { exists $display_modes{$_} }
  163     @{$r->ce->{pg}->{displayModes}};
  164   push @active_modes, 'None';
  165   # We have our own displayMode since its value may be None, which is illegal
  166   # in other modules.
  167   my $mydisplayMode = $r->param('mydisplayMode') || $r->ce->{pg}->{options}->{displayMode};
  168   $result .= '&nbsp;Display&nbsp;Mode:&nbsp;'.CGI::popup_menu(-name=> 'mydisplayMode',
  169               -values=>\@active_modes,
  170               -default=> $mydisplayMode);
  171   # Now we give a choice of the number of problems to show
  172   my $defaultMax = $r->param('max_shown') || MAX_SHOW_DEFAULT;
  173   $result .= '&nbsp;Max. Shown:&nbsp'.
  174     CGI::popup_menu(-name=> 'max_shown',
  175                     -values=>[5,10,15,20,25,30,50,'All'],
  176                     -default=> $defaultMax);
  177 
  178   return($result);
  179 }
  180 
  181 
  182 ### The browsing panel has three versions
  183 #####  Version 1 is local problems
  184 sub browse_local_panel {
  185   my $self = shift;
  186   my $library_selected = shift;
  187   my $lib = shift || ''; $lib =~ s/^browse_//;
  188   my $name = ($lib eq '')? 'Local' : $problib{$lib};
  189 
  190   my $list_of_prob_dirs= get_problem_directories($self->r->ce,$lib);
  191   if(scalar(@$list_of_prob_dirs) == 0) {
  192     $library_selected = "Found no directories containing problems";
  193     unshift @{$list_of_prob_dirs}, $library_selected;
  194   } else {
  195     my $default_value = SELECT_LOCAL_STRING;
  196     if (not $library_selected or $library_selected eq $default_value) {
  197       unshift @{$list_of_prob_dirs},  $default_value;
  198       $library_selected = $default_value;
  199     }
  200   }
  201   my $view_problem_line = view_problems_line('view_local_set', 'View Problems', $self->r);
  202   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "$name Problems: ",
  203       CGI::popup_menu(-name=> 'library_sets',
  204           -values=>$list_of_prob_dirs,
  205           -default=> $library_selected),
  206       CGI::br(),
  207       $view_problem_line,
  208            ));
  209 }
  210 
  211 #####  Version 2 is local problem sets
  212 sub browse_mysets_panel {
  213   my $self = shift;
  214   my $library_selected = shift;
  215   my $list_of_local_sets = shift;
  216   my $default_value = "Select a Problem Set";
  217 
  218   if(scalar(@$list_of_local_sets) == 0) {
  219     $list_of_local_sets = [NO_LOCAL_SET_STRING];
  220   } elsif (not $library_selected or $library_selected eq $default_value) {
  221     unshift @{$list_of_local_sets},  $default_value;
  222     $library_selected = $default_value;
  223   }
  224 
  225   my $view_problem_line = view_problems_line('view_mysets_set', 'View Problems', $self->r);
  226   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ",
  227       CGI::popup_menu(-name=> 'library_sets',
  228           -values=>$list_of_local_sets,
  229           -default=> $library_selected),
  230       CGI::br(),
  231                         $view_problem_line
  232            ));
  233 }
  234 
  235 #####  Version 3 is the problem library
  236 
  237 
  238 # There a different levels, and you can pick a new chapter,
  239 # pick a new section, pick all from chapter, pick all from section
  240 #
  241 # Incoming data - current chapter, current section
  242 sub browse_library_panel {
  243   my $self = shift;
  244   my $r = $self->r;
  245   my $ce = $r->ce;
  246 
  247   my $libraryRoot = $r->{ce}->{problemLibrary}->{root};
  248 
  249   unless($libraryRoot) {
  250     print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"},
  251         "The problem library has not been installed.")));
  252     return;
  253   }
  254   # Test if the Library directory exists.  If not, try to make it
  255   unless(-d "$ce->{courseDirs}->{templates}/Library") {
  256     unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) {
  257       my $msg =  <<"HERE";
  258 You are missing the directory <code>templates/Library</code>, which is needed
  259 for the Problem Library to function.  It should be a link pointing to
  260 <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>.
  261 I tried to make the link for you, but that failed.  Check the permissions
  262 in your <code>templates</code> directory.
  263 HERE
  264       $self->addbadmessage($msg);
  265     }
  266   }
  267 
  268   my $default_chap = "All Chapters";
  269   my $default_sect = "All Sections";
  270 
  271   my @chaps = WeBWorK::Utils::ListingDB::getAllChapters($r->{ce});
  272   unshift @chaps, $default_chap;
  273   my $chapter_selected = $r->param('library_chapters') || $default_chap;
  274 
  275   my @sects=();
  276   if ($chapter_selected ne $default_chap) {
  277     @sects = WeBWorK::Utils::ListingDB::getAllSections($r->{ce}, $chapter_selected);
  278   }
  279 
  280   my @textbooks = ('Textbook info not ready');
  281 
  282   unshift @sects, $default_sect;
  283   my $section_selected =  $r->param('library_sections') || $default_sect;
  284   my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r);
  285 
  286   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"},
  287       CGI::start_table(),
  288                         CGI::Tr(
  289         CGI::td(["Chapter:",
  290            CGI::popup_menu(-name=> 'library_chapters',
  291                -values=>\@chaps,
  292                -default=> $chapter_selected,
  293                -onchange=>"submit();return true"
  294               ),
  295            CGI::submit(-name=>"lib_select_chapter", -value=>"Update Section List")])),
  296       CGI::Tr(
  297         CGI::td("Section:"),
  298         CGI::td({-colspan=>2},
  299           CGI::popup_menu(-name=> 'library_sections',
  300               -values=>\@sects,
  301               -default=> $section_selected
  302                    ))),
  303 
  304 #       CGI::Tr(
  305 #         CGI::td("Textbook:"),
  306 #         CGI::td({-colspan=>2},
  307 #           CGI::popup_menu(-name=> 'library_textbooks',
  308 #               -values=>\@textbooks,
  309 #               #            -default=> $section_selected
  310 #                    ))),
  311 
  312 #       CGI::Tr(
  313 #         CGI::td("Keywords:"),
  314 #                                 CGI::td({-colspan=>2}, CGI::textfield(-name=>"keywords",
  315 #                       -default=>"Keywords not implemented yet",
  316 #                       -override=>1, -size=>60))),
  317       CGI::Tr(CGI::td({-colspan=>3},
  318                           $view_problem_line)),
  319       CGI::end_table(),
  320            ));
  321 }
  322 
  323 sub make_top_row {
  324   my $self = shift;
  325   my $r = $self->r;
  326   my $ce = $r->ce;
  327   my %data = @_;
  328 
  329   my $list_of_local_sets = $data{all_set_defs};
  330   my $have_local_sets = scalar(@$list_of_local_sets);
  331   my $browse_which = $data{browse_which};
  332   my $library_selected = $r->param('library_sets');
  333   my $set_selected = $r->param('local_sets');
  334 
  335   my ($dis1, $dis2, $dis3) = ("","","");
  336   $dis1 =  '-disabled' if($browse_which eq 'browse_library');
  337   $dis2 =  '-disabled' if($browse_which eq 'browse_local');
  338   $dis3 =  '-disabled' if($browse_which eq 'browse_mysets');
  339 
  340   ##  Make buttons for additional problem libraries
  341   my $libs = '';
  342   foreach my $lib (sort(keys(%problib))) {
  343     $libs .= ' '. CGI::submit(-name=>"browse_$lib", -value=>$problib{$lib},
  344                                  ($browse_which eq "browse_$lib")? '-disabled': '')
  345       if (-d "$ce->{courseDirs}{templates}/$lib");
  346   }
  347   $libs = CGI::br()."or Problems from".$libs if $libs ne '';
  348 
  349   my $these_widths = "width: 20ex";
  350   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"},
  351       "Browse ",
  352       CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, $dis1),
  353       CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, $dis2),
  354       CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, $dis3),
  355       $libs,
  356            ));
  357 
  358   print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  359 
  360   if ($browse_which eq 'browse_local') {
  361     $self->browse_local_panel($library_selected);
  362   } elsif ($browse_which eq 'browse_mysets') {
  363     $self->browse_mysets_panel($library_selected, $list_of_local_sets);
  364   } elsif ($browse_which eq 'browse_library') {
  365     $self->browse_library_panel();
  366   } else { ## handle other problem libraries
  367     $self->browse_local_panel($library_selected,$browse_which);
  368   }
  369 
  370   print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  371 
  372   if($have_local_sets ==0) {
  373     $list_of_local_sets = [NO_LOCAL_SET_STRING];
  374   } elsif (not $set_selected or $set_selected eq SELECT_SET_STRING) {
  375     if ($list_of_local_sets->[0] eq "Select a Problem Set") {
  376       shift @{$list_of_local_sets};
  377     }
  378     unshift @{$list_of_local_sets}, SELECT_SET_STRING;
  379     $set_selected = SELECT_SET_STRING;
  380   }
  381   my $myjs = 'document.mainform.selfassign.value=confirm("Should I assign the new set to you now?\nUse OK for yes and Cancel for no.");true;';
  382 
  383   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Adding Problems to ",
  384         CGI::b("Target Set: "),
  385       CGI::popup_menu(-name=> 'local_sets',
  386           -values=>$list_of_local_sets,
  387           -default=> $set_selected),
  388       CGI::submit(-name=>"edit_local", -value=>"Edit Target Set"),
  389       CGI::hidden(-name=>"selfassign", -default=>[0]).
  390       CGI::br(),
  391       CGI::br(),
  392       CGI::submit(-name=>"new_local_set", -value=>"Create a New Set in This Course:",
  393       -onclick=>$myjs
  394       ),
  395       "  ",
  396       CGI::textfield(-name=>"new_set_name",
  397                -default=>"Name for new set here",
  398                -override=>1, -size=>30),
  399       CGI::br(),
  400            ));
  401 
  402   print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  403 
  404   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"},
  405                         CGI::start_table({-border=>"0"}),
  406                         CGI::Tr( CGI::td({ -align=>"center"},
  407         CGI::submit(-name=>"select_all", -style=>$these_widths,
  408             -value=>"Mark All For Adding"),
  409         CGI::submit(-name=>"select_none", -style=>$these_widths,
  410             -value=>"Clear All Marks"),
  411                         )),
  412                         CGI::Tr( CGI::td(
  413         CGI::submit(-name=>"update", -style=>$these_widths. "; font-weight:bold",
  414             -value=>"Update"),
  415         CGI::submit(-name=>"rerandomize",
  416             -style=>$these_widths,
  417             -value=>"Rerandomize"),
  418         CGI::submit(-name=>"cleardisplay",
  419             -style=>$these_widths,
  420             -value=>"Clear Problem Display")
  421                         )),
  422                         CGI::end_table()));
  423 
  424 }
  425 
  426 sub make_data_row {
  427   my $self = shift;
  428   my $sourceFileName = shift;
  429   my $pg = shift;
  430   my $cnt = shift;
  431   my $mark = shift || 0;
  432 
  433   $sourceFileName =~ s|^./||; # clean up top ugliness
  434 
  435   my $urlpath = $self->r->urlpath;
  436   my $problem_output = $pg->{flags}->{error_flag} ?
  437     CGI::div({class=>"ResultsWithError"}, CGI::em("This problem produced an error"))
  438     : CGI::div({class=>"RenderSolo"}, $pg->{body_text});
  439 
  440 
  441   my $edit_link =  '';
  442   #if($self->{r}->param('browse_which') ne 'browse_library') {
  443   if($sourceFileName !~ /^Library\//) {
  444     $edit_link = CGI::a({href=>$self->systemLink($urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
  445             courseID =>$urlpath->arg("courseID"),
  446             setID=>"Undefined_Set",
  447             problemID=>"1"),
  448             params=>{sourceFilePath => "$sourceFileName"}
  449               )}, "Edit it" );
  450   }
  451 
  452   my $try_link = CGI::a({href=>$self->systemLink($urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
  453             courseID =>$urlpath->arg("courseID"),
  454             setID=>"Undefined_Set",
  455             problemID=>"1"),
  456               params =>{effectiveUser => $self->r->param('user'),
  457                   editMode => "SetMaker",
  458                   sourceFilePath => "$sourceFileName"}  )}, "Try it");
  459 
  460   my %add_box_data = ( -name=>"trial$cnt",-value=>1,-label=>"Add me to the current set on the next update");
  461   if($mark & SUCCESS) {
  462     $add_box_data{ -label } .= " (just added this problem)";
  463   } elsif($mark & ADDED) {
  464     $add_box_data{ -checked } = 1;
  465   }
  466 
  467   print CGI::Tr({-align=>"left"}, CGI::td(
  468 
  469             CGI::div({-style=>"background-color: #DDDDDD; margin: 0px auto"},
  470 CGI::span({-style=>"float:left ; text-align: left"},"File name: $sourceFileName "),
  471 CGI::span({-style=>"float:right ; text-align: right"}, $edit_link, " ", $try_link)
  472               ), CGI::br(),
  473 
  474 
  475 
  476 
  477             CGI::checkbox(-name=>"hideme$cnt",-value=>1,-label=>"Don't show me on the next update"),
  478             CGI::br(),
  479             CGI::checkbox((%add_box_data)),
  480             CGI::hidden(-name=>"filetrial$cnt", -default=>[$sourceFileName]).
  481             CGI::p($problem_output),
  482            ));
  483 }
  484 
  485 
  486 sub pre_header_initialize {
  487   my ($self) = @_;
  488   my $r = $self->r;
  489   ## For all cases, lets set some things
  490   $self->{error}=0;
  491   my $ce = $r->ce;
  492   my $db = $r->db;
  493   my $maxShown = $r->param('max_shown') || MAX_SHOW_DEFAULT;
  494   $maxShown = 10000000 if($maxShown eq 'All'); # let's hope there aren't more
  495 
  496   ##  These directories will have individual buttons
  497   %problib = %{$ce->{courseFiles}{problibs}} if $ce->{courseFiles}{problibs};
  498 
  499   my $userName = $r->param('user');
  500   my $user = $db->getUser($userName); # checked
  501   die "record for user $userName (real user) does not exist."
  502     unless defined $user;
  503   my $authz = $r->authz;
  504   unless ($authz->hasPermissions($userName, "modify_problem_sets")) {
  505     return(""); # Error message already produced in the body
  506   }
  507 
  508   ## Now one action we have to deal with here
  509   if ($r->param('edit_local')) {
  510     my $urlpath = $r->urlpath;
  511     my $db = $r->db;
  512     my $checkset = $db->getGlobalSet($r->param('local_sets'));
  513     if (not defined($checkset)) {
  514       $self->{error} = 1;
  515       $self->addbadmessage('You need to select a "Target Set" before you can edit it.');
  516     } else {
  517       my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetEditor', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID"));
  518       my $url = $self->systemLink($page);
  519       $self->reply_with_redirect($url);
  520     }
  521   }
  522 
  523   ## Next, lots of set up so that errors can be reported with message()
  524 
  525   ############# List of problems we have already printed
  526 
  527   $self->{past_problems} = get_past_problem_files($r);
  528   # if we don't end up reusing problems, this will be wiped out
  529   # if we do redisplay the same problems, we must adjust this accordingly
  530   my @past_marks = map {$_->[1]} @{$self->{past_problems}};
  531   my $none_shown = scalar(@{$self->{past_problems}})==0;
  532   my @pg_files=();
  533   my $use_previous_problems = 1;
  534   my $first_shown = $r->param('first_shown') || 0;
  535   my $last_shown = $r->param('last_shown');
  536   if (not defined($last_shown)) {
  537     $last_shown = -1;
  538   }
  539   my @all_past_list = (); # these are include requested, but not shown
  540   my $j = 0;
  541   while (defined($r->param("all_past_list$j"))) {
  542     push @all_past_list, $r->param("all_past_list$j");
  543     $j++;
  544   }
  545 
  546   ############# Default of which problem selector to display
  547 
  548   my $browse_which = $r->param('browse_which') || 'browse_local';
  549 
  550   my $problem_seed = $r->param('problem_seed') || 0;
  551   $r->param('problem_seed', $problem_seed); # if it wasn't defined before
  552 
  553   ## check for problem lib buttons
  554   my $browse_lib = '';
  555   foreach my $lib (keys %problib) {
  556     if ($r->param("browse_$lib")) {
  557       $browse_lib = "browse_$lib";
  558       last;
  559     }
  560   }
  561 
  562   ########### Start the logic through if elsif elsif ...
  563 
  564   ##### Asked to browse certain problems
  565   if ($browse_lib ne '') {
  566     $browse_which = $browse_lib;
  567     $r->param('library_sets', "");
  568     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  569   } elsif ($r->param('browse_library')) {
  570     $browse_which = 'browse_library';
  571     $r->param('library_sets', "");
  572     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  573   } elsif ($r->param('browse_local')) {
  574     $browse_which = 'browse_local';
  575     $r->param('library_sets', "");
  576     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  577   } elsif ($r->param('browse_mysets')) {
  578     $browse_which = 'browse_mysets';
  579     $r->param('library_sets', "");
  580     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  581 
  582     ##### Change the seed value
  583 
  584   } elsif ($r->param('rerandomize')) {
  585     $problem_seed++;
  586     $r->param('problem_seed', $problem_seed);
  587     $self->addbadmessage('Changing the problem seed for display, but there are no problems showing.') if $none_shown;
  588 
  589     ##### Clear the display
  590 
  591   } elsif ($r->param('cleardisplay')) {
  592     @pg_files = ();
  593     $use_previous_problems=0;
  594     $self->addbadmessage('The display was already cleared.') if $none_shown;
  595 
  596     ##### View problems selected from the local list
  597 
  598   } elsif ($r->param('view_local_set')) {
  599 
  600     my $set_to_display = $r->param('library_sets');
  601     if (not defined($set_to_display) or $set_to_display eq SELECT_LOCAL_STRING or $set_to_display eq "Found no directories containing problems") {
  602       $self->addbadmessage('You need to select a set to view.');
  603     } else {
  604       $set_to_display = '.' if $set_to_display eq MY_PROBLEMS;
  605       $set_to_display = substr($browse_which,7) if $set_to_display eq MAIN_PROBLEMS;
  606       @pg_files = list_pg_files($ce->{courseDirs}->{templates},
  607         "$set_to_display");
  608       $use_previous_problems=0;
  609     }
  610 
  611     ##### View problems selected from the a set in this course
  612 
  613   } elsif ($r->param('view_mysets_set')) {
  614 
  615     my $set_to_display = $r->param('library_sets');
  616     if (not defined($set_to_display)
  617         or $set_to_display eq "Select a Problem Set"
  618         or $set_to_display eq NO_LOCAL_SET_STRING) {
  619       $self->addbadmessage("You need to select a set from this course to view.");
  620     } else {
  621       my @problemList = $db->listGlobalProblems($set_to_display);
  622       my $problem;
  623       @pg_files=();
  624       for $problem (@problemList) {
  625   my $problemRecord = $db->getGlobalProblem($set_to_display, $problem); # checked
  626   die "global $problem for set $set_to_display not found." unless
  627     $problemRecord;
  628   push @pg_files, $problemRecord->source_file;
  629 
  630       }
  631       $use_previous_problems=0;
  632     }
  633 
  634     ##### View whole chapter from the library
  635     ## This will change somewhat later
  636 
  637   } elsif ($r->param('lib_view')) {
  638 
  639     @pg_files=();
  640     my $chap = $r->param('library_chapters') || "";
  641     $chap = "" if($chap eq "All Chapters");
  642     my $sect = $r->param('library_sections') || "";
  643     $sect = "" if($sect eq "All Sections");
  644     my @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r->{ce}, "$chap", "$sect");
  645     my ($result, $tolibpath);
  646     for $result (@dbsearch) {
  647       $tolibpath = "Library/$result->{path}/$result->{filename}";
  648 
  649       ## Too clunky!!!!
  650       push @pg_files, $tolibpath;
  651     }
  652     $use_previous_problems=0;
  653 
  654     ##### Edit the current local problem set
  655 
  656   } elsif ($r->param('edit_local')) { ## Jump to set edit page
  657 
  658     ; # already handled
  659 
  660 
  661     ##### Make a new local problem set
  662 
  663   } elsif ($r->param('new_local_set')) {
  664     if ($r->param('new_set_name') !~ /^[\w.-]*$/) {
  665       $self->addbadmessage("The name ".$r->param('new_set_name')." is not a valid set name.  Use only letters, digits, -, _, and .");
  666     } else {
  667       my $newSetName = $r->param('new_set_name');
  668       $newSetName =~ s/^set//;
  669       $newSetName =~ s/\.def$//;
  670       $r->param('local_sets',$newSetName);
  671       my $newSetRecord   = $db->getGlobalSet($newSetName);
  672       if (defined($newSetRecord)) {
  673   $self->addbadmessage("The set name $newSetName is already in use.  Pick a different name if you would like to start a new set.");
  674       } else {      # Do it!
  675   $newSetRecord = $db->{set}->{record}->new();
  676   $newSetRecord->set_id($newSetName);
  677   $newSetRecord->set_header("");
  678   $newSetRecord->problem_header("");
  679   $newSetRecord->open_date(time()+60*60*24*7); # in one week
  680   $newSetRecord->due_date(time()+60*60*24*7*2); # in two weeks
  681   $newSetRecord->answer_date(time()+60*60*24*7*3); # in three weeks
  682   eval {$db->addGlobalSet($newSetRecord)};
  683   $self->addgoodmessage("Set $newSetName has been created.");
  684   my $selfassign = $r->param('selfassign') || "";
  685   $selfassign = "" if($selfassign =~ /false/i); # deal with javascript false
  686   if($selfassign) {
  687     $self->assignSetToUser($userName, $newSetRecord);
  688     $self->addgoodmessage("Set $newSetName was assigned to $userName.");
  689         }
  690       }
  691     }
  692 
  693     ##### Add selected problems to the current local set
  694 
  695   } elsif ($r->param('update')) {
  696     ## first handle problems to be added before we hide them
  697     my($localSet, @selected);
  698 
  699     @pg_files = grep {($_->[1] & ADDED) != 0 } @{$self->{past_problems}};
  700     @selected = map {$_->[0]} @pg_files;
  701 
  702     my @action_files = grep {$_->[1] > 0 } @{$self->{past_problems}};
  703     # There are now good reasons to do an update without selecting anything.
  704     #if(scalar(@action_files) == 0) {
  705     #  $self->addbadmessage('Update requested, but no problems were marked.');
  706     #}
  707 
  708     if (scalar(@selected)>0) {  # if some are to be added, they need a place to go
  709       $localSet = $r->param('local_sets');
  710       if (not defined($localSet) or
  711           $localSet eq SELECT_SET_STRING or
  712     $localSet eq NO_LOCAL_SET_STRING) {
  713   $self->addbadmessage('You are trying to add problems to something, but you did not select a "Target Set" name as a target.');
  714       } else {
  715   my $newSetRecord   = $db->getGlobalSet($localSet);
  716   if (not defined($newSetRecord)) {
  717     $self->addbadmessage("You are trying to add problems to $localSet, but that set does not seem to exist!  I bet you used your \"Back\" button.");
  718   } else {
  719     my $addcount = add_selected($self, $db, $localSet);
  720     if($addcount > 0) {
  721       $self->addgoodmessage("Added $addcount problem".(($addcount>1)?'s':'').
  722         " to $localSet.");
  723     }
  724   }
  725       }
  726     }
  727     ## now handle problems to be hidden
  728 
  729     ## only keep the ones which are not hidden
  730     @pg_files = grep {($_->[1] & HIDDEN) ==0 } @{$self->{past_problems}};
  731     @past_marks = map {$_->[1]} @pg_files;
  732     @pg_files = map {$_->[0]} @pg_files;
  733     @all_past_list = (@all_past_list[0..($first_shown-1)],
  734           @pg_files,
  735           @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]);
  736     $last_shown = $first_shown+$maxShown -1;
  737     $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list));
  738 
  739   } elsif ($r->param('next_page')) {
  740     $first_shown = $last_shown+1;
  741     $last_shown = $first_shown+$maxShown-1;
  742     $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list));
  743     @past_marks = ();
  744   } elsif ($r->param('prev_page')) {
  745     $last_shown = $first_shown-1;
  746     $first_shown = $last_shown - $maxShown+1;
  747 
  748     $first_shown = 0 if($first_shown<0);
  749     @past_marks = ();
  750 
  751   } elsif ($r->param('select_all')) {
  752     @past_marks = map {1} @past_marks;
  753   } elsif ($r->param('select_none')) {
  754     @past_marks = ();
  755 
  756     ##### No action requested, probably our first time here
  757 
  758   } else {
  759     #my $c = $r->connection;
  760     #print "Debug info: ". $r->get_remote_host ."<p>".  $c->remote_ip ;
  761     ;
  762   }       ##### end of the if elsif ...
  763 
  764 
  765   ############# List of local sets
  766 
  767   my @all_set_defs = $db->listGlobalSets;
  768   for ($j=0; $j<scalar(@all_set_defs); $j++) {
  769     $all_set_defs[$j] =~ s|^set||;
  770     $all_set_defs[$j] =~ s|\.def||;
  771   }
  772 
  773   if ($use_previous_problems) {
  774     @pg_files = @all_past_list;
  775   } else {
  776     $first_shown = 0;
  777     $last_shown = scalar(@pg_files)<$maxShown ? scalar(@pg_files) : $maxShown;
  778     $last_shown--;    # to make it an array index
  779     @past_marks = ();
  780   }
  781   ############# Now store data in self for retreival by body
  782   $self->{first_shown} = $first_shown;
  783   $self->{last_shown} = $last_shown;
  784   $self->{browse_which} = $browse_which;
  785   $self->{problem_seed} = $problem_seed;
  786   $self->{pg_files} = \@pg_files;
  787   $self->{past_marks} = \@past_marks;
  788   $self->{all_set_defs} = \@all_set_defs;
  789 
  790 }
  791 
  792 
  793 sub title {
  794   return "Problem Set Maker";
  795 }
  796 
  797 sub body {
  798   my ($self) = @_;
  799 
  800   my $r = $self->r;
  801   my $ce = $r->ce;    # course environment
  802   my $db = $r->db;    # database
  803   my $j;      # garden variety counter
  804 
  805   my $userName = $r->param('user');
  806 
  807   my $user = $db->getUser($userName); # checked
  808   die "record for user $userName (real user) does not exist."
  809     unless defined $user;
  810 
  811   ### Check that this is a professor
  812   my $authz = $r->authz;
  813   unless ($authz->hasPermissions($userName, "modify_problem_sets")) {
  814     print "User $userName returned " .
  815       $authz->hasPermissions($user, "modify_problem_sets") .
  816   " for permission";
  817     return(CGI::div({class=>'ResultsWithError'},
  818     CGI::em("You are not authorized to access the Instructor tools.")));
  819   }
  820 
  821   ##########  Extract information computed in pre_header_initialize
  822 
  823   my $first_shown = $self->{first_shown};
  824   my $last_shown = $self->{last_shown};
  825   my $browse_which = $self->{browse_which};
  826   my $problem_seed = $self->{problem_seed};
  827   my @pg_files = @{$self->{pg_files}};
  828   my @all_set_defs = @{$self->{all_set_defs}};
  829 
  830   my @pg_html=($last_shown>=$first_shown) ?
  831     renderProblems(r=> $r,
  832                    user => $user,
  833                    problem_list => [@pg_files[$first_shown..$last_shown]],
  834                    displayMode => $r->param('mydisplayMode')) : ();
  835 
  836   ##########  Top part
  837   print CGI::startform({-method=>"POST", -action=>$r->uri, -name=>'mainform'}),
  838     $self->hidden_authen_fields,
  839       '<div align="center">',
  840   CGI::start_table({-border=>2});
  841   $self->make_top_row('all_set_defs'=>\@all_set_defs,
  842          'browse_which'=> $browse_which);
  843   print CGI::hidden(-name=>'browse_which', -default=>[$browse_which]),
  844     CGI::hidden(-name=>'problem_seed', -default=>[$problem_seed]);
  845   for ($j = 0 ; $j < scalar(@pg_files) ; $j++) {
  846     print CGI::hidden(-name=>"all_past_list$j", -default=>$pg_files[$j]);
  847   }
  848 
  849   print CGI::hidden(-name=>'first_shown', -default=>[$first_shown]);
  850   print CGI::hidden(-name=>'last_shown', -default=>[$last_shown]);
  851 
  852 
  853   ########## Now print problems
  854   my $jj;
  855   for ($jj=0; $jj<scalar(@pg_html); $jj++) {
  856     $pg_files[$jj] =~ s|^$ce->{courseDirs}->{templates}/?||;
  857     $self->make_data_row($pg_files[$jj+$first_shown], $pg_html[$jj], $jj+1, $self->{past_marks}->[$jj]);
  858   }
  859 
  860   ########## Finish things off
  861   print CGI::end_table();
  862   print '</div>';
  863   #  if($first_shown>0 or (1+$last_shown)<scalar(@pg_files)) {
  864   my ($next_button, $prev_button) = ("", "");
  865   if ($first_shown > 0) {
  866     $prev_button = CGI::submit(-name=>"prev_page", -style=>"width:15ex",
  867              -value=>"Previous page");
  868   }
  869   if ((1+$last_shown)<scalar(@pg_files)) {
  870     $next_button = CGI::submit(-name=>"next_page", -style=>"width:15ex",
  871              -value=>"Next page");
  872   }
  873   if (scalar(@pg_files)>0) {
  874     print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files).
  875      " shown.", $prev_button, " ", $next_button);
  876   }
  877   #  }
  878   print CGI::endform(), "\n";
  879 
  880   return "";
  881 }
  882 
  883 ############################################## End of Body
  884 
  885 # SKEL: To emit your own HTTP header, uncomment this:
  886 #
  887 #sub header {
  888 # my ($self) = @_;
  889 #
  890 # # Generate your HTTP header here.
  891 #
  892 # # If you return something, it will be used as the HTTP status code for this
  893 # # request. The Apache::Constants module might be useful for gerating status
  894 # # codes. If you don't return anything, the status code "OK" will be used.
  895 # return "";
  896 #}
  897 
  898 # SKEL: If you need to do any processing after the HTTP header is sent, but before
  899 # any template processing occurs, or you need to calculate values that will be
  900 # used in multiple methods, do it in this method:
  901 #
  902 #sub initialize {
  903 #my ($self) = @_;
  904 #}
  905 
  906 # SKEL: If you need to add tags to the document <HEAD>, uncomment this method:
  907 #
  908 #sub head {
  909 # my ($self) = @_;
  910 #
  911 # # You can print head tags here, like <META>, <SCRIPT>, etc.
  912 #
  913 # return "";
  914 #}
  915 
  916 # SKEL: To fill in the "info" box (to the right of the main body), use this
  917 # method:
  918 #
  919 #sub info {
  920 # my ($self) = @_;
  921 #
  922 # # Print HTML here.
  923 #
  924 # return "";
  925 #}
  926 
  927 # SKEL: To provide navigation links, use this method:
  928 #
  929 #sub nav {
  930 # my ($self, $args) = @_;
  931 #
  932 # # See the documentation of path() and pathMacro() in
  933 # # WeBWorK::ContentGenerator for more information.
  934 #
  935 # return "";
  936 #}
  937 
  938 # SKEL: For a little box for display options, etc., use this method:
  939 #
  940 #sub options {
  941 # my ($self) = @_;
  942 #
  943 # # Print HTML here.
  944 #
  945 # return "";
  946 #}
  947 
  948 # SKEL: For a list of sibling objects, use this method:
  949 #
  950 #sub siblings {
  951 # my ($self, $args) = @_;
  952 #
  953 # # See the documentation of siblings() and siblingsMacro() in
  954 # # WeBWorK::ContentGenerator for more information.
  955 # #
  956 # # Refer to implementations in ProblemSet and Problem.
  957 #
  958 # return "";
  959 #}
  960 
  961 =head1 AUTHOR
  962 
  963 Written by John Jones, jj (at) asu.edu.
  964 
  965 =cut
  966 
  967 
  968 
  969 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9