Parent Directory
|
Revision Log
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 " ", 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 |