[system] / branches / rel-2-4-patches / webwork2 / lib / WeBWorK / ContentGenerator / CourseAdmin.pm Repository:
ViewVC logotype

Annotation of /branches/rel-2-4-patches/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4295 - (view) (download) (as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm

1 : sh002i 1945 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 : sh002i 3973 # Copyright © 2000-2006 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 4295 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v 1.52 2006/07/18 13:10:54 gage Exp $
5 : sh002i 1945 #
6 :     # This program is free software; you can redistribute it and/or modify it under
7 :     # the terms of either: (a) the GNU General Public License as published by the
8 :     # Free Software Foundation; either version 2, or (at your option) any later
9 :     # version, or (b) the "Artistic License" which comes with this package.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 :     ################################################################################
16 :    
17 :     package WeBWorK::ContentGenerator::CourseAdmin;
18 :     use base qw(WeBWorK::ContentGenerator);
19 :    
20 :     =head1 NAME
21 :    
22 :     WeBWorK::ContentGenerator::CourseAdmin - Add, rename, and delete courses.
23 :    
24 :     =cut
25 :    
26 :     use strict;
27 :     use warnings;
28 : gage 4235 #use CGI qw(-nosticky );
29 :     use WeBWorK::CGI;
30 : sh002i 1945 use Data::Dumper;
31 : sh002i 1985 use File::Temp qw/tempfile/;
32 : sh002i 2138 use WeBWorK::CourseEnvironment;
33 : gage 3235 use IO::File;
34 : sh002i 4087 use WeBWorK::Debug;
35 : gage 3235 use WeBWorK::Utils qw(cryptPassword writeLog listFilesRecursive);
36 : gage 4129 use WeBWorK::Utils::CourseManagement qw(addCourse renameCourse deleteCourse listCourses archiveCourse
37 :     listArchivedCourses unarchiveCourse);
38 : sh002i 1985 use WeBWorK::Utils::DBImportExport qw(dbExport dbImport);
39 : sh002i 1945
40 : sh002i 1985 sub pre_header_initialize {
41 :     my ($self) = @_;
42 :     my $r = $self->r;
43 :     my $ce = $r->ce;
44 :     my $db = $r->db;
45 :     my $authz = $r->authz;
46 :     my $urlpath = $r->urlpath;
47 : gage 2026 my $user = $r->param('user');
48 : sh002i 1985
49 : gage 2026 # check permissions
50 :     unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
51 :     $self->addmessage( CGI::div({class=>'ResultsWithError'},"$user is not authorized to create or delete courses") );
52 :     return;
53 :     }
54 : sh002i 1945
55 : gage 3284 # get result and send to message
56 :     my $status_message = $r->param("status_message");
57 :     $self->addmessage(CGI::p("$status_message")) if $status_message;
58 :    
59 : sh002i 2478 ## if the user is asking for the downloaded database...
60 :     #if (defined $r->param("download_exported_database")) {
61 :     # my $courseID = $r->param("export_courseID");
62 :     # my $random_chars = $r->param("download_exported_database");
63 :     #
64 :     # die "courseID not specified" unless defined $courseID;
65 :     # die "invalid file specification" unless $random_chars =~ m/^\w+$/;
66 :     #
67 :     # my $tempdir = $ce->{webworkDirs}->{tmp};
68 :     # my $export_file = "$tempdir/db_export_$random_chars";
69 :     #
70 :     # $self->reply_with_file("application/xml", $export_file, "${courseID}_database.xml", 0);
71 :     #
72 :     # return "";
73 :     #}
74 :     #
75 :     ## otherwise...
76 : gage 2026
77 : sh002i 2478 my @errors;
78 :     my $method_to_call;
79 : gage 2026
80 : sh002i 1960 my $subDisplay = $r->param("subDisplay");
81 :     if (defined $subDisplay) {
82 : sh002i 1945
83 : sh002i 1960 if ($subDisplay eq "add_course") {
84 :     if (defined $r->param("add_course")) {
85 : sh002i 2478 @errors = $self->add_course_validate;
86 : sh002i 1960 if (@errors) {
87 : sh002i 2478 $method_to_call = "add_course_form";
88 : sh002i 1960 } else {
89 : sh002i 2478 $method_to_call = "do_add_course";
90 : sh002i 1960 }
91 :     } else {
92 : sh002i 2478 $method_to_call = "add_course_form";
93 : sh002i 1960 }
94 :     }
95 :    
96 : sh002i 3059 elsif ($subDisplay eq "rename_course") {
97 :     if (defined $r->param("rename_course")) {
98 :     @errors = $self->rename_course_validate;
99 :     if (@errors) {
100 :     $method_to_call = "rename_course_form";
101 :     } else {
102 :     $method_to_call = "do_rename_course";
103 :     }
104 :     } else {
105 :     $method_to_call = "rename_course_form";
106 :     }
107 :     }
108 :    
109 : sh002i 1960 elsif ($subDisplay eq "delete_course") {
110 :     if (defined $r->param("delete_course")) {
111 :     # validate or confirm
112 : sh002i 2478 @errors = $self->delete_course_validate;
113 : sh002i 1960 if (@errors) {
114 : sh002i 2478 $method_to_call = "delete_course_form";
115 : sh002i 1960 } else {
116 : sh002i 2478 $method_to_call = "delete_course_confirm";
117 : sh002i 1960 }
118 :     } elsif (defined $r->param("confirm_delete_course")) {
119 :     # validate and delete
120 : sh002i 2478 @errors = $self->delete_course_validate;
121 : sh002i 1960 if (@errors) {
122 : sh002i 2478 $method_to_call = "delete_course_form";
123 : sh002i 1960 } else {
124 : sh002i 2478 $method_to_call = "do_delete_course";
125 : sh002i 1960 }
126 :     } else {
127 :     # form only
128 : sh002i 2478 $method_to_call = "delete_course_form";
129 : sh002i 1960 }
130 :     }
131 :    
132 : sh002i 1985 elsif ($subDisplay eq "export_database") {
133 :     if (defined $r->param("export_database")) {
134 : sh002i 2478 @errors = $self->export_database_validate;
135 : sh002i 1985 if (@errors) {
136 : sh002i 2478 $method_to_call = "export_database_form";
137 : sh002i 1985 } else {
138 : sh002i 2478 # we have to do something special here, since we're sending
139 :     # the database as we export it. $method_to_call still gets
140 :     # set here, but it gets caught by header() and content()
141 :     # below instead of by body().
142 :     $method_to_call = "do_export_database";
143 : sh002i 1985 }
144 :     } else {
145 : sh002i 2478 $method_to_call = "export_database_form";
146 : sh002i 1985 }
147 :     }
148 :    
149 :     elsif ($subDisplay eq "import_database") {
150 :     if (defined $r->param("import_database")) {
151 : sh002i 2478 @errors = $self->import_database_validate;
152 : sh002i 1985 if (@errors) {
153 : sh002i 2478 $method_to_call = "import_database_form";
154 : sh002i 1985 } else {
155 : sh002i 2478 $method_to_call = "do_import_database";
156 : sh002i 1985 }
157 :     } else {
158 : sh002i 2478 $method_to_call = "import_database_form";
159 : sh002i 1985 }
160 :     }
161 :    
162 : gage 3528 elsif ($subDisplay eq "archive_course") {
163 :     if (defined $r->param("archive_course")) {
164 :     # validate or confirm
165 :     @errors = $self->archive_course_validate;
166 :     if (@errors) {
167 :     $method_to_call = "archive_course_form";
168 :     } else {
169 :     $method_to_call = "archive_course_confirm";
170 :     }
171 :     } elsif (defined $r->param("confirm_archive_course")) {
172 :     # validate and archive
173 :     @errors = $self->archive_course_validate;
174 :     if (@errors) {
175 :     $method_to_call = "archive_course_form";
176 :     } else {
177 :     $method_to_call = "do_archive_course";
178 :     }
179 :     } else {
180 :     # form only
181 :     $method_to_call = "archive_course_form";
182 :     }
183 :     }
184 : gage 4129 elsif ($subDisplay eq "unarchive_course") {
185 :     if (defined $r->param("unarchive_course")) {
186 :     # validate or confirm
187 :     @errors = $self->unarchive_course_validate;
188 :     if (@errors) {
189 :     $method_to_call = "unarchive_course_form";
190 :     } else {
191 :     $method_to_call = "unarchive_course_confirm";
192 :     }
193 :     } elsif (defined $r->param("confirm_unarchive_course")) {
194 :     # validate and archive
195 :     @errors = $self->unarchive_course_validate;
196 :     if (@errors) {
197 :     $method_to_call = "unarchive_course_form";
198 :     } else {
199 :     $method_to_call = "do_unarchive_course";
200 :     }
201 :     } else {
202 :     # form only
203 :     $method_to_call = "unarchive_course_form";
204 :     }
205 :     }
206 : sh002i 1985 else {
207 : sh002i 2478 @errors = "Unrecognized sub-display @{[ CGI::b($subDisplay) ]}.";
208 : sh002i 1985 }
209 :    
210 : sh002i 1960 }
211 : sh002i 1945
212 : sh002i 2478 $self->{errors} = \@errors;
213 :     $self->{method_to_call} = $method_to_call;
214 :     }
215 :    
216 :     sub header {
217 :     my ($self) = @_;
218 :     my $method_to_call = $self->{method_to_call};
219 : gage 3235 # if (defined $method_to_call and $method_to_call eq "do_export_database") {
220 :     # my $r = $self->r;
221 :     # my $courseID = $r->param("export_courseID");
222 :     # $r->content_type("application/octet-stream");
223 :     # $r->header_out("Content-Disposition" => "attachment; filename=\"${courseID}_database.xml\"");
224 :     # $r->send_http_header;
225 :     # } else {
226 : sh002i 2478 $self->SUPER::header;
227 : gage 3235 # }
228 : sh002i 2478 }
229 :    
230 :     # sends:
231 : sh002i 2479 #
232 : sh002i 2478 # HTTP/1.1 200 OK
233 :     # Date: Fri, 09 Jul 2004 19:05:55 GMT
234 :     # Server: Apache/1.3.27 (Unix) mod_perl/1.27
235 :     # Content-Disposition: attachment; filename="mth143_database.xml"
236 :     # Connection: close
237 :     # Content-Type: application/octet-stream
238 :    
239 :     sub content {
240 :     my ($self) = @_;
241 :     my $method_to_call = $self->{method_to_call};
242 :     if (defined $method_to_call and $method_to_call eq "do_export_database") {
243 : gage 3235 #$self->do_export_database;
244 :     $self->SUPER::content;
245 : sh002i 2478 } else {
246 :     $self->SUPER::content;
247 :     }
248 :     }
249 :    
250 :     sub body {
251 :     my ($self) = @_;
252 :     my $r = $self->r;
253 :     my $ce = $r->ce;
254 :     my $db = $r->db;
255 :     my $authz = $r->authz;
256 :     my $urlpath = $r->urlpath;
257 :    
258 :     my $user = $r->param('user');
259 :    
260 :     # check permissions
261 :     unless ($authz->hasPermissions($user, "create_and_delete_courses")) {
262 :     return "";
263 :     }
264 : gage 3235 my $method_to_call = $self->{method_to_call};
265 :     my $methodMessage ="";
266 : sh002i 2478
267 : gage 3235 (defined($method_to_call) and $method_to_call eq "do_export_database") && do {
268 :     my @export_courseID = $r->param("export_courseID");
269 :     my $course_ids = join(", ", @export_courseID);
270 :     $methodMessage = CGI::p("Exporting database for course(s) $course_ids").
271 :     CGI::p(".... please wait....
272 :     If your browser times out you will
273 :     still be able to download the exported database using the
274 :     file manager.").CGI::hr();
275 :     };
276 :    
277 :    
278 : sh002i 2478 print CGI::p({style=>"text-align: center"},
279 : gage 3437 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"add_course",add_admin_users=>1,
280 :     add_dbLayout=>'sql_single',
281 :     add_templates_course => $ce->{siteDefaults}->{default_templates_course} ||""}
282 :     )},
283 :     "Add Course"
284 :     ),
285 : sh002i 2478 " | ",
286 : sh002i 3059 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"rename_course"})}, "Rename Course"),
287 :     " | ",
288 : sh002i 2478 CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"delete_course"})}, "Delete Course"),
289 :     " | ",
290 :     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"export_database"})}, "Export Database"),
291 :     " | ",
292 :     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"import_database"})}, "Import Database"),
293 : gage 3528 " | ",
294 :     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"archive_course"})}, "Archive Course"),
295 : gage 4129 "|",
296 :     CGI::a({href=>$self->systemLink($urlpath, params=>{subDisplay=>"unarchive_course"})}, "Unarchive Course"),
297 : gage 3235 CGI::hr(),
298 :     $methodMessage,
299 :    
300 : sh002i 2478 );
301 :    
302 : gage 3235 print CGI::p("The ability to import and to export databases is still under development.
303 :     It seems to work but it is <b>VERY</b> slow on large courses. You may prefer to
304 :     use webwork2/bin/wwdb or the mysql dump facility for archiving large courses.
305 :     Please send bug reports if you find errors. ");
306 : sh002i 2478
307 :     my @errors = @{$self->{errors}};
308 :    
309 : gage 3235
310 : sh002i 2478 if (@errors) {
311 :     print CGI::div({class=>"ResultsWithError"},
312 :     CGI::p("Please correct the following errors and try again:"),
313 :     CGI::ul(CGI::li(\@errors)),
314 :     );
315 :     }
316 :    
317 :     if (defined $method_to_call and $method_to_call ne "") {
318 :     $self->$method_to_call;
319 : gage 3434 } else {
320 :    
321 :     print CGI::h2("Courses");
322 :    
323 : gage 3435 print CGI::start_ol();
324 : gage 3434
325 :     my @courseIDs = listCourses($ce);
326 :     foreach my $courseID (sort {lc($a) cmp lc($b) } @courseIDs) {
327 :     next if $courseID eq "admin"; # done already above
328 :     my $urlpath = $r->urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets", courseID => $courseID);
329 :     my $tempCE = WeBWorK::CourseEnvironment->new(
330 :     $ce->{webworkDirs}->{root},
331 :     $ce->{webworkURLs}->{root},
332 :     $ce->{pg}->{directories}->{root},
333 :     $courseID,
334 :     );
335 :     print CGI::li(CGI::a({href=>$self->systemLink($urlpath, authen => 0)}, $courseID),
336 :     CGI::code(
337 :     $tempCE->{dbLayoutName},
338 :     ),
339 :     (-r $tempCE->{courseFiles}->{environment}) ? "" : CGI::i(", missing course.conf"),
340 :    
341 :     );
342 :    
343 :     }
344 :    
345 : gage 3435 print CGI::end_ol();
346 : gage 4129
347 :     print CGI::h2("Archived Courses");
348 :     print CGI::start_ol();
349 :    
350 :     @courseIDs = listArchivedCourses($ce);
351 :     foreach my $courseID (sort {lc($a) cmp lc($b) } @courseIDs) {
352 :     print CGI::li($courseID),
353 :     }
354 :    
355 :     print CGI::end_ol();
356 : sh002i 2478 }
357 : sh002i 1960 return "";
358 :     }
359 :    
360 : sh002i 1985 ################################################################################
361 :    
362 : sh002i 1960 sub add_course_form {
363 :     my ($self) = @_;
364 :     my $r = $self->r;
365 :     my $ce = $r->ce;
366 :     #my $db = $r->db;
367 :     #my $authz = $r->authz;
368 :     #my $urlpath = $r->urlpath;
369 : sh002i 1945
370 : gage 2254 my $add_courseID = $r->param("add_courseID") || "";
371 : sh002i 2378 my $add_courseTitle = $r->param("add_courseTitle") || "";
372 :     my $add_courseInstitution = $r->param("add_courseInstitution") || "";
373 :    
374 :     my $add_admin_users = $r->param("add_admin_users") || "";
375 :    
376 :     my $add_initial_userID = $r->param("add_initial_userID") || "";
377 :     my $add_initial_password = $r->param("add_initial_password") || "";
378 :     my $add_initial_confirmPassword = $r->param("add_initial_confirmPassword") || "";
379 :     my $add_initial_firstName = $r->param("add_initial_firstName") || "";
380 :     my $add_initial_lastName = $r->param("add_initial_lastName") || "";
381 :     my $add_initial_email = $r->param("add_initial_email") || "";
382 :    
383 :     my $add_templates_course = $r->param("add_templates_course") || "";
384 :    
385 : gage 2254 my $add_dbLayout = $r->param("add_dbLayout") || "";
386 :     my $add_sql_host = $r->param("add_sql_host") || "";
387 :     my $add_sql_port = $r->param("add_sql_port") || "";
388 :     my $add_sql_username = $r->param("add_sql_username") || "";
389 :     my $add_sql_password = $r->param("add_sql_password") || "";
390 :     my $add_sql_database = $r->param("add_sql_database") || "";
391 :     my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
392 :     my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
393 : sh002i 1945
394 : sh002i 2639 my @dbLayouts = do {
395 :     my @ordered_layouts;
396 : sh002i 4087 foreach my $layout (@{$ce->{dbLayout_order}}) {
397 : sh002i 2639 if (exists $ce->{dbLayouts}->{$layout}) {
398 :     push @ordered_layouts, $layout;
399 :     }
400 :     }
401 :    
402 :     my %ordered_layouts; @ordered_layouts{@ordered_layouts} = ();
403 :     my @other_layouts;
404 :     foreach my $layout (keys %{ $ce->{dbLayouts} }) {
405 :     unless (exists $ordered_layouts{$layout}) {
406 :     push @other_layouts, $layout;
407 :     }
408 :     }
409 :    
410 :     (@ordered_layouts, @other_layouts);
411 :     };
412 : sh002i 1960
413 :     my $ce2 = WeBWorK::CourseEnvironment->new(
414 :     $ce->{webworkDirs}->{root},
415 :     $ce->{webworkURLs}->{root},
416 :     $ce->{pg}->{directories}->{root},
417 :     "COURSENAME",
418 :     );
419 :    
420 : sh002i 2378 my @existingCourses = listCourses($ce);
421 : gage 3434 @existingCourses = sort { lc($a) cmp lc ($b) } @existingCourses; #make sort case insensitive
422 : sh002i 2148
423 : sh002i 1960 print CGI::h2("Add Course");
424 : sh002i 1945
425 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
426 : sh002i 1960 print $self->hidden_authen_fields;
427 :     print $self->hidden_fields("subDisplay");
428 : sh002i 1945
429 : sh002i 2378 print CGI::p("Specify an ID, title, and institution for the new course. The course ID may contain only letters, numbers, hyphens, and underscores.");
430 : sh002i 1960
431 :     print CGI::table({class=>"FormLayout"},
432 : gage 4280 CGI::Tr({},
433 : gage 2242 CGI::th({class=>"LeftHeader"}, "Course ID:"),
434 : gage 4244 CGI::td(CGI::textfield(-name=>"add_courseID", -value=>$add_courseID, -size=>25)),
435 : sh002i 1960 ),
436 : gage 4280 CGI::Tr({},
437 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Course Title:"),
438 : gage 4244 CGI::td(CGI::textfield(-name=>"add_courseTitle", -value=>$add_courseTitle, -size=>25)),
439 : gage 2242 ),
440 : gage 4280 CGI::Tr({},
441 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Institution:"),
442 : gage 4244 CGI::td(CGI::textfield(-name=>"add_courseInstitution", -value=>$add_courseInstitution, -size=>25)),
443 : gage 2242 ),
444 : sh002i 2378 );
445 :    
446 :     print CGI::p("To add the WeBWorK administrators to the new course (as instructors) check the box below.");
447 : gage 4246 my @checked = ($add_admin_users) ?(checked=>1): (); # workaround because CGI::checkbox seems to have a bug -- it won't default to checked.
448 : gage 4280 print CGI::p({},CGI::input({-type=>'checkbox', -name=>"add_admin_users", @checked }, "Add WeBWorK administrators to new course"));
449 : sh002i 2378
450 : gage 4127 print CGI::p("To add an additional instructor to the new course, specify user information below. The user ID may contain only
451 :     numbers, letters, hyphens, periods (dots), commas,and underscores.\n");
452 : sh002i 2378
453 : gage 4280 print CGI::table({class=>"FormLayout"}, CGI::Tr({},
454 :     CGI::td({},
455 : sh002i 2378 CGI::table({class=>"FormLayout"},
456 : gage 4280 CGI::Tr({},
457 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "User ID:"),
458 : gage 4244 CGI::td(CGI::textfield(-name=>"add_initial_userID", -value=>$add_initial_userID, -size=>25)),
459 : sh002i 2378 ),
460 : gage 4280 CGI::Tr({},
461 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Password:"),
462 : gage 4244 CGI::td(CGI::password_field(-name=>"add_initial_password", -value=>$add_initial_password, -size=>25)),
463 : sh002i 2378 ),
464 : gage 4280 CGI::Tr({},
465 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Confirm Password:"),
466 : gage 4244 CGI::td(CGI::password_field(-name=>"add_initial_confirmPassword", -value=>$add_initial_confirmPassword, -size=>25)),
467 : sh002i 2378 ),
468 :     ),
469 : gage 2299 ),
470 : gage 4280 CGI::td({},
471 : sh002i 2378 CGI::table({class=>"FormLayout"},
472 : gage 4280 CGI::Tr({},
473 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "First Name:"),
474 : gage 4244 CGI::td(CGI::textfield(-name=>"add_initial_firstName", -value=>$add_initial_firstName, -size=>25)),
475 : sh002i 2378 ),
476 : gage 4280 CGI::Tr({},
477 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Last Name:"),
478 : gage 4244 CGI::td(CGI::textfield(-name=>"add_initial_lastName", -value=>$add_initial_lastName, -size=>25)),
479 : sh002i 2378 ),
480 : gage 4280 CGI::Tr({},
481 : sh002i 2378 CGI::th({class=>"LeftHeader"}, "Email Address:"),
482 : gage 4244 CGI::td(CGI::textfield(-name=>"add_initial_email", -value=>$add_initial_email, -size=>25)),
483 : sh002i 2378 ),
484 :     ),
485 : gage 2242
486 :     ),
487 : sh002i 2378 ));
488 : gage 2254
489 : sh002i 2378 print CGI::p("To copy problem templates from an existing course, select the course below.");
490 : gage 2254
491 :     print CGI::table({class=>"FormLayout"},
492 : gage 4280 CGI::Tr({},
493 : gage 2254 CGI::th({class=>"LeftHeader"}, "Copy templates from:"),
494 :     CGI::td(
495 :     CGI::popup_menu(
496 :     -name => "add_templates_course",
497 :     -values => [ "", @existingCourses ],
498 :     -default => $add_templates_course,
499 :     #-size => 10,
500 :     #-multiple => 0,
501 :     #-labels => \%courseLabels,
502 :     ),
503 :    
504 :     ),
505 :     ),
506 :     );
507 :    
508 : sh002i 2378 print CGI::p("Select a database layout below.");
509 : gage 4295 print CGI::start_table({class=>"FormLayout"});
510 : sh002i 1960 foreach my $dbLayout (@dbLayouts) {
511 :    
512 : gage 4295
513 : sh002i 4087 my $dbLayoutLabel = (defined $ce->{dbLayout_descr}{$dbLayout})
514 :     ? "$dbLayout - " . $ce->{dbLayout_descr}{$dbLayout}
515 : gage 4295 : "$dbLayout - no description provided in global.conf";
516 : sh002i 2639
517 : sh002i 1960 # we generate singleton radio button tags ourselves because it's too much of a pain to do it with CGI.pm
518 : gage 4280 print CGI::Tr({},
519 : gage 4295 CGI::td({width=>'20%'},
520 : gage 4280 # why did this not work? because values aren't escaped?
521 :     # '<input type="radio" name="add_dbLayout" value="' . $dbLayout . '"'
522 :     # . ($add_dbLayout eq $dbLayout ? 'checked=>"1"' : '') . ' />',
523 : gage 4295 CGI::radio_group(-name =>"add_dbLayout",
524 :     -value => [$dbLayout],
525 :     -default => $dbLayout,
526 : gage 4280 ),
527 :    
528 : sh002i 1945 ),
529 : sh002i 2639 CGI::td($dbLayoutLabel),
530 : sh002i 1945 );
531 :    
532 : gage 4295
533 : sh002i 1945 }
534 : gage 4295 print CGI::end_table();
535 :     print CGI::p({style=>"text-align: left"}, CGI::submit(-name=>"add_course", -label=>"Add Course"));
536 : sh002i 1945
537 : sh002i 1960 print CGI::end_form();
538 :     }
539 :    
540 :     sub add_course_validate {
541 :     my ($self) = @_;
542 :     my $r = $self->r;
543 :     my $ce = $r->ce;
544 :     #my $db = $r->db;
545 :     #my $authz = $r->authz;
546 :     #my $urlpath = $r->urlpath;
547 :    
548 : gage 2254 my $add_courseID = $r->param("add_courseID") || "";
549 : sh002i 2378 my $add_courseTitle = $r->param("add_courseTitle") || "";
550 :     my $add_courseInstitution = $r->param("add_courseInstitution") || "";
551 :    
552 :     my $add_admin_users = $r->param("add_admin_users") || "";
553 :    
554 :     my $add_initial_userID = $r->param("add_initial_userID") || "";
555 :     my $add_initial_password = $r->param("add_initial_password") || "";
556 :     my $add_initial_confirmPassword = $r->param("add_initial_confirmPassword") || "";
557 :     my $add_initial_firstName = $r->param("add_initial_firstName") || "";
558 :     my $add_initial_lastName = $r->param("add_initial_lastName") || "";
559 :     my $add_initial_email = $r->param("add_initial_email") || "";
560 :    
561 :     my $add_templates_course = $r->param("add_templates_course") || "";
562 :    
563 : gage 2254 my $add_dbLayout = $r->param("add_dbLayout") || "";
564 :     my $add_sql_host = $r->param("add_sql_host") || "";
565 :     my $add_sql_port = $r->param("add_sql_port") || "";
566 :     my $add_sql_username = $r->param("add_sql_username") || "";
567 :     my $add_sql_password = $r->param("add_sql_password") || "";
568 :     my $add_sql_database = $r->param("add_sql_database") || "";
569 :     my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
570 :     my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
571 : sh002i 2378
572 : sh002i 1960 my @errors;
573 :    
574 :     if ($add_courseID eq "") {
575 : sh002i 2378 push @errors, "You must specify a course ID.";
576 : sh002i 1960 }
577 : sh002i 2887 unless ($add_courseID =~ /^[\w-]*$/) { # regex copied from CourseAdministration.pm
578 :     push @errors, "Course ID may only contain letters, numbers, hyphens, and underscores.";
579 :     }
580 : sh002i 2373 if (grep { $add_courseID eq $_ } listCourses($ce)) {
581 : sh002i 2378 push @errors, "A course with ID $add_courseID already exists.";
582 : sh002i 2373 }
583 : sh002i 2378 if ($add_courseTitle eq "") {
584 :     push @errors, "You must specify a course title.";
585 : gage 2242 }
586 : sh002i 2378 if ($add_courseInstitution eq "") {
587 :     push @errors, "You must specify an institution for this course.";
588 : gage 2242 }
589 : sh002i 2378
590 :     if ($add_initial_userID ne "") {
591 :     if ($add_initial_password eq "") {
592 :     push @errors, "You must specify a password for the initial instructor.";
593 :     }
594 :     if ($add_initial_confirmPassword eq "") {
595 :     push @errors, "You must confirm the password for the initial instructor.";
596 :     }
597 :     if ($add_initial_password ne $add_initial_confirmPassword) {
598 :     push @errors, "The password and password confirmation for the instructor must match.";
599 :     }
600 :     if ($add_initial_firstName eq "") {
601 :     push @errors, "You must specify a first name for the initial instructor.";
602 :     }
603 :     if ($add_initial_lastName eq "") {
604 :     push @errors, "You must specify a last name for the initial instructor.";
605 :     }
606 :     if ($add_initial_email eq "") {
607 :     push @errors, "You must specify an email address for the initial instructor.";
608 :     }
609 : gage 2242 }
610 : sh002i 1960
611 :     if ($add_dbLayout eq "") {
612 :     push @errors, "You must select a database layout.";
613 :     } else {
614 :     if (exists $ce->{dbLayouts}->{$add_dbLayout}) {
615 :     if ($add_dbLayout eq "sql") {
616 :     push @errors, "You must specify the SQL admin username." if $add_sql_username eq "";
617 :     push @errors, "You must specify the WeBWorK host." if $add_sql_wwhost eq "";
618 :     } elsif ($add_dbLayout eq "gdbm") {
619 :     push @errors, "You must specify the GDBM global user ID." if $add_gdbm_globalUserID eq "";
620 :     }
621 :     } else {
622 :     push @errors, "The database layout $add_dbLayout doesn't exist.";
623 :     }
624 :     }
625 :    
626 :     return @errors;
627 :     }
628 :    
629 :     sub do_add_course {
630 :     my ($self) = @_;
631 :     my $r = $self->r;
632 :     my $ce = $r->ce;
633 :     my $db = $r->db;
634 : gage 4127 my $authz = $r->authz;
635 : sh002i 1960 my $urlpath = $r->urlpath;
636 :    
637 : sh002i 2378 my $add_courseID = $r->param("add_courseID") || "";
638 :     my $add_courseTitle = $r->param("add_courseTitle") || "";
639 :     my $add_courseInstitution = $r->param("add_courseInstitution") || "";
640 :    
641 :     my $add_admin_users = $r->param("add_admin_users") || "";
642 :    
643 :     my $add_initial_userID = $r->param("add_initial_userID") || "";
644 :     my $add_initial_password = $r->param("add_initial_password") || "";
645 :     my $add_initial_confirmPassword = $r->param("add_initial_confirmPassword") || "";
646 :     my $add_initial_firstName = $r->param("add_initial_firstName") || "";
647 :     my $add_initial_lastName = $r->param("add_initial_lastName") || "";
648 :     my $add_initial_email = $r->param("add_initial_email") || "";
649 :    
650 :     my $add_templates_course = $r->param("add_templates_course") || "";
651 :    
652 :     my $add_dbLayout = $r->param("add_dbLayout") || "";
653 :     my $add_sql_host = $r->param("add_sql_host") || "";
654 :     my $add_sql_port = $r->param("add_sql_port") || "";
655 :     my $add_sql_username = $r->param("add_sql_username") || "";
656 :     my $add_sql_password = $r->param("add_sql_password") || "";
657 :     my $add_sql_database = $r->param("add_sql_database") || "";
658 :     my $add_sql_wwhost = $r->param("add_sql_wwhost") || "";
659 :     my $add_gdbm_globalUserID = $r->param("add_gdbm_globalUserID") || "";
660 : gage 2242
661 : sh002i 1960 my $ce2 = WeBWorK::CourseEnvironment->new(
662 :     $ce->{webworkDirs}->{root},
663 :     $ce->{webworkURLs}->{root},
664 :     $ce->{pg}->{directories}->{root},
665 :     $add_courseID,
666 :     );
667 :    
668 : gage 2042 my %courseOptions = ( dbLayoutName => $add_dbLayout );
669 : sh002i 2384
670 :     if ($add_initial_email ne "") {
671 :     $courseOptions{allowedRecipients} = [ $add_initial_email ];
672 : sh002i 2853 # don't set feedbackRecipients -- this just gets in the way of the more
673 :     # intelligent "receive_recipients" method.
674 :     #$courseOptions{feedbackRecipients} = [ $add_initial_email ];
675 : sh002i 2384 }
676 :    
677 : sh002i 2004 if ($add_dbLayout eq "gdbm") {
678 :     $courseOptions{globalUserID} = $add_gdbm_globalUserID if $add_gdbm_globalUserID ne "";
679 :     }
680 :    
681 : sh002i 1960 my %dbOptions;
682 :     if ($add_dbLayout eq "sql") {
683 :     $dbOptions{host} = $add_sql_host if $add_sql_host ne "";
684 :     $dbOptions{port} = $add_sql_port if $add_sql_port ne "";
685 :     $dbOptions{username} = $add_sql_username;
686 :     $dbOptions{password} = $add_sql_password;
687 : sh002i 2104 $dbOptions{database} = $add_sql_database || "webwork_$add_courseID";
688 : sh002i 1960 $dbOptions{wwhost} = $add_sql_wwhost;
689 :     }
690 : sh002i 2378
691 : sh002i 1960 my @users;
692 : sh002i 2378
693 :     # copy users from current (admin) course if desired
694 :     if ($add_admin_users ne "") {
695 :     foreach my $userID ($db->listUsers) {
696 : sh002i 2887 if ($userID eq $add_initial_userID) {
697 : gage 3284 $self->addbadmessage( "User '$userID' will not be copied from admin course as it is the initial instructor.");
698 : sh002i 2885 next;
699 :     }
700 : sh002i 2378 my $User = $db->getUser($userID);
701 :     my $Password = $db->getPassword($userID);
702 :     my $PermissionLevel = $db->getPermissionLevel($userID);
703 : gage 4127 push @users, [ $User, $Password, $PermissionLevel ]
704 :     if $authz->hasPermissions($userID,"create_and_delete_courses");
705 :     #only transfer the "instructors" in the admin course classlist.
706 : sh002i 2378 }
707 :     }
708 :    
709 :     # add initial instructor if desired
710 : sh002i 1960 if ($add_initial_userID ne "") {
711 : sh002i 2004 my $User = $db->newUser(
712 : sh002i 2384 user_id => $add_initial_userID,
713 :     first_name => $add_initial_firstName,
714 :     last_name => $add_initial_lastName,
715 :     student_id => $add_initial_userID,
716 :     email_address => $add_initial_email,
717 :     status => "C",
718 : sh002i 2004 );
719 :     my $Password = $db->newPassword(
720 : sh002i 2378 user_id => $add_initial_userID,
721 : sh002i 1960 password => cryptPassword($add_initial_password),
722 : sh002i 2004 );
723 :     my $PermissionLevel = $db->newPermissionLevel(
724 : sh002i 2378 user_id => $add_initial_userID,
725 : sh002i 1960 permission => "10",
726 : sh002i 2004 );
727 :     push @users, [ $User, $Password, $PermissionLevel ];
728 : sh002i 1960 }
729 : sh002i 2378
730 : dpvc 2704 push @{$courseOptions{PRINT_FILE_NAMES_FOR}}, map { $_->[0]->user_id } @users;
731 : sh002i 2384
732 : sh002i 2148 my %optional_arguments;
733 :     if ($add_templates_course ne "") {
734 :     $optional_arguments{templatesFrom} = $add_templates_course;
735 :     }
736 :    
737 : sh002i 1960 eval {
738 :     addCourse(
739 : sh002i 2004 courseID => $add_courseID,
740 :     ce => $ce2,
741 :     courseOptions => \%courseOptions,
742 :     dbOptions => \%dbOptions,
743 :     users => \@users,
744 : sh002i 2148 %optional_arguments,
745 : sh002i 1945 );
746 : sh002i 1960 };
747 :     if ($@) {
748 :     my $error = $@;
749 :     print CGI::div({class=>"ResultsWithError"},
750 :     CGI::p("An error occured while creating the course $add_courseID:"),
751 :     CGI::tt(CGI::escapeHTML($error)),
752 :     );
753 : gage 2254 # get rid of any partially built courses
754 :     # FIXME -- this is too fragile
755 :     unless ($error =~ /course exists/) {
756 :     eval {
757 :     deleteCourse(
758 :     courseID => $add_courseID,
759 :     ce => $ce2,
760 :     dbOptions => \%dbOptions,
761 :     );
762 :     }
763 :     }
764 : sh002i 1960 } else {
765 : gage 2256 #log the action
766 : gage 2242 writeLog($ce, "hosted_courses", join("\t",
767 :     "\tAdded",
768 : sh002i 2378 $add_courseInstitution,
769 :     $add_courseTitle,
770 : gage 2242 $add_courseID,
771 : sh002i 2378 $add_initial_firstName,
772 :     $add_initial_lastName,
773 :     $add_initial_email,
774 : gage 2242 ));
775 : gage 2256 # add contact to admin course as student?
776 :     # FIXME -- should we do this?
777 : gage 4127 if ($add_initial_userID ne "") {
778 :     my $composite_id = "${add_initial_userID}_${add_courseID}"; # student id includes school name and contact
779 :     my $User = $db->newUser(
780 :     user_id => $composite_id, # student id includes school name and contact
781 :     first_name => $add_initial_firstName,
782 :     last_name => $add_initial_lastName,
783 :     student_id => $add_initial_userID,
784 :     email_address => $add_initial_email,
785 :     status => "C",
786 :     );
787 :     my $Password = $db->newPassword(
788 :     user_id => $composite_id,
789 :     password => cryptPassword($add_initial_password),
790 :     );
791 :     my $PermissionLevel = $db->newPermissionLevel(
792 :     user_id => $composite_id,
793 :     permission => "0",
794 :     );
795 :     # add contact to admin course as student
796 :     # or if this contact and course already exist in a dropped status
797 :     # change the student's status to enrolled
798 :     if (my $oldUser = $db->getUser($composite_id) ) {
799 :     warn "Replacing old data for $composite_id status: ". $oldUser->status;
800 :     $db->deleteUser($composite_id);
801 :     }
802 :     eval { $db->addUser($User) }; warn $@ if $@;
803 :     eval { $db->addPassword($Password) }; warn $@ if $@;
804 :     eval { $db->addPermissionLevel($PermissionLevel) }; warn $@ if $@;
805 :     }
806 : sh002i 1960 print CGI::div({class=>"ResultsWithoutError"},
807 :     CGI::p("Successfully created the course $add_courseID"),
808 :     );
809 :     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
810 :     courseID => $add_courseID);
811 :     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
812 :     print CGI::div({style=>"text-align: center"},
813 :     CGI::a({href=>$newCourseURL}, "Log into $add_courseID"),
814 :     );
815 :     }
816 : gage 2322
817 : gage 2299
818 : sh002i 1960 }
819 :    
820 :     ################################################################################
821 :    
822 : sh002i 3059 sub rename_course_form {
823 :     my ($self) = @_;
824 :     my $r = $self->r;
825 :     my $ce = $r->ce;
826 :     #my $db = $r->db;
827 :     #my $authz = $r->authz;
828 :     #my $urlpath = $r->urlpath;
829 :    
830 :     my $rename_oldCourseID = $r->param("rename_oldCourseID") || "";
831 :     my $rename_newCourseID = $r->param("rename_newCourseID") || "";
832 :    
833 :     my $rename_sql_host = $r->param("rename_sql_host") || "";
834 :     my $rename_sql_port = $r->param("rename_sql_port") || "";
835 :     my $rename_sql_username = $r->param("rename_sql_username") || "";
836 :     my $rename_sql_password = $r->param("rename_sql_password") || "";
837 :     my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || "";
838 :     my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || "";
839 :     my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || "";
840 :    
841 :     my @courseIDs = listCourses($ce);
842 : gage 3434 @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs;
843 : sh002i 3059
844 :     my %courseLabels; # records... heh.
845 :     foreach my $courseID (@courseIDs) {
846 :     my $tempCE = WeBWorK::CourseEnvironment->new(
847 :     $ce->{webworkDirs}->{root},
848 :     $ce->{webworkURLs}->{root},
849 :     $ce->{pg}->{directories}->{root},
850 :     $courseID,
851 :     );
852 :     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
853 :     }
854 :    
855 :     print CGI::h2("Rename Course");
856 :    
857 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
858 : sh002i 3059 print $self->hidden_authen_fields;
859 :     print $self->hidden_fields("subDisplay");
860 :    
861 :     print CGI::p("Select a course to rename.");
862 :    
863 :     print CGI::table({class=>"FormLayout"},
864 : gage 4280 CGI::Tr({},
865 : sh002i 3059 CGI::th({class=>"LeftHeader"}, "Course Name:"),
866 :     CGI::td(
867 :     CGI::scrolling_list(
868 :     -name => "rename_oldCourseID",
869 :     -values => \@courseIDs,
870 :     -default => $rename_oldCourseID,
871 :     -size => 10,
872 :     -multiple => 0,
873 :     -labels => \%courseLabels,
874 :     ),
875 :     ),
876 :     ),
877 : gage 4280 CGI::Tr({},
878 : sh002i 3059 CGI::th({class=>"LeftHeader"}, "New Name:"),
879 : gage 4244 CGI::td(CGI::textfield(-name=>"rename_newCourseID", -value=>$rename_newCourseID, -size=>25)),
880 : sh002i 3059 ),
881 :     );
882 :    
883 : gage 4280 # print CGI::p(
884 :     # "If the course's database layout (indicated in parentheses above) is "
885 :     # . CGI::b("sql") . ", supply the SQL connections information requested below."
886 :     # );
887 :     #
888 :     # print CGI::start_table({class=>"FormLayout"});
889 :     # print CGI::Tr(CGI::td({colspan=>2},
890 :     # "Enter the user ID and password for an SQL account with sufficient permissions to create and delete databases."
891 :     # )
892 :     # );
893 :     # print CGI::Tr({},
894 :     # CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
895 :     # CGI::td(CGI::textfield(-name=>"rename_sql_username", -value=>$rename_sql_username, -size=>25)),
896 :     # );
897 :     # print CGI::Tr({},
898 :     # CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
899 :     # CGI::td(CGI::password_field(-name=>"rename_sql_password", -value=>$rename_sql_password, -size=>25)),
900 :     # );
901 :     #
902 :     # print CGI::Tr({},
903 :     # CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
904 :     # CGI::td({},
905 :     # CGI::textfield(-name=>"rename_sql_host", -value=>$rename_sql_host, -size=>25),
906 :     # CGI::br(),
907 :     # CGI::small("Leave blank to use the default host."),
908 :     # ),
909 :     # );
910 :     # print CGI::Tr({},
911 :     # CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
912 :     # CGI::td({},
913 :     # CGI::textfield(-name=>"rename_sql_port", -value=>$rename_sql_port, -size=>25),
914 :     # CGI::br(),
915 :     # CGI::small("Leave blank to use the default port."),
916 :     # ),
917 :     # );
918 :     #
919 :     # print CGI::Tr({},
920 :     # CGI::th({class=>"LeftHeader"}, "SQL Current Database Name:"),
921 :     # CGI::td({},
922 :     # CGI::textfield(-name=>"rename_sql_database", -value=>$rename_sql_oldDatabase, -size=>25),
923 :     # CGI::br(),
924 :     # CGI::small("Leave blank to use the name ". CGI::tt("webwork_COURSENAME"). "."),
925 :     # ),
926 :     # );
927 :     # print CGI::Tr({},
928 :     # CGI::th({class=>"LeftHeader"}, "SQL New Database Name:"),
929 :     # CGI::td({},
930 :     # CGI::textfield(-name=>"rename_sql_database", -value=>$rename_sql_newDatabase, -size=>25),
931 :     # CGI::br(),
932 :     # CGI::small("Leave blank to use the name ".CGI::tt("webwork_COURSENAME"). "."),
933 :     # ),
934 :     # );
935 :     # print CGI::Tr({},
936 :     # CGI::th({class=>"LeftHeader"}, "WeBWorK Host:"),
937 :     # CGI::td({},
938 :     # CGI::textfield(-name=>"rename_sql_wwhost", -value=>$rename_sql_wwhost || "localhost", -size=>25),
939 :     # CGI::br(),
940 :     # 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."),
941 :     # ),
942 :     # );
943 : sh002i 3059 print CGI::end_table();
944 :    
945 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"rename_course", -label=>"Rename Course"));
946 : sh002i 3059
947 :     print CGI::end_form();
948 :     }
949 :    
950 :     sub rename_course_validate {
951 :     my ($self) = @_;
952 :     my $r = $self->r;
953 :     my $ce = $r->ce;
954 :     #my $db = $r->db;
955 :     #my $authz = $r->authz;
956 :     #my $urlpath = $r->urlpath;
957 :    
958 :     my $rename_oldCourseID = $r->param("rename_oldCourseID") || "";
959 :     my $rename_newCourseID = $r->param("rename_newCourseID") || "";
960 :    
961 :     my $rename_sql_host = $r->param("rename_sql_host") || "";
962 :     my $rename_sql_port = $r->param("rename_sql_port") || "";
963 :     my $rename_sql_username = $r->param("rename_sql_username") || "";
964 :     my $rename_sql_password = $r->param("rename_sql_password") || "";
965 :     my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || "";
966 :     my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || "";
967 :     my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || "";
968 :    
969 :     my @errors;
970 :    
971 :     if ($rename_oldCourseID eq "") {
972 :     push @errors, "You must select a course to rename.";
973 :     }
974 :     if ($rename_newCourseID eq "") {
975 :     push @errors, "You must specify a new name for the course.";
976 :     }
977 :     if ($rename_oldCourseID eq $rename_newCourseID) {
978 :     push @errors, "Can't rename to the same name.";
979 :     }
980 :     unless ($rename_newCourseID =~ /^[\w-]*$/) { # regex copied from CourseAdministration.pm
981 :     push @errors, "Course ID may only contain letters, numbers, hyphens, and underscores.";
982 :     }
983 :     if (grep { $rename_newCourseID eq $_ } listCourses($ce)) {
984 :     push @errors, "A course with ID $rename_newCourseID already exists.";
985 :     }
986 :    
987 :     my $ce2 = WeBWorK::CourseEnvironment->new(
988 :     $ce->{webworkDirs}->{root},
989 :     $ce->{webworkURLs}->{root},
990 :     $ce->{pg}->{directories}->{root},
991 :     $rename_oldCourseID,
992 :     );
993 :    
994 :     if ($ce2->{dbLayoutName} eq "sql") {
995 :     push @errors, "You must specify the SQL admin username." if $rename_sql_username eq "";
996 :     #push @errors, "You must specify the SQL admin password." if $rename_sql_password eq "";
997 :     #push @errors, "You must specify the current SQL database name." if $rename_sql_oldDatabase eq "";
998 :     #push @errors, "You must specify the new SQL database name." if $rename_sql_newDatabase eq "";
999 :     }
1000 :    
1001 :     return @errors;
1002 :     }
1003 :    
1004 :     sub do_rename_course {
1005 :     my ($self) = @_;
1006 :     my $r = $self->r;
1007 :     my $ce = $r->ce;
1008 :     my $db = $r->db;
1009 :     #my $authz = $r->authz;
1010 :     my $urlpath = $r->urlpath;
1011 :    
1012 :     my $rename_oldCourseID = $r->param("rename_oldCourseID") || "";
1013 :     my $rename_newCourseID = $r->param("rename_newCourseID") || "";
1014 :    
1015 :     my $rename_sql_host = $r->param("rename_sql_host") || "";
1016 :     my $rename_sql_port = $r->param("rename_sql_port") || "";
1017 :     my $rename_sql_username = $r->param("rename_sql_username") || "";
1018 :     my $rename_sql_password = $r->param("rename_sql_password") || "";
1019 :     my $rename_sql_oldDatabase = $r->param("rename_sql_oldDatabase") || "";
1020 :     my $rename_sql_newDatabase = $r->param("rename_sql_newDatabase") || "";
1021 :     my $rename_sql_wwhost = $r->param("rename_sql_wwhost") || "";
1022 :    
1023 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1024 :     $ce->{webworkDirs}->{root},
1025 :     $ce->{webworkURLs}->{root},
1026 :     $ce->{pg}->{directories}->{root},
1027 :     $rename_oldCourseID,
1028 :     );
1029 :    
1030 :     my $dbLayoutName = $ce->{dbLayoutName};
1031 :    
1032 :     my %dbOptions;
1033 :     if ($dbLayoutName eq "sql") {
1034 :     $dbOptions{host} = $rename_sql_host if $rename_sql_host ne "";
1035 :     $dbOptions{port} = $rename_sql_port if $rename_sql_port ne "";
1036 :     $dbOptions{username} = $rename_sql_username;
1037 :     $dbOptions{password} = $rename_sql_password;
1038 :     $dbOptions{old_database} = $rename_sql_oldDatabase || "webwork_$rename_oldCourseID";
1039 :     $dbOptions{new_database} = $rename_sql_newDatabase || "webwork_$rename_newCourseID";
1040 :     $dbOptions{wwhost} = $rename_sql_wwhost;
1041 :     }
1042 :    
1043 :     eval {
1044 :     renameCourse(
1045 :     courseID => $rename_oldCourseID,
1046 :     ce => $ce2,
1047 :     dbOptions => \%dbOptions,
1048 :     newCourseID => $rename_newCourseID,
1049 :     );
1050 :     };
1051 :     if ($@) {
1052 :     my $error = $@;
1053 :     print CGI::div({class=>"ResultsWithError"},
1054 :     CGI::p("An error occured while renaming the course $rename_oldCourseID to $rename_newCourseID:"),
1055 :     CGI::tt(CGI::escapeHTML($error)),
1056 :     );
1057 :     } else {
1058 :     print CGI::div({class=>"ResultsWithoutError"},
1059 :     CGI::p("Successfully renamed the course $rename_oldCourseID to $rename_newCourseID"),
1060 :     );
1061 :     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
1062 :     courseID => $rename_newCourseID);
1063 :     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
1064 :     print CGI::div({style=>"text-align: center"},
1065 :     CGI::a({href=>$newCourseURL}, "Log into $rename_newCourseID"),
1066 :     );
1067 :     }
1068 :     }
1069 :    
1070 :     ################################################################################
1071 :    
1072 : sh002i 1960 sub delete_course_form {
1073 :     my ($self) = @_;
1074 :     my $r = $self->r;
1075 :     my $ce = $r->ce;
1076 :     #my $db = $r->db;
1077 :     #my $authz = $r->authz;
1078 :     #my $urlpath = $r->urlpath;
1079 :    
1080 :     my $delete_courseID = $r->param("delete_courseID") || "";
1081 :     my $delete_sql_host = $r->param("delete_sql_host") || "";
1082 :     my $delete_sql_port = $r->param("delete_sql_port") || "";
1083 :     my $delete_sql_username = $r->param("delete_sql_username") || "";
1084 :     my $delete_sql_password = $r->param("delete_sql_password") || "";
1085 :     my $delete_sql_database = $r->param("delete_sql_database") || "";
1086 :    
1087 :     my @courseIDs = listCourses($ce);
1088 : gage 3434 @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs; #make sort case insensitive
1089 : sh002i 1960
1090 :     my %courseLabels; # records... heh.
1091 :     foreach my $courseID (@courseIDs) {
1092 :     my $tempCE = WeBWorK::CourseEnvironment->new(
1093 :     $ce->{webworkDirs}->{root},
1094 :     $ce->{webworkURLs}->{root},
1095 :     $ce->{pg}->{directories}->{root},
1096 :     $courseID,
1097 :     );
1098 :     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
1099 :     }
1100 :    
1101 :     print CGI::h2("Delete Course");
1102 :    
1103 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
1104 : sh002i 1960 print $self->hidden_authen_fields;
1105 :     print $self->hidden_fields("subDisplay");
1106 :    
1107 :     print CGI::p("Select a course to delete.");
1108 :    
1109 :     print CGI::table({class=>"FormLayout"},
1110 : gage 4280 CGI::Tr({},
1111 : sh002i 1960 CGI::th({class=>"LeftHeader"}, "Course Name:"),
1112 : sh002i 1945 CGI::td(
1113 : sh002i 1960 CGI::scrolling_list(
1114 :     -name => "delete_courseID",
1115 :     -values => \@courseIDs,
1116 :     -default => $delete_courseID,
1117 :     -size => 10,
1118 :     -multiple => 0,
1119 :     -labels => \%courseLabels,
1120 : sh002i 1945 ),
1121 :     ),
1122 : sh002i 1960 ),
1123 :     );
1124 :    
1125 :     print CGI::p(
1126 :     "If the course's database layout (indicated in parentheses above) is "
1127 :     . CGI::b("sql") . ", supply the SQL connections information requested below."
1128 :     );
1129 :    
1130 : sh002i 2719 print CGI::start_table({class=>"FormLayout"});
1131 :     print CGI::Tr(CGI::td({colspan=>2},
1132 :     "Enter the user ID and password for an SQL account with sufficient permissions to delete an existing database."
1133 :     )
1134 :     );
1135 : gage 4280 print CGI::Tr({},
1136 : sh002i 2719 CGI::th({class=>"LeftHeader"}, "SQL Admin Username:"),
1137 : gage 4244 CGI::td(CGI::textfield(-name=>"delete_sql_username", -value=>$delete_sql_username, -size=>25)),
1138 : sh002i 2719 );
1139 : gage 4280 print CGI::Tr({},
1140 : sh002i 2719 CGI::th({class=>"LeftHeader"}, "SQL Admin Password:"),
1141 : gage 4244 CGI::td(CGI::password_field(-name=>"delete_sql_password", -value=>$delete_sql_password, -size=>25)),
1142 : sh002i 2719 );
1143 : sh002i 1960
1144 : sh002i 2719 #print CGI::Tr(CGI::td({colspan=>2},
1145 :     # "The optionial SQL settings you enter below must match the settings in the DBI source"
1146 :     # . " specification " . CGI::tt($dbi_source) . ". Replace " . CGI::tt("COURSENAME")
1147 :     # . " with the course name you entered above."
1148 :     # )
1149 :     #);
1150 : gage 4280 print CGI::Tr({},
1151 : sh002i 2719 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
1152 : gage 4280 CGI::td({},
1153 : gage 4244 CGI::textfield(-name=>"delete_sql_host", -value=>$delete_sql_host, -size=>25),
1154 : sh002i 2719 CGI::br(),
1155 : gage 4244 CGI::small(-name=>"Leave blank to use the default host."),
1156 : sh002i 2719 ),
1157 :     );
1158 : gage 4280 print CGI::Tr({},
1159 : sh002i 2719 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
1160 : gage 4280 CGI::td({},
1161 : gage 4244 CGI::textfield(-name=>"delete_sql_port", -value=>$delete_sql_port, -size=>25),
1162 : sh002i 2719 CGI::br(),
1163 :     CGI::small("Leave blank to use the default port."),
1164 :     ),
1165 :     );
1166 :    
1167 : gage 4280 print CGI::Tr({},
1168 : sh002i 2719 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
1169 : gage 4280 CGI::td({},
1170 : gage 4244 CGI::textfield(-name=>"delete_sql_database", -value=>$delete_sql_database, -size=>25),
1171 : sh002i 2719 CGI::br(),
1172 : gage 4244 CGI::small("Leave blank to use the name ". CGI::tt("webwork_COURSENAME"). "."),
1173 : sh002i 2719 ),
1174 :     );
1175 :     print CGI::end_table();
1176 :    
1177 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"delete_course", -value=>"Delete Course"));
1178 : sh002i 1960
1179 :     print CGI::end_form();
1180 :     }
1181 :    
1182 :     sub delete_course_validate {
1183 :     my ($self) = @_;
1184 :     my $r = $self->r;
1185 :     my $ce = $r->ce;
1186 :     #my $db = $r->db;
1187 :     #my $authz = $r->authz;
1188 :     my $urlpath = $r->urlpath;
1189 :    
1190 :     my $delete_courseID = $r->param("delete_courseID") || "";
1191 :     my $delete_sql_host = $r->param("delete_sql_host") || "";
1192 :     my $delete_sql_port = $r->param("delete_sql_port") || "";
1193 :     my $delete_sql_username = $r->param("delete_sql_username") || "";
1194 :     my $delete_sql_password = $r->param("delete_sql_password") || "";
1195 :     my $delete_sql_database = $r->param("delete_sql_database") || "";
1196 :    
1197 :     my @errors;
1198 :    
1199 :     if ($delete_courseID eq "") {
1200 :     push @errors, "You must specify a course name.";
1201 :     } elsif ($delete_courseID eq $urlpath->arg("courseID")) {
1202 :     push @errors, "You cannot delete the course you are currently using.";
1203 :     }
1204 :    
1205 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1206 :     $ce->{webworkDirs}->{root},
1207 :     $ce->{webworkURLs}->{root},
1208 :     $ce->{pg}->{directories}->{root},
1209 :     $delete_courseID,
1210 :     );
1211 :    
1212 :     if ($ce2->{dbLayoutName} eq "sql") {
1213 :     push @errors, "You must specify the SQL admin username." if $delete_sql_username eq "";
1214 : sh002i 2189 #push @errors, "You must specify the SQL admin password." if $delete_sql_password eq "";
1215 :     #push @errors, "You must specify the SQL database name." if $delete_sql_database eq "";
1216 : sh002i 1960 }
1217 :    
1218 :     return @errors;
1219 :     }
1220 :    
1221 :     sub delete_course_confirm {
1222 :     my ($self) = @_;
1223 :     my $r = $self->r;
1224 :     my $ce = $r->ce;
1225 :     #my $db = $r->db;
1226 :     #my $authz = $r->authz;
1227 :     #my $urlpath = $r->urlpath;
1228 :    
1229 :     print CGI::h2("Delete Course");
1230 :    
1231 :     my $delete_courseID = $r->param("delete_courseID") || "";
1232 :     my $delete_sql_host = $r->param("delete_sql_host") || "";
1233 :     my $delete_sql_port = $r->param("delete_sql_port") || "";
1234 :     my $delete_sql_database = $r->param("delete_sql_database") || "";
1235 :    
1236 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1237 :     $ce->{webworkDirs}->{root},
1238 :     $ce->{webworkURLs}->{root},
1239 :     $ce->{pg}->{directories}->{root},
1240 :     $delete_courseID,
1241 :     );
1242 :    
1243 :     if ($ce2->{dbLayoutName} eq "sql") {
1244 :     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
1245 :     . "? All course files and data and the following database will be destroyed."
1246 :     . " There is no undo available.");
1247 :    
1248 :     print CGI::table({class=>"FormLayout"},
1249 : gage 4280 CGI::Tr({},
1250 : sh002i 1960 CGI::th({class=>"LeftHeader"}, "SQL Server Host:"),
1251 :     CGI::td($delete_sql_host || "system default"),
1252 : sh002i 1945 ),
1253 : gage 4280 CGI::Tr({},
1254 : sh002i 1960 CGI::th({class=>"LeftHeader"}, "SQL Server Port:"),
1255 :     CGI::td($delete_sql_port || "system default"),
1256 :     ),
1257 : gage 4280 CGI::Tr({},
1258 : sh002i 1960 CGI::th({class=>"LeftHeader"}, "SQL Database Name:"),
1259 : sh002i 2189 CGI::td($delete_sql_database || "webwork_$delete_courseID"),
1260 : sh002i 1960 ),
1261 : sh002i 1945 );
1262 : sh002i 1960 } else {
1263 :     print CGI::p("Are you sure you want to delete the course " . CGI::b($delete_courseID)
1264 :     . "? All course files and data will be destroyed. There is no undo available.");
1265 : sh002i 1945 }
1266 :    
1267 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
1268 : sh002i 1960 print $self->hidden_authen_fields;
1269 :     print $self->hidden_fields("subDisplay");
1270 :     print $self->hidden_fields(qw/delete_courseID delete_sql_host delete_sql_port delete_sql_username delete_sql_password delete_sql_database/);
1271 :    
1272 :     print CGI::p({style=>"text-align: center"},
1273 : gage 4244 CGI::submit(-name=>"decline_delete_course", -label=>"Don't delete"),
1274 : sh002i 1960 "&nbsp;",
1275 : gage 4244 CGI::submit(-name=>"confirm_delete_course", -label=>"Delete"),
1276 : sh002i 1960 );
1277 :    
1278 :     print CGI::end_form();
1279 :     }
1280 :    
1281 :     sub do_delete_course {
1282 :     my ($self) = @_;
1283 :     my $r = $self->r;
1284 :     my $ce = $r->ce;
1285 : gage 4127 my $db = $r->db;
1286 : sh002i 1960 #my $authz = $r->authz;
1287 :     #my $urlpath = $r->urlpath;
1288 :    
1289 :     my $delete_courseID = $r->param("delete_courseID") || "";
1290 :     my $delete_sql_host = $r->param("delete_sql_host") || "";
1291 :     my $delete_sql_port = $r->param("delete_sql_port") || "";
1292 :     my $delete_sql_username = $r->param("delete_sql_username") || "";
1293 :     my $delete_sql_password = $r->param("delete_sql_password") || "";
1294 :     my $delete_sql_database = $r->param("delete_sql_database") || "";
1295 :    
1296 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1297 :     $ce->{webworkDirs}->{root},
1298 :     $ce->{webworkURLs}->{root},
1299 :     $ce->{pg}->{directories}->{root},
1300 :     $delete_courseID,
1301 :     );
1302 :    
1303 :     my %dbOptions;
1304 :     if ($ce2->{dbLayoutName} eq "sql") {
1305 :     $dbOptions{host} = $delete_sql_host if $delete_sql_host ne "";
1306 :     $dbOptions{port} = $delete_sql_port if $delete_sql_port ne "";
1307 :     $dbOptions{username} = $delete_sql_username;
1308 :     $dbOptions{password} = $delete_sql_password;
1309 : sh002i 2189 $dbOptions{database} = $delete_sql_database || "webwork_$delete_courseID";
1310 : sh002i 1960 }
1311 :    
1312 :     eval {
1313 :     deleteCourse(
1314 :     courseID => $delete_courseID,
1315 :     ce => $ce2,
1316 :     dbOptions => \%dbOptions,
1317 :     );
1318 :     };
1319 :    
1320 :     if ($@) {
1321 :     my $error = $@;
1322 :     print CGI::div({class=>"ResultsWithError"},
1323 :     CGI::p("An error occured while deleting the course $delete_courseID:"),
1324 :     CGI::tt(CGI::escapeHTML($error)),
1325 :     );
1326 :     } else {
1327 : gage 4127 # mark the contact person in the admin course as dropped.
1328 :     # find the contact person for the course by searching the admin classlist.
1329 :     my @contacts = grep /_$delete_courseID$/, $db->listUsers;
1330 :     die "Incorrect number of contacts for the course $delete_courseID". join(" ", @contacts) if @contacts !=1;
1331 :     #warn "contacts", join(" ", @contacts);
1332 :     #my $composite_id = "${add_initial_userID}_${add_courseID}";
1333 :     my $composite_id = $contacts[0];
1334 :    
1335 :     # mark the contact person as dropped.
1336 :     my $User = $db->getUser($composite_id);
1337 :     my $status_name = 'Drop';
1338 :     my $status_value = ($ce->status_name_to_abbrevs($status_name))[0];
1339 :     $User->status($status_value);
1340 :     $db->putUser($User);
1341 :    
1342 : sh002i 1960 print CGI::div({class=>"ResultsWithoutError"},
1343 : sh002i 2378 CGI::p("Successfully deleted the course $delete_courseID."),
1344 : sh002i 1960 );
1345 : gage 2242 writeLog($ce, "hosted_courses", join("\t",
1346 :     "\tDeleted",
1347 :     "",
1348 :     "",
1349 :     $delete_courseID,
1350 :     ));
1351 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
1352 : sh002i 1945 print $self->hidden_authen_fields;
1353 : sh002i 1960 print $self->hidden_fields("subDisplay");
1354 : sh002i 1945
1355 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"decline_delete_course", -value=>"OK"),);
1356 : sh002i 1945
1357 : sh002i 1960 print CGI::end_form();
1358 : sh002i 1945 }
1359 :     }
1360 :    
1361 : sh002i 1985 ################################################################################
1362 :    
1363 :     sub export_database_form {
1364 :     my ($self) = @_;
1365 :     my $r = $self->r;
1366 :     my $ce = $r->ce;
1367 :     #my $db = $r->db;
1368 :     #my $authz = $r->authz;
1369 :     #my $urlpath = $r->urlpath;
1370 :    
1371 :     my @tables = keys %{$ce->{dbLayout}};
1372 :    
1373 :     my $export_courseID = $r->param("export_courseID") || "";
1374 :     my @export_tables = $r->param("export_tables");
1375 : gage 3235
1376 : sh002i 1985 @export_tables = @tables unless @export_tables;
1377 :    
1378 :     my @courseIDs = listCourses($ce);
1379 : gage 3434 @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs; #make sort case insensitive
1380 : sh002i 1985
1381 :     my %courseLabels; # records... heh.
1382 :     foreach my $courseID (@courseIDs) {
1383 :     my $tempCE = WeBWorK::CourseEnvironment->new(
1384 :     $ce->{webworkDirs}->{root},
1385 :     $ce->{webworkURLs}->{root},
1386 :     $ce->{pg}->{directories}->{root},
1387 :     $courseID,
1388 :     );
1389 :     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
1390 :     }
1391 :    
1392 :     print CGI::h2("Export Database");
1393 :    
1394 : gage 4244 print CGI::start_form(-method=>"GET", -action=>$r->uri);
1395 : sh002i 1985 print $self->hidden_authen_fields;
1396 :     print $self->hidden_fields("subDisplay");
1397 :    
1398 : gage 4280 print CGI::p({},"Select a course to export the course's database. Please note
1399 : sh002i 2844 that exporting can take a very long time for a large course. If you have
1400 :     shell access to the WeBWorK server, you may use the ", CGI::code("wwdb"), "
1401 :     utility instead.");
1402 : sh002i 1985
1403 :     print CGI::table({class=>"FormLayout"},
1404 : gage 4280 CGI::Tr({},
1405 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Course Name:"),
1406 :     CGI::td(
1407 :     CGI::scrolling_list(
1408 :     -name => "export_courseID",
1409 :     -values => \@courseIDs,
1410 :     -default => $export_courseID,
1411 :     -size => 10,
1412 : gage 3235 -multiple => 1,
1413 : sh002i 1985 -labels => \%courseLabels,
1414 :     ),
1415 :     ),
1416 :     ),
1417 : gage 4280 CGI::Tr({},
1418 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Tables to Export:"),
1419 : gage 4280 CGI::td({},
1420 : sh002i 1985 CGI::checkbox_group(
1421 :     -name => "export_tables",
1422 :     -values => \@tables,
1423 :     -default => \@export_tables,
1424 :     -linebreak => 1,
1425 :     ),
1426 :     ),
1427 :     ),
1428 :     );
1429 :    
1430 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"export_database", -value=>"Export Database"));
1431 : sh002i 1985
1432 :     print CGI::end_form();
1433 :     }
1434 :    
1435 :     sub export_database_validate {
1436 :     my ($self) = @_;
1437 :     my $r = $self->r;
1438 :     #my $ce = $r->ce;
1439 :     #my $db = $r->db;
1440 :     #my $authz = $r->authz;
1441 :     #my $urlpath = $r->urlpath;
1442 :    
1443 : gage 3235 my @export_courseID = $r->param("export_courseID") || ();
1444 : sh002i 1985 my @export_tables = $r->param("export_tables");
1445 : gage 3235
1446 : sh002i 1985 my @errors;
1447 : gage 3235
1448 :     unless ( @export_courseID) {
1449 :     push @errors, "You must specify at least one course name.";
1450 : sh002i 1985 }
1451 :    
1452 :     unless (@export_tables) {
1453 :     push @errors, "You must specify at least one table to export.";
1454 :     }
1455 :    
1456 :     return @errors;
1457 :     }
1458 :    
1459 :     sub do_export_database {
1460 :     my ($self) = @_;
1461 :     my $r = $self->r;
1462 :     my $ce = $r->ce;
1463 :     #my $db = $r->db;
1464 :     #my $authz = $r->authz;
1465 :     my $urlpath = $r->urlpath;
1466 :    
1467 : gage 3235 my @export_courseID = $r->param("export_courseID");
1468 : sh002i 1985 my @export_tables = $r->param("export_tables");
1469 :    
1470 : gage 3235 foreach my $export_courseID (@export_courseID) {
1471 :    
1472 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1473 :     $ce->{webworkDirs}->{root},
1474 :     $ce->{webworkURLs}->{root},
1475 :     $ce->{pg}->{directories}->{root},
1476 :     $export_courseID,
1477 :     );
1478 :    
1479 :     my $db2 = new WeBWorK::DB($ce2->{dbLayout});
1480 :    
1481 :     #my ($fh, $export_file) = tempfile("db_export_XXXXXX", DIR => $ce->{webworkDirs}->{tmp});
1482 :     #my ($random_chars) = $export_file =~ m/db_export_(\w+)$/;
1483 :     # export to the admin/templates directory
1484 :     my $exportFileName = "$export_courseID.exported.xml";
1485 :     my $exportFilePath = $ce->{courseDirs}->{templates}."/$exportFileName";
1486 :     # get a unique name
1487 :     my $number =1;
1488 :     while (-e "$exportFilePath.$number.gz") {
1489 :     $number++;
1490 :     last if $number>9;
1491 :     }
1492 :     if ($number<=9 ) {
1493 :     $exportFilePath = "$exportFilePath.$number";
1494 :     $exportFileName = "$exportFileName.$number";
1495 :     } else {
1496 :     $self->addbadmessage(CGI::p("There are more than 9 exported files for this course! Please
1497 :     remove some of these files."));
1498 :     $exportFilePath = "$exportFilePath.999";
1499 :     $exportFileName = "$exportFileName.999";
1500 :     }
1501 : sh002i 1985
1502 : gage 3235 my $outputFileHandle = new IO::File(">$exportFilePath") or warn "Unable to create $exportFilePath";
1503 : sh002i 1985
1504 : gage 3235 my @errors;
1505 :     eval {
1506 :     @errors = dbExport(
1507 :     db => $db2,
1508 :     #xml => $fh,
1509 :     xml => $outputFileHandle,
1510 :     tables => \@export_tables,
1511 :     );
1512 :     };
1513 :    
1514 :     $outputFileHandle->close();
1515 : sh002i 1985
1516 : gage 3235 my $gzipMessage = system( 'gzip', $exportFilePath);
1517 :     if ( !$gzipMessage ) {
1518 :     $self->addgoodmessage(CGI::p( "Database saved to templates/$exportFileName.gzip.
1519 :     You may download it with the file manager."));
1520 :     } else {
1521 :     $self->addbadmessage(CGI::p( "Failed to gzip file $exportFilePath"));
1522 :     }
1523 :     unlink $exportFilePath;
1524 :     } # end export of one course
1525 : sh002i 2478 #push @errors, "Fatal exception: $@" if $@;
1526 :     #
1527 :     #if (@errors) {
1528 :     # print CGI::div({class=>"ResultsWithError"},
1529 :     # CGI::p("An error occured while exporting the database of course $export_courseID:"),
1530 :     # CGI::ul(CGI::li(\@errors)),
1531 :     # );
1532 :     #} else {
1533 :     # print CGI::div({class=>"ResultsWithoutError"},
1534 :     # CGI::p("Export succeeded."),
1535 :     # );
1536 :     #
1537 :     # print CGI::div({style=>"text-align: center"},
1538 :     # CGI::a({href=>$self->systemLink($urlpath, params=>{download_exported_database=>$random_chars, export_courseID=>undef})}, "Download Exported Database"),
1539 :     # );
1540 :     #}
1541 : sh002i 1985 }
1542 :    
1543 :     ################################################################################
1544 :    
1545 :     sub import_database_form {
1546 :     my ($self) = @_;
1547 :     my $r = $self->r;
1548 :     my $ce = $r->ce;
1549 :     #my $db = $r->db;
1550 :     #my $authz = $r->authz;
1551 :     #my $urlpath = $r->urlpath;
1552 :    
1553 :     my @tables = keys %{$ce->{dbLayout}};
1554 :    
1555 :     my $import_file = $r->param("import_file") || "";
1556 :     my $import_courseID = $r->param("import_courseID") || "";
1557 :     my @import_tables = $r->param("import_tables");
1558 :     my $import_conflict = $r->param("import_conflict") || "skip";
1559 :    
1560 :     @import_tables = @tables unless @import_tables;
1561 :    
1562 :     my @courseIDs = listCourses($ce);
1563 : gage 3434 @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs; #make sort case insensitive
1564 : gage 2045
1565 : sh002i 1985
1566 :     my %courseLabels; # records... heh.
1567 :     foreach my $courseID (@courseIDs) {
1568 :     my $tempCE = WeBWorK::CourseEnvironment->new(
1569 :     $ce->{webworkDirs}->{root},
1570 :     $ce->{webworkURLs}->{root},
1571 :     $ce->{pg}->{directories}->{root},
1572 :     $courseID,
1573 :     );
1574 :     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
1575 :     }
1576 :    
1577 : gage 3235 # find databases:
1578 :     my $templatesDir = $ce->{courseDirs}->{templates};
1579 :     my %probLibs = %{ $r->ce->{courseFiles}->{problibs} };
1580 :     my $exempt_dirs = join("|", keys %probLibs);
1581 :    
1582 :     my @databaseFiles = listFilesRecursive(
1583 :     $templatesDir,
1584 :     qr/.\.exported\.xml\.\d*\.gz$/, # match these files #FIXME this is too restricive!!
1585 :     qr/^(?:$exempt_dirs|CVS)$/, # prune these directories
1586 :     0, # match against file name only
1587 :     1, # prune against path relative to $templatesDir
1588 :     );
1589 :    
1590 :     my %databaseLabels = map { ($_ => $_) } @databaseFiles;
1591 :    
1592 :     #######
1593 :    
1594 : sh002i 1985 print CGI::h2("Import Database");
1595 :    
1596 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri, -enctype=>&CGI::MULTIPART);
1597 : sh002i 1985 print $self->hidden_authen_fields;
1598 :     print $self->hidden_fields("subDisplay");
1599 :    
1600 :     print CGI::table({class=>"FormLayout"},
1601 : gage 4280 CGI::Tr({},
1602 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Database XML File:"),
1603 :     CGI::td(
1604 : gage 3235 CGI::scrolling_list(
1605 : sh002i 1985 -name => "import_file",
1606 : gage 3235 -values => \@databaseFiles,
1607 :     -default => undef,
1608 :     -size => 10,
1609 :     -multiple => 0,
1610 :     -labels => \%databaseLabels,
1611 : sh002i 1985 ),
1612 : gage 3235
1613 :     )
1614 : sh002i 1985 ),
1615 : gage 4280 CGI::Tr({},
1616 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Tables to Import:"),
1617 :     CGI::td(
1618 :     CGI::checkbox_group(
1619 :     -name => "import_tables",
1620 :     -values => \@tables,
1621 :     -default => \@import_tables,
1622 :     -linebreak => 1,
1623 :     ),
1624 :     ),
1625 :     ),
1626 : gage 4280 CGI::Tr({},
1627 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Import into Course:"),
1628 :     CGI::td(
1629 :     CGI::scrolling_list(
1630 :     -name => "import_courseID",
1631 :     -values => \@courseIDs,
1632 :     -default => $import_courseID,
1633 :     -size => 10,
1634 :     -multiple => 0,
1635 :     -labels => \%courseLabels,
1636 :     ),
1637 :     ),
1638 :     ),
1639 : gage 4280 CGI::Tr({},
1640 : sh002i 1985 CGI::th({class=>"LeftHeader"}, "Conflicts:"),
1641 :     CGI::td(
1642 :     CGI::radio_group(
1643 :     -name => "import_conflict",
1644 :     -values => [qw/skip replace/],
1645 :     -default => $import_conflict,
1646 :     -linebreak=>'true',
1647 :     -labels => {
1648 :     skip => "Skip duplicate records",
1649 :     replace => "Replace duplicate records",
1650 :     },
1651 :     ),
1652 :     ),
1653 :     ),
1654 :     );
1655 :    
1656 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"import_database", -value=>"Import Database"));
1657 : sh002i 1985
1658 :     print CGI::end_form();
1659 :     }
1660 :    
1661 :     sub import_database_validate {
1662 :     my ($self) = @_;
1663 :     my $r = $self->r;
1664 :     #my $ce = $r->ce;
1665 :     #my $db = $r->db;
1666 :     #my $authz = $r->authz;
1667 :     #my $urlpath = $r->urlpath;
1668 :    
1669 :     my $import_file = $r->param("import_file") || "";
1670 :     my $import_courseID = $r->param("import_courseID") || "";
1671 :     my @import_tables = $r->param("import_tables");
1672 :     #my $import_conflict = $r->param("import_conflict") || "skip"; # not checked
1673 :    
1674 :     my @errors;
1675 :    
1676 :     if ($import_file eq "") {
1677 : gage 3235 push @errors, "You must specify a database file to import.";
1678 : sh002i 1985 }
1679 :    
1680 :     if ($import_courseID eq "") {
1681 :     push @errors, "You must specify a course name.";
1682 :     }
1683 :    
1684 :     unless (@import_tables) {
1685 :     push @errors, "You must specify at least one table to import.";
1686 :     }
1687 :    
1688 :     return @errors;
1689 :     }
1690 :    
1691 :     sub do_import_database {
1692 :     my ($self) = @_;
1693 :     my $r = $self->r;
1694 :     my $ce = $r->ce;
1695 :     #my $db = $r->db;
1696 :     #my $authz = $r->authz;
1697 :     my $urlpath = $r->urlpath;
1698 :    
1699 :     my $import_file = $r->param("import_file");
1700 :     my $import_courseID = $r->param("import_courseID");
1701 :     my @import_tables = $r->param("import_tables");
1702 :     my $import_conflict = $r->param("import_conflict") || "skip"; # need default -- not checked above
1703 :    
1704 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1705 :     $ce->{webworkDirs}->{root},
1706 :     $ce->{webworkURLs}->{root},
1707 :     $ce->{pg}->{directories}->{root},
1708 :     $import_courseID,
1709 :     );
1710 :    
1711 :     my $db2 = new WeBWorK::DB($ce2->{dbLayout});
1712 :    
1713 : gage 3235 # locate file
1714 :     my $templateDir = $ce->{courseDirs}->{templates};
1715 :     my $filePath = "$templateDir/$import_file";
1716 :    
1717 :     my $gunzipMessage = system( 'gunzip', $filePath);
1718 :     #FIXME
1719 :     #warn "gunzip ", $gunzipMessage;
1720 :     $filePath =~ s/\.gz$//;
1721 :     #warn "new file path is $filePath";
1722 :     my $fileHandle = new IO::File("<$filePath");
1723 : sh002i 1985 # retrieve upload from upload cache
1724 : gage 3235 # my ($id, $hash) = split /\s+/, $import_file;
1725 :     # my $upload = WeBWorK::Upload->retrieve($id, $hash,
1726 :     # dir => $ce->{webworkDirs}->{uploadCache}
1727 :     # );
1728 : sh002i 1985
1729 :     my @errors;
1730 :    
1731 :     eval {
1732 :     @errors = dbImport(
1733 :     db => $db2,
1734 : gage 3235 # xml => $upload->fileHandle,
1735 :     xml => $fileHandle,
1736 : sh002i 1985 tables => \@import_tables,
1737 :     conflict => $import_conflict,
1738 :     );
1739 :     };
1740 :    
1741 :     push @errors, "Fatal exception: $@" if $@;
1742 : gage 3235 push @errors, $gunzipMessage if $gunzipMessage;
1743 : sh002i 1985
1744 :     if (@errors) {
1745 :     print CGI::div({class=>"ResultsWithError"},
1746 :     CGI::p("An error occured while importing the database of course $import_courseID:"),
1747 :     CGI::ul(CGI::li(\@errors)),
1748 :     );
1749 :     } else {
1750 :     print CGI::div({class=>"ResultsWithoutError"},
1751 :     CGI::p("Import succeeded."),
1752 :     );
1753 :     }
1754 :     }
1755 : gage 3528 ##########################################################################
1756 :     sub archive_course_form {
1757 :     my ($self) = @_;
1758 :     my $r = $self->r;
1759 :     my $ce = $r->ce;
1760 :     #my $db = $r->db;
1761 :     #my $authz = $r->authz;
1762 :     #my $urlpath = $r->urlpath;
1763 :    
1764 :     my $archive_courseID = $r->param("archive_courseID") || "";
1765 :     my $archive_sql_host = $r->param("archive_sql_host") || "";
1766 :     my $archive_sql_port = $r->param("archive_sql_port") || "";
1767 :     my $archive_sql_username = $r->param("archive_sql_username") || "";
1768 :     my $archive_sql_password = $r->param("archive_sql_password") || "";
1769 :     my $archive_sql_database = $r->param("archive_sql_database") || "";
1770 :    
1771 :     my @courseIDs = listCourses($ce);
1772 :     @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs; #make sort case insensitive
1773 :    
1774 :     my %courseLabels; # records... heh.
1775 :     foreach my $courseID (@courseIDs) {
1776 :     my $tempCE = WeBWorK::CourseEnvironment->new(
1777 :     $ce->{webworkDirs}->{root},
1778 :     $ce->{webworkURLs}->{root},
1779 :     $ce->{pg}->{directories}->{root},
1780 :     $courseID,
1781 :     );
1782 :     $courseLabels{$courseID} = "$courseID (" . $tempCE->{dbLayoutName} . ")";
1783 :     }
1784 :    
1785 :     print CGI::h2("archive Course");
1786 :    
1787 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
1788 : gage 3528 print $self->hidden_authen_fields;
1789 :     print $self->hidden_fields("subDisplay");
1790 :    
1791 :     print CGI::p("Select a course to archive.");
1792 :    
1793 :     print CGI::table({class=>"FormLayout"},
1794 : gage 4280 CGI::Tr({},
1795 : gage 3528 CGI::th({class=>"LeftHeader"}, "Course Name:"),
1796 :     CGI::td(
1797 :     CGI::scrolling_list(
1798 :     -name => "archive_courseID",
1799 :     -values => \@courseIDs,
1800 :     -default => $archive_courseID,
1801 :     -size => 10,
1802 :     -multiple => 0,
1803 :     -labels => \%courseLabels,
1804 :     ),
1805 :     ),
1806 : gage 4136
1807 : gage 3528 ),
1808 : gage 4280 CGI::Tr({},
1809 : gage 4136 CGI::th({class=>"LeftHeader"}, "Delete course:"),
1810 :     CGI::td({-style=>'color:red'}, CGI::checkbox({
1811 :     -name=>'delete_course',
1812 :     -checked=>0,
1813 :     -value => 1,
1814 :     -label =>'Delete course after archiving. Caution there is no undo!',
1815 :     },
1816 :     ),
1817 :     ),
1818 :     )
1819 : gage 3528 );
1820 :    
1821 :     print CGI::p(
1822 :     "Currently the archive facility is only available for mysql databases.
1823 :     It depends on the mysqldump application."
1824 :     );
1825 : gage 4129
1826 : gage 3528
1827 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"archive_course", -value=>"archive Course"));
1828 : gage 3528
1829 :     print CGI::end_form();
1830 :     }
1831 : sh002i 1985
1832 : gage 3528 sub archive_course_validate {
1833 :     my ($self) = @_;
1834 :     my $r = $self->r;
1835 :     my $ce = $r->ce;
1836 :     #my $db = $r->db;
1837 :     #my $authz = $r->authz;
1838 :     my $urlpath = $r->urlpath;
1839 :    
1840 :     my $archive_courseID = $r->param("archive_courseID") || "";
1841 :     my $archive_sql_host = $r->param("archive_sql_host") || "";
1842 :     my $archive_sql_port = $r->param("archive_sql_port") || "";
1843 :     my $archive_sql_username = $r->param("archive_sql_username") || "";
1844 :     my $archive_sql_password = $r->param("archive_sql_password") || "";
1845 :     my $archive_sql_database = $r->param("archive_sql_database") || "";
1846 :    
1847 :     my @errors;
1848 :    
1849 :     if ($archive_courseID eq "") {
1850 :     push @errors, "You must specify a course name.";
1851 :     } elsif ($archive_courseID eq $urlpath->arg("courseID")) {
1852 :     push @errors, "You cannot archive the course you are currently using.";
1853 :     }
1854 :    
1855 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1856 :     $ce->{webworkDirs}->{root},
1857 :     $ce->{webworkURLs}->{root},
1858 :     $ce->{pg}->{directories}->{root},
1859 :     $archive_courseID,
1860 :     );
1861 :    
1862 :     if ($ce2->{dbLayoutName} eq "sql") {
1863 :     push @errors, "You must specify the SQL admin username." if $archive_sql_username eq "";
1864 :     #push @errors, "You must specify the SQL admin password." if $archive_sql_password eq "";
1865 :     #push @errors, "You must specify the SQL database name." if $archive_sql_database eq "";
1866 :     }
1867 :    
1868 :     return @errors;
1869 :     }
1870 :    
1871 :     sub archive_course_confirm {
1872 :     my ($self) = @_;
1873 :     my $r = $self->r;
1874 :     my $ce = $r->ce;
1875 :     #my $db = $r->db;
1876 :     #my $authz = $r->authz;
1877 :     #my $urlpath = $r->urlpath;
1878 :    
1879 :     print CGI::h2("archive Course");
1880 :    
1881 :     my $archive_courseID = $r->param("archive_courseID") || "";
1882 :     my $archive_sql_host = $r->param("archive_sql_host") || "";
1883 :     my $archive_sql_port = $r->param("archive_sql_port") || "";
1884 :     my $archive_sql_database = $r->param("archive_sql_database") || "";
1885 : gage 4136 my $delete_course_flag = $r->param("delete_course") || "";
1886 : gage 3528 my $ce2 = WeBWorK::CourseEnvironment->new(
1887 :     $ce->{webworkDirs}->{root},
1888 :     $ce->{webworkURLs}->{root},
1889 :     $ce->{pg}->{directories}->{root},
1890 :     $archive_courseID,
1891 :     );
1892 :    
1893 : gage 4136 if ($ce2->{dbLayoutName} ) {
1894 : gage 3528 print CGI::p("Are you sure you want to archive the course " . CGI::b($archive_courseID)
1895 : gage 3621 . "? ");
1896 : gage 4136 print(CGI::p({-style=>'color:red; font-weight:bold'}, "Are you sure that you want to delete the course ".
1897 :     CGI::b($archive_courseID). " after archiving? This cannot be undone!")) if $delete_course_flag;
1898 : gage 3528
1899 : gage 4136
1900 : gage 3528 }
1901 :    
1902 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
1903 : gage 3528 print $self->hidden_authen_fields;
1904 :     print $self->hidden_fields("subDisplay");
1905 : gage 4136 print $self->hidden_fields(qw/archive_courseID archive_sql_host archive_sql_port archive_sql_username archive_sql_password archive_sql_database delete_course/);
1906 : gage 3528
1907 :     print CGI::p({style=>"text-align: center"},
1908 : gage 4244 CGI::submit(-name=>"decline_archive_course", -value=>"Don't archive"),
1909 : gage 3528 "&nbsp;",
1910 : gage 4244 CGI::submit(-name=>"confirm_archive_course", -value=>"archive"),
1911 : gage 3528 );
1912 :    
1913 :     print CGI::end_form();
1914 :     }
1915 :    
1916 :     sub do_archive_course {
1917 :     my ($self) = @_;
1918 :     my $r = $self->r;
1919 :     my $ce = $r->ce;
1920 : gage 4136 my $db = $r->db;
1921 : gage 3528 #my $authz = $r->authz;
1922 :     #my $urlpath = $r->urlpath;
1923 :    
1924 :     my $archive_courseID = $r->param("archive_courseID") || "";
1925 :     my $archive_sql_host = $r->param("archive_sql_host") || "";
1926 :     my $archive_sql_port = $r->param("archive_sql_port") || "";
1927 :     my $archive_sql_username = $r->param("archive_sql_username") || "";
1928 :     my $archive_sql_password = $r->param("archive_sql_password") || "";
1929 :     my $archive_sql_database = $r->param("archive_sql_database") || "";
1930 : gage 4136 my $delete_course_flag = $r->param("delete_course") || "";
1931 : gage 3528
1932 :     my $ce2 = WeBWorK::CourseEnvironment->new(
1933 :     $ce->{webworkDirs}->{root},
1934 :     $ce->{webworkURLs}->{root},
1935 :     $ce->{pg}->{directories}->{root},
1936 :     $archive_courseID,
1937 :     );
1938 :    
1939 :     my %dbOptions;
1940 :     if ($ce2->{dbLayoutName} eq "sql") {
1941 :     $dbOptions{host} = $archive_sql_host if $archive_sql_host ne "";
1942 :     $dbOptions{port} = $archive_sql_port if $archive_sql_port ne "";
1943 :     $dbOptions{username} = $archive_sql_username;
1944 :     $dbOptions{password} = $archive_sql_password;
1945 :     $dbOptions{database} = $archive_sql_database || "webwork_$archive_courseID";
1946 :     }
1947 :    
1948 :     eval {
1949 :     archiveCourse(
1950 :     courseID => $archive_courseID,
1951 :     ce => $ce2,
1952 :     dbOptions => \%dbOptions,
1953 :     );
1954 :     };
1955 :    
1956 :     if ($@) {
1957 :     my $error = $@;
1958 :     print CGI::div({class=>"ResultsWithError"},
1959 :     CGI::p("An error occured while archiving the course $archive_courseID:"),
1960 :     CGI::tt(CGI::escapeHTML($error)),
1961 :     );
1962 :     } else {
1963 :     print CGI::div({class=>"ResultsWithoutError"},
1964 :     CGI::p("Successfully archived the course $archive_courseID"),
1965 :     );
1966 :     writeLog($ce, "hosted_courses", join("\t",
1967 :     "\tarchived",
1968 :     "",
1969 :     "",
1970 :     $archive_courseID,
1971 :     ));
1972 : gage 4136
1973 :     if ($delete_course_flag) {
1974 :     eval {
1975 :     deleteCourse(
1976 :     courseID => $archive_courseID,
1977 :     ce => $ce2,
1978 :     dbOptions => \%dbOptions,
1979 :     );
1980 :     };
1981 :    
1982 :     if ($@) {
1983 :     my $error = $@;
1984 :     print CGI::div({class=>"ResultsWithError"},
1985 :     CGI::p("An error occured while deleting the course $archive_courseID:"),
1986 :     CGI::tt(CGI::escapeHTML($error)),
1987 :     );
1988 :     } else {
1989 :     # mark the contact person in the admin course as dropped.
1990 :     # find the contact person for the course by searching the admin classlist.
1991 :     my @contacts = grep /_$archive_courseID$/, $db->listUsers;
1992 :     die "Incorrect number of contacts for the course $archive_courseID". join(" ", @contacts) if @contacts !=1;
1993 :     #warn "contacts", join(" ", @contacts);
1994 :     #my $composite_id = "${add_initial_userID}_${add_courseID}";
1995 :     my $composite_id = $contacts[0];
1996 :    
1997 :     # mark the contact person as dropped.
1998 :     my $User = $db->getUser($composite_id);
1999 :     my $status_name = 'Drop';
2000 :     my $status_value = ($ce->status_name_to_abbrevs($status_name))[0];
2001 :     $User->status($status_value);
2002 :     $db->putUser($User);
2003 :    
2004 :     print CGI::div({class=>"ResultsWithoutError"},
2005 :     CGI::p("Successfully deleted the course $archive_courseID."),
2006 :     );
2007 :     }
2008 :    
2009 :    
2010 :     }
2011 :    
2012 : gage 4244 # print CGI::start_form(-method=>"POST", -action=>$r->uri);
2013 : gage 4129 # print $self->hidden_authen_fields;
2014 :     # print $self->hidden_fields("subDisplay");
2015 :     #
2016 :     # print CGI::p({style=>"text-align: center"}, CGI::submit("decline_archive_course", "OK"),);
2017 :     #
2018 :     # print CGI::end_form();
2019 : gage 3528 }
2020 :     }
2021 : gage 4129 ##########################################################################
2022 :     sub unarchive_course_form {
2023 :     my ($self) = @_;
2024 :     my $r = $self->r;
2025 :     my $ce = $r->ce;
2026 :     #my $db = $r->db;
2027 :     #my $authz = $r->authz;
2028 :     #my $urlpath = $r->urlpath;
2029 :    
2030 :     my $unarchive_courseID = $r->param("unarchive_courseID") || "";
2031 :     my $unarchive_sql_host = $r->param("unarchive_sql_host") || "";
2032 :     my $unarchive_sql_port = $r->param("unarchive_sql_port") || "";
2033 :     my $unarchive_sql_username = $r->param("unarchive_sql_username") || "";
2034 :     my $unarchive_sql_password = $r->param("unarchive_sql_password") || "";
2035 :     my $unarchive_sql_database = $r->param("unarchive_sql_database") || "";
2036 :    
2037 :     # First find courses which have been archived.
2038 :     my @courseIDs = listArchivedCourses($ce);
2039 :     @courseIDs = sort {lc($a) cmp lc ($b) } @courseIDs; #make sort case insensitive
2040 :    
2041 :     my %courseLabels; # records... heh.
2042 :     foreach my $courseID (@courseIDs) {
2043 :     $courseLabels{$courseID} = $courseID;
2044 :     }
2045 :    
2046 :     print CGI::h2("Unarchive Course -- not yet operational");
2047 :    
2048 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
2049 : gage 4129 print $self->hidden_authen_fields;
2050 :     print $self->hidden_fields("subDisplay");
2051 :    
2052 :     print CGI::p("Select a course to unarchive.");
2053 :    
2054 :     print CGI::table({class=>"FormLayout"},
2055 : gage 4280 CGI::Tr({},
2056 : gage 4129 CGI::th({class=>"LeftHeader"}, "Course Name:"),
2057 :     CGI::td(
2058 :     CGI::scrolling_list(
2059 :     -name => "unarchive_courseID",
2060 :     -values => \@courseIDs,
2061 :     -default => $unarchive_courseID,
2062 :     -size => 10,
2063 :     -multiple => 0,
2064 :     -labels => \%courseLabels,
2065 :     ),
2066 :     ),
2067 :     ),
2068 :     );
2069 :    
2070 :     print CGI::p(
2071 :     "Currently the unarchive facility is only available for mysql databases.
2072 :     It depends on the mysqldump application."
2073 :     );
2074 : gage 3528
2075 : gage 4129
2076 : gage 4244 print CGI::p({style=>"text-align: center"}, CGI::submit(-name=>"unarchive_course", -value=>"Unarchive Course"));
2077 : gage 4129
2078 :     print CGI::end_form();
2079 :     }
2080 :    
2081 :     sub unarchive_course_validate {
2082 :     my ($self) = @_;
2083 :     my $r = $self->r;
2084 :     my $ce = $r->ce;
2085 :     #my $db = $r->db;
2086 :     #my $authz = $r->authz;
2087 :     my $urlpath = $r->urlpath;
2088 :    
2089 :     my $unarchive_courseID = $r->param("unarchive_courseID") || "";
2090 :     my $unarchive_sql_host = $r->param("unarchive_sql_host") || "";
2091 :     my $unarchive_sql_port = $r->param("unarchive_sql_port") || "";
2092 :     my $unarchive_sql_username = $r->param("unarchive_sql_username") || "";
2093 :     my $unarchive_sql_password = $r->param("unarchive_sql_password") || "";
2094 :     my $unarchive_sql_database = $r->param("unarchive_sql_database") || "";
2095 :    
2096 :     my @errors;
2097 :    
2098 :     my $new_courseID = $unarchive_courseID; $new_courseID =~ s/\.tar\.gz$//;
2099 :    
2100 :     if ($new_courseID eq "") {
2101 :     push @errors, "You must specify a course name.";
2102 :     } elsif ( -d $ce->{webworkDirs}->{courses}."/$new_courseID" ) {
2103 :     #Check that a directory for this course doesn't already exist
2104 :     push @errors, "A directory already exists with the name $new_courseID.
2105 :     You must first delete this existing course before you can unarchive.";
2106 :     }
2107 :    
2108 :    
2109 :    
2110 :     return @errors;
2111 :     }
2112 :    
2113 :     sub unarchive_course_confirm {
2114 :     my ($self) = @_;
2115 :     my $r = $self->r;
2116 :     my $ce = $r->ce;
2117 :     #my $db = $r->db;
2118 :     #my $authz = $r->authz;
2119 :     #my $urlpath = $r->urlpath;
2120 :    
2121 :     print CGI::h2("Unarchive Course");
2122 :    
2123 :     my $unarchive_courseID = $r->param("unarchive_courseID") || "";
2124 :     my $unarchive_sql_host = $r->param("unarchive_sql_host") || "";
2125 :     my $unarchive_sql_port = $r->param("unarchive_sql_port") || "";
2126 :     my $unarchive_sql_database = $r->param("unarchive_sql_database") || "";
2127 :    
2128 :     my $new_courseID = $unarchive_courseID; $new_courseID =~ s/\.tar\.gz$//;
2129 :    
2130 :    
2131 :    
2132 : gage 4244 print CGI::start_form(-method=>"POST", -action=>$r->uri);
2133 : gage 4129 print CGI::p($unarchive_courseID," to course ",
2134 :     CGI::input({-name=>'new_courseID', -value=>$new_courseID})
2135 :     );
2136 :    
2137 :     print $self->hidden_authen_fields;
2138 :     print $self->hidden_fields("subDisplay");
2139 :     print $self->hidden_fields(qw/unarchive_courseID
2140 :     unarchive_sql_host
2141 :     unarchive_sql_port
2142 :     unarchive_sql_username
2143 :     unarchive_sql_password
2144 :     unarchive_sql_database/);
2145 :    
2146 :     print CGI::p({style=>"text-align: center"},
2147 : gage 4244 CGI::submit(-name=>"decline_unarchive_course", -value=>"Don't unarchive"),
2148 : gage 4129 "&nbsp;",
2149 : gage 4244 CGI::submit(-name=>"confirm_unarchive_course", -value=>"unarchive"),
2150 : gage 4129 );
2151 :    
2152 :     print CGI::end_form();
2153 :     }
2154 :    
2155 :     sub do_unarchive_course {
2156 :     my ($self) = @_;
2157 :     my $r = $self->r;
2158 :     my $ce = $r->ce;
2159 :     #my $db = $r->db;
2160 :     #my $authz = $r->authz;
2161 :     my $urlpath = $r->urlpath;
2162 :     my $new_courseID = $r->param("new_courseID") || "";
2163 :     my $unarchive_courseID = $r->param("unarchive_courseID") || "";
2164 :     my $unarchive_sql_host = $r->param("unarchive_sql_host") || "";
2165 :     my $unarchive_sql_port = $r->param("unarchive_sql_port") || "";
2166 :     my $unarchive_sql_username = $r->param("unarchive_sql_username") || "";
2167 :     my $unarchive_sql_password = $r->param("unarchive_sql_password") || "";
2168 :     my $unarchive_sql_database = $r->param("unarchive_sql_database") || "";
2169 :    
2170 :    
2171 :     my %dbOptions;
2172 :    
2173 :     eval {
2174 :     unarchiveCourse(
2175 :     courseID => $new_courseID,
2176 :     archivePath =>$ce->{webworkDirs}->{courses}."/$unarchive_courseID",
2177 :     ce => $ce , # $ce2,
2178 :     dbOptions => undef,
2179 :     );
2180 :     };
2181 :    
2182 :     if ($@) {
2183 :     my $error = $@;
2184 :     print CGI::div({class=>"ResultsWithError"},
2185 :     CGI::p("An error occured while archiving the course $unarchive_courseID:"),
2186 :     CGI::tt(CGI::escapeHTML($error)),
2187 :     );
2188 :     } else {
2189 :     print CGI::div({class=>"ResultsWithoutError"},
2190 :     CGI::p("Successfully unarchived $unarchive_courseID to the course $new_courseID"),
2191 :     );
2192 :     writeLog($ce, "hosted_courses", join("\t",
2193 :     "\tunarchived",
2194 :     "",
2195 :     "",
2196 :     "$unarchive_courseID to $new_courseID",
2197 :     ));
2198 :    
2199 :     my $newCoursePath = $urlpath->newFromModule("WeBWorK::ContentGenerator::ProblemSets",
2200 :     courseID => $new_courseID);
2201 :     my $newCourseURL = $self->systemLink($newCoursePath, authen => 0);
2202 :     print CGI::div({style=>"text-align: center"},
2203 :     CGI::a({href=>$newCourseURL}, "Log into $new_courseID"),
2204 :     );
2205 :     }
2206 :     }
2207 :    
2208 : gage 3528 ################################################################################
2209 : sh002i 1945 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9