[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 1985 - (download) (as text) (annotate)
Thu Apr 29 22:22:33 2004 UTC (9 years ago) by sh002i
File size: 32830 byte(s)
implemented import and export, fixed some bugs

    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.2 2004/04/09 20:19:25 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::Utils qw(cryptPassword);
   32 use WeBWorK::Utils::CourseManagement qw(addCourse deleteCourse listCourses);
   33 use WeBWorK::Utils::DBImportExport qw(dbExport dbImport);
   34 
   35 # SKEL: If you need to do any processing before the HTTP header is sent, do it
   36 # in this method:
   37 #
   38 sub pre_header_initialize {
   39   my ($self) = @_;
   40   my $r = $self->r;
   41   my $ce = $r->ce;
   42   my $db = $r->db;
   43   my $authz = $r->authz;
   44   my $urlpath = $r->urlpath;
   45 
   46   if (defined $r->param("download_exported_database")) {
   47     my $courseID = $r->param("export_courseID");
   48     my $random_chars = $r->param("download_exported_database");
   49 
   50     die "courseID not specified" unless defined $courseID;
   51     die "invalid file specification" unless $random_chars =~ m/^\w+$/;
   52 
   53     my $tempdir = $ce->{webworkDirs}->{tmp};
   54     my $export_file = "$tempdir/db_export_$random_chars";
   55 
   56     $self->reply_with_file("text/xml", $export_file, "${courseID}_database.xml", 0);
   57   }
   58 }
   59 
   60 # SKEL: To emit your own HTTP header, uncomment this:
   61 #
   62 #sub header {
   63 # my ($self) = @_;
   64 #
   65 # # Generate your HTTP header here.
   66 #
   67 # # If you return something, it will be used as the HTTP status code for this
   68 # # request. The Apache::Constants module might be useful for gerating status
   69 # # codes. If you don't return anything, the status code "OK" will be used.
   70 # return "";
   71 #}
   72 
   73 # SKEL: If you need to do any processing after the HTTP header is sent, but before
   74 # any template processing occurs, or you need to calculate values that will be
   75 # used in multiple methods, do it in this method:
   76 #
   77 #sub initialize {
   78 # my ($self) = @_;
   79 #
   80 # # Do your processing here! Don't print or return anything -- store data in
   81 # # the self hash for later retrieveal.
   82 #}
   83 
   84 # SKEL: If you need to add tags to the document <HEAD>, uncomment this method:
   85 #
   86 #sub head {
   87 # my ($self) = @_;
   88 #
   89 # # You can print head tags here, like <META>, <SCRIPT>, etc.
   90 #
   91 # return "";
   92 #}
   93 
   94 # SKEL: To fill in the "info" box (to the right of the main body), use this
   95 # method:
   96 #
   97 #sub info {
   98 # my ($self) = @_;
   99 #
  100 # # Print HTML here.
  101 #
  102 # return "";
  103 #}
  104 
  105 # SKEL: To provide navigation links, use this method:
  106 #
  107 #sub nav {
  108 # my ($self, $args) = @_;
  109 #
  110 # # See the documentation of path() and pathMacro() in
  111 # # WeBWorK::ContentGenerator for more information.
  112 #
  113 # return "";
  114 #}
  115 
  116 # SKEL: For a little box for display options, etc., use this method:
  117 #
  118 #sub options {
  119 # my ($self) = @_;
  120 #
  121 # # Print HTML here.
  122 #
  123 # return "";
  124 #}
  125 
  126 # SKEL: For a list of sibling objects, use this method:
  127 #
  128 #sub siblings {
  129 # my ($self, $args) = @_;
  130 #
  131 # # See the documentation of siblings() and siblingsMacro() in
  132 # # WeBWorK::ContentGenerator for more information.
  133 # #
  134 # # Refer to implementations in ProblemSet and Problem.
  135 #
  136 # return "";
  137 #}
  138 
  139 # SKEL: Okay, here's the body. Most of your stuff will go here:
  140 #
  141 sub body {
  142   my ($self) = @_;
  143   my $r = $self->r;
  144   my $ce = $r->ce;
  145   my $db = $r->db;
  146   my $authz = $r->authz;
  147   my $urlpath = $r->urlpath;
  148 
  149   print CGI::p({style=>"text-align: center"},
  150     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"add_course"})}, "Add Course"),
  151     #" | ",
  152     #CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"rename_course"})}, "Rename Course"),
  153     " | ",
  154     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"delete_course"})}, "Delete Course"),
  155     " | ",
  156     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"export_database"})}, "Export Database"),
  157     " | ",
  158     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"import_database"})}, "Import Database"),
  159   );
  160 
  161   print CGI::hr();
  162 
  163   my $subDisplay = $r->param("subDisplay");
  164   if (defined $subDisplay) {
  165 
  166     if ($subDisplay eq "add_course") {
  167       if (defined $r->param("add_course")) {
  168         my @errors = $self->add_course_validate;
  169         if (@errors) {
  170           print CGI::div({class=>"ResultsWithError"},
  171             CGI::p("Please correct the following errors and try again:"),
  172             CGI::ul(CGI::li(\@errors)),
  173           );
  174           $self->add_course_form;
  175         } else {
  176           $self->do_add_course;
  177         }
  178       } else {
  179         $self->add_course_form;
  180       }
  181     }
  182 
  183     elsif ($subDisplay eq "delete_course") {
  184       if (defined $r->param("delete_course")) {
  185         # validate or confirm
  186         my @errors = $self->delete_course_validate;
  187         if (@errors) {
  188           print CGI::div({class=>"ResultsWithError"},
  189             CGI::p("Please correct the following errors and try again:"),
  190             CGI::ul(CGI::li(\@errors)),
  191           );
  192           $self->delete_course_form;
  193         } else {
  194           $self->delete_course_confirm;
  195         }
  196       } elsif (defined $r->param("confirm_delete_course")) {
  197         # validate and delete
  198         my @errors = $self->delete_course_validate;
  199         if (@errors) {
  200           print CGI::div({class=>"ResultsWithError"},
  201             CGI::p("Please correct the following errors and try again:"),
  202             CGI::ul(CGI::li(\@errors)),
  203           );
  204           $self->delete_course_form;
  205         } else {
  206           $self->do_delete_course;
  207         }
  208       } else {
  209         # form only
  210         $self->delete_course_form;
  211       }
  212     }
  213 
  214     elsif ($subDisplay eq "export_database") {
  215       if (defined $r->param("export_database")) {
  216         my @errors = $self->export_database_validate;
  217         if (@errors) {
  218           print CGI::div({class=>"ResultsWithError"},
  219             CGI::p("Please correct the following errors and try again:"),
  220             CGI::ul(CGI::li(\@errors)),
  221           );
  222           $self->export_database_form;
  223         } else {
  224           $self->do_export_database;
  225         }
  226       } else {
  227         $self->export_database_form;
  228       }
  229     }
  230 
  231     elsif ($subDisplay eq "import_database") {
  232       if (defined $r->param("import_database")) {
  233         my @errors = $self->import_database_validate;
  234         if (@errors) {
  235           print CGI::div({class=>"ResultsWithError"},
  236             CGI::p("Please correct the following errors and try again:"),
  237             CGI::ul(CGI::li(\@errors)),
  238           );
  239           $self->import_database_form;
  240         } else {
  241           $self->do_import_database;
  242         }
  243       } else {
  244         $self->import_database_form;
  245       }
  246     }
  247 
  248     else {
  249       print CGI::div({class=>"ResultsWithError"},
  250         "Unrecognized sub-display @{[ CGI::b($subDisplay) ]}.");
  251     }
  252 
  253   }
  254 
  255   return "";
  256 }
  257 
  258 ################################################################################
  259 
  260 sub add_course_form {
  261   my ($self) = @_;
  262   my $r = $self->r;
  263   my $ce = $r->ce;
  264   #my $db = $r->db;
  265   #my $authz = $r->authz;
  266   #my $urlpath = $r->urlpath;
  267 
  268   my $add_courseID          = $r->param("add_courseID") || "";
  269   my $add_dbLayout          = $r->param("add_dbLayout") || "";
  270   my $add_sql_host          = $r->param("add_sql_host") || "";
  271   my $add_sql_port          = $r->param("add_sql_port") || "";
  272   my $add_sql_username      = $r->param("add_sql_username") || "";
  273   my $add_sql_password      = $r->param("add_sql_password") || "";
  274   my $add_sql_database      = $r->param("add_sql_database") || "";
  275   my $add_sql_wwhost        = $r->param("add_sql_wwhost") || "";
  276   my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
  277   my $add_initial_userID    = $r->param("add_initial_userID") || "";
  278   my $add_initial_password  = $r->param("add_initial_password") || "";
  279 
  280   my @dbLayouts = sort keys %{ $ce->{dbLayouts} };
  281 
  282   my $ce2 = WeBWorK::CourseEnvironment->new(
  283     $ce->{webworkDirs}->{root},
  284     $ce->{webworkURLs}->{root},
  285     $ce->{pg}->{directories}->{root},
  286     "COURSENAME",
  287   );
  288 
  289   my $dbi_source = do {
  290     # find the most common SQL source (stolen from CourseManagement.pm)
  291     my %sources;
  292     foreach my $table (keys %{ $ce2->{dbLayouts}->{sql} }) {
  293       $sources{$ce2->{dbLayouts}->{sql}->{$table}->{source}}++;
  294     }
  295     my $source;
  296     if (keys %sources > 1) {
  297       foreach my $curr (keys %sources) {
  298         $source = $curr if @{ $sources{$curr} } > @{ $sources{$source} };
  299       }
  300     } else {
  301       ($source) = keys %sources;
  302     }
  303     $source;
  304   };
  305 
  306   print CGI::h2("Add Course");
  307 
  308   print CGI::start_form("POST", $r->uri);
  309   print $self->hidden_authen_fields;
  310   print $self->hidden_fields("subDisplay");
  311 
  312   print CGI::p("Specify a name for the new course.");
  313 
  314   print CGI::table({class=>"FormLayout"},
  315     CGI::Tr(
  316       CGI::th({class=>"LeftHeader"}, "Course Name:"),
  317       CGI::td(CGI::textfield("add_courseID", $add_courseID, 25)),
  318     ),
  319   );
  320 
  321   print CGI::p("Select a database layout below. Some database layouts require additional information.");
  322 
  323   #print CGI::start_Tr();
  324   #print CGI::th({class=>"LeftHeader"}, "Database Layout:");
  325   #print CGI::start_td();
  326 
  327   foreach my $dbLayout (@dbLayouts) {
  328     print CGI::start_table({class=>"FormLayout"});
  329 
  330     # we generate singleton radio button tags ourselves because it's too much of a pain to do it with CGI.pm
  331     print CGI::Tr(
  332       CGI::td({style=>"text-align: right"},
  333         '<input type="radio" name="add_dbLayout" value="' . $dbLayout . '"'
  334         . ($add_dbLayout eq $dbLayout ? " checked" : "") . ' />',
  335       ),
  336       CGI::td($dbLayout),
  337     );
  338 
  339     print CGI::start_Tr();
  340     print CGI::td(); # for indentation :(
  341     print CGI::start_td();
  342 
  343     if ($dbLayout eq "sql") {
  344       print CGI::p(
  345         "The SQL settings you enter below must match the settings in the DBI source",
  346         " specification ", CGI::tt($dbi_source), ". Replace ", CGI::tt("COURSENAME"),
  347         " with the course name you entered above."
  348       );
  349       print CGI::start_table({class=>"FormLayout"});
  350       print CGI::Tr(
  351         CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  352         CGI::td(
  353           CGI::textfield("add_sql_host", $add_sql_host, 25),
  354           CGI::br(),
  355           CGI::small("Leave blank to use the default host."),
  356         ),
  357       );
  358       print CGI::Tr(
  359         CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  360         CGI::td(
  361           CGI::textfield("add_sql_port", $add_sql_port, 25),
  362           CGI::br(),
  363           CGI::small("Leave blank to use the default port."),
  364         ),
  365       );
  366       print CGI::Tr(
  367         CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
  368         CGI::td(CGI::textfield("add_sql_username", $add_sql_username, 25)),
  369       );
  370       print CGI::Tr(
  371         CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
  372         CGI::td(CGI::password_field("add_sql_password", $add_sql_password, 25)),
  373       );
  374       print CGI::Tr(
  375         CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  376         CGI::td(CGI::textfield("add_sql_database", $add_sql_database, 25)),
  377       );
  378       print CGI::Tr(
  379         CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"),
  380         CGI::td(
  381           CGI::textfield("add_sql_wwhost", $add_sql_wwhost || "localhost", 25),
  382           CGI::br(),
  383           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."),
  384         ),
  385       );
  386       print CGI::end_table();
  387     } elsif ($dbLayout eq "gdbm") {
  388       print CGI::start_table({class=>"FormLayout"});
  389       print CGI::Tr(
  390         CGI::th({class=>"LeftHeader"}, "GDBM Global User ID:"),
  391         CGI::td(CGI::textfield("add_gdbm_globalUserID", $add_gdbm_globalUserID || "professor", 25)),
  392       );
  393       print CGI::end_table();
  394     }
  395 
  396     print CGI::end_td();
  397     print CGI::end_Tr();
  398     print CGI::end_table();
  399   }
  400 
  401 
  402   print CGI::p("To add an initial user to the new course, enter a user ID and password below. If you do not do so, you will not be able to log into the course.");
  403 
  404   print CGI::table({class=>"FormLayout"},
  405     CGI::Tr(
  406       CGI::th({class=>"LeftHeader"}, "Professor User ID:"),
  407       CGI::td(CGI::textfield("add_initial_userID", $add_initial_userID || "professor", 25)),
  408     ),
  409     CGI::Tr(
  410       CGI::th({class=>"LeftHeader"}, "Professor Password:"),
  411       CGI::td(CGI::password_field("add_initial_password", $add_initial_password, 25)),
  412     ),
  413   );
  414 
  415   print CGI::p({style=>"text-align: center"}, CGI::submit("add_course", "Add Course"));
  416 
  417   print CGI::end_form();
  418 }
  419 
  420 sub add_course_validate {
  421   my ($self) = @_;
  422   my $r = $self->r;
  423   my $ce = $r->ce;
  424   #my $db = $r->db;
  425   #my $authz = $r->authz;
  426   #my $urlpath = $r->urlpath;
  427 
  428   my $add_courseID          = $r->param("add_courseID") || "";
  429   my $add_dbLayout          = $r->param("add_dbLayout") || "";
  430   my $add_sql_host          = $r->param("add_sql_host") || "";
  431   my $add_sql_port          = $r->param("add_sql_port") || "";
  432   my $add_sql_username      = $r->param("add_sql_username") || "";
  433   my $add_sql_password      = $r->param("add_sql_password") || "";
  434   my $add_sql_database      = $r->param("add_sql_database") || "";
  435   my $add_sql_wwhost        = $r->param("add_sql_wwhost") || "";
  436   my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
  437   my $add_initial_userID    = $r->param("add_initial_userID") || "";
  438   my $add_initial_password  = $r->param("add_initial_password") || "";
  439 
  440   my @errors;
  441 
  442   if ($add_courseID eq "") {
  443     push @errors, "You must specify a course name.";
  444   }
  445 
  446   if ($add_dbLayout eq "") {
  447     push @errors, "You must select a database layout.";
  448   } else {
  449     if (exists $ce->{dbLayouts}->{$add_dbLayout}) {
  450       if ($add_dbLayout eq "sql") {
  451         push @errors, "You must specify the SQL admin username." if $add_sql_username eq "";
  452         push @errors, "You must specify the SQL admin password." if $add_sql_password eq "";
  453         push @errors, "You must specify the SQL confirm_delete_course." if $add_sql_database eq "";
  454         push @errors, "You must specify the WeBWorK host." if $add_sql_wwhost eq "";
  455       } elsif ($add_dbLayout eq "gdbm") {
  456         push @errors, "You must specify the GDBM global user ID." if $add_gdbm_globalUserID eq "";
  457       }
  458     } else {
  459       push @errors, "The database layout $add_dbLayout doesn't exist.";
  460     }
  461   }
  462 
  463   if ($add_initial_userID ne "") {
  464     push @errors, "You must specify a professor password." if $add_initial_password eq "";
  465   }
  466 
  467   return @errors;
  468 }
  469 
  470 sub do_add_course {
  471   my ($self) = @_;
  472   my $r = $self->r;
  473   my $ce = $r->ce;
  474   my $db = $r->db;
  475   #my $authz = $r->authz;
  476   my $urlpath = $r->urlpath;
  477 
  478   my $add_courseID          = $r->param("add_courseID") || "";
  479   my $add_dbLayout          = $r->param("add_dbLayout") || "";
  480   my $add_sql_host          = $r->param("add_sql_host") || "";
  481   my $add_sql_port          = $r->param("add_sql_port") || "";
  482   my $add_sql_username      = $r->param("add_sql_username") || "";
  483   my $add_sql_password      = $r->param("add_sql_password") || "";
  484   my $add_sql_database      = $r->param("add_sql_database") || "";
  485   my $add_sql_wwhost        = $r->param("add_sql_wwhost") || "";
  486   my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
  487   my $add_initial_userID    = $r->param("add_initial_userID") || "";
  488   my $add_initial_password  = $r->param("add_initial_password") || "";
  489 
  490   my $ce2 = WeBWorK::CourseEnvironment->new(
  491     $ce->{webworkDirs}->{root},
  492     $ce->{webworkURLs}->{root},
  493     $ce->{pg}->{directories}->{root},
  494     $add_courseID,
  495   );
  496 
  497   my %dbOptions;
  498   if ($add_dbLayout eq "sql") {
  499     $dbOptions{host}     = $add_sql_host if $add_sql_host ne "";
  500     $dbOptions{port}     = $add_sql_port if $add_sql_port ne "";
  501     $dbOptions{username} = $add_sql_username;
  502     $dbOptions{password} = $add_sql_password;
  503     $dbOptions{database} = $add_sql_database;
  504     $dbOptions{wwhost}   = $add_sql_wwhost;
  505   }
  506 
  507   my @users;
  508   if ($add_initial_userID ne "") {
  509      my $User = $db->newUser(
  510       user_id => $add_initial_userID,
  511       status => "C",
  512      );
  513      my $Password = $db->newPassword(
  514       user_id => $add_initial_userID,
  515       password => cryptPassword($add_initial_password),
  516      );
  517      my $PermissionLevel = $db->newPermissionLevel(
  518       user_id => $add_initial_userID,
  519       permission => "10",
  520      );
  521      push @users, [ $User, $Password, $PermissionLevel ];
  522   }
  523 
  524   eval {
  525     addCourse(
  526       courseID => $add_courseID,
  527       ce => $ce2,
  528       courseOptions => { dbLayoutName => $add_dbLayout },
  529       dbOptions => \%dbOptions,
  530       users => \@users,
  531     );
  532   };
  533 
  534   if ($@) {
  535     my $error = $@;
  536     print CGI::div({class=>"ResultsWithError"},
  537       CGI::p("An error occured while creating the course $add_courseID:"),
  538       CGI::tt(CGI::escapeHTML($error)),
  539     );
  540   } else {
  541     print CGI::div({class=>"ResultsWithoutError"},
  542       CGI::p("Successfully created the course $add_courseID"),
  543     );
  544     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
  545       courseID => $add_courseID);
  546     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
  547     print CGI::div({style=>"text-align: center"},
  548       CGI::a({href=>$newCourseURL}, "Log into $add_courseID"),
  549     );
  550   }
  551 }
  552 
  553 ################################################################################
  554 
  555 sub delete_course_form {
  556   my ($self) = @_;
  557   my $r = $self->r;
  558   my $ce = $r->ce;
  559   #my $db = $r->db;
  560   #my $authz = $r->authz;
  561   #my $urlpath = $r->urlpath;
  562 
  563   my $delete_courseID     = $r->param("delete_courseID")     || "";
  564   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  565   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  566   my $delete_sql_username = $r->param("delete_sql_username") || "";
  567   my $delete_sql_password = $r->param("delete_sql_password") || "";
  568   my $delete_sql_database = $r->param("delete_sql_database")    || "";
  569 
  570   my @courseIDs = listCourses($ce);
  571 
  572   my %courseLabels; # records... heh.
  573   foreach my $courseID (@courseIDs) {
  574     my $tempCE = WeBWorK::CourseEnvironment->new(
  575       $ce->{webworkDirs}->{root},
  576       $ce->{webworkURLs}->{root},
  577       $ce->{pg}->{directories}->{root},
  578       $courseID,
  579     );
  580     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
  581   }
  582 
  583   print CGI::h2("Delete Course");
  584 
  585   print CGI::start_form("POST", $r->uri);
  586   print $self->hidden_authen_fields;
  587   print $self->hidden_fields("subDisplay");
  588 
  589   print CGI::p("Select a course to delete.");
  590 
  591   print CGI::table({class=>"FormLayout"},
  592     CGI::Tr(
  593       CGI::th({class=>"LeftHeader"}, "Course Name:"),
  594       CGI::td(
  595         CGI::scrolling_list(
  596           -name => "delete_courseID",
  597           -values => \@courseIDs,
  598           -default => $delete_courseID,
  599           -size => 10,
  600           -multiple => 0,
  601           -labels => \%courseLabels,
  602         ),
  603       ),
  604     ),
  605   );
  606 
  607   print CGI::p(
  608     "If the course's database layout (indicated in parentheses above) is "
  609     . CGI::b("sql") . ", supply the SQL connections information requested below."
  610   );
  611 
  612   print CGI::start_table({class=>"FormLayout"});
  613   print CGI::Tr(
  614     CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  615     CGI::td(
  616       CGI::textfield("delete_sql_host", $delete_sql_host, 25),
  617       CGI::br(),
  618       CGI::small("Leave blank to use the default host."),
  619     ),
  620   );
  621   print CGI::Tr(
  622     CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  623     CGI::td(
  624       CGI::textfield("delete_sql_port", $delete_sql_port, 25),
  625       CGI::br(),
  626       CGI::small("Leave blank to use the default port."),
  627     ),
  628   );
  629   print CGI::Tr(
  630     CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
  631     CGI::td(CGI::textfield("delete_sql_username", $delete_sql_username, 25)),
  632   );
  633   print CGI::Tr(
  634     CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
  635     CGI::td(CGI::password_field("delete_sql_password", $delete_sql_password, 25)),
  636   );
  637   print CGI::Tr(
  638     CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  639     CGI::td(CGI::textfield("delete_sql_database", $delete_sql_database, 25)),
  640   );
  641   print CGI::end_table();
  642 
  643   print CGI::p({style=>"text-align: center"}, CGI::submit("delete_course", "Delete Course"));
  644 
  645   print CGI::end_form();
  646 }
  647 
  648 sub delete_course_validate {
  649   my ($self) = @_;
  650   my $r = $self->r;
  651   my $ce = $r->ce;
  652   #my $db = $r->db;
  653   #my $authz = $r->authz;
  654   my $urlpath = $r->urlpath;
  655 
  656   my $delete_courseID     = $r->param("delete_courseID")     || "";
  657   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  658   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  659   my $delete_sql_username = $r->param("delete_sql_username") || "";
  660   my $delete_sql_password = $r->param("delete_sql_password") || "";
  661   my $delete_sql_database = $r->param("delete_sql_database") || "";
  662 
  663   my @errors;
  664 
  665   if ($delete_courseID eq "") {
  666     push @errors, "You must specify a course name.";
  667   } elsif ($delete_courseID eq $urlpath->arg("courseID")) {
  668     push @errors, "You cannot delete the course you are currently using.";
  669   }
  670 
  671   my $ce2 = WeBWorK::CourseEnvironment->new(
  672     $ce->{webworkDirs}->{root},
  673     $ce->{webworkURLs}->{root},
  674     $ce->{pg}->{directories}->{root},
  675     $delete_courseID,
  676   );
  677 
  678   if ($ce2->{dbLayoutName} eq "sql") {
  679     push @errors, "You must specify the SQL admin username." if $delete_sql_username eq "";
  680     push @errors, "You must specify the SQL admin password." if $delete_sql_password eq "";
  681     push @errors, "You must specify the SQL database name." if $delete_sql_database eq "";
  682   }
  683 
  684   return @errors;
  685 }
  686 
  687 sub delete_course_confirm {
  688   my ($self) = @_;
  689   my $r = $self->r;
  690   my $ce = $r->ce;
  691   #my $db = $r->db;
  692   #my $authz = $r->authz;
  693   #my $urlpath = $r->urlpath;
  694 
  695   print CGI::h2("Delete Course");
  696 
  697   my $delete_courseID     = $r->param("delete_courseID")     || "";
  698   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  699   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  700   my $delete_sql_database = $r->param("delete_sql_database") || "";
  701 
  702   my $ce2 = WeBWorK::CourseEnvironment->new(
  703     $ce->{webworkDirs}->{root},
  704     $ce->{webworkURLs}->{root},
  705     $ce->{pg}->{directories}->{root},
  706     $delete_courseID,
  707   );
  708 
  709   if ($ce2->{dbLayoutName} eq "sql") {
  710     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  711     . "? All course files and data and the following database will be destroyed."
  712     . " There is no undo available.");
  713 
  714     print CGI::table({class=>"FormLayout"},
  715       CGI::Tr(
  716         CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
  717         CGI::td($delete_sql_host || "system default"),
  718       ),
  719       CGI::Tr(
  720         CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
  721         CGI::td($delete_sql_port || "system default"),
  722       ),
  723       CGI::Tr(
  724         CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
  725         CGI::td($delete_sql_database),
  726       ),
  727     );
  728   } else {
  729     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
  730       . "? All course files and data will be destroyed. There is no undo available.");
  731   }
  732 
  733   print CGI::start_form("POST", $r->uri);
  734   print $self->hidden_authen_fields;
  735   print $self->hidden_fields("subDisplay");
  736   print $self->hidden_fields(qw/delete_courseID delete_sql_host delete_sql_port delete_sql_username delete_sql_password delete_sql_database/);
  737 
  738   print CGI::p({style=>"text-align: center"},
  739     CGI::submit("decline_delete_course", "Don't delete"),
  740     "&nbsp;",
  741     CGI::submit("confirm_delete_course", "Delete"),
  742   );
  743 
  744   print CGI::end_form();
  745 }
  746 
  747 sub do_delete_course {
  748   my ($self) = @_;
  749   my $r = $self->r;
  750   my $ce = $r->ce;
  751   #my $db = $r->db;
  752   #my $authz = $r->authz;
  753   #my $urlpath = $r->urlpath;
  754 
  755   my $delete_courseID     = $r->param("delete_courseID")     || "";
  756   my $delete_sql_host     = $r->param("delete_sql_host")     || "";
  757   my $delete_sql_port     = $r->param("delete_sql_port")     || "";
  758   my $delete_sql_username = $r->param("delete_sql_username") || "";
  759   my $delete_sql_password = $r->param("delete_sql_password") || "";
  760   my $delete_sql_database = $r->param("delete_sql_database") || "";
  761 
  762   my $ce2 = WeBWorK::CourseEnvironment->new(
  763     $ce->{webworkDirs}->{root},
  764     $ce->{webworkURLs}->{root},
  765     $ce->{pg}->{directories}->{root},
  766     $delete_courseID,
  767   );
  768 
  769   my %dbOptions;
  770   if ($ce2->{dbLayoutName} eq "sql") {
  771     $dbOptions{host}     = $delete_sql_host if $delete_sql_host ne "";
  772     $dbOptions{port}     = $delete_sql_port if $delete_sql_port ne "";
  773     $dbOptions{username} = $delete_sql_username;
  774     $dbOptions{password} = $delete_sql_password;
  775     $dbOptions{database} = $delete_sql_database;
  776   }
  777 
  778   eval {
  779     deleteCourse(
  780       courseID => $delete_courseID,
  781       ce => $ce2,
  782       dbOptions => \%dbOptions,
  783     );
  784   };
  785 
  786   if ($@) {
  787     my $error = $@;
  788     print CGI::div({class=>"ResultsWithError"},
  789       CGI::p("An error occured while deleting the course $delete_courseID:"),
  790       CGI::tt(CGI::escapeHTML($error)),
  791     );
  792   } else {
  793     print CGI::div({class=>"ResultsWithoutError"},
  794       CGI::p("Possibly deleted the course $delete_courseID. (We need better error checking in deleteCourse().)"),
  795     );
  796 
  797     print CGI::start_form("POST", $r->uri);
  798     print $self->hidden_authen_fields;
  799     print $self->hidden_fields("subDisplay");
  800 
  801     print CGI::p({style=>"text-align: center"}, CGI::submit("decline_delete_course", "OK"),);
  802 
  803     print CGI::end_form();
  804   }
  805 }
  806 
  807 ################################################################################
  808 
  809 sub export_database_form {
  810   my ($self) = @_;
  811   my $r = $self->r;
  812   my $ce = $r->ce;
  813   #my $db = $r->db;
  814   #my $authz = $r->authz;
  815   #my $urlpath = $r->urlpath;
  816 
  817   my @tables = keys %{$ce->{dbLayout}};
  818 
  819   my $export_courseID = $r->param("export_courseID") || "";
  820   my @export_tables   = $r->param("export_tables");
  821 
  822   @export_tables = @tables unless @export_tables;
  823 
  824   my @courseIDs = listCourses($ce);
  825 
  826   my %courseLabels; # records... heh.
  827   foreach my $courseID (@courseIDs) {
  828     my $tempCE = WeBWorK::CourseEnvironment->new(
  829       $ce->{webworkDirs}->{root},
  830       $ce->{webworkURLs}->{root},
  831       $ce->{pg}->{directories}->{root},
  832       $courseID,
  833     );
  834     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
  835   }
  836 
  837   print CGI::h2("Export Database");
  838 
  839   print CGI::start_form("POST", $r->uri);
  840   print $self->hidden_authen_fields;
  841   print $self->hidden_fields("subDisplay");
  842 
  843   print CGI::p("Select a course to export the course's database.");
  844 
  845   print CGI::table({class=>"FormLayout"},
  846     CGI::Tr(
  847       CGI::th({class=>"LeftHeader"}, "Course Name:"),
  848       CGI::td(
  849         CGI::scrolling_list(
  850           -name => "export_courseID",
  851           -values => \@courseIDs,
  852           -default => $export_courseID,
  853           -size => 10,
  854           -multiple => 0,
  855           -labels => \%courseLabels,
  856         ),
  857       ),
  858     ),
  859     CGI::Tr(
  860       CGI::th({class=>"LeftHeader"}, "Tables to Export:"),
  861       CGI::td(
  862         CGI::checkbox_group(
  863           -name => "export_tables",
  864           -values => \@tables,
  865           -default => \@export_tables,
  866           -linebreak => 1,
  867         ),
  868       ),
  869     ),
  870   );
  871 
  872   print CGI::p({style=>"text-align: center"}, CGI::submit("export_database", "Export Database"));
  873 
  874   print CGI::end_form();
  875 }
  876 
  877 sub export_database_validate {
  878   my ($self) = @_;
  879   my $r = $self->r;
  880   #my $ce = $r->ce;
  881   #my $db = $r->db;
  882   #my $authz = $r->authz;
  883   #my $urlpath = $r->urlpath;
  884 
  885   my $export_courseID = $r->param("export_courseID") || "";
  886   my @export_tables   = $r->param("export_tables");
  887 
  888   my @errors;
  889 
  890   if ($export_courseID eq "") {
  891     push @errors, "You must specify a course name.";
  892   }
  893 
  894   unless (@export_tables) {
  895     push @errors, "You must specify at least one table to export.";
  896   }
  897 
  898   return @errors;
  899 }
  900 
  901 sub do_export_database {
  902   my ($self) = @_;
  903   my $r = $self->r;
  904   my $ce = $r->ce;
  905   #my $db = $r->db;
  906   #my $authz = $r->authz;
  907   my $urlpath = $r->urlpath;
  908 
  909   my $export_courseID = $r->param("export_courseID");
  910   my @export_tables   = $r->param("export_tables");
  911 
  912   my $ce2 = WeBWorK::CourseEnvironment->new(
  913     $ce->{webworkDirs}->{root},
  914     $ce->{webworkURLs}->{root},
  915     $ce->{pg}->{directories}->{root},
  916     $export_courseID,
  917   );
  918 
  919   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
  920 
  921   my ($fh, $export_file) = tempfile("db_export_XXXXXX", DIR => $ce->{webworkDirs}->{tmp});
  922   my ($random_chars) = $export_file =~ m/db_export_(\w+)$/;
  923 
  924   my @errors;
  925 
  926   eval {
  927     @errors = dbExport(
  928       db => $db2,
  929       xml => $fh,
  930       tables => \@export_tables,
  931     );
  932   };
  933 
  934   push @errors, "Fatal exception: $@" if $@;
  935 
  936   if (@errors) {
  937     print CGI::div({class=>"ResultsWithError"},
  938       CGI::p("An error occured while exporting the database of course $export_courseID:"),
  939       CGI::ul(CGI::li(\@errors)),
  940     );
  941   } else {
  942     print CGI::div({class=>"ResultsWithoutError"},
  943       CGI::p("Export succeeded."),
  944     );
  945 
  946     print CGI::div({style=>"text-align: center"},
  947       CGI::a({href=>$self->systemLink($urlpath, params=>{download_exported_database=>$random_chars, export_courseID=>undef})}, "Download Exported Database"),
  948     );
  949   }
  950 }
  951 
  952 ################################################################################
  953 
  954 sub import_database_form {
  955   my ($self) = @_;
  956   my $r = $self->r;
  957   my $ce = $r->ce;
  958   #my $db = $r->db;
  959   #my $authz = $r->authz;
  960   #my $urlpath = $r->urlpath;
  961 
  962   my @tables = keys %{$ce->{dbLayout}};
  963 
  964   my $import_file     = $r->param("import_file")     || "";
  965   my $import_courseID = $r->param("import_courseID") || "";
  966   my @import_tables   = $r->param("import_tables");
  967   my $import_conflict = $r->param("import_conflict") || "skip";
  968 
  969   @import_tables = @tables unless @import_tables;
  970 
  971   my @courseIDs = listCourses($ce);
  972 
  973   my %courseLabels; # records... heh.
  974   foreach my $courseID (@courseIDs) {
  975     my $tempCE = WeBWorK::CourseEnvironment->new(
  976       $ce->{webworkDirs}->{root},
  977       $ce->{webworkURLs}->{root},
  978       $ce->{pg}->{directories}->{root},
  979       $courseID,
  980     );
  981     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
  982   }
  983 
  984   print CGI::h2("Import Database");
  985 
  986   print CGI::start_form("POST", $r->uri, &CGI::MULTIPART);
  987   print $self->hidden_authen_fields;
  988   print $self->hidden_fields("subDisplay");
  989 
  990   print CGI::table({class=>"FormLayout"},
  991     CGI::Tr(
  992       CGI::th({class=>"LeftHeader"}, "Database XML File:"),
  993       CGI::td(
  994         CGI::filefield(
  995           -name => "import_file",
  996           -size => 50,
  997         ),
  998       ),
  999     ),
 1000     CGI::Tr(
 1001       CGI::th({class=>"LeftHeader"}, "Tables to Import:"),
 1002       CGI::td(
 1003         CGI::checkbox_group(
 1004           -name => "import_tables",
 1005           -values => \@tables,
 1006           -default => \@import_tables,
 1007           -linebreak => 1,
 1008         ),
 1009       ),
 1010     ),
 1011     CGI::Tr(
 1012       CGI::th({class=>"LeftHeader"}, "Import into Course:"),
 1013       CGI::td(
 1014         CGI::scrolling_list(
 1015           -name => "import_courseID",
 1016           -values => \@courseIDs,
 1017           -default => $import_courseID,
 1018           -size => 10,
 1019           -multiple => 0,
 1020           -labels => \%courseLabels,
 1021         ),
 1022       ),
 1023     ),
 1024     CGI::Tr(
 1025       CGI::th({class=>"LeftHeader"}, "Conflicts:"),
 1026       CGI::td(
 1027         CGI::radio_group(
 1028           -name => "import_conflict",
 1029           -values => [qw/skip replace/],
 1030           -default => $import_conflict,
 1031           -linebreak=>'true',
 1032           -labels => {
 1033             skip => "Skip duplicate records",
 1034             replace => "Replace duplicate records",
 1035           },
 1036         ),
 1037       ),
 1038     ),
 1039   );
 1040 
 1041   print CGI::p({style=>"text-align: center"}, CGI::submit("import_database", "Import Database"));
 1042 
 1043   print CGI::end_form();
 1044 }
 1045 
 1046 sub import_database_validate {
 1047   my ($self) = @_;
 1048   my $r = $self->r;
 1049   #my $ce = $r->ce;
 1050   #my $db = $r->db;
 1051   #my $authz = $r->authz;
 1052   #my $urlpath = $r->urlpath;
 1053 
 1054   my $import_file     = $r->param("import_file")     || "";
 1055   my $import_courseID = $r->param("import_courseID") || "";
 1056   my @import_tables   = $r->param("import_tables");
 1057   #my $import_conflict = $r->param("import_conflict") || "skip"; # not checked
 1058 
 1059   my @errors;
 1060 
 1061   if ($import_file eq "") {
 1062     push @errors, "You must specify a database file to upload.";
 1063   }
 1064 
 1065   if ($import_courseID eq "") {
 1066     push @errors, "You must specify a course name.";
 1067   }
 1068 
 1069   unless (@import_tables) {
 1070     push @errors, "You must specify at least one table to import.";
 1071   }
 1072 
 1073   return @errors;
 1074 }
 1075 
 1076 sub do_import_database {
 1077   my ($self) = @_;
 1078   my $r = $self->r;
 1079   my $ce = $r->ce;
 1080   #my $db = $r->db;
 1081   #my $authz = $r->authz;
 1082   my $urlpath = $r->urlpath;
 1083 
 1084   my $import_file     = $r->param("import_file");
 1085   my $import_courseID = $r->param("import_courseID");
 1086   my @import_tables   = $r->param("import_tables");
 1087   my $import_conflict = $r->param("import_conflict") || "skip"; # need default -- not checked above
 1088 
 1089   my $ce2 = WeBWorK::CourseEnvironment->new(
 1090     $ce->{webworkDirs}->{root},
 1091     $ce->{webworkURLs}->{root},
 1092     $ce->{pg}->{directories}->{root},
 1093     $import_courseID,
 1094   );
 1095 
 1096   my $db2 = new WeBWorK::DB($ce2->{dbLayout});
 1097 
 1098   # retrieve upload from upload cache
 1099   my ($id, $hash) = split /\s+/, $import_file;
 1100   my $upload = WeBWorK::Upload->retrieve($id, $hash,
 1101     dir => $ce->{webworkDirs}->{uploadCache}
 1102   );
 1103 
 1104   my @errors;
 1105 
 1106   eval {
 1107     @errors = dbImport(
 1108       db => $db2,
 1109       xml => $upload->fileHandle,
 1110       tables => \@import_tables,
 1111       conflict => $import_conflict,
 1112     );
 1113   };
 1114 
 1115   $upload->dispose;
 1116 
 1117   push @errors, "Fatal exception: $@" if $@;
 1118 
 1119   if (@errors) {
 1120     print CGI::div({class=>"ResultsWithError"},
 1121       CGI::p("An error occured while importing the database of course $import_courseID:"),
 1122       CGI::ul(CGI::li(\@errors)),
 1123     );
 1124   } else {
 1125     print CGI::div({class=>"ResultsWithoutError"},
 1126       CGI::p("Import succeeded."),
 1127     );
 1128   }
 1129 }
 1130 
 1131 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9