Deprecate the UndeleteForm::undelete hook

It allowed replacement of the PageArchive object, which is so horrific
that I'm going to have nightmares for a while after seeing that code.

A new hook, PageUndelete, was added to give users something to migrate
to that is also used by API requests etc, and for symmetry with
DeletePage.

This change needs to be in 1.37, since the capability of replacing
PageArchive will be removed in 1.38 by the addition of the UndeletePage
service. Note that in 1.37, errors from the status will not be used
since PageArchive::undeleteAsUser returns false in case of errors.

The only usage of this hook in WMF production (ext:Newsletter) is fixed
in a dependent patch. A non-WMF usage in ext:Video is not fixed since
that one does replace PageArchive and I'd rather not mess with that.

SpecialUndelete has two other similar hooks that pass a PageArchive by
reference, but in those places PageArchive is used as a lookup (not an
undeletion command), so they're not affected by the ongoing undeletion
work, and we cannot deprecate them since we'd have to provide
replacements first. I've left some comments anyway.

Bug: T290021
Change-Id: If434c7ff9de92482f84d535baae5139c18081174
This commit is contained in:
Daimona Eaytoy 2021-09-28 00:50:14 +02:00
parent 6108f30c52
commit eedd8a7774
7 changed files with 80 additions and 1 deletions

View file

@ -805,6 +805,10 @@ because of Phabricator reports.
- .transform-origin()
- .transition()
- .transition-transform()
* The `UndeleteForm::undelete` hook was deprecated. A new hook was
introduced, `PageUndelete`, that provides handlers with more information and
is also called for non-UI requests. The capability of replacing the
PageArchive object has been removed, as that violates the laws of nature.
=== Other changes in 1.37 ===
* WatchlistManager::addWatch() and WatchlistManager::addWatchIgnoringRights(),

View file

@ -58,6 +58,7 @@ class DeprecatedHooks {
'UserSaveOptions' => [ 'deprecatedVersion' => '1.37' ],
'UserSetCookies' => [ 'deprecatedVersion' => '1.27' ],
'WikiPageDeletionUpdates' => [ 'deprecatedVersion' => '1.32', 'silent' => true ],
'UndeleteForm::undelete' => [ 'deprecatedVersion' => '1.37' ],
'userCan' => [ 'deprecatedVersion' => '1.37' ],
'ArticleDelete' => [ 'deprecatedVersion' => '1.37', 'silent' => true ],
'ArticleDeleteComplete' => [ 'deprecatedVersion' => '1.37', 'silent' => true ],

View file

@ -454,6 +454,7 @@ class HookRunner implements
\MediaWiki\Page\Hook\PageDeleteCompleteHook,
\MediaWiki\Page\Hook\PageDeleteHook,
\MediaWiki\Page\Hook\PageDeletionDataUpdatesHook,
\MediaWiki\Page\Hook\PageUndeleteHook,
\MediaWiki\Page\Hook\PageViewUpdatesHook,
\MediaWiki\Page\Hook\RevisionFromEditCompleteHook,
\MediaWiki\Page\Hook\RevisionUndeletedHook,
@ -2731,6 +2732,21 @@ class HookRunner implements
);
}
public function onPageUndelete(
ProperPageIdentity $page,
Authority $performer,
string $reason,
bool $unsuppress,
array $timestamps,
array $fileVersions,
StatusValue $status
) {
return $this->container->run(
'PageUndelete',
[ $page, $performer, $reason, $unsuppress, $timestamps, $fileVersions, $status ]
);
}
public function onPageHistoryBeforeList( $article, $context ) {
return $this->container->run(
'PageHistoryBeforeList',

View file

@ -0,0 +1,41 @@
<?php
namespace MediaWiki\Page\Hook;
use MediaWiki\Page\ProperPageIdentity;
use MediaWiki\Permissions\Authority;
use StatusValue;
/**
* This is a hook handler interface, see docs/Hooks.md.
* Use the hook name "PageUndelete" to register handlers implementing this interface.
*
* @stable to implement
* @ingroup Hooks
*/
interface PageUndeleteHook {
/**
* This hook is called before (part of) a page is undeleted.
*
* @since 1.37
*
* @param ProperPageIdentity $page Page being undeleted.
* @param Authority $performer Who is undeleting the page
* @param string $reason Reason the page is being undeleted
* @param bool $unsuppress Whether content is being unsuppressed or not
* @param string[] $timestamps Timestamps of revisions that we're going to undelete. If empty, means all revisions.
* @param int[] $fileVersions Versions of a file that we're going to undelete. If empty, means all versions.
* @param StatusValue $status Add any error here.
* @return bool|void True or no return value to continue; false to abort, which also requires adding
* a fatal error to $status.
*/
public function onPageUndelete(
ProperPageIdentity $page,
Authority $performer,
string $reason,
bool $unsuppress,
array $timestamps,
array $fileVersions,
StatusValue $status
);
}

View file

@ -131,6 +131,21 @@ class UndeletePage {
$unsuppress = false,
$tags = null
): StatusValue {
$hookStatus = StatusValue::newGood();
$hookRes = $this->hookRunner->onPageUndelete(
$this->page,
$this->performer,
$comment,
$unsuppress,
$timestamps,
$fileVersions ?: [],
$hookStatus
);
if ( !$hookRes && !$hookStatus->isGood() ) {
// Note: as per the PageUndeleteHook documentation, `return false` is ignored if $status is good.
return $hookStatus;
}
// If both the set of text revisions and file revisions are empty,
// restore everything. Otherwise, just restore the requested items.
$restoreAll = empty( $timestamps ) && empty( $fileVersions );

View file

@ -10,7 +10,7 @@ use Title;
* This is a hook handler interface, see docs/Hooks.md.
* Use the hook name "UndeleteForm::undelete" to register handlers implementing this interface.
*
* @stable to implement
* @deprecated since 1.37
* @ingroup Hooks
*/
interface UndeleteForm__undeleteHook {

View file

@ -494,6 +494,7 @@ class SpecialUndelete extends SpecialPage {
}
$archive = new PageArchive( $this->mTargetObj );
// FIXME: This hook must be deprecated, passing PageArchive by ref is awful.
if ( !$this->getHookRunner()->onUndeleteForm__showRevision(
$archive, $this->mTargetObj )
) {
@ -854,6 +855,7 @@ class SpecialUndelete extends SpecialPage {
);
$archive = new PageArchive( $this->mTargetObj );
// FIXME: This hook must be deprecated, passing PageArchive by ref is awful.
$this->getHookRunner()->onUndeleteForm__showHistory( $archive, $this->mTargetObj );
$out->addHTML( Html::openElement( 'div', [ 'class' => 'mw-undelete-history' ] ) );