[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 3054 - (download) (as text) (annotate)
Sun Dec 19 22:39:59 2004 UTC (8 years, 4 months ago) by gage
Original Path: trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm
File size: 41898 byte(s)
Changed message passing when there is a duplicate administrator.

use addbadmessage() facility instead of warn

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9