[system] / branches / rel-2-4-patches / webwork-modperl / lib / WeBWorK / ContentGenerator / CourseAdmin.pm Repository:
ViewVC logotype

View of /branches/rel-2-4-patches/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2853 - (download) (as text) (annotate)
Wed Sep 29 23:45:42 2004 UTC (8 years, 7 months ago) by sh002i
Original Path: trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm
File size: 41574 byte(s)
don't send stupid header for safari, don't set feedbackRecipients.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v 1.28 2004/09/29 16:19:37 sh002i 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::CourseAdmin;
   18 use base qw(WeBWorK::ContentGenerator);
   19 
   20 =head1 NAME
   21 
   22 WeBWorK::ContentGenerator::CourseAdmin - Add, rename, and delete courses.
   23 
   24 =cut
   25 
   26 use strict;
   27 use warnings;
   28 use CGI::Pretty qw();
   29 use Data::Dumper;
   30 use File::Temp qw/tempfile/;
   31 use WeBWorK::CourseEnvironment;
   32 use WeBWorK::Utils qw(cryptPassword writeLog);
   33 use WeBWorK::Utils::CourseManagement qw(addCourse deleteCourse listCourses);
   34 use WeBWorK::Utils::DBImportExport qw(dbExport dbImport);
   35 
   36 # put the following database layouts at the top of the list, in this order
   37 our @DB_LAYOUT_ORDER = qw/sql_single gdbm sql/;
   38 
   39 our %DB_LAYOUT_DESCRIPTIONS = (
   40   gdbm => "Deprecated. Uses GDBM databases to record WeBWorK data. Use this layout if the course must be used with WeBWorK 1.x.",
   41   sql => "Deprecated. Uses a separate SQL database to record WeBWorK data for each course.",
   42   sql_single => "Uses a single SQL database to record WeBWorK data for all courses using this layout. This is the recommended layout for new courses.",
   43 );
   44 
   45 sub pre_header_initialize {
   46   my ($self) = @_;
   47   my $r = $self->r;
   48   my $ce = $r->ce;
   49   my $db = $r->db;
   50   my $authz = $r->authz;
   51   my $urlpath = $r->urlpath;
   52   my $user        = $r->param('user');
   53 
   54   # check permissions
   55   unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
   56     $self->addmessage( CGI::div({class=>'ResultsWithError'},"$user is not authorized to create or delete courses") );
   57     return;
   58   }
   59 
   60   ## if the user is asking for the downloaded database...
   61   #if (defined $r->param("download_exported_database")) {
   62   # my $courseID = $r->param("export_courseID");
   63   # my $random_chars = $r->param("download_exported_database");
   64   #
   65   # die "courseID not specified" unless defined $courseID;
   66   # die "invalid file specification" unless $random_chars =~ m/^\w+$/;
   67   #
   68   # my $tempdir = $ce->{webworkDirs}->{tmp};
   69   # my $export_file = "$tempdir/db_export_$random_chars";
   70   #
   71   # $self->reply_with_file("application/xml", $export_file, "${courseID}_database.xml", 0);
   72   #
   73   # return "";
   74   #}
   75   #
   76   ## otherwise...
   77 
   78   my @errors;
   79   my $method_to_call;
   80 
   81   my $subDisplay = $r->param("subDisplay");
   82   if (defined $subDisplay) {
   83 
   84     if ($subDisplay eq "add_course") {
   85       if (defined $r->param("add_course")) {
   86         @errors = $self->add_course_validate;
   87         if (@errors) {
   88           $method_to_call = "add_course_form";
   89         } else {
   90           $method_to_call = "do_add_course";
   91         }
   92       } else {
   93         $method_to_call = "add_course_form";
   94       }
   95     }
   96 
   97     elsif ($subDisplay eq "delete_course") {
   98       if (defined $r->param("delete_course")) {
   99         # validate or confirm
  100         @errors = $self->delete_course_validate;
  101         if (@errors) {
  102           $method_to_call = "delete_course_form";
  103         } else {
  104           $method_to_call = "delete_course_confirm";
  105         }
  106       } elsif (defined $r->param("confirm_delete_course")) {
  107         # validate and delete
  108         @errors = $self->delete_course_validate;
  109         if (@errors) {
  110           $method_to_call = "delete_course_form";
  111         } else {
  112           $method_to_call = "do_delete_course";
  113         }
  114       } else {
  115         # form only
  116         $method_to_call = "delete_course_form";
  117       }
  118     }
  119 
  120     elsif ($subDisplay eq "export_database") {
  121       if (defined $r->param("export_database")) {
  122         @errors = $self->export_database_validate;
  123         if (@errors) {
  124           $method_to_call = "export_database_form";
  125         } else {
  126           # we have to do something special here, since we're sending
  127           # the database as we export it. $method_to_call still gets
  128           # set here, but it gets caught by header() and content()
  129           # below instead of by body().
  130           $method_to_call = "do_export_database";
  131         }
  132       } else {
  133         $method_to_call = "export_database_form";
  134       }
  135     }
  136 
  137     elsif ($subDisplay eq "import_database") {
  138       if (defined $r->param("import_database")) {
  139         @errors = $self->import_database_validate;
  140         if (@errors) {
  141           $method_to_call = "import_database_form";
  142         } else {
  143           $method_to_call = "do_import_database";
  144         }
  145       } else {
  146         $method_to_call = "import_database_form";
  147       }
  148     }
  149 
  150     else {
  151       @errors = "Unrecognized sub-display @{[ CGI::b($subDisplay) ]}.";
  152     }
  153 
  154   }
  155 
  156   $self->{errors} = \@errors;
  157   $self->{method_to_call} = $method_to_call;
  158 }
  159 
  160 sub header {
  161   my ($self) = @_;
  162   my $method_to_call = $self->{method_to_call};
  163   if (defined $method_to_call and $method_to_call eq "do_export_database") {
  164     my $r = $self->r;
  165     my $courseID = $r->param("export_courseID");
  166     $r->content_type("application/octet-stream");
  167     $r->header_out("Content-Disposition" => "attachment; filename=\"${courseID}_database.xml\"");
  168     $r->send_http_header;
  169   } else {
  170     $self->SUPER::header;
  171   }
  172 }
  173 
  174 # sends:
  175 #
  176 # HTTP/1.1 200 OK
  177 # Date: Fri, 09 Jul 2004 19:05:55 GMT
  178 # Server: Apache/1.3.27 (Unix) mod_perl/1.27
  179 # Content-Disposition: attachment; filename="mth143_database.xml"
  180 # Connection: close
  181 # Content-Type: application/octet-stream
  182 
  183 sub content {
  184   my ($self) = @_;
  185   my $method_to_call = $self->{method_to_call};
  186   if (defined $method_to_call and $method_to_call eq "do_export_database") {
  187     #print "<!-- ̣Ջ͗ -->\n";
  188     #print "<!-- Those were some high-bit characters to convince Safari that we really do want this saved as a file. -->\n";
  189     $self->do_export_database;
  190   } else {
  191     $self->SUPER::content;
  192   }
  193 }
  194 
  195 sub body {
  196   my ($self) = @_;
  197   my $r = $self->r;
  198   my $ce = $r->ce;
  199   my $db = $r->db;
  200   my $authz = $r->authz;
  201   my $urlpath = $r->urlpath;
  202 
  203   my $user = $r->param('user');
  204 
  205   # check permissions
  206   unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
  207     return "";
  208   }
  209 
  210   print CGI::p({style=>"text-align: center"},
  211     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"add_course"})}, "Add Course"),
  212     " | ",
  213     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"delete_course"})}, "Delete Course"),
  214     " | ",
  215     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"export_database"})}, "Export Database"),
  216     " | ",
  217     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"import_database"})}, "Import Database"),
  218   );
  219 
  220   print CGI::hr();
  221 
  222   my @errors = @{$self->{errors}};
  223   my $method_to_call = $self->{method_to_call};
  224 
  225   if (@errors) {
  226     print CGI::div({class=>"ResultsWithError"},
  227       CGI::p("Please correct the following errors and try again:"),
  228       CGI::ul(CGI::li(\@errors)),
  229     );
  230   }
  231 
  232   if (defined $method_to_call and $method_to_call ne "") {
  233     $self->$method_to_call;
  234   }
  235 
  236   return "";
  237 }
  238 
  239 ################################################################################
  240 
  241 sub add_course_form {
  242   my ($self) = @_;
  243   my $r = $self->r;
  244   my $ce = $r->ce;
  245   #my $db = $r->db;
  246   #my $authz = $r->authz;
  247   #my $urlpath = $r->urlpath;
  248 
  249   my $add_courseID                     = $r->param("add_courseID") || "";
  250   my $add_courseTitle                  = $r->param("add_courseTitle") || "";
  251   my $add_courseInstitution            = $r->param("add_courseInstitution") || "";
  252 
  253   my $add_admin_users                  = $r->param("add_admin_users") || "";
  254 
  255   my $add_initial_userID               = $r->param("add_initial_userID") || "";
  256   my $add_initial_password             = $r->param("add_initial_password") || "";
  257   my $add_initial_confirmPassword      = $r->param("add_initial_confirmPassword") || "";
  258   my $add_initial_firstName            = $r->param("add_initial_firstName") || "";
  259   my $add_initial_lastName             = $r->param("add_initial_lastName") || "";
  260   my $add_initial_email                = $r->param("add_initial_email") || "";
  261 
  262   my $add_templates_course             = $r->param("add_templates_course") || "";
  263 
  264   my $add_dbLayout                     = $r->param("add_dbLayout") || "";
  265   my $add_sql_host                     = $r->param("add_sql_host") || "";
  266   my $add_sql_port                     = $r->param("add_sql_port") || "";
  267   my $add_sql_username                 = $r->param("add_sql_username") || "";
  268   my $add_sql_password                 = $r->param("add_sql_password") || "";
  269   my $add_sql_database                 = $r->param("add_sql_database") || "";
  270   my $add_sql_wwhost                   = $r->param("add_sql_wwhost") || "";
  271   my $add_gdbm_globalUserID            = $r->param("add_gdbm_globalUserID") || "";
  272 
  273   my @dbLayouts = do {
  274     my @ordered_layouts;
  275     foreach my $layout (@DB_LAYOUT_ORDER) {
  276       if (exists $ce->{dbLayouts}->{$layout}) {
  277         push @ordered_layouts, $layout;
  278       }
  279     }
  280 
  281     my %ordered_layouts; @ordered_layouts{@ordered_layouts} = ();
  282     my @other_layouts;
  283     foreach my $layout (keys %{ $ce->{dbLayouts} }) {
  284       unless (exists $ordered_layouts{$layout}) {
  285         push @other_layouts, $layout;
  286       }
  287     }
  288 
  289     (@ordered_layouts, @other_layouts);
  290   };
  291 
  292   my $ce2 = WeBWorK::CourseEnvironment->new(
  293     $ce->{webworkDirs}->{root},
  294     $ce->{webworkURLs}->{root},
  295     $ce->{pg}->{directories}->{root},
  296     "COURSENAME",
  297   );
  298 
  299   my $dbi_source = do {
  300     # find the most common SQL source (stolen from CourseManagement.pm)
  301     my %sources;
  302     foreach my $table (keys %{ $ce2->{dbLayouts}->{sql} }) {
  303       $sources{$ce2->{dbLayouts}->{sql}->{$table}->{source}}++;
  304     }
  305     my $source;
  306     if (keys %sources > 1) {
  307       foreach my $curr (keys %sources) {
  308         $source = $curr if not defined $source or
  309           $sources{$curr} > $sources{$source};
  310       }
  311     } else {
  312       ($source) = keys %sources;
  313     }
  314     $source;
  315   };
  316 
  317   my @existingCourses = listCourses($ce);
  318   @existingCourses = sort @existingCourses;
  319 
  320   print CGI::h2("Add Course");
  321 
  322   print CGI::start_form("POST", $r->uri);
  323   print $self->hidden_authen_fields;
  324   print $self->hidden_fields("subDisplay");
  325 
  326   print CGI::p("Specify an ID, title, and institution for the new course. The course ID may contain only letters, numbers, hyphens, and underscores.");
  327 
  328   print CGI::table({class=>"FormLayout"},
  329     CGI::Tr(
  330       CGI::th({class=>"LeftHeader"}, "Course ID:"),
  331       CGI::td(CGI::textfield("add_courseID", $add_courseID, 25)),
  332     ),
  333     CGI::Tr(
  334       CGI::th({class=>"LeftHeader"}, "Course Title:"),
  335       CGI::td(CGI::textfield("add_courseTitle", $add_courseTitle, 25)),
  336     ),
  337     CGI::Tr(
  338       CGI::th({class=>"LeftHeader"}, "Institution:"),
  339       CGI::td(CGI::textfield("add_courseInstitution", $add_courseInstitution, 25)),
  340     ),
  341   );
  342 
  343   print CGI::p("To add the WeBWorK administrators to the new course (as instructors) check the box below.");
  344 
  345   print CGI::p(CGI::checkbox("add_admin_users", $add_admin_users, "on", "Add WeBWorK administrators to new course"));
  346 
  347   print CGI::p("To add an additional instructor to the new course, specify user information below. The user ID may contain only numbers, letters, hyphens, and underscores.");
  348 
  349   print CGI::table({class=>"FormLayout"}, CGI::Tr(
  350     CGI::td(
  351       CGI::table({class=>"FormLayout"},
  352         CGI::Tr(
  353           CGI::th({class=>"LeftHeader"}, "User ID:"),
  354           CGI::td(CGI::textfield("add_initial_userID", $add_initial_userID, 25)),
  355         ),
  356         CGI::Tr(
  357           CGI::th({class=>"LeftHeader"}, "Password:"),
  358           CGI::td(CGI::password_field("add_initial_password", $add_initial_password, 25)),
  359         ),
  360         CGI::Tr(
  361           CGI::th({class=>"LeftHeader"}, "Confirm Password:"),
  362           CGI::td(CGI::password_field("add_initial_confirmPassword", $add_initial_confirmPassword, 25)),
  363         ),
  364       ),
  365     ),
  366     CGI::td(
  367       CGI::table({class=>"FormLayout"},
  368         CGI::Tr(
  369           CGI::th({class=>"LeftHeader"}, "First Name:"),
  370           CGI::td(CGI::textfield("add_initial_firstName", $add_initial_firstName, 25)),
  371         ),
  372         CGI::Tr(
  373           CGI::th({class=>"LeftHeader"}, "Last Name:"),
  374           CGI::td(CGI::textfield("add_initial_lastName", $add_initial_lastName, 25)),
  375         ),
  376         CGI::Tr(
  377           CGI::th({class=>"LeftHeader"}, "Email Address:"),
  378           CGI::td(CGI::textfield("add_initial_email", $add_initial_email, 25)),
  379         ),
  380       ),
  381 
  382     ),
  383   ));
  384 
  385   print CGI::p("To copy problem templates from an existing course, select the course below.");
  386 
  387   print CGI::table({class=>"FormLayout"},
  388     CGI::Tr(
  389       CGI::th({class=>"LeftHeader"}, "Copy templates from:"),
  390       CGI::td(
  391         CGI::popup_menu(
  392           -name => "add_templates_course",
  393           -values => [ "", @existingCourses ],
  394           -default => $add_templates_course,
  395           #-size => 10,
  396           #-multiple => 0,
  397           #-labels => \%courseLabels,
  398         ),
  399 
  400       ),
  401     ),
  402   );
  403 
  404   print CGI::p("Select a database layout below.");
  405 
  406   foreach my $dbLayout (@dbLayouts) {
  407     print CGI::start_table({class=>"FormLayout"});
  408 
  409     my $dbLayoutLabel = (defined $DB_LAYOUT_DESCRIPTIONS{$dbLayout})
  410       ? "$dbLayout - $DB_LAYOUT_DESCRIPTIONS{$dbLayout}"
  411       : $dbLayout;
  412 
  413     # we generate singleton radio button tags ourselves because it's too much of a pain to do it with CGI.pm
  414     print CGI::Tr(
  415       CGI::td({style=>"text-align: right"},
  416         '<input type="radio" name="add_dbLayout" value="' . $dbLayout . '"'
  417         . ($add_dbLayout eq $dbLayout ? " checked" : "") . ' />',
  418       ),
  419       CGI::td($dbLayoutLabel),
  420     );
  421 
  422     print CGI::start_Tr();
  423     print CGI::td(); # for indentation :(
  424     print CGI::start_td();
  425 
  426     if ($dbLayout eq "sql") {
  427       print CGI::start_table({class=>"FormLayout"});
  428       print CGI::Tr(CGI::td({colspan=>2},
  429           "Enter the user ID and password for an SQL account with sufficient permissions to create a new database."
  430         )
  431       );
  432       print CGI::Tr(
  433         CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
  434         CGI::td(CGI::textfield("add_sql_username", $add_sql_username, 25)),
  435       );
  436       print CGI::Tr(
  437         CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
  438         CGI::td(CGI::password_field("add_sql_password", $add_sql_password, 25)),
  439       );
  440 
  441       print CGI::Tr(CGI::td({colspan=>2},
  442           "The optionial SQL settings you enter below must match the settings in the DBI source"
  443           . " specification " . CGI::tt($dbi_source) . ". Replace " . CGI::tt("COURSENAME")
  444           . " with the course name you entered above."
  445         )
  446       );
  447       print CGI::Tr(
  448         CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  449         CGI::td(
  450           CGI::textfield("add_sql_host", $add_sql_host, 25),
  451           CGI::br(),
  452           CGI::small("Leave blank to use the default host."),
  453         ),
  454       );
  455       print CGI::Tr(
  456         CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  457         CGI::td(
  458           CGI::textfield("add_sql_port", $add_sql_port, 25),
  459           CGI::br(),
  460           CGI::small("Leave blank to use the default port."),
  461         ),
  462       );
  463 
  464       print CGI::Tr(
  465         CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  466         CGI::td(
  467           CGI::textfield("add_sql_database", $add_sql_database, 25),
  468           CGI::br(),
  469           CGI::small("Leave blank to use the name ", CGI::tt("webwork_COURSENAME"), "."),
  470         ),
  471       );
  472       print CGI::Tr(
  473         CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"),
  474         CGI::td(
  475           CGI::textfield("add_sql_wwhost", $add_sql_wwhost || "localhost", 25),
  476           CGI::br(),
  477           CGI::small("If the SQL server does not run on the same host as WeBWorK, enter the host name of the WeBWorK server as seen by the SQL server."),
  478         ),
  479       );
  480       print CGI::end_table();
  481     } elsif ($dbLayout eq "gdbm") {
  482       print CGI::start_table({class=>"FormLayout"});
  483       print CGI::Tr(
  484         CGI::th({class=>"LeftHeader"}, "GDBM Global User ID:"),
  485         CGI::td(CGI::textfield("add_gdbm_globalUserID", $add_gdbm_globalUserID || "global_user", 25)),
  486       );
  487       print CGI::end_table();
  488     }
  489 
  490     print CGI::end_td();
  491     print CGI::end_Tr();
  492     print CGI::end_table();
  493   }
  494 
  495   print CGI::p({style=>"text-align: center"}, CGI::submit("add_course", "Add Course"));
  496 
  497   print CGI::end_form();
  498 }
  499 
  500 sub add_course_validate {
  501   my ($self) = @_;
  502   my $r = $self->r;
  503   my $ce = $r->ce;
  504   #my $db = $r->db;
  505   #my $authz = $r->authz;
  506   #my $urlpath = $r->urlpath;
  507 
  508   my $add_courseID                     = $r->param("add_courseID") || "";
  509   my $add_courseTitle                  = $r->param("add_courseTitle") || "";
  510   my $add_courseInstitution            = $r->param("add_courseInstitution") || "";
  511 
  512   my $add_admin_users                  = $r->param("add_admin_users") || "";
  513 
  514   my $add_initial_userID               = $r->param("add_initial_userID") || "";
  515   my $add_initial_password             = $r->param("add_initial_password") || "";
  516   my $add_initial_confirmPassword      = $r->param("add_initial_confirmPassword") || "";
  517   my $add_initial_firstName            = $r->param("add_initial_firstName") || "";
  518   my $add_initial_lastName             = $r->param("add_initial_lastName") || "";
  519   my $add_initial_email                = $r->param("add_initial_email") || "";
  520 
  521   my $add_templates_course             = $r->param("add_templates_course") || "";
  522 
  523   my $add_dbLayout                     = $r->param("add_dbLayout") || "";
  524   my $add_sql_host                     = $r->param("add_sql_host") || "";
  525   my $add_sql_port                     = $r->param("add_sql_port") || "";
  526   my $add_sql_username                 = $r->param("add_sql_username") || "";
  527   my $add_sql_password                 = $r->param("add_sql_password") || "";
  528   my $add_sql_database                 = $r->param("add_sql_database") || "";
  529   my $add_sql_wwhost                   = $r->param("add_sql_wwhost") || "";
  530   my $add_gdbm_globalUserID            = $r->param("add_gdbm_globalUserID") || "";
  531 
  532   my @errors;
  533 
  534   if ($add_courseID eq "") {
  535     push @errors, "You must specify a course ID.";
  536   }
  537   if (grep { $add_courseID eq $_ } listCourses($ce)) {
  538     push @errors, "A course with ID $add_courseID already exists.";
  539   }
  540   if ($add_courseTitle eq "") {
  541     push @errors, "You must specify a course title.";
  542   }
  543   if ($add_courseInstitution eq "") {
  544     push @errors, "You must specify an institution for this course.";
  545   }
  546 
  547   if ($add_initial_userID ne "") {
  548     if ($add_initial_password eq "") {
  549       push @errors, "You must specify a password for the initial instructor.";
  550     }
  551     if ($add_initial_confirmPassword eq "") {
  552       push @errors, "You must confirm the password for the initial instructor.";
  553     }
  554     if ($add_initial_password ne $add_initial_confirmPassword) {
  555       push @errors, "The password and password confirmation for the instructor must match.";
  556     }
  557     if ($add_initial_firstName eq "") {
  558       push @errors, "You must specify a first name for the initial instructor.";
  559     }
  560     if ($add_initial_lastName eq "") {
  561       push @errors, "You must specify a last name for the initial instructor.";
  562     }
  563     if ($add_initial_email eq "") {
  564       push @errors, "You must specify an email address for the initial instructor.";
  565     }
  566   }
  567 
  568   if ($add_dbLayout eq "") {
  569     push @errors, "You must select a database layout.";
  570   } else {
  571     if (exists $ce->{dbLayouts}->{$add_dbLayout}) {
  572       if ($add_dbLayout eq "sql") {
  573         push @errors, "You must specify the SQL admin username." if $add_sql_username eq "";
  574         push @errors, "You must specify the WeBWorK host." if $add_sql_wwhost eq "";
  575       } elsif ($add_dbLayout eq "gdbm") {
  576         push @errors, "You must specify the GDBM global user ID." if $add_gdbm_globalUserID eq "";
  577       }
  578     } else {
  579       push @errors, "The database layout $add_dbLayout doesn't exist.";
  580     }
  581   }
  582 
  583   return @errors;
  584 }
  585 
  586 sub do_add_course {
  587   my ($self) = @_;
  588   my $r = $self->r;
  589   my $ce = $r->ce;
  590   my $db = $r->db;
  591   #my $authz = $r->authz;
  592   my $urlpath = $r->urlpath;
  593 
  594   my $add_courseID                     = $r->param("add_courseID") || "";
  595   my $add_courseTitle                  = $r->param("add_courseTitle") || "";
  596   my $add_courseInstitution            = $r->param("add_courseInstitution") || "";
  597 
  598   my $add_admin_users                  = $r->param("add_admin_users") || "";
  599 
  600   my $add_initial_userID               = $r->param("add_initial_userID") || "";
  601   my $add_initial_password             = $r->param("add_initial_password") || "";
  602   my $add_initial_confirmPassword      = $r->param("add_initial_confirmPassword") || "";
  603   my $add_initial_firstName            = $r->param("add_initial_firstName") || "";
  604   my $add_initial_lastName             = $r->param("add_initial_lastName") || "";
  605   my $add_initial_email                = $r->param("add_initial_email") || "";
  606 
  607   my $add_templates_course             = $r->param("add_templates_course") || "";
  608 
  609   my $add_dbLayout                     = $r->param("add_dbLayout") || "";
  610   my $add_sql_host                     = $r->param("add_sql_host") || "";
  611   my $add_sql_port                     = $r->param("add_sql_port") || "";
  612   my $add_sql_username                 = $r->param("add_sql_username") || "";
  613   my $add_sql_password                 = $r->param("add_sql_password") || "";
  614   my $add_sql_database                 = $r->param("add_sql_database") || "";
  615   my $add_sql_wwhost                   = $r->param("add_sql_wwhost") || "";
  616   my $add_gdbm_globalUserID            = $r->param("add_gdbm_globalUserID") || "";
  617 
  618   my $ce2 = WeBWorK::CourseEnvironment->new(
  619     $ce->{webworkDirs}->{root},
  620     $ce->{webworkURLs}->{root},
  621     $ce->{pg}->{directories}->{root},
  622     $add_courseID,
  623   );
  624 
  625   my %courseOptions = ( dbLayoutName => $add_dbLayout );
  626 
  627   if ($add_initial_email ne "") {
  628     $courseOptions{allowedRecipients} = [ $add_initial_email ];
  629     # don't set feedbackRecipients -- this just gets in the way of the more
  630     # intelligent "receive_recipients" method.
  631     #$courseOptions{feedbackRecipients} = [ $add_initial_email ];
  632   }
  633 
  634   if ($add_dbLayout eq "gdbm") {
  635     $courseOptions{globalUserID} = $add_gdbm_globalUserID if $add_gdbm_globalUserID ne "";
  636   }
  637 
  638   my %dbOptions;
  639   if ($add_dbLayout eq "sql") {
  640     $dbOptions{host}     = $add_sql_host if $add_sql_host ne "";
  641     $dbOptions{port}     = $add_sql_port if $add_sql_port ne "";
  642     $dbOptions{username} = $add_sql_username;
  643     $dbOptions{password} = $add_sql_password;
  644     $dbOptions{database} = $add_sql_database || "webwork_$add_courseID";
  645     $dbOptions{wwhost}   = $add_sql_wwhost;
  646   }
  647 
  648   my @users;
  649 
  650   # copy users from current (admin) course if desired
  651   if ($add_admin_users ne "") {
  652     foreach my $userID ($db->listUsers) {
  653       my $User            = $db->getUser($userID);
  654       my $Password        = $db->getPassword($userID);
  655       my $PermissionLevel = $db->getPermissionLevel($userID);
  656       push @users, [ $User, $Password, $PermissionLevel ];
  657     }
  658   }
  659 
  660   # add initial instructor if desired
  661   if ($add_initial_userID ne "") {
  662     my $User = $db->newUser(
  663       user_id       => $add_initial_userID,
  664       first_name    => $add_initial_firstName,
  665       last_name     => $add_initial_lastName,
  666       student_id    => $add_initial_userID,
  667       email_address => $add_initial_email,
  668       status        => "C",
  669     );
  670     my $Password = $db->newPassword(
  671       user_id  => $add_initial_userID,
  672       password => cryptPassword($add_initial_password),
  673     );
  674     my $PermissionLevel = $db->newPermissionLevel(
  675       user_id    => $add_initial_userID,
  676       permission => "10",
  677     );
  678     push @users, [ $User, $Password, $PermissionLevel ];
  679   }
  680 
  681   push @{$courseOptions{PRINT_FILE_NAMES_FOR}}, map { $_->[0]->user_id } @users;
  682 
  683   my %optional_arguments;
  684   if ($add_templates_course ne "") {
  685     $optional_arguments{templatesFrom} = $add_templates_course;
  686   }
  687 
  688   eval {
  689     addCourse(
  690       courseID      => $add_courseID,
  691       ce            => $ce2,
  692       courseOptions => \%courseOptions,
  693       dbOptions     => \%dbOptions,
  694       users         => \@users,
  695       %optional_arguments,
  696     );
  697   };
  698   if ($@) {
  699     my $error = $@;
  700     print CGI::div({class=>"ResultsWithError"},
  701       CGI::p("An error occured while creating the course $add_courseID:"),
  702       CGI::tt(CGI::escapeHTML($error)),
  703     );
  704     # get rid of any partially built courses
  705     # FIXME  -- this is too fragile
  706     unless ($error =~ /course exists/) {
  707       eval {
  708         deleteCourse(
  709           courseID   => $add_courseID,
  710           ce         => $ce2,
  711           dbOptions  => \%dbOptions,
  712         );
  713       }
  714     }
  715   } else {
  716       #log the action
  717       writeLog($ce, "hosted_courses", join("\t",
  718         "\tAdded",
  719         $add_courseInstitution,
  720         $add_courseTitle,
  721         $add_courseID,
  722         $add_initial_firstName,
  723         $add_initial_lastName,
  724         $add_initial_email,
  725       ));
  726       # add contact to admin course as student?
  727       # FIXME -- should we do this?
  728     print CGI::div({class=>"ResultsWithoutError"},
  729       CGI::p("Successfully created the course $add_courseID"),
  730     );
  731     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
  732       courseID => $add_courseID);
  733     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
  734     print CGI::div({style=>"text-align: center"},
  735       CGI::a({href=>$newCourseURL}, "Log into $add_courseID"),
  736     );
  737   }
  738 
  739 
  740 }
  741 
  742 ################################################################################
  743 
  744 sub delete_course_form {
  745   my ($self) = @_;
  746   my $r = $self->r;
  747   my $ce = $r->ce;
  748   #my $db = $r->db;
  749   #my $authz = $r->authz;
  750   #my $urlpath = $r->urlpath;
  751 
  752   my $delete_courseID     = $r->param("delete_courseID")     || "";
  753   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  754   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  755   my $delete_sql_username = $r->param("delete_sql_username") || "";
  756   my $delete_sql_password = $r->param("delete_sql_password") || "";
  757   my $delete_sql_database = $r->param("delete_sql_database")    || "";
  758 
  759   my @courseIDs = listCourses($ce);
  760   @courseIDs    = sort @courseIDs;
  761 
  762   my %courseLabels; # records... heh.
  763   foreach my $courseID (@courseIDs) {
  764     my $tempCE = WeBWorK::CourseEnvironment->new(
  765       $ce->{webworkDirs}->{root},
  766       $ce->{webworkURLs}->{root},
  767       $ce->{pg}->{directories}->{root},
  768       $courseID,
  769     );
  770     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
  771   }
  772 
  773   print CGI::h2("Delete Course");
  774 
  775   print CGI::start_form("POST", $r->uri);
  776   print $self->hidden_authen_fields;
  777   print $self->hidden_fields("subDisplay");
  778 
  779   print CGI::p("Select a course to delete.");
  780 
  781   print CGI::table({class=>"FormLayout"},
  782     CGI::Tr(
  783       CGI::th({class=>"LeftHeader"}, "Course Name:"),
  784       CGI::td(
  785         CGI::scrolling_list(
  786           -name => "delete_courseID",
  787           -values => \@courseIDs,
  788           -default => $delete_courseID,
  789           -size => 10,
  790           -multiple => 0,
  791           -labels => \%courseLabels,
  792         ),
  793       ),
  794     ),
  795   );
  796 
  797   print CGI::p(
  798     "If the course's database layout (indicated in parentheses above) is "
  799     . CGI::b("sql") . ", supply the SQL connections information requested below."
  800   );
  801 
  802   print CGI::start_table({class=>"FormLayout"});
  803   print CGI::Tr(CGI::td({colspan=>2},
  804       "Enter the user ID and password for an SQL account with sufficient permissions to delete an existing database."
  805     )
  806   );
  807   print CGI::Tr(
  808     CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
  809     CGI::td(CGI::textfield("delete_sql_username", $delete_sql_username, 25)),
  810   );
  811   print CGI::Tr(
  812     CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
  813     CGI::td(CGI::password_field("delete_sql_password", $delete_sql_password, 25)),
  814   );
  815 
  816   #print CGI::Tr(CGI::td({colspan=>2},
  817   #   "The optionial SQL settings you enter below must match the settings in the DBI source"
  818   #   . " specification " . CGI::tt($dbi_source) . ". Replace " . CGI::tt("COURSENAME")
  819   #   . " with the course name you entered above."
  820   # )
  821   #);
  822   print CGI::Tr(
  823     CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  824     CGI::td(
  825       CGI::textfield("delete_sql_host", $delete_sql_host, 25),
  826       CGI::br(),
  827       CGI::small("Leave blank to use the default host."),
  828     ),
  829   );
  830   print CGI::Tr(
  831     CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  832     CGI::td(
  833       CGI::textfield("delete_sql_port", $delete_sql_port, 25),
  834       CGI::br(),
  835       CGI::small("Leave blank to use the default port."),
  836     ),
  837   );
  838 
  839   print CGI::Tr(
  840     CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  841     CGI::td(
  842       CGI::textfield("delete_sql_database", $delete_sql_database, 25),
  843       CGI::br(),
  844       CGI::small("Leave blank to use the name ", CGI::tt("webwork_COURSENAME"), "."),
  845     ),
  846   );
  847   print CGI::end_table();
  848 
  849   print CGI::p({style=>"text-align: center"}, CGI::submit("delete_course", "Delete Course"));
  850 
  851   print CGI::end_form();
  852 }
  853 
  854 sub delete_course_validate {
  855   my ($self) = @_;
  856   my $r = $self->r;
  857   my $ce = $r->ce;
  858   #my $db = $r->db;
  859   #my $authz = $r->authz;
  860   my $urlpath = $r->urlpath;
  861 
  862   my $delete_courseID     = $r->param("delete_courseID")     || "";
  863   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  864   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  865   my $delete_sql_username = $r->param("delete_sql_username") || "";
  866   my $delete_sql_password = $r->param("delete_sql_password") || "";
  867   my $delete_sql_database = $r->param("delete_sql_database") || "";
  868 
  869   my @errors;
  870 
  871   if ($delete_courseID eq "") {
  872     push @errors, "You must specify a course name.";
  873   } elsif ($delete_courseID eq $urlpath->arg("courseID")) {
  874     push @errors, "You cannot delete the course you are currently using.";
  875   }
  876 
  877   my $ce2 = WeBWorK::CourseEnvironment->new(
  878     $ce->{webworkDirs}->{root},
  879     $ce->{webworkURLs}->{root},
  880     $ce->{pg}->{directories}->{root},
  881     $delete_courseID,
  882   );
  883 
  884   if ($ce2->{dbLayoutName} eq "sql") {
  885     push @errors, "You must specify the SQL admin username." if $delete_sql_username eq "";
  886     #push @errors, "You must specify the SQL admin password." if $delete_sql_password eq "";
  887     #push @errors, "You must specify the SQL database name." if $delete_sql_database eq "";
  888   }
  889 
  890   return @errors;
  891 }
  892 
  893 sub delete_course_confirm {
  894   my ($self) = @_;
  895   my $r = $self->r;
  896   my $ce = $r->ce;
  897   #my $db = $r->db;
  898   #my $authz = $r->authz;
  899   #my $urlpath = $r->urlpath;
  900 
  901   print CGI::h2("Delete Course");
  902 
  903   my $delete_courseID     = $r->param("delete_courseID")     || "";
  904   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  905   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  906   my $delete_sql_database = $r->param("delete_sql_database") || "";
  907 
  908   my $ce2 = WeBWorK::CourseEnvironment->new(
  909     $ce->{webworkDirs}->{root},
  910     $ce->{webworkURLs}->{root},
  911     $ce->{pg}->{directories}->{root},
  912     $delete_courseID,
  913   );
  914 
  915   if ($ce2->{dbLayoutName} eq "sql") {
  916     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  917     . "? All course files and data and the following database will be destroyed."
  918     . " There is no undo available.");
  919 
  920     print CGI::table({class=>"FormLayout"},
  921       CGI::Tr(
  922         CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  923         CGI::td($delete_sql_host || "system default"),
  924       ),
  925       CGI::Tr(
  926         CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  927         CGI::td($delete_sql_port || "system default"),
  928       ),
  929       CGI::Tr(
  930         CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  931         CGI::td($delete_sql_database || "webwork_$delete_courseID"),
  932       ),
  933     );
  934   } else {
  935     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  936       . "? All course files and data will be destroyed. There is no undo available.");
  937   }
  938 
  939   print CGI::start_form("POST", $r->uri);
  940   print $self->hidden_authen_fields;
  941   print $self->hidden_fields("subDisplay");
  942   print $self->hidden_fields(qw/delete_courseID delete_sql_host delete_sql_port delete_sql_username delete_sql_password delete_sql_database/);
  943 
  944   print CGI::p({style=>"text-align: center"},
  945     CGI::submit("decline_delete_course", "Don't delete"),
  946     "&nbsp;",
  947     CGI::submit("confirm_delete_course", "Delete"),
  948   );
  949 
  950   print CGI::end_form();
  951 }
  952 
  953 sub do_delete_course {
  954   my ($self) = @_;
  955   my $r = $self->r;
  956   my $ce = $r->ce;
  957   #my $db = $r->db;
  958   #my $authz = $r->authz;
  959   #my $urlpath = $r->urlpath;
  960 
  961   my $delete_courseID     = $r->param("delete_courseID")     || "";
  962   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  963   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  964   my $delete_sql_username = $r->param("delete_sql_username") || "";
  965   my $delete_sql_password = $r->param("delete_sql_password") || "";
  966   my $delete_sql_database = $r->param("delete_sql_database") || "";
  967 
  968   my $ce2 = WeBWorK::CourseEnvironment->new(
  969     $ce->{webworkDirs}->{root},
  970     $ce->{webworkURLs}->{root},
  971     $ce->{pg}->{directories}->{root},
  972     $delete_courseID,
  973   );
  974 
  975   my %dbOptions;
  976   if ($ce2->{dbLayoutName} eq "sql") {
  977     $dbOptions{host}     = $delete_sql_host if $delete_sql_host ne "";
  978     $dbOptions{port}     = $delete_sql_port if $delete_sql_port ne "";
  979     $dbOptions{username} = $delete_sql_username;
  980     $dbOptions{password} = $delete_sql_password;
  981     $dbOptions{database} = $delete_sql_database || "webwork_$delete_courseID";
  982   }
  983 
  984   eval {
  985     deleteCourse(
  986       courseID => $delete_courseID,
  987       ce => $ce2,
  988       dbOptions => \%dbOptions,
  989     );
  990   };
  991 
  992   if ($@) {
  993     my $error = $@;
  994     print CGI::div({class=>"ResultsWithError"},
  995       CGI::p("An error occured while deleting the course $delete_courseID:"),
  996       CGI::tt(CGI::escapeHTML($error)),
  997     );
  998   } else {
  999     print CGI::div({class=>"ResultsWithoutError"},
 1000       CGI::p("Successfully deleted the course $delete_courseID."),
 1001     );
 1002      writeLog($ce, "hosted_courses", join("\t",
 1003         "\tDeleted",
 1004         "",
 1005         "",
 1006         $delete_courseID,
 1007       ));
 1008     print CGI::start_form("POST", $r->uri);
 1009     print $self->hidden_authen_fields;
 1010     print $self->hidden_fields("subDisplay");
 1011 
 1012     print CGI::p({style=>"text-align: center"}, CGI::submit("decline_delete_course", "OK"),);
 1013 
 1014     print CGI::end_form();
 1015   }
 1016 }
 1017 
 1018 ################################################################################
 1019 
 1020 sub export_database_form {
 1021   my ($self) = @_;
 1022   my $r = $self->r;
 1023   my $ce = $r->ce;
 1024   #my $db = $r->db;
 1025   #my $authz = $r->authz;
 1026   #my $urlpath = $r->urlpath;
 1027 
 1028   my @tables = keys %{$ce->{dbLayout}};
 1029 
 1030   my $export_courseID = $r->param("export_courseID") || "";
 1031   my @export_tables   = $r->param("export_tables");
 1032 
 1033   @export_tables = @tables unless @export_tables;
 1034 
 1035   my @courseIDs = listCourses($ce);
 1036   @courseIDs    = sort @courseIDs;
 1037 
 1038   my %courseLabels; # records... heh.
 1039   foreach my $courseID (@courseIDs) {
 1040     my $tempCE = WeBWorK::CourseEnvironment->new(
 1041       $ce->{webworkDirs}->{root},
 1042       $ce->{webworkURLs}->{root},
 1043       $ce->{pg}->{directories}->{root},
 1044       $courseID,
 1045     );
 1046     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
 1047   }
 1048 
 1049   print CGI::h2("Export Database");
 1050 
 1051   print CGI::start_form("GET", $r->uri);
 1052   print $self->hidden_authen_fields;
 1053   print $self->hidden_fields("subDisplay");
 1054 
 1055   print CGI::p("Select a course to export the course's database. Please note
 1056   that exporting can take a very long time for a large course. If you have
 1057   shell access to the WeBWorK server, you may use the ", CGI::code("wwdb"), "
 1058   utility instead.");
 1059 
 1060   print CGI::table({class=>"FormLayout"},
 1061     CGI::Tr(
 1062       CGI::th({class=>"LeftHeader"}, "Course Name:"),
 1063       CGI::td(
 1064         CGI::scrolling_list(
 1065           -name => "export_courseID",
 1066           -values => \@courseIDs,
 1067           -default => $export_courseID,
 1068           -size => 10,
 1069           -multiple => 0,
 1070           -labels => \%courseLabels,
 1071         ),
 1072       ),
 1073     ),
 1074     CGI::Tr(
 1075       CGI::th({class=>"LeftHeader"}, "Tables to Export:"),
 1076       CGI::td(
 1077         CGI::checkbox_group(
 1078           -name => "export_tables",
 1079           -values => \@tables,
 1080           -default => \@export_tables,
 1081           -linebreak => 1,
 1082         ),
 1083       ),
 1084     ),
 1085   );
 1086 
 1087   print CGI::p({style=>"text-align: center"}, CGI::submit("export_database", "Export Database"));
 1088 
 1089   print CGI::end_form();
 1090 }
 1091 
 1092 sub export_database_validate {
 1093   my ($self) = @_;
 1094   my $r = $self->r;
 1095   #my $ce = $r->ce;
 1096   #my $db = $r->db;
 1097   #my $authz = $r->authz;
 1098   #my $urlpath = $r->urlpath;
 1099 
 1100   my $export_courseID = $r->param("export_courseID") || "";
 1101   my @export_tables   = $r->param("export_tables");
 1102 
 1103   my @errors;
 1104 
 1105   if ($export_courseID eq "") {
 1106     push @errors, "You must specify a course name.";
 1107   }
 1108 
 1109   unless (@export_tables) {
 1110     push @errors, "You must specify at least one table to export.";
 1111   }
 1112 
 1113   return @errors;
 1114 }
 1115 
 1116 sub do_export_database {
 1117   my ($self) = @_;
 1118   my $r = $self->r;
 1119   my $ce = $r->ce;
 1120   #my $db = $r->db;
 1121   #my $authz = $r->authz;
 1122   my $urlpath = $r->urlpath;
 1123 
 1124   my $export_courseID = $r->param("export_courseID");
 1125   my @export_tables   = $r->param("export_tables");
 1126 
 1127   my $ce2 = WeBWorK::CourseEnvironment->new(
 1128     $ce->{webworkDirs}->{root},
 1129     $ce->{webworkURLs}->{root},
 1130     $ce->{pg}->{directories}->{root},
 1131     $export_courseID,
 1132   );
 1133 
 1134   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
 1135 
 1136   #my ($fh, $export_file) = tempfile("db_export_XXXXXX", DIR => $ce->{webworkDirs}->{tmp});
 1137   #my ($random_chars) = $export_file =~ m/db_export_(\w+)$/;
 1138 
 1139   my @errors;
 1140 
 1141   eval {
 1142     @errors = dbExport(
 1143       db => $db2,
 1144       #xml => $fh,
 1145       xml => *STDOUT,
 1146       tables => \@export_tables,
 1147     );
 1148   };
 1149 
 1150   #push @errors, "Fatal exception: $@" if $@;
 1151   #
 1152   #if (@errors) {
 1153   # print CGI::div({class=>"ResultsWithError"},
 1154   #   CGI::p("An error occured while exporting the database of course $export_courseID:"),
 1155   #   CGI::ul(CGI::li(\@errors)),
 1156   # );
 1157   #} else {
 1158   # print CGI::div({class=>"ResultsWithoutError"},
 1159   #   CGI::p("Export succeeded."),
 1160   # );
 1161   #
 1162   # print CGI::div({style=>"text-align: center"},
 1163   #   CGI::a({href=>$self->systemLink($urlpath, params=>{download_exported_database=>$random_chars, export_courseID=>undef})}, "Download Exported Database"),
 1164   # );
 1165   #}
 1166 }
 1167 
 1168 ################################################################################
 1169 
 1170 sub import_database_form {
 1171   my ($self) = @_;
 1172   my $r = $self->r;
 1173   my $ce = $r->ce;
 1174   #my $db = $r->db;
 1175   #my $authz = $r->authz;
 1176   #my $urlpath = $r->urlpath;
 1177 
 1178   my @tables = keys %{$ce->{dbLayout}};
 1179 
 1180   my $import_file     = $r->param("import_file")     || "";
 1181   my $import_courseID = $r->param("import_courseID") || "";
 1182   my @import_tables   = $r->param("import_tables");
 1183   my $import_conflict = $r->param("import_conflict") || "skip";
 1184 
 1185   @import_tables = @tables unless @import_tables;
 1186 
 1187   my @courseIDs = listCourses($ce);
 1188   @courseIDs    = sort @courseIDs;
 1189 
 1190 
 1191   my %courseLabels; # records... heh.
 1192   foreach my $courseID (@courseIDs) {
 1193     my $tempCE = WeBWorK::CourseEnvironment->new(
 1194       $ce->{webworkDirs}->{root},
 1195       $ce->{webworkURLs}->{root},
 1196       $ce->{pg}->{directories}->{root},
 1197       $courseID,
 1198     );
 1199     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
 1200   }
 1201 
 1202   print CGI::h2("Import Database");
 1203 
 1204   print CGI::start_form("POST", $r->uri, &CGI::MULTIPART);
 1205   print $self->hidden_authen_fields;
 1206   print $self->hidden_fields("subDisplay");
 1207 
 1208   print CGI::table({class=>"FormLayout"},
 1209     CGI::Tr(
 1210       CGI::th({class=>"LeftHeader"}, "Database XML File:"),
 1211       CGI::td(
 1212         CGI::filefield(
 1213           -name => "import_file",
 1214           -size => 50,
 1215         ),
 1216       ),
 1217     ),
 1218     CGI::Tr(
 1219       CGI::th({class=>"LeftHeader"}, "Tables to Import:"),
 1220       CGI::td(
 1221         CGI::checkbox_group(
 1222           -name => "import_tables",
 1223           -values => \@tables,
 1224           -default => \@import_tables,
 1225           -linebreak => 1,
 1226         ),
 1227       ),
 1228     ),
 1229     CGI::Tr(
 1230       CGI::th({class=>"LeftHeader"}, "Import into Course:"),
 1231       CGI::td(
 1232         CGI::scrolling_list(
 1233           -name => "import_courseID",
 1234           -values => \@courseIDs,
 1235           -default => $import_courseID,
 1236           -size => 10,
 1237           -multiple => 0,
 1238           -labels => \%courseLabels,
 1239         ),
 1240       ),
 1241     ),
 1242     CGI::Tr(
 1243       CGI::th({class=>"LeftHeader"}, "Conflicts:"),
 1244       CGI::td(
 1245         CGI::radio_group(
 1246           -name => "import_conflict",
 1247           -values => [qw/skip replace/],
 1248           -default => $import_conflict,
 1249           -linebreak=>'true',
 1250           -labels => {
 1251             skip => "Skip duplicate records",
 1252             replace => "Replace duplicate records",
 1253           },
 1254         ),
 1255       ),
 1256     ),
 1257   );
 1258 
 1259   print CGI::p({style=>"text-align: center"}, CGI::submit("import_database", "Import Database"));
 1260 
 1261   print CGI::end_form();
 1262 }
 1263 
 1264 sub import_database_validate {
 1265   my ($self) = @_;
 1266   my $r = $self->r;
 1267   #my $ce = $r->ce;
 1268   #my $db = $r->db;
 1269   #my $authz = $r->authz;
 1270   #my $urlpath = $r->urlpath;
 1271 
 1272   my $import_file     = $r->param("import_file")     || "";
 1273   my $import_courseID = $r->param("import_courseID") || "";
 1274   my @import_tables   = $r->param("import_tables");
 1275   #my $import_conflict = $r->param("import_conflict") || "skip"; # not checked
 1276 
 1277   my @errors;
 1278 
 1279   if ($import_file eq "") {
 1280     push @errors, "You must specify a database file to upload.";
 1281   }
 1282 
 1283   if ($import_courseID eq "") {
 1284     push @errors, "You must specify a course name.";
 1285   }
 1286 
 1287   unless (@import_tables) {
 1288     push @errors, "You must specify at least one table to import.";
 1289   }
 1290 
 1291   return @errors;
 1292 }
 1293 
 1294 sub do_import_database {
 1295   my ($self) = @_;
 1296   my $r = $self->r;
 1297   my $ce = $r->ce;
 1298   #my $db = $r->db;
 1299   #my $authz = $r->authz;
 1300   my $urlpath = $r->urlpath;
 1301 
 1302   my $import_file     = $r->param("import_file");
 1303   my $import_courseID = $r->param("import_courseID");
 1304   my @import_tables   = $r->param("import_tables");
 1305   my $import_conflict = $r->param("import_conflict") || "skip"; # need default -- not checked above
 1306 
 1307   my $ce2 = WeBWorK::CourseEnvironment->new(
 1308     $ce->{webworkDirs}->{root},
 1309     $ce->{webworkURLs}->{root},
 1310     $ce->{pg}->{directories}->{root},
 1311     $import_courseID,
 1312   );
 1313 
 1314   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
 1315 
 1316   # retrieve upload from upload cache
 1317   my ($id, $hash) = split /\s+/, $import_file;
 1318   my $upload = WeBWorK::Upload->retrieve($id, $hash,
 1319     dir => $ce->{webworkDirs}->{uploadCache}
 1320   );
 1321 
 1322   my @errors;
 1323 
 1324   eval {
 1325     @errors = dbImport(
 1326       db => $db2,
 1327       xml => $upload->fileHandle,
 1328       tables => \@import_tables,
 1329       conflict => $import_conflict,
 1330     );
 1331   };
 1332 
 1333   $upload->dispose;
 1334 
 1335   push @errors, "Fatal exception: $@" if $@;
 1336 
 1337   if (@errors) {
 1338     print CGI::div({class=>"ResultsWithError"},
 1339       CGI::p("An error occured while importing the database of course $import_courseID:"),
 1340       CGI::ul(CGI::li(\@errors)),
 1341     );
 1342   } else {
 1343     print CGI::div({class=>"ResultsWithoutError"},
 1344       CGI::p("Import succeeded."),
 1345     );
 1346   }
 1347 }
 1348 
 1349 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9