Add a service to format filter specs

This requires a MessageLocalizer, which currently means providing the
main RequestContext. This is the only alternative right now, until core
provides a proper MessageLocalizer service (see T247127).

Change-Id: I8c93e2ae7e7bd4fc561c5e8490ed2feb1ef0edc2
This commit is contained in:
Daimona Eaytoy 2020-10-02 17:08:48 +02:00
parent dc7509811a
commit 7bcb5ec2d5
16 changed files with 414 additions and 135 deletions

View file

@ -70,7 +70,8 @@
"PermissionManager",
"AbuseFilterPermissionManager",
"AbuseFilterConsequencesRegistry",
"AbuseFilterVariablesBlobStore"
"AbuseFilterVariablesBlobStore",
"AbuseFilterSpecsFormatter"
]
},
"AbuseFilter": {
@ -164,6 +165,7 @@
"MediaWiki\\Extension\\AbuseFilter\\AbuseFilterPermissionManager": "includes/AbuseFilterPermissionManager.php",
"MediaWiki\\Extension\\AbuseFilter\\EchoNotifier": "includes/EchoNotifier.php",
"MediaWiki\\Extension\\AbuseFilter\\ThrottleFilterPresentationModel": "includes/ThrottleFilterPresentationModel.php",
"MediaWiki\\Extension\\AbuseFilter\\SpecsFormatter": "includes/SpecsFormatter.php",
"MediaWiki\\Extension\\AbuseFilter\\AbuseFilterServices": "includes/AbuseFilterServices.php",
"MediaWiki\\Extension\\AbuseFilter\\FilterProfiler": "includes/FilterProfiler.php",
"MediaWiki\\Extension\\AbuseFilter\\BlockAutopromoteStore": "includes/BlockAutopromoteStore.php",

View file

@ -68,21 +68,6 @@ class AbuseFilter {
return $runner->run();
}
/**
* @param string $action
* @param MessageLocalizer|null $localizer
* @return string HTML
*/
public static function getActionDisplay( $action, MessageLocalizer $localizer = null ) {
$msgCallback = $localizer != null ? [ $localizer, 'msg' ] : 'wfMessage';
// Give grep a chance to find the usages:
// abusefilter-action-tag, abusefilter-action-throttle, abusefilter-action-warn,
// abusefilter-action-blockautopromote, abusefilter-action-block, abusefilter-action-degroup,
// abusefilter-action-rangeblock, abusefilter-action-disallow
$msg = $msgCallback( "abusefilter-action-$action" );
return $msg->isDisabled() ? htmlspecialchars( $action ) : $msg->escaped();
}
/**
* @param mixed $var
* @param string $indent
@ -177,99 +162,6 @@ class AbuseFilter {
return $output;
}
/**
* @param string $action
* @param string[] $parameters
* @param Language $lang
* @return string
*/
public static function formatAction( $action, $parameters, $lang ) {
if ( count( $parameters ) === 0 ||
( $action === 'block' && count( $parameters ) !== 3 ) ) {
$displayAction = self::getActionDisplay( $action );
} else {
if ( $action === 'block' ) {
// Needs to be treated separately since the message is more complex
$messages = [
wfMessage( 'abusefilter-block-anon' )->escaped() .
wfMessage( 'colon-separator' )->escaped() .
$lang->translateBlockExpiry( $parameters[1] ),
wfMessage( 'abusefilter-block-user' )->escaped() .
wfMessage( 'colon-separator' )->escaped() .
$lang->translateBlockExpiry( $parameters[2] )
];
if ( $parameters[0] === 'blocktalk' ) {
$messages[] = wfMessage( 'abusefilter-block-talk' )->escaped();
}
$displayAction = $lang->commaList( $messages );
} elseif ( $action === 'throttle' ) {
array_shift( $parameters );
list( $actions, $time ) = explode( ',', array_shift( $parameters ) );
// Join comma-separated groups in a commaList with a final "and", and convert to messages.
// Messages used here: abusefilter-throttle-ip, abusefilter-throttle-user,
// abusefilter-throttle-site, abusefilter-throttle-creationdate, abusefilter-throttle-editcount
// abusefilter-throttle-range, abusefilter-throttle-page, abusefilter-throttle-none
foreach ( $parameters as &$val ) {
if ( strpos( $val, ',' ) !== false ) {
$subGroups = explode( ',', $val );
foreach ( $subGroups as &$group ) {
$msg = wfMessage( "abusefilter-throttle-$group" );
// We previously accepted literally everything in this field, so old entries
// may have weird stuff.
$group = $msg->exists() ? $msg->text() : $group;
}
unset( $group );
$val = $lang->listToText( $subGroups );
} else {
$msg = wfMessage( "abusefilter-throttle-$val" );
$val = $msg->exists() ? $msg->text() : $val;
}
}
unset( $val );
$groups = $lang->semicolonList( $parameters );
$displayAction = self::getActionDisplay( $action ) .
wfMessage( 'colon-separator' )->escaped() .
wfMessage( 'abusefilter-throttle-details' )->params( $actions, $time, $groups )->escaped();
} else {
$displayAction = self::getActionDisplay( $action ) .
wfMessage( 'colon-separator' )->escaped() .
$lang->semicolonList( array_map( 'htmlspecialchars', $parameters ) );
}
}
return $displayAction;
}
/**
* @param string $value
* @param Language $lang
* @return string
*/
public static function formatFlags( $value, $lang ) {
$flags = array_filter( explode( ',', $value ) );
$flags_display = [];
foreach ( $flags as $flag ) {
$flags_display[] = wfMessage( "abusefilter-history-$flag" )->escaped();
}
return $lang->commaList( $flags_display );
}
/**
* Gives either the user-specified name for a group,
* or spits the input back out
* @param string $group The filter's group (as defined in $wgAbuseFilterValidGroups)
* @return string A name for that filter group, or the input.
*/
public static function nameGroup( $group ) {
// Give grep a chance to find the usages: abusefilter-group-default
$msg = "abusefilter-group-$group";
return wfMessage( $msg )->exists() ? wfMessage( $msg )->escaped() : $group;
}
/**
* Look up some text of a revision from its revision id
*

View file

@ -197,4 +197,11 @@ class AbuseFilterServices {
public static function getFilterRunnerFactory() : FilterRunnerFactory {
return MediaWikiServices::getInstance()->getService( FilterRunnerFactory::SERVICE_NAME );
}
/**
* @return SpecsFormatter
*/
public static function getSpecsFormatter() : SpecsFormatter {
return MediaWikiServices::getInstance()->getService( SpecsFormatter::SERVICE_NAME );
}
}

View file

@ -2,8 +2,8 @@
namespace MediaWiki\Extension\AbuseFilter\LogFormatter;
use AbuseFilter;
use LogFormatter;
use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use Message;
use SpecialPage;
@ -52,8 +52,10 @@ class AbuseLogHitFormatter extends LogFormatter {
$actions = explode( ',', $actions_takenRaw );
$displayActions = [];
$specsFormatter = AbuseFilterServices::getSpecsFormatter();
$specsFormatter->setMessageLocalizer( $this->context );
foreach ( $actions as $action ) {
$displayActions[] = AbuseFilter::getActionDisplay( $action, $this->context );
$displayActions[] = $specsFormatter->getActionDisplay( $action );
}
$actions_taken = $this->context->getLanguage()->commaList( $displayActions );
}

View file

@ -5,6 +5,7 @@ namespace MediaWiki\Extension\AbuseFilter\Pager;
use AbuseFilter;
use HtmlArmor;
use Linker;
use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use MediaWiki\Extension\AbuseFilter\View\AbuseFilterViewHistory;
use MediaWiki\Linker\LinkRenderer;
use SpecialPage;
@ -92,6 +93,8 @@ class AbuseFilterHistoryPager extends TablePager {
public function formatValue( $name, $value ) {
$lang = $this->getLanguage();
$linkRenderer = $this->getLinkRenderer();
$specsFormatter = AbuseFilterServices::getSpecsFormatter();
$specsFormatter->setMessageLocalizer( $this->getContext() );
$row = $this->mCurrentRow;
@ -119,7 +122,7 @@ class AbuseFilterHistoryPager extends TablePager {
$formatted = htmlspecialchars( $value, ENT_QUOTES, 'UTF-8', false );
break;
case 'afh_flags':
$formatted = AbuseFilter::formatFlags( $value, $lang );
$formatted = $specsFormatter->formatFlags( $value, $lang );
break;
case 'afh_actions':
$actions = unserialize( $value );
@ -127,7 +130,7 @@ class AbuseFilterHistoryPager extends TablePager {
$display_actions = '';
foreach ( $actions as $action => $parameters ) {
$displayAction = AbuseFilter::formatAction( $action, $parameters, $lang );
$displayAction = $specsFormatter->formatAction( $action, $parameters, $lang );
$display_actions .= Xml::tags( 'li', null, $displayAction );
}
$display_actions = Xml::tags( 'ul', null, $display_actions );

View file

@ -2,7 +2,6 @@
namespace MediaWiki\Extension\AbuseFilter\Pager;
use AbuseFilter;
use FakeResultWrapper;
use Linker;
use LogicException;
@ -187,6 +186,8 @@ class AbuseFilterPager extends TablePager {
$lang = $this->getLanguage();
$user = $this->getUser();
$linkRenderer = $this->getLinkRenderer();
$specsFormatter = AbuseFilterServices::getSpecsFormatter();
$specsFormatter->setMessageLocalizer( $this->getContext() );
$row = $this->mCurrentRow;
switch ( $name ) {
@ -205,9 +206,8 @@ class AbuseFilterPager extends TablePager {
case 'af_actions':
$actions = explode( ',', $value );
$displayActions = [];
$context = $this->getContext();
foreach ( $actions as $action ) {
$displayActions[] = AbuseFilter::getActionDisplay( $action, $context );
$displayActions[] = $specsFormatter->getActionDisplay( $action );
}
return $lang->commaList( $displayActions );
case 'af_enabled':
@ -276,7 +276,7 @@ class AbuseFilterPager extends TablePager {
wfEscapeWikiText( $row->af_user_text )
)->parse();
case 'af_group':
return AbuseFilter::nameGroup( $value );
return $specsFormatter->nameGroup( $value );
default:
throw new MWException( "Unknown row type $name!" );
}

View file

@ -2,7 +2,6 @@
namespace MediaWiki\Extension\AbuseFilter\Pager;
use AbuseFilter;
use HtmlArmor;
use IContextSource;
use Linker;
@ -166,9 +165,10 @@ class AbuseLogPager extends ReverseChronologicalPager {
$actions = explode( ',', $actions_takenRaw );
$displayActions = [];
$context = $this->getContext();
$specsFormatter = AbuseFilterServices::getSpecsFormatter();
$specsFormatter->setMessageLocalizer( $this->getContext() );
foreach ( $actions as $action ) {
$displayActions[] = AbuseFilter::getActionDisplay( $action, $context );
$displayActions[] = $specsFormatter->getActionDisplay( $action );
}
$actions_taken = $lang->commaList( $displayActions );
}

View file

@ -2,7 +2,7 @@
namespace MediaWiki\Extension\AbuseFilter\Pager;
use AbuseFilter;
use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use MediaWiki\Extension\AbuseFilter\View\AbuseFilterViewList;
use MediaWiki\Linker\LinkRenderer;
@ -28,6 +28,8 @@ class GlobalAbuseFilterPager extends AbuseFilterPager {
*/
public function formatValue( $name, $value ) {
$lang = $this->getLanguage();
$specsFormatter = AbuseFilterServices::getSpecsFormatter();
$specsFormatter->setMessageLocalizer( $this->getContext() );
$row = $this->mCurrentRow;
switch ( $name ) {
@ -67,7 +69,7 @@ class GlobalAbuseFilterPager extends AbuseFilterPager {
)->parse();
case 'af_group':
// If this is global, local name probably doesn't exist, but try
return AbuseFilter::nameGroup( $value );
return $specsFormatter->nameGroup( $value );
default:
return parent::formatValue( $name, $value );
}

View file

@ -28,6 +28,7 @@ use MediaWiki\Extension\AbuseFilter\FilterValidator;
use MediaWiki\Extension\AbuseFilter\Hooks\AbuseFilterHookRunner;
use MediaWiki\Extension\AbuseFilter\KeywordsManager;
use MediaWiki\Extension\AbuseFilter\Parser\ParserFactory;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Extension\AbuseFilter\VariablesBlobStore;
use MediaWiki\Extension\AbuseFilter\Watcher\EmergencyWatcher;
use MediaWiki\Extension\AbuseFilter\Watcher\UpdateHitCountWatcher;
@ -263,6 +264,12 @@ return [
$services->getMainConfig()->get( 'AbuseFilterValidGroups' )
);
},
SpecsFormatter::SERVICE_NAME => function ( MediaWikiServices $services ): SpecsFormatter {
return new SpecsFormatter(
// TODO: Use a proper MessageLocalizer once available (T247127)
RequestContext::getMain()
);
},
];
// @codeCoverageIgnoreEnd

133
includes/SpecsFormatter.php Normal file
View file

@ -0,0 +1,133 @@
<?php
namespace MediaWiki\Extension\AbuseFilter;
use Language;
use MessageLocalizer;
/**
* @todo Improve this once DI around Message objects is improved in MW core.
*/
class SpecsFormatter {
public const SERVICE_NAME = 'AbuseFilterSpecsFormatter';
/** @var MessageLocalizer */
private $messageLocalizer;
/**
* @param MessageLocalizer $messageLocalizer
*/
public function __construct( MessageLocalizer $messageLocalizer ) {
$this->messageLocalizer = $messageLocalizer;
}
/**
* @param MessageLocalizer $messageLocalizer
*/
public function setMessageLocalizer( MessageLocalizer $messageLocalizer ) : void {
$this->messageLocalizer = $messageLocalizer;
}
/**
* @param string $action
* @return string HTML
*/
public function getActionDisplay( string $action ) : string {
// Give grep a chance to find the usages:
// abusefilter-action-tag, abusefilter-action-throttle, abusefilter-action-warn,
// abusefilter-action-blockautopromote, abusefilter-action-block, abusefilter-action-degroup,
// abusefilter-action-rangeblock, abusefilter-action-disallow
$msg = $this->messageLocalizer->msg( "abusefilter-action-$action" );
return $msg->isDisabled() ? htmlspecialchars( $action ) : $msg->escaped();
}
/**
* @param string $action
* @param string[] $parameters
* @param Language $lang
* @return string
*/
public function formatAction( string $action, array $parameters, Language $lang ) : string {
if ( count( $parameters ) === 0 || ( $action === 'block' && count( $parameters ) !== 3 ) ) {
$displayAction = $this->getActionDisplay( $action );
} elseif ( $action === 'block' ) {
// Needs to be treated separately since the message is more complex
$messages = [
$this->messageLocalizer->msg( 'abusefilter-block-anon' )->escaped() .
$this->messageLocalizer->msg( 'colon-separator' )->escaped() .
$lang->translateBlockExpiry( $parameters[1] ),
$this->messageLocalizer->msg( 'abusefilter-block-user' )->escaped() .
$this->messageLocalizer->msg( 'colon-separator' )->escaped() .
$lang->translateBlockExpiry( $parameters[2] )
];
if ( $parameters[0] === 'blocktalk' ) {
$messages[] = $this->messageLocalizer->msg( 'abusefilter-block-talk' )->escaped();
}
$displayAction = $lang->commaList( $messages );
} elseif ( $action === 'throttle' ) {
array_shift( $parameters );
list( $actions, $time ) = explode( ',', array_shift( $parameters ) );
// Join comma-separated groups in a commaList with a final "and", and convert to messages.
// Messages used here: abusefilter-throttle-ip, abusefilter-throttle-user,
// abusefilter-throttle-site, abusefilter-throttle-creationdate, abusefilter-throttle-editcount
// abusefilter-throttle-range, abusefilter-throttle-page, abusefilter-throttle-none
foreach ( $parameters as &$val ) {
if ( strpos( $val, ',' ) !== false ) {
$subGroups = explode( ',', $val );
foreach ( $subGroups as &$group ) {
$msg = $this->messageLocalizer->msg( "abusefilter-throttle-$group" );
// We previously accepted literally everything in this field, so old entries
// may have weird stuff.
$group = $msg->exists() ? $msg->text() : $group;
}
unset( $group );
$val = $lang->listToText( $subGroups );
} else {
$msg = $this->messageLocalizer->msg( "abusefilter-throttle-$val" );
$val = $msg->exists() ? $msg->text() : $val;
}
}
unset( $val );
$groups = $lang->semicolonList( $parameters );
$displayAction = $this->getActionDisplay( $action ) .
$this->messageLocalizer->msg( 'colon-separator' )->escaped() .
$this->messageLocalizer->msg( 'abusefilter-throttle-details' )
->params( $actions, $time, $groups )->escaped();
} else {
$displayAction = $this->getActionDisplay( $action ) .
$this->messageLocalizer->msg( 'colon-separator' )->escaped() .
$lang->semicolonList( array_map( 'htmlspecialchars', $parameters ) );
}
return $displayAction;
}
/**
* @param string $value
* @param Language $lang
* @return string
*/
public function formatFlags( string $value, Language $lang ) : string {
$flags = array_filter( explode( ',', $value ) );
$flagsDisplay = [];
foreach ( $flags as $flag ) {
$flagsDisplay[] = $this->messageLocalizer->msg( "abusefilter-history-$flag" )->escaped();
}
return $lang->commaList( $flagsDisplay );
}
/**
* Gives either the user-specified name for a group,
* or spits the input back out when the message for the group is disabled
* @param string $group The filter's group (as defined in $wgAbuseFilterValidGroups)
* @return string A name for that filter group, or the input.
*/
public function nameGroup( string $group ) : string {
// Give grep a chance to find the usages: abusefilter-group-default
$msg = $this->messageLocalizer->msg( "abusefilter-group-$group" );
return $msg->isDisabled() ? $group : $msg->escaped();
}
}

View file

@ -5,7 +5,11 @@ namespace MediaWiki\Extension\AbuseFilter\View;
use AbuseFilter;
use Diff;
use DifferenceEngine;
use IContextSource;
use Linker;
use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Linker\LinkRenderer;
use OOUI;
use stdClass;
use TableDiffFormatterFullContext;
@ -31,6 +35,31 @@ class AbuseFilterViewDiff extends AbuseFilterView {
* @var int|null The ID of the filter
*/
private $filter;
/**
* @var SpecsFormatter
*/
private $specsFormatter;
/**
* @param AbuseFilterPermissionManager $afPermManager
* @param SpecsFormatter $specsFormatter
* @param IContextSource $context
* @param LinkRenderer $linkRenderer
* @param string $basePageName
* @param array $params
*/
public function __construct(
AbuseFilterPermissionManager $afPermManager,
SpecsFormatter $specsFormatter,
IContextSource $context,
LinkRenderer $linkRenderer,
string $basePageName,
array $params
) {
parent::__construct( $afPermManager, $context, $linkRenderer, $basePageName, $params );
$this->specsFormatter = $specsFormatter;
$this->specsFormatter->setMessageLocalizer( $this->getContext() );
}
/**
* Shows the page
@ -338,14 +367,14 @@ class AbuseFilterViewDiff extends AbuseFilterView {
) {
$info .= $this->getDiffRow(
'abusefilter-edit-group',
AbuseFilter::nameGroup( $oldVersion['info']['group'] ),
AbuseFilter::nameGroup( $newVersion['info']['group'] )
$this->specsFormatter->nameGroup( $oldVersion['info']['group'] ),
$this->specsFormatter->nameGroup( $newVersion['info']['group'] )
);
}
$info .= $this->getDiffRow(
'abusefilter-edit-flags',
AbuseFilter::formatFlags( $oldVersion['info']['flags'], $this->getLanguage() ),
AbuseFilter::formatFlags( $newVersion['info']['flags'], $this->getLanguage() )
$this->specsFormatter->formatFlags( $oldVersion['info']['flags'], $this->getLanguage() ),
$this->specsFormatter->formatFlags( $newVersion['info']['flags'], $this->getLanguage() )
);
$info .= $this->getDiffRow(
@ -397,7 +426,7 @@ class AbuseFilterViewDiff extends AbuseFilterView {
ksort( $actions );
foreach ( $actions as $action => $parameters ) {
$lines[] = AbuseFilter::formatAction( $action, $parameters, $this->getLanguage() );
$lines[] = $this->specsFormatter->formatAction( $action, $parameters, $this->getLanguage() );
}
return $lines;

View file

@ -2,7 +2,6 @@
namespace MediaWiki\Extension\AbuseFilter\View;
use AbuseFilter;
use BadMethodCallException;
use Html;
use HtmlArmor;
@ -20,6 +19,7 @@ use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use MediaWiki\Extension\AbuseFilter\FilterStore;
use MediaWiki\Extension\AbuseFilter\InvalidImportDataException;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Permissions\PermissionManager;
use MWException;
@ -57,6 +57,9 @@ class AbuseFilterViewEdit extends AbuseFilterView {
/** @var ConsequencesRegistry */
private $consequencesRegistry;
/** @var SpecsFormatter */
private $specsFormatter;
/**
* @param PermissionManager $permissionManager
* @param AbuseFilterPermissionManager $afPermManager
@ -66,6 +69,7 @@ class AbuseFilterViewEdit extends AbuseFilterView {
* @param FilterStore $filterStore
* @param EditBoxBuilderFactory $boxBuilderFactory
* @param ConsequencesRegistry $consequencesRegistry
* @param SpecsFormatter $specsFormatter
* @param IContextSource $context
* @param LinkRenderer $linkRenderer
* @param string $basePageName
@ -80,6 +84,7 @@ class AbuseFilterViewEdit extends AbuseFilterView {
FilterStore $filterStore,
EditBoxBuilderFactory $boxBuilderFactory,
ConsequencesRegistry $consequencesRegistry,
SpecsFormatter $specsFormatter,
IContextSource $context,
LinkRenderer $linkRenderer,
string $basePageName,
@ -93,6 +98,8 @@ class AbuseFilterViewEdit extends AbuseFilterView {
$this->filterStore = $filterStore;
$this->boxBuilderFactory = $boxBuilderFactory;
$this->consequencesRegistry = $consequencesRegistry;
$this->specsFormatter = $specsFormatter;
$this->specsFormatter->setMessageLocalizer( $this->getContext() );
$this->filter = $this->mParams['filter'];
$this->historyID = $this->mParams['history'] ?? null;
}
@ -321,7 +328,7 @@ class AbuseFilterViewEdit extends AbuseFilterView {
$options = [];
foreach ( $validGroups as $group ) {
$options += [ AbuseFilter::nameGroup( $group ) => $group ];
$options += [ $this->specsFormatter->nameGroup( $group ) => $group ];
}
$options = Xml::listDropDownOptionsOoui( $options );

View file

@ -2,7 +2,6 @@
namespace MediaWiki\Extension\AbuseFilter\View;
use AbuseFilter;
use HTMLForm;
use IContextSource;
use Linker;
@ -11,6 +10,7 @@ use MediaWiki\Block\DatabaseBlock;
use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager;
use MediaWiki\Extension\AbuseFilter\BlockAutopromoteStore;
use MediaWiki\Extension\AbuseFilter\FilterUser;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Extension\AbuseFilter\VariablesBlobStore;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\User\UserGroupManager;
@ -63,12 +63,18 @@ class AbuseFilterViewRevert extends AbuseFilterView {
*/
private $varBlobStore;
/**
* @var SpecsFormatter
*/
private $specsFormatter;
/**
* @param UserGroupManager $userGroupManager
* @param AbuseFilterPermissionManager $afPermManager
* @param BlockAutopromoteStore $blockAutopromoteStore
* @param FilterUser $filterUser
* @param VariablesBlobStore $varBlobStore
* @param SpecsFormatter $specsFormatter
* @param IContextSource $context
* @param LinkRenderer $linkRenderer
* @param string $basePageName
@ -80,6 +86,7 @@ class AbuseFilterViewRevert extends AbuseFilterView {
BlockAutopromoteStore $blockAutopromoteStore,
FilterUser $filterUser,
VariablesBlobStore $varBlobStore,
SpecsFormatter $specsFormatter,
IContextSource $context,
LinkRenderer $linkRenderer,
string $basePageName,
@ -90,6 +97,8 @@ class AbuseFilterViewRevert extends AbuseFilterView {
$this->blockAutopromoteStore = $blockAutopromoteStore;
$this->filterUser = $filterUser;
$this->varBlobStore = $varBlobStore;
$this->specsFormatter = $specsFormatter;
$this->specsFormatter->setMessageLocalizer( $this->getContext() );
}
/**
@ -186,11 +195,10 @@ class AbuseFilterViewRevert extends AbuseFilterView {
$dateForm->addPostText( $this->msg( 'abusefilter-revert-preview-intro' )->parseAsBlock() );
$list = [];
$context = $this->getContext();
foreach ( $results as $result ) {
$displayActions = [];
foreach ( $result['actions'] as $action ) {
$displayActions[] = AbuseFilter::getActionDisplay( $action, $context );
$displayActions[] = $this->specsFormatter->getActionDisplay( $action );
}
$msg = $this->msg( 'abusefilter-revert-preview-item' )

View file

@ -10,6 +10,7 @@ use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use MediaWiki\Extension\AbuseFilter\FilterStore;
use MediaWiki\Extension\AbuseFilter\FilterUser;
use MediaWiki\Extension\AbuseFilter\Parser\ParserFactory as AfParserFactory;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Extension\AbuseFilter\VariablesBlobStore;
use MediaWiki\Extension\AbuseFilter\View\AbuseFilterView;
use MediaWiki\Extension\AbuseFilter\View\AbuseFilterViewDiff;
@ -35,6 +36,7 @@ class SpecialAbuseFilter extends AbuseFilterSpecialPage {
private const SERVICES_PER_VIEW = [
AbuseFilterViewDiff::class => [
AbuseFilterPermissionManager::SERVICE_NAME,
SpecsFormatter::SERVICE_NAME,
],
AbuseFilterViewEdit::class => [
'PermissionManager',
@ -45,6 +47,7 @@ class SpecialAbuseFilter extends AbuseFilterSpecialPage {
FilterStore::SERVICE_NAME,
EditBoxBuilderFactory::SERVICE_NAME,
ConsequencesRegistry::SERVICE_NAME,
SpecsFormatter::SERVICE_NAME,
],
AbuseFilterViewExamine::class => [
'RevisionLookup',
@ -70,6 +73,7 @@ class SpecialAbuseFilter extends AbuseFilterSpecialPage {
BlockAutopromoteStore::SERVICE_NAME,
FilterUser::SERVICE_NAME,
VariablesBlobStore::SERVICE_NAME,
SpecsFormatter::SERVICE_NAME,
],
AbuseFilterViewTestBatch::class => [
AbuseFilterPermissionManager::SERVICE_NAME,

View file

@ -6,6 +6,7 @@ use MediaWiki\Extension\AbuseFilter\AbuseFilterServices;
use MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesRegistry;
use MediaWiki\Extension\AbuseFilter\GlobalNameUtils;
use MediaWiki\Extension\AbuseFilter\Pager\AbuseLogPager;
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use MediaWiki\Extension\AbuseFilter\VariablesBlobStore;
use MediaWiki\Extension\AbuseFilter\View\HideAbuseLog;
use MediaWiki\Logger\LoggerFactory;
@ -82,19 +83,24 @@ class SpecialAbuseLog extends AbuseFilterSpecialPage {
/** @var VariablesBlobStore */
private $varBlobStore;
/** @var SpecsFormatter */
private $specsFormatter;
/**
* @param LinkBatchFactory $linkBatchFactory
* @param PermissionManager $permissionManager
* @param AbuseFilterPermissionManager $afPermissionManager
* @param ConsequencesRegistry $consequencesRegistry
* @param VariablesBlobStore $varBlobStore
* @param SpecsFormatter $specsFormatter
*/
public function __construct(
LinkBatchFactory $linkBatchFactory,
PermissionManager $permissionManager,
AbuseFilterPermissionManager $afPermissionManager,
ConsequencesRegistry $consequencesRegistry,
VariablesBlobStore $varBlobStore
VariablesBlobStore $varBlobStore,
SpecsFormatter $specsFormatter
) {
parent::__construct( 'AbuseLog', 'abusefilter-log' );
$this->linkBatchFactory = $linkBatchFactory;
@ -102,6 +108,8 @@ class SpecialAbuseLog extends AbuseFilterSpecialPage {
$this->afPermissionManager = $afPermissionManager;
$this->consequencesRegistry = $consequencesRegistry;
$this->varBlobStore = $varBlobStore;
$this->specsFormatter = $specsFormatter;
$this->specsFormatter->setMessageLocalizer( $this->getContext() );
}
/**
@ -274,9 +282,8 @@ class SpecialAbuseLog extends AbuseFilterSpecialPage {
'default' => 'any',
];
$options = [];
$context = $this->getContext();
foreach ( $this->consequencesRegistry->getAllActionNames() as $action ) {
$key = AbuseFilter::getActionDisplay( $action, $context );
$key = $this->specsFormatter->getActionDisplay( $action );
$options[$key] = $action;
}
ksort( $options );

View file

@ -0,0 +1,176 @@
<?php
use MediaWiki\Extension\AbuseFilter\SpecsFormatter;
use Wikimedia\TestingAccessWrapper;
/**
* @coversDefaultClass \MediaWiki\Extension\AbuseFilter\SpecsFormatter
*/
class AbuseFilterSpecsFormatterTest extends MediaWikiUnitTestCase {
/**
* @param bool $msgDisabled Should the message be disabled?
* @return SpecsFormatter
*/
private function getFormatter( bool $msgDisabled = false ) : SpecsFormatter {
$localizer = $this->createMock( MessageLocalizer::class );
$localizer->method( 'msg' )->willReturnCallback( function ( $k, $p = [] ) use ( $msgDisabled ) {
if ( $k === 'abusefilter-throttle-details' ) {
// Special case
$msg = $this->createMock( Message::class );
$msg->method( 'params' )->willReturnCallback( function ( ...$p ) use ( $k ) {
$text = implode( '|', array_merge( [ $k ], $p ) );
return $this->getMockMessage( $text, [] );
} );
return $msg;
}
$msg = $this->getMockMessage( $k, $p );
$msg->method( 'isDisabled' )->willReturn( $msgDisabled );
return $msg;
} );
return new SpecsFormatter( $localizer );
}
/**
* @covers ::__construct
*/
public function testConstruct() {
$this->assertInstanceOf(
SpecsFormatter::class,
new SpecsFormatter( $this->createMock( MessageLocalizer::class ) )
);
}
/**
* @covers ::setMessageLocalizer
*/
public function testSetMessageLocalizer() {
$formatter = $this->getFormatter();
$ml = $this->createMock( MessageLocalizer::class );
$formatter->setMessageLocalizer( $ml );
$this->assertSame( $ml, TestingAccessWrapper::newFromObject( $formatter )->messageLocalizer );
}
/**
* @param string $action
* @param bool $msgDisabled
* @param string $expected
* @dataProvider provideActionDisplay
* @covers ::getActionDisplay
*/
public function testGetActionDisplay( string $action, bool $msgDisabled, string $expected ) {
$formatter = $this->getFormatter( $msgDisabled );
$this->assertSame( $expected, $formatter->getActionDisplay( $action ) );
}
/**
* @return array[]
*/
public function provideActionDisplay() : array {
return [
'exists' => [ 'foobar', false, 'abusefilter-action-foobar' ],
'does not exist' => [ 'foobar', true, 'foobar' ],
];
}
/**
* @return Language
*/
private function getMockLanguage() : Language {
$lang = $this->createMock( Language::class );
$lang->method( 'translateBlockExpiry' )->willReturnCallback( function ( $x ) {
return "expiry-$x";
} );
$lang->method( 'commaList' )->willReturnCallback( function ( $x ) {
return implode( ',', $x );
} );
$lang->method( 'listToText' )->willReturnCallback( function ( $x ) {
return implode( ',', $x );
} );
$lang->method( 'semicolonList' )->willReturnCallback( function ( $x ) {
return implode( ';', $x );
} );
return $lang;
}
/**
* @param string $action
* @param array $params
* @param string $expected
* @dataProvider provideFormatAction
* @covers ::formatAction
*/
public function testFormatAction( string $action, array $params, string $expected ) {
$formatter = $this->getFormatter();
$lang = $this->getMockLanguage();
$this->assertSame( $expected, $formatter->formatAction( $action, $params, $lang ) );
}
public function provideFormatAction() {
yield 'no params' => [ 'foobar', [], 'abusefilter-action-foobar' ];
yield 'legacy block' => [ 'block', [], 'abusefilter-action-block' ];
$colon = 'colon-separator';
$baseBlock = "abusefilter-block-anon{$colon}expiry-1 day,abusefilter-block-user{$colon}expiry-1 week";
yield 'new block, no talk' => [ 'block', [ 'noTalkBlockSet', '1 day', '1 week' ], $baseBlock ];
yield 'new block, with talk' => [
'block',
[ 'blocktalk', '1 day', '1 week' ],
"$baseBlock,abusefilter-block-talk"
];
yield 'throttle' => [
'throttle',
[ 'ignored', '42,163', 'ip,user', 'site' ],
"abusefilter-action-throttle{$colon}abusefilter-throttle-details|42|163|" .
'abusefilter-throttle-ip,abusefilter-throttle-user;abusefilter-throttle-site'
];
yield 'generic parametrized' => [ 'myaction', [ 'foo', 'bar' ], "abusefilter-action-myaction{$colon}foo;bar" ];
}
/**
* @param string $flags
* @param string $expected
* @dataProvider provideFlags
* @covers ::formatFlags
*/
public function testFormatFlags( string $flags, string $expected ) {
$formatter = $this->getFormatter();
$lang = $this->createMock( Language::class );
$lang->method( 'commaList' )->willReturnCallback( function ( $x ) {
return implode( ',', $x );
} );
$this->assertSame( $expected, $formatter->formatFlags( $flags, $lang ) );
}
/**
* @return array
*/
public function provideFlags() : array {
return [
'empty' => [ '', '' ],
'single' => [ 'foo', 'abusefilter-history-foo' ],
'multiple' => [ 'foo,bar,baz', 'abusefilter-history-foo,abusefilter-history-bar,abusefilter-history-baz' ]
];
}
/**
* @param string $group
* @param bool $msgDisabled
* @param string $expected
* @dataProvider provideGroup
* @covers ::nameGroup
*/
public function testNameGroup( string $group, bool $msgDisabled, string $expected ) {
$formatter = $this->getFormatter( $msgDisabled );
$this->assertSame( $expected, $formatter->nameGroup( $group ) );
}
/**
* @return array[]
*/
public function provideGroup() : array {
return [
'exists' => [ 'foobar', false, 'abusefilter-group-foobar' ],
'does not exist' => [ 'foobar', true, 'foobar' ],
];
}
}