diff --git a/.gitignore b/.gitignore index 2129ff5078..8dca4e4871 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,9 @@ applets tmp logs courses.dist -library-directory-tree.json -library-subject-tree.json -textbook-tree.json +*library-directory-tree.json +*library-subject-tree.json +*textbook-tree.json development.yml *~ !tmp/README diff --git a/bin/OPL-update b/bin/OPL-update index 72382f38cd..9425a89527 100755 --- a/bin/OPL-update +++ b/bin/OPL-update @@ -21,6 +21,32 @@ use File::Basename; use Cwd; use DBI; +# Command line arguments +# for some reason the first command line argument is disappearing before it gets here + +my $myLib = "OPL" ; # default value +my $clearAll = 1 ; # default value - drop ALL old tables + +if ( ( 0 + @ARGV ) > 0 ) { + + #print join(" , ", @ARGV ); + + $myLib = shift; + + print "myLib = $myLib \n"; + + my $nextArg = "none"; + if ( @ARGV ) { + $nextArg = shift ; + if ( $nextArg eq "noDrop" ) { + $clearAll = 0 ; + print "Received the noDrop setting.\n"; + } + + } +} + + #(maximum varchar length is 255 for mysql version < 5.0.3. #You can increase path length to 4096 for mysql > 5.0.3) @@ -56,6 +82,9 @@ my %OPLtables = ( problem => 'OPL_problem', morelt => 'OPL_morelt', pgfile_problem => 'OPL_pgfile_problem', + cnt_dbsubject => 'Cnt_DBsubject', + cnt_dbchapter => 'Cnt_DBchapter', + cnt_dbsection => 'Cnt_DBsection', ); @@ -74,8 +103,34 @@ my %NPLtables = ( problem => 'NPL-problem', morelt => 'NPL-morelt', pgfile_problem => 'NPL-pgfile-problem', + cnt_dbsubject => 'Cnt_DBsubject', + cnt_dbchapter => 'Cnt_DBchapter', + cnt_dbsection => 'Cnt_DBsection', ); +# Which tables to ALWAYS drop and recreate and which can remain +# 1 = always drop, 0 = conditional on command-line arguments, 2 = NEVER drop +my %AlwayDropTables = ( + dbsubject => 0, + dbchapter => 0, + dbsection => 0, + author => 0, + path => 0, + keyword => 0, + textbook => 0, + chapter => 0, + section => 0, + problem => 0, + morelt => 0, + pgfile => 1, + pgfile_keyword => 1, + pgfile_problem => 1, + cnt_dbsubject => 2, + cnt_dbchapter => 2, + cnt_dbsection => 2, +); + + # Get database connection @@ -96,9 +151,9 @@ my $dbh = DBI->connect( }, ); -my $libraryRoot = $ce->{problemLibrary}->{root}; +my $libraryRoot = $ce->{problemLibrary}->{$myLib}->{root}; $libraryRoot =~ s|/+$||; -my $libraryVersion = $ce->{problemLibrary}->{version}; +my $libraryVersion = $ce->{problemLibrary}->{$myLib}->{version}; my $db_storage_engine = $ce->{problemLibrary_db}->{storage_engine}; my $verbose = 0; @@ -130,14 +185,30 @@ if($libraryVersion eq '2.5') { print "Library version is $libraryVersion; NPLtables! \n"; } + +# Modify table names for per-library tables +my @special_tables = qw( pgfile pgfile_keyword pgfile_problem ); +my $tmp1; my $tblName; +foreach $tmp1 ( @special_tables ) { + $tblName = $tables{$tmp1}; + #print "old table name $tblName\n"; + if ( $libraryVersion eq '2.5') { + $tblName =~ s/OPL/${myLib}/; + } else { + $tblName =~ s/NPL/${myLib}/; + } + #print "new table name $tblName\n"; + $tables{$tmp1} = $tblName; +} + @create_tables = ( -[$tables{dbsubject}, ' +["dbsubject",$tables{dbsubject}, ' DBsubject_id int(15) NOT NULL auto_increment, name varchar(255) NOT NULL, KEY DBsubject (name), PRIMARY KEY (DBsubject_id) '], -[$tables{dbchapter}, ' +["dbchapter",$tables{dbchapter}, ' DBchapter_id int(15) NOT NULL auto_increment, name varchar(255) NOT NULL, DBsubject_id int(15) DEFAULT 0 NOT NULL, @@ -145,7 +216,7 @@ if($libraryVersion eq '2.5') { KEY (DBsubject_id), PRIMARY KEY (DBchapter_id) '], -[$tables{dbsection}, ' +["dbsection",$tables{dbsection}, ' DBsection_id int(15) NOT NULL auto_increment, name varchar(255) NOT NULL, DBchapter_id int(15) DEFAULT 0 NOT NULL, @@ -153,7 +224,7 @@ if($libraryVersion eq '2.5') { KEY (DBchapter_id), PRIMARY KEY (DBsection_id) '], -[$tables{author}, ' +["author",$tables{author}, ' author_id int (15) NOT NULL auto_increment, institution tinyblob, lastname varchar (255) NOT NULL, @@ -162,7 +233,7 @@ if($libraryVersion eq '2.5') { KEY author (lastname(100), firstname(100)), PRIMARY KEY (author_id) '], -[$tables{path}, ' +["path",$tables{path}, ' path_id int(15) NOT NULL auto_increment, path varchar(255) NOT NULL, machine varchar(255), @@ -170,7 +241,7 @@ if($libraryVersion eq '2.5') { KEY (path), PRIMARY KEY (path_id) '], -[$tables{pgfile}, ' +["pgfile",$tables{pgfile}, ' pgfile_id int(15) NOT NULL auto_increment, DBsection_id int(15) NOT NULL, author_id int(15), @@ -184,19 +255,19 @@ if($libraryVersion eq '2.5') { MO TINYINT, PRIMARY KEY (pgfile_id) '], -[$tables{keyword}, ' +["keyword",$tables{keyword}, ' keyword_id int(15) NOT NULL auto_increment, keyword varchar(256) NOT NULL, KEY (keyword), PRIMARY KEY (keyword_id) '], -[$tables{pgfile_keyword}, ' +["pgfile_keyword",$tables{pgfile_keyword}, ' pgfile_id int(15) DEFAULT 0 NOT NULL, keyword_id int(15) DEFAULT 0 NOT NULL, KEY pgfile_keyword (keyword_id, pgfile_id), KEY pgfile (pgfile_id) '], -[$tables{textbook}, ' +["textbook",$tables{textbook}, ' textbook_id int (15) NOT NULL auto_increment, title varchar (255) NOT NULL, edition int (15) DEFAULT 0 NOT NULL, @@ -206,7 +277,7 @@ if($libraryVersion eq '2.5') { pubdate varchar (255), PRIMARY KEY (textbook_id) '], -[$tables{chapter}, ' +["chapter",$tables{chapter}, ' chapter_id int (15) NOT NULL auto_increment, textbook_id int (15), number int(3), @@ -216,7 +287,7 @@ if($libraryVersion eq '2.5') { KEY (number), PRIMARY KEY (chapter_id) '], -[$tables{section}, ' +["section",$tables{section}, ' section_id int(15) NOT NULL auto_increment, chapter_id int (15), number int(3), @@ -226,7 +297,7 @@ if($libraryVersion eq '2.5') { KEY (number), PRIMARY KEY section (section_id) '], -[$tables{problem}, ' +["problem",$tables{problem}, ' problem_id int(15) NOT NULL auto_increment, section_id int(15), number int(4) NOT NULL, @@ -235,7 +306,7 @@ if($libraryVersion eq '2.5') { KEY (section_id), PRIMARY KEY (problem_id) '], -[$tables{morelt}, ' +["morelt",$tables{morelt}, ' morelt_id int(15) NOT NULL auto_increment, name varchar(255) NOT NULL, DBsection_id int(15), @@ -243,10 +314,28 @@ if($libraryVersion eq '2.5') { KEY (name), PRIMARY KEY (morelt_id) '], -[$tables{pgfile_problem}, ' +["pgfile_problem",$tables{pgfile_problem}, ' pgfile_id int(15) DEFAULT 0 NOT NULL, problem_id int(15) DEFAULT 0 NOT NULL, PRIMARY KEY (pgfile_id, problem_id) +'], +["cnt_dbsubject",$tables{cnt_dbsubject}, ' + libcode varchar(60) NOT NULL, + DBsubject_id int(15) NOT NULL, + count int(15) NOT NULL, + PRIMARY KEY (libcode,DBsubject_id) +'], +["cnt_dbchapter",$tables{cnt_dbchapter}, ' + libcode varchar(60) NOT NULL, + DBchapter_id int(15) NOT NULL, + count int(15) NOT NULL, + PRIMARY KEY (libcode,DBchapter_id) +'], +["cnt_dbsection",$tables{cnt_dbsection}, ' + libcode varchar(60) NOT NULL, + DBsection_id int(15) NOT NULL, + count int(15) NOT NULL, + PRIMARY KEY (libcode,DBsection_id) ']); ### End of database data @@ -258,8 +347,25 @@ $dbh->do("DROP TABLE IF EXISTS `NPL-institution`"); $dbh->do("DROP TABLE IF EXISTS `NPL-pgfile-institution`"); for my $tableinfo (@create_tables) { - my $tabname = $tableinfo->[0]; - my $tabinit = $tableinfo->[1]; + my $tabCnm = $tableinfo->[0]; + my $tabname = $tableinfo->[1]; + my $tabinit = $tableinfo->[2]; + +# FIXME some tables should NOT be dropped on special libraries + if ( $AlwayDropTables{$tabCnm} == 2 ) { + print "Not dropping/re-creating $tabname\n"; + my $query = "CREATE TABLE IF NOT EXISTS `$tabname` ( $tabinit ) ENGINE=$db_storage_engine"; + $dbh->do($query); + next; + } + if ( $clearAll == 0 ) { + # Do not drop and recreate some tables + if ( $AlwayDropTables{$tabCnm} == 0 ) { + print "Not dropping/re-creating $tabname\n"; + next; + } + } + my $query = "DROP TABLE IF EXISTS `$tabname`"; $dbh->do($query); $query = "CREATE TABLE `$tabname` ( $tabinit ) ENGINE=$db_storage_engine"; @@ -431,7 +537,7 @@ if(open(IN, "$libraryRoot/Textbooks")) { close(IN); } else { print "Textbooks file was not found in library $libraryRoot. If the path to the problem library doesn't seem - correct, make modifications in webwork2/conf/site.conf (\$problemLibrary{root}). If that is correct then + correct, make modifications in webwork2/conf/localOverrides.conf (\$problemLibrary{OPL}{root}). If that is correct then updating from git should download the Textbooks file.\n"; } #### End of textbooks @@ -453,7 +559,7 @@ if(open(IN, "$libraryRoot/Taxonomy2")) { $canopenfile = 1; } else { print "Taxonomy file was not found in library $libraryRoot. If the path to the problem library doesn't seem - correct, make modifications in webwork2/conf/site.conf (\$problemLibrary{root}). If that is correct then + correct, make modifications in webwork2/conf/localOverrides.conf (\$problemLibrary{OPL}{root}). If that is correct then updating from git should download the Taxonomy file.\n"; } @@ -514,7 +620,12 @@ if($canopenfile) { #### Save the official taxonomy in json format my $webwork_htdocs = $ce->{webwork_dir}."/htdocs"; -my $file = "$webwork_htdocs/DATA/tagging-taxonomy.json"; + +# Get the filename for the taxo_file which is set for THIS library via the +# settings in conf/defaults.config and/or conf/localOverrides.conf +my $taxo_file = $ce->{problemLibrary}->{$myLib}->{taxo}; + +my $file = "$webwork_htdocs/DATA/${taxo_file}"; open(OUTF, ">$file") or die "Cannot open $file"; print OUTF to_json($tagtaxo,{pretty=>1}) or die "Cannot write to $file"; close(OUTF); @@ -860,33 +971,37 @@ sub pgfiles { print "\n\n"; -# Now prune away DBsection, etc, which do not appear in any files -#%my $query = "SELECT chapter_id FROM `$tables{chapter}` WHERE textbook_id = \"$bookid\" AND number = \"$1\""; -#%my $chapid = $dbh->selectrow_array($query); +# When allowing multiple libraries, only the FIRST library should do pruning. +if ( $clearAll == 1 ) { -#select dbs.DBsection_id from OPL_DBsection dbs; -#select COUNT(*) from OPL_pgfile where DBsection_id=857; + # Now prune away DBsection, etc, which do not appear in any files + #%my $query = "SELECT chapter_id FROM `$tables{chapter}` WHERE textbook_id = \"$bookid\" AND number = \"$1\""; + #%my $chapid = $dbh->selectrow_array($query); -my $dbsects = $dbh->selectall_arrayref("SELECT DBsection_id from `$tables{dbsection}`"); -for my $sect (@{$dbsects}) { + #select dbs.DBsection_id from OPL_DBsection dbs; + #select COUNT(*) from OPL_pgfile where DBsection_id=857; + + my $dbsects = $dbh->selectall_arrayref("SELECT DBsection_id from `$tables{dbsection}`"); + for my $sect (@{$dbsects}) { $sect = $sect->[0]; my $srar = $dbh->selectall_arrayref("SELECT * FROM `$tables{pgfile}` WHERE DBsection_id=$sect"); if(scalar(@{$srar})==0) { $dbh->do("DELETE FROM `$tables{dbsection}` WHERE DBsection_id=$sect"); } -} + } -my $dbchaps = $dbh->selectall_arrayref("SELECT DBchapter_id from `$tables{dbchapter}`"); -for my $chap (@{$dbchaps}) { + my $dbchaps = $dbh->selectall_arrayref("SELECT DBchapter_id from `$tables{dbchapter}`"); + for my $chap (@{$dbchaps}) { $chap = $chap->[0]; my $srar = $dbh->selectall_arrayref("SELECT * FROM `$tables{dbsection}` WHERE DBchapter_id=$chap"); if(scalar(@{$srar})==0) { $dbh->do("DELETE FROM `$tables{dbchapter}` WHERE DBchapter_id=$chap"); } + } } # Now run the script build-library-tree -# This is used to create the file library-tree.json which can be used to +# This is used to create the file ${myLib}-library-tree.json which can be used to # load in subject-chapter-section information for the OPL use strict; @@ -960,16 +1075,20 @@ foreach my $i (0..$#subjects){ push (@subject_tree, $clone); } -build_library_directory_tree($ce); -build_library_subject_tree($ce,$dbh); -build_library_textbook_tree($ce,$dbh); +build_library_directory_tree($myLib,$ce); +build_library_subject_tree($myLib,$ce,$dbh); +build_library_textbook_tree($myLib,$ce,$dbh); $dbh->disconnect; -if ($ce->{problemLibrary}{showLibraryLocalStats} || - $ce->{problemLibrary}{showLibraryGlobalStats}) { - print "\nUpdating Library Statistics.\n"; - do $ENV{WEBWORK_ROOT}.'/bin/update-OPL-statistics'; +if ( $myLib eq "OPL" ) { + # Only the "real" OPL has Library statistics + + if ($ce->{problemLibrary}{$myLib}{showLibraryLocalStats} || + $ce->{problemLibrary}{$myLib}{showLibraryGlobalStats}) { + print "\nUpdating Library Statistics.\n"; + do $ENV{WEBWORK_ROOT}.'/bin/update-OPL-statistics'; + } } diff --git a/bin/OPLUtils.pm b/bin/OPLUtils.pm index 323436ab48..62ceb25650 100644 --- a/bin/OPLUtils.pm +++ b/bin/OPLUtils.pm @@ -6,11 +6,13 @@ use base qw(Exporter); # This file contains the subroutines that build JSON files from the database to help speed up the client side. # # The following files are created: -# 1. $webwork_htdocs/DATA/library-directory-tree.json (the directory structure of the library) -# 2. $webwork_htdocs/DATA/library-subject-tree.json (the subject/chapter/section struture of the library) -# 3. +# 1. $webwork_htdocs/DATA/LIBNAME-library-directory-tree.json (the directory structure of the library) +# 2. $webwork_htdocs/DATA/LIBNAME-library-subject-tree.json (the subject/chapter/section struture of the library) +# 3. $webwork_htdocs/DATA/LIBNAME-textbook-tree.json (textbook data) -# This is used to create the file library-directory-tree.json which can be used to load in +# The filenames are set via hash values for the current library in conf/defaults.config and/or conf/localOverrides.conf + +# This is used to create the file LIBNAME-library-directory-tree.json which can be used to load in # directory information for the OPL. It writes the file as a JSON of directories to be easily loaded. use strict; @@ -25,6 +27,10 @@ use JSON; our @EXPORT = (); our @EXPORT_OK = qw(build_library_directory_tree build_library_subject_tree build_library_textbook_tree); +# what library are we handling, now is first argument of the function +my $myLib = shift; + + ### Data for creating the database tables @@ -65,16 +71,17 @@ my %NPLtables = ( - - sub build_library_directory_tree { + # what library are we handling, now is first argument of the function + my $myLib = shift; + my $ce = shift; print "Creating the Directory Tree\n"; - my $libraryRoot = $ce->{problemLibrary}->{root}; + my $libraryRoot = $ce->{problemLibrary}->{$myLib}->{root}; $libraryRoot =~ s|/+$||; - my $libraryVersion = $ce->{problemLibrary}->{version}; + my $libraryVersion = $ce->{problemLibrary}->{$myLib}->{version}; my($filename, $directories) = fileparse($libraryRoot); @@ -82,7 +89,12 @@ sub build_library_directory_tree { push(@dirArray,buildTree($libraryRoot)); my $webwork_htdocs = $ce->{webwork_dir}."/htdocs"; - my $file = "$webwork_htdocs/DATA/library-directory-tree.json"; + + # Determine the proper json file names to use for THIS library via the + # settings in conf/defaults.config and/or conf/localOverrides.conf + my $jsonFile = $ce->{problemLibrary}->{$myLib}->{tree}; + + my $file = "$webwork_htdocs/DATA/${jsonFile}"; # use a variable for the file handle my $OUTFILE; @@ -144,15 +156,30 @@ sub buildTree { sub build_library_subject_tree { - my ($ce,$dbh) = @_; + # what library are we handling, now is first argument of the function + my ($myLib,$ce,$dbh) = @_; - my $libraryRoot = $ce->{problemLibrary}->{root}; + my $libraryRoot = $ce->{problemLibrary}->{$myLib}->{root}; $libraryRoot =~ s|/+$||; - my $libraryVersion = $ce->{problemLibrary}->{version}; + my $libraryVersion = $ce->{problemLibrary}->{$myLib}->{version}; my %tables = ($libraryVersion eq '2.5')? %OPLtables : %NPLtables; + # Modify table names for per-library tables + my @special_tables = qw( pgfile pgfile_keyword pgfile_problem ); + my $tmp1; my $tblName; + foreach $tmp1 ( @special_tables ) { + $tblName = $tables{$tmp1}; + #print "old table name $tblName\n"; + if ( $libraryVersion eq '2.5') { + $tblName =~ s/OPL/$myLib/; + } else { + $tblName =~ s/NPL/$myLib/; + } + #print "new table name $tblName\n"; + $tables{$tmp1} = $tblName; + } my $selectClause = "select subj.name, ch.name, sect.name, path.path,pg.filename from `$tables{dbsection}` AS sect " ."JOIN `$tables{dbchapter}` AS ch ON ch.DBchapter_id = sect.DBchapter_id " @@ -272,7 +299,12 @@ sub build_library_subject_tree { print "\n"; my $webwork_htdocs = $ce->{webwork_dir}."/htdocs"; - my $file = "$webwork_htdocs/DATA/library-subject-tree.json"; + + # Determine the proper json file names to use for THIS library via the + # settings in conf/defaults.config and/or conf/localOverrides.conf + my $jsonFile = $ce->{problemLibrary}->{$myLib}->{subj}; + + my $file = "$webwork_htdocs/DATA/${jsonFile}"; # use a variable for the file handle my $OUTFILE; @@ -292,15 +324,29 @@ sub build_library_subject_tree { } sub build_library_textbook_tree { + # what library are we handling, now is first argument of the function + my ($myLib,$ce,$dbh) = @_; - my ($ce,$dbh) = @_; - - my $libraryRoot = $ce->{problemLibrary}->{root}; + my $libraryRoot = $ce->{problemLibrary}->{$myLib}->{root}; $libraryRoot =~ s|/+$||; - my $libraryVersion = $ce->{problemLibrary}->{version}; + my $libraryVersion = $ce->{problemLibrary}->{$myLib}->{version}; my %tables = ($libraryVersion eq '2.5')? %OPLtables : %NPLtables; + # Modify table names for per-library tables + my @special_tables = qw( pgfile pgfile_keyword pgfile_problem ); + my $tmp1; my $tblName; + foreach $tmp1 ( @special_tables ) { + $tblName = $tables{$tmp1}; + #print "old table name $tblName\n"; + if ( $libraryVersion eq '2.5') { + $tblName =~ s/OPL/$myLib/; + } else { + $tblName =~ s/NPL/$myLib/; + } + #print "new table name $tblName\n"; + $tables{$tmp1} = $tblName; + } my $selectClause = "SELECT pg.pgfile_id from `$tables{path}` as path " ."LEFT JOIN `$tables{pgfile}` AS pg ON pg.path_id=path.path_id " @@ -376,7 +422,12 @@ sub build_library_textbook_tree { print "\n"; my $webwork_htdocs = $ce->{webwork_dir}."/htdocs"; - my $file = "$webwork_htdocs/DATA/textbook-tree.json"; + + # Determine the proper json file names to use for THIS library via the + # settings in conf/defaults.config and/or conf/localOverrides.conf + my $jsonFile = $ce->{problemLibrary}->{$myLib}->{text}; + + my $file = "$webwork_htdocs/DATA/${jsonFile}"; # use a variable for the file handle my $OUTFILE; diff --git a/bin/setfilepermissions b/bin/setfilepermissions index eb9ab9e03c..00854c9d69 100755 --- a/bin/setfilepermissions +++ b/bin/setfilepermissions @@ -72,7 +72,7 @@ system("chmod g+w ".$ce->{pg_dir}."/lib/chromatic"); # The server should not be able to write to the OPL (for most sites) -my $libroot = $ce->{problemLibrary}->{root}; +my $libroot = $ce->{problemLibrary}->{OPL}->{root}; system("chown -R $me $libroot"); system("chmod -R 755 $libroot"); diff --git a/bin/update-OPL-statistics b/bin/update-OPL-statistics index 528b165f1c..35efd8cdaa 100755 --- a/bin/update-OPL-statistics +++ b/bin/update-OPL-statistics @@ -182,7 +182,8 @@ $dbh->commit(); # check to see if the global statistics file exists and if it does, upload it. -my $global_sql_file = $ce->{problemLibrary}{root}.'/OPL_global_statistics.sql'; +# FIXME - currently hardwired for OPL +my $global_sql_file = $ce->{problemLibrary}{OPL}{root}.'/OPL_global_statistics.sql'; if (-e $global_sql_file) { @@ -201,6 +202,9 @@ DROP TABLE IF EXISTS OPL_global_statistics; EOS $dbh->commit(); + # Added NSW + $dbh->disconnect(); + $dbuser = shell_quote($dbuser); $dbpass = shell_quote($dbpass); $db = shell_quote($db); @@ -209,6 +213,8 @@ EOS `$mysql_command --host=$host --port=$port --user=$dbuser --password=$dbpass $db < $global_sql_file`; +} else { + $dbh->disconnect(); } 1; diff --git a/conf/defaults.config b/conf/defaults.config index a442618fcd..bca858df9c 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -572,6 +572,10 @@ $maxCourseIdLength = 40; # # The problemLibrary configuration data should now be set in localOverrides.conf +# 2018 - in order to support multiple installed libraries, there are changes to +# the structure of the configuration settings. +# the "{OPL}" was added to the path to the records for the main OPL settings. + # For configuration instructions, see: # http://webwork.maa.org/wiki/National_Problem_Library # The directory containing the natinal problem library files. @@ -582,8 +586,8 @@ $maxCourseIdLength = 40; #RE-CONFIGURE problemLibrary values in localOverrides.conf ################################################# -$problemLibrary{root} ="/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; -$problemLibrary{version} ="2.5"; # 2.0 for NPL, 2.5 for OPL +$problemLibrary{OPL}{root} ="/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; +$problemLibrary{OPL}{version} ="2.5"; # 2.0 for NPL, 2.5 for OPL ########################################################### # Problem Library SQL database connection information @@ -594,14 +598,16 @@ $problemLibrary_db = { storage_engine => 'MYISAM', }; -$problemLibrary{tree} = 'library-directory-tree.json'; +$problemLibrary{OPL}{tree} = 'OPL-library-directory-tree.json'; +$problemLibrary{OPL}{taxo} = 'OPL-tagging-taxonomy.json'; + # These flags control if statistics on opl problems are shown in the library # browser. If you want to include local statistics you will need to # run webwork2/bin/update-OPL-statistics on a regular basis. -$problemLibrary{showLibraryLocalStats} = 1; -# This flag controls whether global statistics will0be displayed -$problemLibrary{showLibraryGlobalStats} = 1; +$problemLibrary{OPL}{showLibraryLocalStats} = 1; +# This flag controls whether global statistics will be displayed +$problemLibrary{OPL}{showLibraryGlobalStats} = 1; ################################################################################ # Logs diff --git a/conf/localOverrides.conf.dist b/conf/localOverrides.conf.dist index 16cf72334e..e3db32aa6b 100644 --- a/conf/localOverrides.conf.dist +++ b/conf/localOverrides.conf.dist @@ -121,26 +121,130 @@ $webworkFiles{screenSnippets}{setHeader} = "$webworkDirs{conf}/snippets/ # NationalProblemLibrary -- OpenProblemLibrary ################################################################################ +# 2018 - in order to support multiple installed libraries, there are changes to +# the structure of the configuration settings. +# the "{OPL}" was added to the path to the records for the main OPL settings. + +$problemLibrary{OPL} = { }; # Create an empty hash for the OPL library records # For configuration instructions, see: # http://webwork.maa.org/wiki/National_Problem_Library # The directory containing the natinal problem library files. Set to "" if no problem # library is installed. # NationalProblemLibrary (NPL) has been renamed to OpenProblemLibrary (OPL) -#$problemLibrary{root} = "/opt/webwork/libraries/NationalProblemLibrary"; -#$problemLibrary{version} = "2"; -# uncomment these lines below and comment out the line above if using OPL instead of NPL +#$problemLibrary{OPL}{root} = "/opt/webwork/libraries/NationalProblemLibrary"; +#$problemLibrary{OPL}{version} = "2"; +# uncomment the 2 lines above and comment the 2 below if using NPL instead of OPL + +$problemLibrary{OPL}{root} = "/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; +$contribLibrary{OPL}{root} = "/opt/webwork/libraries/webwork-open-problem-library/Contrib"; +$problemLibrary{OPL}{version} = "2.5"; + +# What is the "displayed" name of this library +$problemLibrary{OPL}{name} = "Open Problem Library"; + -$problemLibrary{root} = "/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; -$contribLibrary{root} = "/opt/webwork/libraries/webwork-open-problem-library/Contrib"; -$problemLibrary{version} = "2.5"; +# What is the name of the symbolic link from inside course template directories +# to this library. For the main OPL the value "Library" should be used. Some +# PG files which load other files have that value hard-coded in. +$problemLibrary{OPL}{linkname} = "Library"; # Do NOT change this for the OPL + +# Used to get internal short name from the "linkname": +$problemLibrary{LookupTable}{Library} = "OPL"; + +# JSON files for this library +$problemLibrary{OPL}{tree} = 'OPL-library-directory-tree.json'; +$problemLibrary{OPL}{taxo} = 'OPL-tagging-taxonomy.json'; +$problemLibrary{OPL}{subj} = 'OPL-library-subject-tree.json'; +$problemLibrary{OPL}{text} = 'OPL-textbook-tree.json'; # These flags control if statistics on opl problems are shown in the library # browser. If you want to include local statistics you will need to # run webwork2/bin/update-OPL-statistics on a regular basis. -$problemLibrary{showLibraryLocalStats} = 1; +$problemLibrary{OPL}{showLibraryLocalStats} = 1; # This flag controls whether global statistics will be displayed -$problemLibrary{showLibraryGlobalStats} = 1; +$problemLibrary{OPL}{showLibraryGlobalStats} = 1; + +# ====================================================== + +# Sample records for an additional SEARCHABLE library + +#$problemLibrary{TSTL1} = { }; # Empty hash for the TSTL1 library records + +# Where is the library root directory on the server +#$problemLibrary{TSTL1}{root} = "/opt/webwork/libraries/tl-01"; + +# What table version should we use. Should match that of the OTHER libraries +# so we use the value set for the primary libraries +#$problemLibrary{TSTL1}{version} = "$problemLibrary{OPL}{version}"; + +# What is the "displayed" name of this library +#$problemLibrary{TSTL1}{name} = "Test Library 1"; + +# What is the name of the symbolic link from inside course template directories +# to this library. +# Warning: Do NOT use the value "Library" for anything except the main OPL. +# Some PG files in the OPL reference/load other problems under the +# assumption that the OPL is under "Library" so we should NOT put something else there. +#$problemLibrary{TSTL1}{linkname} = "TestLibrary1"; # Do not call this "Library" that should be reserved for the main OPL only, as linked PG problems in the OPL expect that specific value + +# Set the LookupTable values used to get internal short name from the "linkname": +#$problemLibrary{LookupTable}{TestLibrary1} = "TSTL1"; + +# JSON files for this library +#$problemLibrary{TSTL1}{tree} = 'TSTL1-library-directory-tree.json'; +#$problemLibrary{TSTL1}{taxo} = 'TSTL1-tagging-taxonomy.json'; +#$problemLibrary{TSTL1}{subj} = 'TSTL1-library-subject-tree.json'; +#$problemLibrary{TSTL1}{text} = 'TSTL1-textbook-tree.json'; + +# A present it is assumed that additional libraries will NOT have stats supports, +# so we disable the following settings. +#$problemLibrary{TSTL1}{showLibraryLocalStats} = 0; +#$problemLibrary{TSTL1}{showLibraryGlobalStats} = 0; + +# End of sample records for an additional SEARCHABLE library + +# ====================================================== + +# Sample records for an additional SEARCHABLE library + +#$problemLibrary{TSTL2} = { }; # Empty hash for the TSTL1 library records + +# Where is the library root directory on the server +#$problemLibrary{TSTL2}{root} = "/opt/webwork/libraries/tl-02"; + +# What table version should we use. Should match that of the OTHER libraries +# so we use the value set for the primary libraries +#$problemLibrary{TSTL2}{version} = "$problemLibrary{OPL}{version}"; + +# What is the "displayed" name of this library +#$problemLibrary{TSTL2}{name} = "Test Library 2"; + +# What is the name of the symbolic link from inside course template directories +# to this library. +# Warning: Do NOT use the value "Library" for anything except the main OPL. +# Some PG files in the OPL reference/load other problems under the +# assumption that the OPL is under "Library" so we should NOT put something else there. +#$problemLibrary{TSTL2}{linkname} = "TestLibrary2"; # Do not call this "Library" that should be reserved for the main OPL only, as linked PG problems in the OPL expect that specific value + +# Set the LookupTable values used to get internal short name from the "linkname": +#$problemLibrary{LookupTable}{TestLibrary2} = "TSTL2"; + +# JSON files for this library +#$problemLibrary{TSTL2}{tree} = 'TSTL2-library-directory-tree.json'; +#$problemLibrary{TSTL2}{taxo} = 'TSTL2-tagging-taxonomy.json'; +#$problemLibrary{TSTL2}{subj} = 'TSTL2-library-subject-tree.json'; +#$problemLibrary{TSTL2}{text} = 'TSTL2-textbook-tree.json'; + +# A present it is assumed that additional libraries will NOT have stats supports, +# so we disable the following settings. +#$problemLibrary{TSTL2}{showLibraryLocalStats} = 0; +#$problemLibrary{TSTL2}{showLibraryGlobalStats} = 0; + +# End of sample records for an additional SEARCHABLE library + +# ====================================================== + # Additional library buttons can be added to the Library Browser (SetMaker.pm) # by adding the libraries you want to the following line. For each key=>value @@ -322,12 +426,12 @@ $pg{options}{periodicRandomizationPeriod} = 5; ################################################################################ $pg{specialPGEnvironmentVars}{DragMath} = 0; - $pg{specialPGEnvironmentVars}{CAPA_Tools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools/", - $pg{specialPGEnvironmentVars}{CAPA_MCTools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools/", - $pg{specialPGEnvironmentVars}{CAPA_GraphicsDirectory} = "$courseDirs{templates}/Contrib/CAPA/CAPA_Graphics/", - push @{$pg{directories}{macrosPath}}, - "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools", - "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools"; + #$pg{specialPGEnvironmentVars}{CAPA_Tools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools/", + #$pg{specialPGEnvironmentVars}{CAPA_MCTools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools/", + #$pg{specialPGEnvironmentVars}{CAPA_GraphicsDirectory} = "$courseDirs{templates}/Contrib/CAPA/CAPA_Graphics/", + #push @{$pg{directories}{macrosPath}}, + # "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools", + # "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools"; # The link Contrib in the course templates directory should point to ../webwork-open-problem-library/Contrib diff --git a/conf/site.conf.dist b/conf/site.conf.dist index 2f479c169b..9e0be2c3bb 100644 --- a/conf/site.conf.dist +++ b/conf/site.conf.dist @@ -250,6 +250,9 @@ $mail{tls_allowed} = 0; # # The problemLibrary configuration data should now be set in localOverrides.conf +# 2018 - in order to support multiple installed libraries, there are changes to +# the structure of the configuration settings. + # For configuration instructions, see: # http://webwork.maa.org/wiki/National_Problem_Library # The directory containing the Open Problem Library files. @@ -260,7 +263,7 @@ $mail{tls_allowed} = 0; #CONFIGURE problemLibrary values in this file. These settings override defaults in default.config ################################################# -$problemLibrary{root} ="/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; +$problemLibrary{OPL}{root} ="/opt/webwork/libraries/webwork-open-problem-library/OpenProblemLibrary"; ########################################################### ################################################################################ diff --git a/htdocs/js/apps/SetMaker/setmaker.js b/htdocs/js/apps/SetMaker/setmaker.js index 47b78150e6..0520103bf7 100644 --- a/htdocs/js/apps/SetMaker/setmaker.js +++ b/htdocs/js/apps/SetMaker/setmaker.js @@ -94,20 +94,24 @@ function init_webservice(command) { } function lib_update(who, what) { - var child = { subjects : 'chapters', chapters : 'sections', sections : 'count'}; + var child = { myLibrary : 'subjects', subjects : 'chapters', chapters : 'sections', sections : 'count'}; nomsg(); var all = 'All ' + capFirstLetter(who); + if(who=='myLibrary') { all = 'All Libraries'; } + var mydefaultRequestObject = init_webservice('searchLib'); if(mydefaultRequestObject == null) { // We failed // console.log("Could not get webservice request object"); return false; } + var myLb = $('[name="library_name"] option:selected').val(); var subj = $('[name="library_subjects"] option:selected').val(); var chap = $('[name="library_chapters"] option:selected').val(); var sect = $('[name="library_sections"] option:selected').val(); + if(myLb == 'All Libraries'){ myLb = '';}; if(subj == 'All Subjects') { subj = '';}; if(chap == 'All Chapters') { chap = '';}; if(sect == 'All Sections') { sect = '';}; @@ -117,12 +121,16 @@ function lib_update(who, what) { if(lib_text == 'All Textbooks') { lib_text = '';}; if(lib_textchap == 'All Chapters') { lib_textchap = '';}; if(lib_textsect == 'All Sections') { lib_textsect = '';}; + + mydefaultRequestObject.library_name = myLb; + mydefaultRequestObject.library_subjects = subj; mydefaultRequestObject.library_chapters = chap; mydefaultRequestObject.library_sections = sect; mydefaultRequestObject.library_textbooks = lib_text; mydefaultRequestObject.library_textchapter = lib_textchap; mydefaultRequestObject.library_textsection = lib_textsect; + if(who == 'count') { mydefaultRequestObject.command = 'countDBListings'; // console.log(mydefaultRequestObject); @@ -131,6 +139,7 @@ function lib_update(who, what) { data: mydefaultRequestObject, timeout: 10000, //milliseconds success: function (data) { + if (data.match(/WeBWorK error/)) { reportWWerror(data); } @@ -139,11 +148,21 @@ function lib_update(who, what) { // console.log(response); var arr = response.result_data; arr = arr[0]; - var line = "There are "+ arr +" matching WeBWorK problems" - if(arr == "1") { - line = "There is 1 matching WeBWorK problem" + + if(myLb == ''){ myLb = 'All Libraries';}; + + + var line = "There are "+ arr +" matching WeBWorK problems in " + myLb + if (arr == "1") { + line = "There is 1 matching WeBWorK problem in " + myLb + } else if (arr == "0") { + line = "There are no matching WeBWorK problem in " + myLb + } $('#library_count_line').html(line); + + if(myLb == 'All Libraries'){ myLb = '';}; + return true; }, error: function (data) { @@ -157,9 +176,35 @@ function lib_update(who, what) { setselect('library_'+who, [all]); return lib_update(child[who], 'clear'); } + if(who=='subjects' && myLb=='') { return lib_update(who, 'clear'); } if(who=='chapters' && subj=='') { return lib_update(who, 'clear'); } if(who=='sections' && chap=='') { return lib_update(who, 'clear'); } - if(who=='sections') { subcommand = "getSectionListings";} + +// if(who=='myLibrary'){ subcommand = "getAllLibraries";} + + if(who=='myLibrary'){ + subcommand = "getAllLibraries"; + mydefaultRequestObject.library_name=''; + mydefaultRequestObject.library_subjects=''; + mydefaultRequestObject.library_chapters=''; + mydefaultRequestObject.library_sections=''; + } + if(who=='subjects') { + subcommand = "getAllDBsubjects"; + mydefaultRequestObject.library_subjects=''; + mydefaultRequestObject.library_chapters=''; + mydefaultRequestObject.library_sections=''; + } + if(who=='chapters') { + subcommand = "getAllDBchapters"; + mydefaultRequestObject.library_chapters=''; + mydefaultRequestObject.library_sections=''; + } + if(who=='sections') { + subcommand = "getSectionListings"; + mydefaultRequestObject.library_sections=''; + } + mydefaultRequestObject.command = subcommand; // console.log(mydefaultRequestObject); return $.ajax({type:'post', diff --git a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm index 118902dae1..f1f9eba8c4 100644 --- a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -3384,8 +3384,8 @@ sub upgrade_notification { } } - die "Couldn't find ".$ce->{problemLibrary}{root}.'. Are you sure $problemLibrary{root} is set correctly in localOverrides.conf?' unless - chdir($ce->{problemLibrary}{root}); + die "Couldn't find ".$ce->{problemLibrary}{OPL}{root}.'. Are you sure $problemLibrary{OPL}{root} is set correctly in localOverrides.conf?' unless + chdir($ce->{problemLibrary}{OPL}{root}); if ($LibraryRemote && $LibraryBranch) { # Check if there is an updated version of the OPL available @@ -3421,11 +3421,11 @@ sub upgrade_notification { # Check to see if the OPL_update script has been run more recently # than the last pull of the library. # this json file is (re)-created every time OPL-update is run. - my $jsonfile = $ce->{webworkDirs}{htdocs}.'/DATA/'.$ce->{problemLibrary}{tree}; + my $jsonfile = $ce->{webworkDirs}{htdocs}.'/DATA/'.$ce->{problemLibrary}{OPL}{tree}; # If no json file then the OPL script needs to be run unless (-e $jsonfile) { $upgradesAvailable = 1; - $upgradeMessage .= CGI::Tr(CGI::td($r->maketext('There is no library tree file for the library, you will need to run OPL-update.'))); + $upgradeMessage .= CGI::Tr(CGI::td($r->maketext('There is no library tree file for the OPL library, you will need to run OPL-update (on the main OPL).'))); # otherwise we need to check to see if the date on the tree file # is after the date on the last commit in the library } else { @@ -3435,7 +3435,7 @@ sub upgrade_notification { my $lastcommit = `git log -1 --pretty=format:%at`; if ($lastcommit > $opldate) { $upgradesAvailable = 1; - $upgradeMessage .= CGI::Tr(CGI::td($r->maketext('The library index is older than the library, you need to run OPL-update.'))); + $upgradeMessage .= CGI::Tr(CGI::td($r->maketext('The OPL library index is older than the OPL library, you need to run OPL-update(on the main OPL).'))); } } } diff --git a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm index 59bdf70598..92a4c5cc3e 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -56,13 +56,14 @@ use constant ALL_SECTIONS => 'All Sections'; use constant ALL_TEXTBOOKS => 'All Textbooks'; use constant LIB2_DATA => { - 'dbchapter' => {name => 'library_chapters', all => 'All Chapters'}, + 'dbLibrary' => {name => 'library_name', all => 'All Libraries'}, + 'dbchapter' => {name => 'library_chapters', all => 'All Chapters'}, 'dbsection' => {name => 'library_sections', all =>'All Sections' }, 'dbsubject' => {name => 'library_subjects', all => 'All Subjects' }, - 'textbook' => {name => 'library_textbook', all => 'All Textbooks'}, - 'textchapter' => {name => 'library_textchapter', all => 'All Chapters'}, - 'textsection' => {name => 'library_textsection', all => 'All Sections'}, - 'keywords' => {name => 'library_keywords', all => '' }, + 'textbook' => {name => 'library_textbook', all => 'All Textbooks'}, + 'textchapter'=> {name => 'library_textchapter', all => 'All Chapters'}, + 'textsection'=> {name => 'library_textsection', all => 'All Sections'}, + 'keywords' => {name => 'library_keywords', all => '' }, }; ## Flags for operations on files @@ -122,6 +123,9 @@ sub get_library_sets { my @pgdirs; my @dirs = grep {!$ignoredir{$_} and -d "$dir/$_"} @lis; if ($top == 1) {@dirs = grep {!$problib{$_}} @dirs} + + # FIXME - "Library" is hardwired + # Never include Library at the top level if ($top == 1) {@dirs = grep {$_ ne 'Library'} @dirs} foreach my $subdir (@dirs) { @@ -205,6 +209,8 @@ sub getDBextras { my $r = shift; my $sourceFileName = shift; + # FIXME - "Library" is hardwired + if($sourceFileName =~ /^Library/) { return @{WeBWorK::Utils::ListingDB::getDBextras($r, $sourceFileName)}; } @@ -472,21 +478,33 @@ sub browse_library_panel { my $r = $self->r; my $ce = $r->ce; - # See if the problem library is installed - my $libraryRoot = $r->{ce}->{problemLibrary}->{root}; + # See if the problem library is installed - we check for OPL + my $libraryRoot = $r->{ce}->{problemLibrary}->{OPL}->{root}; + + my $linkName = $r->{ce}->{problemLibrary}->{OPL}->{linkname}; + + # # Debug code below displays the hash data in the HTML output + #my $pl1 = $r->{ce}->{problemLibrary}; + #my $opl1 = $pl1->{OPL}; + #print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, + # "libraryRoot setting is $libraryRoot and pl1 keys: " + # . join(" ",keys( %$pl1)) + # . "
opl1 keys: " + # . join(" ",keys( %$opl1)) + # ))); unless($libraryRoot) { print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, - "The problem library has not been installed."))); + "The OPL problem library has not been installed."))); return; } # Test if the Library directory link exists. If not, try to make it - unless(-d "$ce->{courseDirs}->{templates}/Library") { - unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) { + unless(-d "$ce->{courseDirs}->{templates}/${linkName}") { + unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/${linkName}")) { my $msg = <<"HERE"; -You are missing the directory templates/Library, which is needed +You are missing the directory templates/${linkName}, which is needed for the Problem Library to function. It should be a link pointing to -$libraryRoot, which you set in conf/site.conf. +$libraryRoot, which you set in conf/localOverrides.conf. I tried to make the link for you, but that failed. Check the permissions in your templates directory. HERE @@ -495,7 +513,7 @@ HERE } # Now check what version we are supposed to use - my $libraryVersion = $r->{ce}->{problemLibrary}->{version} || 1; + my $libraryVersion = $r->{ce}->{problemLibrary}->{OPL}->{version} || 1; if($libraryVersion == 1) { return $self->browse_library_panel1; } elsif($libraryVersion >= 2) { @@ -555,6 +573,11 @@ sub browse_library_panel2 { my $r = $self->r; my $ce = $r->ce; + my @libs = WeBWorK::Utils::ListingDB::getAllLibraries($r); + unshift @libs, LIB2_DATA->{dbLibrary}{all}; + + my %libNames = WeBWorK::Utils::ListingDB::getAllLibrariesNameHash($r); + my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r); unshift @subjs, LIB2_DATA->{dbsubject}{all}; @@ -565,23 +588,58 @@ sub browse_library_panel2 { @sects = WeBWorK::Utils::ListingDB::getAllDBsections($r); unshift @sects, LIB2_DATA->{dbsection}{all}; + my $libName_selected = $r->param('library_name') || LIB2_DATA->{dbLibrary}{all}; my $subject_selected = $r->param('library_subjects') || LIB2_DATA->{dbsubject}{all}; my $chapter_selected = $r->param('library_chapters') || LIB2_DATA->{dbchapter}{all}; my $section_selected = $r->param('library_sections') || LIB2_DATA->{dbsection}{all}; my $view_problem_line = view_problems_line('lib_view', $r->maketext('View Problems'), $self->r); - my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); + my $count_line = 0; + if ( $libName_selected eq LIB2_DATA->{dbLibrary}{all} ) { + # LOOP over all libraries + my $ll; + my $cc; + foreach $ll ( keys( %{$ce->{problemLibrary}} ) ) { + # skip "LookupTable" + next if ( ($ll eq "LookupTable") || ( $ll eq "" ) ) ; + $r->param( 'library_name' => "$ce->{problemLibrary}->{$ll}->{linkname}" ); + + # FIXME should check here that this library is installed for this course + + $count_line += WeBWorK::Utils::ListingDB::countDBListings($r); + } + $r->param( 'library_name' => LIB2_DATA->{dbLibrary}{all} ); + } else { + $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); + } if($count_line==0) { - $count_line = $r->maketext("There are no matching WeBWorK problems"); + $count_line = $r->maketext("There are no matching WeBWorK problems in [_1]", $libName_selected); + } elsif ( $count_line == 1 ) { + $count_line = $r->maketext("There is 1 matching WeBWorK problems in [_1]", $libName_selected); } else { - $count_line = $r->maketext("There are [_1] matching WeBWorK problems", $count_line); + $count_line = $r->maketext("There are [_1] matching WeBWorK problems in [_2]", $count_line, $libName_selected); } print CGI::Tr({}, CGI::td({-class=>"InfoPanel", -align=>"left"}, CGI::hidden(-name=>"library_is_basic", -default=>1,-override=>1), CGI::start_table({-width=>"100%"}), + + CGI::Tr({}, + CGI::td([$r->maketext("Library:"), + CGI::popup_menu(-name=> 'library_name', + -values=>\@libs, + -labels=>\%libNames, + -default=> $libName_selected, + -onchange=>"lib_update('count', 'clear');return true" + )]), + CGI::td({-colspan=>2, -align=>"left"}, + CGI::button(-name=>"change_library", -value=>$r->maketext("Get subjects in this library"), + -onclick=>"lib_update('subjects', 'get');return true" + )) + ), + CGI::Tr({}, CGI::td([$r->maketext("Subject:"), CGI::popup_menu(-name=> 'library_subjects', @@ -609,6 +667,10 @@ sub browse_library_panel2 { -default=> $section_selected, -onchange=>"lib_update('count', 'clear');return true" )]), + #CGI::td({-colspan=>2, -align=>"left"}, + # CGI::button(-name=>"rerun_search", -value=>$r->maketext("Run search again"), # Not needed + # -onclick=>"lib_update('count', 'clear');return true" + # )) ), CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)), CGI::Tr(CGI::td({-colspan=>3, -align=>"center", -id=>"library_count_line"}, $count_line)), @@ -623,6 +685,14 @@ sub browse_library_panel2adv { my $ce = $r->ce; my $right_button_style = "width: 18ex"; + my @libs = WeBWorK::Utils::ListingDB::getAllLibraries($r); + if(! grep { $_ eq $r->param('library_name') } @libs) { + $r->param('library_name', 'Library'); # Fall back value FIXME + } + unshift @libs, LIB2_DATA->{dbLibrary}{all}; + + my %libNames = WeBWorK::Utils::ListingDB::getAllLibrariesNameHash($r); + my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r); if(! grep { $_ eq $r->param('library_subjects') } @subjs) { $r->param('library_subjects', ''); @@ -668,7 +738,7 @@ sub browse_library_panel2adv { unshift @textsecs, LIB2_DATA->{textsection}{all}; my %selected = (); - for my $j (qw( dbsection dbchapter dbsubject textbook textchapter textsection )) { + for my $j (qw( dbLibrary dbsection dbchapter dbsubject textbook textchapter textsection )) { $selected{$j} = $r->param(LIB2_DATA->{$j}{name}) || LIB2_DATA->{$j}{all}; } @@ -683,11 +753,31 @@ sub browse_library_panel2adv { my $view_problem_line = view_problems_line('lib_view', $r->maketext('View Problems'), $self->r); - my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); + my $libName_selected = $r->param('library_name') || LIB2_DATA->{dbLibrary}{all}; + + my $count_line = 0; + if ( $libName_selected eq LIB2_DATA->{dbLibrary}{all} ) { + # LOOP over all libraries + my $ll; + foreach $ll ( keys( %{$ce->{problemLibrary}} ) ) { + # skip "LookupTable" + next if ( ($ll eq "LookupTable") || ( $ll eq "" ) ) ; + $r->param( 'library_name' => "$ce->{problemLibrary}->{$ll}->{linkname}" ); + + # FIXME should check here that this library is installed for this course + + $count_line += WeBWorK::Utils::ListingDB::countDBListings($r); + } + $r->param( 'library_name' => LIB2_DATA->{dbLibrary}{all} ); + } else { + $count_line = WeBWorK::Utils::ListingDB::countDBListings($r); + } if($count_line==0) { - $count_line = "There are no matching WeBWorK problems"; + $count_line = $r->maketext("There are no matching WeBWorK problems in [_1]", $libName_selected); + } elsif ( $count_line == 1 ) { + $count_line = $r->maketext("There is 1 matching WeBWorK problems in [_1]", $libName_selected); } else { - $count_line = "There are $count_line matching WeBWorK problems"; + $count_line = $r->maketext("There are [_1] matching WeBWorK problems in [_2]", $count_line, $libName_selected); } # Formatting level checkboxes by hand @@ -713,6 +803,21 @@ sub browse_library_panel2adv { CGI::start_table({-width=>"100%"}), # Html done by hand since it is temporary CGI::Tr(CGI::td({-colspan=>4, -align=>"center"}, $r->maketext('All Selected Constraints Joined by "And"'))), + + CGI::Tr({}, + CGI::td([$r->maketext("Library:"), + CGI::popup_menu(-name=> 'library_name', + -values=>\@libs, + -labels=>\%libNames, + -default=> $selected{dbLibrary}, + -onchange=>"lib_update('count', 'clear');return true" + )]), + CGI::td({-colspan=>2, -align=>"left"}, + CGI::button(-name=>"change_library", -value=>$r->maketext("Get subjects in this library"), # Not needed + -onclick=>"lib_update('subjects', 'get');return true" + )) + ), + CGI::Tr({}, CGI::td([$r->maketext("Subject:"), CGI::popup_menu(-name=> 'library_subjects', @@ -755,6 +860,10 @@ sub browse_library_panel2adv { -default=> $selected{textchapter}, -onchange=>"submit();return true" )]), + #CGI::td({-colspan=>2, -align=>"left"}, + # CGI::button(-name=>"rerun_search", -value=>$r->maketext("Run search again"), # Not needed + # -onclick=>"lib_update('count', 'clear');return true" + # )) ), CGI::Tr({}, CGI::td([$r->maketext("Text section:"), @@ -883,7 +992,7 @@ sub make_top_row { print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, $r->maketext("Browse").' ', - CGI::submit(-name=>"browse_npl_library", -value=>$r->maketext("Open Problem Library"), -style=>$these_widths, @dis1), + CGI::submit(-name=>"browse_npl_library", -value=>$r->maketext("Searchable Libraries"), -style=>$these_widths, @dis1), CGI::submit(-name=>"browse_local", -value=>$r->maketext("Local Problems"), -style=>$these_widths, @dis2), CGI::submit(-name=>"browse_mysets", -value=>$r->maketext("From This Course"), -style=>$these_widths, @dis3), CGI::submit(-name=>"browse_setdefs", -value=>$r->maketext("Set Definition Files"), -style=>$these_widths, @dis4), @@ -959,8 +1068,10 @@ sub make_data_row { my $self = shift; my $r = $self->r; my $ce = $r->{ce}; + my $sourceFileData = shift; my $sourceFileName = $sourceFileData->{filepath}; + my $libCode = $sourceFileData->{libCode}; my $pg = shift; my $isstatic = $sourceFileData->{static}; my $isMO = $sourceFileData->{MO}; @@ -1069,7 +1180,9 @@ sub make_data_row { # get statistics to display my $global_problem_stats = ''; - if ($ce->{problemLibrary}{showLibraryGlobalStats}) { + + # use $libCode below + if ($ce->{problemLibrary}{$libCode}{showLibraryGlobalStats}) { my $stats = $self->{library_stats_handler}->getGlobalStats($sourceFileName); if ($stats->{students_attempted}) { $global_problem_stats = $self->helpMacro("Global_Usage_Data",$r->maketext('GLOBAL Usage')).': '. @@ -1083,7 +1196,9 @@ sub make_data_row { my $local_problem_stats = ''; - if ($ce->{problemLibrary}{showLibraryLocalStats}) { + + # use $libCode below + if ($ce->{problemLibrary}{$libCode}{showLibraryLocalStats}) { my $stats = $self->{library_stats_handler}->getLocalStats($sourceFileName); if ($stats->{students_attempted}) { $local_problem_stats = $self->helpMacro("Local_Usage_Data",$r->maketext('LOCAL Usage')).': '. @@ -1147,8 +1262,21 @@ sub process_search { # Build a hash of MLT entries keyed by morelt_id my %mlt = (); my $mltind; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode; + my $libSymLink; + if ( exists( $r->ce->{problemLibrary}->{LookupTable}->{$reqLib} ) ) { + $libCode = $r->ce->{problemLibrary}->{LookupTable}->{$reqLib}; + $libSymLink = $r->ce->{problemLibrary}->{$libCode}->{linkname}; + } else { + # Fall back to old default + $libSymLink = "Library"; + } + for my $indx (0..$#dbsearch) { - $dbsearch[$indx]->{filepath} = "Library/".$dbsearch[$indx]->{path}."/".$dbsearch[$indx]->{filename}; + $dbsearch[$indx]->{filepath} = "${libSymLink}/".$dbsearch[$indx]->{path}."/".$dbsearch[$indx]->{filename}; # For debugging $dbsearch[$indx]->{oindex} = $indx; if($mltind = $dbsearch[$indx]->{morelt}) { @@ -1407,10 +1535,41 @@ sub pre_header_initialize { ##### View from the library database } elsif ($r->param('lib_view')) { - + @pg_files=(); - my @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r); - @pg_files = process_search($r, @dbsearch); + my @dbsearch; + + # When "All Libraries" is selected, the value of $r->param('library_name') + # is an empty string... + + if ( ( $r->param('library_name') eq "" ) || + ( $r->param('library_name') eq LIB2_DATA->{dbLibrary}{all} ) ) { + # search all libraries + my @libs = WeBWorK::Utils::ListingDB::getAllLibraries($r); + + # FIXME should check here which libraries are installed for this course + + my $cl; + my @tmp1; + my $tmpRec; + + foreach $cl ( @libs ) { + $r->param( 'library_name' => "$cl" ); + + @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r); + @tmp1 = process_search($r, @dbsearch); + #foreach $tmpRec ( @tmp1 ) { + # push( @pg_files, $tmpRec ); + #} + push( @pg_files, @tmp1 ); + + } + $r->param( 'library_name' => LIB2_DATA->{dbLibrary}{all} ); # Set it back + } else { + # regular, single library search + @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r); + @pg_files = process_search($r, @dbsearch); + } $use_previous_problems=0; ##### View a set from a set*.def @@ -1585,8 +1744,9 @@ sub pre_header_initialize { my $library_stats_handler = ''; - if ($ce->{problemLibrary}{showLibraryGlobalStats} || - $ce->{problemLibrary}{showLibraryLocalStats} ) { +# FIXME NSW - need correct library code + if ($ce->{problemLibrary}{OPL}{showLibraryGlobalStats} || + $ce->{problemLibrary}{OPL}{showLibraryLocalStats} ) { $library_stats_handler = WeBWorK::Utils::LibraryStats->new($ce); } @@ -1760,14 +1920,20 @@ sub output_JS { if ($self->r->authz->hasPermissions(scalar($self->r->param('user')), "modify_tags")) { my $site_url = $ce->{webworkURLs}->{htdocs}; print qq!!; - if (open(TAXONOMY, $ce->{webworkDirs}{root}.'/htdocs/DATA/tagging-taxonomy.json') ) { + + + # Determine the proper taxonomy file to use + my $tagging_from = "OPL"; # FIXME, should come from settings + my $taxofile = $ce->{problemLibrary}->{$tagging_from}->{taxo}; + + if (open(TAXONOMY, $ce->{webworkDirs}{root}.'/htdocs/DATA/${taxofile}') ) { my $taxo = '[]'; $taxo = join("", ); close TAXONOMY; print qq!\n!; } else { print qq!\n!; - print qq!\n!; + print qq!\n!; } } return ''; diff --git a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker2.pm b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker2.pm index dbe7169fdc..92a5e8c755 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker2.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker2.pm @@ -539,11 +539,12 @@ sub browse_library_panel { my $ce = $r->ce; # See if the problem library is installed - my $libraryRoot = $r->{ce}->{problemLibrary}->{root}; + # FIXME NSW + my $libraryRoot = $r->{ce}->{problemLibrary}->{OPL}->{root}; unless($libraryRoot) { print CGI::div({class=>'ResultsWithError', align=>"center"}, - "The problem library has not been installed."); + "The OPL problem library has not been installed."); return; } # Test if the Library directory link exists. If not, try to make it @@ -551,8 +552,8 @@ sub browse_library_panel { unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) { my $msg = <<"HERE"; You are missing the directory templates/Library, which is needed -for the Problem Library to function. It should be a link pointing to -$libraryRoot, which you set in conf/site.conf. +for the Open Problem Library to function. It should be a link pointing to +$libraryRoot, which you set in conf/localOverrides.conf. I tried to make the link for you, but that failed. Check the permissions in your templates directory. HERE @@ -561,7 +562,7 @@ HERE } # Now check what version we are supposed to use - my $libraryVersion = $r->{ce}->{problemLibrary}->{version} || 1; + my $libraryVersion = $r->{ce}->{problemLibrary}->{OPL}->{version} || 1; if($libraryVersion == 1) { return $self->browse_library_panel1; } elsif($libraryVersion >= 2) { diff --git a/lib/WeBWorK/ContentGenerator/Instructor/SetMakernojs.pm b/lib/WeBWorK/ContentGenerator/Instructor/SetMakernojs.pm index 6aef538306..692db0f57c 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/SetMakernojs.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/SetMakernojs.pm @@ -32,34 +32,36 @@ use warnings; use WeBWorK::CGI; use WeBWorK::Debug; use WeBWorK::Form; -use WeBWorK::Utils qw(readDirectory max sortByName); +use WeBWorK::Utils qw(readDirectory max sortByName wwRound x); use WeBWorK::Utils::Tasks qw(renderProblems); use File::Find; require WeBWorK::Utils::ListingDB; +# we use x to mark strings for maketext use constant SHOW_HINTS_DEFAULT => 0; use constant SHOW_SOLUTIONS_DEFAULT => 0; use constant MAX_SHOW_DEFAULT => 20; -use constant NO_LOCAL_SET_STRING => 'No sets in this course yet'; -use constant SELECT_SET_STRING => 'Select a Set from this Course'; -use constant SELECT_LOCAL_STRING => 'Select a Problem Collection'; -use constant MY_PROBLEMS => ' My Problems '; -use constant MAIN_PROBLEMS => ' Unclassified Problems '; -use constant CREATE_SET_BUTTON => 'Create New Set'; +use constant NO_LOCAL_SET_STRING => x('No sets in this course yet'); +use constant SELECT_SET_STRING => x('Select a Set from this Course'); +use constant SELECT_LOCAL_STRING => x('Select a Problem Collection'); +use constant MY_PROBLEMS => x('My Problems'); +use constant MAIN_PROBLEMS => x('Unclassified Problems'); +use constant CREATE_SET_BUTTON => x('Create New Set'); use constant ALL_CHAPTERS => 'All Chapters'; use constant ALL_SUBJECTS => 'All Subjects'; use constant ALL_SECTIONS => 'All Sections'; use constant ALL_TEXTBOOKS => 'All Textbooks'; use constant LIB2_DATA => { - 'dbchapter' => {name => 'library_chapters', all => 'All Chapters'}, + 'dbLibrary' => {name => 'library_name', all => 'All Libraries'}, + 'dbchapter' => {name => 'library_chapters', all => 'All Chapters'}, 'dbsection' => {name => 'library_sections', all =>'All Sections' }, 'dbsubject' => {name => 'library_subjects', all => 'All Subjects' }, - 'textbook' => {name => 'library_textbook', all => 'All Textbooks'}, - 'textchapter' => {name => 'library_textchapter', all => 'All Chapters'}, - 'textsection' => {name => 'library_textsection', all => 'All Sections'}, - 'keywords' => {name => 'library_keywords', all => '' }, + 'textbook' => {name => 'library_textbook', all => 'All Textbooks'}, + 'textchapter'=> {name => 'library_textchapter', all => 'All Chapters'}, + 'textsection'=> {name => 'library_textsection', all => 'All Sections'}, + 'keywords' => {name => 'library_keywords', all => '' }, }; ## Flags for operations on files @@ -407,11 +409,11 @@ sub browse_library_panel { my $ce = $r->ce; # See if the problem library is installed - my $libraryRoot = $r->{ce}->{problemLibrary}->{root}; + my $libraryRoot = $r->{ce}->{problemLibrary}->{OPL}->{root}; unless($libraryRoot) { print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"}, - "The problem library has not been installed."))); + "The OPL problem library has not been installed."))); return; } # Test if the Library directory link exists. If not, try to make it @@ -419,8 +421,8 @@ sub browse_library_panel { unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) { my $msg = <<"HERE"; You are missing the directory templates/Library, which is needed -for the Problem Library to function. It should be a link pointing to -$libraryRoot, which you set in conf/site.conf. +for the Open Problem Library to function. It should be a link pointing to +$libraryRoot, which you set in conf/localOverrides.conf. I tried to make the link for you, but that failed. Check the permissions in your templates directory. HERE @@ -429,7 +431,7 @@ HERE } # Now check what version we are supposed to use - my $libraryVersion = $r->{ce}->{problemLibrary}->{version} || 1; + my $libraryVersion = $r->{ce}->{problemLibrary}->{OPL}->{version} || 1; if($libraryVersion == 1) { return $self->browse_library_panel1; } elsif($libraryVersion >= 2) { diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index 5b90b14a62..c94ac53842 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -2183,14 +2183,18 @@ sub output_JS{ # This is for tagging menus (if allowed) if ($r->authz->hasPermissions($r->param('user'), "modify_tags")) { - if (open(TAXONOMY, $ce->{webworkDirs}{root}.'/htdocs/DATA/tagging-taxonomy.json') ) { + # Determine the proper taxonomy file to use + my $tagging_from = "OPL"; # FIXME, should come from settings + my $taxofile = $ce->{problemLibrary}->{$tagging_from}->{taxo}; + + if (open(TAXONOMY, $ce->{webworkDirs}{root}.'/htdocs/DATA/${taxofile}') ) { my $taxo = '[]'; $taxo = join("", ); close TAXONOMY; print qq!\n!; } else { print qq!\n!; - print qq!\n!; + print qq!\n!; } print CGI::start_script({type=>"text/javascript", src=>"$site_url/js/apps/TagWidget/tagwidget.js"}), CGI::end_script(); } diff --git a/lib/WeBWorK/Utils/LibraryStats.pm b/lib/WeBWorK/Utils/LibraryStats.pm index 7ef55e239a..db75fd0ca6 100644 --- a/lib/WeBWorK/Utils/LibraryStats.pm +++ b/lib/WeBWorK/Utils/LibraryStats.pm @@ -66,7 +66,12 @@ sub getLocalStats { unless ($selectstm->execute($source_file)) { if ($selectstm->errstr =~ /Table .* doesn't exist/) { - warn "Couldn't find the OPL local statistics table. Did you download the latest OPL and run update-OPL-statistics?" + warn "Couldn't find the OPL local statistics table. Did you download the latest OPL and run update-OPL-statistics?"; + + # NSW hack - to avoid crash when no statistics + return {source_file => $source_file}; + # END NSW hack + } die $selectstm->errstr; } @@ -92,7 +97,12 @@ sub getGlobalStats { unless ($selectstm->execute($source_file)) { if ($selectstm->errstr =~ /Table .* doesn't exist/) { - warn "Couldn't find the OPL global statistics table. Did you download the latest OPL and run update-OPL-statistics?" + warn "Couldn't find the OPL global statistics table. Did you download the latest OPL and run update-OPL-statistics?"; + + # NSW hack - to avoid crash when no statistics + return {source_file => $source_file}; + # END NSW hack + } die $selectstm->errstr; } diff --git a/lib/WeBWorK/Utils/ListingDB.pm b/lib/WeBWorK/Utils/ListingDB.pm index 987c1e9d9b..9e0edcf473 100644 --- a/lib/WeBWorK/Utils/ListingDB.pm +++ b/lib/WeBWorK/Utils/ListingDB.pm @@ -44,7 +44,8 @@ BEGIN &createListing &updateListing &deleteListing &getAllChapters &getAllSections &searchListings &getAllListings &getSectionListings &getAllDBsubjects &getAllDBchapters &getAllDBsections &getDBTextbooks - &getDBListings &countDBListings &getTables &getDBextras + &getDBListings &countDBListings &getTables &getDBextras &getAllLibraries + &getAllLibrariesNameHash ); %EXPORT_TAGS =(); @EXPORT_OK =qw(); @@ -66,6 +67,9 @@ my %OPLtables = ( problem => 'OPL_problem', morelt => 'OPL_morelt', pgfile_problem => 'OPL_pgfile_problem', + cnt_dbsubject => 'Cnt_DBsubject', + cnt_dbchapter => 'Cnt_DBchapter', + cnt_dbsection => 'Cnt_DBsection', ); @@ -84,19 +88,40 @@ my %NPLtables = ( problem => 'NPL-problem', morelt => 'NPL-morelt', pgfile_problem => 'NPL-pgfile-problem', + cnt_dbsubject => 'Cnt_DBsubject', + cnt_dbchapter => 'Cnt_DBchapter', + cnt_dbsection => 'Cnt_DBsection', ); sub getTables { my $ce = shift; - my $libraryRoot = $ce->{problemLibrary}->{root}; + my $myLib = shift; # Library code name (as used in top level of %problemLibrary) + my %tables; - if($ce->{problemLibrary}->{version} == 2.5) { - %tables = %OPLtables; - } else { + if( $ce->{problemLibrary}->{$myLib}->{version} eq "2" ) { %tables = %NPLtables; - } + } else { + %tables = %OPLtables; + } + + # Modify table names for per-library tables + my @special_tables = qw( pgfile pgfile_keyword pgfile_problem ); + my $tmp1; my $tblName; + foreach $tmp1 ( @special_tables ) { + next if ( $myLib eq "" ); # Skip this + $tblName = $tables{$tmp1}; + #print "old table name $tblName\n"; + if ( $ce->{problemLibrary}->{$myLib}->{version} eq "2" ) { + $tblName =~ s/NPL/${myLib}/; + } else { + $tblName =~ s/OPL/${myLib}/; + } + #print "new table name $tblName\n"; + $tables{$tmp1} = $tblName; + } + return %tables; } @@ -200,12 +225,26 @@ Out put is an array reference: [MO, static] sub getDBextras { my $r = shift; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + my $path = shift; - my %tables = getTables($r->ce); + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $dbh = getDB($r->ce); my ($mo, $static)=(0,0); - $path =~ s|^Library/||; + # The old code assumed that the path header is "Library/" which + # is correct for the main OPL, but not for other libraries. + # OLD: + # $path =~ s|^Library/||; + # NEW: + $path =~ s|^${reqLib}/||; + my $filename = basename $path; $path = dirname $path; my $query = "SELECT pgfile.MO, pgfile.static FROM `$tables{pgfile}` pgfile, `$tables{path}` p WHERE p.path=\"$path\" AND pgfile.path_id=p.path_id AND pgfile.filename=\"$filename\""; @@ -233,15 +272,23 @@ consistent with the DB subject, chapter, section selected. sub getDBTextbooks { my $r = shift; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + my $thing = shift || 'textbook'; my $dbh = getDB($r->ce); - my %tables = getTables($r->ce); + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $extrawhere = ''; # Handle DB* restrictions my @search_params=(); my $subj = $r->param('library_subjects') || ""; my $chap = $r->param('library_chapters') || ""; - my $sec = $r->param('library_sections') || ""; + my $sec = $r->param('library_sections') || ""; if($subj) { $subj =~ s/'/\\'/g; $extrawhere .= " AND t.name = ?\n"; @@ -327,6 +374,58 @@ sub getDBTextbooks { } } +=item getAllLibraries($r) +Returns an array of Library names + +$r is the Apache request object + +=cut + +sub getAllLibraries { + my $r = shift; + + my $libLookupTable = $r->{ce}->{problemLibrary}->{LookupTable}; + + # The keys are the names used for the symbolic links to the library + # the value for a key is the + + my @results = keys( %$libLookupTable ); + + # Fixme - reorder ??? + # Fixme - want a "human" name rather than symbolic link name + + return @results; +} + +=item getAllLibrariesNameHash($r) +Returns an hash of Library code names to long names + +$r is the Apache request object + +=cut + +sub getAllLibrariesNameHash { + my $r = shift; + + my $libLookupTable = $r->{ce}->{problemLibrary}->{LookupTable}; + + # The keys are the names used for the symbolic links to the library + # the value for a key is the + + my %result; + + my $k; + my $code; + foreach $k ( keys( %$libLookupTable ) ) { + $code = $r->{ce}->{problemLibrary}->{LookupTable}->{$k}; + $result{$k} = $r->{ce}->{problemLibrary}->{$code}->{name}; + } + + $result{"All Libraries"} = "All Libraries"; + + return %result; +} + =item getAllDBsubjects($r) Returns an array of DBsubject names @@ -336,7 +435,14 @@ $r is the Apache request object sub getAllDBsubjects { my $r = shift; - my %tables = getTables($r->ce); + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my @results=(); my @row; my $query = "SELECT DISTINCT name, DBsubject_id FROM `$tables{dbsubject}` ORDER BY DBsubject_id"; @@ -347,8 +453,37 @@ sub getAllDBsubjects { while (@row = $sth->fetchrow_array()) { push @results, $row[0]; } - # @results = sortByName(undef, @results); - return @results; + + # When no current library is set, or "All Libraries" was set and + # changed to an empty string - list ALL subjects from ALL libraries. + if ( !defined($reqLib) || ( $reqLib eq "" ) ) { + #@results = sortByName(undef, @results); + return @results; + } + + # Get count of problems to determine if the subject should be listed. + my $tmp1; + my $savedCount; + my @nonEmptyResults; # Results which are not empty + + foreach $tmp1 ( @results ) { + + # Set the "param"eter - needs special code when this is a WebworkXMLRPC object + my $toSet = 'library_subjects'; + if ( ref($r) eq "WebworkXMLRPC" ) { + $r->setParam($toSet, $tmp1); + } else { + $r->param($toSet => "$tmp1"); + } + + $savedCount = countDBListings( $r ); + #warn "In getAllDBsubjects $tmp1 savedCount = $savedCount"; + push( @nonEmptyResults, $tmp1) if ( $savedCount > 0 ); + } + + #@results = sortByName(undef, @results); + #return @results; + return @nonEmptyResults; } @@ -361,7 +496,14 @@ $r is the Apache request object sub getAllDBchapters { my $r = shift; - my %tables = getTables($r->ce); + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $subject = $r->param('library_subjects'); return () unless($subject); my $dbh = getDB($r->ce); @@ -379,8 +521,36 @@ sub getAllDBchapters { my $all_chaps_ref = $dbh->selectall_arrayref($query, {},$subject); my @results = map { $_->[0] } @{$all_chaps_ref}; + + # When no current library is set, or "All Libraries" was set and + # changed to an empty string - list ALL chapters from ALL libraries. + if ( !defined($reqLib) || ( $reqLib eq "" ) ) { + #@results = sortByName(undef, @results); + return @results; + } + + # Get count of problems to determine if the chapter should be listed. + my $tmp1; + my $savedCount; + my @nonEmptyResults; # Results which are not empty + foreach $tmp1 ( @results ) { + + # Set the "param"eter - needs special code when this is a WebworkXMLRPC object + my $toSet = 'library_chapters'; + if ( ref($r) eq "WebworkXMLRPC" ) { + $r->setParam($toSet, $tmp1); + } else { + $r->param($toSet => "$tmp1"); + } + + $savedCount = countDBListings( $r ); + #warn "In getAllDBchapters $tmp1 savedCount = $savedCount"; + push( @nonEmptyResults, $tmp1) if ( $savedCount > 0 ); + } + #@results = sortByName(undef, @results); - return @results; + #return @results; + return @nonEmptyResults; } =item getAllDBsections($r) @@ -392,7 +562,14 @@ $r is the Apache request object sub getAllDBsections { my $r = shift; - my %tables = getTables($r->ce); + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $subject = $r->param('library_subjects'); return () unless($subject); my $chapter = $r->param('library_chapters'); @@ -414,8 +591,35 @@ sub getAllDBsections { my $all_sections_ref = $dbh->selectall_arrayref($query, {},$subject, $chapter); my @results = map { $_->[0] } @{$all_sections_ref}; + + # When no current library is set, or "All Libraries" was set and + # changed to an empty string - list ALL subjects from ALL libraries. + if ( !defined($reqLib) || ( $reqLib eq "" ) ) { + #@results = sortByName(undef, @results); + return @results; + } + + # Get count of problems to determine if the section should be listed. + my $tmp1; + my $savedCount; + my @nonEmptyResults; # Results which are not empty + foreach $tmp1 ( @results ) { + # Set the "param"eter - needs special code when this is a WebworkXMLRPC object + my $toSet = 'library_sections'; + if ( ref($r) eq "WebworkXMLRPC" ) { + $r->setParam($toSet, $tmp1); + } else { + $r->param($toSet => "$tmp1"); + } + + $savedCount = countDBListings( $r ); + #warn "In getAllDBsections $tmp1 savedCount = $savedCount"; + push( @nonEmptyResults, $tmp1) if ( $savedCount > 0 ); + } + #@results = sortByName(undef, @results); - return @results; + #return @results; + return @nonEmptyResults; } =item getDBSectionListings($r) @@ -433,9 +637,48 @@ Here, we search on all known fields out of r sub getDBListings { my $r = shift; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + if ( $reqLib eq "" ) { + # When called via instructorXMLHandler from JavaScript + # there can be a difference between the "param" value and the "hash" value. + # and we want the non-empty value + $reqLib = $r->{library_name}; + } + + # Need to handle case of "All Libraries" which should not get passed + # into this function, but would cause an error below. + if ( $reqLib eq "All Libraries" ) { + my $tmp1amcounter = shift; # 0-1 if I am a counter. + if ( $tmp1amcounter ) { + # If we got here - report 100000 results - to be seen as an unreasonable result + return( 100000 ); + } else { + # If we got here - report empty array of results + my @tmp1 = (); # no results + return @tmp1 ; + } + } + if ( $reqLib eq "" ) { + my $tmp1amcounter = shift; # 0-1 if I am a counter. + if ( $tmp1amcounter ) { + # If we got here - report 1000000 results - to be seen as an unreasonable result + return( 1000000 ); + } else { + # If we got here - report empty array of results + my @tmp1 = (); # no results + return @tmp1 ; + } + } + + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $amcounter = shift; # 0-1 if I am a counter. my $ce = $r->ce; - my %tables = getTables($ce); my $subj = $r->param('library_subjects') || ""; my $chap = $r->param('library_chapters') || ""; my $sec = $r->param('library_sections') || ""; @@ -562,21 +805,282 @@ sub getDBListings { WHERE p.path_id = pgf.path_id AND pgf.pgfile_id= ? "; my $row = $dbh->selectrow_arrayref($query,{},$pgid); - push @results, {'path' => $row->[0], 'filename' => $row->[1], 'morelt' => $row->[2], 'pgid'=> $row->[3], 'static' => $row->[4], 'MO' => $row->[5] }; + push @results, {'path' => $row->[0], 'filename' => $row->[1], 'morelt' => $row->[2], 'pgid'=> $row->[3], 'static' => $row->[4], 'MO' => $row->[5], 'libCode' => "$libCode" }; } return @results; } +# special return codes: +# -200 = all libraries, do not save data +# -100 = should not save data +# -1 = should save count after it is found + +sub requestSavedCount { + my $r = shift; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + if ( $reqLib eq "" ) { + # When called via instructorXMLHandler from JavaScript + # there can be a difference between the "param" value and the "hash" value. + # and we want the non-empty value + $reqLib = $r->{library_name}; + } + + # Need to handle case of "All Libraries" which should not get passed + # into this function, but would cause an error below. + if ( ( $reqLib eq "All Libraries" ) || ( $reqLib eq "" ) ) { + return( -200 ); + } + + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $ce = $r->ce; + + my $keywords = $r->param('library_keywords') || ""; + if($keywords) { + return( -100 ); # No saved counts for this case + } + + for my $j (qw( textbook textchapter textsection )) { + my $foo = $r->param(LIBRARY_STRUCTURE->{$j}{name}) || ''; + $foo =~ s/^\s*\d+\.\s*//; + if($foo) { + return( -100 ); # No saved counts for this case + } + } + + # Next could be an array, an array reference, or nothing + my @levels = $r->param('level'); + if(scalar(@levels) == 1 and ref($levels[0]) eq 'ARRAY') { + @levels = @{$levels[0]}; + } + @levels = grep { defined($_) && m/\S/ } @levels; + if(scalar(@levels)) { + return( -100 ); # No saved counts for this case + } + + my $subj = $r->param('library_subjects') || ""; + my $chap = $r->param('library_chapters') || ""; + my $sec = $r->param('library_sections') || ""; + + my $dbh = getDB($ce); + my $cnt_table = $tables{cnt_dbsubject}; + my $query; + + my $typewhere = ''; + my $extrawhere = ''; + my @select_parameters=(); + + if($subj) { + $cnt_table = $tables{cnt_dbsubject}; + $typewhere = "AND dbsj.DBsubject_id = cnt.DBsubject_id "; + $extrawhere .= " AND dbsj.name= ? "; + push @select_parameters, $subj; + } + if($chap) { + $cnt_table = $tables{cnt_dbchapter}; + $typewhere = " AND dbc.DBchapter_id = cnt.DBchapter_id "; + $extrawhere .= " AND dbc.name= ? "; + push @select_parameters, $chap; + } + if($sec) { + $cnt_table = $tables{cnt_dbsection}; + $typewhere = " AND dbsc.DBsection_id = cnt.DBsection_id "; + $extrawhere .= " AND dbsc.name= ? "; + push @select_parameters, $sec; + } + push @select_parameters, $libCode; + + my $query = "SELECT count from `$cnt_table` cnt, + `$tables{dbsection}` dbsc, + `$tables{dbchapter}` dbc, + `$tables{dbsubject}` dbsj + WHERE dbsj.DBsubject_id = dbc.DBsubject_id AND + dbc.DBchapter_id = dbsc.DBchapter_id + $typewhere $extrawhere AND cnt.libcode = ?"; + + $query =~ s/\n/ /g; + #warn "no text info: ", $query; + #warn "params: ", join(" | ",@select_parameters); + + my $sth = $dbh->prepare_cached( $query ); + if ( !defined($sth) ) { + warn "Couldn't prepare statement: " . $dbh->errstr; + return(-300); + } + + my $rv = $sth->execute(@select_parameters); + if ( !defined($rv) ) { + warn "Couldn't execute statement: " . $sth->errstr; + return(-300); + } + + if ($sth->rows == 0) { + #warn "No record found"; + return(-1); + } + my @data = $sth->fetchrow_array(); + return( $data[0] ); +} + +# Get the id +sub safe_get_id { + my $dbh = shift; + my $tablename = shift; + my $idname = shift; + my $whereclause = shift; + my $wherevalues = shift; + + my $query = "SELECT $idname FROM `$tablename` ".$whereclause; + my $sth = $dbh->prepare($query); + $sth->execute(@$wherevalues); + my $idvalue; + my @row; + unless(@row = $sth->fetchrow_array()) { + return -1; + } + $idvalue = $row[0]; + return($idvalue); +} + + +sub saveCount { + my $r = shift; + my $countToSave = shift; # count found + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + if ( $reqLib eq "" ) { + # When called via instructorXMLHandler from JavaScript + # there can be a difference between the "param" value and the "hash" value. + # and we want the non-empty value + $reqLib = $r->{library_name}; + } + + # Need to handle case of "All Libraries" which should not get passed + # into this function, but would cause an error below. + if ( ( $reqLib eq "All Libraries" ) || ( $reqLib eq "" ) ) { + return; # Do not save counts for this case + } + + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $ce = $r->ce; + + my $keywords = $r->param('library_keywords') || ""; + if($keywords) { + return; # Do not save counts for this case + } + + for my $j (qw( textbook textchapter textsection )) { + my $foo = $r->param(LIBRARY_STRUCTURE->{$j}{name}) || ''; + $foo =~ s/^\s*\d+\.\s*//; + if($foo) { + return; # Do not save counts for this case + } + } + + # Next could be an array, an array reference, or nothing + my @levels = $r->param('level'); + if(scalar(@levels) == 1 and ref($levels[0]) eq 'ARRAY') { + @levels = @{$levels[0]}; + } + @levels = grep { defined($_) && m/\S/ } @levels; + if(scalar(@levels)) { + return; # Do not save counts for this case + } + + my $subj = $r->param('library_subjects') || ""; + my $chap = $r->param('library_chapters') || ""; + my $sec = $r->param('library_sections') || ""; + + my $dbh = getDB($ce); + my $cnt_table = $tables{cnt_dbsubject}; + my $query; + + my @insert_parameters=( "$libCode" ); # Always the first parameter + + my $id_to_use = -1; + + my $new_dbsubj_id; + my $new_dbchap_id; + my $new_dbsect_id; + + if($subj) { + $new_dbsubj_id = safe_get_id($dbh, $tables{dbsubject}, 'DBsubject_id', + qq(WHERE name = ?), ["$subj"] ); + $id_to_use = $new_dbsubj_id; + $cnt_table = $tables{cnt_dbsubject}; + } + if($chap) { + $new_dbchap_id = safe_get_id($dbh, $tables{dbchapter}, 'DBchapter_id', + qq(WHERE name = ? and DBsubject_id = ?), ["$chap", $new_dbsubj_id] ); + $id_to_use = $new_dbchap_id; + $cnt_table = $tables{cnt_dbchapter}; + } + if($sec) { + $new_dbsect_id = safe_get_id($dbh, $tables{dbsection}, 'DBsection_id', + qq(WHERE name = ? and DBchapter_id = ?), ["$sec", $new_dbchap_id] ); + $id_to_use = $new_dbsect_id; + $cnt_table = $tables{cnt_dbsection}; + } + push( @insert_parameters, $id_to_use, $countToSave ); + +# my $query = "INSERT INTO `$cnt_table` VALUES (?,?,?)"; + my $query = "REPLACE INTO `$cnt_table` VALUES (?,?,?)"; + + $query =~ s/\n/ /g; + #warn "no text info: ", $query; + #warn "params: ", join(" | ",@insert_parameters); + + my $sth = $dbh->prepare_cached( $query ); + if ( !defined($sth) ) { + warn "Couldn't prepare statement: " . $dbh->errstr; + return; + } + + my $rv = $sth->execute(@insert_parameters); + if ( !defined($rv) ) { + warn "Couldn't execute statement: " . $sth->errstr; + return; + } +} + sub countDBListings { - my $r = shift; - return (getDBListings($r,1)); + my $r = shift; + my $fromSaved = -1; + $fromSaved = requestSavedCount($r); + if ( $fromSaved >= 0 ) { + #warn "fromSaved = $fromSaved"; + return( $fromSaved ); + } else { + #warn "fromSaved = $fromSaved"; + my $countedNow = getDBListings($r,1); + #warn "countedNow = $countedNow"; + if ( $fromSaved == -1 ) { + saveCount($r, $countedNow); + } + return( $countedNow ); + } } sub getMLTleader { my $r = shift; my $mltid = shift; - my %tables = getTables($r->ce); + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + my $dbh = getDB($r->ce); my $query = "SELECT leader FROM `$tables{morelt}` WHERE morelt_id=\"$mltid\""; my $row = $dbh->selectrow_arrayref($query); @@ -787,8 +1291,17 @@ sub getMLTleader { sub getSectionListings { #print STDERR "ListingDB::getSectionListings(chapter,section)\n"; my $r = shift; + + # Find library (directory) name and then lookup the code name + my $reqLib = $r->param('library_name'); + my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; + + # Now depends on the $libCode + my %tables = getTables($r->ce, $libCode); + + my $ce = $r->ce; - my $version = $ce->{problemLibrary}->{version} || 1; + my $version = $ce->{problemLibrary}->{$libCode}->{version} || 1; if($version => 2) { return(getDBListings($r, 0))} my $subj = $r->param('library_subjects') || ""; my $chap = $r->param('library_chapters') || ""; @@ -818,7 +1331,6 @@ sub getSectionListings { FROM classify c, pgfiles p WHERE ? ? c.pgfiles_id = p.pgfiles_id"; my $dbh = getDB($ce); - my %tables = getTables($ce); my $sth = $dbh->prepare($query); $sth->execute($chapstring,$secstring); @@ -846,13 +1358,25 @@ sub getSectionListings { # 1 = all ok # # not implemented yet +# currently hacked up to force to "OPL" as it does not get the request object sub deleteListing { my $ce = shift; my $listing_id = shift; #print STDERR "ListingDB::deleteListing(): listing == '$listing_id'\n"; my $dbh = getDB($ce); - my %tables = getTables($ce); + +# FIXME +# # Find library (directory) name and then lookup the code name +# my $reqLib = $r->param('library_name'); +# my $libCode = $r->{ce}->{problemLibrary}->{LookupTable}->{$reqLib}; +# +# # Now depends on the $libCode +# my %tables = getTables($r->ce, $libCode); + +# FIXME - hack to OPL + + my %tables = getTables($ce, "OPL"); return undef; } @@ -904,6 +1428,7 @@ hash has the following format: Written by Bill Ziemer. Modified by John Jones. +Modifed by Nathan Wallach to add support for multiple libraries. =cut diff --git a/lib/WebworkWebservice.pm b/lib/WebworkWebservice.pm index c3e5b71e7c..2cf23add7d 100644 --- a/lib/WebworkWebservice.pm +++ b/lib/WebworkWebservice.pm @@ -936,11 +936,11 @@ sub updateSetting { ce db - params + param authz authen maketext - + setParam - Added to add an extra param like value =cut sub ce { @@ -959,6 +959,12 @@ sub param { # imitate get behavior of the request object params method debug("use param $param => $out") if $UNIT_TESTS_ON; $out; } +sub setParam { # add a new param like value + my $self =shift; + my $param = shift; + my $value = shift; + $self->{fake_r}->{$param} = $value; +} sub authz { my $self = shift; debug("use authz ") if $UNIT_TESTS_ON; diff --git a/lib/WebworkWebservice/LibraryActions.pm b/lib/WebworkWebservice/LibraryActions.pm index 70f5d767dc..3279274388 100644 --- a/lib/WebworkWebservice/LibraryActions.pm +++ b/lib/WebworkWebservice/LibraryActions.pm @@ -284,7 +284,15 @@ sub searchLib { #API for searching the NPL database if($rh->{library_levels}) { $self->{level} = [split(//, $rh->{library_levels})]; } + + # The code which supports multiple libraries needs the problemLibrary data + # data to be passed on into WeBWorK::Utils::ListingDB when called via + # the instructorXMLHandler, so add it here: + $self->{ce}->{problemLibrary} = {%{$ce->{problemLibrary}} }; + + 'getDBTextbooks' eq $subcommand && do { + $self->{library_name} = $rh->{library_name}; $self->{library_subjects} = $rh->{library_subjects}; $self->{library_chapters} = $rh->{library_chapters}; $self->{library_sections} = $rh->{library_sections}; @@ -293,23 +301,32 @@ sub searchLib { #API for searching the NPL database $out->{ra_out} = \@textbooks; return($out); }; + 'getAllLibraries' eq $subcommand && do { + my @libraries = WeBWorK::Utils::ListingDB::getAllLibraries($self); + $out->{ra_out} = \@libraries; + $out->{text} = encode_base64("Libraries loaded."); + return($out); + }; 'getAllDBsubjects' eq $subcommand && do { + $self->{library_name} = $rh->{library_name}; my @subjects = WeBWorK::Utils::ListingDB::getAllDBsubjects($self); $out->{ra_out} = \@subjects; $out->{text} = encode_base64("Subjects loaded."); return($out); }; 'getAllDBchapters' eq $subcommand && do { + $self->{library_name} = $rh->{library_name}; $self->{library_subjects} = $rh->{library_subjects}; my @chaps = WeBWorK::Utils::ListingDB::getAllDBchapters($self); $out->{ra_out} = \@chaps; - $out->{text} = encode_base64("Chapters loaded."); + $out->{text} = encode_base64("Chapters loaded."); return($out); }; 'getDBListings' eq $subcommand && do { my $templateDir = $self->ce->{courseDirs}->{templates}; + $self->{library_name} = $rh->{library_name}; $self->{library_subjects} = $rh->{library_subjects}; $self->{library_chapters} = $rh->{library_chapters}; $self->{library_sections} = $rh->{library_sections}; @@ -318,25 +335,39 @@ sub searchLib { #API for searching the NPL database $self->{library_textchapter} = $rh->{library_textchapter}; $self->{library_textsection} = $rh->{library_textsection}; debug(to_json($rh)); + my @listings = WeBWorK::Utils::ListingDB::getDBListings($self); - my @output = map {$templateDir."/Library/".$_->{path}."/".$_->{filename}} @listings; + + # Find library (directory) name and then lookup the code name + my $reqLib = $rh->{library_name}; + my $libCode = $ce->{problemLibrary}->{LookupTable}->{$reqLib}; + my $linkName = $ce->{problemLibrary}->{$libCode}->{linkname}; # Name of the symbolic link + + # OLD code assumed the directory name "Library" which was for the main OPL + #my @output = map {$templateDir."/Library/".$_->{path}."/".$_->{filename}} @listings; #change the hard coding!!!....just saying + + # NEW: + my @output = map {$templateDir."/${linkName}/".$_->{path}."/".$_->{filename}} @listings; + $out->{ra_out} = \@output; return($out); }; 'getSectionListings' eq $subcommand && do { + $self->{library_name} = $rh->{library_name}; $self->{library_subjects} = $rh->{library_subjects}; $self->{library_chapters} = $rh->{library_chapters}; $self->{library_sections} = $rh->{library_sections}; my @section_listings = WeBWorK::Utils::ListingDB::getAllDBsections($self); $out->{ra_out} = \@section_listings; - $out->{text} = encode_base64("Sections loaded."); + $out->{text} = encode_base64("Sections loaded."); return($out); }; 'countDBListings' eq $subcommand && do { + $self->{library_name} = $rh->{library_name}; $self->{library_subjects} = $rh->{library_subjects}; $self->{library_chapters} = $rh->{library_chapters}; $self->{library_sections} = $rh->{library_sections}; @@ -344,8 +375,33 @@ sub searchLib { #API for searching the NPL database $self->{library_textbook} = $rh->{library_textbook}; $self->{library_textchapter} = $rh->{library_textchapter}; $self->{library_textsection} = $rh->{library_textsection}; - my $count = WeBWorK::Utils::ListingDB::countDBListings($self); - $out->{text} = encode_base64("Count done."); + + # The code which supports multiple libraries needs the problemLibrary data + # to be passed on + #$self->{ce}->{problemLibrary} = {%{$ce->{problemLibrary}} }; + + + my $count = 0; + if ( ( $rh->{library_name} eq "All Libraries" ) || + # ( !defined( $rh->{library_name} ) ) || + ( $rh->{library_name} eq "" ) ) { # "All Libraries gets changes to "" by JS code + my $jjj = $rh->{library_name}; + # LOOP over all libraries + my @libs = keys( %{$ce->{problemLibrary}} ); + my $ll; + $count = ""; + foreach $ll ( @libs ) { + # skip "LookupTable" + next if ( ( $ll eq "LookupTable" ) || ( $ll eq "" ) ); + $self->{library_name} = "$ce->{problemLibrary}->{$ll}->{linkname}"; + + $count += WeBWorK::Utils::ListingDB::countDBListings($self); + } + } else { + $count = WeBWorK::Utils::ListingDB::countDBListings($self); + } + + $out->{text} = encode_base64("Count done."); $out->{ra_out} = [$count]; return($out); }; @@ -392,6 +448,7 @@ sub getProblemDirectories { my %libraries = %{$self->ce->{courseFiles}->{problibs}}; + # FIXME - this is for the OPL with the fixed path my $lib = "Library"; my $source = $ce->{courseDirs}{templates}; my $main = MY_PROBLEMS; my $isTop = 1;