Parent Directory
|
Revision Log
CAUTION. Major update!!! Modifications made up until the release of 2.0 on July 16, 2004 on the 2.0 branch have been incorporated into version 2.1 alpha 1. A moderate amount of testing has been done. It will take some time to reconfigure your global.conf file once you update to this version.
1 ################################################################################ 2 # WeBWorK Online Homework Delivery System 3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 4 # $CVSHeader: webwork2/lib/WeBWorK/Utils/CourseManagement.pm,v 1.17 2004/06/24 17:44:16 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::Utils::CourseManagement; 18 use base qw(Exporter); 19 20 =head1 NAME 21 22 WeBWorK::Utils::CourseManagement - create, rename, and delete courses. 23 24 =cut 25 26 use strict; 27 use warnings; 28 use Carp; 29 use DBI; 30 use File::Path qw(rmtree); 31 use WeBWorK::CourseEnvironment; 32 use WeBWorK::Debug; 33 use WeBWorK::Utils qw(runtime_use undefstr readDirectory); 34 35 our @EXPORT = (); 36 our @EXPORT_OK = qw( 37 addCourse 38 renameCourse 39 deleteCourse 40 listCourses 41 ); 42 43 use constant CREATE_HELPERS => { 44 sql => \&addCourseSQL, 45 }; 46 47 use constant RENAME_HELPERS => { 48 sql => \&renameCourseSQL, 49 gdbm => \&renameCourseGDBM, 50 }; 51 52 use constant DELETE_HELPERS => { 53 sql => \&deleteCourseSQL, 54 }; 55 56 =head1 FUNCTIONS 57 58 =over 59 60 =item addCourse(%options) 61 62 %options must contain: 63 64 courseID => $courseID, 65 ce => $ce, 66 courseOptions => $courseOptions, 67 dbOptions => $dbOptions, 68 users => $users 69 70 %options may contain: 71 72 templatesFrom => $templatesCourseID, 73 74 Create a new course named $courseID. 75 76 $ce is a WeBWorK::CourseEnvironment object that describes the new course's 77 environment. 78 79 $courseOptions is a reference to a hash containing the following options: 80 81 dbLayoutName => $dbLayoutName 82 globalUserID => $dbLayouts{gdbm}->{set}->{params}->{globalUserID} 83 $dbLayouts{gdbm}->{problem}->{params}->{globalUserID} 84 allowedRecipients => $mail{allowedRecipients} 85 feedbackRecipients => $mail{feedbackRecipients} 86 PRINT_FILE_NAMES_FOR => $pg{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR} 87 88 C<dbLayoutName> is required. C<allowedRecipients>, C<feedbackRecipients>, and 89 C<PRINT_FILE_NAMES_FOR> are references to arrays. 90 91 $dbOptions is a reference to a hash containing information required to create a 92 database for the course. 93 94 if dbLayout == "sql": 95 96 host => host to connect to 97 port => port to connect to 98 username => user to connect as (must have CREATE, DELETE, FILE, INSERT, 99 SELECT, UPDATE privileges, WITH GRANT OPTION.) 100 password => password to supply 101 database => the name of the database to create 102 wwhost => the host from which the webwork database users will be allowed 103 to connect. (if host is set to localhost, this should be set to 104 localhost too.) 105 106 These values must match the information given in the selected dbLayout. If 107 $dbOptions is undefined, addCourse() assumes that the database has already been 108 created, and skips that step in the course creation process. 109 110 $users is a list of arrayrefs, each containing a User, Password, and 111 PermissionLevel record for a single user: 112 113 $users = [ $User, $Password, $PermissionLevel ] 114 115 These users are added to the course. 116 117 $templatesCourseID indicates the ID of a course from which the contents of the 118 templates directory will be copied to the new course. 119 120 =cut 121 122 sub addCourse { 123 my (%options) = @_; 124 125 my $courseID = $options{courseID}; 126 my $ce = $options{ce}; 127 my %courseOptions = %{ $options{courseOptions} }; 128 my %dbOptions = defined $options{dbOptions} ? %{ $options{dbOptions} } : (); 129 my @users = exists $options{users} ? @{ $options{users} } : (); 130 131 # get the database layout out of the options hash 132 my $dbLayoutName = $courseOptions{dbLayoutName}; 133 134 # collect some data 135 my $coursesDir = $ce->{webworkDirs}->{courses}; 136 my $courseDir = "$coursesDir/$courseID"; 137 138 # fail if the course already exists 139 # IMPORTANT: this must be the first check! if any check other than this one 140 # fails, CourseAdmin deletes the course!! Oh no!!! 141 if (-e $courseDir) { 142 croak "$courseID: course exists"; 143 } 144 145 # FIXME: is hyphen ok? signs point to "no" 146 croak "Invalid characters in course ID: '$courseID' (valid characters are [A-Za-z0-9_])" 147 unless $courseID =~ m/^[\w-]*$/; 148 149 # fail if the database layout is invalid 150 if (defined $dbLayoutName and not exists $ce->{dbLayouts}->{$dbLayoutName}) { 151 croak "$dbLayoutName: not found in \%dbLayouts"; 152 } 153 154 # if we didn't get a database layout, use the default one 155 if (not defined $dbLayoutName) { 156 $dbLayoutName = $ce->{dbLayoutName}; 157 } 158 159 ##### step 1: create course directory structure ##### 160 161 my @subDirs = sort values %{ $ce->{courseDirs} }; 162 foreach my $subDir (@subDirs) { 163 mkdir "$subDir" 164 or die "Failed to create course directory $subDir: $!\n"; 165 } 166 167 ##### step 2: create course database (if necessary) ##### 168 169 my $createHelper = CREATE_HELPERS->{$dbLayoutName}; 170 if (defined $createHelper) { 171 my $createHelperResult = $createHelper->($courseID, $ce, $dbLayoutName, %dbOptions); 172 die "$courseID: course database creation failed.\n" unless $createHelperResult; 173 } 174 175 ##### step 3: populate course database ##### 176 177 my $db = WeBWorK::DB->new($ce->{dbLayouts}->{$dbLayoutName}); 178 179 # make sure we add the global user 180 if (exists $courseOptions{globalUserID}) { 181 unless (grep { $_->[0]->user_id eq $courseOptions{globalUserID} } @users) { 182 push @users, [ 183 $db->newUser(user_id => $courseOptions{globalUserID}), 184 $db->newPassword(user_id => $courseOptions{globalUserID}), 185 $db->newPermissionLevel(user_id => $courseOptions{globalUserID}), 186 ]; 187 } 188 } 189 190 my @professors; # user ID of any user whose permission level == 10 191 192 foreach my $userTriple (@users) { 193 my ($User, $Password, $PermissionLevel) = @$userTriple; 194 195 if (defined $PermissionLevel->permission and $PermissionLevel->permission == 10) { 196 push @professors, $PermissionLevel->user_id; 197 } 198 199 eval { $db->addUser($User) }; warn $@ if $@; 200 eval { $db->addPassword($Password) }; warn $@ if $@; 201 eval { $db->addPermissionLevel($PermissionLevel) }; warn $@ if $@; 202 } 203 204 ##### step 4: write course.conf file ##### 205 206 my $courseEnvFile = $ce->{courseFiles}->{environment}; 207 open my $fh, ">", $courseEnvFile 208 or die "failed to open $courseEnvFile for writing.\n"; 209 writeCourseConf($fh, $ce, %courseOptions); 210 close $fh; 211 212 ##### step 5: copy templates ##### 213 214 if (exists $options{templatesFrom}) { 215 my $sourceCourse = $options{templatesFrom}; 216 my $sourceCE = new WeBWorK::CourseEnvironment( 217 $ce->{webworkDirs}->{root}, 218 $ce->{webworkURLs}->{root}, 219 $ce->{pg}->{directories}->{root}, 220 $sourceCourse, 221 ); 222 my $sourceDir = $sourceCE->{courseDirs}->{templates}; 223 224 if (-d $sourceDir) { 225 my $destDir = $ce->{courseDirs}->{templates}; 226 my $errno = system "/bin/cp -R $sourceDir/* $destDir"; 227 if ($errno) { 228 warn "Failed to copy templates from course '$sourceCourse' (errno=$errno): $!\n"; 229 } 230 } else { 231 warn "Failed to copy templates from course '$sourceCourse': templates directory '$sourceDir' does not exist.\n"; 232 } 233 } 234 235 } 236 237 =item renameCourse($webworkRoot, $oldCourseID, $newCourseID) 238 239 Rename the course named $oldCourseID to $newCourseID. 240 241 The name course directory is set to $newCourseID. 242 243 If the course's database layout is C<sql>, a new database is created, course 244 data is exported from the old database and imported into the new database, and 245 the old database is deleted. 246 247 If the course's database layout is C<gdbm>, the DBM files are simply renamed on 248 disk. 249 250 If the course's database layout is something else, no database changes are made. 251 252 Any errors encountered while renaming the course are returned. 253 254 =cut 255 256 sub renameCourse { 257 my ($webworkRoot, $oldCourseID, $newCourseID) = @_; 258 259 260 } 261 262 =item deleteCourse(%options) 263 264 Options must contain: 265 266 courseID => $courseID, 267 ce => $ce, 268 dbOptions => $dbOptions, 269 270 $ce is a WeBWorK::CourseEnvironment object that describes the course's 271 environment. It is your responsability to pass a course environment object that 272 describes the course to be deleted. Do not pass the course environment object 273 associated with the request, unless you are deleting the course you're currently 274 using. 275 276 $dbOptions is a reference to a hash containing information required to create a 277 database for the course. 278 279 if dbLayout == "sql": 280 281 host => host to connect to 282 port => port to connect to 283 username => user to connect as (must have CREATE, DELETE, FILE, INSERT, 284 SELECT, UPDATE privileges, WITH GRANT OPTION.) 285 password => password to supply 286 database => the name of the database to create 287 288 Deletes the course named $courseID. The course directory is removed. 289 290 If the course's database layout is C<sql>, the course database is dropped. 291 292 If the course's database layout is something else, no databases are removed. 293 294 Any errors encountered while deleting the course are returned. 295 296 =cut 297 298 sub deleteCourse { 299 my (%options) = @_; 300 301 my $courseID = $options{courseID}; 302 my $ce = $options{ce}; 303 my %dbOptions = defined $options{dbOptions} ? %{ $options{dbOptions} } : (); 304 305 # make sure the user isn't brain damaged 306 die "the course environment supplied doesn't appear to describe the course $courseID. can't proceed." 307 unless $ce->{courseName} eq $courseID; 308 309 ##### step 1: delete course database (if necessary) ##### 310 311 my $dbLayoutName = $ce->{dbLayoutName}; 312 my $deleteHelper = DELETE_HELPERS->{$dbLayoutName}; 313 if (defined $deleteHelper) { 314 my $deleteHelperResult = $deleteHelper->($courseID, $ce, $dbLayoutName, %dbOptions); 315 debug("deleteHelper returned '$deleteHelperResult'."); 316 unless ($deleteHelperResult) { 317 die "Failed to delete course database. Does the database exist? Were proper admin credentials given?\n"; 318 } 319 } 320 321 ##### step 2: delete course directory structure ##### 322 323 # my $courseDir = $ce->{courseDirs}->{root}; 324 # the tmp file might be in a different tree 325 my @courseDirs = keys %{ $ce->{courseDirs} }; 326 foreach my $key (@courseDirs) { 327 my $courseDir = $ce->{courseDirs}->{$key}; 328 rmtree($courseDir, 0, 0) if -e $courseDir; 329 } 330 } 331 332 =item listCourses($ce) 333 334 Lists the courses defined. 335 336 =cut 337 338 sub listCourses { 339 my ($ce) = @_; 340 341 my $coursesDir = $ce->{webworkDirs}->{courses}; 342 343 return grep { not (m/^\./ or m/^CVS$/) and -d "$coursesDir/$_" } readDirectory($coursesDir); 344 } 345 346 =back 347 348 =cut 349 350 ################################################################################ 351 352 =head1 DATABASE-LAYOUT SPECIFIC HELPER FUNCTIONS 353 354 These functions are used by the methods and should not be called directly. 355 356 =over 357 358 =item addCourseSQL($courseID, $ce, $dbLayoutName, %options) 359 360 Creates the course database for an SQL course. Return value is boolean, 361 indicates success or failure. 362 363 =cut 364 365 sub addCourseSQL { 366 my ($courseID, $ce, $dbLayoutName, %options) = @_; 367 368 ##### parse dbLayout to generate sql statements ##### 369 370 my %sources; 371 372 debug("dbLayoutName=$dbLayoutName"); 373 374 my %dbLayout = %{ $ce->{dbLayouts}->{$dbLayoutName} }; 375 376 my @tables = keys %dbLayout; 377 debug("layout defines the following tables: @tables"); 378 379 foreach my $table (@tables) { 380 my %table = %{ $dbLayout{$table} }; 381 my %params = %{ $table{params} }; 382 383 my $source = $table{source}; 384 debug("$table: DBI source is $source\n"); 385 386 my $tableOverride = $params{tableOverride}; 387 debug("$table: SQL table name is ", undefstr("not defined", $tableOverride), "\n"); 388 389 my $recordClass = $table{record}; 390 debug("$table: record class is $recordClass\n"); 391 392 runtime_use($recordClass); 393 my @fields = $recordClass->FIELDS; 394 debug("$table: WeBWorK field names: @fields\n"); 395 396 if (exists $params{fieldOverride}) { 397 my %fieldOverride = %{ $params{fieldOverride} }; 398 foreach my $field (@fields) { 399 $field = $fieldOverride{$field} if exists $fieldOverride{$field}; 400 } 401 debug("$table: SQL field names: @fields\n"); 402 } 403 404 # generate table creation statement 405 406 my $tableName = $tableOverride || $table; 407 my @fieldList; 408 foreach my $field (@fields) { 409 # a stupid hack to make PSVNs numeric and auto-increment 410 if ($field eq "psvn") { 411 push @fieldList, "$field INT NOT NULL PRIMARY KEY AUTO_INCREMENT"; 412 } else { 413 push @fieldList, "$field TEXT"; 414 } 415 } 416 my $fieldString = join(", ", @fieldList); 417 my $createStmt = "CREATE TABLE $tableName ( $fieldString );"; 418 419 debug("$table: CREATE statement is: $createStmt\n"); 420 421 # generate GRANT statements 422 423 my $grantStmtRO = "GRANT SELECT" 424 . " ON `$options{database}`.$tableName" 425 . " TO $params{usernameRO}\@$options{wwhost}" 426 . " IDENTIFIED BY '$params{passwordRO}';"; 427 my $grantStmtRW = "GRANT SELECT, INSERT, UPDATE, DELETE" 428 . " ON `$options{database}`.$tableName" 429 . " TO $params{usernameRW}\@$options{wwhost}" 430 . " IDENTIFIED BY '$params{passwordRW}';"; 431 432 debug("$table: GRANT RO statement is: $grantStmtRO\n"); 433 debug("$table: GRANT RW statement is: $grantStmtRW\n"); 434 435 # add to source hash 436 437 if (exists $sources{$source}) { 438 push @{ $sources{$source} }, $createStmt, $grantStmtRO, $grantStmtRW; 439 } else { 440 $sources{$source} = [ $createStmt, $grantStmtRO, $grantStmtRW ]; 441 } 442 443 #warn "\n"; 444 } 445 446 ##### handle multiple sources ##### 447 448 # if more than one source is listed, we only want to create the tables that 449 # have the most popular source 450 451 my $source; 452 if (keys %sources > 1) { 453 # more than one -- warn and select the most popular source 454 debug("database layout $dbLayoutName defines more than one SQL source.\n"); 455 foreach my $curr (keys %sources) { 456 $source = $curr if not defined $source or @{ $sources{$curr} } > @{ $sources{$source} }; 457 } 458 debug("only creating tables with source \"$source\".\n"); 459 debug("others will have to be created manually.\n"); 460 } else { 461 # there's only one 462 ($source) = keys %sources; 463 } 464 my @stmts = ( 465 "CREATE DATABASE `$options{database}`;", 466 "USE $options{database};", # oddly, backquotes prohibited with USE statement... 467 @{ $sources{$source} } 468 ); 469 470 ##### issue SQL statements ##### 471 472 my ($driver) = $source =~ m/^dbi:(\w+):/i; 473 return execSQLStatements($driver, $ce->{externalPrograms}, \%options, @stmts) 474 } 475 476 =item renameCourseSQL($oldCourseID, $newCourseID, $ce, $dbLayoutName, %options) 477 478 =cut 479 480 =item deleteCourseSQL($courseID, $ce, $dbLayoutName, %options) 481 482 =cut 483 484 sub deleteCourseSQL { 485 my ($courseID, $ce, $dbLayoutName, %options) = @_; 486 487 # get the most popular DBI source, so we know what driver to use 488 my $dbi_source = do { 489 my %sources; 490 foreach my $table (keys %{ $ce->{dbLayouts}->{$dbLayoutName} }) { 491 $sources{$ce->{dbLayouts}->{$dbLayoutName}->{$table}->{source}}++; 492 } 493 my $source; 494 if (keys %sources > 1) { 495 foreach my $curr (keys %sources) { 496 $source = $curr if @{ $sources{$curr} } > @{ $sources{$source} }; 497 } 498 } else { 499 ($source) = keys %sources; 500 } 501 $source; 502 }; 503 504 my $stmt = "DROP DATABASE `$options{database}`;"; 505 506 my ($driver) = $dbi_source =~ m/^dbi:(\w+):/i; 507 return execSQLStatements($driver, $ce->{externalPrograms}, \%options, $stmt); 508 } 509 510 =item renameCourseGDBM($oldCourseID, $newCourseID, $ce, $dbLayoutName, %options) 511 512 =cut 513 514 =back 515 516 =cut 517 518 ################################################################################ 519 520 =head1 UTILITIES 521 522 These functions are used by the methods and should not be called directly. 523 524 =over 525 526 =item execSQLStatements($driver, $externalPrograms, $dbOptions, @statements) 527 528 Execute the listed SQL statements. The appropriate SQL console is determined 529 using $driver and invoked with the options listed in $dbOptions. 530 531 $options is a reference to a hash containing the pairs accepted in %dbOptions by 532 addCourse(), above. 533 534 Returns true on success, false on failure. 535 536 =cut 537 538 sub execSQLStatements { 539 my ($driver, $externalPrograms, $dbOptions, @statements) = @_; 540 my %options = %$dbOptions; 541 542 my $exit_status; 543 544 if (lc $driver eq "mysql") { 545 my @commandLine = ( $externalPrograms->{mysql} ); 546 push @commandLine, "--host=$options{host}" if exists $options{host}; 547 push @commandLine, "--port=$options{port}" if exists $options{port}; 548 push @commandLine, "--user=$options{username}" if exists $options{username}; 549 push @commandLine, "--password=$options{password}" if exists $options{password}; 550 551 open my $mysql, "|@commandLine" 552 or die "execSQLStatements: failed to execute \"@commandLine\": $!\n"; 553 554 # exec sql statements 555 foreach my $stmt (@statements) { 556 debug("exec: $stmt"); 557 print $mysql "$stmt\n"; 558 } 559 560 close $mysql; 561 $exit_status = $?; 562 } 563 564 # add code to deal with other RDBMSs here: 565 # 566 #elsif (lc $driver eq "foobar") { 567 # # do something else 568 #} 569 570 else { 571 die "execSQLStatements: driver \"$driver\" is not supported.\n"; 572 } 573 574 # "...the exit value of the subprocess is in the high byte, that is, $? >> 575 # 8; in the low byte, $? & 127 says which signal (if any) the process died 576 # from, while $? & 128 reports whether its demise produced a core dump." 577 # -- Camel, 3rd ed 578 my $status = $exit_status >> 8; 579 #my $signal = $exit_status & 127; 580 #my $core = $exit_status & 128 581 582 # we want to return true for success and false for failure 583 debug("SQL console returned exit status $status.\n"); 584 return not $status; 585 } 586 587 =item protectQString($string) 588 589 Protects the contents of a single-quoted Perl string. 590 591 =cut 592 593 sub protectQString { 594 my ($string) = @_; 595 $string =~ s/'/\'/g; 596 return $string; 597 } 598 599 =item writeCourseConf($fh, $ce, %options) 600 601 Writes a course.conf file to $fh, a file handle, using defaults from the course 602 environment object $ce and overrides from %options. %options can contain any of 603 the pairs accepted in %courseOptions by addCourse(), above. 604 605 =cut 606 607 sub writeCourseConf { 608 my ($fh, $ce, %options) = @_; 609 610 # several options should be defined no matter what 611 $options{dbLayoutName} = $ce->{dbLayoutName} unless defined $options{dbLayoutName}; 612 $options{globalUserID} = $ce->{dbLayouts}->{gdbm}->{set}->{params}->{globalUserID} 613 unless defined $options{globalUserID}; 614 615 print $fh <<'EOF'; 616 #!perl 617 ################################################################################ 618 # WeBWorK Online Homework Delivery System 619 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 620 # 621 # This program is free software; you can redistribute it and/or modify it under 622 # the terms of either: (a) the GNU General Public License as published by the 623 # Free Software Foundation; either version 2, or (at your option) any later 624 # version, or (b) the "Artistic License" which comes with this package. 625 # 626 # This program is distributed in the hope that it will be useful, but WITHOUT 627 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 628 # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the 629 # Artistic License for more details. 630 ################################################################################ 631 632 # This file is used to override the global WeBWorK course environment for 633 # requests to this course. All package variables set in this file are added to 634 # the course environment. If you wish to set a variable here but omit it from 635 # the course environment, use the "my" keyword. Commonly changed configuration 636 # options are noted below. 637 638 EOF 639 640 print $fh <<'EOF'; 641 # Database Layout (global value typically defined in global.conf) 642 # 643 # Several database are defined in the file conf/database.conf and stored in the 644 # hash %dbLayouts. 645 # 646 # The database layout is always set here, since one should be able to change the 647 # default value in global.conf without disrupting existing courses. 648 # 649 # global.conf values: 650 EOF 651 652 print $fh "# \t", '$dbLayoutName = \'', protectQString($ce->{dbLayoutName}), '\';', "\n"; 653 print $fh "# \t", '*dbLayout = $dbLayouts{$dbLayoutName};', "\n"; 654 print $fh "\n"; 655 656 if (defined $options{dbLayoutName}) { 657 print $fh '$dbLayoutName = \'', protectQString($options{dbLayoutName}), '\';', "\n"; 658 print $fh '*dbLayout = $dbLayouts{$dbLayoutName};', "\n"; 659 print $fh "\n"; 660 } else { 661 print $fh "\n\n\n"; 662 } 663 664 print $fh <<'EOF'; 665 # Global User ID (global value typically defined in database.conf) 666 # 667 # The globalUserID parameter given for the set and problem tables denotes the ID 668 # of the user that the GlobalTableEmulator will use to store data for the set 669 # and problem tables. 670 # 671 # If a course will be used under WeBWorK 1.x, this value should be overridden on 672 # a course-by-course basis to the ID of the professor who is most likely to be 673 # involved in creating new problem sets. Sets which have not been assigned will 674 # only be visible to this user when logging into WeBWorK 1.x. 675 # 676 # The global user ID is always set here, since one should be able to change the 677 # default value in database.conf without disrupting existing courses. 678 # 679 # global.conf values: 680 EOF 681 682 print $fh "# \t", '$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = \'', 683 protectQString($ce->{dbLayouts}->{gdbm}->{set}->{params}->{globalUserID}), '\';', "\n"; 684 print $fh "# \t", '$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = \'', 685 protectQString($ce->{dbLayouts}->{gdbm}->{problem}->{params}->{globalUserID}), '\';', "\n"; 686 print $fh "\n"; 687 688 if (defined $options{globalUserID} or defined $options{globalUserID}) { 689 if (defined $options{globalUserID}) { 690 print $fh '$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = \'', 691 protectQString($options{globalUserID}), '\';', "\n"; 692 } 693 if (defined $options{globalUserID}) { 694 print $fh '$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = \'', 695 protectQString($options{globalUserID}), '\';', "\n"; 696 } 697 print $fh "\n"; 698 } else { 699 print $fh "\n\n\n"; 700 } 701 702 print $fh <<'EOF'; 703 # Allowed Mail Recipients (global value typically not defined) 704 # 705 # Defines addresses to which the PG system is allowed to send mail. This should 706 # probably be set to the addresses of professors of this course. Sending mail 707 # from the PG system (i.e. questionaires, essay questions) will fail if this is 708 # not set. 709 # 710 # global.conf values: 711 EOF 712 713 if (defined $ce->{mail}->{allowedRecipients}) { 714 print $fh "# \t", '$mail{allowedRecipients} = [', 715 join(", ", map { "'" . protectQString($_) . "'" } @{ $ce->{mail}->{allowedRecipients} }), '];', "\n"; 716 } else { 717 print $fh "# \t", '$mail{allowedRecipients} = [ ];', "\n"; 718 } 719 print $fh "\n"; 720 721 if (defined $options{allowedRecipients}) { 722 print $fh '$mail{allowedRecipients} = [', 723 join(", ", map { "'" . protectQString($_) . "'" } @{ $options{allowedRecipients} }), '];', "\n"; 724 print $fh "\n"; 725 } else { 726 print $fh "\n\n\n"; 727 } 728 729 print $fh <<'EOF'; 730 # Feedback Mail Recipients (global value typically not defined) 731 # 732 # Defines recipients for feedback mail. If not defined, mail is sent to all 733 # instructors and TAs. 734 # 735 # global.conf values: 736 EOF 737 738 if (defined $ce->{mail}->{feedbackRecipients}) { 739 print $fh "# \t", '$mail{feedbackRecipients} = [', 740 join(", ", map { "'" . protectQString($_) . "'" } @{ $ce->{mail}->{feedbackRecipients} }), '];', "\n"; 741 } else { 742 print $fh "# \t", '$mail{feedbackRecipients} = [ ];', "\n"; 743 } 744 print $fh "\n"; 745 746 if (defined $options{feedbackRecipients}) { 747 print $fh '$mail{feedbackRecipients} = [', 748 join(", ", map { "'" . protectQString($_) . "'" } @{ $options{feedbackRecipients} }), '];', "\n"; 749 print $fh "\n"; 750 } else { 751 print $fh "\n\n\n"; 752 } 753 754 print $fh <<'EOF'; 755 # Users for whom to label problems with the PG file name (global value typically "professor") 756 # 757 # For users in this list, PG will display the source file name when rendering a problem. 758 # 759 # global.conf values: 760 EOF 761 762 if (defined $ce->{pg}{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR}) { 763 print $fh "# \t", '$pg{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR} = [', 764 join(", ", map { "'" . protectQString($_) . "'" } @{ $ce->{pg}{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR} }), '];', "\n"; 765 } else { 766 print $fh "# \t", '$pg{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR} = [ ];', "\n"; 767 } 768 print $fh "\n"; 769 770 if (defined $options{PRINT_FILE_NAMES_FOR}) { 771 print $fh '$pg{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR} = [', 772 join(", ", map { "'" . protectQString($_) . "'" } @{ $options{PRINT_FILE_NAMES_FOR} }), '];', "\n"; 773 print $fh "\n"; 774 } else { 775 print $fh "\n\n\n"; 776 } 777 } 778 779 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |