Inject services in Hooks and MobileFrontendHandler

Hooks::canReceiveThanks is still static, because it is also used in
MobileFrontendHandler.

Change-Id: Idff34ebce914ad37bcaea8de04b3ef5e01d7d98d
This commit is contained in:
Fomafix 2023-11-07 21:55:06 +00:00
parent ad6496d4fa
commit 4bf74e6415
3 changed files with 89 additions and 38 deletions

View file

@ -179,10 +179,22 @@
}, },
"HookHandlers": { "HookHandlers": {
"main": { "main": {
"class": "MediaWiki\\Extension\\Thanks\\Hooks" "class": "MediaWiki\\Extension\\Thanks\\Hooks",
"services": [
"MainConfig",
"GenderCache",
"PermissionManager",
"RevisionLookup",
"UserFactory",
"UserOptionsManager"
]
}, },
"mobile-frontend": { "mobile-frontend": {
"class": "MediaWiki\\Extension\\Thanks\\MobileFrontendHandler" "class": "MediaWiki\\Extension\\Thanks\\MobileFrontendHandler",
"services": [
"MainConfig",
"UserFactory"
]
} }
}, },
"ServiceWiringFiles": [ "ServiceWiringFiles": [

View file

@ -11,12 +11,14 @@ use DifferenceEngine;
use EchoAttributeManager; use EchoAttributeManager;
use EchoUserLocator; use EchoUserLocator;
use ExtensionRegistry; use ExtensionRegistry;
use GenderCache;
use IContextSource; use IContextSource;
use LogEventsList; use LogEventsList;
use LogPage; use LogPage;
use MediaWiki\Api\Hook\ApiMain__moduleManagerHook; use MediaWiki\Api\Hook\ApiMain__moduleManagerHook;
use MediaWiki\Auth\Hook\LocalUserCreatedHook; use MediaWiki\Auth\Hook\LocalUserCreatedHook;
use MediaWiki\Block\Hook\GetAllBlockActionsHook; use MediaWiki\Block\Hook\GetAllBlockActionsHook;
use MediaWiki\Config\Config;
use MediaWiki\Config\ConfigException; use MediaWiki\Config\ConfigException;
use MediaWiki\Diff\Hook\DifferenceEngineViewHeaderHook; use MediaWiki\Diff\Hook\DifferenceEngineViewHeaderHook;
use MediaWiki\Diff\Hook\DiffToolsHook; use MediaWiki\Diff\Hook\DiffToolsHook;
@ -31,12 +33,15 @@ use MediaWiki\Hook\LogEventsListLineEndingHook;
use MediaWiki\Hook\PageHistoryBeforeListHook; use MediaWiki\Hook\PageHistoryBeforeListHook;
use MediaWiki\Html\Html; use MediaWiki\Html\Html;
use MediaWiki\Linker\LinkTarget; use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
use MediaWiki\Output\OutputPage; use MediaWiki\Output\OutputPage;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\RevisionRecord;
use MediaWiki\SpecialPage\SpecialPage; use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Title\Title; use MediaWiki\Title\Title;
use MediaWiki\User\Options\UserOptionsManager;
use MediaWiki\User\User; use MediaWiki\User\User;
use MediaWiki\User\UserFactory;
use MediaWiki\User\UserIdentity; use MediaWiki\User\UserIdentity;
use RequestContext; use RequestContext;
use Skin; use Skin;
@ -61,6 +66,28 @@ class Hooks implements
LogEventsListLineEndingHook, LogEventsListLineEndingHook,
PageHistoryBeforeListHook PageHistoryBeforeListHook
{ {
private Config $config;
private GenderCache $genderCache;
private PermissionManager $permissionManager;
private RevisionLookup $revisionLookup;
private UserFactory $userFactory;
private UserOptionsManager $userOptionsManager;
public function __construct(
Config $config,
GenderCache $genderCache,
PermissionManager $permissionManager,
RevisionLookup $revisionLookup,
UserFactory $userFactory,
UserOptionsManager $userOptionsManager
) {
$this->config = $config;
$this->genderCache = $genderCache;
$this->permissionManager = $permissionManager;
$this->revisionLookup = $revisionLookup;
$this->userFactory = $userFactory;
$this->userOptionsManager = $userOptionsManager;
}
/** /**
* Handler for the HistoryTools hook * Handler for the HistoryTools hook
@ -76,7 +103,7 @@ class Hooks implements
$oldRevisionRecord, $oldRevisionRecord,
$userIdentity $userIdentity
) { ) {
self::insertThankLink( $revisionRecord, $this->insertThankLink( $revisionRecord,
$links, $userIdentity ); $links, $userIdentity );
} }
@ -96,16 +123,14 @@ class Hooks implements
) { ) {
// Don't allow thanking for a diff that includes multiple revisions // Don't allow thanking for a diff that includes multiple revisions
// This does a query that is too expensive for history rows (T284274) // This does a query that is too expensive for history rows (T284274)
$previous = MediaWikiServices::getInstance() $previous = $this->revisionLookup->getPreviousRevision( $revisionRecord );
->getRevisionLookup()
->getPreviousRevision( $revisionRecord );
if ( $oldRevisionRecord && $previous && if ( $oldRevisionRecord && $previous &&
$previous->getId() !== $oldRevisionRecord->getId() $previous->getId() !== $oldRevisionRecord->getId()
) { ) {
return; return;
} }
self::insertThankLink( $revisionRecord, $this->insertThankLink( $revisionRecord,
$links, $userIdentity, true ); $links, $userIdentity, true );
} }
@ -117,7 +142,7 @@ class Hooks implements
* @param UserIdentity $userIdentity The user performing the thanks. * @param UserIdentity $userIdentity The user performing the thanks.
* @param bool $isPrimaryButton whether the link/button should be progressive * @param bool $isPrimaryButton whether the link/button should be progressive
*/ */
private static function insertThankLink( private function insertThankLink(
RevisionRecord $revisionRecord, RevisionRecord $revisionRecord,
array &$links, array &$links,
UserIdentity $userIdentity, UserIdentity $userIdentity,
@ -129,7 +154,7 @@ class Hooks implements
return; return;
} }
$user = MediaWikiServices::getInstance()->getUserFactory()->newFromUserIdentity( $userIdentity ); $user = $this->userFactory->newFromUserIdentity( $userIdentity );
// Don't let users thank themselves. // Don't let users thank themselves.
// Exclude anonymous users. // Exclude anonymous users.
@ -140,13 +165,13 @@ class Hooks implements
// Check whether we have a revision id to link to // Check whether we have a revision id to link to
if ( $user->isNamed() if ( $user->isNamed()
&& !$userIdentity->equals( $recipient ) && !$userIdentity->equals( $recipient )
&& !self::isUserBlockedFromTitle( $user, $revisionRecord->getPageAsLinkTarget() ) && !$this->isUserBlockedFromTitle( $user, $revisionRecord->getPageAsLinkTarget() )
&& !self::isUserBlockedFromThanks( $user ) && !self::isUserBlockedFromThanks( $user )
&& self::canReceiveThanks( $recipient ) && self::canReceiveThanks( $this->config, $this->userFactory, $recipient )
&& !$revisionRecord->isDeleted( RevisionRecord::DELETED_TEXT ) && !$revisionRecord->isDeleted( RevisionRecord::DELETED_TEXT )
&& $revisionRecord->getId() !== 0 && $revisionRecord->getId() !== 0
) { ) {
$links[] = self::generateThankElement( $links[] = $this->generateThankElement(
$revisionRecord->getId(), $revisionRecord->getId(),
$user, $user,
$recipient, $recipient,
@ -166,9 +191,8 @@ class Hooks implements
* @param LinkTarget $title * @param LinkTarget $title
* @return bool * @return bool
*/ */
private static function isUserBlockedFromTitle( User $user, LinkTarget $title ) { private function isUserBlockedFromTitle( User $user, LinkTarget $title ) {
return MediaWikiServices::getInstance()->getPermissionManager() return $this->permissionManager->isBlockedFrom( $user, $title, true );
->isBlockedFrom( $user, $title, true );
} }
/** /**
@ -185,16 +209,22 @@ class Hooks implements
/** /**
* Check whether a user is allowed to receive thanks or not * Check whether a user is allowed to receive thanks or not
* *
* @param Config $config
* @param UserFactory $userFactory
* @param UserIdentity $user Recipient * @param UserIdentity $user Recipient
* @return bool true if allowed, false if not * @return bool true if allowed, false if not
*/ */
public static function canReceiveThanks( UserIdentity $user ) { public static function canReceiveThanks(
$legacyUser = MediaWikiServices::getInstance()->getUserFactory()->newFromUserIdentity( $user ); Config $config,
UserFactory $userFactory,
UserIdentity $user
) {
$legacyUser = $userFactory->newFromUserIdentity( $user );
if ( !$user->isRegistered() || $legacyUser->isSystemUser() ) { if ( !$user->isRegistered() || $legacyUser->isSystemUser() ) {
return false; return false;
} }
if ( !MediaWikiServices::getInstance()->getMainConfig()->get( 'ThanksSendToBots' ) && if ( !$config->get( 'ThanksSendToBots' ) &&
$legacyUser->isBot() $legacyUser->isBot()
) { ) {
return false; return false;
@ -213,7 +243,7 @@ class Hooks implements
* @param bool $isPrimaryButton whether the link/button should be progressive * @param bool $isPrimaryButton whether the link/button should be progressive
* @return string * @return string
*/ */
protected static function generateThankElement( protected function generateThankElement(
$id, User $sender, UserIdentity $recipient, $type = 'revision', $id, User $sender, UserIdentity $recipient, $type = 'revision',
bool $isPrimaryButton = false bool $isPrimaryButton = false
) { ) {
@ -235,7 +265,6 @@ class Hooks implements
); );
} }
$genderCache = MediaWikiServices::getInstance()->getGenderCache();
// Add 'thank' link // Add 'thank' link
$tooltip = wfMessage( 'thanks-thank-tooltip' ) $tooltip = wfMessage( 'thanks-thank-tooltip' )
->params( $sender->getName(), $recipient->getName() ) ->params( $sender->getName(), $recipient->getName() )
@ -250,7 +279,7 @@ class Hooks implements
'href' => SpecialPage::getTitleFor( 'Thanks', $subpage . $id )->getFullURL(), 'href' => SpecialPage::getTitleFor( 'Thanks', $subpage . $id )->getFullURL(),
'title' => $tooltip, 'title' => $tooltip,
'data-' . $type . '-id' => $id, 'data-' . $type . '-id' => $id,
'data-recipient-gender' => $genderCache->getGenderOf( $recipient->getName(), __METHOD__ ), 'data-recipient-gender' => $this->genderCache->getGenderOf( $recipient->getName(), __METHOD__ ),
], ],
wfMessage( 'thanks-thank', $sender->getName(), $recipient->getName() )->text() wfMessage( 'thanks-thank', $sender->getName(), $recipient->getName() )->text()
); );
@ -259,10 +288,8 @@ class Hooks implements
/** /**
* @param OutputPage $outputPage The OutputPage to add the module to. * @param OutputPage $outputPage The OutputPage to add the module to.
*/ */
protected static function addThanksModule( OutputPage $outputPage ) { protected function addThanksModule( OutputPage $outputPage ) {
$confirmationRequired = MediaWikiServices::getInstance() $confirmationRequired = $this->config->get( 'ThanksConfirmationRequired' );
->getMainConfig()
->get( 'ThanksConfirmationRequired' );
$outputPage->addModules( [ 'ext.thanks.corethank' ] ); $outputPage->addModules( [ 'ext.thanks.corethank' ] );
$outputPage->addJsConfigVars( 'thanks-confirmation-required', $confirmationRequired ); $outputPage->addJsConfigVars( 'thanks-confirmation-required', $confirmationRequired );
} }
@ -276,7 +303,7 @@ class Hooks implements
*/ */
public function onPageHistoryBeforeList( $page, $context ) { public function onPageHistoryBeforeList( $page, $context ) {
if ( $context->getUser()->isRegistered() ) { if ( $context->getUser()->isRegistered() ) {
static::addThanksModule( $context->getOutput() ); $this->addThanksModule( $context->getOutput() );
} }
} }
@ -287,7 +314,7 @@ class Hooks implements
*/ */
public function onDifferenceEngineViewHeader( $diff ) { public function onDifferenceEngineViewHeader( $diff ) {
if ( $diff->getUser()->isRegistered() ) { if ( $diff->getUser()->isRegistered() ) {
static::addThanksModule( $diff->getOutput() ); $this->addThanksModule( $diff->getOutput() );
} }
} }
@ -362,8 +389,7 @@ class Hooks implements
// New users get echo preferences set that are not the default settings for existing users. // New users get echo preferences set that are not the default settings for existing users.
// Specifically, new users are opted into email notifications for thanks. // Specifically, new users are opted into email notifications for thanks.
if ( !$user->isTemp() && !$autocreated ) { if ( !$user->isTemp() && !$autocreated ) {
$userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); $this->userOptionsManager->setOption( $user, 'echo-subscriptions-email-edit-thank', true );
$userOptionsManager->setOption( $user, 'echo-subscriptions-email-edit-thank', true );
} }
} }
@ -404,7 +430,7 @@ class Hooks implements
$title->isSpecial( 'Recentchangeslinked' ) || $title->isSpecial( 'Recentchangeslinked' ) ||
$title->isSpecial( 'Watchlist' ) $title->isSpecial( 'Watchlist' )
) { ) {
static::addThanksModule( $out ); $this->addThanksModule( $out );
} }
} }
@ -482,16 +508,14 @@ class Hooks implements
if ( if (
$user->isAnon() $user->isAnon()
|| $entry->isDeleted( LogPage::DELETED_USER ) || $entry->isDeleted( LogPage::DELETED_USER )
|| self::isUserBlockedFromTitle( $user, $entry->getTarget() ) || $this->isUserBlockedFromTitle( $user, $entry->getTarget() )
|| self::isUserBlockedFromThanks( $user ) || self::isUserBlockedFromThanks( $user )
) { ) {
return; return;
} }
// Make sure this log type is allowed. // Make sure this log type is allowed.
$allowedLogTypes = MediaWikiServices::getInstance() $allowedLogTypes = $this->config->get( 'ThanksAllowedLogTypes' );
->getMainConfig()
->get( 'ThanksAllowedLogTypes' );
if ( !in_array( $entry->getType(), $allowedLogTypes ) if ( !in_array( $entry->getType(), $allowedLogTypes )
&& !in_array( $entry->getType() . '/' . $entry->getSubtype(), $allowedLogTypes ) ) { && !in_array( $entry->getType() . '/' . $entry->getSubtype(), $allowedLogTypes ) ) {
return; return;
@ -502,7 +526,9 @@ class Hooks implements
// Don't check for deleted revision (this avoids extraneous queries from Special:Log). // Don't check for deleted revision (this avoids extraneous queries from Special:Log).
$recipient = $entry->getPerformerIdentity(); $recipient = $entry->getPerformerIdentity();
if ( $recipient->getId() === $user->getId() || !self::canReceiveThanks( $recipient ) ) { if ( $recipient->getId() === $user->getId() ||
!self::canReceiveThanks( $this->config, $this->userFactory, $recipient )
) {
return; return;
} }
@ -510,7 +536,7 @@ class Hooks implements
// or the log entry. // or the log entry.
$type = $entry->getAssociatedRevId() ? 'revision' : 'log'; $type = $entry->getAssociatedRevId() ? 'revision' : 'log';
$id = $entry->getAssociatedRevId() ?: $entry->getId(); $id = $entry->getAssociatedRevId() ?: $entry->getId();
$thankLink = self::generateThankElement( $id, $user, $recipient, $type ); $thankLink = $this->generateThankElement( $id, $user, $recipient, $type );
// Add parentheses to match what's done with Thanks in revision lists and diff displays. // Add parentheses to match what's done with Thanks in revision lists and diff displays.
$ret .= ' ' . wfMessage( 'parentheses' )->rawParams( $thankLink )->escaped(); $ret .= ' ' . wfMessage( 'parentheses' )->rawParams( $thankLink )->escaped();

View file

@ -3,7 +3,9 @@
namespace MediaWiki\Extension\Thanks; namespace MediaWiki\Extension\Thanks;
use ExtensionRegistry; use ExtensionRegistry;
use MediaWiki\Config\Config;
use MediaWiki\Output\OutputPage; use MediaWiki\Output\OutputPage;
use MediaWiki\User\UserFactory;
use MobileContext; use MobileContext;
use MobileFrontend\Hooks\BeforeSpecialMobileDiffDisplayHook; use MobileFrontend\Hooks\BeforeSpecialMobileDiffDisplayHook;
@ -16,6 +18,17 @@ use MobileFrontend\Hooks\BeforeSpecialMobileDiffDisplayHook;
class MobileFrontendHandler implements class MobileFrontendHandler implements
BeforeSpecialMobileDiffDisplayHook BeforeSpecialMobileDiffDisplayHook
{ {
private Config $config;
private UserFactory $userFactory;
public function __construct(
Config $config,
UserFactory $userFactory
) {
$this->config = $config;
$this->userFactory = $userFactory;
}
/** /**
* Add thanks button to SpecialMobileDiff page * Add thanks button to SpecialMobileDiff page
* @param OutputPage &$output OutputPage object * @param OutputPage &$output OutputPage object
@ -35,7 +48,7 @@ class MobileFrontendHandler implements
if ( $rev if ( $rev
&& ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) && ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' )
&& $rev->getUser() && $rev->getUser()
&& Hooks::canReceiveThanks( $rev->getUser() ) && Hooks::canReceiveThanks( $this->config, $this->userFactory, $rev->getUser() )
&& $output->getUser()->isRegistered() && $output->getUser()->isRegistered()
) { ) {
$output->addModules( [ 'ext.thanks.mobilediff' ] ); $output->addModules( [ 'ext.thanks.mobilediff' ] );