2018-09-11 16:57:49 +00:00
|
|
|
<?php
|
|
|
|
|
2020-12-02 22:47:40 +00:00
|
|
|
use MediaWiki\Extension\AbuseFilter\GlobalNameUtils;
|
2018-09-11 16:57:49 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
|
|
|
if ( getenv( 'MW_INSTALL_PATH' ) ) {
|
|
|
|
$IP = getenv( 'MW_INSTALL_PATH' );
|
|
|
|
} else {
|
|
|
|
$IP = __DIR__ . '/../../..';
|
|
|
|
}
|
|
|
|
require_once "$IP/maintenance/Maintenance.php";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Split afl_filter in afl_filter_id and afl_global per T42757
|
|
|
|
*/
|
|
|
|
class MigrateAflFilter extends LoggedUpdateMaintenance {
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function __construct() {
|
|
|
|
parent::__construct();
|
|
|
|
|
|
|
|
$this->addOption( 'dry-run', 'Perform a dry run' );
|
|
|
|
$this->requireExtension( 'Abuse Filter' );
|
|
|
|
$this->setBatchSize( 500 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function getUpdateKey() {
|
|
|
|
return __CLASS__;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
public function doDBUpdates() {
|
|
|
|
$aflFilterMigrationStage = $this->getConfig()->get( 'AbuseFilterAflFilterMigrationStage' );
|
|
|
|
|
|
|
|
// Keep this check in place in case the script is executed manually
|
|
|
|
if ( !( $aflFilterMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) {
|
|
|
|
$this->output(
|
|
|
|
"...cannot update while \$wgAbuseFilterAflFilterMigrationStage lacks SCHEMA_COMPAT_WRITE_NEW\n"
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$dryRun = $this->hasOption( 'dry-run' );
|
|
|
|
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
|
|
|
|
$dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
|
2020-12-02 22:47:40 +00:00
|
|
|
$globalPrefix = GlobalNameUtils::GLOBAL_FILTER_PREFIX;
|
2018-09-11 16:57:49 +00:00
|
|
|
|
|
|
|
$batchSize = $this->getBatchSize();
|
|
|
|
$updated = 0;
|
|
|
|
|
|
|
|
$prevID = 1;
|
|
|
|
$curID = $batchSize;
|
|
|
|
|
|
|
|
// Save the row count, and stop once it's reached. This is so that we can tolerate rows with
|
|
|
|
// low IDs that were already updated in a previous execution.
|
|
|
|
$allRowsCount = (int)$dbw->selectField(
|
|
|
|
'abuse_filter_log',
|
|
|
|
'MAX(afl_id)',
|
|
|
|
[],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
|
|
|
do {
|
|
|
|
$this->output( "... processing afl_id's from $prevID to $curID\n" );
|
|
|
|
$updateIDs = $dbw->selectFieldValues(
|
|
|
|
'abuse_filter_log',
|
|
|
|
'afl_id',
|
|
|
|
[
|
|
|
|
// Use the primary key to avoid slow queries (and enforce batch size)
|
|
|
|
"afl_id >= $prevID",
|
|
|
|
"afl_id <= $curID",
|
|
|
|
// Skip updated rows straight away
|
|
|
|
'afl_filter_id' => 0
|
|
|
|
],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
|
|
|
$count = count( $updateIDs );
|
|
|
|
|
|
|
|
$prevID = $curID + 1;
|
|
|
|
$curID += $batchSize;
|
|
|
|
$updated += $count;
|
|
|
|
|
|
|
|
if ( $count === 0 ) {
|
|
|
|
// Can mostly happen if we're on low IDs but they were already updated
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !$dryRun ) {
|
2020-12-02 22:47:40 +00:00
|
|
|
// Use native SQL functions instead of GlobalNameUtils::splitGlobalName so that we can update
|
2018-09-11 16:57:49 +00:00
|
|
|
// all rows at the same time.
|
|
|
|
$newIdSQL = $dbw->buildIntegerCast( $dbw->strreplace(
|
|
|
|
'afl_filter',
|
|
|
|
$dbw->addQuotes( $globalPrefix ),
|
|
|
|
$dbw->addQuotes( '' )
|
|
|
|
) );
|
|
|
|
$globalSQL = $dbw->buildIntegerCast(
|
2020-12-09 08:26:25 +00:00
|
|
|
'(' . $dbw->buildSubstring( 'afl_filter', 1, strlen( $globalPrefix ) ) . ' = ' .
|
|
|
|
$dbw->addQuotes( $globalPrefix ) . ' )'
|
2018-09-11 16:57:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
$dbw->update(
|
|
|
|
'abuse_filter_log',
|
|
|
|
[
|
|
|
|
"afl_filter_id = $newIdSQL",
|
|
|
|
"afl_global = $globalSQL"
|
|
|
|
],
|
|
|
|
[ 'afl_id' => $updateIDs ],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
$lbFactory->waitForReplication();
|
|
|
|
}
|
|
|
|
} while ( $prevID <= $allRowsCount );
|
|
|
|
|
|
|
|
if ( $updated === 0 ) {
|
|
|
|
$this->output( "No rows to change\n" );
|
|
|
|
return !$dryRun;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $dryRun ) {
|
|
|
|
$this->output( "Found $updated rows to migrate in abuse_filter_log\n" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->output( "Migrated $updated rows.\n" );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$maintClass = 'MigrateAflFilter';
|
|
|
|
require_once RUN_MAINTENANCE_IF_MAIN;
|