Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F585075
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php
index 67c92c074c9..327bf47e28b 100644
--- a/maintenance/reassignEdits.php
+++ b/maintenance/reassignEdits.php
@@ -49,24 +49,29 @@ class ReassignEdits extends Maintenance {
}
public function execute() {
- if ( $this->hasArg( 0 ) && $this->hasArg( 1 ) ) {
- # Set up the users involved
- $from = $this->initialiseUser( $this->getArg( 0 ) );
- $to = $this->initialiseUser( $this->getArg( 1 ) );
-
- # If the target doesn't exist, and --force is not set, stop here
- if ( $to->getId() || $this->hasOption( 'force' ) ) {
- # Reassign the edits
- $report = $this->hasOption( 'report' );
- $this->doReassignEdits( $from, $to, !$this->hasOption( 'norc' ), $report );
- # If reporting, and there were items, advise the user to run without --report
- if ( $report ) {
- $this->output( "Run the script again without --report to update.\n" );
- }
- } else {
- $ton = $to->getName();
- $this->error( "User '{$ton}' not found." );
+ # Set up the users involved
+ $from = $this->initialiseUser( $this->getArg( 0 ) );
+ $to = $this->initialiseUser( $this->getArg( 1 ) );
+
+ // Reject attempts to re-assign to an IP address. This is done because the script does not
+ // populate ip_changes and it breaks if temporary accounts are enabled (T373914).
+ if ( IPUtils::isIPAddress( $to->getName() ) ) {
+ $this->fatalError( 'Script does not support re-assigning to another IP.' );
+ } elseif ( $from->equals( $to ) ) {
+ $this->fatalError( 'The from and to user cannot be the same.' );
+ }
+
+ # If the target doesn't exist, and --force is not set, stop here
+ if ( $to->getId() || $this->hasOption( 'force' ) ) {
+ # Reassign the edits
+ $report = $this->hasOption( 'report' );
+ $this->doReassignEdits( $from, $to, !$this->hasOption( 'norc' ), $report );
+ # If reporting, and there were items, advise the user to run without --report
+ if ( $report ) {
+ $this->output( "Run the script again without --report to update.\n" );
}
+ } else {
+ $this->fatalError( "User '{$to->getName()}' not found." );
}
}
diff --git a/tests/phpunit/maintenance/ReassignEditsTest.php b/tests/phpunit/maintenance/ReassignEditsTest.php
new file mode 100644
index 00000000000..f33fb3e28c2
--- /dev/null
+++ b/tests/phpunit/maintenance/ReassignEditsTest.php
@@ -0,0 +1,168 @@
+<?php
+
+namespace MediaWiki\Tests\Maintenance;
+
+use MediaWiki\Tests\User\TempUser\TempUserTestTrait;
+use MediaWiki\Title\Title;
+use ReassignEdits;
+
+/**
+ * @covers \ReassignEdits
+ * @group Database
+ * @group Maintenance
+ */
+class ReassignEditsTest extends MaintenanceBaseTestCase {
+ use TempUserTestTrait;
+
+ public function getMaintenanceClass() {
+ return ReassignEdits::class;
+ }
+
+ /**
+ * Verifies the output of the maintenance script given various information about the test data and
+ * users provided to the maintenance script.
+ *
+ * @param int $revisionCount
+ * @param int $deletedCount
+ * @param int|null $recentChangesCount Null if the script is set to not search through recentchanges.
+ * @param bool $fromIsIP
+ * @param bool $isDryRun
+ * @return void
+ */
+ private function commonVerifyOutput(
+ int $revisionCount, int $deletedCount, ?int $recentChangesCount, bool $fromIsIP, bool $isDryRun
+ ) {
+ $actualOutput = $this->getActualOutputForAssertion();
+ $total = $revisionCount + $deletedCount;
+
+ // Verify that the counting part of the script had the correct output
+ $this->assertStringContainsString( "Checking current edits...found $revisionCount.", $actualOutput );
+ $this->assertStringContainsString( "Checking deleted edits...found $deletedCount", $actualOutput );
+ if ( $recentChangesCount === null ) {
+ $this->assertStringNotContainsString( "Checking recent changes", $actualOutput );
+ } else {
+ $total += $recentChangesCount;
+ $this->assertStringContainsString( "Checking recent changes...found $recentChangesCount", $actualOutput );
+ }
+ $this->assertStringContainsString( "Total entries to change: $total", $actualOutput );
+
+ // Verify that if it's not a dry-run, the script starts updating the DB
+ if ( $isDryRun ) {
+ $this->assertStringContainsString( 'Run the script again without --report to update', $actualOutput );
+ $this->assertStringNotContainsString( 'Reassigning current edits', $actualOutput );
+ $this->assertStringNotContainsString( 'Reassigning deleted edits', $actualOutput );
+ $this->assertStringNotContainsString( 'Reassigning recent changes edits', $actualOutput );
+ $this->assertStringNotContainsString( 'Deleting ip_changes', $actualOutput );
+
+ return;
+ }
+
+ if ( $revisionCount ) {
+ $this->assertStringContainsString( 'Reassigning current edits...done', $actualOutput );
+ }
+ if ( $deletedCount ) {
+ $this->assertStringContainsString( 'Reassigning deleted edits...done', $actualOutput );
+ }
+ if ( $deletedCount ) {
+ $this->assertStringContainsString( 'Updating recent changes...done', $actualOutput );
+ }
+ if ( $fromIsIP && $total ) {
+ $this->assertStringContainsString( 'Deleting ip_changes...done', $actualOutput );
+ }
+ }
+
+ public function testExecuteToIP() {
+ $fromIP = $this->getServiceContainer()->getUserFactory()->newAnonymous( '1.2.3.4' );
+ $toIP = $this->getServiceContainer()->getUserFactory()->newAnonymous( '1.2.3.5' );
+
+ $this->maintenance->setArg( 'from', $fromIP->getName() );
+ $this->maintenance->setArg( 'to', $toIP->getName() );
+
+ $this->expectCallToFatalError();
+ $this->expectOutputRegex( '/Script does not support re-assigning to another IP/' );
+ $this->maintenance->execute();
+ }
+
+ public function testExecuteWhenUsernameInvalid() {
+ $this->maintenance->setArg( 'from', 'User:::abc#test' );
+ $this->maintenance->setArg( 'to', 'abc#test' );
+
+ $this->expectCallToFatalError();
+ $this->expectOutputRegex( '/Invalid username/' );
+ $this->maintenance->execute();
+ }
+
+ public function testExecuteWhenFromAndToAreSameUser() {
+ $testUser = $this->getTestUser()->getUserIdentity();
+ $this->maintenance->setArg( 'from', $testUser->getName() );
+ $this->maintenance->setArg( 'to', $testUser->getName() );
+ $this->maintenance->setName( 'reassignEdits.php' );
+
+ $this->expectCallToFatalError();
+ $this->expectOutputRegex( '/The from and to user cannot be the same/' );
+ $this->maintenance->execute();
+ }
+
+ public function testExecuteFromIPToUserWhenNoActionsToMove() {
+ $fromIP = $this->getServiceContainer()->getUserFactory()->newAnonymous( '1.2.3.4' );
+ $toUser = $this->getTestUser()->getUserIdentity();
+
+ $this->maintenance->setArg( 'from', $fromIP->getName() );
+ $this->maintenance->setArg( 'to', $toUser->getName() );
+ $this->maintenance->execute();
+
+ $this->commonVerifyOutput( 0, 0, 0, true, false );
+ }
+
+ public function testExecuteFromIPToUserWhenActionsToMoveButReportOnlyMode() {
+ $this->disableAutoCreateTempUser();
+ $fromIP = $this->getServiceContainer()->getUserFactory()->newAnonymous( '1.2.3.4' );
+ $toUser = $this->getTestUser()->getUserIdentity();
+ $this->editPage(
+ $this->getNonexistingTestPage(), 'Testing', '', NS_MAIN, $fromIP
+ );
+
+ $this->maintenance->setArg( 'from', $fromIP->getName() );
+ $this->maintenance->setArg( 'to', $toUser->getName() );
+ $this->maintenance->setOption( 'report', 1 );
+ $this->maintenance->execute();
+
+ $this->commonVerifyOutput( 1, 0, 1, true, true );
+ }
+
+ public function testExecuteFromIPToUserWhenActionsToMove() {
+ $this->disableAutoCreateTempUser();
+ $fromIP = $this->getServiceContainer()->getUserFactory()->newAnonymous( '1.2.3.4' );
+ $toUser = $this->getTestUser()->getUserIdentity();
+ $this->editPage(
+ $this->getNonexistingTestPage(), 'Testing', '', NS_MAIN, $fromIP
+ );
+
+ $this->maintenance->setArg( 'from', $fromIP->getName() );
+ $this->maintenance->setArg( 'to', $toUser->getName() );
+ $this->maintenance->setArg( 'force', 1 );
+ $this->maintenance->execute();
+
+ $this->commonVerifyOutput( 1, 0, 1, true, false );
+ }
+
+ public function testExecuteFromUserToUserWhenActionsToMove() {
+ $this->disableAutoCreateTempUser();
+ $fromUser = $this->getTestUser()->getUser();
+ $toUser = $this->getTestSysop()->getUserIdentity();
+ $pageToDelete = $this->getNonexistingTestPage( Title::newFromText( 'Testing' ) );
+ $this->editPage( $pageToDelete, 'Testing', '', NS_MAIN, $fromUser );
+ $this->deletePage( $pageToDelete );
+
+ $this->editPage(
+ $this->getNonexistingTestPage( Title::newFromText( 'Testingabc' ) ),
+ 'Testingabc', '', NS_MAIN, $fromUser
+ );
+
+ $this->maintenance->setArg( 'from', $fromUser->getName() );
+ $this->maintenance->setArg( 'to', $toUser->getName() );
+ $this->maintenance->execute();
+
+ $this->commonVerifyOutput( 1, 1, 1, false, false );
+ }
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jul 5, 5:32 AM (14 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
227509
Default Alt Text
(8 KB)
Attached To
Mode
rMW mediawiki
Attached
Detach File
Event Timeline
Log In to Comment