[system] / branches / rel-2-1-patches / webwork2 / bin / ww_db_v2_to_v3 Repository:
ViewVC logotype

View of /branches/rel-2-1-patches/webwork2/bin/ww_db_v2_to_v3

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3141 - (download) (annotate)
Sun Feb 6 15:20:52 2005 UTC (8 years, 3 months ago)
File size: 21403 byte(s)
This commit was manufactured by cvs2svn to create branch 'rel-2-1-patches'.

    1 #!/usr/bin/env perl
    2 ################################################################################
    3 # WeBWorK Online Homework Delivery System
    4 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    5 # $CVSHeader: webwork2/bin/ww_db_v2_to_v3,v 1.4 2004/12/09 16:30:12 sh002i Exp $
    6 # 
    7 # This program is free software; you can redistribute it and/or modify it under
    8 # the terms of either: (a) the GNU General Public License as published by the
    9 # Free Software Foundation; either version 2, or (at your option) any later
   10 # version, or (b) the "Artistic License" which comes with this package.
   11 # 
   12 # This program is distributed in the hope that it will be useful, but WITHOUT
   13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   14 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   15 # Artistic License for more details.
   16 ################################################################################
   17 
   18 =head1 NAME
   19 
   20 ww_db_v2_to_v3 - convert a WWDBv2 database to a WWDBv3 database.
   21 
   22 =head1 SYNOPSIS
   23 
   24  ww_db_v2_to_v3 -crsuv course ...
   25 
   26 =head1 DESCRIPTION
   27 
   28 Copies course data from legacy WWDBv2 database(s) to a WWDBv3 database. This may
   29 take a long time.
   30 
   31 You must disallow login to the WeBWorK system while the transfer is taking
   32 place. To disable logins for all courses, set the permission level necessary for
   33 C<login> to $nobody in F<global.conf>. (It is usually set to $student.)
   34 
   35 =head1 OPTIONS
   36 
   37 =over
   38 
   39 =item -c
   40 
   41 If an error occurs while copying a course's data, continue copying with the next
   42 course.
   43 
   44 =item -r
   45 
   46 Update role table in WWDBv3 database from permission level information in
   47 F<global.conf>.
   48 
   49 =item -s
   50 
   51 Update status table in WWDBv3 database from the status information in
   52 F<global.conf>.
   53 
   54 =item -u
   55 
   56 When importing a user that already exists in the WWDBv3 database, replace the
   57 existing information (including the password) with the information in the user
   58 record being imported.
   59 
   60 If this option is not specified, existing users are not updated.
   61 
   62 =item -v
   63 
   64 Verbose operation.
   65 
   66 =item course ...
   67 
   68 Data from these courses will be copied.
   69 
   70 =back
   71 
   72 =head1 BEHAVIOR
   73 
   74 =head2 ROLES
   75 
   76 =over
   77 
   78 =item *
   79 
   80 Roles created with the -r switch are created as system-wide roles.
   81 
   82 =item *
   83 
   84 Roles are created by observing the %permissionLevels hash in F<global.conf>, and
   85 collecting the privileges granted at each permission level into sets. Each set
   86 of privileges becomes a WWDBv3 role record.
   87 
   88 =item *
   89 
   90 When a role with the same set of permissions already exists in the WWDBv3
   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.
  130 
  131 =back
  132 
  133 =head2 USERS
  134 
  135 =over
  136 
  137 =item *
  138 
  139 WWDBv2 user IDs are converted to login IDs.
  140 
  141 =item *
  142 
  143 Users with the same v2 user ID in different courses are assumed to be the same
  144 user.
  145 
  146 =item *
  147 
  148 A user's permission level is used to determine the role to assign to their v3
  149 participant record. (See L<ROLES>.) If the user has an empty permission level,
  150 they are assigned the role associated with permission level "0".
  151 
  152 =item *
  153 
  154 A user's status abbreviation is used to determine the status to assign to their
  155 v3 participant record. (See L<STATUSES>.) If the user has an empty status, they
  156 are assigned the status "Enrolled".
  157 
  158 =item *
  159 
  160 If a user has a non-empty section or recitation, their v3 participant record
  161 will be assigned to the section or recitation with a matching name.
  162 
  163 =back
  164 
  165 =cut
  166 
  167 use strict;
  168 use warnings;
  169 use Data::Dumper;
  170 use DateTime;
  171 use Getopt::Std;
  172 
  173 BEGIN {
  174 	die "WEBWORK_ROOT not found in environment.\n"
  175 		unless exists $ENV{WEBWORK_ROOT};
  176 }
  177 
  178 use lib "$ENV{WEBWORK_ROOT}/lib";
  179 use WeBWorK::CourseEnvironment;
  180 use WeBWorK::DB;
  181 use WeBWorK::DBv3;
  182 
  183 # map statuses from course environment to sets of status privileges
  184 use constant STATUS_MAP => {
  185 	Enrolled => { allow_course_access => 1, include_in_assignment => 1, include_in_stats => 1, include_in_scoring => 1 },
  186 	Audit    => { allow_course_access => 1, include_in_assignment => 1, include_in_stats => 1, include_in_scoring => 0 },
  187 	Drop     => { allow_course_access => 0, include_in_assignment => 0, include_in_stats => 0, include_in_scoring => 0 },
  188 };
  189 
  190 use constant DEFAULT_STATUS => "C";
  191 use constant DEFAULT_PERMISSION_LEVEL => "0";
  192 
  193 our ($opt_c, $opt_r, $opt_s, $opt_u, $opt_v);
  194 getopts("crsuv");
  195 
  196 sub debug { print STDERR @_ if $opt_v }
  197 sub usage { print STDERR "usage: $0 [-crsuv] course ...\n"; exit 1 }
  198 
  199 main(@ARGV);
  200 
  201 sub main {
  202 	my (@courseIDs) = @_;
  203 	
  204 	usage() unless @courseIDs;
  205 	
  206 	my $ce = WeBWorK::CourseEnvironment->new({webwork_dir => $ENV{WEBWORK_ROOT}});
  207 	
  208 	WeBWorK::DBv3::init($ce->{wwdbv3_settings});
  209 	
  210 	my %abbrev_to_status_id = set_up_statuses($ce->{siteDefaults}{status});
  211 	warn "abbrev_to_status_id: ", Dumper(\%abbrev_to_status_id);
  212 	
  213 	my %level_to_role_id = set_up_roles($ce->{permissionLevels});
  214 	warn "level_to_role_id: ", Dumper(\%level_to_role_id);
  215 	
  216 	foreach my $courseID (@courseIDs) {
  217 		eval { copy_course_data($courseID, \%abbrev_to_status_id, \%level_to_role_id) };
  218 		if ($@) {
  219 			warn "An error occured while copying data from course '$courseID':\n\n$@\n\n";
  220 			if ($opt_c) {
  221 				warn "Continuing with the next course...\n";
  222 			} else {
  223 				warn "Exiting.\n";
  224 				exit 2;
  225 			}
  226 		}
  227 	}
  228 }
  229 
  230 ################################################################################
  231 
  232 sub reverse_hash {
  233 	my (%hash) = @_;
  234 	
  235 	my %reverse_hash;
  236 	foreach my $key (keys %hash) {
  237 		my $value = $hash{$key};
  238 		if (defined $value and not ref $value) {
  239 			push @{ $reverse_hash{$value} }, $key;
  240 		#} else {
  241 		#	my $val_string = defined $value ? $value : "UNDEF";
  242 		#	warn "pair ( $key => $val_string ) skipped.\n";
  243 		}
  244 	}
  245 	
  246 	return %reverse_hash;
  247 }
  248 
  249 sub listeq {
  250 	my ($a, $b) = @_;
  251 	return "" unless @$a == @$b;
  252 	for (my $i = 0; $i < @$a; $i++) {
  253 		return "" unless $a->[$i] eq $b->[$i];
  254 	}
  255 	return 1;
  256 }
  257 
  258 sub is_empty {
  259 	my ($val) = @_;
  260 	return (not defined $val or $val eq "");
  261 }
  262 
  263 ################################################################################
  264 
  265 sub set_up_roles {
  266 	my ($permissionLevels) = @_;
  267 	my %permissionLevels = %$permissionLevels;
  268 	
  269 	my %level_to_role_id;
  270 	
  271 	# reverse the permission levels hash, resulting in a hash mapping
  272 	# permissions levels to arrayrefs containing privileges
  273 	my %levels = reverse_hash(%permissionLevels);
  274 	
  275 	# copy up the privileges at each level to the next-higher level
  276  	# also sort each level
  277 	my @level_names = sort { $a <=> $b } keys %levels;
  278 	foreach my $i (0 .. $#level_names-1) {
  279 		my $this_level = $level_names[$i];
  280 		my $next_level = $level_names[$i+1];
  281 		push @{ $levels{$next_level} }, @{ $levels{$this_level} };
  282 	}
  283 	
  284 	# sort the privileges in each level
  285 	debug("I found the following permission levels:\n");
  286 	foreach my $level (keys %levels) {
  287 		my @sorted = sort @{ $levels{$level} };
  288 		$levels{$level} = [ @sorted ];
  289 		debug("\t$level => @sorted\n");
  290 	}
  291 	
  292 	# keep track of role names so we know if we need to rename any of our new ones
  293 	my %role_names;
  294 	
  295 	# look at existing roles to see if we can avoid adding some new ones
  296 	my $i = retrieve_all WeBWorK::DBv3::Role;
  297 	while (my $Role = $i->next) {
  298 		$role_names{$Role->name} = 1;
  299 		my @role_privs = sort $Role->privs_list;
  300 		
  301 		foreach my $level (keys %levels) {
  302 			if (listeq($levels{$level}, \@role_privs)) {
  303 				debug("Permission level '$level' is already represented as role '",
  304 					$Role->name, "' (ID $Role) -- skipping.\n");
  305 				delete $levels{$level};
  306 				$level_to_role_id{$level} = $Role->id;
  307 			}
  308 		}
  309 	}
  310 	
  311 	if ($opt_r) {
  312 		debug("Updating role table (as per -r switch).\n");
  313 		foreach my $level (keys %levels) {
  314 			my $name = "Legacy permission level $level";
  315 			if (exists $role_names{$name}) {
  316 				my $i = 2;
  317 				while (1) {
  318 					my $try_name = "$name (#$i)";
  319 					if (not exists $role_names{$try_name}) {
  320 						$name = $try_name;
  321 						last;
  322 					}
  323 				}
  324 			}
  325 			
  326 			my @privs = @{ $levels{$level} };
  327 			
  328 			my $Role = create WeBWorK::DBv3::Role({name => $name});
  329 			$Role->privs_list(@privs);
  330 			$Role->update;
  331 			debug("Added role '", $Role->name, "' (ID $Role) with privileges '@privs'.\n");
  332 			$level_to_role_id{$level} = $Role->id;
  333 		}
  334 	} else {
  335 		debug("Not updating role table (as per lack of -r switch).\n");
  336 		debug("I might run into users with permission levels that don't map to roles later.\n");
  337 	}
  338 	
  339 	return %level_to_role_id;
  340 }
  341 
  342 sub set_up_statuses {
  343 	my ($abbrevs) = @_;
  344 	my %abbrevs = %$abbrevs;
  345 	
  346 	my %abbrev_to_status_id;
  347 	
  348 	# reverse the statuses hash, resulting in a hash mapping statuses to
  349 	# arrayrefs containing abbreviations
  350 	my %statuses = reverse_hash(%abbrevs);
  351 	
  352 	# look at existing statuses to see if we can avoid adding some new ones
  353 	my $i = retrieve_all WeBWorK::DBv3::Status;
  354 	while (my $Status = $i->next) {
  355 		if (exists $statuses{$Status->name}) {
  356 			debug("Status '", $Status->name, "' (ID $Status) already exists in the database -- skipping.\n");
  357 			# add entries mapping abbreviations to the ID of this status
  358 			foreach my $abbrev (@{$statuses{$Status->name}}) {
  359 				$abbrev_to_status_id{$abbrev} = $Status->id;
  360 			}
  361 			
  362 			delete $statuses{$Status->name};
  363 		}
  364 	}
  365 	
  366 	if ($opt_s) {
  367 		debug("Updating status table (as per -s switch).\n");
  368 		foreach my $status (keys %statuses) {
  369 			my %flags;
  370 			%flags = %{ STATUS_MAP->{$status} } if exists STATUS_MAP->{$status};
  371 			my $Status = create WeBWorK::DBv3::Status({name => $status, %flags});
  372 			
  373 			my @flags = grep { $flags{$_} } keys %flags;
  374 			debug("Added status '", $Status->name, "' (ID $Status) with flags '@flags'.\n");
  375 			
  376 			# add entries mapping abbreviations to the ID of this status
  377 			foreach my $abbrev (@{$statuses{$status}}) {
  378 				$abbrev_to_status_id{$abbrev} = $Status->id;
  379 			}
  380 		}
  381 	} else {
  382 		debug("Not updating status table (as per lack of -s switch).\n");
  383 		debug("I might run into users with status abbreviations that don't map to statuses later.\n");
  384 	}
  385 	
  386 	return %abbrev_to_status_id;
  387 }
  388 
  389 ################################################################################
  390 
  391 sub copy_course_data {
  392 	my ($courseID, $abbrev_to_status_id, $level_to_role_id) = @_;
  393 	
  394 	debug("Processing course '$courseID'...\n");
  395 	
  396 	my $course_ce = WeBWorK::CourseEnvironment->new({
  397 		webwork_dir => $ENV{WEBWORK_ROOT},
  398 		courseName => $courseID,
  399 	});
  400 	
  401 	my $course_db = WeBWorK::DB->new($course_ce->{dbLayout});
  402 	
  403 	debug("Adding course '$courseID' to v3 DB.\n");
  404 	my $v3Course = eval { create WeBWorK::DBv3::Course({name => $courseID}) };
  405 	$@ =~ /Duplicate entry/ and die "Course '$courseID' exists in v3 DB.\n";
  406 	$@ and die $@;
  407 	
  408 	copy_users($course_db, $v3Course, $abbrev_to_status_id, $level_to_role_id);
  409 	
  410 	# { $globalSetID => [ $v3AbsSet->id, { $globalProblemID => $vAbsProb->id, ... }, ... }
  411 	my %global_set_id_to_abstract_set_data = copy_abstract_data($course_db, $v3Course);
  412 }
  413 
  414 ################################################################################
  415 
  416 sub copy_users {
  417 	my ($course_db, $v3Course, $abbrev_to_status_id, $level_to_role_id) = @_;
  418 	
  419 	my $DefaultStatus = find_status(DEFAULT_STATUS, $abbrev_to_status_id);
  420 	die "Default status '", DEFAULT_STATUS, "' does not correspond to any v3 status.\n"
  421 		unless $DefaultStatus;
  422 	
  423 	my $DefaultRole = find_role(DEFAULT_PERMISSION_LEVEL, $level_to_role_id);
  424 	die "Default permission level '", DEFAULT_PERMISSION_LEVEL, "' does not correspond to any v3 role.\n"
  425 		unless $DefaultRole;
  426 	
  427 	my @userIDs = $course_db->listUsers;
  428 	my %Users; @Users{@userIDs} = $course_db->getUsers(@userIDs);
  429 	my %Passwords; @Passwords{@userIDs} = $course_db->getPasswords(@userIDs);
  430 	my %PermissionLevels; @PermissionLevels{@userIDs} = $course_db->getPermissionLevels(@userIDs);
  431 	
  432 	foreach my $userID (keys %Users) {
  433 		my $User = $Users{$userID};
  434 		my $Password = $Passwords{$userID};
  435 		my $PermissionLevel = $PermissionLevels{$userID};
  436 		
  437 		unless (defined $User) {
  438 			debug("User record for user ID '$userID' not found -- skipping.\n");
  439 			next;
  440 		}
  441 		
  442 		debug("Processing user '$userID'...\n");
  443 		
  444 		# create/update user record
  445 		my ($v3User) = search WeBWorK::DBv3::User(login_id => $userID);
  446 		if ($v3User) {
  447 			debug("A user with login_id '$userID' exists in v3 database -- ");
  448 			if ($opt_u) {
  449 				# password record might not exist (annoying...)
  450 				my $password = defined $Password ? $Password->password : "";
  451 				
  452 				debug("updating (as per -u switch).\n");
  453 				$v3User->first_name($User->first_name) unless is_empty($User->first_name);
  454 				$v3User->last_name($User->first_name) unless is_empty($User->last_name);
  455 				$v3User->email_address($User->email_address) unless is_empty($User->email_address);
  456 				$v3User->student_id($User->student_id) unless is_empty($User->student_id);
  457 				$v3User->password($password) unless is_empty($password);
  458 				$v3User->update;
  459 			} else {
  460 				debug("not updating (as per lack of -u switch).\n");
  461 			}
  462 		} else {
  463 			# password record might not exist (annoying...)
  464 			my $password = defined $Password ? $Password->password : "";
  465 			
  466 			debug("No user with login_id '$userID' exists in v3 database -- adding.\n");
  467 			$v3User = create WeBWorK::DBv3::User({
  468 				first_name    => $User->first_name,
  469 				last_name     => $User->last_name,
  470 				email_address => $User->email_address,
  471 				student_id    => $User->student_id,
  472 				login_id      => $User->user_id,
  473 				password      => $password,
  474 			});
  475 		}
  476 		
  477 		# get status
  478 		my $v3Status = find_status($User->status, $abbrev_to_status_id);
  479 		unless ($v3Status) {
  480 			debug("Using default status '", $DefaultStatus->name, "'.\n");
  481 			$v3Status = $DefaultStatus;
  482 		}
  483 		
  484 		# get role
  485 		my $level = defined $PermissionLevel ? $PermissionLevel->permission : "";
  486 		my $v3Role = find_role($level, $level_to_role_id);
  487 		unless ($v3Role) {
  488 			debug("Using default role '", $DefaultRole->name, "'.\n");
  489 			$v3Role = $DefaultRole;
  490 		}
  491 		
  492 		# find/create section record
  493 		my $section = $User->section;
  494 		my $v3Section;
  495 		if (is_empty($section)) {
  496 			debug("This user has section '$section'.\n");
  497 			($v3Section) = search WeBWorK::DBv3::Section(course => $v3Course, name => $section);
  498 			if ($v3Section) {
  499 				debug("This corresponds to existing section ID $v3Section in v3 database.\n");
  500 			} else {
  501 				debug("No corresponding section exists in v3 DB -- adding.\n");
  502 				$v3Section = create WeBWorK::DBv3::Section({
  503 					course => $v3Course,
  504 					name   => $section,
  505 				});
  506 				debug("Added section '", $v3Section->name, "' (ID $v3Section).\n");
  507 			}
  508 		} else {
  509 			debug("This user has no section.\n");
  510 		}
  511 		
  512 		# find/create recitation record
  513 		my $recitation = $User->recitation;
  514 		my $v3Recitation;
  515 		if (is_empty($recitation)) {
  516 			debug("This user has recitation '$recitation'.\n");
  517  			($v3Recitation) = search WeBWorK::DBv3::Recitation(course => $v3Course, name => $User->recitation);
  518 			if ($v3Recitation) {
  519 				debug("This correponds to existing recitation ID $v3Recitation in v3 database.\n");
  520 			} else {
  521 				debug("No corresponding recitation exists in v3 DB -- adding.\n");
  522 				$v3Recitation = create WeBWorK::DBv3::Recitation({
  523 					course => $v3Course,
  524 					name   => $User->recitation,
  525 				});
  526 				debug("Added recitation '", $v3Recitation->name, "' (ID $v3Recitation).\n");
  527 			}
  528 		} else {
  529 			debug("This user has no recitation.\n");
  530 		}
  531 		
  532 		# create participant record
  533 		debug("Adding participant record for user '$userID'...");
  534 		#my $sectionID = $v3Section->id if defined $v3Section;
  535 		#my $recitationID = $v3Recitation->id if defined $v3Recitation;
  536 		my $v3Participant = create WeBWorK::DBv3::Participant({
  537 			course     => $v3Course,
  538 			user       => $v3User,
  539 			status     => $v3Status,
  540 			role       => $v3Role,
  541 			section    => $v3Section,
  542 			recitation => $v3Recitation,
  543 			comment    => $User->comment,
  544 		});
  545 		debug(" added participant ID $v3Participant.\n");
  546 	}
  547 }
  548 
  549 sub find_status {
  550 	my ($status, $abbrev_to_status_id) = @_;
  551 	
  552 	return if is_empty($status);
  553 	
  554 	my $v3Status_id = $abbrev_to_status_id->{$status};
  555 	my $v3Status;
  556 	if (defined $v3Status_id) {
  557 		#debug("Status '$status' maps to v3 status ID '$v3Status_id'.\n");
  558 		$v3Status = retrieve WeBWorK::DBv3::Status($v3Status_id);
  559 	} else {
  560 		#debug("Status '$status' doesn't map to any v3 status.\n");
  561 	}
  562 	
  563 	return $v3Status;
  564 }
  565 
  566 sub find_role {
  567 	my ($level, $level_to_role_id) = @_;
  568 	
  569 	return if is_empty($level);
  570 	
  571 	my $v3Role_id = $level_to_role_id->{$level};
  572 	my $v3Role;
  573 	if (defined $v3Role_id) {
  574 		#debug("Permission level '$level' maps to v3 role ID '$v3Role_id'.\n");
  575 		$v3Role = retrieve WeBWorK::DBv3::Role($v3Role_id);
  576 	} else {
  577 		#debug("Permission level '$level' doesn't map to any v3 role.\n");
  578 	}
  579 	
  580 	return $v3Role;
  581 }
  582 
  583 ################################################################################
  584 
  585 sub copy_abstract_data {
  586 	my ($course_db, $v3Course) = @_;
  587 	
  588 	my %global_set_id_to_abstract_set_data;
  589 	
  590 	my @globalSetIDs = $course_db->listGlobalSets;
  591 	my %GlobalSets; @GlobalSets{@globalSetIDs} = $course_db->getGlobalSets(@globalSetIDs);
  592 	
  593 	foreach my $globalSetID (keys %GlobalSets) {
  594 		my $GlobalSet = $GlobalSets{$globalSetID};
  595 		
  596 		unless (defined $GlobalSet) {
  597 			debug("Global set record for global set ID '$globalSetID' not found -- skipping.\n");
  598 			next;
  599 		}
  600 		
  601 		debug("Processing global set '$globalSetID'...\n");
  602 		
  603 		# set up some fields that need setting up
  604 		# (if the conditional is false, the variable is left undefined)
  605 		
  606 		# convert empty strings to undefined values
  607 		my $set_header = $GlobalSet->set_header unless is_empty($GlobalSet->set_header);
  608 		my $hardcopy_header = $GlobalSet->hardcopy_header unless is_empty($GlobalSet->hardcopy_header);
  609 		
  610 		# convert 
  611 		my $open_date = DateTime->from_epoch(epoch => $GlobalSet->open_date);
  612 		my $due_date = DateTime->from_epoch(epoch => $GlobalSet->due_date);
  613 		my $answer_date = DateTime->from_epoch(epoch => $GlobalSet->answer_date);
  614 		
  615 		# create abstract_set record
  616 		debug("Adding abstract_set record for global set '$globalSetID'...");
  617 		my $v3AbsSet = create WeBWorK::DBv3::AbstractSet({
  618 			course => $v3Course,
  619 			name => $GlobalSet->set_id,
  620 			set_header => $set_header,
  621 			hardcopy_header => $hardcopy_header,
  622 			open_date => $open_date,
  623 			due_date => $due_date,
  624 			answer_date => $answer_date,
  625 			published => $GlobalSet->published,
  626 		});
  627 		debug(" added abstract_set ID '$v3AbsSet'.\n");
  628 		
  629 		
  630 		my %problem_mapping;
  631 		
  632 		my @globalProblemIDs = sort { $a <=> $b } $course_db->listGlobalProblems($globalSetID);
  633 		warn "globalProblemIDs=@globalProblemIDs\n";
  634 		my %GlobalProblems; @GlobalProblems{@globalProblemIDs}
  635 			= $course_db->getGlobalProblems(map { [ $globalSetID, $_ ] } @globalProblemIDs);
  636 		
  637 		my @problem_order;
  638 		
  639 		foreach my $globalProblemID (@globalProblemIDs) {
  640 			my $GlobalProblem = $GlobalProblems{$globalProblemID};
  641 			
  642 			unless (defined $GlobalProblem) {
  643 				warn "Global problem record for global problem ID '$globalProblemID' in set ID '$globalSetID' not found -- skipping.\n";
  644 				next;
  645 			}
  646 			
  647 			debug("Processing global problem '$globalProblemID'...\n");
  648 		
  649 			# convert max_attempts of -1 to undef
  650 			my $max_attempts_per_version = $GlobalProblem->max_attempts
  651 				if $GlobalProblem->max_attempts >= 0;
  652 			
  653 			# create abstract_problem record
  654 			debug("Adding abstract_set record for global problem '$globalProblemID'...");
  655 			my $v3AbsProb = create WeBWorK::DBv3::AbstractProblem({
  656 				abstract_set => $v3AbsSet,
  657 				name => "Legacy problem $globalProblemID",
  658 				source_type => "file",
  659 				source_file => $GlobalProblem->source_file,
  660 				weight => $GlobalProblem->value,
  661 				max_attempts_per_version => $max_attempts_per_version,
  662 				version_creation_interval => undef,
  663 				versions_per_interval => 1,
  664 				version_due_date_offset => undef,
  665 				version_answer_date_offset => undef,
  666 			});
  667 			debug(" added abstract_problem ID '$v3AbsProb'.\n");
  668 			
  669 			push @problem_order, $v3AbsProb->id;
  670 			
  671 			$problem_mapping{$globalProblemID} = $v3AbsProb->id;
  672 		}
  673 		
  674 		# update problem order
  675 		debug("Setting problem order to: '@problem_order'...");
  676 		$v3AbsSet->problem_order_list(@problem_order);
  677 		$v3AbsSet->update;
  678 		debug(" done.\n");
  679 		
  680 		$global_set_id_to_abstract_set_data{$globalSetID} = [ $v3AbsSet->id, \%problem_mapping ];
  681 	}
  682 	
  683 	return %global_set_id_to_abstract_set_data;
  684 }
  685 
  686 ################################################################################
  687 
  688 sub copy_assignment_data {
  689 	my ($course_db, $v3Course, $global_set_id_to_abstract_set_data) = @_;
  690 	
  691 	my $participant_iter = WeBWorK::DBv3::Participant->search(course => $v3Course);
  692 	
  693 	while (my $Participant = $participant_iter->next) {
  694 		my @userSetIDs = $course_db->listUserSets($Participant->user->login_id);
  695 		$v3AbsSet->
  696 	}
  697 }
  698 
  699 sub copy_single_assignment {
  700 	my ($course_db, $v3Course, $v3Participant, $v3AbsSet, $global_set_id_to_abstract_set_data) = @_;
  701 	
  702 	
  703 }

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9