#!/usr/bin/perl -w -I/opt/eprints3/perl_lib ###################################################################### # # This file is part of GNU EPrints 2. # # Copyright (c) 2000-2004 University of Southampton, UK. SO17 1BJ. # # EPrints 2 is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # EPrints 2 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with EPrints 2; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ###################################################################### =pod =head1 NAME B<epadmin> - EPrints repository admin tool =head1 SYNOPSIS =over 8 =item B<epadmin> create START HERE! This option will walk you through the tasks needed to create your repository. =item B<epadmin> test I<repository_id> A null operation which just checks your configuration files are OK and that you can connect to the database. =item B<epadmin> config_core I<repository_id> Set hostname, contact email and repository name. =item B<epadmin> config_db I<repository_id> Set database connection properties and, optionally, to create database and database user. =item B<epadmin> create_db I<repository_id> Create a database and database user with the current settings. =item B<epadmin> create_tables I<repository_id> Create the database tables. =item B<epadmin> create_user I<repository_id> Create a new user. You need to do this to create your first admin account. =item B<epadmin> erase_fulltext_index I<repository_id> This erases all the .words and .indexcodes cache files from your repository, forcing the indexer to rerun the tools used to extract full text from your documents. This is useful if you only setup the fulltext indexing after your repository is already live, or if you discover there has been a problem. =item B<epadmin> recommit I<repository_id> I<dataset_id> Recommit all the records in the given dataset. What this does is cause the automatic values to be re-calculated. =item B<epadmin> reindex I<repository_id> I<dataset_id> Schedule the dataset for reindexing. The indexer will do the actual indexing and it may take some time. This only schedules the reindexing. =item B<epadmin> rehash I<repository_id> [I<document_id>] Recalculate the hashes of the files in this document and write it to a probity log file. If a document id is given then just generate the hash for that document. =item B<epadmin> reload I<repository_id> Cause the web server to reload the repository configuration. =item B<epadmin> redo_thumbnails I<repository_id> Regenerate all the thumbnail and image-preview files. =item B<epadmin> erase_data I<repository_id> Erases and recreates the database. Removes all documents and files. Does not touch the configuration files. =item B<epadmin> erase_eprints I<repository_id> Erases all the documents and eprints (including their files). Recreates the eprint and document tables. Leaves configuration files and the users and subjects tables alone. =item B<epadmin> upgrade I<repository_id> After upgrading EPrints, use this to update the database tables. It will advise any other tasks that are required. =item B<epadmin> --help =back =head1 OPTIONS =over 8 =item B<--help> Print a brief help message and exit. =item B<--man> Print the full manual page and then exit. =item B<--quiet> This option does not do anything. =item B<--verbose> Explain in detail what is going on. May be repeated for greater effect. =item B<--version> Output version information and exit. =back =head1 AUTHOR This is part of this EPrints 3 system. EPrints 3 is developed by Christopher Gutteridge. =head1 VERSION EPrints Version: 3.0 =head1 CONTACT For more information goto B<http://www.eprints.org/> which give information on mailing lists and the like. Chris Gutteridge may be contacted at B<support@eprints.org> Should you need a real world address for some reason, EPrints can be contacted in the real world at EPrints c/o Christopher Gutteridge Department of Electronics and Computer Science University of Southampton SO17 1BJ United Kingdom =head1 COPYRIGHT This file is part of GNU EPrints 2. Copyright (c) 2000-2004 University of Southampton, UK. SO17 1BJ. EPrints 2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EPrints 2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EPrints 2; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut #cjg Does not use noise levels use EPrints; use Sys::Hostname; use DBI; use Unicode::String qw(utf8 latin1); use Data::Dumper; use strict; use Getopt::Long; use Pod::Usage; my $verbose = 0; my $quiet = 0; my $help = 0; my $man = 0; my $version = 0; GetOptions( 'help|?' => \$help, 'man' => \$man, 'version' => \$version, 'verbose+' => \$verbose, 'silent' => \$quiet, 'quiet' => \$quiet ) || pod2usage( 2 ); EPrints::Utils::cmd_version( "epadmin" ) if $version; pod2usage( 1 ) if $help; pod2usage( -exitstatus => 0, -verbose => 2 ) if $man; pod2usage( 2 ) if( scalar @ARGV == 0 ); # Set STDOUT to auto flush (without needing a \n) $|=1; my $noise = 1; $noise = 0 if( $quiet ); $noise = 1+$verbose if( $verbose ); my $REGEXP_HOSTNAME_MIDDLE = '[a-z0-9-]+(\.[a-z0-9-]+)*'; my $REGEXP_HOSTNAME = '^'.$REGEXP_HOSTNAME_MIDDLE.'$'; my $REGEXP_EMAIL = '^[^@]+@'.$REGEXP_HOSTNAME_MIDDLE.'$'; my $REGEXP_HOSTNAME_FULL = '^[a-z0-9-]+(\.[a-z0-9-]+)+$'; my $REGEXP_VARNAME = '^[a-zA-Z][_A-Za-z0-9]*$'; my $REGEXP_NUMBER = '^[0-9]+$'; my $REGEXP_YESNO = '^(yes|no)$'; my $REGEXP_ANY = '^.*$'; my $action = $ARGV[0]; if( $action eq "create" ) { create(); } else { my $repoid = $ARGV[1]; pod2usage(1) unless defined $repoid; if( $action eq "config_core" ) { config_core( $repoid ); } elsif( $action eq "config_db" ) { config_db( $repoid ); } elsif( $action eq "create_db" ) { create_db( $repoid ); } elsif( $action eq "create_user" ) { create_user( $repoid ); } elsif( $action eq "create_tables" ) { create_tables( $repoid ); } elsif( $action eq "erase_data" ) { erase_data( $repoid ); } elsif( $action eq "erase_eprints" ) { erase_eprints( $repoid ); } elsif( $action eq "erase_fulltext_index" ) { erase_fulltext_index( $repoid ); } elsif( $action eq "reload" ) { reload( $repoid ); } elsif( $action eq "redo_thumbnails" ) { redo_thumbnails( $repoid ); } elsif( $action eq "upgrade" ) { upgrade( $repoid ); } elsif( $action eq "test" ) { test( $repoid ); } elsif( $action eq "recommit" ) { my $datasetid = $ARGV[2]; pod2usage(1) unless defined $datasetid; recommit( $repoid, $datasetid ); } elsif( $action eq "reindex" ) { my $datasetid = $ARGV[2]; pod2usage(1) unless defined $datasetid; reindex( $repoid, $datasetid ); } elsif( $action eq "rehash" ) { rehash( $repoid ); } else { pod2usage( 1 ); } } exit; sub create { pod2usage( 2 ) if( scalar @ARGV != 1 ); print <<END; Create an EPrint Repository Please select an ID for the repository, which will be used to create a directory and identify the repository. Lower case letters and numbers, may not start with a number. examples: "lemurprints" or "test3" END if( scalar EPrints::Config::get_repository_ids() ) { print "Existing repositories:\n"; print join( ", ", EPrints::Config::get_repository_ids() )."\n\n"; } my $repoid = EPrints::Utils::get_input( $REGEXP_VARNAME, 'Archive ID' ); my $repodir = EPrints::Config::get( "base_path" )."/archives/".$repoid; my $loaded_config = EPrints::Config::get_repository_config( $repoid ); my $exists = ( defined $loaded_config ); if( $exists ) { print "A repository with that ID already exist.\n"; exit; } unless( -e $repodir ) { print "We need to create $repodir, doing it now...\n"; unless( EPrints::Platform::mkdir( $repodir ) ) { print "Problem creating directory\n\n"; exit; } } unless( -d $repodir ) { print "$repodir MUST be a directory.\n\n"; } my $username = EPrints::Config::get( "user" ); print "Getting uid and gid information for $username\n"; my(undef,undef,$uid,$gid) = EPrints::Platform::getpwnam( $username ); print "UID: $uid\n"; print "GID: $gid\n"; print "\nCreating initial files:\n"; &install( EPrints::Config::get( "base_path" )."/lib/defaultcfg", $EPrints::SystemSettings::conf->{"file_perms"}, $uid, $gid, $repodir."/cfg", $repoid ); foreach( "var", "html", "documents", "documents/disk0" ) { my $dir = $repodir."/".$_; EPrints::Platform::mkdir( $dir ); EPrints::Platform::chown( $uid, $gid, $dir ); } print <<END; Ok. I've created the initial config files and directory structure. I've also created a "disk0" directory under documents/ if you want your full texts to be stored on a different partition then remove the disk0, and create a symbolic link to the directory you wish to store the full texts in. Additional links may be placed here to be used when the first is full. END print "\n"; my $config_core = EPrints::Utils::get_input( $REGEXP_YESNO, "Configure vital settings?", "yes" ); if( $config_core eq "yes" ) { config_core( $repoid ); } else { print "OK, but you'll need to edit 10_core.pl by hand in that case.\n"; } print "\n"; my $config_db = EPrints::Utils::get_input( $REGEXP_YESNO, "Configure database?", "yes" ); if( $config_db eq "yes" ) { config_db( $repoid ); } else { print "OK, but you'll need to edit database.pl by hand in that case, and make sure the database exists.\n"; } print "\n"; my $create_user = EPrints::Utils::get_input( $REGEXP_YESNO, "Create an initial user?", "yes" ); if( $create_user eq "yes" ) { create_user( $repoid ); } else { print "OK, but you will not be able to log into the website. You can always run 'epadmin create_user $repoid' later.\n" } # cjg: Register with website! my $ok; $ok = EPrints::Utils::get_input( $REGEXP_YESNO, "Do you want to build the static web pages?", "yes" ); if( $ok eq "yes" ) { run_script( $repoid, "generate_static", "--verbose", $repoid ); } $ok = EPrints::Utils::get_input( $REGEXP_YESNO, "Do you want to import the LOC subjects?", "yes" ); if( $ok eq "yes" ) { run_script( $repoid, "import_subjects", "--verbose", "--force", $repoid ); } $ok = EPrints::Utils::get_input( $REGEXP_YESNO, "Do you want to update the apache config files? (you still need to add the 'Include' line)", "yes" ); if( $ok eq "yes" ) { run_script( $repoid, "generate_apacheconf", "--verbose" ); } my $base_path = EPrints::Config::get( "base_path" ); print <<END; -------------------------------------------------------------------------- That seemed to more or less work... -------------------------------------------------------------------------- Now make any required changes to the cfg files. Note that changing the metadata configuration may require the database tables to be regenerated. epadmin erase_data will regenerate the eprints and documents tables only. erase_data will regenerate everything. (nb. these also do erase the contents of the tables, and any uploaded files). Make sure that your main apache config file contains the line: Include $base_path/cfg/apache.conf Then stop and start your webserver: Often: /etc/rc.d/init.d/httpd stop /etc/rc.d/init.d/httpd start (or maybe /usr/local/apache/bin/apachectl stop & start) And then try connecting to your repository. -------------------------------------------------------------------------- Don't forget to register your repository at http://roar.eprints.org/ END exit; } # don't be fooled. This isn't the same as the install() in # eprints-install sub install { my($dir, $perms, $user, $group, $dest, $repoid) = @_; print "Installing: $dest\n"; opendir(INDIR, $dir) or die("Unable to install directory: $dir"); my @dirs = (); my @files = (); EPrints::Platform::mkdir( $dest ); EPrints::Platform::chown($user, $group, $dest); while(my $item = readdir(INDIR)) { next if $item=~m/^\./; if (-d "$dir/$item") { push(@dirs, $item); } else { push(@files, $item); } } closedir(INDIR); foreach my $filename (@files) { if( $filename eq "Config.pm" ) { open(my $i_fh, "<", "$dir/$filename"); open(my $o_fh, ">", "$dest/$filename") or die "Can't write to $dest/$filename"; while(defined($_ = <$i_fh>)) { if( /^package/ ) { # Change the package name to the local repository ($/ = line seperator) $_ = "package EPrints::Config::$repoid;$/"; } print $o_fh $_; } close($i_fh); close($o_fh); } else { EPrints::Utils::copy("$dir/$filename", "$dest/$filename"); } EPrints::Platform::chmod($perms, "$dest/$filename"); EPrints::Platform::chown($user, $group, "$dest/$filename"); } foreach(@dirs) { install("$dir/".$_, $perms, $user, $group, "$dest/$_", $repoid ); } } sub run_script { my( $repoid, $script, @opts ) = @_; my $repo = EPrints::Repository->new( $repoid ); my $bin = $repo->get_conf( "bin_path" ); system( "$bin/$script", @opts ); } sub config_core { my( $repoid ) = @_; print "Core configuration for $repoid\n\n"; my %config = (); $config{port} = 80; $config{host} = undef; $config{urlpath} = '/'; $config{archiveroot} = "archives/".$repoid; $config{configmodule} = "cfg/Config.pm"; $config{aliases} = []; $config{securehost} = undef; $config{securepath} = undef; $config{adminemail} = undef; $config{archive_name} = "Test Repository"; print <<END; Please enter the fully qualified hostname of the repository. For a production system we recommend against using the real hostname of the machine. Example: $repoid.footle.ac.uk END $config{host} = EPrints::Utils::get_input( $REGEXP_HOSTNAME_FULL, 'Hostname', $config{host} ); print <<END; Please enter the port of the webserver. This is probably 80, but you may wish to run apache on a different port if you are experimenting. END $config{port} = EPrints::Utils::get_input( $REGEXP_NUMBER, 'Webserver Port', $config{port} ); # calculate example aliases my $realhostname = hostname(); if( $realhostname !~ m/\./ ) { # No dots in the actual hostname! Lets try and got the # domain from resolv.conf my $domain = ""; if( open( RESOLV, "/etc/resolv.conf" ) && 0) { while( <RESOLV> ) { if( m/^search\s+([^\s]+)/ ) { $domain = $1; last; } } close RESOLV; } $domain = "mydomain.com" if( $domain eq "" ); $realhostname.=".".$domain; } my @example_aliases = (); push @example_aliases,$realhostname; $realhostname=~m/^(([^\.]*)\.[^\.]*)(\.|$)?/; push @example_aliases,$1 if( $3 eq "."); push @example_aliases,$2; $config{host}=~m/^(([^\.]*)\.[^\.]*)(\.|$)?/; push @example_aliases,$1 if( $3 eq "." ); push @example_aliases,$2; print <<END; Please enter all the aliases which could reach the repository, and indicate if you would like EPrints to write a Redirect Rule to redirect requests to this alias to the correct URL. END if( scalar @{$config{aliases}}==0 ) { print "Some suggestions:\n"; foreach( @example_aliases ) { print $_."\n"; } } print <<END; Enter a single hash (#) when you're done. END my @aliases = @{$config{aliases}}; $config{aliases} = []; for(;;) { my $default = shift @aliases; my $alias = EPrints::Utils::get_input( '^('.$REGEXP_HOSTNAME_MIDDLE.'|#)$', 'Alias (enter # when done)', (defined $default ? $default->{name} : '#' ) ); last if( $alias eq "#" ); my $aliasrecord = {}; $aliasrecord->{name} = $alias; $aliasrecord->{redirect} = EPrints::Utils::get_input( $REGEXP_YESNO, "Redirect $alias to $config{host}", (defined $default && !$default->{redirect} ? 'no' : 'yes' ) ); push @{$config{aliases}},$aliasrecord; print "\n"; } #print <<END; # #Language Configuration # #Please enter the primary language and other supported languages for the #repository. Supporting other languages represents a serious commitment to #translate all the phrases and templates etc. into each of these other #languages. # #Available languages: (please use the ID to refer to them) #END #my @langs = EPrints::Config::get_supported_languages(); #foreach( @langs ) #{ # my $title = utf8(""); # $title->utf8( "".EPrints::Config::lang_title( $_ ) ); # print $_." - ".($title->latin1)."\n"; #} #print <<END; # #If you plan to add support for another language, you will need to edit the #languages.xml file to indicate that this language is supported, and create #the relevant phrase and template files. # #END print "\n"; print "\n"; $config{adminemail} = EPrints::Utils::get_input( $REGEXP_EMAIL, 'Administrator Email', $config{adminemail} ); print <<END; Enter the name of the repository in the default language. If you wish to enter other titles for other languages or enter non ascii characters then you may enter something as a placeholder and edit the XML config file which this script generates. END $config{archive_name} = EPrints::Utils::get_input( '^.+$', 'Archive Name', $config{archive_name} ); # Write files? print "\n"; my $config_core = EPrints::Utils::get_input( $REGEXP_YESNO, "Write these core settings?", "yes" ); if( $config_core eq "no" ) { print "\nOK. Not writing after all.\n"; return; } # Write files! my $repodir = EPrints::Config::get( "base_path" )."/archives/".$repoid; my $aemailfile = "$repodir/cfg/cfg.d/adminemail.pl"; open( AEMAIL, ">$aemailfile" ) || die "Could not write to $aemailfile: $!"; print AEMAIL Data::Dumper->Dump( [ $config{adminemail}, ], [qw/ $c->{adminemail} /] ); close AEMAIL; print "Wrote $aemailfile\n"; my $corefile = "$repodir/cfg/cfg.d/10_core.pl"; open( CORE, ">$corefile" ) || die "Could not write to $corefile: $!"; print CORE Data::Dumper->Dump( [ $config{host}, $config{port}, $config{aliases}, $config{securehost}, $config{secureport}, ], [qw/ $c->{host} $c->{port} $c->{aliases} $c->{securehost} $c->{securepath} /] ); close CORE; print "Wrote $corefile\n"; my $anamefile = "$repodir/cfg/lang/en/phrases/archive_name.xml"; open( ANAME, ">$anamefile" ) || die "Could not write to $anamefile: $!"; print ANAME <<END; <?xml version="1.0" encoding="iso-8859-1" standalone="no" ?> <!DOCTYPE phrases SYSTEM "entities.dtd"> <epp:phrases xmlns="http://www.w3.org/1999/xhtml" xmlns:epp="http://eprints.org/ep3/phrase"> <epp:phrase id="archive_name">$config{archive_name}</epp:phrase> </epp:phrases> END close( ANAME ); print "Wrote $anamefile\n"; } sub config_db { my( $repoid ) = @_; my %config = (); $config{dbname} = $repoid; $config{dbhost} = "localhost"; $config{dbport} = undef; $config{dbsock} = undef; $config{dbuser} = $repoid; $config{dbpass} = undef; print "\nConfiguring Database for: $repoid\n"; $config{dbname} = EPrints::Utils::get_input( $REGEXP_VARNAME, 'Database Name', $config{dbname} ); $config{dbhost} = EPrints::Utils::get_input( $REGEXP_HOSTNAME, 'MySQL Host', $config{dbhost} ); print "\nYou probably don't need to set socket and port (unless you do!?).\n"; $config{dbport} = "#" if( !defined $config{dbport} ); $config{dbport} = EPrints::Utils::get_input( '^[0-9]+|#$', 'MySQL Port (# for no setting)', $config{dbport} ); $config{dbport} = undef if( $config{dbport} eq "#" ); $config{dbsock} = "#" if( !defined $config{dbsock} ); # can't remember what is a legal mysql socket... cjg $config{dbsock} = EPrints::Utils::get_input( '^.*$', 'MySQL Socket (# for no setting)', $config{dbsock} ); $config{dbsock} = undef if( $config{dbsock} eq "#" ); $config{dbuser} = EPrints::Utils::get_input( $REGEXP_VARNAME, 'Database User', $config{dbuser} ); $config{dbpass} = EPrints::Utils::get_input_hidden( $REGEXP_VARNAME, 'Database Password', $config{dbpass} ); print "\n"; my $config_db = EPrints::Utils::get_input( $REGEXP_YESNO, "Write these database settings?", "yes" ); if( $config_db eq "no" ) { print "\nOK. Not writing after all.\n"; return; } my $repodir = EPrints::Config::get( "base_path" )."/archives/".$repoid; my $dbfile = "$repodir/cfg/cfg.d/database.pl"; open( DBCONF, ">$dbfile" ) || die "Could not write to $dbfile: $!"; print DBCONF Data::Dumper->Dump( [ $config{dbname}, $config{dbhost}, $config{dbport}, $config{dbsock}, $config{dbuser}, $config{dbpass}, ], [qw/ $c->{dbname} $c->{dbhost} $c->{dbport} $c->{dbsock} $c->{dbuser} $c->{dbpass} /] ); close DBCONF; print "Wrote $dbfile\n"; print <<END; EPrints can create the database, and grant the correct permissions. END my $makedb = EPrints::Utils::get_input( $REGEXP_YESNO, "Create database \"$config{dbname}\"", "yes" ); if( $makedb eq "yes" ) { create_db( $repoid ); } else { print "\nWell, OK. But you'll need to do it yourself then.\n"; } } my $mysql_root_password; # subroutine so that it can cache if we do several operations sub get_mysql_root_password { return $mysql_root_password if( defined $mysql_root_password ); #cjg hide password from display? print <<END; Ok, I'll need to connect to the mysql database as root. What is the root password? END $mysql_root_password = EPrints::Utils::get_input_hidden( '^.*$', "MySQL Root Password" ); return $mysql_root_password; } sub root_dbh { my( $repoid, $dbname ) = @_; my $config = EPrints::Config::load_repository_config_module( $repoid ); $dbname = $config->{dbname} unless defined $dbname; my $mysqlrootpassword = get_mysql_root_password(); print "Connecting to the database...\n"; my $dbh = DBI->connect( EPrints::Database::build_connection_string( dbname=>$dbname, dbsock=>$config->{dbsock}, dbport=>$config->{dbport}, dbhost=>$config->{dbhost} ), "root", $mysqlrootpassword ); return $dbh; } sub create_db { my( $repoid ) = @_; my $dbh = root_dbh( $repoid, "mysql" ); if( !defined $dbh ) { print <<END; Hmmm. Problem connecting to database as root. We'll skip this but you should create it by hand. END exit 1; } my $mversion = EPrints::Database::mysql_version_from_dbh( $dbh ); my $oldpasswords = 0; if( $mversion >= 40100 ) { print "MySQL version id $mversion >= 40100\n"; print "MYSQL OLD PASSWORDS will be used for compatibility with DBI::mysql\n"; $oldpasswords = 1; } my $config = EPrints::Config::load_repository_config_module( $repoid ); my $sth = $dbh->prepare( "show databases" ); $sth->execute; my $dbexists = 0; my @row; while( @row = $sth->fetchrow_array ) { $dbexists = 1 if $row[0] eq $config->{dbname}; } if( $dbexists ) { print "Hmm. A database called ".$config->{dbname}." already exists, oh well.\n\n"; return; } else { my $SQL = "CREATE DATABASE ".$config->{dbname}; #print "DOING: $SQL\n"; $dbh->do( $SQL ); } print "Setting MySQL privs\n"; #cjg @localhost ??? what about remote mysql's? my $SQL; $SQL = 'GRANT ALL ON '.$config->{dbname}.'.* TO '.$config->{dbuser}.'@localhost'; #print "DOING: $SQL\n"; $dbh->do( $SQL ); my $pass = '"'.$config->{dbpass}.'"'; if( $oldpasswords ) { $pass = "OLD_PASSWORD($pass)"; } else { $pass = "PASSWORD($pass)"; } $SQL = 'SET PASSWORD FOR '.$config->{dbuser}.'@localhost = '.$pass; #print "DOING: $SQL\n"; $dbh->do( $SQL ); print "Disconnecting from database.\n\n"; $dbh->disconnect; my $mktables = EPrints::Utils::get_input( $REGEXP_YESNO, "Create database tables?", "yes" ); if( $mktables eq "yes" ) { create_tables( $repoid ); } } sub create_user { my( $repoid ) = @_; my $session = EPrints::Session->new( 1 , $repoid, $noise ); exit unless( defined $session ); my $user_info = {}; print "Creating a new user in $repoid\n\n"; $user_info->{username} = EPrints::Utils::get_input( $REGEXP_VARNAME, 'Enter a username', 'admin' ); while( defined EPrints::DataObj::User::user_with_username( $session, $user_info->{username} ) ) { print STDERR "User with username '".$user_info->{username}."' already exists.\n"; $user_info->{username} = EPrints::Utils::get_input( $REGEXP_VARNAME, 'Enter a username', 'admin' ); } my @utypes = $session->get_repository->get_types( "user" ); $user_info->{usertype} = EPrints::Utils::get_input( '^('.join( '|', @utypes ).')$', 'Select a user type ('.join( "|",@utypes).')', 'admin' ); my $rawpassword = EPrints::Utils::get_input_hidden( $REGEXP_VARNAME, 'Enter Password' ); $user_info->{password} = EPrints::Utils::crypt_password( $rawpassword, $session ); $user_info->{email} = EPrints::Utils::get_input( $REGEXP_EMAIL, 'Email' ); my $user_ds = $session->get_repository->get_dataset( "user" ); my $new_user = $user_ds->create_object( $session, $user_info ); print "\n"; if( defined $new_user ) { if( $noise >= 1 ) { print "Successfully created new user:\n"; print " ID: ".$new_user->get_value( "userid" )."\n"; } if( $noise >= 2 ) { print " Username: ".$new_user->get_value( "username" )."\n"; print " Type: ".$new_user->get_value( "usertype" )."\n"; } } else { my $db_error = $session->get_database->error; print STDERR "Error creating user: $db_error\n"; } $session->terminate; } sub redo_thumbnails { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $doc_ds = $session->get_repository->get_dataset( "document" ); $doc_ds->map( $session, sub { my( $session , $dataset , $doc ) = @_; if( $noise >= 2 ) { print "Attempting to build thumbnails for document #".$doc->get_id."\n"; } $doc->remove_thumbnails; #ouch! $doc->make_thumbnails; } ); $session->terminate; } sub reload { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $file = $session->get_repository->get_conf( "variables_path" )."/last_changed.timestamp"; unless( open( CHANGEDFILE, ">$file" ) ) { EPrints::abort( "Cannot write to file $file" ); } print CHANGEDFILE "This file last poked at: ".EPrints::Time::human_time()."\n"; close CHANGEDFILE; if( $noise > 0 ) { print <<END; The repository config will be reloaded, but you should still restart apache as soon as possible. END } $session->terminate; } sub create_tables { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise, 1 ); exit( 1 ) unless( defined $session ); if( $session->get_database->has_table( "eprint" ) ) { print "WARNING: Database is NOT empty. Contains an \"eprint\" table.\n"; print "You might consider running 'epadmin erase_data $repoid' instead.\n"; $session->terminate; exit 1; } foreach my $dsid ( &EPrints::DataSet::get_sql_dataset_ids ) { my $ds = $session->get_repository->get_dataset( $dsid ); my $indexes = $ds->count_indexes; if( $indexes > 32 ) { print STDERR "WARNING: Main table of dataset \"$dsid\" requires $indexes indexes.\n"; $session->terminate; EPrints::abort( "MySQL has a maximum of 32 indexes per table and the '$dsid'\ntable requires $indexes. Add an sql_index=>0 parameter to some of the\nfields in this dataset. See the Documentation for more information\non the 'sql_index' metadata parameter. --force will override this\ncheck but the SQL will probably fail anyway." ); } } if( $noise>=1 ) { print "Creating database tables...\n"; } if( $session->get_database->create_archive_tables ) { if( $noise>=1 ) { print "Done creating database tables.\n\n"; } } else { my $error = $session->get_database->error; print STDERR "DB Error: $error\n"; $session->terminate; exit 1; } } sub erase_data { my( $repoid ) = @_; print <<END; You are about to erase from $repoid: - all database tables - all eprint files - the generated html pages but NOT the configuration files. END my $sure = EPrints::Utils::get_input_confirm( "Are you sure you want this to happen" ); unless( $sure ) { print "Aborting then.\n"; exit( 1 ); } erase_eprint_files( $repoid ); drop_and_recreate_db( $repoid ); } sub erase_eprints { my( $repoid ) = @_; print <<END; You are about to erase from $repoid: - all eprints and documents data - all eprint files - all change history - the document requests - the access logs - the generated html pages but NOT the configuration files, user data or subject data. END my $sure = EPrints::Utils::get_input_confirm( "Are you sure you want this to happen" ); unless( $sure ) { print "Aborting then.\n"; exit( 1 ); } erase_eprint_files( $repoid ); foreach( "eprint", "history","access","request","document" ) { reset_dataset( $repoid, $_ ); } my $ok; $ok = EPrints::Utils::get_input( $REGEXP_YESNO, "Do you want to build the static web pages?", "yes" ); if( $ok eq "yes" ) { run_script( $repoid, "generate_static", "--verbose", $repoid ); } } sub reset_dataset { my( $repoid, $datasetid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise, 1 ); exit( 1 ) unless( defined $session ); my $db = $session->get_database; my @tables = $db->get_tables; print "Erasing dataset $datasetid\n" if( $noise >= 1 ); foreach my $table ( @tables ) { next unless( $table =~ m/^$datasetid/ ); print "Erasing table $table\n" if( $noise >= 2 ); my $sql = "DROP TABLE ".$table; $db->do( $sql ); } print "Creating dataset $datasetid\n"; $db->create_dataset_tables( $session->get_repository->get_dataset( $datasetid ) ); if( $datasetid ne "subject" ) { print "Resetting counter ${datasetid}id\n"; $db->counter_reset( $datasetid."id" ); } $session->terminate; } # not an option directly! sub drop_and_recreate_db { my( $repoid ) = @_; my $repo = EPrints::Repository->new( $repoid ); my $database = $repo->get_conf( "dbname" ); if( $noise>=1 ) { print "Connecting to mysql...\n"; } my $dbh = DBI->connect( EPrints::Database::build_connection_string( dbname=>"mysql", dbsock=>$repo->get_conf( "dbsock" ), dbport=>$repo->get_conf( "dbport" ), dbhost=>$repo->get_conf( "dbhost" ) ), "root", get_mysql_root_password() ); if( !defined $dbh ) { print STDERR "\n\nFailed to connect to database. Aborting.\n\n"; exit( 1 ); } if( $noise>=1 ) { print "Dropping database \"$database\"\n"; } $dbh->do( "drop database $database" ); if( $noise>=1 ) { print "Re-creating database \"$database\"\n"; } $dbh->do( "create database $database" ); $dbh->disconnect; if( $noise>=1 ) { print "Done recreating database\n\n"; } my $mktables = EPrints::Utils::get_input( $REGEXP_YESNO, "Create database tables?", "yes" ); if( $mktables eq "yes" ) { create_tables( $repoid ); } } # not an option directly! sub erase_eprint_files { my( $repoid ) = @_; if( $noise>=1 ) { print "Erasing eprint files...\n"; } my $repo = EPrints::Repository->new( $repoid ); my $documents_path = $repo->get_conf( "documents_path" ); my $htdocs_path = $repo->get_conf( "htdocs_path" ); # Get available directories opendir DOCSTORE, $documents_path or print STDERR "Can't open DOCSTORE\n"; my @doomeddirs; foreach( readdir DOCSTORE ) { next if m/^\.\.?$/; # skip . and .. push @doomeddirs, $documents_path."/".$_; } closedir DOCSTORE; # Remove the contents of each of the directories. push @doomeddirs, $htdocs_path; foreach my $dir (@doomeddirs) { if( $noise>=2 ) { print "Removing stuff in: $dir\n"; } my $rc = $repo->exec( "rmall", TARGET=>$dir ); print STDERR "Warning: Cleaning $dir didn't go smoothly\n" unless( $rc==0 ); } if( $noise>=1 ) { print "...done erasing eprint files.\n"; } } sub erase_fulltext_index { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $ds = $session->get_repository->get_dataset( "document" ); print "Stating to erase caches\n" if( $noise >= 1 ); $ds->map( $session, sub { my( $session , $dataset , $doc ) = @_; if( $noise >= 2 ) { print "Removing fulltext index for: ".$doc->get_id."\n"; } my @files = ( $doc->words_file, $doc->indexcodes_file ); foreach my $file ( @files ) { next unless( -e $file ); if( $noise >= 2 ) { print "Erasing: $file\n"; } unlink( $file ); } } ); print "Done erasing\n" if( $noise >= 1 ); print "Queuing records for re-indexing\n" if( $noise >= 1 ); my $fn = sub { my( $session, $dataset, $item ) = @_; $session->get_database->index_queue( 'eprint', $item->get_id, $EPrints::Utils::FULLTEXT ); if( $session->get_noise() >= 2 ) { print STDERR "Queued item: ".$dataset->id()."/".$item->get_id()."\n"; } }; my $ep_ds = $session->get_repository->get_dataset( "eprint" ); $ep_ds->map( $session, $fn ); print "Done queuing\n" if( $noise >= 1 ); $session->terminate; } sub test { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); $session->terminate; print "Everything seems OK.\n"; } sub rehash { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $docid = $ARGV[2]; if( defined $docid ) { my $doc = EPrints::DataObj::Document->new( $session, $docid ); if( !defined $doc ) { $session->get_repository->log( "Document #$docid not found. Can't rehash." ); } else { $doc->rehash; print "Rehashed document #$docid\n" if( $noise > 0); } } else { print "Rehashing documents\n" if( $noise > 0); my $dataset = $session->get_repository->get_dataset( "document" ); my $info = { count=>0 }; $dataset->map( $session , sub { my( $session, $dataset, $doc, $info ) = @_; $doc->rehash; if( $noise > 1 ) { print "Rehashed ".$doc->get_value( "docid" )."\n"; } $info->{count}++; }, $info ); if( $noise > 0) { print "Done rehashing ".$info->{count}." documents\n"; } } $session->terminate; } ################################### # # DATASET related utilities # ################################### sub recommit { my( $repoid, $datasetid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $dataset = $session->get_repository->get_dataset( $datasetid ); if( !defined $dataset ) { print "Exiting due to unknown dataset.\n" if( $noise >= 1 ); $session->terminate(); exit( 1 ); } if( $noise > 0 ) { print "\n"; print "You are about to recommit \"$datasetid\" in the $repoid repository.\n"; print "This can take some time.\n\n"; print "Number of records in set: ".$dataset->count( $session )."\n"; } my $sure = EPrints::Utils::get_input_confirm( "Continue" ); unless( $sure ) { print "Aborting then.\n\n"; $session->terminate(); exit( 1 ); } my $fn = sub { my( $session, $dataset, $item ) = @_; if( $session->get_noise() >= 2 ) { print STDERR "Committing item: ".$dataset->id()."/".$item->get_id()."\n"; } $item->commit(); }; $dataset->map( $session, $fn ); print "All items in \"$datasetid\" have been re-commited.\n" if( $noise >= 1 ); $session->terminate; } sub reindex { my( $repoid, $datasetid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise ); exit( 1 ) unless( defined $session ); my $dataset = $session->get_repository->get_dataset( $datasetid ); if( !defined $dataset ) { print "Exiting due to unknown dataset.\n" if( $noise >= 1 ); $session->terminate(); exit( 1 ); } my $fn = sub { my( $session, $dataset, $item ) = @_; foreach my $field ( $dataset->get_fields() ) { next unless( $field->get_property( "text_index" ) ); $session->get_database->index_queue( $dataset->id, $item->get_id, $field->get_name ); } if( $dataset->confid eq "eprint" ) { $session->get_database->index_queue( $dataset->id, $item->get_id, $EPrints::Utils::FULLTEXT ); } if( $session->get_noise() >= 2 ) { print STDERR "Queued item: ".$dataset->id()."/".$item->get_id()."\n"; } }; $dataset->map( $session, $fn ); $session->terminate; } #################################################################### # # UPGRADE CODE # #################################################################### sub upgrade { my( $repoid ) = @_; my $session = new EPrints::Session( 1 , $repoid , $noise, 1 ); exit( 1 ) unless( defined $session ); my $db = $session->get_db(); my $dbversion = $db->get_version(); if( $dbversion eq "3.0" ) { upgrade_3_0_to_3_0_1( $repoid, $db ); $dbversion="3.0.1"; $db->set_version( $dbversion ); } if( $dbversion eq "3.0.1" ) { upgrade_3_0_1_to_3_0_2( $repoid, $db ); $dbversion="3.0.2"; $db->set_version( $dbversion ); } if( $dbversion eq "3.0.2" ) { upgrade_3_0_2_to_3_0_3( $repoid, $db ); $dbversion="3.0.3"; $db->set_version( $dbversion ); } if( $dbversion eq "3.0.3" ) { upgrade_3_0_3_to_3_0_4( $repoid, $db ); $dbversion="3.0.4"; $db->set_version( $dbversion ); } if( $dbversion eq "3.0.4" ) { upgrade_3_0_4_to_3_0_5( $repoid, $db ); $dbversion="3.0.5"; $db->set_version( $dbversion ); } if( $dbversion eq "3.0.5" ) { upgrade_3_0_5_to_3_0_6( $repoid, $db ); $dbversion="3.0.6"; $db->set_version( $dbversion ); } print $dbversion."\n"; $session->terminate; } sub upgrade_3_0_to_3_0_1 { my( $repoid, $db ) = @_; my $rootdbh = root_dbh( $repoid ); if( !defined $rootdbh ) { die "Could not open database as root"; } my @tables = $db->get_tables; my $sql; $sql = "ALTER TABLE saved_search ADD public set('TRUE','FALSE') default 'FALSE' AFTER mailempty"; $rootdbh->do( $sql ); $sql = "CREATE TABLE user_items_fields ( userid INT NOT NULL, pos INT, items_fields VARCHAR(255) default NULL, KEY userid (userid), KEY pos (pos) ) "; $rootdbh->do( $sql ); $sql = "CREATE TABLE user_review_fields ( userid INT NOT NULL, pos INT, review_fields VARCHAR(255) default NULL, KEY userid (userid), KEY pos (pos) ) "; $rootdbh->do( $sql ); foreach my $table ( @tables ) { if( $table =~ m/^saved_search__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table ADD public TEXT AFTER mailempty", $rootdbh->do( $sql ); } if( $table =~ m/^user__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table ADD items_fields TEXT AFTER mailempty", $rootdbh->do( $sql ); $sql = "ALTER TABLE $table ADD review_fields TEXT AFTER items_fields", $rootdbh->do( $sql ); } } $rootdbh->disconnect; } sub upgrade_3_0_1_to_3_0_2 { my( $repoid, $db ) = @_; my $rootdbh = root_dbh( $repoid ); if( !defined $rootdbh ) { die "Could not open database as root"; } my @tables = $db->get_tables; my $sql; $sql = "ALTER TABLE saved_search ADD name VARCHAR(255) NOT NULL AFTER pos"; $rootdbh->do( $sql ); $sql = "ALTER TABLE cachemap ADD userid INTEGER AFTER lastused"; $rootdbh->do( $sql ); foreach my $table ( @tables ) { if( $table =~ m/^saved_search__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table ADD name TEXT AFTER pos", $rootdbh->do( $sql ); } } $rootdbh->disconnect; } sub upgrade_3_0_2_to_3_0_3 { my( $repoid, $db ) = @_; my $rootdbh = root_dbh( $repoid ); if( !defined $rootdbh ) { die "Could not open database as root"; } my @tables = $db->get_tables; my $sql; $sql = "ALTER TABLE eprint DROP fileinfo"; $rootdbh->do( $sql ); $sql = "ALTER TABLE eprint ADD fileinfo TEXT AFTER contact_email"; $rootdbh->do( $sql ); foreach my $table ( @tables ) { if( $table =~ m/^eprint__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table DROP fileinfo"; $rootdbh->do( $sql ); $sql = "ALTER TABLE $table ADD fileinfo TEXT AFTER contact_email", $rootdbh->do( $sql ); } } $rootdbh->disconnect; } sub upgrade_3_0_3_to_3_0_4 { my( $repoid, $db ) = @_; my $rootdbh = root_dbh( $repoid ); if( !defined $rootdbh ) { die "Could not open database as root"; } my @tables = $db->get_tables; my $sql; $sql = "ALTER TABLE eprint ADD latitude FLOAT AFTER fileinfo"; $rootdbh->do( $sql ); $sql = "ALTER TABLE eprint ADD longitude FLOAT AFTER latitude"; $rootdbh->do( $sql ); $sql = "ALTER TABLE user ADD latitude FLOAT AFTER mailempty"; $rootdbh->do( $sql ); $sql = "ALTER TABLE user ADD longitude FLOAT AFTER latitude"; $rootdbh->do( $sql ); foreach my $table ( @tables ) { if( $table =~ m/^eprint__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table ADD latitude TEXT AFTER fileinfo"; $rootdbh->do( $sql ); $sql = "ALTER TABLE $table ADD longitude TEXT AFTER latitude"; $rootdbh->do( $sql ); } if( $table =~ m/^user__ordervalues_.*$/ ) { $sql = "ALTER TABLE $table ADD latitude TEXT AFTER review_fields"; $rootdbh->do( $sql ); $sql = "ALTER TABLE $table ADD longitude TEXT AFTER latitude"; $rootdbh->do( $sql ); } } $rootdbh->disconnect; } sub upgrade_3_0_4_to_3_0_5 { my( $repoid, $db ) = @_; $db->_create_messages_table; } sub upgrade_3_0_5_to_3_0_6 { my( $repoid, $db ) = @_; reset_dataset( $repoid, 'subject' ); }