Merge "UndeletePage cleanup, part 1"

This commit is contained in:
jenkins-bot 2021-09-27 14:24:53 +00:00 committed by Gerrit Code Review
commit 07f3f8053b
5 changed files with 54 additions and 65 deletions

View file

@ -408,8 +408,10 @@ class PageArchive {
$unsuppress = false,
$tags = null
) {
$up = new UndeletePage( $this->title );
$ret = $up->undeleteAsUser( $timestamps, $user, $comment, $fileVersions, $unsuppress, $tags );
$page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $this->title );
$user = MediaWikiServices::getInstance()->getUserFactory()->newFromUserIdentity( $user );
$up = new UndeletePage( $page, $user );
$ret = $up->undelete( $timestamps, $comment, $fileVersions, $unsuppress, $tags );
$this->fileStatus = $up->getFileStatus();
$this->revisionStatus = $up->getRevisionStatus();
return $ret;

View file

@ -28,16 +28,15 @@ use ManualLogEntry;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\Authority;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\User\UserFactory;
use MediaWiki\User\UserIdentity;
use Psr\Log\LoggerInterface;
use ReadOnlyError;
use ReadOnlyMode;
use RepoGroup;
use Status;
use Title;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
use WikiPage;
@ -67,17 +66,20 @@ class UndeletePage {
/** @var WikiPageFactory */
private $wikiPageFactory;
/** @var Title */
private $title;
/** @var ProperPageIdentity */
private $page;
/** @var Authority */
private $performer;
/** @var Status|null */
private $fileStatus;
/** @var Status|null */
private $revisionStatus;
/**
* @param Title $title
* @param ProperPageIdentity $page
* @param Authority $performer
*/
public function __construct( Title $title ) {
public function __construct( ProperPageIdentity $page, Authority $performer ) {
$services = MediaWikiServices::getInstance();
$this->hookRunner = new HookRunner( $services->getHookContainer() );
@ -90,7 +92,8 @@ class UndeletePage {
$this->userFactory = $services->getUserFactory();
$this->wikiPageFactory = $services->getWikiPageFactory();
$this->title = $title;
$this->page = $page;
$this->performer = $performer;
}
/**
@ -103,7 +106,6 @@ class UndeletePage {
*
* @param array $timestamps Pass an empty array to restore all revisions,
* otherwise list the ones to undelete.
* @param UserIdentity $user
* @param string $comment
* @param array $fileVersions
* @param bool $unsuppress
@ -112,9 +114,8 @@ class UndeletePage {
* @return array|bool [ number of file revisions restored, number of image revisions
* restored, log message ] on success, false on failure.
*/
public function undeleteAsUser(
public function undelete(
$timestamps,
UserIdentity $user,
$comment = '',
$fileVersions = [],
$unsuppress = false,
@ -127,9 +128,9 @@ class UndeletePage {
$restoreText = $restoreAll || !empty( $timestamps );
$restoreFiles = $restoreAll || !empty( $fileVersions );
if ( $restoreFiles && $this->title->getNamespace() === NS_FILE ) {
if ( $restoreFiles && $this->page->getNamespace() === NS_FILE ) {
/** @var LocalFile $img */
$img = $this->repoGroup->getLocalRepo()->newFile( $this->title );
$img = $this->repoGroup->getLocalRepo()->newFile( $this->page );
$img->load( File::READ_LATEST );
$this->fileStatus = $img->restore( $fileVersions, $unsuppress );
if ( !$this->fileStatus->isOK() ) {
@ -151,8 +152,6 @@ class UndeletePage {
$textRestored = 0;
}
// Touch the log!
if ( !$textRestored && !$filesRestored ) {
$this->logger->debug( "Undelete: nothing undeleted..." );
@ -160,8 +159,8 @@ class UndeletePage {
}
$logEntry = new ManualLogEntry( 'delete', 'restore' );
$logEntry->setPerformer( $user );
$logEntry->setTarget( $this->title );
$logEntry->setPerformer( $this->performer->getUser() );
$logEntry->setTarget( $this->page );
$logEntry->setComment( $comment );
$logEntry->addTags( $tags );
$logEntry->setParameters( [
@ -199,8 +198,8 @@ class UndeletePage {
$restoreAll = empty( $timestamps );
$oldWhere = [
'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey(),
'ar_namespace' => $this->page->getNamespace(),
'ar_title' => $this->page->getDBkey(),
];
if ( !$restoreAll ) {
$oldWhere['ar_timestamp'] = array_map( [ &$dbw, 'timestamp' ], $timestamps );
@ -212,9 +211,6 @@ class UndeletePage {
$queryInfo['fields'][] = 'rev_id';
$queryInfo['joins']['revision'] = [ 'LEFT JOIN', 'ar_rev_id=rev_id' ];
/**
* Select each archived revision...
*/
$result = $dbw->select(
$queryInfo['tables'],
$queryInfo['fields'],
@ -273,9 +269,10 @@ class UndeletePage {
}
}
$result->seek( 0 ); // move back
// move back
$result->seek( 0 );
$article = $this->wikiPageFactory->newFromTitle( $this->title );
$wikiPage = $this->wikiPageFactory->newFromTitle( $this->page );
$oldPageId = 0;
/** @var RevisionRecord|null $revision */
@ -283,14 +280,15 @@ class UndeletePage {
$created = true;
$oldcountable = false;
$updatedCurrentRevision = false;
$restored = 0; // number of revisions restored
$restoredRevCount = 0;
$restoredPages = [];
// If there are no restorable revisions, we can skip most of the steps.
if ( $latestRestorableRow === null ) {
$failedRevisionCount = $rev_count;
} else {
$oldPageId = (int)$latestRestorableRow->ar_page_id; // pass this to ArticleUndelete hook
// pass this to ArticleUndelete hook
$oldPageId = (int)$latestRestorableRow->ar_page_id;
// Grab the content to check consistency with global state before restoring the page.
// XXX: The only current use case is Wikibase, which tries to enforce uniqueness of
@ -298,21 +296,17 @@ class UndeletePage {
$revision = $revisionStore->newRevisionFromArchiveRow(
$latestRestorableRow,
0,
$this->title
$this->page
);
// TODO: use UserFactory::newFromUserIdentity from If610c68f4912e
// TODO: The User isn't used for anything in prepareSave()! We should drop it.
$user = $this->userFactory->newFromName(
$revision->getUser( RevisionRecord::RAW )->getName(),
UserFactory::RIGOR_NONE
);
$legacyRevUser = $this->userFactory->newFromUserIdentity( $revision->getUser( RevisionRecord::RAW ) );
foreach ( $revision->getSlotRoles() as $role ) {
$content = $revision->getContent( $role, RevisionRecord::RAW );
// NOTE: article ID may not be known yet. prepareSave() should not modify the database.
$status = $content->prepareSave( $article, 0, -1, $user );
$status = $content->prepareSave( $wikiPage, 0, -1, $legacyRevUser );
if ( !$status->isOK() ) {
$dbw->endAtomic( __METHOD__ );
@ -320,10 +314,10 @@ class UndeletePage {
}
}
$pageId = $article->insertOn( $dbw, $latestRestorableRow->ar_page_id );
$pageId = $wikiPage->insertOn( $dbw, $latestRestorableRow->ar_page_id );
if ( $pageId === false ) {
// The page ID is reserved; let's pick another
$pageId = $article->insertOn( $dbw );
$pageId = $wikiPage->insertOn( $dbw );
if ( $pageId === false ) {
// The page title must be already taken (race condition)
$created = false;
@ -333,12 +327,12 @@ class UndeletePage {
# Does this page already exist? We'll have to update it...
if ( !$created ) {
# Load latest data for the current page (T33179)
$article->loadPageData( WikiPage::READ_EXCLUSIVE );
$pageId = $article->getId();
$oldcountable = $article->isCountable();
$wikiPage->loadPageData( WikiPage::READ_EXCLUSIVE );
$pageId = $wikiPage->getId();
$oldcountable = $wikiPage->isCountable();
$previousTimestamp = false;
$latestRevId = $article->getLatest();
$latestRevId = $wikiPage->getLatest();
if ( $latestRevId ) {
$previousTimestamp = $revisionStore->getTimestampFromId(
$latestRevId,
@ -381,7 +375,7 @@ class UndeletePage {
$revision = $revisionStore->newRevisionFromArchiveRow(
$row,
0,
$this->title,
$this->page,
[
'page_id' => $pageId,
'deleted' => $unsuppress ? 0 : $row->ar_deleted
@ -391,7 +385,7 @@ class UndeletePage {
// This will also copy the revision to ip_changes if it was an IP edit.
$revisionStore->insertRevisionOn( $revision, $dbw );
$restored++;
$restoredRevCount++;
$this->hookRunner->onRevisionUndeleted( $revision, $row->ar_page_id );
@ -411,23 +405,22 @@ class UndeletePage {
__METHOD__ );
}
$status = Status::newGood( $restored );
$status = Status::newGood( $restoredRevCount );
if ( $failedRevisionCount > 0 ) {
$status->warning(
wfMessage( 'undeleterevision-duplicate-revid', $failedRevisionCount ) );
$status->warning( 'undeleterevision-duplicate-revid', $failedRevisionCount );
}
// Was anything restored at all?
if ( $restored ) {
if ( $restoredRevCount ) {
if ( $updatedCurrentRevision ) {
// Attach the latest revision to the page...
// XXX: updateRevisionOn should probably move into a PageStore service.
$wasnew = $article->updateRevisionOn(
$wasnew = $wikiPage->updateRevisionOn(
$dbw,
$revision,
$created ? 0 : $article->getLatest()
$created ? 0 : $wikiPage->getLatest()
);
} else {
$wasnew = false;
@ -436,8 +429,7 @@ class UndeletePage {
if ( $created || $wasnew ) {
// Update site stats, link tables, etc
// TODO: use DerivedPageDataUpdater from If610c68f4912e!
// TODO use UserFactory::newFromUserIdentity
$article->doEditUpdates(
$wikiPage->doEditUpdates(
$revision,
$revision->getUser( RevisionRecord::RAW ),
[
@ -449,11 +441,11 @@ class UndeletePage {
}
$this->hookRunner->onArticleUndelete(
$this->title, $created, $comment, $oldPageId, $restoredPages );
$wikiPage->getTitle(), $created, $comment, $oldPageId, $restoredPages );
if ( $this->title->getNamespace() === NS_FILE ) {
if ( $this->page->getNamespace() === NS_FILE ) {
$job = HTMLCacheUpdateJob::newForBacklinks(
$this->title,
$this->page,
'imagelinks',
[ 'causeAction' => 'file-restore' ]
);

View file

@ -50,7 +50,7 @@ class WikiPageFactory {
*
* @return WikiPage
*/
public function newFromTitle( PageIdentity $pageIdentity ) {
public function newFromTitle( PageIdentity $pageIdentity ): WikiPage {
if ( $pageIdentity instanceof WikiPage ) {
return $pageIdentity;
}

View file

@ -58,11 +58,6 @@ class PurgePage extends Maintenance {
$page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
if ( $page === null ) {
$this->error( "Could not instantiate page object" );
return;
}
if ( !$this->getOption( 'skip-exists-check' ) && !$page->exists() ) {
$this->error( "Page doesn't exist" );
return;

View file

@ -13,9 +13,9 @@ use Wikimedia\IPUtils;
*/
class UndeletePageTest extends MediaWikiIntegrationTestCase {
/**
* @var Title
* @var WikiPage
*/
private $pageTitle;
private $page;
/**
* A logged out user who edited the page before it was archived.
@ -90,11 +90,11 @@ class UndeletePageTest extends MediaWikiIntegrationTestCase {
// Delete the page
$page->doDeleteArticleReal( 'Just a test deletion', $user );
$this->pageTitle = $page->getTitle();
$this->page = $page;
}
/**
* @covers ::undeleteAsUser
* @covers ::undelete
* @covers ::undeleteRevisions
*/
public function testUndeleteRevisions() {
@ -123,8 +123,8 @@ class UndeletePageTest extends MediaWikiIntegrationTestCase {
$this->assertFalse( $row );
// Restore the page
$undeletePage = new UndeletePage( $this->pageTitle );
$undeletePage->undeleteAsUser( [], $this->getTestSysop()->getUser() );
$undeletePage = new UndeletePage( $this->page, $this->getTestSysop()->getUser() );
$undeletePage->undelete( [] );
// Should be back in revision
$revQuery = $revisionStore->getQueryInfo();