Add perm checks to UndeletePage and make it a real service
Add entry in MediaWikiServices, add wiring code, inject all dependencies. Also add an alternative entry point with permission checks, like for DeletePage. The new service is no longer @unstable, and the relevant methods in PageArchive were deprecated. Bug: T290021 Change-Id: I452a98679f5bfea3f7367aacd5c930acffd32102
This commit is contained in:
parent
08766dcad4
commit
249306e112
9 changed files with 151 additions and 27 deletions
|
|
@ -146,6 +146,8 @@ because of Phabricator reports.
|
|||
=== Deprecations in 1.38 ===
|
||||
* The MWGrants class is deprecated in favor of the new GrantsInfo and
|
||||
GrantsLocalization services.
|
||||
* PageArchive::undeleteAsUser(), ::getFileStatus() and ::getRevisionStatus()
|
||||
were deprecated. Use UndeletePage instead.
|
||||
* The global functions wfReadOnly() and wfReadOnlyReason() have been
|
||||
deprecated in favor of the ReadOnlyMode service.
|
||||
* PageProps::getInstance() has been deprecated. Use
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ use MediaWiki\Page\PageStore;
|
|||
use MediaWiki\Page\PageStoreFactory;
|
||||
use MediaWiki\Page\ParserOutputAccess;
|
||||
use MediaWiki\Page\RollbackPageFactory;
|
||||
use MediaWiki\Page\UndeletePageFactory;
|
||||
use MediaWiki\Page\WikiPageFactory;
|
||||
use MediaWiki\Parser\ParserCacheFactory;
|
||||
use MediaWiki\Permissions\GrantsInfo;
|
||||
|
|
@ -1662,6 +1663,14 @@ class MediaWikiServices extends ServiceContainer {
|
|||
return $this->getService( 'UnblockUserFactory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.38
|
||||
* @return UndeletePageFactory
|
||||
*/
|
||||
public function getUndeletePageFactory(): UndeletePageFactory {
|
||||
return $this->getService( 'UndeletePageFactory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.32
|
||||
* @return UploadRevisionImporter
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ use MediaWiki\Page\PageStore;
|
|||
use MediaWiki\Page\PageStoreFactory;
|
||||
use MediaWiki\Page\ParserOutputAccess;
|
||||
use MediaWiki\Page\RollbackPageFactory;
|
||||
use MediaWiki\Page\UndeletePageFactory;
|
||||
use MediaWiki\Page\WikiPageFactory;
|
||||
use MediaWiki\Parser\ParserCacheFactory;
|
||||
use MediaWiki\Parser\ParserObserver;
|
||||
|
|
@ -1702,6 +1703,10 @@ return [
|
|||
return $services->getService( '_UserBlockCommandFactory' );
|
||||
},
|
||||
|
||||
'UndeletePageFactory' => static function ( MediaWikiServices $services ): UndeletePageFactory {
|
||||
return $services->getService( '_PageCommandFactory' );
|
||||
},
|
||||
|
||||
'UploadRevisionImporter' => static function ( MediaWikiServices $services ): UploadRevisionImporter {
|
||||
return new ImportableUploadRevisionImporter(
|
||||
$services->getMainConfig()->get( 'EnableUploads' ),
|
||||
|
|
@ -1978,7 +1983,8 @@ return [
|
|||
ObjectCache::getInstance( 'db-replicated' ),
|
||||
WikiMap::getCurrentWikiDbDomain()->getId(),
|
||||
WebRequest::getRequestId(),
|
||||
$services->getBacklinkCacheFactory()
|
||||
$services->getBacklinkCacheFactory(),
|
||||
LoggerFactory::getInstance( 'UndeletePage' )
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ class PageArchive {
|
|||
* (depending what operations are attempted).
|
||||
*
|
||||
* @since 1.35
|
||||
* @deprecated since 1.38, use UndeletePage instead
|
||||
*
|
||||
* @param array $timestamps Pass an empty array to restore all revisions,
|
||||
* otherwise list the ones to undelete.
|
||||
|
|
@ -408,9 +409,10 @@ class PageArchive {
|
|||
$unsuppress = false,
|
||||
$tags = null
|
||||
) {
|
||||
$page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $this->title );
|
||||
$user = MediaWikiServices::getInstance()->getUserFactory()->newFromUserIdentity( $user );
|
||||
$up = new UndeletePage( $page, $user );
|
||||
$services = MediaWikiServices::getInstance();
|
||||
$page = $services->getWikiPageFactory()->newFromTitle( $this->title );
|
||||
$user = $services->getUserFactory()->newFromUserIdentity( $user );
|
||||
$up = $services->getUndeletePageFactory()->newUndeletePage( $page, $user );
|
||||
if ( is_string( $tags ) ) {
|
||||
$tags = [ $tags ];
|
||||
} elseif ( $tags === null ) {
|
||||
|
|
@ -421,7 +423,7 @@ class PageArchive {
|
|||
->setUndeleteOnlyFileVersions( $fileVersions ?: [] )
|
||||
->setUnsuppress( $unsuppress )
|
||||
->setTags( $tags ?: [] )
|
||||
->undelete( $comment );
|
||||
->undeleteUnsafe( $comment );
|
||||
// BC with old return format
|
||||
if ( $status->isGood() ) {
|
||||
$restoredRevs = $status->getValue()[UndeletePage::REVISIONS_RESTORED];
|
||||
|
|
@ -440,6 +442,7 @@ class PageArchive {
|
|||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 1.38 The entrypoints in UndeletePage return a StatusValue
|
||||
* @return Status|null
|
||||
*/
|
||||
public function getFileStatus() {
|
||||
|
|
@ -447,6 +450,7 @@ class PageArchive {
|
|||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 1.38 The entrypoints in UndeletePage return a StatusValue
|
||||
* @return Status|null
|
||||
*/
|
||||
public function getRevisionStatus() {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ use MediaWiki\User\UserIdentity;
|
|||
use MergeHistory;
|
||||
use MovePage;
|
||||
use NamespaceInfo;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReadOnlyMode;
|
||||
use RepoGroup;
|
||||
use Title;
|
||||
|
|
@ -62,7 +63,8 @@ class PageCommandFactory implements
|
|||
DeletePageFactory,
|
||||
MergeHistoryFactory,
|
||||
MovePageFactory,
|
||||
RollbackPageFactory
|
||||
RollbackPageFactory,
|
||||
UndeletePageFactory
|
||||
{
|
||||
|
||||
/** @var Config */
|
||||
|
|
@ -137,6 +139,9 @@ class PageCommandFactory implements
|
|||
/** @var BacklinkCacheFactory */
|
||||
private $backlinkCacheFactory;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $undeletePageLogger;
|
||||
|
||||
public function __construct(
|
||||
Config $config,
|
||||
LBFactory $lbFactory,
|
||||
|
|
@ -161,7 +166,8 @@ class PageCommandFactory implements
|
|||
BagOStuff $dbReplicatedCache,
|
||||
string $localWikiID,
|
||||
string $webRequestID,
|
||||
BacklinkCacheFactory $backlinkCacheFactory
|
||||
BacklinkCacheFactory $backlinkCacheFactory,
|
||||
LoggerInterface $undeletePageLogger
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->lbFactory = $lbFactory;
|
||||
|
|
@ -187,6 +193,7 @@ class PageCommandFactory implements
|
|||
$this->localWikiID = $localWikiID;
|
||||
$this->webRequestID = $webRequestID;
|
||||
$this->backlinkCacheFactory = $backlinkCacheFactory;
|
||||
$this->undeletePageLogger = $undeletePageLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -315,4 +322,23 @@ class PageCommandFactory implements
|
|||
$byUser
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function newUndeletePage( ProperPageIdentity $page, Authority $authority ): UndeletePage {
|
||||
return new UndeletePage(
|
||||
$this->hookContainer,
|
||||
$this->jobQueueGroup,
|
||||
$this->lbFactory->getMainLB(),
|
||||
$this->readOnlyMode,
|
||||
$this->repoGroup,
|
||||
$this->undeletePageLogger,
|
||||
$this->revisionStore,
|
||||
$this->userFactory,
|
||||
$this->wikiPageFactory,
|
||||
$page,
|
||||
$authority
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,16 @@
|
|||
|
||||
namespace MediaWiki\Page;
|
||||
|
||||
use ChangeTags;
|
||||
use File;
|
||||
use HTMLCacheUpdateJob;
|
||||
use JobQueueGroup;
|
||||
use LocalFile;
|
||||
use ManualLogEntry;
|
||||
use MediaWiki\HookContainer\HookContainer;
|
||||
use MediaWiki\HookContainer\HookRunner;
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Permissions\PermissionStatus;
|
||||
use MediaWiki\Revision\RevisionRecord;
|
||||
use MediaWiki\Revision\RevisionStore;
|
||||
use MediaWiki\User\UserFactory;
|
||||
|
|
@ -45,7 +46,6 @@ use WikiPage;
|
|||
/**
|
||||
* @since 1.38
|
||||
* @package MediaWiki\Page
|
||||
* @unstable
|
||||
*/
|
||||
class UndeletePage {
|
||||
|
||||
|
|
@ -90,21 +90,40 @@ class UndeletePage {
|
|||
private $tags = [];
|
||||
|
||||
/**
|
||||
* @param HookContainer $hookContainer
|
||||
* @param JobQueueGroup $jobQueueGroup
|
||||
* @param ILoadBalancer $loadBalancer
|
||||
* @param ReadOnlyMode $readOnlyMode
|
||||
* @param RepoGroup $repoGroup
|
||||
* @param LoggerInterface $logger
|
||||
* @param RevisionStore $revisionStore
|
||||
* @param UserFactory $userFactory
|
||||
* @param WikiPageFactory $wikiPageFactory
|
||||
* @param ProperPageIdentity $page
|
||||
* @param Authority $performer
|
||||
*/
|
||||
public function __construct( ProperPageIdentity $page, Authority $performer ) {
|
||||
$services = MediaWikiServices::getInstance();
|
||||
|
||||
$this->hookRunner = new HookRunner( $services->getHookContainer() );
|
||||
$this->jobQueueGroup = $services->getJobQueueGroup();
|
||||
$this->loadBalancer = $services->getDBLoadBalancer();
|
||||
$this->readOnlyMode = $services->getReadOnlyMode();
|
||||
$this->repoGroup = $services->getRepoGroup();
|
||||
$this->logger = LoggerFactory::getInstance( 'PageArchive' );
|
||||
$this->revisionStore = $services->getRevisionStore();
|
||||
$this->userFactory = $services->getUserFactory();
|
||||
$this->wikiPageFactory = $services->getWikiPageFactory();
|
||||
public function __construct(
|
||||
HookContainer $hookContainer,
|
||||
JobQueueGroup $jobQueueGroup,
|
||||
ILoadBalancer $loadBalancer,
|
||||
ReadOnlyMode $readOnlyMode,
|
||||
RepoGroup $repoGroup,
|
||||
LoggerInterface $logger,
|
||||
RevisionStore $revisionStore,
|
||||
UserFactory $userFactory,
|
||||
WikiPageFactory $wikiPageFactory,
|
||||
ProperPageIdentity $page,
|
||||
Authority $performer
|
||||
) {
|
||||
$this->hookRunner = new HookRunner( $hookContainer );
|
||||
$this->jobQueueGroup = $jobQueueGroup;
|
||||
$this->loadBalancer = $loadBalancer;
|
||||
$this->readOnlyMode = $readOnlyMode;
|
||||
$this->repoGroup = $repoGroup;
|
||||
$this->logger = $logger;
|
||||
$this->revisionStore = $revisionStore;
|
||||
$this->userFactory = $userFactory;
|
||||
$this->wikiPageFactory = $wikiPageFactory;
|
||||
|
||||
$this->page = $page;
|
||||
$this->performer = $performer;
|
||||
|
|
@ -154,6 +173,33 @@ class UndeletePage {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as undeleteUnsafe, but checks permissions.
|
||||
*
|
||||
* @param string $comment
|
||||
* @return StatusValue
|
||||
*/
|
||||
public function undeleteIfAllowed( string $comment ): StatusValue {
|
||||
$status = $this->authorizeUndeletion();
|
||||
if ( !$status->isGood() ) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $this->undeleteUnsafe( $comment );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PermissionStatus
|
||||
*/
|
||||
private function authorizeUndeletion(): PermissionStatus {
|
||||
$status = PermissionStatus::newEmpty();
|
||||
$this->performer->authorizeWrite( 'undelete', $this->page, $status );
|
||||
if ( $this->tags ) {
|
||||
$status->merge( ChangeTags::canAddTagsAccompanyingChange( $this->tags, $this->performer ) );
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the given (or all) text and file revisions for the page.
|
||||
* Once restored, the items will be removed from the archive tables.
|
||||
|
|
@ -162,6 +208,8 @@ class UndeletePage {
|
|||
* This also sets Status objects, $this->fileStatus and $this->revisionStatus
|
||||
* (depending what operations are attempted).
|
||||
*
|
||||
* @note This method doesn't check user permissions. Use undeleteIfAllowed for that.
|
||||
*
|
||||
* @param string $comment
|
||||
* @return StatusValue Good Status with the following value on success:
|
||||
* [
|
||||
|
|
@ -170,7 +218,7 @@ class UndeletePage {
|
|||
* ]
|
||||
* Fatal Status on failure.
|
||||
*/
|
||||
public function undelete( string $comment ): StatusValue {
|
||||
public function undeleteUnsafe( string $comment ): StatusValue {
|
||||
$hookStatus = StatusValue::newGood();
|
||||
$hookRes = $this->hookRunner->onPageUndelete(
|
||||
$this->page,
|
||||
|
|
|
|||
18
includes/page/UndeletePageFactory.php
Normal file
18
includes/page/UndeletePageFactory.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Page;
|
||||
|
||||
use MediaWiki\Permissions\Authority;
|
||||
|
||||
/**
|
||||
* @since 1.38
|
||||
*/
|
||||
interface UndeletePageFactory {
|
||||
|
||||
/**
|
||||
* @param ProperPageIdentity $page
|
||||
* @param Authority $authority
|
||||
* @return UndeletePage
|
||||
*/
|
||||
public function newUndeletePage( ProperPageIdentity $page, Authority $authority ): UndeletePage;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Page\UndeletePage;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\Revision\MutableRevisionRecord;
|
||||
use MediaWiki\Revision\RevisionRecord;
|
||||
use MediaWiki\Storage\SlotRecord;
|
||||
|
|
@ -94,7 +94,7 @@ class UndeletePageTest extends MediaWikiIntegrationTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @covers ::undelete
|
||||
* @covers ::undeleteUnsafe
|
||||
* @covers ::undeleteRevisions
|
||||
*/
|
||||
public function testUndeleteRevisions() {
|
||||
|
|
@ -123,8 +123,11 @@ class UndeletePageTest extends MediaWikiIntegrationTestCase {
|
|||
$this->assertFalse( $row );
|
||||
|
||||
// Restore the page
|
||||
$undeletePage = new UndeletePage( $this->page, $this->getTestSysop()->getUser() );
|
||||
$undeletePage->undelete( '' );
|
||||
$undeletePage = MediaWikiServices::getInstance()->getUndeletePageFactory()->newUndeletePage(
|
||||
$this->page,
|
||||
$this->getTestSysop()->getUser()
|
||||
);
|
||||
$undeletePage->undeleteUnsafe( '' );
|
||||
|
||||
// Should be back in revision
|
||||
$revQuery = $revisionStore->getQueryInfo();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use MediaWiki\Page\PageIdentity;
|
|||
use MediaWiki\Page\PageIdentityValue;
|
||||
use MediaWiki\Page\ProperPageIdentity;
|
||||
use MediaWiki\Page\RollbackPage;
|
||||
use MediaWiki\Page\UndeletePage;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Tests\Unit\MockServiceDependenciesTrait;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
|
@ -112,4 +113,11 @@ class PageCommandFactoryTest extends MediaWikiUnitTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
public function testUndeletePage() {
|
||||
$undeletePage = $this->getFactory()->newUndeletePage(
|
||||
$this->createMock( ProperPageIdentity::class ),
|
||||
$this->createMock( Authority::class )
|
||||
);
|
||||
$this->assertInstanceOf( UndeletePage::class, $undeletePage );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue