Add support for extentions to change Special:Mute form

The hook (SpecialMuteModifyFormFields) is used to append
the option to mute/unmute notifications from a specified user.

Special:Mute handles posting and saving the fields, the only
requirement is that the field name is the same as the property
that wants to be modified.

Currently there are only two notifications "blacklists":
* `email-blacklist` is directly handled in this page 'cause it is part of core.
* `echo-notifications-blacklist` is part of Echo, so this change is required
  to support it. See I77b3ccfdce9b501e

Bug: T220163
Change-Id: I2b3eee0802cb086091f35ecce13ae77a8e7d518d
This commit is contained in:
Dayllan Maza 2019-07-01 10:14:42 -04:00 committed by Dbarratt
parent 3e39ec72a6
commit b5f384f943
6 changed files with 65 additions and 39 deletions

View file

@ -77,6 +77,8 @@ For notes on 1.33.x and older releases, see HISTORY.
of headers in private wikis.
* Language::formatTimePeriod now supports the new 'avoidhours' option to output
strings like "5 days ago" instead of "5 days 13 hours ago".
* (T220163) Added SpecialMuteModifyFormFields hook to allow extensions
to add fields to Special:Mute.
=== External library changes in 1.34 ===

View file

@ -3200,6 +3200,10 @@ $request: WebRequest object for getting the value provided by the current user
&$oldTitle: old title (object)
&$newTitle: new title (object)
'SpecialMuteModifyFormFields': Add more fields to Special:Mute
$sp: SpecialPage object, for context
&$fields: Current HTMLForm fields descriptors
'SpecialNewpagesConditions': Called when building sql query for
Special:NewPages.
&$special: NewPagesPager object (subclass of ReverseChronologicalPager)

View file

@ -28,6 +28,8 @@ use MediaWiki\Preferences\MultiUsernameFilter;
*/
class SpecialMute extends FormSpecialPage {
const PAGE_NAME = 'Mute';
/** @var User */
private $target;
@ -51,7 +53,7 @@ class SpecialMute extends FormSpecialPage {
$this->centralIdLookup = CentralIdLookup::factory();
parent::__construct( 'Mute', '', false );
parent::__construct( self::PAGE_NAME, '', false );
}
/**
@ -66,7 +68,7 @@ class SpecialMute extends FormSpecialPage {
parent::execute( $par );
$out = $this->getOutput();
$out->addModules( 'mediawiki.special.pageLanguage' );
$out->addModules( 'mediawiki.misc-authed-ooui' );
}
/**
@ -97,10 +99,12 @@ class SpecialMute extends FormSpecialPage {
* @return bool
*/
public function onSubmit( array $data, HTMLForm $form = null ) {
if ( !empty( $data['MuteEmail'] ) ) {
$this->muteEmailsFromTarget();
} else {
$this->unmuteEmailsFromTarget();
foreach ( $data as $userOption => $value ) {
if ( $value ) {
$this->muteTarget( $userOption );
} else {
$this->unmuteTarget( $userOption );
}
}
return true;
@ -114,10 +118,12 @@ class SpecialMute extends FormSpecialPage {
}
/**
* Un-mute emails from target
* Un-mute target
*
* @param string $userOption up_property key that holds the blacklist
*/
private function unmuteEmailsFromTarget() {
$blacklist = $this->getBlacklist();
private function unmuteTarget( $userOption ) {
$blacklist = $this->getBlacklist( $userOption );
$key = array_search( $this->targetCentralId, $blacklist );
if ( $key !== false ) {
@ -125,24 +131,25 @@ class SpecialMute extends FormSpecialPage {
$blacklist = implode( "\n", $blacklist );
$user = $this->getUser();
$user->setOption( 'email-blacklist', $blacklist );
$user->setOption( $userOption, $blacklist );
$user->saveSettings();
}
}
/**
* Mute emails from target
* Mute target
* @param string $userOption up_property key that holds the blacklist
*/
private function muteEmailsFromTarget() {
private function muteTarget( $userOption ) {
// avoid duplicates just in case
if ( !$this->isTargetBlacklisted() ) {
$blacklist = $this->getBlacklist();
if ( !$this->isTargetBlacklisted( $userOption ) ) {
$blacklist = $this->getBlacklist( $userOption );
$blacklist[] = $this->targetCentralId;
$blacklist = implode( "\n", $blacklist );
$user = $this->getUser();
$user->setOption( 'email-blacklist', $blacklist );
$user->setOption( $userOption, $blacklist );
$user->saveSettings();
}
}
@ -150,30 +157,38 @@ class SpecialMute extends FormSpecialPage {
/**
* @inheritDoc
*/
protected function alterForm( HTMLForm $form ) {
protected function getForm() {
$form = parent::getForm();
$form->setId( 'mw-specialmute-form' );
$form->setHeaderText( $this->msg( 'specialmute-header', $this->target )->parse() );
$form->setSubmitTextMsg( 'specialmute-submit' );
$form->setSubmitID( 'save' );
return $form;
}
/**
* @inheritDoc
*/
protected function getFormFields() {
if ( !$this->enableUserEmailBlacklist || !$this->enableUserEmail ) {
throw new ErrorPageError( 'specialmute', 'specialmute-error-email-blacklist-disabled' );
$fields = [];
if (
$this->enableUserEmailBlacklist &&
$this->enableUserEmail &&
$this->getUser()->getEmailAuthenticationTimestamp()
) {
$fields['email-blacklist'] = [
'type' => 'check',
'label-message' => 'specialmute-label-mute-email',
'default' => $this->isTargetBlacklisted( 'email-blacklist' ),
];
}
if ( !$this->getUser()->getEmailAuthenticationTimestamp() ) {
throw new ErrorPageError( 'specialmute', 'specialmute-error-email-preferences' );
}
Hooks::run( 'SpecialMuteModifyFormFields', [ $this, &$fields ] );
$fields['MuteEmail'] = [
'type' => 'check',
'label-message' => 'specialmute-label-mute-email',
'default' => $this->isTargetBlacklisted(),
];
if ( count( $fields ) == 0 ) {
throw new ErrorPageError( 'specialmute', 'specialmute-error-no-options' );
}
return $fields;
}
@ -192,18 +207,20 @@ class SpecialMute extends FormSpecialPage {
}
/**
* @param string $userOption
* @return bool
*/
private function isTargetBlacklisted() {
$blacklist = $this->getBlacklist();
return in_array( $this->targetCentralId, $blacklist );
public function isTargetBlacklisted( $userOption ) {
$blacklist = $this->getBlacklist( $userOption );
return in_array( $this->targetCentralId, $blacklist, true );
}
/**
* @param string $userOption
* @return array
*/
private function getBlacklist() {
$blacklist = $this->getUser()->getOption( 'email-blacklist' );
private function getBlacklist( $userOption ) {
$blacklist = $this->getUser()->getOption( $userOption );
if ( !$blacklist ) {
return [];
}

View file

@ -4202,10 +4202,9 @@
"specialmute-success": "Your mute preferences have been updated. See all muted users in [[Special:Preferences|your preferences]].",
"specialmute-submit": "Confirm",
"specialmute-label-mute-email": "Mute emails from this user",
"specialmute-header": "Please select your mute preferences for {{BIDI:[[User:$1]]}}.",
"specialmute-header": "Please select your mute preferences for <b>{{BIDI:[[User:$1]]}}</b>.",
"specialmute-error-invalid-user": "The username requested could not be found.",
"specialmute-error-email-blacklist-disabled": "Muting users from sending you emails is not enabled.",
"specialmute-error-email-preferences": "You must confirm your email address before you can mute a user. You may do so from [[Special:Preferences]].",
"specialmute-error-no-options": "Mute features are unavailable. This might be because: you haven't confirmed your email address or the wiki administrator has disabled email features and/or email blacklist for this wiki.",
"specialmute-email-footer": "To manage email preferences for {{BIDI:$2}} please visit <$1>.",
"specialmute-login-required": "Please log in to change your mute preferences.",
"mute-preferences": "Mute preferences",

View file

@ -4413,8 +4413,7 @@
"specialmute-label-mute-email": "Label for the checkbox that mutes/unmutes emails from the specified user.",
"specialmute-header": "Used as header text on [[Special:Mute]]. Shown before the form with the muting options.\n* $1 - User selected for muting",
"specialmute-error-invalid-user": "Error displayed when the username cannot be found.",
"specialmute-error-email-blacklist-disabled": "Error displayed when email blacklist is not enabled.",
"specialmute-error-email-preferences": "Error displayed when the user has not confirmed their email address.",
"specialmute-error-no-options": "Error displayed when there are no options available to mute on [[Special:Mute]].",
"specialmute-email-footer": "Email footer in plain text linking to [[Special:Mute]] preselecting the sender to manage muting options.\n* $1 - Url linking to [[Special:Mute]].\n* $2 - The user sending the email.",
"specialmute-login-required": "Error displayed when a user tries to access [[Special:Mute]] before logging in.",
"mute-preferences": "Link in the sidebar to manage muting preferences for a user. It links to [[Special:Mute]] with the user in context as the subpage.",

View file

@ -35,10 +35,15 @@ class SpecialMuteTest extends SpecialPageTestBase {
/**
* @covers SpecialMute::execute
* @expectedExceptionMessage Muting users from sending you emails is not enabled
* @expectedExceptionMessage Mute features are unavailable
* @expectedException ErrorPageError
*/
public function testEmailBlacklistNotEnabled() {
$this->setTemporaryHook(
'SpecialMuteModifyFormFields',
null
);
$this->setMwGlobals( [
'wgEnableUserEmailBlacklist' => false
] );
@ -72,7 +77,7 @@ class SpecialMuteTest extends SpecialPageTestBase {
$loggedInUser->confirmEmail();
$loggedInUser->saveSettings();
$fauxRequest = new FauxRequest( [ 'wpMuteEmail' => 1 ], true );
$fauxRequest = new FauxRequest( [ 'wpemail-blacklist' => true ], true );
list( $html, ) = $this->executeSpecialPage(
$targetUser->getName(), $fauxRequest, 'qqx', $loggedInUser
);
@ -99,7 +104,7 @@ class SpecialMuteTest extends SpecialPageTestBase {
$loggedInUser->confirmEmail();
$loggedInUser->saveSettings();
$fauxRequest = new FauxRequest( [ 'wpMuteEmail' => false ], true );
$fauxRequest = new FauxRequest( [ 'wpemail-blacklist' => false ], true );
list( $html, ) = $this->executeSpecialPage(
$targetUser->getName(), $fauxRequest, 'qqx', $loggedInUser
);