mediawiki-extensions-AbuseF.../maintenance/AddMissingLoggingEntries.php
Timo Tijhof d2fc2ff8bb maintenance,includes: Clean up file headers
Follows-up Iaa1b4683c5c856.

* Match $IP pattern verbatim from most other WMF extensions.

* Improve descriptions a bit, and move/merge any meaningful
  information from file docblock into class docblock. The file blocks
  are visually ignored and identical in each file, and often out of
  date or duplicated when given text separately from the class block.

  See also similar changes in core:
  https://gerrit.wikimedia.org/r/q/message:ingroup+owner:Krinkle

* Use `@internal` instead of `@private` as per Stable interface
  policy.

Change-Id: I8bed9a625af003446c7e25f6b794931164767b5a
2022-09-29 17:56:49 +01:00

147 lines
4 KiB
PHP

<?php
namespace MediaWiki\Extension\AbuseFilter\Maintenance;
// @codeCoverageIgnoreStart
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
}
require_once "$IP/maintenance/Maintenance.php";
// @codeCoverageIgnoreEnd
use LoggedUpdateMaintenance;
use ManualLogEntry;
use MediaWiki\Extension\AbuseFilter\Special\SpecialAbuseFilter;
use MediaWiki\MediaWikiServices;
use User;
/**
* @codeCoverageIgnore
* No need to test old single-use script.
*/
class AddMissingLoggingEntries extends LoggedUpdateMaintenance {
public function __construct() {
parent::__construct();
$this->addDescription( 'Add missing logging entries for abusefilter-modify T54919' );
$this->addOption( 'dry-run', 'Perform a dry run' );
$this->addOption( 'verbose', 'Print a list of affected afh_id' );
$this->requireExtension( 'Abuse Filter' );
}
/**
* @inheritDoc
*/
public function getUpdateKey() {
return 'AddMissingLoggingEntries';
}
/**
* @inheritDoc
*/
public function doDBUpdates() {
$dryRun = $this->hasOption( 'dry-run' );
$logParams = [];
$afhRows = [];
$db = wfGetDB( DB_REPLICA, 'vslow' );
$logParamsConcat = $db->buildConcat( [ 'afh_id', $db->addQuotes( "\n" ) ] );
$legacyParamsLike = $db->buildLike( $logParamsConcat, $db->anyString() );
// Non-legacy entries are a serialized array with 'newId' and 'historyId' keys
$newLogParamsLike = $db->buildLike( $db->anyString(), 'historyId', $db->anyString() );
// Find all entries in abuse_filter_history without logging entry of same timestamp
$afhResult = $db->select(
[ 'abuse_filter_history', 'logging' ],
[ 'afh_id', 'afh_filter', 'afh_timestamp', 'afh_user', 'afh_deleted', 'afh_user_text' ],
[
'log_id IS NULL',
"NOT log_params $newLogParamsLike"
],
__METHOD__,
[],
[ 'logging' => [
'LEFT JOIN',
"afh_timestamp = log_timestamp AND log_params $legacyParamsLike AND log_type = 'abusefilter'"
] ]
);
// Because the timestamp matches aren't exact (sometimes a couple of
// seconds off), we need to check all our results and ignore those that
// do actually have log entries
foreach ( $afhResult as $row ) {
$logParams[] = $row->afh_id . "\n" . $row->afh_filter;
$afhRows[$row->afh_id] = $row;
}
if ( !count( $afhRows ) ) {
$this->output( "Nothing to do.\n" );
return !$dryRun;
}
$logResult = wfGetDB( DB_REPLICA )->select(
'logging',
[ 'log_params' ],
[ 'log_type' => 'abusefilter', 'log_params' => $logParams ],
__METHOD__
);
foreach ( $logResult as $row ) {
// id . "\n" . filter
$afhId = explode( "\n", $row->log_params, 2 )[0];
// Forget this row had any issues - it just has a different timestamp in the log
unset( $afhRows[$afhId] );
}
if ( !count( $afhRows ) ) {
$this->output( "Nothing to do.\n" );
return !$dryRun;
}
if ( $dryRun ) {
$msg = count( $afhRows ) . " rows to insert.";
if ( $this->hasOption( 'verbose' ) ) {
$msg .= " Affected IDs (afh_id):\n" . implode( ', ', array_keys( $afhRows ) );
}
$this->output( "$msg\n" );
return false;
}
$dbw = wfGetDB( DB_PRIMARY );
$factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
$count = 0;
foreach ( $afhRows as $row ) {
if ( $count % 100 === 0 ) {
$factory->waitForReplication();
}
$user = User::newFromAnyId( $row->afh_user, $row->afh_user_text, null );
if ( $user === null ) {
// This isn't supposed to happen.
continue;
}
// This copies the code in FilterStore
$logEntry = new ManualLogEntry( 'abusefilter', 'modify' );
$logEntry->setPerformer( $user );
$logEntry->setTarget( SpecialAbuseFilter::getTitleForSubpage( $row->afh_filter ) );
// Use the new format!
$logEntry->setParameters( [
'historyId' => $row->afh_id,
'newId' => $row->afh_filter
] );
$logEntry->setTimestamp( $row->afh_timestamp );
$logEntry->insert( $dbw );
$count++;
}
$this->output( "Inserted $count rows.\n" );
return true;
}
}
$maintClass = AddMissingLoggingEntries::class;
require_once RUN_MAINTENANCE_IF_MAIN;