[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / CourseAdmin.pm Repository:
ViewVC logotype

Diff of /trunk/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm

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

Revision 1945 Revision 2043
1################################################################################ 1################################################################################
2# WeBWorK Online Homework Delivery System 2# WeBWorK Online Homework Delivery System
3# Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ 3# Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4# $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Skeleton.pm,v 1.2 2004/03/15 21:13:06 sh002i Exp $ 4# $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v 1.7 2004/05/07 22:26:49 gage Exp $
5# 5#
6# This program is free software; you can redistribute it and/or modify it under 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 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 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. 9# version, or (b) the "Artistic License" which comes with this package.
25 25
26use strict; 26use strict;
27use warnings; 27use warnings;
28use CGI::Pretty qw(); 28use CGI::Pretty qw();
29use Data::Dumper; 29use Data::Dumper;
30use File::Temp qw/tempfile/;
30use WeBWorK::Utils qw(cryptPassword); 31use WeBWorK::Utils qw(cryptPassword);
31use WeBWorK::Utils::CourseManagement qw(addCourse); 32use WeBWorK::Utils::CourseManagement qw(addCourse deleteCourse listCourses);
33use WeBWorK::Utils::DBImportExport qw(dbExport dbImport);
32 34
33# SKEL: If you need to do any processing before the HTTP header is sent, do it
34# in this method:
35#
36#sub pre_header_initialize { 35sub pre_header_initialize {
37# my ($self) = @_;
38#
39# # Do your processing here! Don't print or return anything -- store data in
40# # the self hash for later retrieveal.
41#}
42
43# SKEL: To emit your own HTTP header, uncomment this:
44#
45#sub header {
46# my ($self) = @_;
47#
48# # Generate your HTTP header here.
49#
50# # If you return something, it will be used as the HTTP status code for this
51# # request. The Apache::Constants module might be useful for gerating status
52# # codes. If you don't return anything, the status code "OK" will be used.
53# return "";
54#}
55
56# SKEL: If you need to do any processing after the HTTP header is sent, but before
57# any template processing occurs, or you need to calculate values that will be
58# used in multiple methods, do it in this method:
59#
60#sub initialize {
61# my ($self) = @_;
62#
63# # Do your processing here! Don't print or return anything -- store data in
64# # the self hash for later retrieveal.
65#}
66
67# SKEL: If you need to add tags to the document <HEAD>, uncomment this method:
68#
69#sub head {
70# my ($self) = @_;
71#
72# # You can print head tags here, like <META>, <SCRIPT>, etc.
73#
74# return "";
75#}
76
77# SKEL: To fill in the "info" box (to the right of the main body), use this
78# method:
79#
80#sub info {
81# my ($self) = @_;
82#
83# # Print HTML here.
84#
85# return "";
86#}
87
88# SKEL: To provide navigation links, use this method:
89#
90#sub nav {
91# my ($self, $args) = @_;
92#
93# # See the documentation of path() and pathMacro() in
94# # WeBWorK::ContentGenerator for more information.
95#
96# return "";
97#}
98
99# SKEL: For a little box for display options, etc., use this method:
100#
101#sub options {
102# my ($self) = @_;
103#
104# # Print HTML here.
105#
106# return "";
107#}
108
109# SKEL: For a list of sibling objects, use this method:
110#
111#sub siblings {
112# my ($self, $args) = @_;
113#
114# # See the documentation of siblings() and siblingsMacro() in
115# # WeBWorK::ContentGenerator for more information.
116# #
117# # Refer to implementations in ProblemSet and Problem.
118#
119# return "";
120#}
121
122# SKEL: Okay, here's the body. Most of your stuff will go here:
123#
124sub body {
125 my ($self) = @_; 36 my ($self) = @_;
126 my $r = $self->r; 37 my $r = $self->r;
127 my $ce = $r->ce; 38 my $ce = $r->ce;
128 my $db = $r->db; 39 my $db = $r->db;
129 my $authz = $r->authz; 40 my $authz = $r->authz;
130 my $urlpath = $r->urlpath; 41 my $urlpath = $r->urlpath;
42 my $user = $r->param('user');
131 43
132 print CGI::h2("Create a new course"); 44 # check permissions
133 45 unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
134 my $add_step_max = 4; # the step that actually creates the course 46 $self->addmessage( CGI::div({class=>'ResultsWithError'},"$user is not authorized to create or delete courses") );
135 47 return;
136 my $add_step = $r->param("add_step") || 0; 48 }
137 49
50 if (defined $r->param("download_exported_database")) {
138 my $new_courseID = $r->param("new_courseID"); 51 my $courseID = $r->param("export_courseID");
139 my $new_dbLayout = $r->param("new_dbLayout"); 52 my $random_chars = $r->param("download_exported_database");
140 my $new_skipDBCreation = $r->param("new_skipDBCreation"); 53
141 my $new_sql_host = $r->param("new_sql_host"); 54 die "courseID not specified" unless defined $courseID;
142 my $new_sql_port = $r->param("new_sql_port"); 55 die "invalid file specification" unless $random_chars =~ m/^\w+$/;
143 my $new_sql_username = $r->param("new_sql_username"); 56
144 my $new_sql_password = $r->param("new_sql_password"); 57 my $tempdir = $ce->{webworkDirs}->{tmp};
145 my $new_sql_database = $r->param("new_sql_database"); 58 my $export_file = "$tempdir/db_export_$random_chars";
146 my $new_sql_wwhost = $r->param("new_sql_wwhost"); 59
147 my $new_gdbm_globalUserID = $r->param("new_gdbm_globalUserID"); 60 $self->reply_with_file("text/xml", $export_file, "${courseID}_database.xml", 0);
148 my $new_initial_userID = $r->param("new_initial_userID");
149 my $new_initial_password = $r->param("new_initial_password");
150
151 # "back up" if certain fields aren't filled in
152
153 if ($add_step > 0) {
154 $add_step = 0 if $new_courseID eq "" or $new_dbLayout eq "";
155 } 61 }
62}
63
64sub body {
65 my ($self) = @_;
66 my $r = $self->r;
67 my $ce = $r->ce;
68 my $db = $r->db;
69 my $authz = $r->authz;
70 my $urlpath = $r->urlpath;
156 71
157 if ($add_step > 1 and not $new_skipDBCreation) { 72 my $user = $r->param('user');
158 if ($new_dbLayout eq "sql") { 73
159 $add_step = 1 if $new_sql_username eq "" or $new_sql_password eq "" 74 # check permissions
160 or $new_sql_database eq "" or $new_sql_wwhost eq ""; 75 unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
161 } elsif ($new_dbLayout eq "gdbm") { 76 return "";
162 $add_step = 1 if $new_gdbm_globalUserID eq ""; 77 }
78
79 print CGI::p({style=>"text-align: center"},
80 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"add_course"})}, "Add Course"),
81 #" | ",
82 #CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"rename_course"})}, "Rename Course"),
83 " | ",
84 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"delete_course"})}, "Delete Course"),
85 " | ",
86 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"export_database"})}, "Export Database"),
87 " | ",
88 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"import_database"})}, "Import Database"),
89 );
90
91 print CGI::hr();
92
93 my $subDisplay = $r->param("subDisplay");
94 if (defined $subDisplay) {
95
96 if ($subDisplay eq "add_course") {
97 if (defined $r->param("add_course")) {
98 my @errors = $self->add_course_validate;
99 if (@errors) {
100 print CGI::div({class=>"ResultsWithError"},
101 CGI::p("Please correct the following errors and try again:"),
102 CGI::ul(CGI::li(\@errors)),
103 );
104 $self->add_course_form;
105 } else {
106 $self->do_add_course;
107 }
108 } else {
109 $self->add_course_form;
110 }
163 } 111 }
112
113 elsif ($subDisplay eq "delete_course") {
114 if (defined $r->param("delete_course")) {
115 # validate or confirm
116 my @errors = $self->delete_course_validate;
117 if (@errors) {
118 print CGI::div({class=>"ResultsWithError"},
119 CGI::p("Please correct the following errors and try again:"),
120 CGI::ul(CGI::li(\@errors)),
121 );
122 $self->delete_course_form;
123 } else {
124 $self->delete_course_confirm;
125 }
126 } elsif (defined $r->param("confirm_delete_course")) {
127 # validate and delete
128 my @errors = $self->delete_course_validate;
129 if (@errors) {
130 print CGI::div({class=>"ResultsWithError"},
131 CGI::p("Please correct the following errors and try again:"),
132 CGI::ul(CGI::li(\@errors)),
133 );
134 $self->delete_course_form;
135 } else {
136 $self->do_delete_course;
137 }
138 } else {
139 # form only
140 $self->delete_course_form;
141 }
164 } 142 }
165 143
166 if ($add_step > 2) { 144 elsif ($subDisplay eq "export_database") {
167 $add_step = 2 if $new_initial_userID ne "" and $new_initial_password eq ""; 145 if (defined $r->param("export_database")) {
146 my @errors = $self->export_database_validate;
147 if (@errors) {
148 print CGI::div({class=>"ResultsWithError"},
149 CGI::p("Please correct the following errors and try again:"),
150 CGI::ul(CGI::li(\@errors)),
151 );
152 $self->export_database_form;
153 } else {
154 $self->do_export_database;
155 }
156 } else {
157 $self->export_database_form;
158 }
168 } 159 }
160
161 elsif ($subDisplay eq "import_database") {
162 if (defined $r->param("import_database")) {
163 my @errors = $self->import_database_validate;
164 if (@errors) {
165 print CGI::div({class=>"ResultsWithError"},
166 CGI::p("Please correct the following errors and try again:"),
167 CGI::ul(CGI::li(\@errors)),
168 );
169 $self->import_database_form;
170 } else {
171 $self->do_import_database;
172 }
173 } else {
174 $self->import_database_form;
175 }
176 }
177
178 else {
179 print CGI::div({class=>"ResultsWithError"},
180 "Unrecognized sub-display @{[ CGI::b($subDisplay) ]}.");
181 }
182
183 }
169 184
170 my $ce2; 185 return "";
171 if ($new_courseID) { 186}
187
188################################################################################
189
190sub add_course_form {
191 my ($self) = @_;
192 my $r = $self->r;
193 my $ce = $r->ce;
194 #my $db = $r->db;
195 #my $authz = $r->authz;
196 #my $urlpath = $r->urlpath;
197
198 my $add_courseID = $r->param("add_courseID") || "";
199 my $add_dbLayout = $r->param("add_dbLayout") || "";
200 my $add_sql_host = $r->param("add_sql_host") || "";
201 my $add_sql_port = $r->param("add_sql_port") || "";
202 my $add_sql_username = $r->param("add_sql_username") || "";
203 my $add_sql_password = $r->param("add_sql_password") || "";
204 my $add_sql_database = $r->param("add_sql_database") || "";
205 my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
206 my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
207 my $add_initial_userID = $r->param("add_initial_userID") || "";
208 my $add_initial_password = $r->param("add_initial_password") || "";
209
210 my @dbLayouts = sort keys %{ $ce->{dbLayouts} };
211
172 $ce2 = WeBWorK::CourseEnvironment->new( 212 my $ce2 = WeBWorK::CourseEnvironment->new(
173 $ce->{webworkDirs}->{root}, 213 $ce->{webworkDirs}->{root},
174 $ce->{webworkURLs}->{root}, 214 $ce->{webworkURLs}->{root},
175 "FAKE_PG_ROOT", # heh, there's no way to get the PG root out... damn. 215 $ce->{pg}->{directories}->{root},
176 $new_courseID, 216 "COURSENAME",
177 ); 217 );
218
219 my $dbi_source = do {
220 # find the most common SQL source (stolen from CourseManagement.pm)
221 my %sources;
222 foreach my $table (keys %{ $ce2->{dbLayouts}->{sql} }) {
223 $sources{$ce2->{dbLayouts}->{sql}->{$table}->{source}}++;
178 } 224 }
225 my $source;
226 if (keys %sources > 1) {
227 foreach my $curr (keys %sources) {
228 $source = $curr if not defined $source or
229 $sources{$curr} > $sources{$source};
230 }
231 } else {
232 ($source) = keys %sources;
233 }
234 $source;
235 };
179 236
180 if ($add_step >= 0 and $add_step < $add_step_max) { 237 print CGI::h2("Add Course");
238
181 print CGI::start_form("POST", $r->uri); 239 print CGI::start_form("POST", $r->uri);
182 print $self->hidden_authen_fields; 240 print $self->hidden_authen_fields;
183 print CGI::hidden("add_step", 1); 241 print $self->hidden_fields("subDisplay");
242
243 print CGI::p("Specify a name for the new course.");
244
184 print CGI::table({class=>"FormLayout"}, 245 print CGI::table({class=>"FormLayout"},
185 CGI::Tr( 246 CGI::Tr(
186 CGI::th({class=>"LeftHeader"}, "Course Name:"), 247 CGI::th({class=>"LeftHeader"}, "Course Name:"),
187 CGI::td( 248 CGI::td(CGI::textfield("add_courseID", $add_courseID, 25)),
188 CGI::textfield(
189 -name => "new_courseID",
190 -value => defined $new_courseID ? $new_courseID : "",
191 -size => 50,
192 ),
193 ), 249 ),
250 );
251
252 print CGI::p("Select a database layout below. Some database layouts require additional information.");
253
254 #print CGI::start_Tr();
255 #print CGI::th({class=>"LeftHeader"}, "Database Layout:");
256 #print CGI::start_td();
257
258 foreach my $dbLayout (@dbLayouts) {
259 print CGI::start_table({class=>"FormLayout"});
260
261 # we generate singleton radio button tags ourselves because it's too much of a pain to do it with CGI.pm
262 print CGI::Tr(
263 CGI::td({style=>"text-align: right"},
264 '<input type="radio" name="add_dbLayout" value="' . $dbLayout . '"'
265 . ($add_dbLayout eq $dbLayout ? " checked" : "") . ' />',
194 ), 266 ),
195 CGI::Tr( 267 CGI::td($dbLayout),
196 CGI::th({class=>"LeftHeader"}, "Database Layout:"),
197 CGI::td(
198 CGI::popup_menu(
199 -name => "new_dbLayout",
200 -values => [ sort keys %{ $ce->{dbLayouts} } ],
201 -default => defined $new_dbLayout ? $new_dbLayout : "",
202 ),
203 ),
204 ),
205 CGI::Tr({class=>"ButtonRow"},
206 CGI::td({colspan=>2},
207 CGI::submit(
208 -name => "create_course",
209 -value => ($add_step > 0 ? "Change" : "Continue"),
210 ),
211 ),
212 ),
213 ); 268 );
214 print CGI::end_form(); 269
215 }
216
217 if ($add_step >= 1 and $add_step < $add_step_max) {
218 print CGI::hr(); 270 print CGI::start_Tr();
271 print CGI::td(); # for indentation :(
272 print CGI::start_td();
219 273
220 print CGI::start_form("POST", $r->uri);
221 print $self->hidden_authen_fields;
222 print CGI::hidden("add_step", 2);
223
224 print CGI::hidden("new_courseID", $new_courseID);
225 print CGI::hidden("new_dbLayout", $new_dbLayout);
226 print CGI::hidden("new_skipDBCreation", $new_skipDBCreation);
227
228 # there are specific things we're doing per database layout:
229 if ($new_dbLayout eq "sql") { 274 if ($dbLayout eq "sql") {
230 {
231 # find the most common SQL source (stolen from CourseManagement.pm)
232 my %sources;
233 foreach my $table (keys %{ $ce2->{dbLayouts}->{sql} }) {
234 $sources{$ce2->{dbLayouts}->{sql}->{$table}->{source}}++;
235 }
236 my $source;
237 if (keys %sources > 1) {
238 foreach my $curr (keys %sources) {
239 $source = $curr if @{ $sources{$curr} } > @{ $sources{$source} };
240 }
241 } else {
242 ($source) = keys %sources;
243 }
244
245 print CGI::p( 275 print CGI::p(
246 CGI::checkbox( 276 "The SQL settings you enter below must match the settings in the DBI source",
247 -name => "new_skipDBCreation", 277 " specification ", CGI::tt($dbi_source), ". Replace ", CGI::tt("COURSENAME"),
248 -checked => $new_skipDBCreation, 278 " with the course name you entered above."
249 -value => "1",
250 -label => "Skip database creation",
251 ),
252 CGI::br(),
253 "If this is selected, you need not fill in the SQL settings below. However, you must create the database manually before creating this course.",
254 ); 279 );
255
256 # print instructions
257 print CGI::p("The SQL settings you enter below must match the settings in this DBI source specification:");
258 print CGI::p({style=>"text-align:center"}, CGI::tt($source));
259 if (keys %sources > 1) {
260 print CGI::p("Note that there is more than one DBI source in this database layout. Only tables using the most common source (above) will be created.");
261 }
262 }
263
264 print CGI::start_table({class=>"FormLayout"}); 280 print CGI::start_table({class=>"FormLayout"});
265 print CGI::Tr( 281 print CGI::Tr(
266 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"), 282 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
267 CGI::td( 283 CGI::td(
268 CGI::textfield( 284 CGI::textfield("add_sql_host", $add_sql_host, 25),
269 -name => "new_sql_host",
270 -value => defined $new_sql_host ? $new_sql_host : "",
271 -size => 50,
272 ),
273 CGI::br(), 285 CGI::br(),
274 CGI::small("Leave blank to use the default host."), 286 CGI::small("Leave blank to use the default host."),
275 ), 287 ),
276 ); 288 );
277 print CGI::Tr( 289 print CGI::Tr(
278 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"), 290 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
279 CGI::td( 291 CGI::td(
280 CGI::textfield( 292 CGI::textfield("add_sql_port", $add_sql_port, 25),
281 -name => "new_sql_port",
282 -value => defined $new_sql_port ? $new_sql_port : "",
283 -size => 50,
284 ),
285 CGI::br(), 293 CGI::br(),
286 CGI::small("Leave blank to use the default port."), 294 CGI::small("Leave blank to use the default port."),
287 ), 295 ),
288 ); 296 );
289 print CGI::Tr( 297 print CGI::Tr(
290 CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"), 298 CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
291 CGI::td( 299 CGI::td(CGI::textfield("add_sql_username", $add_sql_username, 25)),
292 CGI::textfield(
293 -name => "new_sql_username",
294 -value => defined $new_sql_username ? $new_sql_username : "",
295 -size => 50,
296 ),
297 ),
298 ); 300 );
299 print CGI::Tr( 301 print CGI::Tr(
300 CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"), 302 CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
301 CGI::td( 303 CGI::td(CGI::password_field("add_sql_password", $add_sql_password, 25)),
302 CGI::password_field(
303 -name => "new_sql_password",
304 -value => defined $new_sql_password ? $new_sql_password : "",
305 -size => 50,
306 ),
307 ),
308 ); 304 );
309 print CGI::Tr( 305 print CGI::Tr(
310 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"), 306 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
311 CGI::td( 307 CGI::td(CGI::textfield("add_sql_database", $add_sql_database, 25)),
312 CGI::textfield(
313 -name => "new_sql_database",
314 -value => defined $new_sql_database ? $new_sql_database : "",
315 -size => 50,
316 ),
317 ),
318 ); 308 );
319 print CGI::Tr( 309 print CGI::Tr(
320 CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"), 310 CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"),
321 CGI::td( 311 CGI::td(
322 CGI::textfield( 312 CGI::textfield("add_sql_wwhost", $add_sql_wwhost || "localhost", 25),
323 -name => "new_sql_wwhost",
324 -value => defined $new_sql_wwhost ? $new_sql_wwhost : "localhost",
325 -size => 50,
326 ),
327 CGI::br(), 313 CGI::br(),
328 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."), 314 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."),
329 ), 315 ),
330 ); 316 );
317 print CGI::end_table();
331 } elsif ($new_dbLayout eq "gdbm") { 318 } elsif ($dbLayout eq "gdbm") {
332 print CGI::start_table({class=>"FormLayout"}); 319 print CGI::start_table({class=>"FormLayout"});
333 print CGI::Tr( 320 print CGI::Tr(
334 CGI::th({class=>"LeftHeader"}, "GDBM Global User ID:"), 321 CGI::th({class=>"LeftHeader"}, "GDBM Global User ID:"),
335 CGI::td( 322 CGI::td(CGI::textfield("add_gdbm_globalUserID", $add_gdbm_globalUserID || "global_user", 25)),
336 CGI::textfield(
337 -name => "new_gdbm_globalUserID",
338 -value => defined $new_gdbm_globalUserID ? $new_gdbm_globalUserID : "global_user",
339 -size => 50,
340 ),
341 ),
342 ); 323 );
324 print CGI::end_table();
343 } 325 }
344 326
327 print CGI::end_td();
328 print CGI::end_Tr();
329 print CGI::end_table();
330 }
331
332
333 print CGI::p("To add an initial user to the new course, enter a user ID and password below. If you do not do so, you will not be able to log into the course.");
334
335 print CGI::table({class=>"FormLayout"},
336 CGI::Tr(
337 CGI::th({class=>"LeftHeader"}, "Professor User ID:"),
338 CGI::td(CGI::textfield("add_initial_userID", $add_initial_userID || "professor", 25)),
339 ),
340 CGI::Tr(
341 CGI::th({class=>"LeftHeader"}, "Professor Password:"),
342 CGI::td(CGI::password_field("add_initial_password", $add_initial_password, 25)),
343 ),
344 );
345
346 print CGI::p({style=>"text-align: center"}, CGI::submit("add_course", "Add Course"));
347
348 print CGI::end_form();
349}
350
351sub add_course_validate {
352 my ($self) = @_;
353 my $r = $self->r;
354 my $ce = $r->ce;
355 #my $db = $r->db;
356 #my $authz = $r->authz;
357 #my $urlpath = $r->urlpath;
358
359 my $add_courseID = $r->param("add_courseID") || "";
360 my $add_dbLayout = $r->param("add_dbLayout") || "";
361 my $add_sql_host = $r->param("add_sql_host") || "";
362 my $add_sql_port = $r->param("add_sql_port") || "";
363 my $add_sql_username = $r->param("add_sql_username") || "";
364 my $add_sql_password = $r->param("add_sql_password") || "";
365 my $add_sql_database = $r->param("add_sql_database") || "";
366 my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
367 my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
368 my $add_initial_userID = $r->param("add_initial_userID") || "";
369 my $add_initial_password = $r->param("add_initial_password") || "";
370
371 my @errors;
372
373 if ($add_courseID eq "") {
374 push @errors, "You must specify a course name.";
375 }
376
377 if ($add_dbLayout eq "") {
378 push @errors, "You must select a database layout.";
379 } else {
380 if (exists $ce->{dbLayouts}->{$add_dbLayout}) {
381 if ($add_dbLayout eq "sql") {
382 push @errors, "You must specify the SQL admin username." if $add_sql_username eq "";
383 push @errors, "You must specify the SQL admin password." if $add_sql_password eq "";
384 push @errors, "You must specify the SQL confirm_delete_course." if $add_sql_database eq "";
385 push @errors, "You must specify the WeBWorK host." if $add_sql_wwhost eq "";
386 } elsif ($add_dbLayout eq "gdbm") {
387 push @errors, "You must specify the GDBM global user ID." if $add_gdbm_globalUserID eq "";
388 }
389 } else {
390 push @errors, "The database layout $add_dbLayout doesn't exist.";
345 391 }
346 print CGI::Tr({class=>"ButtonRow"}, 392 }
347 CGI::td({colspan=>2}, 393
348 CGI::submit( 394 if ($add_initial_userID ne "") {
395 push @errors, "You must specify a professor password." if $add_initial_password eq "";
396 }
397
398 return @errors;
399}
400
401sub do_add_course {
402 my ($self) = @_;
403 my $r = $self->r;
404 my $ce = $r->ce;
405 my $db = $r->db;
406 #my $authz = $r->authz;
407 my $urlpath = $r->urlpath;
408
409 my $add_courseID = $r->param("add_courseID") || "";
410 my $add_dbLayout = $r->param("add_dbLayout") || "";
411 my $add_sql_host = $r->param("add_sql_host") || "";
412 my $add_sql_port = $r->param("add_sql_port") || "";
413 my $add_sql_username = $r->param("add_sql_username") || "";
414 my $add_sql_password = $r->param("add_sql_password") || "";
415 my $add_sql_database = $r->param("add_sql_database") || "";
416 my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
417 my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
418 my $add_initial_userID = $r->param("add_initial_userID") || "";
419 my $add_initial_password = $r->param("add_initial_password") || "";
420
421 my $ce2 = WeBWorK::CourseEnvironment->new(
422 $ce->{webworkDirs}->{root},
423 $ce->{webworkURLs}->{root},
424 $ce->{pg}->{directories}->{root},
425 $add_courseID,
426 );
427
428 my %courseOptions = ( dbLayoutName => $add_dbLayout );
429 if ($add_dbLayout eq "gdbm") {
430 $courseOptions{globalUserID} = $add_gdbm_globalUserID if $add_gdbm_globalUserID ne "";
431 }
432
433 my %dbOptions;
434 if ($add_dbLayout eq "sql") {
435 $dbOptions{host} = $add_sql_host if $add_sql_host ne "";
436 $dbOptions{port} = $add_sql_port if $add_sql_port ne "";
437 $dbOptions{username} = $add_sql_username;
438 $dbOptions{password} = $add_sql_password;
439 $dbOptions{database} = $add_sql_database;
440 $dbOptions{wwhost} = $add_sql_wwhost;
441 }
442
443 my @users;
444 if ($add_initial_userID ne "") {
445 my $User = $db->newUser(
446 user_id => $add_initial_userID,
447 status => "C",
448 );
449 my $Password = $db->newPassword(
450 user_id => $add_initial_userID,
451 password => cryptPassword($add_initial_password),
452 );
453 my $PermissionLevel = $db->newPermissionLevel(
454 user_id => $add_initial_userID,
455 permission => "10",
456 );
457 push @users, [ $User, $Password, $PermissionLevel ];
458 }
459
460 eval {
461 addCourse(
462 courseID => $add_courseID,
463 ce => $ce2,
464 courseOptions => \%courseOptions,
465 dbOptions => \%dbOptions,
466 users => \@users,
467 );
468 };
469
470 if ($@) {
471 my $error = $@;
472 print CGI::div({class=>"ResultsWithError"},
473 CGI::p("An error occured while creating the course $add_courseID:"),
474 CGI::tt(CGI::escapeHTML($error)),
475 );
476 } else {
477 print CGI::div({class=>"ResultsWithoutError"},
478 CGI::p("Successfully created the course $add_courseID"),
479 );
480 my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
481 courseID => $add_courseID);
482 my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
483 print CGI::div({style=>"text-align: center"},
484 CGI::a({href=>$newCourseURL}, "Log into $add_courseID"),
485 );
486 }
487}
488
489################################################################################
490
491sub delete_course_form {
492 my ($self) = @_;
493 my $r = $self->r;
494 my $ce = $r->ce;
495 #my $db = $r->db;
496 #my $authz = $r->authz;
497 #my $urlpath = $r->urlpath;
498
499 my $delete_courseID = $r->param("delete_courseID") || "";
500 my $delete_sql_host = $r->param("delete_sql_host") || "";
501 my $delete_sql_port = $r->param("delete_sql_port") || "";
502 my $delete_sql_username = $r->param("delete_sql_username") || "";
503 my $delete_sql_password = $r->param("delete_sql_password") || "";
504 my $delete_sql_database = $r->param("delete_sql_database") || "";
505
506 my @courseIDs = listCourses($ce);
507
508 my %courseLabels; # records... heh.
509 foreach my $courseID (@courseIDs) {
510 my $tempCE = WeBWorK::CourseEnvironment->new(
511 $ce->{webworkDirs}->{root},
512 $ce->{webworkURLs}->{root},
513 $ce->{pg}->{directories}->{root},
514 $courseID,
515 );
516 $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
517 }
518
519 print CGI::h2("Delete Course");
520
521 print CGI::start_form("POST", $r->uri);
522 print $self->hidden_authen_fields;
523 print $self->hidden_fields("subDisplay");
524
525 print CGI::p("Select a course to delete.");
526
527 print CGI::table({class=>"FormLayout"},
528 CGI::Tr(
529 CGI::th({class=>"LeftHeader"}, "Course Name:"),
530 CGI::td(
531 CGI::scrolling_list(
349 -name => "add_course", 532 -name => "delete_courseID",
350 -value => ($add_step > 1 ? "Change" : "Continue"), 533 -values => \@courseIDs,
534 -default => $delete_courseID,
535 -size => 10,
536 -multiple => 0,
537 -labels => \%courseLabels,
351 ), 538 ),
352 ), 539 ),
540 ),
353 ); 541 );
542
543 print CGI::p(
544 "If the course's database layout (indicated in parentheses above) is "
545 . CGI::b("sql") . ", supply the SQL connections information requested below."
546 );
547
548 print CGI::start_table({class=>"FormLayout"});
549 print CGI::Tr(
550 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
551 CGI::td(
552 CGI::textfield("delete_sql_host", $delete_sql_host, 25),
553 CGI::br(),
554 CGI::small("Leave blank to use the default host."),
555 ),
556 );
557 print CGI::Tr(
558 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
559 CGI::td(
560 CGI::textfield("delete_sql_port", $delete_sql_port, 25),
561 CGI::br(),
562 CGI::small("Leave blank to use the default port."),
563 ),
564 );
565 print CGI::Tr(
566 CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
567 CGI::td(CGI::textfield("delete_sql_username", $delete_sql_username, 25)),
568 );
569 print CGI::Tr(
570 CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
571 CGI::td(CGI::password_field("delete_sql_password", $delete_sql_password, 25)),
572 );
573 print CGI::Tr(
574 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
575 CGI::td(CGI::textfield("delete_sql_database", $delete_sql_database, 25)),
576 );
354 print CGI::end_table(); 577 print CGI::end_table();
578
579 print CGI::p({style=>"text-align: center"}, CGI::submit("delete_course", "Delete Course"));
580
355 print CGI::end_form(); 581 print CGI::end_form();
582}
583
584sub delete_course_validate {
585 my ($self) = @_;
586 my $r = $self->r;
587 my $ce = $r->ce;
588 #my $db = $r->db;
589 #my $authz = $r->authz;
590 my $urlpath = $r->urlpath;
591
592 my $delete_courseID = $r->param("delete_courseID") || "";
593 my $delete_sql_host = $r->param("delete_sql_host") || "";
594 my $delete_sql_port = $r->param("delete_sql_port") || "";
595 my $delete_sql_username = $r->param("delete_sql_username") || "";
596 my $delete_sql_password = $r->param("delete_sql_password") || "";
597 my $delete_sql_database = $r->param("delete_sql_database") || "";
598
599 my @errors;
600
601 if ($delete_courseID eq "") {
602 push @errors, "You must specify a course name.";
603 } elsif ($delete_courseID eq $urlpath->arg("courseID")) {
604 push @errors, "You cannot delete the course you are currently using.";
605 }
606
607 my $ce2 = WeBWorK::CourseEnvironment->new(
608 $ce->{webworkDirs}->{root},
609 $ce->{webworkURLs}->{root},
610 $ce->{pg}->{directories}->{root},
611 $delete_courseID,
612 );
613
614 if ($ce2->{dbLayoutName} eq "sql") {
615 push @errors, "You must specify the SQL admin username." if $delete_sql_username eq "";
616 push @errors, "You must specify the SQL admin password." if $delete_sql_password eq "";
617 push @errors, "You must specify the SQL database name." if $delete_sql_database eq "";
618 }
619
620 return @errors;
621}
622
623sub delete_course_confirm {
624 my ($self) = @_;
625 my $r = $self->r;
626 my $ce = $r->ce;
627 #my $db = $r->db;
628 #my $authz = $r->authz;
629 #my $urlpath = $r->urlpath;
630
631 print CGI::h2("Delete Course");
632
633 my $delete_courseID = $r->param("delete_courseID") || "";
634 my $delete_sql_host = $r->param("delete_sql_host") || "";
635 my $delete_sql_port = $r->param("delete_sql_port") || "";
636 my $delete_sql_database = $r->param("delete_sql_database") || "";
637
638 my $ce2 = WeBWorK::CourseEnvironment->new(
639 $ce->{webworkDirs}->{root},
640 $ce->{webworkURLs}->{root},
641 $ce->{pg}->{directories}->{root},
642 $delete_courseID,
643 );
644
645 if ($ce2->{dbLayoutName} eq "sql") {
646 print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
647 . "? All course files and data and the following database will be destroyed."
648 . " There is no undo available.");
649
650 print CGI::table({class=>"FormLayout"},
651 CGI::Tr(
652 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
653 CGI::td($delete_sql_host || "system default"),
654 ),
655 CGI::Tr(
656 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
657 CGI::td($delete_sql_port || "system default"),
658 ),
659 CGI::Tr(
660 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
661 CGI::td($delete_sql_database),
662 ),
663 );
664 } else {
665 print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
666 . "? All course files and data will be destroyed. There is no undo available.");
667 }
668
669 print CGI::start_form("POST", $r->uri);
670 print $self->hidden_authen_fields;
671 print $self->hidden_fields("subDisplay");
672 print $self->hidden_fields(qw/delete_courseID delete_sql_host delete_sql_port delete_sql_username delete_sql_password delete_sql_database/);
673
674 print CGI::p({style=>"text-align: center"},
675 CGI::submit("decline_delete_course", "Don't delete"),
676 "&nbsp;",
677 CGI::submit("confirm_delete_course", "Delete"),
678 );
679
680 print CGI::end_form();
681}
682
683sub do_delete_course {
684 my ($self) = @_;
685 my $r = $self->r;
686 my $ce = $r->ce;
687 #my $db = $r->db;
688 #my $authz = $r->authz;
689 #my $urlpath = $r->urlpath;
690
691 my $delete_courseID = $r->param("delete_courseID") || "";
692 my $delete_sql_host = $r->param("delete_sql_host") || "";
693 my $delete_sql_port = $r->param("delete_sql_port") || "";
694 my $delete_sql_username = $r->param("delete_sql_username") || "";
695 my $delete_sql_password = $r->param("delete_sql_password") || "";
696 my $delete_sql_database = $r->param("delete_sql_database") || "";
697
698 my $ce2 = WeBWorK::CourseEnvironment->new(
699 $ce->{webworkDirs}->{root},
700 $ce->{webworkURLs}->{root},
701 $ce->{pg}->{directories}->{root},
702 $delete_courseID,
703 );
704
705 my %dbOptions;
706 if ($ce2->{dbLayoutName} eq "sql") {
707 $dbOptions{host} = $delete_sql_host if $delete_sql_host ne "";
708 $dbOptions{port} = $delete_sql_port if $delete_sql_port ne "";
709 $dbOptions{username} = $delete_sql_username;
710 $dbOptions{password} = $delete_sql_password;
711 $dbOptions{database} = $delete_sql_database;
712 }
713
714 eval {
715 deleteCourse(
716 courseID => $delete_courseID,
717 ce => $ce2,
718 dbOptions => \%dbOptions,
719 );
356 } 720 };
357 721
358 if ($add_step >= 2 and $add_step < $add_step_max) { 722 if ($@) {
359 print CGI::hr(); 723 my $error = $@;
724 print CGI::div({class=>"ResultsWithError"},
725 CGI::p("An error occured while deleting the course $delete_courseID:"),
726 CGI::tt(CGI::escapeHTML($error)),
727 );
728 } else {
729 print CGI::div({class=>"ResultsWithoutError"},
730 CGI::p("Possibly deleted the course $delete_courseID. (We need better error checking in deleteCourse().)"),
731 );
360 732
361 print CGI::start_form("POST", $r->uri); 733 print CGI::start_form("POST", $r->uri);
362 print $self->hidden_authen_fields; 734 print $self->hidden_authen_fields;
363 print CGI::hidden("add_step", 4); 735 print $self->hidden_fields("subDisplay");
364 736
365 print CGI::hidden("new_courseID", $new_courseID); 737 print CGI::p({style=>"text-align: center"}, CGI::submit("decline_delete_course", "OK"),);
366 print CGI::hidden("new_dbLayout", $new_dbLayout);
367 print CGI::hidden("new_skipDBCreation", $new_skipDBCreation);
368 print CGI::hidden("new_sql_host", $new_sql_host);
369 print CGI::hidden("new_sql_port", $new_sql_port);
370 print CGI::hidden("new_sql_username", $new_sql_username);
371 print CGI::hidden("new_sql_password", $new_sql_password);
372 print CGI::hidden("new_sql_database", $new_sql_database);
373 print CGI::hidden("new_sql_wwhost", $new_sql_wwhost);
374 print CGI::hidden("new_gdbm_globalUserID", $new_gdbm_globalUserID);
375 738
739 print CGI::end_form();
740 }
741}
742
743################################################################################
744
745sub export_database_form {
746 my ($self) = @_;
747 my $r = $self->r;
748 my $ce = $r->ce;
749 #my $db = $r->db;
750 #my $authz = $r->authz;
751 #my $urlpath = $r->urlpath;
752
753 my @tables = keys %{$ce->{dbLayout}};
754
755 my $export_courseID = $r->param("export_courseID") || "";
756 my @export_tables = $r->param("export_tables");
757
758 @export_tables = @tables unless @export_tables;
759
760 my @courseIDs = listCourses($ce);
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("Export Database");
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 export the course's database.");
780
376 print CGI::start_table({class=>"FormLayout"}); 781 print CGI::table({class=>"FormLayout"},
377 print CGI::Tr( 782 CGI::Tr(
378 CGI::th({class=>"LeftHeader"}, "Professor User ID:"), 783 CGI::th({class=>"LeftHeader"}, "Course Name:"),
379 CGI::td( 784 CGI::td(
380 CGI::textfield( 785 CGI::scrolling_list(
381 -name => "new_initial_userID", 786 -name => "export_courseID",
382 -value => defined $new_initial_userID ? $new_initial_userID : "professor", 787 -values => \@courseIDs,
788 -default => $export_courseID,
383 -size => 50, 789 -size => 10,
384 ), 790 -multiple => 0,
385 CGI::br(), 791 -labels => \%courseLabels,
386 CGI::small("Leave blank to skip user creation."),
387 ),
388 );
389 print CGI::Tr(
390 CGI::th({class=>"LeftHeader"}, "Professor Password:"),
391 CGI::td(
392 CGI::password_field(
393 -name => "new_initial_password",
394 -value => defined $new_initial_password ? $new_initial_password : "",
395 -size => 50,
396 ), 792 ),
397 ), 793 ),
398 ); 794 ),
399 print CGI::Tr({class=>"ButtonRow"}, 795 CGI::Tr(
400 CGI::td({colspan=>2}, 796 CGI::th({class=>"LeftHeader"}, "Tables to Export:"),
401 CGI::submit( 797 CGI::td(
402 -name => "add_course", 798 CGI::checkbox_group(
403 -value => ($add_step > 1 ? "Change" : "Continue"), 799 -name => "export_tables",
800 -values => \@tables,
801 -default => \@export_tables,
802 -linebreak => 1,
404 ), 803 ),
405 ), 804 ),
805 ),
406 ); 806 );
407 print CGI::end_table(); 807
808 print CGI::p({style=>"text-align: center"}, CGI::submit("export_database", "Export Database"));
809
408 print CGI::end_form(); 810 print CGI::end_form();
409 } 811}
812
813sub export_database_validate {
814 my ($self) = @_;
815 my $r = $self->r;
816 #my $ce = $r->ce;
817 #my $db = $r->db;
818 #my $authz = $r->authz;
819 #my $urlpath = $r->urlpath;
410 820
411 if ($add_step >= 3 and $add_step < $add_step_max) { 821 my $export_courseID = $r->param("export_courseID") || "";
412 print CGI::hr(); 822 my @export_tables = $r->param("export_tables");
413 823
414 print CGI::start_form("POST", $r->uri); 824 my @errors;
415 print $self->hidden_authen_fields; 825
416 print CGI::hidden("add_step", 4); 826 if ($export_courseID eq "") {
417 827 push @errors, "You must specify a course name.";
418 print CGI::hidden("new_courseID", $new_courseID); 828 }
419 print CGI::hidden("new_dbLayout", $new_dbLayout); 829
420 print CGI::hidden("new_skipDBCreation", $new_skipDBCreation); 830 unless (@export_tables) {
421 print CGI::hidden("new_sql_host", $new_sql_host); 831 push @errors, "You must specify at least one table to export.";
422 print CGI::hidden("new_sql_port", $new_sql_port); 832 }
423 print CGI::hidden("new_sql_username", $new_sql_username); 833
424 print CGI::hidden("new_sql_password", $new_sql_password); 834 return @errors;
425 print CGI::hidden("new_sql_database", $new_sql_database); 835}
426 print CGI::hidden("new_sql_wwhost", $new_sql_wwhost); 836
427 print CGI::hidden("new_gdbm_globalUserID", $new_gdbm_globalUserID); 837sub do_export_database {
428 print CGI::hidden("new_initial_userID", $new_initial_userID); 838 my ($self) = @_;
429 print CGI::hidden("new_initial_password", $new_initial_password); 839 my $r = $self->r;
430 840 my $ce = $r->ce;
431 print CGI::p("Ready to create the new course. Click ", CGI::b("Create"), "below to do so:"); 841 #my $db = $r->db;
432 print CGI::submit( 842 #my $authz = $r->authz;
433 -name => "create_course", 843 my $urlpath = $r->urlpath;
434 -value => "Create", 844
845 my $export_courseID = $r->param("export_courseID");
846 my @export_tables = $r->param("export_tables");
847
848 my $ce2 = WeBWorK::CourseEnvironment->new(
849 $ce->{webworkDirs}->{root},
850 $ce->{webworkURLs}->{root},
851 $ce->{pg}->{directories}->{root},
852 $export_courseID,
435 ); 853 );
436 }
437 854
438 if ($add_step == $add_step_max) { 855 my $db2 = new WeBWorK::DB($ce2->{dbLayout});
439 # we're creating the course 856
440 857 my ($fh, $export_file) = tempfile("db_export_XXXXXX", DIR => $ce->{webworkDirs}->{tmp});
441 my %dbOptions; 858 my ($random_chars) = $export_file =~ m/db_export_(\w+)$/;
442 if ($new_dbLayout eq "sql") { 859
443 $dbOptions{host} = $new_sql_host if $new_sql_host ne "";
444 $dbOptions{port} = $new_sql_port if $new_sql_port ne "";
445 $dbOptions{username} = $new_sql_username;
446 $dbOptions{password} = $new_sql_password;
447 $dbOptions{database} = $new_sql_database;
448 $dbOptions{wwhost} = $new_sql_wwhost;
449 }
450
451 my @users; 860 my @errors;
452 if ($new_initial_userID ne "") { 861
453 my $User = $db->newUser(
454 user_id => $new_initial_userID,
455 status => "C",
456 );
457 my $Password = $db->newPassword(
458 user_id => $new_initial_userID,
459 password => cryptPassword($new_initial_password),
460 );
461 my $PermissionLevel = $db->newPermissionLevel(
462 user_id => $new_initial_userID,
463 permission => "10",
464 );
465 push @users, [ $User, $Password, $PermissionLevel ];
466 }
467
468 eval { 862 eval {
469 addCourse( 863 @errors = dbExport(
470 courseID => $new_courseID, 864 db => $db2,
471 ce => $ce2, 865 xml => $fh,
472 courseOptions => { dbLayoutName => $new_dbLayout }, 866 tables => \@export_tables,
473 dbOptions => \%dbOptions,
474 users => \@users,
475 ) 867 );
476 }; 868 };
477 869
478 if ($@) { 870 push @errors, "Fatal exception: $@" if $@;
479 my $error = $@; 871
872 if (@errors) {
480 print CGI::div({class=>"ResultsWithError"}, 873 print CGI::div({class=>"ResultsWithError"},
481 CGI::p("An error occured while creating the course $new_courseID:"), 874 CGI::p("An error occured while exporting the database of course $export_courseID:"),
482 CGI::tt(CGI::escapeHTML($error)), 875 CGI::ul(CGI::li(\@errors)),
483 ); 876 );
484 } else { 877 } else {
485 print CGI::div({class=>"ResultsWithoutError"}, 878 print CGI::div({class=>"ResultsWithoutError"},
486 CGI::p("Successfully created the course $new_courseID"), 879 CGI::p("Export succeeded."),
487 ); 880 );
488 } 881
882 print CGI::div({style=>"text-align: center"},
883 CGI::a({href=>$self->systemLink($urlpath, params=>{download_exported_database=>$random_chars, export_courseID=>undef})}, "Download Exported Database"),
884 );
885 }
886}
887
888################################################################################
889
890sub import_database_form {
891 my ($self) = @_;
892 my $r = $self->r;
893 my $ce = $r->ce;
894 #my $db = $r->db;
895 #my $authz = $r->authz;
896 #my $urlpath = $r->urlpath;
897
898 my @tables = keys %{$ce->{dbLayout}};
899
900 my $import_file = $r->param("import_file") || "";
901 my $import_courseID = $r->param("import_courseID") || "";
902 my @import_tables = $r->param("import_tables");
903 my $import_conflict = $r->param("import_conflict") || "skip";
904
905 @import_tables = @tables unless @import_tables;
906
907 my @courseIDs = listCourses($ce);
908
909 my %courseLabels; # records... heh.
910 foreach my $courseID (@courseIDs) {
911 my $tempCE = WeBWorK::CourseEnvironment->new(
912 $ce->{webworkDirs}->{root},
913 $ce->{webworkURLs}->{root},
914 $ce->{pg}->{directories}->{root},
915 $courseID,
916 );
917 $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
918 }
919
920 print CGI::h2("Import Database");
921
922 print CGI::start_form("POST", $r->uri, &CGI::MULTIPART);
923 print $self->hidden_authen_fields;
924 print $self->hidden_fields("subDisplay");
925
926 print CGI::table({class=>"FormLayout"},
927 CGI::Tr(
928 CGI::th({class=>"LeftHeader"}, "Database XML File:"),
929 CGI::td(
930 CGI::filefield(
931 -name => "import_file",
932 -size => 50,
933 ),
934 ),
935 ),
936 CGI::Tr(
937 CGI::th({class=>"LeftHeader"}, "Tables to Import:"),
938 CGI::td(
939 CGI::checkbox_group(
940 -name => "import_tables",
941 -values => \@tables,
942 -default => \@import_tables,
943 -linebreak => 1,
944 ),
945 ),
946 ),
947 CGI::Tr(
948 CGI::th({class=>"LeftHeader"}, "Import into Course:"),
949 CGI::td(
950 CGI::scrolling_list(
951 -name => "import_courseID",
952 -values => \@courseIDs,
953 -default => $import_courseID,
954 -size => 10,
955 -multiple => 0,
956 -labels => \%courseLabels,
957 ),
958 ),
959 ),
960 CGI::Tr(
961 CGI::th({class=>"LeftHeader"}, "Conflicts:"),
962 CGI::td(
963 CGI::radio_group(
964 -name => "import_conflict",
965 -values => [qw/skip replace/],
966 -default => $import_conflict,
967 -linebreak=>'true',
968 -labels => {
969 skip => "Skip duplicate records",
970 replace => "Replace duplicate records",
971 },
972 ),
973 ),
974 ),
975 );
976
977 print CGI::p({style=>"text-align: center"}, CGI::submit("import_database", "Import Database"));
978
979 print CGI::end_form();
980}
981
982sub import_database_validate {
983 my ($self) = @_;
984 my $r = $self->r;
985 #my $ce = $r->ce;
986 #my $db = $r->db;
987 #my $authz = $r->authz;
988 #my $urlpath = $r->urlpath;
989
990 my $import_file = $r->param("import_file") || "";
991 my $import_courseID = $r->param("import_courseID") || "";
992 my @import_tables = $r->param("import_tables");
993 #my $import_conflict = $r->param("import_conflict") || "skip"; # not checked
994
995 my @errors;
996
997 if ($import_file eq "") {
998 push @errors, "You must specify a database file to upload.";
999 }
1000
1001 if ($import_courseID eq "") {
1002 push @errors, "You must specify a course name.";
1003 }
1004
1005 unless (@import_tables) {
1006 push @errors, "You must specify at least one table to import.";
1007 }
1008
1009 return @errors;
1010}
1011
1012sub do_import_database {
1013 my ($self) = @_;
1014 my $r = $self->r;
1015 my $ce = $r->ce;
1016 #my $db = $r->db;
1017 #my $authz = $r->authz;
1018 my $urlpath = $r->urlpath;
1019
1020 my $import_file = $r->param("import_file");
1021 my $import_courseID = $r->param("import_courseID");
1022 my @import_tables = $r->param("import_tables");
1023 my $import_conflict = $r->param("import_conflict") || "skip"; # need default -- not checked above
1024
1025 my $ce2 = WeBWorK::CourseEnvironment->new(
1026 $ce->{webworkDirs}->{root},
1027 $ce->{webworkURLs}->{root},
1028 $ce->{pg}->{directories}->{root},
1029 $import_courseID,
1030 );
1031
1032 my $db2 = new WeBWorK::DB($ce2->{dbLayout});
1033
1034 # retrieve upload from upload cache
1035 my ($id, $hash) = split /\s+/, $import_file;
1036 my $upload = WeBWorK::Upload->retrieve($id, $hash,
1037 dir => $ce->{webworkDirs}->{uploadCache}
1038 );
1039
1040 my @errors;
1041
1042 eval {
1043 @errors = dbImport(
1044 db => $db2,
1045 xml => $upload->fileHandle,
1046 tables => \@import_tables,
1047 conflict => $import_conflict,
1048 );
489 } 1049 };
490 1050
491 return ""; 1051 $upload->dispose;
1052
1053 push @errors, "Fatal exception: $@" if $@;
1054
1055 if (@errors) {
1056 print CGI::div({class=>"ResultsWithError"},
1057 CGI::p("An error occured while importing the database of course $import_courseID:"),
1058 CGI::ul(CGI::li(\@errors)),
1059 );
1060 } else {
1061 print CGI::div({class=>"ResultsWithoutError"},
1062 CGI::p("Import succeeded."),
1063 );
1064 }
492} 1065}
493 1066
4941; 10671;

Legend:
Removed from v.1945  
changed lines
  Added in v.2043

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9