Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions maintenance/DeleteWiki.php

This file was deleted.

128 changes: 110 additions & 18 deletions maintenance/DeleteWikis.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,115 @@

class DeleteWikis extends Maintenance {

private array $deletedWikis = [];
private bool $notified = false;

public function __construct() {
parent::__construct();

$this->addDescription(
'Allows complete deletion of wikis with args controlling ' .
'deletion levels. Will never DROP a database!'
'Deletes wikis. If the --deletewiki option is provided, deletes a single wiki specified by database. ' .
'Otherwise, lists or deletes all wikis marked as deleted (will never DROP a database!). ' .
'A notification is always sent regardless of mode.'
);

$this->addOption( 'delete', 'Actually performs deletions and not outputs wikis to be deleted', false );
$this->addArg( 'user', 'Username or reference name of the person running this script. ' .
$this->addOption( 'deletewiki', 'Specify the database name to delete (single deletion mode).', false, true );
$this->addOption( 'delete', 'Actually performs deletion and not just outputs what would be deleted.' );

$this->addOption( 'user',
'Username or reference name of the person running this script. ' .
'Will be used in tracking and notification internally.',
true );
true, true );

$this->requireExtension( 'CreateWiki' );
}

private function log( string $msg, bool $output ): void {
$logger = $this->getServiceContainer()->get( 'CreateWikiLogger' );
$logger->debug( "DeleteWikis: $msg" );
if ( $output ) {
$this->output( "$msg\n" );
}
}

public function execute(): void {
$user = $this->getOption( 'user' );
if ( !$user ) {
$this->fatalError( 'Please specify the username of the user executing this script.' );
}

$this->deletedWikis = [];

register_shutdown_function( [ $this, 'shutdownHandler' ] );

try {
$dbname = $this->getOption( 'deletewiki' );
if ( $dbname ) {
$this->processSingleDeletion( $dbname );
return;
}

$this->processMultipleDeletions();
$this->output( "Done.\n" );
} finally {
// Make sure we notify deletions regardless even
// if an exception occurred, we always want to notify which
// ones have already been deleted.
$this->notifyDeletions();
}
}

private function processSingleDeletion( string $dbname ): void {
if ( $this->hasOption( 'delete' ) ) {
$this->output(
"You are about to delete $dbname from CreateWiki. " .
"This will not DROP the database. If this is wrong, Ctrl-C now!\n"
);

// Let's count down JUST to be safe!
$this->countDown( 10 );

$wikiManager = $this->getServiceContainer()->get( 'WikiManagerFactory' )
->newInstance( $dbname );
$delete = $wikiManager->delete( force: true );

if ( $delete ) {
$this->fatalError( $delete );
}

$this->log( "Wiki $dbname deleted.", output: true );
$this->deletedWikis[] = $dbname;
} else {
$this->output( "Wiki $dbname would be deleted. Use --delete to actually perform deletion.\n" );
$this->deletedWikis[] = $dbname;
}
}

private function processMultipleDeletions(): void {
if ( $this->hasOption( 'delete' ) ) {
$this->output(
"You are about to delete all wikis that are marked as deleted from CreateWiki. " .
"This will not DROP any databases. If this is wrong, Ctrl-C now!\n"
);

// Let's count down JUST to be safe!
$this->countDown( 10 );
}

$databaseUtils = $this->getServiceContainer()->get( 'CreateWikiDatabaseUtils' );
$wikiManagerFactory = $this->getServiceContainer()->get( 'WikiManagerFactory' );

$dbr = $databaseUtils->getGlobalReplicaDB();

$res = $dbr->newSelectQueryBuilder()
->select( '*' )
->from( 'cw_wikis' )
->table( 'cw_wikis' )
->fields( [
'wiki_dbcluster',
'wiki_dbname',
] )
->where( [ 'wiki_deleted' => 1 ] )
->caller( __METHOD__ )
->fetchResultSet();

$deletedWikis = [];

foreach ( $res as $row ) {
$wiki = $row->wiki_dbname;
$dbCluster = $row->wiki_dbcluster;
Expand All @@ -46,25 +124,37 @@ public function execute(): void {
$delete = $wikiManager->delete( force: false );

if ( $delete ) {
$this->output( "{$wiki}: {$delete}\n" );
$this->log( "$wiki: $delete", output: true );
continue;
}

$this->output( "$dbCluster: DROP DATABASE {$wiki};\n" );
$deletedWikis[] = $wiki;
$this->log( "Wiki $wiki deleted from $dbCluster.", output: false );
$this->output( "$dbCluster: DROP DATABASE $wiki;\n" );
$this->deletedWikis[] = $wiki;
} else {
$this->output( "$wiki: $dbCluster\n" );
$this->deletedWikis[] = $wiki;
}
}
}

$this->output( "Done.\n" );
/**
* Shutdown handler to catch termination of the script.
*/
public function shutdownHandler(): void {
if ( !$this->notified ) {
$this->notifyDeletions();
}
}

$user = $this->getArg( 0 );
$deletedWikis = implode( ', ', $deletedWikis );
private function notifyDeletions(): void {
$user = $this->getOption( 'user' );
$deletedWikisList = implode( ', ', $this->deletedWikis );
$action = $this->hasOption( 'delete' ) ? 'has deleted' : 'is about to delete';

$message = "Hello!\nThis is an automatic notification from CreateWiki notifying you that " .
"just now {$user} has deleted the following wikis from the CreateWiki and " .
"associated extensions:\n{$deletedWikis}";
"just now that $user $action the following wiki(s) from CreateWiki and " .
"associated extensions:\n$deletedWikisList";

$notificationData = [
'type' => 'deletion',
Expand All @@ -78,6 +168,8 @@ public function execute(): void {
// No receivers, it will send to configured email
receivers: []
);

$this->notified = true;
}
}

Expand Down