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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2026 - (download) (as text) (annotate)
Fri May 7 14:12:20 2004 UTC (9 years ago) by gage
Original Path: trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm
File size: 33442 byte(s)
Only someone with professor privileges can use CourseAdministration.pm

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9