summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php')
-rw-r--r--www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php267
1 files changed, 267 insertions, 0 deletions
diff --git a/www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php b/www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php
new file mode 100644
index 00000000..715fa536
--- /dev/null
+++ b/www/wiki/extensions/AbuseFilter/includes/Views/AbuseFilterViewList.php
@@ -0,0 +1,267 @@
+<?php
+
+/**
+ * The default view used in Special:AbuseFilter
+ */
+class AbuseFilterViewList extends AbuseFilterView {
+ function show() {
+ global $wgAbuseFilterCentralDB, $wgAbuseFilterIsCentral;
+
+ $out = $this->getOutput();
+ $request = $this->getRequest();
+
+ // Status info...
+ $this->showStatus();
+
+ $out->addWikiMsg( 'abusefilter-intro' );
+
+ // New filter button
+ if ( $this->canEdit() ) {
+ $out->enableOOUI();
+ $link = new OOUI\ButtonWidget( [
+ 'label' => $this->msg( 'abusefilter-new' )->text(),
+ 'href' => $this->getTitle( 'new' )->getFullURL(),
+ ] );
+ $out->addHTML( $link );
+ }
+
+ // Options.
+ $conds = [];
+ $deleted = $request->getVal( 'deletedfilters' );
+ $hidedisabled = $request->getBool( 'hidedisabled' );
+ $defaultscope = 'all';
+ if ( isset( $wgAbuseFilterCentralDB ) && !$wgAbuseFilterIsCentral ) {
+ // Show on remote wikis as default only local filters
+ $defaultscope = 'local';
+ }
+ $scope = $request->getVal( 'rulescope', $defaultscope );
+
+ $searchEnabled = $this->canViewPrivate() && !( isset( $wgAbuseFilterCentralDB ) &&
+ !$wgAbuseFilterIsCentral && $scope == 'global' );
+
+ if ( $searchEnabled ) {
+ $querypattern = $request->getVal( 'querypattern' );
+ $searchmode = $request->getVal( 'searchoption', 'LIKE' );
+ } else {
+ $querypattern = '';
+ $searchmode = '';
+ }
+
+ if ( $deleted == 'show' ) {
+ # Nothing
+ } elseif ( $deleted == 'only' ) {
+ $conds['af_deleted'] = 1;
+ } else { # hide, or anything else.
+ $conds['af_deleted'] = 0;
+ $deleted = 'hide';
+ }
+ if ( $hidedisabled ) {
+ $conds['af_deleted'] = 0;
+ $conds['af_enabled'] = 1;
+ }
+
+ if ( $scope == 'local' ) {
+ $conds['af_global'] = 0;
+ } elseif ( $scope == 'global' ) {
+ $conds['af_global'] = 1;
+ }
+
+ $dbr = wfGetDB( DB_REPLICA );
+
+ if ( $querypattern !== '' ) {
+ if ( $searchmode !== 'LIKE' ) {
+ // Check regex pattern validity
+ Wikimedia\suppressWarnings();
+ $validreg = preg_match( '/' . $querypattern . '/', null );
+ Wikimedia\restoreWarnings();
+
+ if ( $validreg === false ) {
+ $out->wrapWikiMsg(
+ '<div class="errorbox">$1</div>',
+ 'abusefilter-list-regexerror'
+ );
+ $this->showList(
+ [ 'af_deleted' => 0 ],
+ compact( 'deleted', 'hidedisabled', 'querypattern', 'searchmode', 'scope', 'searchEnabled' )
+ );
+ return;
+ }
+ if ( $searchmode === 'RLIKE' ) {
+ $conds[] = 'af_pattern RLIKE ' .
+ $dbr->addQuotes( $querypattern );
+ } else {
+ $conds[] = 'LOWER( CAST( af_pattern AS char ) ) RLIKE ' .
+ strtolower( $dbr->addQuotes( $querypattern ) );
+ }
+ } else {
+ // Build like query escaping tokens and encapsulating in % to search everywhere
+ $conds[] = 'LOWER( CAST( af_pattern AS char ) ) ' .
+ $dbr->buildLike(
+ $dbr->anyString(),
+ strtolower( $querypattern ),
+ $dbr->anyString()
+ );
+ }
+ }
+
+ $this->showList(
+ $conds,
+ compact( 'deleted', 'hidedisabled', 'querypattern', 'searchmode', 'scope', 'searchEnabled' )
+ );
+ }
+
+ function showList( $conds = [ 'af_deleted' => 0 ], $optarray = [] ) {
+ global $wgAbuseFilterCentralDB, $wgAbuseFilterIsCentral;
+
+ $this->getOutput()->addHTML(
+ Xml::element( 'h2', null, $this->msg( 'abusefilter-list' )->parse() )
+ );
+
+ $deleted = $optarray['deleted'];
+ $hidedisabled = $optarray['hidedisabled'];
+ $scope = $optarray['scope'];
+ $searchEnabled = $optarray['searchEnabled'];
+ $querypattern = $optarray['querypattern'];
+ $searchmode = $optarray['searchmode'];
+
+ if ( isset( $wgAbuseFilterCentralDB ) && !$wgAbuseFilterIsCentral && $scope == 'global' ) {
+ $pager = new GlobalAbuseFilterPager(
+ $this,
+ $conds,
+ $this->linkRenderer
+ );
+ } else {
+ $pager = new AbuseFilterPager(
+ $this,
+ $conds,
+ $this->linkRenderer,
+ [ $querypattern, $searchmode ]
+ );
+ }
+
+ # Options form
+ $formDescriptor = [];
+ $formDescriptor['deletedfilters'] = [
+ 'name' => 'deletedfilters',
+ 'type' => 'radio',
+ 'flatlist' => true,
+ 'label-message' => 'abusefilter-list-options-deleted',
+ 'options-messages' => [
+ 'abusefilter-list-options-deleted-show' => 'show',
+ 'abusefilter-list-options-deleted-hide' => 'hide',
+ 'abusefilter-list-options-deleted-only' => 'only',
+ ],
+ 'default' => $deleted,
+ ];
+
+ if ( isset( $wgAbuseFilterCentralDB ) ) {
+ $optionsMsg = [
+ 'abusefilter-list-options-scope-local' => 'local',
+ 'abusefilter-list-options-scope-global' => 'global',
+ ];
+ if ( $wgAbuseFilterIsCentral ) {
+ // For central wiki: add third scope option
+ $optionsMsg['abusefilter-list-options-scope-all'] = 'all';
+ }
+ $formDescriptor['rulescope'] = [
+ 'name' => 'rulescope',
+ 'type' => 'radio',
+ 'flatlist' => true,
+ 'label-message' => 'abusefilter-list-options-scope',
+ 'options-messages' => $optionsMsg,
+ 'default' => $scope,
+ ];
+ }
+
+ $formDescriptor['info'] = [
+ 'type' => 'info',
+ 'default' => $this->msg( 'abusefilter-list-options-disabled' )->parse(),
+ ];
+
+ $formDescriptor['hidedisabled'] = [
+ 'name' => 'hidedisabled',
+ 'type' => 'check',
+ 'label-message' => 'abusefilter-list-options-hidedisabled',
+ 'selected' => $hidedisabled,
+ ];
+
+ // ToDo: Since this is only for saving space, we should convert it
+ // to use a 'hide-if'
+ if ( $searchEnabled ) {
+ $formDescriptor['querypattern'] = [
+ 'name' => 'querypattern',
+ 'type' => 'text',
+ 'label-message' => 'abusefilter-list-options-searchfield',
+ 'placeholder' => $this->msg( 'abusefilter-list-options-searchpattern' )->text(),
+ 'default' => $querypattern
+ ];
+
+ $formDescriptor['searchoption'] = [
+ 'name' => 'searchoption',
+ 'type' => 'radio',
+ 'flatlist' => true,
+ 'label-message' => 'abusefilter-list-options-searchoptions',
+ 'options-messages' => [
+ 'abusefilter-list-options-search-like' => 'LIKE',
+ 'abusefilter-list-options-search-rlike' => 'RLIKE',
+ 'abusefilter-list-options-search-irlike' => 'IRLIKE',
+ ],
+ 'default' => $searchmode
+ ];
+ }
+
+ $formDescriptor['limit'] = [
+ 'name' => 'limit',
+ 'type' => 'select',
+ 'label-message' => 'abusefilter-list-limit',
+ 'options' => $pager->getLimitSelectList(),
+ 'default' => $pager->getLimit(),
+ ];
+
+ HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->addHiddenField( 'title', $this->getTitle()->getPrefixedDBkey() )
+ ->setAction( $this->getTitle()->getFullURL() )
+ ->setWrapperLegendMsg( 'abusefilter-list-options' )
+ ->setSubmitTextMsg( 'abusefilter-list-options-submit' )
+ ->setMethod( 'get' )
+ ->prepareForm()
+ ->displayForm( false );
+
+ $output =
+ $pager->getNavigationBar() .
+ $pager->getBody() .
+ $pager->getNavigationBar();
+
+ $this->getOutput()->addHTML( $output );
+ }
+
+ function showStatus() {
+ global $wgAbuseFilterConditionLimit, $wgAbuseFilterValidGroups;
+
+ $stash = ObjectCache::getMainStashInstance();
+ $overflow_count = (int)$stash->get( AbuseFilter::filterLimitReachedKey() );
+ $match_count = (int)$stash->get( AbuseFilter::filterMatchesKey() );
+ $total_count = 0;
+ foreach ( $wgAbuseFilterValidGroups as $group ) {
+ $total_count += (int)$stash->get( AbuseFilter::filterUsedKey( $group ) );
+ }
+
+ if ( $total_count > 0 ) {
+ $overflow_percent = sprintf( "%.2f", 100 * $overflow_count / $total_count );
+ $match_percent = sprintf( "%.2f", 100 * $match_count / $total_count );
+
+ $status = $this->msg( 'abusefilter-status' )
+ ->numParams(
+ $total_count,
+ $overflow_count,
+ $overflow_percent,
+ $wgAbuseFilterConditionLimit,
+ $match_count,
+ $match_percent
+ )->parse();
+
+ $status = Xml::tags( 'div', [ 'class' => 'mw-abusefilter-status' ], $status );
+ $this->getOutput()->addHTML( $status );
+ }
+ }
+}