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