[system] / trunk / webwork-modperl / lib / WeBWorK / ContentGenerator / CourseAdmin.pm Repository:
ViewVC logotype

View of /trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2719 - (download) (as text) (annotate)
Thu Sep 2 21:21:43 2004 UTC (8 years, 8 months ago) by sh002i
File size: 41269 byte(s)
formatting fix (also comitted to rel-2-0-patches)

    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.26 2004/08/31 01:15:53 dpvc 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     $courseOptions{feedbackRecipients} = [ $add_initial_email ];
  630   }
  631 
  632   if ($add_dbLayout eq "gdbm") {
  633     $courseOptions{globalUserID} = $add_gdbm_globalUserID if $add_gdbm_globalUserID ne "";
  634   }
  635 
  636   my %dbOptions;
  637   if ($add_dbLayout eq "sql") {
  638     $dbOptions{host}     = $add_sql_host if $add_sql_host ne "";
  639     $dbOptions{port}     = $add_sql_port if $add_sql_port ne "";
  640     $dbOptions{username} = $add_sql_username;
  641     $dbOptions{password} = $add_sql_password;
  642     $dbOptions{database} = $add_sql_database || "webwork_$add_courseID";
  643     $dbOptions{wwhost}   = $add_sql_wwhost;
  644   }
  645 
  646   my @users;
  647 
  648   # copy users from current (admin) course if desired
  649   if ($add_admin_users ne "") {
  650     foreach my $userID ($db->listUsers) {
  651       my $User            = $db->getUser($userID);
  652       my $Password        = $db->getPassword($userID);
  653       my $PermissionLevel = $db->getPermissionLevel($userID);
  654       push @users, [ $User, $Password, $PermissionLevel ];
  655     }
  656   }
  657 
  658   # add initial instructor if desired
  659   if ($add_initial_userID ne "") {
  660     my $User = $db->newUser(
  661       user_id       => $add_initial_userID,
  662       first_name    => $add_initial_firstName,
  663       last_name     => $add_initial_lastName,
  664       student_id    => $add_initial_userID,
  665       email_address => $add_initial_email,
  666       status        => "C",
  667     );
  668     my $Password = $db->newPassword(
  669       user_id  => $add_initial_userID,
  670       password => cryptPassword($add_initial_password),
  671     );
  672     my $PermissionLevel = $db->newPermissionLevel(
  673       user_id    => $add_initial_userID,
  674       permission => "10",
  675     );
  676     push @users, [ $User, $Password, $PermissionLevel ];
  677   }
  678 
  679   push @{$courseOptions{PRINT_FILE_NAMES_FOR}}, map { $_->[0]->user_id } @users;
  680 
  681   my %optional_arguments;
  682   if ($add_templates_course ne "") {
  683     $optional_arguments{templatesFrom} = $add_templates_course;
  684   }
  685 
  686   eval {
  687     addCourse(
  688       courseID      => $add_courseID,
  689       ce            => $ce2,
  690       courseOptions => \%courseOptions,
  691       dbOptions     => \%dbOptions,
  692       users         => \@users,
  693       %optional_arguments,
  694     );
  695   };
  696   if ($@) {
  697     my $error = $@;
  698     print CGI::div({class=>"ResultsWithError"},
  699       CGI::p("An error occured while creating the course $add_courseID:"),
  700       CGI::tt(CGI::escapeHTML($error)),
  701     );
  702     # get rid of any partially built courses
  703     # FIXME  -- this is too fragile
  704     unless ($error =~ /course exists/) {
  705       eval {
  706         deleteCourse(
  707           courseID   => $add_courseID,
  708           ce         => $ce2,
  709           dbOptions  => \%dbOptions,
  710         );
  711       }
  712     }
  713   } else {
  714       #log the action
  715       writeLog($ce, "hosted_courses", join("\t",
  716         "\tAdded",
  717         $add_courseInstitution,
  718         $add_courseTitle,
  719         $add_courseID,
  720         $add_initial_firstName,
  721         $add_initial_lastName,
  722         $add_initial_email,
  723       ));
  724       # add contact to admin course as student?
  725       # FIXME -- should we do this?
  726     print CGI::div({class=>"ResultsWithoutError"},
  727       CGI::p("Successfully created the course $add_courseID"),
  728     );
  729     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
  730       courseID => $add_courseID);
  731     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
  732     print CGI::div({style=>"text-align: center"},
  733       CGI::a({href=>$newCourseURL}, "Log into $add_courseID"),
  734     );
  735   }
  736 
  737 
  738 }
  739 
  740 ################################################################################
  741 
  742 sub delete_course_form {
  743   my ($self) = @_;
  744   my $r = $self->r;
  745   my $ce = $r->ce;
  746   #my $db = $r->db;
  747   #my $authz = $r->authz;
  748   #my $urlpath = $r->urlpath;
  749 
  750   my $delete_courseID     = $r->param("delete_courseID")     || "";
  751   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  752   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  753   my $delete_sql_username = $r->param("delete_sql_username") || "";
  754   my $delete_sql_password = $r->param("delete_sql_password") || "";
  755   my $delete_sql_database = $r->param("delete_sql_database")    || "";
  756 
  757   my @courseIDs = listCourses($ce);
  758   @courseIDs    = sort @courseIDs;
  759 
  760   my %courseLabels; # records... heh.
  761   foreach my $courseID (@courseIDs) {
  762     my $tempCE = WeBWorK::CourseEnvironment->new(
  763       $ce->{webworkDirs}->{root},
  764       $ce->{webworkURLs}->{root},
  765       $ce->{pg}->{directories}->{root},
  766       $courseID,
  767     );
  768     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
  769   }
  770 
  771   print CGI::h2("Delete Course");
  772 
  773   print CGI::start_form("POST", $r->uri);
  774   print $self->hidden_authen_fields;
  775   print $self->hidden_fields("subDisplay");
  776 
  777   print CGI::p("Select a course to delete.");
  778 
  779   print CGI::table({class=>"FormLayout"},
  780     CGI::Tr(
  781       CGI::th({class=>"LeftHeader"}, "Course Name:"),
  782       CGI::td(
  783         CGI::scrolling_list(
  784           -name => "delete_courseID",
  785           -values => \@courseIDs,
  786           -default => $delete_courseID,
  787           -size => 10,
  788           -multiple => 0,
  789           -labels => \%courseLabels,
  790         ),
  791       ),
  792     ),
  793   );
  794 
  795   print CGI::p(
  796     "If the course's database layout (indicated in parentheses above) is "
  797     . CGI::b("sql") . ", supply the SQL connections information requested below."
  798   );
  799 
  800   print CGI::start_table({class=>"FormLayout"});
  801   print CGI::Tr(CGI::td({colspan=>2},
  802       "Enter the user ID and password for an SQL account with sufficient permissions to delete an existing database."
  803     )
  804   );
  805   print CGI::Tr(
  806     CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
  807     CGI::td(CGI::textfield("delete_sql_username", $delete_sql_username, 25)),
  808   );
  809   print CGI::Tr(
  810     CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
  811     CGI::td(CGI::password_field("delete_sql_password", $delete_sql_password, 25)),
  812   );
  813 
  814   #print CGI::Tr(CGI::td({colspan=>2},
  815   #   "The optionial SQL settings you enter below must match the settings in the DBI source"
  816   #   . " specification " . CGI::tt($dbi_source) . ". Replace " . CGI::tt("COURSENAME")
  817   #   . " with the course name you entered above."
  818   # )
  819   #);
  820   print CGI::Tr(
  821     CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  822     CGI::td(
  823       CGI::textfield("delete_sql_host", $delete_sql_host, 25),
  824       CGI::br(),
  825       CGI::small("Leave blank to use the default host."),
  826     ),
  827   );
  828   print CGI::Tr(
  829     CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  830     CGI::td(
  831       CGI::textfield("delete_sql_port", $delete_sql_port, 25),
  832       CGI::br(),
  833       CGI::small("Leave blank to use the default port."),
  834     ),
  835   );
  836 
  837   print CGI::Tr(
  838     CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  839     CGI::td(
  840       CGI::textfield("delete_sql_database", $delete_sql_database, 25),
  841       CGI::br(),
  842       CGI::small("Leave blank to use the name ", CGI::tt("webwork_COURSENAME"), "."),
  843     ),
  844   );
  845   print CGI::end_table();
  846 
  847   print CGI::p({style=>"text-align: center"}, CGI::submit("delete_course", "Delete Course"));
  848 
  849   print CGI::end_form();
  850 }
  851 
  852 sub delete_course_validate {
  853   my ($self) = @_;
  854   my $r = $self->r;
  855   my $ce = $r->ce;
  856   #my $db = $r->db;
  857   #my $authz = $r->authz;
  858   my $urlpath = $r->urlpath;
  859 
  860   my $delete_courseID     = $r->param("delete_courseID")     || "";
  861   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  862   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  863   my $delete_sql_username = $r->param("delete_sql_username") || "";
  864   my $delete_sql_password = $r->param("delete_sql_password") || "";
  865   my $delete_sql_database = $r->param("delete_sql_database") || "";
  866 
  867   my @errors;
  868 
  869   if ($delete_courseID eq "") {
  870     push @errors, "You must specify a course name.";
  871   } elsif ($delete_courseID eq $urlpath->arg("courseID")) {
  872     push @errors, "You cannot delete the course you are currently using.";
  873   }
  874 
  875   my $ce2 = WeBWorK::CourseEnvironment->new(
  876     $ce->{webworkDirs}->{root},
  877     $ce->{webworkURLs}->{root},
  878     $ce->{pg}->{directories}->{root},
  879     $delete_courseID,
  880   );
  881 
  882   if ($ce2->{dbLayoutName} eq "sql") {
  883     push @errors, "You must specify the SQL admin username." if $delete_sql_username eq "";
  884     #push @errors, "You must specify the SQL admin password." if $delete_sql_password eq "";
  885     #push @errors, "You must specify the SQL database name." if $delete_sql_database eq "";
  886   }
  887 
  888   return @errors;
  889 }
  890 
  891 sub delete_course_confirm {
  892   my ($self) = @_;
  893   my $r = $self->r;
  894   my $ce = $r->ce;
  895   #my $db = $r->db;
  896   #my $authz = $r->authz;
  897   #my $urlpath = $r->urlpath;
  898 
  899   print CGI::h2("Delete Course");
  900 
  901   my $delete_courseID     = $r->param("delete_courseID")     || "";
  902   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  903   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  904   my $delete_sql_database = $r->param("delete_sql_database") || "";
  905 
  906   my $ce2 = WeBWorK::CourseEnvironment->new(
  907     $ce->{webworkDirs}->{root},
  908     $ce->{webworkURLs}->{root},
  909     $ce->{pg}->{directories}->{root},
  910     $delete_courseID,
  911   );
  912 
  913   if ($ce2->{dbLayoutName} eq "sql") {
  914     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  915     . "? All course files and data and the following database will be destroyed."
  916     . " There is no undo available.");
  917 
  918     print CGI::table({class=>"FormLayout"},
  919       CGI::Tr(
  920         CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  921         CGI::td($delete_sql_host || "system default"),
  922       ),
  923       CGI::Tr(
  924         CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  925         CGI::td($delete_sql_port || "system default"),
  926       ),
  927       CGI::Tr(
  928         CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  929         CGI::td($delete_sql_database || "webwork_$delete_courseID"),
  930       ),
  931     );
  932   } else {
  933     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  934       . "? All course files and data will be destroyed. There is no undo available.");
  935   }
  936 
  937   print CGI::start_form("POST", $r->uri);
  938   print $self->hidden_authen_fields;
  939   print $self->hidden_fields("subDisplay");
  940   print $self->hidden_fields(qw/delete_courseID delete_sql_host delete_sql_port delete_sql_username delete_sql_password delete_sql_database/);
  941 
  942   print CGI::p({style=>"text-align: center"},
  943     CGI::submit("decline_delete_course", "Don't delete"),
  944     "&nbsp;",
  945     CGI::submit("confirm_delete_course", "Delete"),
  946   );
  947 
  948   print CGI::end_form();
  949 }
  950 
  951 sub do_delete_course {
  952   my ($self) = @_;
  953   my $r = $self->r;
  954   my $ce = $r->ce;
  955   #my $db = $r->db;
  956   #my $authz = $r->authz;
  957   #my $urlpath = $r->urlpath;
  958 
  959   my $delete_courseID     = $r->param("delete_courseID")     || "";
  960   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  961   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  962   my $delete_sql_username = $r->param("delete_sql_username") || "";
  963   my $delete_sql_password = $r->param("delete_sql_password") || "";
  964   my $delete_sql_database = $r->param("delete_sql_database") || "";
  965 
  966   my $ce2 = WeBWorK::CourseEnvironment->new(
  967     $ce->{webworkDirs}->{root},
  968     $ce->{webworkURLs}->{root},
  969     $ce->{pg}->{directories}->{root},
  970     $delete_courseID,
  971   );
  972 
  973   my %dbOptions;
  974   if ($ce2->{dbLayoutName} eq "sql") {
  975     $dbOptions{host}     = $delete_sql_host if $delete_sql_host ne "";
  976     $dbOptions{port}     = $delete_sql_port if $delete_sql_port ne "";
  977     $dbOptions{username} = $delete_sql_username;
  978     $dbOptions{password} = $delete_sql_password;
  979     $dbOptions{database} = $delete_sql_database || "webwork_$delete_courseID";
  980   }
  981 
  982   eval {
  983     deleteCourse(
  984       courseID => $delete_courseID,
  985       ce => $ce2,
  986       dbOptions => \%dbOptions,
  987     );
  988   };
  989 
  990   if ($@) {
  991     my $error = $@;
  992     print CGI::div({class=>"ResultsWithError"},
  993       CGI::p("An error occured while deleting the course $delete_courseID:"),
  994       CGI::tt(CGI::escapeHTML($error)),
  995     );
  996   } else {
  997     print CGI::div({class=>"ResultsWithoutError"},
  998       CGI::p("Successfully deleted the course $delete_courseID."),
  999     );
 1000      writeLog($ce, "hosted_courses", join("\t",
 1001         "\tDeleted",
 1002         "",
 1003         "",
 1004         $delete_courseID,
 1005       ));
 1006     print CGI::start_form("POST", $r->uri);
 1007     print $self->hidden_authen_fields;
 1008     print $self->hidden_fields("subDisplay");
 1009 
 1010     print CGI::p({style=>"text-align: center"}, CGI::submit("decline_delete_course", "OK"),);
 1011 
 1012     print CGI::end_form();
 1013   }
 1014 }
 1015 
 1016 ################################################################################
 1017 
 1018 sub export_database_form {
 1019   my ($self) = @_;
 1020   my $r = $self->r;
 1021   my $ce = $r->ce;
 1022   #my $db = $r->db;
 1023   #my $authz = $r->authz;
 1024   #my $urlpath = $r->urlpath;
 1025 
 1026   my @tables = keys %{$ce->{dbLayout}};
 1027 
 1028   my $export_courseID = $r->param("export_courseID") || "";
 1029   my @export_tables   = $r->param("export_tables");
 1030 
 1031   @export_tables = @tables unless @export_tables;
 1032 
 1033   my @courseIDs = listCourses($ce);
 1034   @courseIDs    = sort @courseIDs;
 1035 
 1036   my %courseLabels; # records... heh.
 1037   foreach my $courseID (@courseIDs) {
 1038     my $tempCE = WeBWorK::CourseEnvironment->new(
 1039       $ce->{webworkDirs}->{root},
 1040       $ce->{webworkURLs}->{root},
 1041       $ce->{pg}->{directories}->{root},
 1042       $courseID,
 1043     );
 1044     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
 1045   }
 1046 
 1047   print CGI::h2("Export Database");
 1048 
 1049   print CGI::start_form("GET", $r->uri);
 1050   print $self->hidden_authen_fields;
 1051   print $self->hidden_fields("subDisplay");
 1052 
 1053   print CGI::p("Select a course to export the course's database.");
 1054 
 1055   print CGI::table({class=>"FormLayout"},
 1056     CGI::Tr(
 1057       CGI::th({class=>"LeftHeader"}, "Course Name:"),
 1058       CGI::td(
 1059         CGI::scrolling_list(
 1060           -name => "export_courseID",
 1061           -values => \@courseIDs,
 1062           -default => $export_courseID,
 1063           -size => 10,
 1064           -multiple => 0,
 1065           -labels => \%courseLabels,
 1066         ),
 1067       ),
 1068     ),
 1069     CGI::Tr(
 1070       CGI::th({class=>"LeftHeader"}, "Tables to Export:"),
 1071       CGI::td(
 1072         CGI::checkbox_group(
 1073           -name => "export_tables",
 1074           -values => \@tables,
 1075           -default => \@export_tables,
 1076           -linebreak => 1,
 1077         ),
 1078       ),
 1079     ),
 1080   );
 1081 
 1082   print CGI::p({style=>"text-align: center"}, CGI::submit("export_database", "Export Database"));
 1083 
 1084   print CGI::end_form();
 1085 }
 1086 
 1087 sub export_database_validate {
 1088   my ($self) = @_;
 1089   my $r = $self->r;
 1090   #my $ce = $r->ce;
 1091   #my $db = $r->db;
 1092   #my $authz = $r->authz;
 1093   #my $urlpath = $r->urlpath;
 1094 
 1095   my $export_courseID = $r->param("export_courseID") || "";
 1096   my @export_tables   = $r->param("export_tables");
 1097 
 1098   my @errors;
 1099 
 1100   if ($export_courseID eq "") {
 1101     push @errors, "You must specify a course name.";
 1102   }
 1103 
 1104   unless (@export_tables) {
 1105     push @errors, "You must specify at least one table to export.";
 1106   }
 1107 
 1108   return @errors;
 1109 }
 1110 
 1111 sub do_export_database {
 1112   my ($self) = @_;
 1113   my $r = $self->r;
 1114   my $ce = $r->ce;
 1115   #my $db = $r->db;
 1116   #my $authz = $r->authz;
 1117   my $urlpath = $r->urlpath;
 1118 
 1119   my $export_courseID = $r->param("export_courseID");
 1120   my @export_tables   = $r->param("export_tables");
 1121 
 1122   my $ce2 = WeBWorK::CourseEnvironment->new(
 1123     $ce->{webworkDirs}->{root},
 1124     $ce->{webworkURLs}->{root},
 1125     $ce->{pg}->{directories}->{root},
 1126     $export_courseID,
 1127   );
 1128 
 1129   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
 1130 
 1131   #my ($fh, $export_file) = tempfile("db_export_XXXXXX", DIR => $ce->{webworkDirs}->{tmp});
 1132   #my ($random_chars) = $export_file =~ m/db_export_(\w+)$/;
 1133 
 1134   my @errors;
 1135 
 1136   eval {
 1137     @errors = dbExport(
 1138       db => $db2,
 1139       #xml => $fh,
 1140       xml => *STDOUT,
 1141       tables => \@export_tables,
 1142     );
 1143   };
 1144 
 1145   #push @errors, "Fatal exception: $@" if $@;
 1146   #
 1147   #if (@errors) {
 1148   # print CGI::div({class=>"ResultsWithError"},
 1149   #   CGI::p("An error occured while exporting the database of course $export_courseID:"),
 1150   #   CGI::ul(CGI::li(\@errors)),
 1151   # );
 1152   #} else {
 1153   # print CGI::div({class=>"ResultsWithoutError"},
 1154   #   CGI::p("Export succeeded."),
 1155   # );
 1156   #
 1157   # print CGI::div({style=>"text-align: center"},
 1158   #   CGI::a({href=>$self->systemLink($urlpath, params=>{download_exported_database=>$random_chars, export_courseID=>undef})}, "Download Exported Database"),
 1159   # );
 1160   #}
 1161 }
 1162 
 1163 ################################################################################
 1164 
 1165 sub import_database_form {
 1166   my ($self) = @_;
 1167   my $r = $self->r;
 1168   my $ce = $r->ce;
 1169   #my $db = $r->db;
 1170   #my $authz = $r->authz;
 1171   #my $urlpath = $r->urlpath;
 1172 
 1173   my @tables = keys %{$ce->{dbLayout}};
 1174 
 1175   my $import_file     = $r->param("import_file")     || "";
 1176   my $import_courseID = $r->param("import_courseID") || "";
 1177   my @import_tables   = $r->param("import_tables");
 1178   my $import_conflict = $r->param("import_conflict") || "skip";
 1179 
 1180   @import_tables = @tables unless @import_tables;
 1181 
 1182   my @courseIDs = listCourses($ce);
 1183   @courseIDs    = sort @courseIDs;
 1184 
 1185 
 1186   my %courseLabels; # records... heh.
 1187   foreach my $courseID (@courseIDs) {
 1188     my $tempCE = WeBWorK::CourseEnvironment->new(
 1189       $ce->{webworkDirs}->{root},
 1190       $ce->{webworkURLs}->{root},
 1191       $ce->{pg}->{directories}->{root},
 1192       $courseID,
 1193     );
 1194     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
 1195   }
 1196 
 1197   print CGI::h2("Import Database");
 1198 
 1199   print CGI::start_form("POST", $r->uri, &CGI::MULTIPART);
 1200   print $self->hidden_authen_fields;
 1201   print $self->hidden_fields("subDisplay");
 1202 
 1203   print CGI::table({class=>"FormLayout"},
 1204     CGI::Tr(
 1205       CGI::th({class=>"LeftHeader"}, "Database XML File:"),
 1206       CGI::td(
 1207         CGI::filefield(
 1208           -name => "import_file",
 1209           -size => 50,
 1210         ),
 1211       ),
 1212     ),
 1213     CGI::Tr(
 1214       CGI::th({class=>"LeftHeader"}, "Tables to Import:"),
 1215       CGI::td(
 1216         CGI::checkbox_group(
 1217           -name => "import_tables",
 1218           -values => \@tables,
 1219           -default => \@import_tables,
 1220           -linebreak => 1,
 1221         ),
 1222       ),
 1223     ),
 1224     CGI::Tr(
 1225       CGI::th({class=>"LeftHeader"}, "Import into Course:"),
 1226       CGI::td(
 1227         CGI::scrolling_list(
 1228           -name => "import_courseID",
 1229           -values => \@courseIDs,
 1230           -default => $import_courseID,
 1231           -size => 10,
 1232           -multiple => 0,
 1233           -labels => \%courseLabels,
 1234         ),
 1235       ),
 1236     ),
 1237     CGI::Tr(
 1238       CGI::th({class=>"LeftHeader"}, "Conflicts:"),
 1239       CGI::td(
 1240         CGI::radio_group(
 1241           -name => "import_conflict",
 1242           -values => [qw/skip replace/],
 1243           -default => $import_conflict,
 1244           -linebreak=>'true',
 1245           -labels => {
 1246             skip => "Skip duplicate records",
 1247             replace => "Replace duplicate records",
 1248           },
 1249         ),
 1250       ),
 1251     ),
 1252   );
 1253 
 1254   print CGI::p({style=>"text-align: center"}, CGI::submit("import_database", "Import Database"));
 1255 
 1256   print CGI::end_form();
 1257 }
 1258 
 1259 sub import_database_validate {
 1260   my ($self) = @_;
 1261   my $r = $self->r;
 1262   #my $ce = $r->ce;
 1263   #my $db = $r->db;
 1264   #my $authz = $r->authz;
 1265   #my $urlpath = $r->urlpath;
 1266 
 1267   my $import_file     = $r->param("import_file")     || "";
 1268   my $import_courseID = $r->param("import_courseID") || "";
 1269   my @import_tables   = $r->param("import_tables");
 1270   #my $import_conflict = $r->param("import_conflict") || "skip"; # not checked
 1271 
 1272   my @errors;
 1273 
 1274   if ($import_file eq "") {
 1275     push @errors, "You must specify a database file to upload.";
 1276   }
 1277 
 1278   if ($import_courseID eq "") {
 1279     push @errors, "You must specify a course name.";
 1280   }
 1281 
 1282   unless (@import_tables) {
 1283     push @errors, "You must specify at least one table to import.";
 1284   }
 1285 
 1286   return @errors;
 1287 }
 1288 
 1289 sub do_import_database {
 1290   my ($self) = @_;
 1291   my $r = $self->r;
 1292   my $ce = $r->ce;
 1293   #my $db = $r->db;
 1294   #my $authz = $r->authz;
 1295   my $urlpath = $r->urlpath;
 1296 
 1297   my $import_file     = $r->param("import_file");
 1298   my $import_courseID = $r->param("import_courseID");
 1299   my @import_tables   = $r->param("import_tables");
 1300   my $import_conflict = $r->param("import_conflict") || "skip"; # need default -- not checked above
 1301 
 1302   my $ce2 = WeBWorK::CourseEnvironment->new(
 1303     $ce->{webworkDirs}->{root},
 1304     $ce->{webworkURLs}->{root},
 1305     $ce->{pg}->{directories}->{root},
 1306     $import_courseID,
 1307   );
 1308 
 1309   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
 1310 
 1311   # retrieve upload from upload cache
 1312   my ($id, $hash) = split /\s+/, $import_file;
 1313   my $upload = WeBWorK::Upload->retrieve($id, $hash,
 1314     dir => $ce->{webworkDirs}->{uploadCache}
 1315   );
 1316 
 1317   my @errors;
 1318 
 1319   eval {
 1320     @errors = dbImport(
 1321       db => $db2,
 1322       xml => $upload->fileHandle,
 1323       tables => \@import_tables,
 1324       conflict => $import_conflict,
 1325     );
 1326   };
 1327 
 1328   $upload->dispose;
 1329 
 1330   push @errors, "Fatal exception: $@" if $@;
 1331 
 1332   if (@errors) {
 1333     print CGI::div({class=>"ResultsWithError"},
 1334       CGI::p("An error occured while importing the database of course $import_courseID:"),
 1335       CGI::ul(CGI::li(\@errors)),
 1336     );
 1337   } else {
 1338     print CGI::div({class=>"ResultsWithoutError"},
 1339       CGI::p("Import succeeded."),
 1340     );
 1341   }
 1342 }
 1343 
 1344 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9