| 1 | #!/usr/bin/env perl |
1 | #!/usr/bin/env perl |
| 2 | ################################################################################ |
2 | ################################################################################ |
| 3 | # WeBWorK Online Homework Delivery System |
3 | # WeBWorK Online Homework Delivery System |
| 4 | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ |
4 | # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ |
| 5 | # $CVSHeader: webwork2/bin/wwdb,v 1.12 2004/09/23 16:53:25 sh002i Exp $ |
5 | # $CVSHeader: webwork2/bin/ww_db_v2_to_v3,v 1.1 2004/11/25 05:50:51 sh002i Exp $ |
| 6 | # |
6 | # |
| 7 | # This program is free software; you can redistribute it and/or modify it under |
7 | # This program is free software; you can redistribute it and/or modify it under |
| 8 | # the terms of either: (a) the GNU General Public License as published by the |
8 | # the terms of either: (a) the GNU General Public License as published by the |
| 9 | # Free Software Foundation; either version 2, or (at your option) any later |
9 | # Free Software Foundation; either version 2, or (at your option) any later |
| 10 | # version, or (b) the "Artistic License" which comes with this package. |
10 | # version, or (b) the "Artistic License" which comes with this package. |
| … | |
… | |
| 75 | |
75 | |
| 76 | =over |
76 | =over |
| 77 | |
77 | |
| 78 | =item * |
78 | =item * |
| 79 | |
79 | |
|
|
80 | Roles created with the -r switch are created as system-wide roles. |
|
|
81 | |
|
|
82 | =item * |
|
|
83 | |
| 80 | Roles are created by observing the %permissionLevels hash in F<global.conf>, and |
84 | Roles are created by observing the %permissionLevels hash in F<global.conf>, and |
| 81 | collecting the privileges granted at each permission level into sets. Each set |
85 | collecting the privileges granted at each permission level into sets. Each set |
| 82 | of privileges becomes a WWDBv3 role record. |
86 | of privileges becomes a WWDBv3 role record. |
| 83 | |
87 | |
| 84 | =item * |
88 | =item * |
| 85 | |
89 | |
| 86 | When a role with the same set of permissions already exists in the WWDBv3 |
90 | When a role with the same set of permissions already exists in the WWDBv3 |
| 87 | database, a new one is not created. |
91 | database, a new one is not created. |
|
|
92 | |
|
|
93 | =back |
|
|
94 | |
|
|
95 | =head2 STATUSES |
|
|
96 | |
|
|
97 | =over |
|
|
98 | |
|
|
99 | =item * |
|
|
100 | |
|
|
101 | Statuses created with the -s switch are created as system-wide statuses. |
|
|
102 | |
|
|
103 | =item * |
|
|
104 | |
|
|
105 | Statuses are created by observing the %{$siteDefaults{status}} hash in |
|
|
106 | F<global.conf>, and |
|
|
107 | |
|
|
108 | =item * |
|
|
109 | |
|
|
110 | A status named "Enrolled" is imported into the database with the |
|
|
111 | C<allow_course_access>, C<include_in_assignment>, C<include_in_stats>, and |
|
|
112 | C<include_in_scoring> flags set. |
|
|
113 | |
|
|
114 | =item * |
|
|
115 | |
|
|
116 | A status named "Audit" is imported into the database with the |
|
|
117 | C<allow_course_access>, C<include_in_assignment>, and C<include_in_stats>, flags |
|
|
118 | set, and the C<include_in_scoring> flag unset. |
|
|
119 | |
|
|
120 | =item * |
|
|
121 | |
|
|
122 | A status named "Drop" is imported into the database with the |
|
|
123 | C<allow_course_access>, C<include_in_assignment>, C<include_in_stats>, and |
|
|
124 | C<include_in_scoring> flags unset. |
|
|
125 | |
|
|
126 | =item * |
|
|
127 | |
|
|
128 | Statuses with other names are imported into the database with the same flags set |
|
|
129 | as the "Enrolled" flag. |
| 88 | |
130 | |
| 89 | =back |
131 | =back |
| 90 | |
132 | |
| 91 | =head2 USERS |
133 | =head2 USERS |
| 92 | |
134 | |
| … | |
… | |
| 120 | use lib "$ENV{WEBWORK_ROOT}/lib"; |
162 | use lib "$ENV{WEBWORK_ROOT}/lib"; |
| 121 | use WeBWorK::CourseEnvironment; |
163 | use WeBWorK::CourseEnvironment; |
| 122 | use WeBWorK::DB; |
164 | use WeBWorK::DB; |
| 123 | use WeBWorK::DBv3; |
165 | use WeBWorK::DBv3; |
| 124 | |
166 | |
|
|
167 | # map statuses from course environment to sets of status privileges |
|
|
168 | use constant STATUS_MAP => { |
|
|
169 | Enrolled => { allow_course_access => 1, include_in_assignment => 1, include_in_stats => 1, include_in_scoring => 1 }, |
|
|
170 | Audit => { allow_course_access => 1, include_in_assignment => 1, include_in_stats => 1, include_in_scoring => 0 }, |
|
|
171 | Drop => { allow_course_access => 0, include_in_assignment => 0, include_in_stats => 0, include_in_scoring => 0 }, |
|
|
172 | }; |
|
|
173 | |
| 125 | our ($opt_c, $opt_r, $opt_s, $opt_u, $opt_v); |
174 | our ($opt_c, $opt_r, $opt_s, $opt_u, $opt_v); |
| 126 | getopts("crsuv"); |
175 | getopts("crsuv"); |
| 127 | |
176 | |
| 128 | sub debug { print STDERR @_ if $opt_v } |
177 | sub debug { print STDERR @_ if $opt_v } |
| 129 | sub usage { print STDERR "usage: $0 [-uv] course ...\n"; exit 1 } |
178 | sub usage { print STDERR "usage: $0 [-crsuv] course ...\n"; exit 1 } |
| 130 | |
179 | |
| 131 | main(@ARGV); |
180 | main(@ARGV); |
| 132 | |
181 | |
| 133 | sub main { |
182 | sub main { |
| 134 | my (@courseIDs) = @_; |
183 | my (@courseIDs) = @_; |
| … | |
… | |
| 140 | WeBWorK::DBv3::init($ce->{wwdbv3_settings}); |
189 | WeBWorK::DBv3::init($ce->{wwdbv3_settings}); |
| 141 | |
190 | |
| 142 | my %level_to_role_id = set_up_roles($ce->{permissionLevels}); |
191 | my %level_to_role_id = set_up_roles($ce->{permissionLevels}); |
| 143 | warn Dumper(\%level_to_role_id); |
192 | warn Dumper(\%level_to_role_id); |
| 144 | |
193 | |
| 145 | my %statuses = update_statuses($ce->{siteDefaults}{status}); |
194 | my %abbrev_to_status_id = set_up_statuses($ce->{siteDefaults}{status}); |
|
|
195 | warn Dumper(\%abbrev_to_status_id); |
| 146 | |
196 | |
| 147 | foreach my $courseID (@courseIDs) { |
197 | foreach my $courseID (@courseIDs) { |
| 148 | eval { copy_course_data($courseID) }; |
198 | eval { copy_course_data($courseID) }; |
| 149 | if ($@) { |
199 | if ($@) { |
| 150 | warn "An error occured while copying data from course '$courseID':\n\n$@\n\n"; |
200 | warn "An error occured while copying data from course '$courseID':\n\n$@\n\n"; |
| … | |
… | |
| 164 | my ($permissionLevels) = @_; |
214 | my ($permissionLevels) = @_; |
| 165 | my %permissionLevels = %$permissionLevels; |
215 | my %permissionLevels = %$permissionLevels; |
| 166 | |
216 | |
| 167 | my %level_to_role_id; |
217 | my %level_to_role_id; |
| 168 | |
218 | |
| 169 | # get all the levels mentioned in %permissionLevels, along with which |
219 | # reverse the permission levels hash, resulting in a hash mapping |
| 170 | # privileges are available at that level |
220 | # permissions levels to arrayrefs containing privileges |
| 171 | my %levels; |
221 | my %levels = reverse_hash(%permissionLevels); |
| 172 | foreach my $privilege (keys %permissionLevels) { |
|
|
| 173 | my $level = $permissionLevels{$privilege}; |
|
|
| 174 | if (defined $level) { |
|
|
| 175 | push @{ $levels{$level} }, $privilege; |
|
|
| 176 | } |
|
|
| 177 | } |
|
|
| 178 | |
|
|
| 179 | my @level_names = sort { $a <=> $b } keys %levels; |
|
|
| 180 | |
222 | |
| 181 | # copy up the privileges at each level to the next-higher level |
223 | # copy up the privileges at each level to the next-higher level |
| 182 | # also sort each level |
224 | # also sort each level |
|
|
225 | my @level_names = sort { $a <=> $b } keys %levels; |
| 183 | foreach my $i (0 .. $#level_names-1) { |
226 | foreach my $i (0 .. $#level_names-1) { |
| 184 | my $this_level = $level_names[$i]; |
227 | my $this_level = $level_names[$i]; |
| 185 | my $next_level = $level_names[$i+1]; |
228 | my $next_level = $level_names[$i+1]; |
| 186 | push @{ $levels{$next_level} }, @{ $levels{$this_level} }; |
229 | push @{ $levels{$next_level} }, @{ $levels{$this_level} }; |
| 187 | } |
230 | } |
| … | |
… | |
| 204 | my @role_privs = sort $Role->priv_list; |
247 | my @role_privs = sort $Role->priv_list; |
| 205 | |
248 | |
| 206 | foreach my $level (keys %levels) { |
249 | foreach my $level (keys %levels) { |
| 207 | if (listeq($levels{$level}, \@role_privs)) { |
250 | if (listeq($levels{$level}, \@role_privs)) { |
| 208 | debug("Permission level '$level' is already represented as role '", |
251 | debug("Permission level '$level' is already represented as role '", |
| 209 | $Role->name, "' -- skipping.\n"); |
252 | $Role->name, "' (ID $Role) -- skipping.\n"); |
| 210 | delete $levels{$level}; |
253 | delete $levels{$level}; |
| 211 | $level_to_role_id{$level} = $Role->id; |
254 | $level_to_role_id{$level} = $Role->id; |
| 212 | } |
255 | } |
| 213 | } |
256 | } |
| 214 | } |
257 | } |
| … | |
… | |
| 231 | my @privs = @{ $levels{$level} }; |
274 | my @privs = @{ $levels{$level} }; |
| 232 | |
275 | |
| 233 | my $Role = create WeBWorK::DBv3::Role({name => $name }); |
276 | my $Role = create WeBWorK::DBv3::Role({name => $name }); |
| 234 | $Role->priv_list(@privs); |
277 | $Role->priv_list(@privs); |
| 235 | $Role->update; |
278 | $Role->update; |
| 236 | debug("Added role '", $Role->name, "' with privileges '@privs'.\n"); |
279 | debug("Added role '", $Role->name, "' (ID $Role) with privileges '@privs'.\n"); |
| 237 | $level_to_role_id{$level} = $Role->id; |
280 | $level_to_role_id{$level} = $Role->id; |
| 238 | } |
281 | } |
| 239 | } else { |
282 | } else { |
| 240 | debug("Not updating role table (as per lack of -r switch).\n"); |
283 | debug("Not updating role table (as per lack of -r switch).\n"); |
| 241 | debug("I might run into users with permission levels that don't map to roles later.\n"); |
284 | debug("I might run into users with permission levels that don't map to roles later.\n"); |
| … | |
… | |
| 243 | |
286 | |
| 244 | return %level_to_role_id; |
287 | return %level_to_role_id; |
| 245 | } |
288 | } |
| 246 | |
289 | |
| 247 | sub set_up_statuses { |
290 | sub set_up_statuses { |
| 248 | my ($statuses) = @_; |
291 | my ($abbrevs) = @_; |
|
|
292 | my %abbrevs = %$abbrevs; |
|
|
293 | |
|
|
294 | my %abbrev_to_status_id; |
|
|
295 | |
|
|
296 | # reverse the statuses hash, resulting in a hash mapping statuses to |
|
|
297 | # arrayrefs containing abbreviations |
|
|
298 | my %statuses = reverse_hash(%abbrevs); |
|
|
299 | |
|
|
300 | # look at existing statuses to see if we can avoid adding some new ones |
|
|
301 | my $i = retrieve_all WeBWorK::DBv3::Status; |
|
|
302 | while (my $Status = $i->next) { |
|
|
303 | if (exists $statuses{$Status->name}) { |
|
|
304 | debug("Status '", $Status->name, "' (ID $Status) already exists in the database -- skipping.\n"); |
|
|
305 | # add entries mapping abbreviations to the ID of this status |
|
|
306 | foreach my $abbrev (@{$statuses{$Status->name}}) { |
|
|
307 | $abbrev_to_status_id{$abbrev} = $Status->id; |
|
|
308 | } |
|
|
309 | |
|
|
310 | delete $statuses{$Status->name}; |
|
|
311 | } |
|
|
312 | } |
|
|
313 | |
|
|
314 | if ($opt_s) { |
|
|
315 | debug("Updating status table (as per -s switch).\n"); |
|
|
316 | foreach my $status (keys %statuses) { |
|
|
317 | my %flags; |
|
|
318 | %flags = %{ STATUS_MAP->{$status} } if exists STATUS_MAP->{$status}; |
|
|
319 | my $Status = create WeBWorK::DBv3::Status({name => $status, %flags}); |
|
|
320 | |
|
|
321 | my @flags = grep { $flags{$_} } keys %flags; |
|
|
322 | debug("Added status '", $Status->name, "' (ID $Status) with flags '@flags'.\n"); |
|
|
323 | |
|
|
324 | # add entries mapping abbreviations to the ID of this status |
|
|
325 | foreach my $abbrev (@{$statuses{$status}}) { |
|
|
326 | $abbrev_to_status_id{$abbrev} = $Status->id; |
|
|
327 | } |
|
|
328 | } |
|
|
329 | } else { |
|
|
330 | debug("Not updating status table (as per lack of -s switch).\n"); |
|
|
331 | debug("I might run into users with status abbreviations that don't map to statuses later.\n"); |
|
|
332 | } |
|
|
333 | |
|
|
334 | return %abbrev_to_status_id; |
|
|
335 | } |
|
|
336 | |
|
|
337 | sub reverse_hash { |
|
|
338 | my (%hash) = @_; |
|
|
339 | |
|
|
340 | my %reverse_hash; |
|
|
341 | foreach my $key (keys %hash) { |
|
|
342 | my $value = $hash{$key}; |
|
|
343 | if (defined $value and not ref $value) { |
|
|
344 | push @{ $reverse_hash{$value} }, $key; |
|
|
345 | #} else { |
|
|
346 | # my $val_string = defined $value ? $value : "UNDEF"; |
|
|
347 | # warn "pair ( $key => $val_string ) skipped.\n"; |
|
|
348 | } |
|
|
349 | } |
|
|
350 | |
|
|
351 | return %reverse_hash; |
| 249 | } |
352 | } |
| 250 | |
353 | |
| 251 | ################################################################################ |
354 | ################################################################################ |
| 252 | |
355 | |
| 253 | sub copy_course_data { |
356 | sub copy_course_data { |
| … | |
… | |
| 263 | my $course_db = WeBWorK::DB->new($course_ce->{dbLayout}); |
366 | my $course_db = WeBWorK::DB->new($course_ce->{dbLayout}); |
| 264 | |
367 | |
| 265 | # First we see if this course already exists. If it does, there's a problem |
368 | # First we see if this course already exists. If it does, there's a problem |
| 266 | # and we throw an exception. |
369 | # and we throw an exception. |
| 267 | if (WeBWorK::DBv3::Course->search(name => $courseID)) { |
370 | if (WeBWorK::DBv3::Course->search(name => $courseID)) { |
| 268 | die "Course '$courseID' exists"; |
371 | die "Course '$courseID' exists in v3 DB"; |
| 269 | } else { |
372 | } else { |
| 270 | debug("Course '$courseID' doesn't exist in v3 DB -- adding.\n"); |
373 | debug("Course '$courseID' doesn't exist in v3 DB -- adding.\n"); |
| 271 | my $Course = WeBWorK::DBv3::Course->create({name => $courseID}); |
374 | my $Course = WeBWorK::DBv3::Course->create({name => $courseID}); |
| 272 | } |
375 | } |
| 273 | |
376 | |