diff --git a/bin/addcourse b/bin/addcourse index fe09f3b44e..42ea11ac5d 100755 --- a/bin/addcourse +++ b/bin/addcourse @@ -18,11 +18,6 @@ be granted professor privileges. =over -=item B<--db-layout>=I - -The specified database layout will be used in place of the default specified in -F. - =item B<--users>=I The users listed in the comma-separated text file I will be added to the @@ -63,30 +58,26 @@ BEGIN { use lib "$ENV{WEBWORK_ROOT}/lib"; use WeBWorK::CourseEnvironment; - -# Grab course environment (by reading webwork2/conf/defaults.config) -my $ce = WeBWorK::CourseEnvironment->new; - -use WeBWorK::DB; use WeBWorK::File::Classlist; use WeBWorK::Utils qw(runtime_use cryptPassword); use WeBWorK::Utils::CourseManagement qw(addCourse); use WeBWorK::File::Classlist qw(parse_classlist); +use WeBWorK::DB::Record::User; +use WeBWorK::DB::Record::Password; +use WeBWorK::DB::Record::PermissionLevel; sub usage_error { warn "@_\n"; warn "usage: $0 [options] COURSEID\n"; warn "Options:\n"; - warn " [--db-layout=LAYOUT]\n"; warn " [--users=FILE [--professors=USERID[,USERID]...] ]\n"; exit; } -my ($dbLayout, $users, $templates_from) = ('', '', ''); +my ($users, $templates_from) = ('', ''); my @professors; GetOptions( - "db-layout=s" => \$dbLayout, "users=s" => \$users, "professors=s" => \@professors, "templates-from=s" => \$templates_from, @@ -96,33 +87,16 @@ my $courseID = shift; usage_error('The COURSEID must be provided.') unless $courseID; -$ce = WeBWorK::CourseEnvironment->new({ courseName => $courseID }); +my $ce = WeBWorK::CourseEnvironment->new({ courseName => $courseID }); die "Aborting addcourse: Course ID cannot exceed $ce->{maxCourseIdLength} characters." if length($courseID) > $ce->{maxCourseIdLength}; -if ($dbLayout) { - die "Database layout $dbLayout does not exist in the course environment.", - " (It must be defined in defaults.config.)\n" - unless exists $ce->{dbLayouts}{$dbLayout}; -} else { - $dbLayout = $ce->{dbLayoutName}; -} - usage_error("Can't specify --professors without also specifying --users.") if @professors && !$users; my @users; if ($users) { - # This is a hack to create records without bringing up a DB object - my $userClass = $ce->{dbLayouts}{$dbLayout}{user}{record}; - my $passwordClass = $ce->{dbLayouts}{$dbLayout}{password}{record}; - my $permissionClass = $ce->{dbLayouts}{$dbLayout}{permission}{record}; - - runtime_use($userClass); - runtime_use($passwordClass); - runtime_use($permissionClass); - my @classlist = parse_classlist($users); for my $record (@classlist) { my %record = %$record; @@ -154,9 +128,9 @@ if ($users) { push @users, [ - $userClass->new(%record), - $record{password} ? $passwordClass->new(user_id => $user_id, password => $record{password}) : undef, - $permissionClass->new( + WeBWorK::DB::Record::User->new(%record), + WeBWorK::DB::Record::Password->new(user_id => $user_id, password => $record{password}), + WeBWorK::DB::Record::PermissionLevel->new( user_id => $user_id, permission => defined $professors{$user_id} ? $ce->{userRoles}{professor} @@ -176,15 +150,7 @@ if ($templates_from) { $optional_arguments{copyTemplatesHtml} = 1; } -eval { - addCourse( - courseID => $courseID, - ce => $ce, - courseOptions => { dbLayoutName => $dbLayout }, - users => \@users, - %optional_arguments, - ); -}; +eval { addCourse(courseID => $courseID, ce => $ce, users => \@users, %optional_arguments,); }; die "$@\n" if $@; diff --git a/bin/change_user_id b/bin/change_user_id index 0be7789621..2ec44a5034 100755 --- a/bin/change_user_id +++ b/bin/change_user_id @@ -47,7 +47,7 @@ my $ce = WeBWorK::CourseEnvironment->new({ courseName => $courseID }); -my $db = new WeBWorK::DB($ce->{dbLayout}); +my $db = WeBWorK::DB->new($ce); die "Error: $old_user_id does not exist!" unless $db->existsUser($old_user_id); unless($db->existsUser($new_user_id)) { diff --git a/bin/check_database_charsets.pl b/bin/check_database_charsets.pl deleted file mode 100755 index c46feb1475..0000000000 --- a/bin/check_database_charsets.pl +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env perl - -my $host = $ENV{WEBWORK_DB_HOST}; -my $port = $ENV{WEBWORK_DB_PORT}; -my $database_name = $ENV{WEBWORK_DB_NAME}; -my $database_user = $ENV{WEBWORK_DB_USER}; -my $database_password = $ENV{WEBWORK_DB_PASSWORD}; - -print - `mysql -u $database_user -p$database_password $database_name -h $host -e "SHOW VARIABLES WHERE Variable_name LIKE \'character\_set\_%\' OR Variable_name LIKE \'collation%\' or Variable_name LIKE \'init_connect\' "`; diff --git a/bin/dump-past-answers.pl b/bin/dump-past-answers.pl index b1dc7132b1..1a1edb739f 100755 --- a/bin/dump-past-answers.pl +++ b/bin/dump-past-answers.pl @@ -123,7 +123,7 @@ sub write_past_answers_csv { next if $courseID eq ($minimal_ce->{admin_course_id} // 'admin') || $courseID eq 'modelCourse'; my $ce = WeBWorK::CourseEnvironment->new({ webwork_dir => $ENV{WEBWORK_ROOT}, courseName => $courseID }); - my $db = WeBWorK::DB->new($ce->{dbLayout}); + my $db = WeBWorK::DB->new($ce); my %permissionLabels = reverse %{ $ce->{userRoles} }; diff --git a/bin/importClassList.pl b/bin/importClassList.pl index de869ef5b9..636ea25421 100755 --- a/bin/importClassList.pl +++ b/bin/importClassList.pl @@ -15,7 +15,7 @@ BEGIN use WeBWorK::CourseEnvironment; -use WeBWorK::DB qw(check_user_id); +use WeBWorK::DB; use WeBWorK::File::Classlist; use WeBWorK::Utils qw(cryptPassword); use WeBWorK::File::Classlist qw(parse_classlist); @@ -35,7 +35,7 @@ BEGIN courseName => $courseID }); -my $db = WeBWorK::DB->new($ce->{dbLayout}); +my $db = WeBWorK::DB->new($ce); my $createNew = 1; # Always set to true, so add new users my $replaceExisting = "none"; # Always set to "none" so no existing accounts are changed diff --git a/bin/newpassword b/bin/newpassword index ff816f5c98..2611690ae7 100755 --- a/bin/newpassword +++ b/bin/newpassword @@ -80,7 +80,7 @@ my $ce = WeBWorK::CourseEnvironment->new({ courseName => $courseID }); -my $db = new WeBWorK::DB($ce->{dbLayout}); +my $db = WeBWorK::DB->new($ce); dopasswd($db, $user, $newP); print "Changed password for $user in $courseID\n"; diff --git a/bin/upgrade-database-to-utf8mb4.pl b/bin/upgrade-database-to-utf8mb4.pl index f3052d9c1c..2d99c84ea6 100755 --- a/bin/upgrade-database-to-utf8mb4.pl +++ b/bin/upgrade-database-to-utf8mb4.pl @@ -198,7 +198,7 @@ BEGIN }, ); -my $db = WeBWorK::DB->new($ce->{dbLayouts}{ $ce->{dbLayoutName} }); +my $db = WeBWorK::DB->new($ce); my @table_types = sort(grep { !$db->{$_}{params}{non_native} } keys %$db); sub checkAndUpdateTableColumnTypes { diff --git a/bin/ww_purge_old_nonces b/bin/ww_purge_old_nonces index 9808b140c1..d8ee043bd7 100755 --- a/bin/ww_purge_old_nonces +++ b/bin/ww_purge_old_nonces @@ -58,7 +58,7 @@ my $ce = WeBWorK::CourseEnvironment->new({ courseName => $course, }); -my $db = WeBWorK::DB->new($ce->{dbLayout}); +my $db = WeBWorK::DB->new($ce); my @errors; diff --git a/bin/wwdb b/bin/wwdb deleted file mode 100755 index 390e7b2353..0000000000 --- a/bin/wwdb +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env perl - -=head1 NAME - -wwdb - export and import webwork databases. - -=head1 SYNOPSIS - - wwdb [-f] course { import | export } file [table ...] - -=head1 DESCRIPTION - -Exports data from a course database to an XML file, or imports data from an XML -file to a course database. Optionally restrict which tables are imported or -exported and specify a duplicate policy. - -=head1 OPTIONS - -=over - -=item -f - -Overwite duplicate records. - -=item course - -Course to use for import or export. - -=item { import | export } - -Specify action -- export or import data. - -=item file - -XML file to write to (in the case of export) or read from (in the case of -import). - -=item [table ...] - -If specified, only the listed tables will be imported or exported. - -=back - -=cut - -use strict; -use warnings; -use Getopt::Std; - -BEGIN { - use Mojo::File qw(curfile); - use Env qw(WEBWORK_ROOT); - - $WEBWORK_ROOT = curfile->dirname->dirname; -} - -use lib "$ENV{WEBWORK_ROOT}/lib"; - -use WeBWorK::CourseEnvironment; -use WeBWorK::DB; -use WeBWorK::Utils::DBImportExport qw/listTables dbExport dbImport/; - -sub usage { - print STDERR "usage: $0 [-f] course { import | export } file [table ...]\n"; - print STDERR "tables: ", join(" ", listTables()), "\n"; - exit 1; -} - -our $opt_f; -getopts("f"); - -my ($course, $command, $file, @tables) = @ARGV; - -usage() unless $course and $command and $file; - -my $ce = WeBWorK::CourseEnvironment->new({ - webwork_dir => $ENV{WEBWORK_ROOT}, - courseName => $course, -}); - -my $db = WeBWorK::DB->new($ce->{dbLayout}); - -my @errors; - -if ($command eq "export") { - my $fh; - if ($file eq "-") { - $fh = *STDOUT; - } else { - open $fh, ">", $file or die "failed to open file '$file' for writing: $!\n"; - } - @errors = dbExport( - db => $db, - xml => $fh, - tables => \@tables, - ); - close $fh; -} elsif ($command eq "import") { - my $conflict = ($opt_f ? "replace" : "skip"); - open my $fh, "<", $file or die "failed to open file '$file' for writing: $!\n"; - @errors = dbImport( - db => $db, - xml => $fh, - tables => \@tables, - conflict => $conflict, - ); - close $fh; -} else { - die "$command: unrecognized command.\n"; -} - -if (@errors) { - warn "The following errors occurred:\n", map { "* $_\n" } @errors; - exit 1; -} diff --git a/bin/wwsh b/bin/wwsh index 0370bded60..e55e969305 100755 --- a/bin/wwsh +++ b/bin/wwsh @@ -40,7 +40,7 @@ $ce = WeBWorK::CourseEnvironment->new({ }); -$db = WeBWorK::DB->new($ce->{dbLayout}); +$db = WeBWorK::DB->new($ce); print <<'EOF'; wwsh - The WeBWorK Shell diff --git a/conf/README.md b/conf/README.md index 4ef53a321d..45ebac0def 100644 --- a/conf/README.md +++ b/conf/README.md @@ -16,8 +16,6 @@ Basic webwork2 configuration files. - `localOverrides.conf.dist` should be copied to `localOverrides.conf`. `localOverrides.conf` will be read after the `defaults.config` file is processed and will overwrite configurations in `defaults.config`. Use this file to make changes to the settings in `defaults.config`. -- `database.conf.dist` contains database configuration parameters. It is included by `defaults.config`. This file - should not be copied or modified unless you really know what you are doing. Configuration extension files. diff --git a/conf/authen_CAS.conf.dist b/conf/authen_CAS.conf.dist index 9c968d0717..4095283e96 100644 --- a/conf/authen_CAS.conf.dist +++ b/conf/authen_CAS.conf.dist @@ -8,9 +8,7 @@ ######################################################################################## # Set CAS as the authentication module to use. -$authen{user_module} = { - "*" => "WeBWorK::Authen::CAS", -}; +$authen{user_module} = 'WeBWorK::Authen::CAS'; # List of authentication modules that may be used to enter the admin course. # This is used instead of $authen{user_module} when logging into the admin course. diff --git a/conf/authen_LTI.conf.dist b/conf/authen_LTI.conf.dist index 9e2ab3ee76..20196f4f49 100644 --- a/conf/authen_LTI.conf.dist +++ b/conf/authen_LTI.conf.dist @@ -40,9 +40,9 @@ $debug_lti_grade_passback = 0; # the LTIAdvantage will be used. If you know a site will not use one or the other, it can be # commented out. Failover to Basic_TheLastOption is necessary to authenticate with cookie keys. $authen{user_module} = [ - { '*' => 'WeBWorK::Authen::LTIAdvantage' }, # first try LTI 1.3 - { '*' => 'WeBWorK::Authen::LTIAdvanced' }, # next try LTI 1.1 - { '*' => 'WeBWorK::Authen::Basic_TheLastOption' } # fallback authorization method + 'WeBWorK::Authen::LTIAdvantage', # first try LTI 1.3 + 'WeBWorK::Authen::LTIAdvanced', # next try LTI 1.1 + 'WeBWorK::Authen::Basic_TheLastOption' # fallback authorization method ]; # List of authentication modules that may be used to enter the admin course. diff --git a/conf/authen_ldap.conf.dist b/conf/authen_ldap.conf.dist index 6dbb1f2895..45cc46179a 100644 --- a/conf/authen_ldap.conf.dist +++ b/conf/authen_ldap.conf.dist @@ -8,7 +8,7 @@ ######################################################################################## # Set LDAP as the authentication module to use. -$authen{user_module} = { "*" => "WeBWorK::Authen::LDAP" }; +$authen{user_module} = 'WeBWorK::Authen::LDAP'; # List of authentication modules that may be used to enter the admin course. # This is used instead of $authen{user_module} when logging into the admin course. diff --git a/conf/database.conf.dist b/conf/database.conf.dist deleted file mode 100644 index 10b12d0f89..0000000000 --- a/conf/database.conf.dist +++ /dev/null @@ -1,344 +0,0 @@ -#!perl - -=head1 NAME - -database.conf - define standard database layouts - -=head1 SYNOPSIS - -In defaults.config: - - include "conf/database.conf"; - *dbLayout = $dbLayouts{layoutName}; - -=head1 DESCRIPTION - -This file contains definitions for the commonly-used database layouts. Database -layouts consist of all the information necessary to describe how to access data -used by WeBWorK. For more information on the format of a database layout, -consult the documentation for the WeBWorK::DB module. - -A database layout is selected from the list of possible layouts by adding a -line like the one below to the F or F file. - - $dbLayoutName = "layoutName"; - *dbLayout = $dbLayouts{$dbLayoutName}; - -=head2 THE SQL_SINGLE DATABASE LAYOUT - -The C layout is similar to the C layout, except that it uses a -single database for all courses. This is accomplished by prefixing each table -name with the name of the course. The names and passwords of these accounts are -given as parameters to each table in the layout. - - username the username to use when connecting to the database - password the password to use when connecting to the database - -Be default, username is "webworkRead" and password is "". It is not recommended -that you use only a non-empty password to secure database access. Most RDBMSs -allow IP-based authorization as well. As the system administrator, IT IS YOUR -RESPONSIBILITY TO SECURE DATABASE ACCESS. - -Don't confuse the account information above with the accounts of the users of a -course. This is a system-wide account which allow WeBWorK to talk to the -database server. - -Other parameters that can be given are as follows: - - tableOverride an alternate name to use when referring to the table (used - when a table name is a reserved word) - debug if true, SQL statements are printed before being executed - -=cut - -# params common to all tables - -my %sqlParams = ( - username => $database_username, - password => $database_password, - debug => $database_debug, - # kinda hacky, but needed for table dumping - mysql_path => $externalPrograms{mysql}, - mysqldump_path => $externalPrograms{mysqldump}, -); - -if ($ce->{database_driver} =~ /^mysql$/i) { - # The extra UTF8 connection setting is ONLY needed for older DBD:mysql driver - # and forbidden by the newer DBD::MariaDB driver - if ($ENABLE_UTF8MB4) { - $sqlParams{mysql_enable_utf8mb4} = 1; # Full 4-bit UTF-8 - } else { - $sqlParams{mysql_enable_utf8} = 1; # Only the partial 3-bit mySQL UTF-8 - } -} - -%dbLayouts = (); # layouts are added to this hash below - -$dbLayouts{sql_single} = { - locations => { - record => "WeBWorK::DB::Record::Locations", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, non_native => 1 }, - }, - location_addresses => { - record => "WeBWorK::DB::Record::LocationAddresses", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, non_native => 1 }, - }, - depths => { - record => "WeBWorK::DB::Record::Depths", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - params => { %sqlParams, non_native => 1 }, - }, - lti_launch_data => { - record => "WeBWorK::DB::Record::LTILaunchData", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, non_native => 1 }, - }, - lti_course_map => { - record => "WeBWorK::DB::Record::LTICourseMap", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, non_native => 1 }, - }, - password => { - record => "WeBWorK::DB::Record::Password", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_password" }, - }, - permission => { - record => "WeBWorK::DB::Record::PermissionLevel", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_permission" }, - }, - key => { - record => "WeBWorK::DB::Record::Key", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_key" }, - }, - user => { - record => "WeBWorK::DB::Record::User", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_user" }, - }, - set => { - record => "WeBWorK::DB::Record::Set", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_set" }, - }, - set_user => { - record => "WeBWorK::DB::Record::UserSet", - schema => "WeBWorK::DB::Schema::NewSQL::NonVersioned", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_set_user" }, - }, - set_merged => { - record => "WeBWorK::DB::Record::UserSet", - schema => "WeBWorK::DB::Schema::NewSQL::Merge", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - depend => [qw/set_user set/], - params => { - %sqlParams, - non_native => 1, - merge => [qw/set_user set/], - }, - }, - set_version => { - record => "WeBWorK::DB::Record::SetVersion", - schema => "WeBWorK::DB::Schema::NewSQL::Versioned", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - params => { - %sqlParams, - non_native => 1, - tableOverride => "${courseName}_set_user", - - }, - }, - set_version_merged => { - record => "WeBWorK::DB::Record::SetVersion", - schema => "WeBWorK::DB::Schema::NewSQL::Merge", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - depend => [qw/set_version set_user set/], - params => { - %sqlParams, - non_native => 1, - merge => [qw/set_version set_user set/], - }, - }, - set_locations => { - record => "WeBWorK::DB::Record::SetLocations", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_set_locations" }, - }, - set_locations_user => { - record => "WeBWorK::DB::Record::UserSetLocations", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_set_locations_user" }, - }, - problem => { - record => "WeBWorK::DB::Record::Problem", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_problem" }, - }, - problem_user => { - record => "WeBWorK::DB::Record::UserProblem", - schema => "WeBWorK::DB::Schema::NewSQL::NonVersioned", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_problem_user" }, - }, - problem_merged => { - record => "WeBWorK::DB::Record::UserProblem", - schema => "WeBWorK::DB::Schema::NewSQL::Merge", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - depend => [qw/problem_user problem/], - params => { - %sqlParams, - non_native => 1, - merge => [qw/problem_user problem/], - }, - }, - problem_version => { - record => "WeBWorK::DB::Record::ProblemVersion", - schema => "WeBWorK::DB::Schema::NewSQL::Versioned", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { - %sqlParams, - non_native => 1, - tableOverride => "${courseName}_problem_user", - }, - }, - problem_version_merged => { - record => "WeBWorK::DB::Record::ProblemVersion", - schema => "WeBWorK::DB::Schema::NewSQL::Merge", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - depend => [qw/problem_version problem_user problem/], - params => { - %sqlParams, - non_native => 1, - merge => [qw/problem_version problem_user problem/], - }, - }, - setting => { - record => "WeBWorK::DB::Record::Setting", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_setting" }, - }, - achievement => { - record => "WeBWorK::DB::Record::Achievement", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_achievement" }, - }, - past_answer => { - record => "WeBWorK::DB::Record::PastAnswer", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_past_answer" }, - }, - - achievement_user => { - record => "WeBWorK::DB::Record::UserAchievement", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_achievement_user" }, - }, - global_user_achievement => { - record => "WeBWorK::DB::Record::GlobalUserAchievement", - schema => "WeBWorK::DB::Schema::NewSQL::Std", - driver => "WeBWorK::DB::Driver::SQL", - source => $database_dsn, - engine => $database_storage_engine, - character_set => $database_character_set, - params => { %sqlParams, tableOverride => "${courseName}_global_user_achievement" }, - }, -}; - -# include ("conf/database.conf"); # uncomment to provide local overrides - -1; diff --git a/conf/defaults.config b/conf/defaults.config index d08f399fbf..f939851149 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -585,34 +585,14 @@ $default_status = "Enrolled"; # Database options ################################################################################ -# Database schemas are defined in the file conf/database.conf and stored in the -# hash %dbLayouts. The standard schema is called "sql_single"; - -include( "./conf/database.conf.dist"); # always include database.conf.dist - - # in the rare case where you want local overrides - # you can place include("conf/database.conf") in - # the database.conf.dist file -# this change is meant to help alleviate the common mistake of forgetting to update the -# database.conf file when changing WW versions. - -# Select the default database layout. This can be overridden in the course.conf -# file of a particular course. The only database layout supported in WW 2.1.4 -# and up is "sql_single". -$dbLayoutName = "sql_single"; - -# This sets the symbol "dbLayout" as an alias for the selected database layout. -*dbLayout = $dbLayouts{$dbLayoutName}; - # This sets the max course id length. It might need to be changed depending # on what database tables are present. Mysql allows a max table length of 64 # characters. With the ${course_id}_global_user_achievement table that means # the max ${course_id} is exactly 40 characters. +# Reference: https://dev.mysql.com/doc/refman/8.0/en/identifier-length.html $maxCourseIdLength = 40; -# Reference: https://dev.mysql.com/doc/refman/8.0/en/identifier-length.html - ################################################################################ # Problem library options ################################################################################ @@ -706,25 +686,14 @@ $modelCoursesForCopy = [ "modelCourse" ]; # Authentication system ################################################################################ -# FIXME This mechanism is a little awkward and probably should be merged with -# the dblayout selection system somehow. - # Select the authentication module to use for normal logins. -# -# If this value is a string, the given authentication module will be used -# regardless of the database layout. -# -# If it is a hash, the database layout name will be looked up in the hash and -# the resulting value will be used as the authentication module. The special -# hash key "*" is used if no entry for the current database layout is found. -# -# If this value is a sequence of strings or hashes, then each string or hash in -# the sequence will be successively tested to see if it provides a module that -# can handle the authentication request by calling the module's sub -# request_has_data_for_this_verification_module(). The first module that +# If this value is a string, then that authentication module will be used. If +# this value is a reference to an array of strings, then each string in the +# array will be successively tested to see if it provides a module that can +# handle the authentication request (by calling that module's +# request_has_data_for_this_verification_module method). The first module that # responds affirmatively will be used. - -$authen{user_module} = {"*" => "WeBWorK::Authen::Basic_TheLastOption"}; +$authen{user_module} = 'WeBWorK::Authen::Basic_TheLastOption'; # Select the authentication module to use for proctor logins. # A string or a hash is accepted, as above. diff --git a/conf/localOverrides.conf.dist b/conf/localOverrides.conf.dist index d4c2302680..b85772929d 100644 --- a/conf/localOverrides.conf.dist +++ b/conf/localOverrides.conf.dist @@ -12,14 +12,12 @@ # localOverrides.conf contains the local modifications commonly made # when installing WeBWorK on a new site. The configurations in defaults.config -# and in database.conf can usually remain untouched. +# should not be changed. # # localOverride.conf is the appropriate place to override permission settings, # paths to macros and other customizations that are specific to your # WeBWorK site - - ################################################################################ # Additional mail settings in defaults.config can be overridden here ################################################################################ @@ -446,24 +444,16 @@ $mail{feedbackRecipients} = [ # methods of authentication. # Select the authentication module to use for normal logins. -# -# If this value is a string, the given authentication module will be used -# regardless of the database layout. -# -# If it is a hash, the database layout name will be looked up in the hash and -# the resulting value will be used as the authentication module. The special -# hash key "*" is used if no entry for the current database layout is found. -# -# If this value is a sequence of strings or hashes, then each string or hash in -# the sequence will be successively tested to see if it provides a module that -# can handle the authentication request by calling the module's sub -# request_has_data_for_this_verification_module(). The first module that +# If this value is a string, then that authentication module will be used. If +# this value is a reference to an array of strings, then each string in the +# array will be successively tested to see if it provides a module that can +# handle the authentication request (by calling that module's +# request_has_data_for_this_verification_module method). The first module that # responds affirmatively will be used. - -#$authen{user_module} = { -# "*" => "WeBWorK::Authen::LDAP" -# "*" => "WeBWorK::Authen::Basic_TheLastOption" -#}; +#$authen{user_module} = [ +# "WeBWorK::Authen::LDAP", +# "WeBWorK::Authen::Basic_TheLastOption" +#]; # Select the authentication module to use for proctor logins. # A string or a hash is accepted, as above. diff --git a/courses.dist/modelCourse/course.conf b/courses.dist/modelCourse/course.conf index fb80c242a5..ff74987a9a 100644 --- a/courses.dist/modelCourse/course.conf +++ b/courses.dist/modelCourse/course.conf @@ -2,17 +2,6 @@ # This file is used to override the global WeBWorK course environment for this course. -# Database Layout (global value typically defined in global.conf) -# Several database are defined in the file conf/database.conf and stored in the -# hash %dbLayouts. -# The database layout is always set here, since one should be able to change the -# default value in global.conf without disrupting existing courses. -# global.conf values: -# $dbLayoutName = 'sql_single'; -# *dbLayout = $dbLayouts{$dbLayoutName}; -$dbLayoutName = 'sql_single'; -*dbLayout = $dbLayouts{$dbLayoutName}; - # Users for whom to label problems with the PG file name # For users in this list, PG will display the source file name when rendering a problem. #$pg{specialPGEnvironmentVars}{PRINT_FILE_NAMES_FOR} = ['user_id1']; diff --git a/lib/FormatRenderedProblem.pm b/lib/FormatRenderedProblem.pm index 9d6bdefeb6..1c7f0194f3 100644 --- a/lib/FormatRenderedProblem.pm +++ b/lib/FormatRenderedProblem.pm @@ -416,7 +416,6 @@ sub pretty_print { # certain internals of the CourseEnvironment in case one slips in. next if (($key =~ /database/) - || ($key =~ /dbLayout/) || ($key eq "ConfigValues") || ($key eq "ENV") || ($key eq "externalPrograms") diff --git a/lib/Mojolicious/WeBWorK.pm b/lib/Mojolicious/WeBWorK.pm index 185a865ea3..c9315547c4 100644 --- a/lib/Mojolicious/WeBWorK.pm +++ b/lib/Mojolicious/WeBWorK.pm @@ -163,8 +163,7 @@ sub startup ($app) { writeTimingLogEntry( $c->ce, '[' . $c->url_for . ']', - sprintf('runTime = %.3f sec', $c->timing->elapsed('content_generator_rendering')) . ' ' - . $c->ce->{dbLayoutName} + sprintf('runTime = %.3f sec', $c->timing->elapsed('content_generator_rendering')) ); } } diff --git a/lib/Mojolicious/WeBWorK/Tasks/AchievementNotification.pm b/lib/Mojolicious/WeBWorK/Tasks/AchievementNotification.pm index daf79fec1a..00640afa51 100644 --- a/lib/Mojolicious/WeBWorK/Tasks/AchievementNotification.pm +++ b/lib/Mojolicious/WeBWorK/Tasks/AchievementNotification.pm @@ -24,7 +24,7 @@ sub run ($job, $mail_data) { $job->{language_handle} = WeBWorK::Localize::getLoc($ce->{language} || 'en'); - my $db = WeBWorK::DB->new($ce->{dbLayout}); + my $db = WeBWorK::DB->new($ce); return $job->fail($job->maketext('Could not obtain database connection for [_1].', $courseID)) unless $db; diff --git a/lib/Mojolicious/WeBWorK/Tasks/LTIMassUpdate.pm b/lib/Mojolicious/WeBWorK/Tasks/LTIMassUpdate.pm index 192c95f053..e0d9e5b866 100644 --- a/lib/Mojolicious/WeBWorK/Tasks/LTIMassUpdate.pm +++ b/lib/Mojolicious/WeBWorK/Tasks/LTIMassUpdate.pm @@ -21,7 +21,7 @@ sub run ($job, $userID = '', $setID = '') { $job->{language_handle} = WeBWorK::Localize::getLoc($ce->{language} || 'en'); - my $db = WeBWorK::DB->new($ce->{dbLayout}); + my $db = WeBWorK::DB->new($ce); return $job->fail($job->maketext('Could not obtain database connection.')) unless $db; my @messages; diff --git a/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm b/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm index eb7fc8c534..388d2338ff 100644 --- a/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm +++ b/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm @@ -21,7 +21,7 @@ sub run ($job, $mail_data) { $job->{language_handle} = WeBWorK::Localize::getLoc($ce->{language} || 'en'); - my $db = WeBWorK::DB->new($ce->{dbLayout}); + my $db = WeBWorK::DB->new($ce); return $job->fail($job->maketext('Could not obtain database connection.')) unless $db; my @result_messages = eval { $job->mail_message_to_recipients($ce, $db, $mail_data) }; diff --git a/lib/WeBWorK.pm b/lib/WeBWorK.pm index 34a3e92b77..72fd080281 100644 --- a/lib/WeBWorK.pm +++ b/lib/WeBWorK.pm @@ -142,7 +142,7 @@ async sub dispatch ($c) { || -e "$ce->{webwork_courses_dir}/$ce->{admin_course_id}/archives/$routeCaptures{courseID}.tar.gz"); return (0, 'This course has been archived and closed.') unless -e $ce->{courseDirs}{root}; - my $db = WeBWorK::DB->new($ce->{dbLayout}); + my $db = WeBWorK::DB->new($ce); debug("(here's the DB handle: $db)\n"); $c->db($db); diff --git a/lib/WeBWorK/Authen.pm b/lib/WeBWorK/Authen.pm index 860c5dd58d..626eff938c 100644 --- a/lib/WeBWorK/Authen.pm +++ b/lib/WeBWorK/Authen.pm @@ -79,29 +79,21 @@ sub class { my ($ce, $type) = @_; if (exists $ce->{authen}{$type}) { - if (ref $ce->{authen}{$type} eq "ARRAY") { + if (ref $ce->{authen}{$type} eq 'ARRAY') { my $authen_type = shift @{ $ce->{authen}{$type} }; - if (ref($authen_type) eq "HASH") { - if (exists $authen_type->{ $ce->{dbLayoutName} }) { - return $authen_type->{ $ce->{dbLayoutName} }; - } elsif (exists $authen_type->{"*"}) { - return $authen_type->{"*"}; - } else { - die "authentication type '$type' in the course environment has no entry for db layout '", - $ce->{dbLayoutName}, "' and no default entry (*)"; - } + if (ref($authen_type) eq 'HASH') { + # Basic backwards compatibility. + return $authen_type->{'*'} if exists $authen_type->{'*'}; + return $authen_type->{sql_single} if exists $authen_type->{sql_single}; + die 'Unsupported authentication module format in the course environment.'; } else { return $authen_type; } - } elsif (ref $ce->{authen}{$type} eq "HASH") { - if (exists $ce->{authen}{$type}{ $ce->{dbLayoutName} }) { - return $ce->{authen}{$type}{ $ce->{dbLayoutName} }; - } elsif (exists $ce->{authen}{$type}{"*"}) { - return $ce->{authen}{$type}{"*"}; - } else { - die "authentication type '$type' in the course environment has no entry for db layout '", - $ce->{dbLayoutName}, "' and no default entry (*)"; - } + } elsif (ref $ce->{authen}{$type} eq 'HASH') { + # Basic backwards compatibility. + return $ce->{authen}{$type}{'*'} if exists $ce->{authen}{$type}{'*'}; + return $ce->{authen}{$type}{sql_single} if exists $ce->{authen}{$type}{sql_single}; + die 'Unsupported authentication module format in the course environment.'; } else { return $ce->{authen}{$type}; } @@ -115,9 +107,7 @@ sub call_next_authen_method { my $c = $self->{c}; my $ce = $c->{ce}; - my $user_authen_module = - WeBWorK::Authen::class($ce, $ce->{courseName} eq $ce->{admin_course_id} ? 'admin_module' : 'user_module'); - + my $user_authen_module = class($ce, $ce->{courseName} eq $ce->{admin_course_id} ? 'admin_module' : 'user_module'); if (!defined $user_authen_module || $user_authen_module eq '') { $self->{error} = $c->maketext( "No authentication method found for your request. If this recurs, please speak with your instructor."); diff --git a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm index 84a4c4f114..c8125cb2d0 100644 --- a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -25,7 +25,6 @@ use WeBWorK::DB; sub pre_header_initialize ($c) { my $ce = $c->ce; - my $db = $c->db; my $authz = $c->authz; my $user = $c->param('user'); @@ -33,7 +32,7 @@ sub pre_header_initialize ($c) { # Check that the non-native tables are present in the database. # These are the tables which are not course specific. - my @table_update_messages = initNonNativeTables($ce, $ce->{dbLayoutName}); + my @table_update_messages = initNonNativeTables($ce); $c->addgoodmessage($c->c(@table_update_messages)->join($c->tag('br'))) if @table_update_messages; my @errors; @@ -236,7 +235,6 @@ sub add_course_validate ($c) { my $add_courseID = trim_spaces($c->param('new_courseID')) || ''; my $number_of_additional_users = $c->param('number_of_additional_users') || 0; - my $add_dbLayout = trim_spaces($c->param('add_dbLayout')) || ''; my @errors; @@ -266,17 +264,6 @@ sub add_course_validate ($c) { } } - if ($add_dbLayout eq '') { - push @errors, 'You must select a database layout.'; - } else { - if (exists $ce->{dbLayouts}{$add_dbLayout}) { - # we used to check for layout-specific fields here, but there aren't any layouts that require them - # anymore. (in the future, we'll probably deal with this in layout-specific modules.) - } else { - push @errors, "The database layout $add_dbLayout doesn't exist."; - } - } - return @errors; } @@ -292,11 +279,9 @@ sub do_add_course ($c) { my $copy_from_course = trim_spaces($c->param('copy_from_course')) // ''; - my $add_dbLayout = trim_spaces($c->param('add_dbLayout')) || ''; - my $ce2 = WeBWorK::CourseEnvironment->new({ courseName => $add_courseID }); - my %courseOptions = (dbLayoutName => $add_dbLayout); + my %courseOptions; my @users; @@ -472,9 +457,8 @@ sub rename_course_confirm ($c) { # Create strings confirming title and institution change. # Connect to the database to get old title and institution. - my $dbLayoutName = $ce->{dbLayoutName}; - my $db = WeBWorK::DB->new($ce->{dbLayouts}{$dbLayoutName}); - my $oldDB = WeBWorK::DB->new($ce2->{dbLayouts}{$dbLayoutName}); + my $db = WeBWorK::DB->new($ce); + my $oldDB = WeBWorK::DB->new($ce2); my $rename_oldCourseTitle = $oldDB->getSettingValue('courseTitle') // ''; my $rename_oldCourseInstitution = $oldDB->getSettingValue('courseInstitution') // ''; @@ -498,49 +482,45 @@ sub rename_course_confirm ($c) { rename_oldCourseID => $rename_oldCourseID ) unless $c->param('rename_newCourseID_checkbox'); - if ($ce2->{dbLayoutName}) { - my $CIchecker = WeBWorK::Utils::CourseDBIntegrityCheck->new($ce2); - - # Check database - my ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($rename_oldCourseID); + my $CIchecker = WeBWorK::Utils::CourseDBIntegrityCheck->new($ce2); - # Upgrade the database if requested. - my @upgrade_report; - if ($c->param('upgrade_course_tables')) { - my @schema_table_names = keys %$dbStatus; - my @tables_to_create = - grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::ONLY_IN_A } @schema_table_names; - my @tables_to_alter = - grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::DIFFER_IN_A_AND_B } - @schema_table_names; - push(@upgrade_report, $CIchecker->updateCourseTables($rename_oldCourseID, [@tables_to_create])); - for my $table_name (@tables_to_alter) { - push(@upgrade_report, $CIchecker->updateTableFields($rename_oldCourseID, $table_name)); - } + # Check database + my ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($rename_oldCourseID); - ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($rename_oldCourseID); + # Upgrade the database if requested. + my @upgrade_report; + if ($c->param('upgrade_course_tables')) { + my @schema_table_names = keys %$dbStatus; + my @tables_to_create = + grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::ONLY_IN_A } @schema_table_names; + my @tables_to_alter = + grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::DIFFER_IN_A_AND_B } + @schema_table_names; + push(@upgrade_report, $CIchecker->updateCourseTables($rename_oldCourseID, [@tables_to_create])); + for my $table_name (@tables_to_alter) { + push(@upgrade_report, $CIchecker->updateTableFields($rename_oldCourseID, $table_name)); } - # Check directories - my ($directories_ok, $directory_report) = checkCourseDirectories($ce2); - - return $c->include( - 'ContentGenerator/CourseAdmin/rename_course_confirm', - upgrade_report => \@upgrade_report, - tables_ok => $tables_ok, - dbStatus => $dbStatus, - directory_report => $directory_report, - directories_ok => $directories_ok, - rename_oldCourseTitle => $rename_oldCourseTitle, - change_course_title_str => $change_course_title_str, - rename_oldCourseInstitution => $rename_oldCourseInstitution, - change_course_institution_str => $change_course_institution_str, - rename_oldCourseID => $rename_oldCourseID, - rename_newCourseID => $rename_newCourseID - ); - } else { - return $c->tag('p', class => 'text-danger fw-bold', "Unable to find database layout for $rename_oldCourseID"); + ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($rename_oldCourseID); } + + # Check directories + my ($directories_ok, $directory_report) = checkCourseDirectories($ce2); + + return $c->include( + 'ContentGenerator/CourseAdmin/rename_course_confirm', + upgrade_report => \@upgrade_report, + tables_ok => $tables_ok, + dbStatus => $dbStatus, + directory_report => $directory_report, + directories_ok => $directories_ok, + rename_oldCourseTitle => $rename_oldCourseTitle, + change_course_title_str => $change_course_title_str, + rename_oldCourseInstitution => $rename_oldCourseInstitution, + change_course_institution_str => $change_course_institution_str, + rename_oldCourseID => $rename_oldCourseID, + rename_newCourseID => $rename_newCourseID + ); } sub rename_course_validate ($c) { @@ -965,48 +945,44 @@ sub archive_course_confirm ($c) { my $ce2 = WeBWorK::CourseEnvironment->new({ courseName => $archive_courseID }); - if ($ce2->{dbLayoutName}) { - my $CIchecker = WeBWorK::Utils::CourseDBIntegrityCheck->new($ce2); - - # Check database - my ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($archive_courseID); + my $CIchecker = WeBWorK::Utils::CourseDBIntegrityCheck->new($ce2); - # Upgrade the database if requested. - my @upgrade_report; - if ($c->param('upgrade_course_tables')) { - my @schema_table_names = keys %$dbStatus; - my @tables_to_create = - grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::ONLY_IN_A } @schema_table_names; - my @tables_to_alter = - grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::DIFFER_IN_A_AND_B } - @schema_table_names; - push(@upgrade_report, $CIchecker->updateCourseTables($archive_courseID, [@tables_to_create])); - for my $table_name (@tables_to_alter) { - push(@upgrade_report, $CIchecker->updateTableFields($archive_courseID, $table_name)); - } + # Check database + my ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($archive_courseID); - ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($archive_courseID); + # Upgrade the database if requested. + my @upgrade_report; + if ($c->param('upgrade_course_tables')) { + my @schema_table_names = keys %$dbStatus; + my @tables_to_create = + grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::ONLY_IN_A } @schema_table_names; + my @tables_to_alter = + grep { $dbStatus->{$_}->[0] == WeBWorK::Utils::CourseDBIntegrityCheck::DIFFER_IN_A_AND_B } + @schema_table_names; + push(@upgrade_report, $CIchecker->updateCourseTables($archive_courseID, [@tables_to_create])); + for my $table_name (@tables_to_alter) { + push(@upgrade_report, $CIchecker->updateTableFields($archive_courseID, $table_name)); } - # Update and check directories. - my $dir_update_messages = $c->param('upgrade_course_tables') ? updateCourseDirectories($ce2) : []; - my ($directories_ok, $directory_report) = checkCourseDirectories($ce2); - - return $c->include( - 'ContentGenerator/CourseAdmin/archive_course_confirm', - ce2 => $ce2, - upgrade_report => \@upgrade_report, - tables_ok => $tables_ok, - dbStatus => $dbStatus, - dir_update_messages => $dir_update_messages, - directory_report => $directory_report, - directories_ok => $directories_ok, - archive_courseID => $archive_courseID, - archive_courseIDs => \@archive_courseIDs - ); - } else { - return $c->tag('p', class => 'text-danger fw-bold', "Unable to find database layout for $archive_courseID"); + ($tables_ok, $dbStatus) = $CIchecker->checkCourseTables($archive_courseID); } + + # Update and check directories. + my $dir_update_messages = $c->param('upgrade_course_tables') ? updateCourseDirectories($ce2) : []; + my ($directories_ok, $directory_report) = checkCourseDirectories($ce2); + + return $c->include( + 'ContentGenerator/CourseAdmin/archive_course_confirm', + ce2 => $ce2, + upgrade_report => \@upgrade_report, + tables_ok => $tables_ok, + dbStatus => $dbStatus, + dir_update_messages => $dir_update_messages, + directory_report => $directory_report, + directories_ok => $directories_ok, + archive_courseID => $archive_courseID, + archive_courseIDs => \@archive_courseIDs + ); } sub do_archive_course ($c) { @@ -1232,7 +1208,7 @@ sub do_unarchive_course ($c) { if ($c->param('clean_up_course')) { my $ce_new = WeBWorK::CourseEnvironment->new({ courseName => $new_courseID }); - my $db_new = WeBWorK::DB->new($ce_new->{dbLayout}); + my $db_new = WeBWorK::DB->new($ce_new); for my $student_id ($db_new->listPermissionLevelsWhere({ permission => $ce->{userRoles}{student} })) { $db_new->deleteUser($student_id->[0]); @@ -2435,7 +2411,7 @@ sub manage_otp_secrets_form ($c) { # Create course data first, since it is used in all cases and initializes course db references. for my $courseID (listCourses($c->ce)) { my $ce = WeBWorK::CourseEnvironment->new({ courseName => $courseID }); - $dbs->{$courseID} = WeBWorK::DB->new($ce->{dbLayouts}{ $ce->{dbLayoutName} }); + $dbs->{$courseID} = WeBWorK::DB->new($ce); # By default ignore courses larger than 200 users, as this can cause a large load building menus. my @users = $dbs->{$courseID}->listUsers; @@ -2543,7 +2519,7 @@ sub copy_otp_secrets_confirm ($c) { my @rows; my %dbs; my $source_ce = WeBWorK::CourseEnvironment->new({ courseName => $source_course }); - $dbs{$source_course} = WeBWorK::DB->new($source_ce->{dbLayouts}{ $source_ce->{dbLayoutName} }); + $dbs{$source_course} = WeBWorK::DB->new($source_ce); for my $s_user (@source_users) { my $s_user_password = $dbs{$source_course}->getPassword($s_user); @@ -2571,7 +2547,7 @@ sub copy_otp_secrets_confirm ($c) { unless ($dbs{$d_course}) { my $dest_ce = WeBWorK::CourseEnvironment->new({ courseName => $d_course }); - $dbs{$d_course} = WeBWorK::DB->new($dest_ce->{dbLayouts}{ $dest_ce->{dbLayoutName} }); + $dbs{$d_course} = WeBWorK::DB->new($dest_ce); } my $d_user_password = $dbs{$d_course}->getPassword($d_user); @@ -2620,7 +2596,7 @@ sub reset_otp_secrets_confirm ($c) { } my $ce = WeBWorK::CourseEnvironment->new({ courseName => $source_course }); - my $db = WeBWorK::DB->new($ce->{dbLayouts}{ $ce->{dbLayoutName} }); + my $db = WeBWorK::DB->new($ce); my @rows; for my $user (@dest_users) { my $password = $db->getPassword($user); diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index f9fd0de1d9..80110d963f 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -424,7 +424,7 @@ async sub pre_header_initialize ($c) { } else { # If there is not a requested version or a latest version, then create dummy set to proceed. # FIXME RETURN TO: should this be global2version? - $set = global2user($ce->{dbLayout}{set_version}{record}, $db->getGlobalSet($setID)); + $set = global2user($db->{set_version}{record}, $db->getGlobalSet($setID)); $set->user_id($effectiveUserID); $set->psvn('000'); $set->set_id($setID); # redundant? diff --git a/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm b/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm index 419a7e7fab..ad218e70ca 100644 --- a/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm +++ b/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm @@ -22,7 +22,7 @@ sub initializeRoute ($c, $routeCaptures) { if (!$courseID && $c->param('context_id')) { # The database object used here is not associated to any course, # and so the only has access to non-native tables. - my @matchingCourses = WeBWorK::DB->new(WeBWorK::CourseEnvironment->new->{dbLayout}) + my @matchingCourses = WeBWorK::DB->new(WeBWorK::CourseEnvironment->new) ->getLTICourseMapsWhere({ lms_context_id => $c->param('context_id') }); if (@matchingCourses == 1) { diff --git a/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm b/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm index b7182b7e1f..1559c3a207 100644 --- a/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm +++ b/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm @@ -61,11 +61,10 @@ sub initializeRoute ($c, $routeCaptures) { # The database object used here is not associated to any course, # and so the only has access to non-native tables. - my @matchingCourses = - WeBWorK::DB->new(WeBWorK::CourseEnvironment->new->{dbLayout})->getLTICourseMapsWhere({ - lms_context_id => + my @matchingCourses = WeBWorK::DB->new(WeBWorK::CourseEnvironment->new)->getLTICourseMapsWhere({ + lms_context_id => $c->stash->{lti_jwt_claims}{'https://purl.imsglobal.org/spec/lti/claim/context'}{id} - }); + }); if (@matchingCourses == 1) { $c->stash->{courseID} = $matchingCourses[0]->course_id; @@ -333,7 +332,7 @@ sub extract_jwt_claims ($c) { return unless $c->param('state'); # The following database object is not associated to any course, and so the only has access to non-native tables. - my $db = WeBWorK::DB->new(WeBWorK::CourseEnvironment->new->{dbLayout}); + my $db = WeBWorK::DB->new(WeBWorK::CourseEnvironment->new); # Retrieve the launch data saved in the login phase, and then delete it from the database. Note that this verifies # the state in the request. If there is no launch data saved in the database for the state in the request, then the @@ -356,7 +355,7 @@ sub extract_jwt_claims ($c) { 'Failed to initialize course environment for ' . $c->stash->{LTILaunchData}->data->{courseID} . ": $@\n"; return; } - $db = WeBWorK::DB->new($ce->{dbLayout}); + $db = WeBWorK::DB->new($ce); $c->purge_expired_lti_data($ce, $db); diff --git a/lib/WeBWorK/DB.pm b/lib/WeBWorK/DB.pm index 226ae4ff58..1ace11f80e 100644 --- a/lib/WeBWorK/DB.pm +++ b/lib/WeBWorK/DB.pm @@ -1,4 +1,5 @@ package WeBWorK::DB; +use Mojo::Base -strict; =head1 NAME @@ -6,7 +7,7 @@ WeBWorK::DB - interface with the WeBWorK databases. =head1 SYNOPSIS - my $db = WeBWorK::DB->new($dbLayout); + my $db = WeBWorK::DB->new($ce); my @userIDs = $db->listUsers(); my $Sam = $db->{user}->{record}->new(); @@ -25,11 +26,10 @@ WeBWorK::DB - interface with the WeBWorK databases. =head1 DESCRIPTION -WeBWorK::DB provides a consistent interface to a number of database backends. -Access and modification functions are provided for each logical table used by -the webwork system. The particular backend ("schema" and "driver"), record -class, data source, and additional parameters are specified by the hash -referenced by C<$dbLayout>, usually taken from the course environment. +WeBWorK::DB provides a database interface. Access and modification functions +are provided for each logical table used by the webwork system. The particular +schema, record class, and additional parameters are specified by the hash return +by the C method. =head1 ARCHITECTURE @@ -54,41 +54,34 @@ They are called "schema" modules because they control the structure of the data for a table. The schema modules provide an API that matches the requirements of the DB -layer, on a per-table basis. Each schema module has a style that determines -which drivers it can interface with. For example, SQL is an "dbi" style -schema. +layer, on a per-table basis. -=head2 Bottom Layer: Drivers +=head2 Bottom Layer: Database -Driver modules implement a style for a schema. They provide physical access to -a data source containing the data for a table. The style of a driver determines -what methods it provides. All drivers provide C and -C methods. A dbi style driver provides a C method which -returns the DBI handle. +The C module implements a DBI connection handle. It provides physical +access to the database. =head2 Record Types -In C<%dblayout>, each table is assigned a record class, used for passing +In the database layout, each table is assigned a record class, used for passing complete records to and from the database. The default record classes are subclasses of the WeBWorK::DB::Record class, and are named as follows: User, Password, PermissionLevel, Key, Set, UserSet, Problem, UserProblem. In the -following documentation, a reference the record class for a table means the -record class currently defined for that table in C<%dbLayout>. +following documentation, a reference to the record class for a table means the +record class currently defined for that table in the database layout. =cut -use strict; -use warnings; - use Carp; use Data::Dumper; -use Scalar::Util qw/blessed/; -use HTML::Entities qw( encode_entities ); +use Scalar::Util qw(blessed); +use HTML::Entities qw(encode_entities); use Mojo::JSON qw(encode_json decode_json); +use WeBWorK::DB::Database; use WeBWorK::DB::Schema; -use WeBWorK::DB::Utils qw/make_vsetID grok_vsetID grok_setID_from_vsetID_sql - grok_versionID_from_vsetID_sql/; +use WeBWorK::DB::Layout qw(databaseLayout); +use WeBWorK::DB::Utils qw(make_vsetID grok_vsetID grok_setID_from_vsetID_sql grok_versionID_from_vsetID_sql); use WeBWorK::Debug; use WeBWorK::Utils qw(runtime_use); @@ -149,77 +142,51 @@ use Exception::Class ( }, ); -################################################################################ -# constructor -################################################################################ - =head1 CONSTRUCTOR -=over - -=item new($dbLayout) - -The C method creates a DB object and brings up the underlying schema/driver -structure according to the hash referenced by C<$dbLayout>. - -=back - -=head2 C<$dbLayout> Format - -C<$dbLayout> is a hash reference consisting of items keyed by table names. The -value of each item is a reference to a hash containing the following items: - -=over - -=item record - -The name of a perl module to use for representing the data in a record. - -=item schema - -The name of a perl module to use for access to the table. + my $db = WeBWorK::DB->new($ce) -=item driver +The C method creates a DB object, connects to the database via the +C module, and brings up the underlying schema structure according to +the hash referenced in the L. A course +environment object is the only required argument (as it is used to construct the +database layout). -The name of a perl module to use for access to the data source. - -=item source - -The location of the data source that should be used by the driver module. -Depending on the driver, this may be a path, a url, or a DBI spec. - -=item params - -A reference to a hash containing extra information needed by the schema. Some -schemas require parameters, some do not. Consult the documentation for the -schema in question. - -=back - -For each table defined in C<$dbLayout>, C loads the record, schema, and -driver modules. It the schema module's C method lists the current table -(or contains the string "*") and the output of the schema and driver modules' -C