Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
21.37% |
25 / 117 |
|
33.33% |
1 / 3 |
CRAP | |
0.00% |
0 / 1 |
| HideAbuseLog | |
21.37% |
25 / 117 |
|
33.33% |
1 / 3 |
109.29 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| show | |
32.86% |
23 / 70 |
|
0.00% |
0 / 1 |
16.90 | |||
| saveHideForm | |
0.00% |
0 / 45 |
|
0.00% |
0 / 1 |
56 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace MediaWiki\Extension\AbuseFilter\View; |
| 4 | |
| 5 | use MediaWiki\Cache\LinkBatchFactory; |
| 6 | use MediaWiki\Context\IContextSource; |
| 7 | use MediaWiki\Deferred\DeferredUpdates; |
| 8 | use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager; |
| 9 | use MediaWiki\Extension\AbuseFilter\Pager\AbuseLogPager; |
| 10 | use MediaWiki\Extension\AbuseFilter\Variables\VariablesBlobStore; |
| 11 | use MediaWiki\Html\Html; |
| 12 | use MediaWiki\HTMLForm\HTMLForm; |
| 13 | use MediaWiki\Linker\LinkRenderer; |
| 14 | use MediaWiki\Logging\LogEventsList; |
| 15 | use MediaWiki\Logging\LogPage; |
| 16 | use MediaWiki\Logging\ManualLogEntry; |
| 17 | use MediaWiki\Permissions\PermissionManager; |
| 18 | use Wikimedia\Rdbms\LBFactory; |
| 19 | |
| 20 | class HideAbuseLog extends AbuseFilterView { |
| 21 | |
| 22 | /** @var int[] */ |
| 23 | private $hideIDs; |
| 24 | |
| 25 | public function __construct( |
| 26 | private readonly LBFactory $lbFactory, |
| 27 | AbuseFilterPermissionManager $afPermManager, |
| 28 | IContextSource $context, |
| 29 | LinkRenderer $linkRenderer, |
| 30 | private readonly LinkBatchFactory $linkBatchFactory, |
| 31 | private readonly PermissionManager $permissionManager, |
| 32 | private readonly VariablesBlobStore $variablesBlobStore, |
| 33 | string $basePageName |
| 34 | ) { |
| 35 | parent::__construct( $afPermManager, $context, $linkRenderer, $basePageName, [] ); |
| 36 | |
| 37 | $this->hideIDs = array_keys( $this->getRequest()->getArray( 'hideids', [] ) ); |
| 38 | } |
| 39 | |
| 40 | /** |
| 41 | * Shows the page |
| 42 | */ |
| 43 | public function show(): void { |
| 44 | $output = $this->getOutput(); |
| 45 | $output->enableOOUI(); |
| 46 | |
| 47 | if ( !$this->afPermManager->canHideAbuseLog( $this->getAuthority() ) ) { |
| 48 | $output->addWikiMsg( 'abusefilter-log-hide-forbidden' ); |
| 49 | return; |
| 50 | } |
| 51 | |
| 52 | if ( !$this->hideIDs ) { |
| 53 | $output->addWikiMsg( 'abusefilter-log-hide-no-selected' ); |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | $pager = new AbuseLogPager( |
| 58 | $this->getContext(), |
| 59 | $this->linkRenderer, |
| 60 | [ 'afl_id' => $this->hideIDs ], |
| 61 | $this->linkBatchFactory, |
| 62 | $this->permissionManager, |
| 63 | $this->afPermManager, |
| 64 | $this->variablesBlobStore, |
| 65 | $this->basePageName, |
| 66 | array_fill_keys( $this->hideIDs, $this->getRequest()->getVal( 'wpshoworhide' ) ) |
| 67 | ); |
| 68 | $pager->doQuery(); |
| 69 | if ( $pager->getResult()->numRows() === 0 ) { |
| 70 | $output->addWikiMsg( 'abusefilter-log-hide-no-selected' ); |
| 71 | return; |
| 72 | } |
| 73 | |
| 74 | $output->addModuleStyles( 'mediawiki.interface.helpers.styles' ); |
| 75 | $output->wrapWikiMsg( |
| 76 | "<strong>$1</strong>", |
| 77 | [ |
| 78 | 'abusefilter-log-hide-selected', |
| 79 | $this->getLanguage()->formatNum( count( $this->hideIDs ) ) |
| 80 | ] |
| 81 | ); |
| 82 | $output->addHTML( Html::rawElement( 'ul', [ 'class' => 'plainlinks' ], $pager->getBody() ) ); |
| 83 | |
| 84 | $hideReasonsOther = $this->msg( 'revdelete-reasonotherlist' )->text(); |
| 85 | $hideReasons = $this->msg( 'revdelete-reason-dropdown-suppress' )->inContentLanguage()->text(); |
| 86 | $hideReasons = Html::listDropdownOptions( $hideReasons, [ 'other' => $hideReasonsOther ] ); |
| 87 | |
| 88 | $formInfo = [ |
| 89 | 'showorhide' => [ |
| 90 | 'type' => 'radio', |
| 91 | 'label-message' => 'abusefilter-log-hide-set-visibility', |
| 92 | 'options-messages' => [ |
| 93 | 'abusefilter-log-hide-show' => 'show', |
| 94 | 'abusefilter-log-hide-hide' => 'hide' |
| 95 | ], |
| 96 | 'default' => 'hide', |
| 97 | 'flatlist' => true |
| 98 | ], |
| 99 | 'dropdownreason' => [ |
| 100 | 'type' => 'select', |
| 101 | 'options' => $hideReasons, |
| 102 | 'label-message' => 'abusefilter-log-hide-reason' |
| 103 | ], |
| 104 | 'reason' => [ |
| 105 | 'type' => 'text', |
| 106 | 'label-message' => 'abusefilter-log-hide-reason-other', |
| 107 | ], |
| 108 | ]; |
| 109 | |
| 110 | $actionURL = $this->getTitle( 'hide' )->getLocalURL( [ 'hideids' => array_fill_keys( $this->hideIDs, 1 ) ] ); |
| 111 | HTMLForm::factory( 'ooui', $formInfo, $this->getContext() ) |
| 112 | ->setAction( $actionURL ) |
| 113 | ->setWrapperLegend( $this->msg( 'abusefilter-log-hide-legend' )->text() ) |
| 114 | ->setSubmitCallback( [ $this, 'saveHideForm' ] ) |
| 115 | ->showAlways(); |
| 116 | |
| 117 | // Show suppress log for this entry. Hack: since every suppression is performed on a |
| 118 | // totally different page (i.e. Special:AbuseLog/xxx), we use showLogExtract without |
| 119 | // specifying a title and then adding it in conds. |
| 120 | // This isn't shown if the request was posted because we update visibility in a DeferredUpdate, so it would |
| 121 | // display outdated info that might confuse the user. |
| 122 | // TODO Can we improve this somehow? |
| 123 | if ( !$this->getRequest()->wasPosted() ) { |
| 124 | $suppressLogPage = new LogPage( 'suppress' ); |
| 125 | $output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" ); |
| 126 | $searchTitles = []; |
| 127 | foreach ( $this->hideIDs as $id ) { |
| 128 | $searchTitles[] = $this->getTitle( (string)$id )->getDBkey(); |
| 129 | } |
| 130 | $conds = [ 'log_namespace' => NS_SPECIAL, 'log_title' => $searchTitles ]; |
| 131 | LogEventsList::showLogExtract( $output, 'suppress', '', '', [ 'conds' => $conds ] ); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * Process the hide form after submission. This performs the actual visibility update. Used as callback by HTMLForm |
| 137 | * |
| 138 | * @param array $fields |
| 139 | * @return bool|array True on success, array of error message keys otherwise |
| 140 | */ |
| 141 | public function saveHideForm( array $fields ) { |
| 142 | // Determine which rows actually have to be changed |
| 143 | $dbw = $this->lbFactory->getPrimaryDatabase(); |
| 144 | $newValue = $fields['showorhide'] === 'hide' ? 1 : 0; |
| 145 | $actualIDs = $dbw->newSelectQueryBuilder() |
| 146 | ->select( 'afl_id' ) |
| 147 | ->from( 'abuse_filter_log' ) |
| 148 | ->where( [ |
| 149 | 'afl_id' => $this->hideIDs, |
| 150 | $dbw->expr( 'afl_deleted', '!=', $newValue ), |
| 151 | ] ) |
| 152 | ->caller( __METHOD__ ) |
| 153 | ->fetchFieldValues(); |
| 154 | if ( !count( $actualIDs ) ) { |
| 155 | return [ 'abusefilter-log-hide-no-change' ]; |
| 156 | } |
| 157 | |
| 158 | $dbw->newUpdateQueryBuilder() |
| 159 | ->update( 'abuse_filter_log' ) |
| 160 | ->set( [ 'afl_deleted' => $newValue ] ) |
| 161 | ->where( [ 'afl_id' => $actualIDs ] ) |
| 162 | ->caller( __METHOD__ ) |
| 163 | ->execute(); |
| 164 | |
| 165 | // Log in a DeferredUpdates to avoid potential flood |
| 166 | DeferredUpdates::addCallableUpdate( function () use ( $fields, $actualIDs ) { |
| 167 | $reason = $fields['dropdownreason']; |
| 168 | if ( $reason === 'other' ) { |
| 169 | $reason = $fields['reason']; |
| 170 | } elseif ( $fields['reason'] !== '' ) { |
| 171 | $reason .= |
| 172 | $this->msg( 'colon-separator' )->inContentLanguage()->text() . $fields['reason']; |
| 173 | } |
| 174 | |
| 175 | $action = $fields['showorhide'] === 'hide' ? 'hide-afl' : 'unhide-afl'; |
| 176 | foreach ( $actualIDs as $logid ) { |
| 177 | $logEntry = new ManualLogEntry( 'suppress', $action ); |
| 178 | $logEntry->setPerformer( $this->getUser() ); |
| 179 | $logEntry->setTarget( $this->getTitle( $logid ) ); |
| 180 | $logEntry->setComment( $reason ); |
| 181 | $logEntry->insert(); |
| 182 | } |
| 183 | } ); |
| 184 | |
| 185 | $count = count( $actualIDs ); |
| 186 | $this->getOutput()->addModuleStyles( 'mediawiki.codex.messagebox.styles' ); |
| 187 | $this->getOutput()->prependHTML( |
| 188 | Html::successBox( |
| 189 | $this->msg( 'abusefilter-log-hide-done' )->params( |
| 190 | $this->getLanguage()->formatNum( $count ), |
| 191 | // Messages used: abusefilter-log-hide-done-hide, abusefilter-log-hide-done-show |
| 192 | $this->msg( 'abusefilter-log-hide-done-' . $fields['showorhide'] )->numParams( $count )->text() |
| 193 | )->escaped() |
| 194 | ) |
| 195 | ); |
| 196 | |
| 197 | return true; |
| 198 | } |
| 199 | |
| 200 | } |