[system] / trunk / webwork2 / bin / addcourse Repository:
ViewVC logotype

View of /trunk/webwork2/bin/addcourse

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2006 - (download) (annotate)
Wed May 5 22:02:50 2004 UTC (9 years ago) by sh002i
File size: 16470 byte(s)
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