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

Diff of /trunk/webwork2/bin/addcourse

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1698  
changed lines
  Added in v.2118

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9