Parent Directory
|
Revision Log
now uses CoureManagement backend
1 #!/usr/bin/env perl 2 ################################################################################ 3 # WeBWorK Online Homework Delivery System 4 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 5 # $CVSHeader: webwork-modperl/bin/addcourse,v 1.10 2004/03/19 21:54:45 sh002i Exp $ 6 # 7 # This program is free software; you can redistribute it and/or modify it under 8 # the terms of either: (a) the GNU General Public License as published by the 9 # Free Software Foundation; either version 2, or (at your option) any later 10 # version, or (b) the "Artistic License" which comes with this package. 11 # 12 # This program is distributed in the hope that it will be useful, but WITHOUT 13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the 15 # Artistic License for more details. 16 ################################################################################ 17 18 =head1 NAME 19 20 addcourse - add a course 21 22 =head1 SYNOPSIS 23 24 addcourse [options] COURSEID 25 26 =head1 DESCRIPTION 27 28 Add a course to the courses directory. The required directories will be 29 created. Optionally, a database can be populated with users and the 30 F<templates> directory can be populated with the contents of another directory. 31 Also, one or more users can be granted professor privileges. 32 33 =head1 OPTIONS 34 35 =over 36 37 =item B<--db-layout>=I<LAYOUT> 38 39 The specified database layout will be used in place of the default specified in 40 F<global.conf>. 41 42 If B<--db-layout> is set to C<gdbm>, the following options are valid: 43 44 =over 45 46 =item B<--global-user>=I<USERID> 47 48 Specifies that the user ID of the global user will be I<USERID>, overriding the 49 value set in F<database.conf>. Applicable only to courses using the C<gdbm> 50 database layout. 51 52 =back 53 54 If B<--db-layout> is set to C<sql>, the following options are valid: 55 56 =over 57 58 =item B<--sql-host>=I<HOST> 59 60 Specifies the hostname of the SQL server on which to create the course database. 61 If not specified, the default for your RDBMS will be used. 62 63 =item B<--sql-port>=I<PORT> 64 65 Specifies the port of the SQL server on which to create the course database. If 66 not specified, the default for your RDBMS will be used. 67 68 =item B<--sql-user>=I<USER> 69 70 Specifies the username to use when connecting to the SQL server to create the 71 course database. This user must have CREATE, DELETE, FILE, INSERT, SELECT, and 72 UPDATE privileges, WITH GRANT OPTION. 73 74 =item B<--sql-pass>=I<PASS> 75 76 Specifies the password to use when connecting to the SQL server. 77 78 =item B<--sql-db>=I<DBNAME> 79 80 Specifies the name of the database to create. (This is usually 81 "webwork_COURSENAME", but can be overridden by changing the database layout in 82 F<global.conf>.) 83 84 =item B<--sql-wwhost>=I<WWHOST> 85 86 Specifies the host from which the webwork database users will be allowed to 87 connect. (if B<--sql-host> is set to localhost, this should be set to localhost 88 too.) 89 90 =back 91 92 =item B<--users>=I<FILE> 93 94 The users listed in the comma-separated text file I<FILE> will be added to the 95 user list of the new course. The format of this file is the same as user lists 96 exported from WeBWorK. 97 98 =item B<--professors>=I<USERID>[,I<USERID>]... 99 100 Each I<USERID>, if it is present in the new course's user list, will be granted 101 professor privileges (i.e. a permission level of 10). Requires B<--users>. 102 103 =item I<COURSEID> 104 105 The name of the course to create. 106 107 =back 108 109 =cut 110 111 BEGIN { 112 # hide arguments (there could be passwords there!) 113 $0 = "$0"; 114 } 115 116 use strict; 117 use warnings; 118 use Getopt::Long; 119 120 BEGIN { 121 die "WEBWORK_ROOT not found in environment.\n" 122 unless exists $ENV{WEBWORK_ROOT}; 123 } 124 125 use lib "$ENV{WEBWORK_ROOT}/lib"; 126 use WeBWorK::CourseEnvironment; 127 use WeBWorK::DB; 128 use WeBWorK::Utils qw(runtime_use readFile cryptPassword); 129 use WeBWorK::Utils::CourseManagement qw(addCourse deleteCourse listCourses); 130 131 sub usage { 132 print STDERR "usage: $0 [options] COURSEID\n"; 133 print STDERR "Options:\n"; 134 print STDERR " [--db-layout=LAYOUT]\n"; 135 print STDERR " for \"sql\" database layout:\n"; 136 print STDERR " [--sql-host=HOST] [--sql-port=port]\n"; 137 print STDERR " --sql-user=USER --sql-pass=PASS\n"; 138 print STDERR " --sql-db=DBNAME --sql-wwhost=WWHOST\n"; 139 print STDERR " for \"gdbm\" database layout:\n"; 140 print STDERR " [--global-user=USERID]\n"; 141 print STDERR " [--users=FILE [--professors=USERID[,USERID]...] ]\n"; 142 exit; 143 } 144 145 sub usage_error { 146 print STDERR "$0: @_\n"; 147 usage(); 148 } 149 150 my $dbLayout = ""; 151 my $sql_host = ""; 152 my $sql_port = ""; 153 my $sql_user = ""; 154 my $sql_pass = ""; 155 my $sql_db = ""; 156 my $sql_wwhost = ""; 157 my $globalUserID = ""; 158 my $users = ""; 159 my @professors = (); 160 my $templates = ""; 161 162 ##### get command-line options ##### 163 164 GetOptions( 165 "db-layout=s" => \$dbLayout, 166 "sql-host=s" => \$sql_host, 167 "sql-port=s" => \$sql_port, 168 "sql-user=s" => \$sql_user, 169 "sql-pass=s" => \$sql_pass, 170 "sql-db=s" => \$sql_db, 171 "sql-wwhost=s" => \$sql_wwhost, 172 "global-user=s" => \$globalUserID, 173 "users=s" => \$users, 174 "professors=s" => \@professors, 175 "templates=s" => \$templates, 176 ); 177 my %professors = map { $_ => 1 } map { split /,/ } @professors; 178 my $courseID = shift; 179 180 ##### perform sanity checks ##### 181 182 usage_error("must specify COURSEID.") unless $courseID; 183 184 # bring up a minimal course environment 185 my $ce = WeBWorK::CourseEnvironment->new($ENV{WEBWORK_ROOT}, "FAKE_URL_ROOT", 186 "FAKE_PG_ROOT", $courseID); 187 188 if ($dbLayout) { 189 die "Database layout $dbLayout does not exist in the course environment.", 190 " (It must be defined in global.conf.)\n" 191 unless exists $ce->{dbLayouts}->{$dbLayout}; 192 } else { 193 # use default value 194 $dbLayout = $ce->{dbLayoutName}; 195 } 196 197 if ($dbLayout eq "sql") { 198 usage_error("must specify --sql-user.") unless $sql_user; 199 usage_error("must specify --sql-pass.") unless $sql_pass; 200 usage_error("must specify --sql-db.") unless $sql_db; 201 usage_error("must specify --sql-wwhost.") unless $sql_wwhost; 202 } elsif ($dbLayout eq "gdbm") { 203 # no required params, apparently... 204 } 205 206 usage_error("can't specify --professors without also specifying --users.") 207 if @professors and not $users; 208 209 ##### set up parameters to pass to addCourse() ##### 210 211 my %courseOptions = ( dbLayoutName => $dbLayout ); 212 if ($dbLayout eq "gdbm") { 213 $courseOptions{globalUserID} = $globalUserID if $globalUserID ne ""; 214 } 215 216 my %dbOptions; 217 if ($dbLayout eq "sql") { 218 $dbOptions{host} = $sql_host if $sql_host ne ""; 219 $dbOptions{port} = $sql_port if $sql_port ne ""; 220 $dbOptions{username} = $sql_user; 221 $dbOptions{password} = $sql_pass; 222 $dbOptions{database} = $sql_db; 223 $dbOptions{wwhost} = $sql_wwhost; 224 } 225 226 my @users; 227 if ($users) { 228 # this is a hack to create records without bringing up a DB object 229 #my $db = WeBWorK::DB->new($ce->{dbLayouts}->{$dbLayout}); 230 my $userClass = $ce->{dbLayouts}->{$dbLayout}->{user}->{record}; 231 my $passwordClass = $ce->{dbLayouts}->{$dbLayout}->{password}->{record}; 232 my $permissionClass = $ce->{dbLayouts}->{$dbLayout}->{permission}->{record}; 233 234 runtime_use($userClass); 235 runtime_use($passwordClass); 236 runtime_use($permissionClass); 237 238 my @contents = split /\n/, readFile($users); 239 240 # much of this code is burgled from UserList.pm 241 foreach my $string (@contents) { 242 $string =~ s/^\s+//; 243 $string =~ s/\s+$//; 244 my ( 245 $student_id, $last_name, $first_name, $status, $comment, 246 $section, $recitation, $email_address, $user_id 247 ) = split /\s*,\s*/, $string; 248 249 my $User = $userClass->new(); 250 $User->user_id($user_id); 251 $User->first_name($first_name); 252 $User->last_name($last_name); 253 $User->email_address($email_address); 254 $User->student_id($student_id); 255 $User->status($status); 256 $User->section($section); 257 $User->recitation($recitation); 258 $User->comment($comment); 259 260 my $Password = $passwordClass->new; 261 $Password->user_id($user_id); 262 $Password->password(cryptPassword($student_id)); 263 264 my $PermissionLevel = $permissionClass->new; 265 $PermissionLevel->user_id($user_id); 266 if (exists $professors{$user_id}) { 267 $PermissionLevel->permission(10); 268 delete $professors{$user_id}; 269 } else { 270 $PermissionLevel->permission(0); 271 } 272 273 push @users, [ $User, $Password, $PermissionLevel ]; 274 } 275 276 if (my @ids = keys %professors) { 277 print STDERR "warning: @ids not in imported user list.\n"; 278 } 279 } 280 281 ##### call addCourse(), handle errors ##### 282 283 eval { 284 addCourse( 285 courseID => $courseID, 286 ce => $ce, 287 courseOptions => \%courseOptions, 288 dbOptions => \%dbOptions, 289 users => \@users, 290 ); 291 }; 292 293 if ($@) { 294 my $error = $@; 295 print STDERR "$error\n"; 296 exit; 297 } 298 299 __END__ 300 301 if ($templates) { 302 unless (-d "$courseDir/templates") { 303 warn "$courseDir/templates: not found, creating:\n"; 304 print "mkdir $courseDir/templates\n"; 305 mkdir "$courseDir/templates" 306 or die "Failed to mkdir $courseDir/templates: $!\n"; 307 } 308 print "copy $templates/* -> $courseDir/templates\n"; 309 system "/bin/cp -r $templates/* $courseDir/templates/" 310 and die "Failed to copy $templates/* to $courseDir/templates: $!\n"; 311 } 312 313 if ($users) { 314 # import users - much of this code is burgled from UserList.pm 315 316 my $db; 317 if ($dbLayout) { 318 # use the specified layout 319 $db = WeBWorK::DB->new($ce->{dbLayouts}->{$dbLayout}); 320 } else { 321 # use the default layout 322 $db = WeBWorK::DB->new($ce->{dbLayout}); 323 } 324 325 my @contents = split /\n/, readFile($users); 326 327 my $globalUserPresent = 0; 328 329 foreach my $string (@contents) { 330 $string =~ s/^\s+//; 331 $string =~ s/\s+$//; 332 my ( 333 $student_id, $last_name, $first_name, $status, $comment, 334 $section, $recitation, $email_address, $user_id 335 ) = split /\s*,\s*/, $string; 336 337 my $User = $db->newUser; 338 $User->user_id($user_id); 339 $User->first_name($first_name); 340 $User->last_name($last_name); 341 $User->email_address($email_address); 342 $User->student_id($student_id); 343 $User->status($status); 344 $User->section($section); 345 $User->recitation($recitation); 346 $User->comment($comment); 347 348 my $PermissionLevel = $db->newPermissionLevel; 349 $PermissionLevel->user_id($user_id); 350 if (exists $professors{$user_id}) { 351 $PermissionLevel->permission(10); 352 } else { 353 $PermissionLevel->permission(0); 354 } 355 356 my $Password = $db->newPassword; 357 $Password->user_id($user_id); 358 $Password->password(cryptPassword($student_id)); 359 360 $db->addUser($User); 361 $db->addPermissionLevel($PermissionLevel); 362 $db->addPassword($Password); 363 364 if ($user_id eq $globalUserID) { 365 $globalUserPresent = 1; 366 } 367 368 if (exists $professors{$user_id}) { 369 print "add professor $user_id\n"; 370 delete $professors{$user_id}; 371 } else { 372 print "add user $user_id\n"; 373 } 374 } 375 376 if (my @ids = keys %professors) { 377 print STDERR "warning: @ids not in imported user list.\n"; 378 } 379 380 unless ($globalUserPresent) { 381 warn "warning: global user $globalUserID not in imported user list.\n", 382 " please add a user with this user ID manually.\n"; 383 } 384 } 385 386 my $courseEnvFile = $ce->{courseFiles}->{environment}; 387 print "writing $courseEnvFile... "; 388 open my $fh, ">", $courseEnvFile 389 or die "failed to open $courseEnvFile for writing.\n"; 390 391 print $fh <<EOF; 392 #!perl 393 ################################################################################ 394 # WeBWorK Online Homework Delivery System 395 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 396 # 397 # This program is free software; you can redistribute it and/or modify it under 398 # the terms of either: (a) the GNU General Public License as published by the 399 # Free Software Foundation; either version 2, or (at your option) any later 400 # version, or (b) the "Artistic License" which comes with this package. 401 # 402 # This program is distributed in the hope that it will be useful, but WITHOUT 403 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 404 # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the 405 # Artistic License for more details. 406 ################################################################################ 407 408 # This file is used to override the global WeBWorK course environment for 409 # requests to this course. All package variables set in this file are added to 410 # the course environment. If you wish to set a variable here but omit it from 411 # the course environment, use the "my" keyword. Commonly changed configuration 412 # options are noted below. The commented-out values are the values which were 413 # set in the global configuration file at the time this course was created. 414 415 EOF 416 417 print $fh <<EOF; 418 # Database layout -- if this course uses a different database layout than the 419 # one defined in the global configuration file, set it here. 420 # 421 # Example: \$dbLayoutName = "sql"; 422 # \*dbLayout = \$dbLayouts{sql}; 423 # 424 EOF 425 426 if ($dbLayout) { 427 print $fh "\$dbLayoutName = '$dbLayout';\n"; 428 print $fh "\*dbLayout = \$dbLayouts{$dbLayout};\n"; 429 } else { 430 my $defaultLayoutName = $ce->{dbLayoutName}; 431 if ($defaultLayoutName) { 432 print $fh "#\$dbLayoutName = '$defaultLayoutName';\n"; 433 print $fh "#\*dbLayout = \$dbLayouts{\$dbLayoutName};\n"; 434 } else { 435 print $fh "#\$dbLayoutName = '#NOT#FOUND#';\n"; 436 print $fh "#\*dbLayout = \$dbLayouts#NOT#FOUND#;\n"; 437 warn "default database layout name (\$dbLayoutName) not found in course environment.\n"; 438 } 439 } 440 441 print $fh <<EOF; 442 443 # Global user ID - denotes the ID of the user that the GlobalTableEmulator will 444 # use to store data for the set and problem tables. only applicable when using 445 # the GDBM database layout. 446 # 447 # Example: \$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = 'some_user'; 448 # \$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = 'some_user'; 449 # 450 EOF 451 452 if ($globalUserID) { 453 print $fh "\$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = '$globalUserID';\n"; 454 print $fh "\$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = '$globalUserID';\n"; 455 } else { 456 my $defaultGlobalUserID = $ce->{dbLayouts}->{gdbm}->{set}->{params}->{globalUserID}; 457 if (defined $defaultGlobalUserID) { 458 print $fh "#\$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = '$defaultGlobalUserID';\n"; 459 print $fh "#\$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = '$defaultGlobalUserID';\n"; 460 } else { 461 print $fh "#\$dbLayouts{gdbm}->{set}->{params}->{globalUserID} = '#NOT#FOUND#';\n"; 462 print $fh "#\$dbLayouts{gdbm}->{problem}->{params}->{globalUserID} = '#NOT#FOUND#';\n"; 463 warn "default GDBM global user ID not found in course environment.\n"; 464 } 465 } 466 467 print $fh <<EOF; 468 469 # Allowed mail recipients - list of email addresses that the PG system is 470 # allowed to send mail to. (This prevents subtle PG exploits.) If this is not 471 # set somewhere, mail from the PG system (i.e. questionaires, essay questions) 472 # will fail. 473 # 474 # Example: \$mail{allowedRecipients} = [ 'gage\@math.rochester.edu', 'apizer\@math.rochester.edu' ]; 475 # 476 EOF 477 478 if (defined $ce->{mail}->{allowedRecipients}) { 479 my $value = join ", ", map { "'$_'" } @{ $ce->{mail}->{allowedRecipients} }; 480 print $fh "#\$mail{allowedRecipients} = [ $value ];\n"; 481 } else { 482 print $fh "#\$mail{allowedRecipients} = [ ];\n"; 483 } 484 485 print $fh <<EOF; 486 487 # Feedback recipients - list of email addresses to send feedback to. If not 488 # defined, mail is sent to all professors and TAs. 489 # 490 # Example: \$mail{feedbackRecipients} = [ 'gage\@math.rochester.edu', 'apizer\@math.rochester.edu', 'feedback-list\@lists.webwork.rochester.edu' ]; 491 # 492 EOF 493 494 if (defined $ce->{mail}->{feedbackRecipients}) { 495 my $value = join ", ", map { "'$_'" } @{ $ce->{mail}->{feedbackRecipients} }; 496 print $fh "#\$mail{feedbackRecipients} = [ $value ];\n"; 497 } else { 498 print $fh "#\$mail{feedbackRecipients} = [ ];\n"; 499 } 500 501 print $fh <<EOF; 502 503 # Special PG environment variable: PRINT_FILE_NAMES_FOR - List the user IDs of 504 # users who should get PG source file names in their rendered problems. This is 505 # usually set to the list of professors and TAs in the course. 506 # 507 # Example: \$pg{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR} = [ 'gage', 'apizer', 'voloshin' ]; 508 # 509 EOF 510 511 if (defined $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}) { 512 my $value = join ", ", map { "'$_'" } 513 @{ $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR} }; 514 print $fh "#\$pg{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR} = [ $value ];\n"; 515 } else { 516 print $fh "#\$pg{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR} = [ ];\n"; 517 } 518 519 close $fh; 520 print "done.\n"; 521 522 =head1 BUGS 523 524 Some database drivers are unable to create storage for their data. The GDBM 525 backend can do this, but the SQL backend cannot (currently). If you wish to 526 create a course using the SQL database layout, you must create a 527 528 =head1 AUTHOR 529 530 Written by Sam Hathaway, hathaway at users.sourceforge.net. 531 532 =cut
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |