1155 lines
32 KiB
Perl
1155 lines
32 KiB
Perl
package WGDev::Command::Reset;
|
|
# ABSTRACT: Reset a site to defaults
|
|
use strict;
|
|
use warnings;
|
|
use 5.008008;
|
|
|
|
use parent qw(WGDev::Command::Base::Verbosity);
|
|
|
|
use WGDev::X ();
|
|
use File::Spec ();
|
|
use constant STAT_MODE => 2;
|
|
use constant STAT_UID => 4;
|
|
use constant STAT_GID => 5;
|
|
|
|
sub config_options {
|
|
return (
|
|
shift->SUPER::config_options, qw(
|
|
fast|f
|
|
|
|
backup!
|
|
delcache!
|
|
import:s
|
|
no-import|noimport
|
|
|
|
test|t
|
|
dev|d
|
|
build|b
|
|
|
|
uploads!
|
|
upgrade!
|
|
|
|
debug!
|
|
starter!
|
|
clear!
|
|
config!
|
|
purge!
|
|
cleantags!
|
|
emptytrash!
|
|
index!
|
|
runwf!
|
|
autologon!
|
|
util=s@
|
|
|
|
delusers
|
|
|
|
profile|pro|p=s@
|
|
) );
|
|
}
|
|
|
|
sub parse_params {
|
|
my ( $self, @args ) = @_;
|
|
$self->option( 'delcache' => 1 );
|
|
return $self->SUPER::parse_params(@args);
|
|
}
|
|
|
|
sub option_no_import {
|
|
my $self = shift;
|
|
$self->option( 'import', undef );
|
|
return;
|
|
}
|
|
|
|
sub option_profile {
|
|
my $self = shift;
|
|
my $profile = shift;
|
|
my $profile_string = $self->wgd->my_config( [ 'profiles', $profile ] );
|
|
if ( !defined $profile_string ) {
|
|
warn "Profile '$profile' does not exist!\n";
|
|
return;
|
|
}
|
|
$self->parse_params_string($profile_string);
|
|
return;
|
|
}
|
|
|
|
sub option_fast {
|
|
my $self = shift;
|
|
$self->option( uploads => 0 );
|
|
$self->option( backup => 0 );
|
|
$self->option( delcache => 0 );
|
|
$self->option( purge => 0 );
|
|
$self->option( cleantags => 0 );
|
|
$self->option( index => 0 );
|
|
$self->option( runwf => 0 );
|
|
return;
|
|
}
|
|
|
|
sub option_dev {
|
|
my $self = shift;
|
|
$self->option( backup => 1 );
|
|
$self->option( import => q{} );
|
|
$self->option( uploads => 1 );
|
|
$self->option( upgrade => 1 );
|
|
$self->option( starter => 0 );
|
|
$self->option( debug => 1 );
|
|
$self->option( clear => 1 );
|
|
return;
|
|
}
|
|
|
|
sub option_build {
|
|
my $self = shift;
|
|
$self->verbosity( $self->verbosity + 1 );
|
|
$self->option( backup => 1 );
|
|
$self->option( uploads => 1 );
|
|
$self->option( import => q{} );
|
|
$self->option( starter => 1 );
|
|
$self->option( debug => 0 );
|
|
$self->option( upgrade => 1 );
|
|
$self->option( purge => 1 );
|
|
$self->option( emptytrash => 1 );
|
|
$self->option( cleantags => 1 );
|
|
$self->option( index => 1 );
|
|
$self->option( runwf => 1 );
|
|
return;
|
|
}
|
|
|
|
sub process {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
|
|
if ( $self->option('backup') ) {
|
|
$self->backup;
|
|
}
|
|
|
|
# Clear cache
|
|
if ( $self->option('delcache') ) {
|
|
$self->clear_cache;
|
|
}
|
|
|
|
# Delete non-system users
|
|
if ( $self->option('delusers') ) {
|
|
$self->delete_users;
|
|
}
|
|
|
|
# Clear and recreate uploads
|
|
if ( $self->option('uploads') ) {
|
|
$self->reset_uploads;
|
|
}
|
|
|
|
if ( defined $self->option('import') ) {
|
|
$self->import_db_script;
|
|
}
|
|
|
|
# Run the upgrade in a fork
|
|
if ( $self->option('upgrade') ) {
|
|
$self->upgrade;
|
|
}
|
|
|
|
if ( $self->option('config') ) {
|
|
$self->reset_config;
|
|
}
|
|
|
|
if ( defined $self->option('debug') || defined $self->option('starter') )
|
|
{
|
|
$self->set_settings;
|
|
}
|
|
|
|
if ( $self->option('clear') ) {
|
|
$self->clear_default_content;
|
|
}
|
|
|
|
if ( $self->option('purge') ) {
|
|
$self->purge_old_revisions;
|
|
}
|
|
|
|
if ( $self->option('emptytrash') ) {
|
|
$self->empty_trash;
|
|
}
|
|
|
|
if ( $self->option('cleantags') ) {
|
|
$self->clean_version_tags;
|
|
}
|
|
|
|
if ( $self->option('runwf') ) {
|
|
$self->run_all_workflows;
|
|
}
|
|
|
|
if ( $self->option('index') ) {
|
|
$self->rebuild_lineage;
|
|
$self->rebuild_index;
|
|
}
|
|
|
|
if ( $self->option('autologon') ) {
|
|
$self->autologon;
|
|
}
|
|
|
|
if ( $self->option('util') ) {
|
|
require WGDev::Command::Util;
|
|
for my $util ( @{ $self->option('util') } ) {
|
|
$self->report("Running utility script '$util'... ");
|
|
$self->report( 2, "\n" );
|
|
my $util_command = WGDev::Command::Util->new($wgd);
|
|
$util_command->parse_params_string($util);
|
|
$util_command->verbosity( $self->verbosity - 1 );
|
|
if ( !$util_command->process ) {
|
|
WGDev::X->throw('Error running util script!');
|
|
}
|
|
$self->report("Done.\n");
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub backup {
|
|
my $self = shift;
|
|
$self->report('Backing up current database... ');
|
|
$self->wgd->db->dump(
|
|
File::Spec->catfile( File::Spec->tmpdir, 'WebGUI-reset-backup.sql' )
|
|
);
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub clear_cache {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
my $cache_type = $wgd->config->get('cacheType');
|
|
$self->report('Clearing cache... ');
|
|
if ( $cache_type && $cache_type eq 'WebGUI::Cache::FileCache' ) {
|
|
my $cache_dir = $wgd->config->get('fileCacheRoot')
|
|
|| '/tmp/WebGUICache';
|
|
require File::Path;
|
|
File::Path::rmtree( $cache_dir, { keep_root => 1 } );
|
|
}
|
|
elsif ( $cache_type && $cache_type eq 'WebGUI::Cache::Database' ) {
|
|
# Don't clear the DB cache if we are importing, as that
|
|
# will wipe it anyway
|
|
if ( !defined $self->option('import') ) {
|
|
my $dsn = $wgd->db->connect;
|
|
$dsn->do('DELETE FROM cache');
|
|
}
|
|
}
|
|
# Assume WebGUI 8 / CHI if no cache type, but with cache config
|
|
elsif ( ( ! $cache_type || $cache_type eq 'WebGUI::Cache::CHI' )
|
|
&& ( my $cache_config = $wgd->config->get('cache') ) ) {
|
|
# If there is a root dir, just wipe it so we don't have to load CHI
|
|
if ( my $cache_dir = $cache_config->{root_dir} ) {
|
|
require File::Path;
|
|
File::Path::rmtree( $cache_dir, { keep_root => 1 } );
|
|
}
|
|
else {
|
|
require CHI;
|
|
my $cache = CHI->new(%{$cache_config});
|
|
$cache->clear;
|
|
}
|
|
}
|
|
# Don't do anything for unknown cache types
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub delete_users {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
|
|
my $session = $wgd->session;
|
|
my @user_ids = grep { $_ ne '1' && $_ ne '3' }
|
|
map { @{$_} }
|
|
@{ $wgd->db->fetchall_arrayref('SELECT userId FROM users') };
|
|
my $n_users = @user_ids;
|
|
$self->report("Deleting $n_users non-system users... ");
|
|
$self->report( 2, "\n" );
|
|
require WebGUI::User;
|
|
|
|
for my $user_id (@user_ids) {
|
|
my $user = WebGUI::User->new( $session, $user_id );
|
|
$self->report( 2, "\tDeleting user '" . $user->username . "'.\n" );
|
|
$user->delete;
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
# Clear and recreate uploads
|
|
sub reset_uploads {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
require File::Copy;
|
|
require File::Find;
|
|
require File::Path;
|
|
$self->report('Recreating uploads... ');
|
|
|
|
my $wg_uploads = File::Spec->catdir( $wgd->root, 'www', 'uploads' );
|
|
my $site_uploads = $wgd->config->get('uploadsPath');
|
|
|
|
my ( $uploads_mode, $uploads_uid, $uploads_gid )
|
|
= ( stat $site_uploads )[ STAT_MODE, STAT_UID, STAT_GID ];
|
|
|
|
# if uploads doesn't exist, use reasonable defaults
|
|
if ( ! defined $uploads_mode ) {
|
|
$uploads_mode = oct 755;
|
|
$uploads_uid = $>;
|
|
$uploads_gid = $);
|
|
}
|
|
|
|
# make umask as permissive as required to match existing uploads folder
|
|
# including sticky bits
|
|
my $permissive_umask = oct 7777 & ~$uploads_mode;
|
|
my $initial_umask = umask $permissive_umask;
|
|
|
|
# set effective UID and GID, fail silently
|
|
local ( $>, $) ) = ( $uploads_uid, $uploads_gid );
|
|
|
|
File::Path::rmtree( $site_uploads, { keep_root => 1 } );
|
|
|
|
File::Find::find( {
|
|
no_chdir => 1,
|
|
wanted => sub {
|
|
no warnings 'once';
|
|
my $wg_path = $File::Find::name;
|
|
my $site_path
|
|
= File::Spec->rel2abs(
|
|
File::Spec->abs2rel( $wg_path, $wg_uploads ),
|
|
$site_uploads );
|
|
if ( -d $wg_path ) {
|
|
my $dir = ( File::Spec->splitdir($wg_path) )[-1];
|
|
if ( $dir =~ /^[.]/msx ) {
|
|
$File::Find::prune = 1;
|
|
return;
|
|
}
|
|
File::Path::mkpath( $site_path, 0, $uploads_mode );
|
|
}
|
|
else {
|
|
File::Copy::copy( $wg_path, $site_path );
|
|
}
|
|
},
|
|
},
|
|
$wg_uploads
|
|
);
|
|
|
|
umask $initial_umask;
|
|
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub import_db_script {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Clearing old database information... ');
|
|
$wgd->db->clear;
|
|
$self->report("Done.\n");
|
|
my $wg8 = $self->wgd->version->module =~ /^8[.]/msx;
|
|
|
|
$self->report('Importing clean database dump... ');
|
|
|
|
my $db_file = $self->option('import');
|
|
if ( defined $db_file && $db_file eq q{} ) {
|
|
if ($wg8) {
|
|
require WebGUI::Paths;
|
|
$db_file = WebGUI::Paths->defaultCreateSQL;
|
|
}
|
|
else {
|
|
# Use previousVersion.sql for upgrades if it is available
|
|
if ($self->option('upgrade')) {
|
|
$db_file = File::Spec->catfile( $wgd->root, 'docs', 'previousVersion.sql' );
|
|
}
|
|
if (! $db_file || ! -f $db_file ) {
|
|
$db_file = File::Spec->catfile( $wgd->root, 'docs', 'create.sql' );
|
|
}
|
|
}
|
|
}
|
|
$wgd->db->load($db_file);
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
# Run the upgrade in a fork
|
|
sub upgrade {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
require File::Spec;
|
|
my $wg8 = $self->wgd->version->module =~ /^8[.]/msx;
|
|
$self->report('Running upgrade script... ');
|
|
|
|
my $pid = fork;
|
|
if ( !$pid ) {
|
|
|
|
# replace sub in WebGUI::Config to only return a single config file
|
|
my $config_filename
|
|
= ( File::Spec->splitpath( $wgd->config_file ) )[2];
|
|
my $config_hash = { $config_filename => $wgd->config };
|
|
require WebGUI::Config;
|
|
no warnings qw(once redefine);
|
|
local *WebGUI::Config::readAllConfigs = sub { return $config_hash };
|
|
|
|
my @args = qw(--doit --override --skipBackup --skipDelete);
|
|
if ( $self->verbosity < 2 ) {
|
|
push @args, '--quiet';
|
|
}
|
|
if ($wg8 && -f File::Spec->catfile($wgd->root, 'sbin', 'webgui.pl')) {
|
|
$self->_run_script( 'webgui.pl', 'upgrade', @args );
|
|
}
|
|
else {
|
|
$self->_run_script( 'upgrade.pl', @args );
|
|
}
|
|
}
|
|
waitpid $pid, 0;
|
|
|
|
# error status of subprocess
|
|
if ($?) {
|
|
WGDev::X->throw('Upgrade failed!');
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub reset_config {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
require File::Copy;
|
|
|
|
$self->report('Resetting config file... ');
|
|
my $reset_config = $wgd->my_config('config');
|
|
|
|
# new config file will include any explicit overrides
|
|
my %set_config;
|
|
if ( exists $reset_config->{override} ) {
|
|
%set_config = %{ $reset_config->{override} };
|
|
}
|
|
|
|
# will also include specified values copied from old config
|
|
my @copy_keys = qw(
|
|
dsn dbuser dbpass uploadsPath uploadsURL
|
|
exportPath extrasPath extrasURL cacheType
|
|
sitename spectreIp spectrePort spectreSubnets
|
|
fileCacheRoot
|
|
); # Update POD docs if these change
|
|
if ( exists $reset_config->{copy} ) {
|
|
unshift @copy_keys, @{ $reset_config->{copy} };
|
|
}
|
|
for my $key (@copy_keys) {
|
|
$set_config{$key} = $wgd->config->get($key);
|
|
}
|
|
|
|
$wgd->close_config;
|
|
open my $fh, '>', $wgd->config_file
|
|
or WGDev::X::IO::Write->throw( path => $wgd->config_file );
|
|
File::Copy::copy(
|
|
File::Spec->catfile( $wgd->root, 'etc', 'WebGUI.conf.original' ),
|
|
$fh );
|
|
close $fh
|
|
or WGDev::X::IO::Write->throw( path => $wgd->config_file );
|
|
|
|
my $config = $wgd->config;
|
|
while ( my ( $key, $value ) = each %set_config ) {
|
|
$config->set( $key, $value );
|
|
}
|
|
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub set_settings {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Setting WebGUI settings... ');
|
|
my $dbh = $wgd->db->connect;
|
|
my $sth = $dbh->prepare(
|
|
q{REPLACE INTO `settings` (`name`, `value`) VALUES (?,?)});
|
|
if ( $self->option('debug') ) {
|
|
$sth->execute( 'showDebug', 1 );
|
|
|
|
# for debug we set this to 1 year
|
|
$sth->execute( 'sessionTimeout', 365 * 24 * 60 * 60 );
|
|
}
|
|
elsif ( defined $self->option('debug') ) {
|
|
$sth->execute( 'showDebug', 0 );
|
|
|
|
# default time is 2 hours
|
|
$sth->execute( 'sessionTimeout', 2 * 60 * 60 );
|
|
}
|
|
if ( $self->option('starter') ) {
|
|
$sth->execute( 'specialState', 'init' );
|
|
}
|
|
elsif ( defined $self->option('starter') ) {
|
|
$dbh->do(q{DELETE FROM `settings` WHERE `name`='specialState'});
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub clear_default_content {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Clearing example assets... ');
|
|
$self->report( 2, "\n" );
|
|
my $home = $wgd->asset->home;
|
|
my $children = $home->getLineage(
|
|
['descendants'],
|
|
{
|
|
statesToInclude => [
|
|
'published', 'clipboard',
|
|
'clipboard-limbo', 'trash',
|
|
'trash-limbo'
|
|
],
|
|
statusToInclude => [ 'approved', 'pending', 'archive' ],
|
|
excludeClasses => ['WebGUI::Asset::Wobject::Layout'],
|
|
returnObjects => 1,
|
|
invertTree => 1,
|
|
} );
|
|
for my $child ( @{$children} ) {
|
|
$self->report( 2, sprintf "\tRemoving %-35s '%s'\n",
|
|
$child->getName, $child->get('title') );
|
|
$child->purge;
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub purge_old_revisions {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
require WebGUI::Asset;
|
|
$self->report('Purging old Asset revisions... ');
|
|
$self->report( 2, "\n" );
|
|
my $sth = $wgd->db->connect->prepare(<<'END_SQL');
|
|
SELECT `assetData`.`assetId`, `asset`.`className`, `assetData`.`revisionDate`
|
|
FROM `asset`
|
|
LEFT JOIN `assetData` ON `asset`.`assetId` = `assetData`.`assetId`
|
|
ORDER BY `assetData`.`revisionDate` ASC
|
|
END_SQL
|
|
$sth->execute;
|
|
while ( my ( $id, $class, $revision ) = $sth->fetchrow_array ) {
|
|
my $current_revision
|
|
= WebGUI::Asset->getCurrentRevisionDate( $wgd->session, $id );
|
|
if ( !defined $current_revision || $current_revision == $revision ) {
|
|
next;
|
|
}
|
|
my $asset = eval { $wgd->asset->by_id($id, $revision) };
|
|
next
|
|
unless $asset;
|
|
|
|
if ( $asset->getRevisionCount('approved') > 1 ) {
|
|
$self->report( 2, sprintf "\tPurging %-35s %s '%s'\n",
|
|
$asset->getName, $revision, $asset->get('title') );
|
|
$asset->purgeRevision;
|
|
}
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub empty_trash {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Emptying trash... ');
|
|
$self->report( 2, "\n" );
|
|
my $assets = $wgd->asset->root->getLineage(
|
|
['descendants'],
|
|
{
|
|
statesToInclude => [qw(trash)],
|
|
statusToInclude => [qw(approved archived pending)],
|
|
} );
|
|
for my $asset_id ( @{$assets} ) {
|
|
my $asset = $wgd->asset->by_id($asset_id);
|
|
$self->report( 2, sprintf "\tPurging %-35s '%s'\n",
|
|
$asset->getName, $asset->get('title') );
|
|
$asset->purge;
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub clean_version_tags {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
|
|
$self->report('Finding current version number... ');
|
|
my $version = $wgd->version->database( $wgd->db->connect );
|
|
$self->report("$version. Done.\n");
|
|
|
|
$self->report('Cleaning out versions Tags... ');
|
|
my $tag_id = 'pbversion0000000000001';
|
|
my $dbh = $wgd->db->connect;
|
|
my $sth = $dbh->prepare(q{UPDATE `assetData` SET `tagId` = ?});
|
|
$sth->execute($tag_id);
|
|
$sth = $dbh->prepare(q{DELETE FROM `assetVersionTag`});
|
|
$sth->execute;
|
|
$sth = $dbh->prepare(<<'END_SQL');
|
|
INSERT INTO `assetVersionTag`
|
|
( `tagId`, `name`, `isCommitted`, `creationDate`, `createdBy`, `commitDate`,
|
|
`committedBy`, `isLocked`, `lockedBy`, `groupToUse`, `workflowId` )
|
|
VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
|
END_SQL
|
|
my $now = time;
|
|
$sth->execute( $tag_id, "Base $version Install",
|
|
1, $now, '3', $now, '3', 0, q{}, '3', q{} );
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub run_all_workflows {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Running all pending workflows... ');
|
|
$self->report( 2, "\n" );
|
|
require WebGUI::Workflow::Instance;
|
|
my $sth = $wgd->db->connect->prepare(
|
|
q{SELECT `instanceId` FROM `WorkflowInstance`});
|
|
$sth->execute;
|
|
while ( my ($instance_id) = $sth->fetchrow_array ) {
|
|
my $instance
|
|
= WebGUI::Workflow::Instance->new( $wgd->session, $instance_id );
|
|
my $waiting_count = 0;
|
|
while ( my $result = $instance->run ) {
|
|
if ( $result eq 'complete' ) {
|
|
$waiting_count = 0;
|
|
next;
|
|
}
|
|
if ( $result eq 'waiting' ) {
|
|
##no critic (ProhibitMagicNumbers)
|
|
if ( $waiting_count++ > 10 ) {
|
|
warn
|
|
"Unable to finish workflow $instance_id, too many iterations!\n";
|
|
last;
|
|
}
|
|
next;
|
|
}
|
|
if ( $result eq 'done' ) {
|
|
}
|
|
elsif ( $result eq 'error' ) {
|
|
warn "Unable to finish workflow $instance_id. Error!\n";
|
|
}
|
|
else {
|
|
warn
|
|
"Unable to finish workflow $instance_id. Unknown status $result!\n";
|
|
}
|
|
last;
|
|
}
|
|
}
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub rebuild_lineage {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Rebuilding lineage... ');
|
|
my $pid = fork;
|
|
if ( !$pid ) {
|
|
|
|
# silence output of rebuildLineage unless we're at max verbosity
|
|
if ( $self->verbosity < 3 ) { ##no critic (ProhibitMagicNumbers)
|
|
##no critic (RequireCheckedOpen)
|
|
open STDIN, '<', File::Spec->devnull;
|
|
open STDOUT, '>', File::Spec->devnull;
|
|
open STDERR, '>', File::Spec->devnull;
|
|
}
|
|
$self->report("\n\n");
|
|
$self->_run_script( 'rebuildLineage.pl',
|
|
'--configFile=' . $wgd->config_file_relative );
|
|
}
|
|
waitpid $pid, 0;
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub rebuild_index {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
$self->report('Rebuilding search index... ');
|
|
my $pid = fork;
|
|
if ( !$pid ) {
|
|
|
|
# silence output of searhc indexer unless we're at max verbosity
|
|
if ( $self->verbosity < 3 ) { ##no critic (ProhibitMagicNumbers)
|
|
##no critic (RequireCheckedOpen)
|
|
open STDIN, '<', File::Spec->devnull;
|
|
open STDOUT, '>', File::Spec->devnull;
|
|
open STDERR, '>', File::Spec->devnull;
|
|
}
|
|
print "\n\n";
|
|
$self->_run_script( 'search.pl', '--indexsite',
|
|
'--configFile=' . $wgd->config_file_relative );
|
|
}
|
|
waitpid $pid, 0;
|
|
$self->report("Done.\n");
|
|
return 1;
|
|
}
|
|
|
|
sub autologon {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
my @session_ids;
|
|
$self->report('Getting active browser site sessions... ');
|
|
my $success;
|
|
if ( eval { push @session_ids, $self->get_firefox_sessions; 1 } ) {
|
|
$success = 1;
|
|
}
|
|
if ( eval { push @session_ids, $self->get_safari_sessions; 1 } ) {
|
|
$success = 1;
|
|
}
|
|
if ($success) {
|
|
$self->report("Done.\n");
|
|
}
|
|
else {
|
|
$self->report("Failed!\n");
|
|
}
|
|
|
|
if (@session_ids) {
|
|
$self->report('Creating sessions on site... ');
|
|
for my $session_id (@session_ids) {
|
|
my $session = $wgd->create_session($session_id);
|
|
$session->user( { userId => 3 } );
|
|
$session->var->switchAdminOn;
|
|
$session->close;
|
|
}
|
|
$self->report("Done.\n");
|
|
}
|
|
}
|
|
|
|
sub get_firefox_sessions {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
|
|
require DBI;
|
|
require DBD::SQLite;
|
|
|
|
my $cookies_file = $self->get_firefox_cookiedb;
|
|
my $dbh = DBI->connect(
|
|
'dbi:SQLite:dbname=' . $cookies_file,
|
|
q{}, q{},
|
|
{
|
|
PrintError => 0,
|
|
RaiseError => 1,
|
|
##no critic (ProhibitMagicNumbers)
|
|
eval { DBD::SQLite->VERSION(1.27) }
|
|
? ( sqlite_unicode => 1 )
|
|
: ( unicode => 1 ),
|
|
} );
|
|
my @sitenames = @{ $wgd->config->get('sitename') };
|
|
my $cookie_name = $wgd->config->get('cookieName');
|
|
my $gateway = $wgd->config->get('gateway');
|
|
my $site_placeholders = join q{,}, (q{?}) x @sitenames;
|
|
my $sth = $dbh->prepare(<<"END_SQL");
|
|
SELECT
|
|
value
|
|
FROM
|
|
moz_cookies
|
|
WHERE
|
|
name = ?
|
|
AND host IN ($site_placeholders)
|
|
AND path = ?
|
|
AND expiry > ?
|
|
END_SQL
|
|
$sth->execute( $cookie_name, @sitenames, $gateway, time );
|
|
my @session_ids;
|
|
|
|
while ( my ($session_id) = $sth->fetchrow_array ) {
|
|
push @session_ids, $session_id;
|
|
}
|
|
$sth->finish;
|
|
$dbh->disconnect;
|
|
return @session_ids;
|
|
}
|
|
|
|
sub get_firefox_cookiedb {
|
|
my $self = shift;
|
|
|
|
require File::HomeDir;
|
|
require Config::INI::Reader;
|
|
require File::Temp;
|
|
File::Temp->VERSION(0.19); ##no critic (ProhibitMagicNumbers)
|
|
require File::Copy;
|
|
|
|
my $firefox_subdir
|
|
= $^O eq 'darwin' ? 'Firefox'
|
|
: $^O eq 'linux' ? '.firefox'
|
|
: WGDev::X->throw('Unsupported operating system');
|
|
|
|
my $firefox_data_dir
|
|
= File::Spec->catdir( File::HomeDir->my_data, $firefox_subdir );
|
|
my $profile_path;
|
|
|
|
my $profile_config = Config::INI::Reader->read_file(
|
|
File::Spec->catfile( $firefox_data_dir, 'profiles.ini' ) );
|
|
my @profiles = grep {/^Profile/msx} keys %{$profile_config};
|
|
if ( @profiles == 1 ) {
|
|
$profile_path = $profile_config->{ $profiles[0] }{Path};
|
|
}
|
|
else {
|
|
for my $key (@profiles) {
|
|
next
|
|
if !$profile_config->{$key}{Default};
|
|
$profile_path = $profile_config->{$key}{Path};
|
|
}
|
|
WGDev::X->throw('Unable to find a profile')
|
|
if !$profile_path;
|
|
}
|
|
|
|
$profile_path = File::Spec->rel2abs( $profile_path, $firefox_data_dir );
|
|
|
|
# database is locked so we have to make a copy to check it
|
|
my $cookies_file = File::Spec->catfile( $profile_path, 'cookies.sqlite' );
|
|
my $tmpdir = File::Temp::tempdir();
|
|
my $cookies_copy = File::Spec->catfile( $tmpdir, 'cookies.sqlite' );
|
|
File::Copy::copy( $cookies_file, $cookies_copy );
|
|
return $cookies_copy;
|
|
}
|
|
|
|
sub get_safari_sessions {
|
|
my $self = shift;
|
|
my $wgd = $self->wgd;
|
|
|
|
if ( $^O ne 'darwin' ) {
|
|
WGDev::X->throw('Safari cookies only available in Mac OS X.');
|
|
}
|
|
|
|
require HTTP::Cookies::Safari;
|
|
require File::HomeDir;
|
|
|
|
my %sitename = map { $_ => 1 } @{ $wgd->config->get('sitename') };
|
|
my $cookie_name = $wgd->config->get('cookieName');
|
|
my $gateway = $wgd->config->get('gateway');
|
|
|
|
my $cookies_file
|
|
= File::Spec->catfile( File::HomeDir->home, 'Library', 'Cookies',
|
|
'Cookies.plist', );
|
|
my $cookie_jar = HTTP::Cookies::Safari->new( file => $cookies_file );
|
|
$cookie_jar->load;
|
|
|
|
my @session_ids;
|
|
$cookie_jar->scan(
|
|
sub {
|
|
my ( undef, $key, $value, $path, $domain ) = @_;
|
|
if ( $key eq $cookie_name
|
|
&& $path eq $gateway
|
|
&& $sitename{$domain} )
|
|
{
|
|
push @session_ids, $value;
|
|
}
|
|
} );
|
|
|
|
return @session_ids;
|
|
}
|
|
|
|
sub _run_script {
|
|
my $self = shift;
|
|
my $script = shift;
|
|
my @args = @_;
|
|
|
|
# child process, don't need to worry about restoring anything
|
|
chdir File::Spec->catdir( $self->wgd->root, 'sbin' );
|
|
|
|
local @ARGV = @args;
|
|
local $0 = q{./} . $script;
|
|
|
|
##no critic (ProhibitMultiplePackages)
|
|
package main;
|
|
do $0;
|
|
die $@
|
|
if $@;
|
|
exit;
|
|
}
|
|
|
|
1;
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
wgd reset [-v] [-q] [-f] [-d | -b | -t]
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Resets a site to defaults, including multiple cleanup options for setting up
|
|
a site for development or for a build. Can also perform the cleanup functions
|
|
without resetting a site.
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over 8
|
|
|
|
=item C<-v> C<--verbose>
|
|
|
|
Output more information
|
|
|
|
=item C<-q> C<--quiet>
|
|
|
|
Output less information
|
|
|
|
=item C<-f> C<--fast>
|
|
|
|
Fast mode - equivalent to:
|
|
C<--no-upload --no-backup --no-delcache --no-purge --no-cleantags --no-index --no-runwf>
|
|
|
|
=item C<-t> C<--test>
|
|
|
|
Test mode - equivalent to:
|
|
C<--backup --import>
|
|
|
|
=item C<-d> C<--dev>
|
|
|
|
Developer mode - equivalent to:
|
|
C<--backup --import --no-starter --debug --clear --upgrade --uploads>
|
|
|
|
=item C<-b> C<--build>
|
|
|
|
Build mode - equivalent to:
|
|
C<--verbose --backup --import --starter --no-debug --upgrade --purge --cleantags --index --runwf>
|
|
|
|
=item C<--[no-]backup>
|
|
|
|
Backup database before doing any other operations.
|
|
|
|
=item C<--[no-]delcache>
|
|
|
|
Delete the site's cache. Defaults to on.
|
|
|
|
=item C<--[no-]import=>
|
|
|
|
Import a database script. If no database file is specified,
|
|
F<docs/create.sql> or F<docs/previousVersion.sql> will be used
|
|
depending on if the upgrade option has been specified.
|
|
|
|
=item C<--[no-]uploads>
|
|
|
|
Recreate uploads directory
|
|
|
|
=item C<--[no-]upgrade>
|
|
|
|
Perform an upgrade - also controls which database script to import
|
|
|
|
=item C<--[no-]debug>
|
|
|
|
Enable debug mode and increase session timeout
|
|
|
|
=item C<--[no-]starter>
|
|
|
|
Enable the site starter
|
|
|
|
=item C<--[no-]clear>
|
|
|
|
Clear the content off the home page and its children
|
|
|
|
=item C<--[no-]config>
|
|
|
|
Resets the site's config file. Some values like database information will be
|
|
preserved. Additional options can be set in the WGDev config file.
|
|
|
|
=item C<--[no-]emptytrash>
|
|
|
|
Purges all items from the trash
|
|
|
|
=item C<--[no-]purge>
|
|
|
|
Purge all old revisions
|
|
|
|
=item C<--[no-]cleantags>
|
|
|
|
Removes all version tags and sets all asset revisions to be
|
|
under a new version tag marked with the current version number
|
|
|
|
=item C<--[no-]index>
|
|
|
|
Rebuild the site lineage and reindex all of the content
|
|
|
|
=item C<--[no-]runwf>
|
|
|
|
Attempt to finish any running workflows
|
|
|
|
=item C<--[no-]autologon>
|
|
|
|
Attempt to create sessions on the site logged in as Admin, with
|
|
admin mode enabled based on browser cookies.
|
|
|
|
=item C<--util=>
|
|
|
|
Run a utility script. Script will be run last, being passed to the
|
|
L<C<util> command|WGDev::Command::Util>. Parameter can be specified multiple
|
|
times to run additional scripts.
|
|
|
|
=item C<-p> C<--pro[file]=>
|
|
|
|
Specify a profile of options to use for resetting. Profiles are specified in
|
|
the WGDev config file under the C<command.reset.profiles> section. A profile
|
|
is defined as a string to be used as additional command line options.
|
|
|
|
=back
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
=over 8
|
|
|
|
=item C<< profiles.<profile name> >>
|
|
|
|
Creates a profile to use with the C<--profile> option. The value of the config
|
|
parameter is a string with the command line parameters to apply when this
|
|
profile is used.
|
|
|
|
=item C<config.overide>
|
|
|
|
Overrides to apply when resetting config file.
|
|
|
|
=item C<config.copy>
|
|
|
|
Parameters to copy from existing config file when resetting it.
|
|
|
|
=back
|
|
|
|
=head2 WebGUI Config File Reset
|
|
|
|
The config file is reset by taking the currently specified WebGUI config file,
|
|
the F<WebGUI.conf.orig> file that WGDev finds in the F<etc> directory, and
|
|
instructions in the WGDev config file (see L<WGDev::Command::Config>).
|
|
|
|
The reset config file contains in order of priority: options copied from the
|
|
existing config file, override options, and options in the F<WebGUI.conf.orig>
|
|
file.
|
|
|
|
Overrides are specified in the config parameter C<command.reset.config.overide>
|
|
as a hash of options to apply. Copied parameters are specified in
|
|
C<command.reset.config.copy> as a list of entries to copy. In addition to the
|
|
configured list, a set of parameters is always copied:
|
|
|
|
dsn dbuser dbpass
|
|
uploadsPath uploadsURL
|
|
extrasPath extrasURL
|
|
exportPath
|
|
cacheType fileCacheRoot
|
|
sitename
|
|
spectreIp spectrePort spectreSubnets
|
|
|
|
=method C<option_build>
|
|
|
|
Enables options for creating a release build. Equivalent to
|
|
|
|
$reset->verbosity( $reset->verbosity + 1 );
|
|
$reset->option( backup => 1 );
|
|
$reset->option( uploads => 1 );
|
|
$reset->option( import => 1 );
|
|
$reset->option( starter => 1 );
|
|
$reset->option( debug => 0 );
|
|
$reset->option( upgrade => 1 );
|
|
$reset->option( emptytrash => 1 );
|
|
$reset->option( purge => 1 );
|
|
$reset->option( cleantags => 1 );
|
|
$reset->option( index => 1 );
|
|
$reset->option( runwf => 1 );
|
|
|
|
=method C<option_dev>
|
|
|
|
Enables options for doing development work. Equivalent to
|
|
|
|
$reset->option( backup => 1 );
|
|
$reset->option( import => 1 );
|
|
$reset->option( uploads => 1 );
|
|
$reset->option( upgrade => 1 );
|
|
$reset->option( starter => 0 );
|
|
$reset->option( debug => 1 );
|
|
$reset->option( clear => 1 );
|
|
|
|
=method C<option_fast>
|
|
|
|
Enables options for doing a faster reset, usually used along with
|
|
other group options or profiles. Equivalent to
|
|
|
|
$reset->option( uploads => 0 );
|
|
$reset->option( backup => 0 );
|
|
$reset->option( delcache => 0 );
|
|
$reset->option( purge => 0 );
|
|
$reset->option( cleantags => 0 );
|
|
$reset->option( index => 0 );
|
|
$reset->option( runwf => 0 );
|
|
|
|
=method C<option_profile>
|
|
|
|
Reads a profile from the config section C<command.reset.profiles>
|
|
and processes it as a string of command line options.
|
|
|
|
=method C<clear_cache>
|
|
|
|
Clears the site's cache.
|
|
|
|
=method C<backup>
|
|
|
|
Creates a backup of the site database in the system's temp directory.
|
|
|
|
=method C<reset_uploads>
|
|
|
|
Clears and recreates the uploads location for a site.
|
|
|
|
=method C<import_db_script>
|
|
|
|
Imports a base database script for the site. If
|
|
C<< $reset->option('upgrade') >> is set, F<previousVersion.sql> is
|
|
used. Otherwise, F<create.sql> is used.
|
|
|
|
=method C<upgrade>
|
|
|
|
Performs an upgrade on the site
|
|
|
|
=method C<set_settings>
|
|
|
|
Enabled/disables debug mode and extended/standard session timeout
|
|
based on C<< $reset->option('debug') >> and enables/disables the
|
|
site starter based on C<< $reset->option('starter') >>.
|
|
|
|
=method C<reset_config>
|
|
|
|
Resets the site's config file based on the rules listed in
|
|
L</WebGUI Config File Reset>.
|
|
|
|
=method C<empty_trash>
|
|
|
|
Purges all items from the trash.
|
|
|
|
=method C<purge_old_revisions>
|
|
|
|
Purges all asset revisions aside from the most recent.
|
|
|
|
=method C<clean_version_tags>
|
|
|
|
Collapses all version tags into a single tag labeled based on the
|
|
current WebGUI version.
|
|
|
|
=method C<clear_default_content>
|
|
|
|
Removes all content descending from the default asset, excluding
|
|
Page Layout assets.
|
|
|
|
=method C<delete_users>
|
|
|
|
Removes all users from the site, excepting the default users of
|
|
Admin and Visitor.
|
|
|
|
=method C<rebuild_index>
|
|
|
|
Rebuilds the search index of the site using the F<search.pl> script.
|
|
|
|
=method C<rebuild_lineage>
|
|
|
|
Rebuilds the lineage of the site using the F<rebuildLineage.pl> script.
|
|
|
|
=method C<run_all_workflows>
|
|
|
|
Attempts to finish processing all active workflows. Waiting workflows
|
|
will be run up to 10 times to complete them.
|
|
|
|
=method C<autologon>
|
|
|
|
Attempts to create sessions on the site matching browser cookies.
|
|
|
|
=method C<get_firefox_sessions>
|
|
|
|
Returns a list of session IDs that Firefox has set in cookies for the site.
|
|
|
|
=method C<get_firefox_cookiedb>
|
|
|
|
Returns the name of a copy of Firefox's cookie database.
|
|
|
|
=method C<get_safari_sessions>
|
|
|
|
Returns a list of session IDs that Safari has set in cookies for the site.
|
|
|
|
=cut
|
|
|