mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-12-01 00:56:26 +00:00
0815fc6a8f
We still had three entries of "LogPage", which is legacy and has some problems (I7bb0e92b2906a2511fc4290bdc76fc39ec4617fe). This patch updates two of them to ManualLogEntry. The last one is handled separately in Ic23e724997e4748c8d0da8138aa73d31b17b7064. Change-Id: I2a4f18ea6baebdc114078c57d8937ce4ca2aace5
322 lines
9.1 KiB
PHP
322 lines
9.1 KiB
PHP
<?php
|
|
|
|
class AbuseFilterViewRevert extends AbuseFilterView {
|
|
public $origPeriodStart, $origPeriodEnd, $mPeriodStart, $mPeriodEnd;
|
|
public $mReason;
|
|
|
|
/**
|
|
* Shows the page
|
|
*/
|
|
public function show() {
|
|
$lang = $this->getLanguage();
|
|
$filter = $this->mPage->mFilter;
|
|
|
|
$user = $this->getUser();
|
|
$out = $this->getOutput();
|
|
|
|
if ( !$user->isAllowed( 'abusefilter-revert' ) ) {
|
|
throw new PermissionsError( 'abusefilter-revert' );
|
|
}
|
|
|
|
$this->loadParameters();
|
|
|
|
if ( $this->attemptRevert() ) {
|
|
return;
|
|
}
|
|
|
|
$out->addWikiMsg( 'abusefilter-revert-intro', Message::numParam( $filter ) );
|
|
$out->setPageTitle( $this->msg( 'abusefilter-revert-title' )->numParams( $filter ) );
|
|
|
|
// First, the search form. Limit dates to avoid huge queries
|
|
$RCMaxAge = $this->getConfig()->get( 'RCMaxAge' );
|
|
$min = wfTimestamp( TS_ISO_8601, time() - $RCMaxAge );
|
|
$max = wfTimestampNow();
|
|
$filterLink =
|
|
$this->linkRenderer->makeLink(
|
|
SpecialPage::getTitleFor( 'AbuseFilter', intval( $filter ) ),
|
|
$lang->formatNum( intval( $filter ) )
|
|
);
|
|
$searchFields = [];
|
|
$searchFields['filterid'] = [
|
|
'type' => 'info',
|
|
'default' => $filterLink,
|
|
'raw' => true,
|
|
'label-message' => 'abusefilter-revert-filter'
|
|
];
|
|
$searchFields['periodstart'] = [
|
|
'type' => 'datetime',
|
|
'name' => 'wpPeriodStart',
|
|
'default' => $this->origPeriodStart,
|
|
'label-message' => 'abusefilter-revert-periodstart',
|
|
'min' => $min,
|
|
'max' => $max
|
|
];
|
|
$searchFields['periodend'] = [
|
|
'type' => 'datetime',
|
|
'name' => 'wpPeriodEnd',
|
|
'default' => $this->origPeriodEnd,
|
|
'label-message' => 'abusefilter-revert-periodend',
|
|
'min' => $min,
|
|
'max' => $max
|
|
];
|
|
|
|
HTMLForm::factory( 'ooui', $searchFields, $this->getContext() )
|
|
->addHiddenField( 'submit', 1 )
|
|
->setAction( $this->getTitle( "revert/$filter" )->getLocalURL() )
|
|
->setWrapperLegendMsg( 'abusefilter-revert-search-legend' )
|
|
->setSubmitTextMsg( 'abusefilter-revert-search' )
|
|
->setMethod( 'post' )
|
|
->prepareForm()
|
|
->displayForm( false );
|
|
|
|
if ( $this->mSubmit ) {
|
|
// Add a summary of everything that will be reversed.
|
|
$out->addWikiMsg( 'abusefilter-revert-preview-intro' );
|
|
|
|
// Look up all of them.
|
|
$results = $this->doLookup();
|
|
$list = [];
|
|
|
|
foreach ( $results as $result ) {
|
|
$displayActions = array_map(
|
|
[ 'AbuseFilter', 'getActionDisplay' ],
|
|
$result['actions'] );
|
|
|
|
$msg = $this->msg( 'abusefilter-revert-preview-item' )
|
|
->params(
|
|
$lang->timeanddate( $result['timestamp'], true )
|
|
)->rawParams(
|
|
Linker::userLink( $result['userid'], $result['user'] )
|
|
)->params(
|
|
$result['action']
|
|
)->rawParams(
|
|
$this->linkRenderer->makeLink( $result['title'] )
|
|
)->params(
|
|
$lang->commaList( $displayActions )
|
|
)->rawParams(
|
|
$this->linkRenderer->makeLink(
|
|
SpecialPage::getTitleFor( 'AbuseLog' ),
|
|
$this->msg( 'abusefilter-log-detailslink' )->text(),
|
|
[],
|
|
[ 'details' => $result['id'] ]
|
|
)
|
|
)->params( $result['user'] )->parse();
|
|
$list[] = Xml::tags( 'li', null, $msg );
|
|
}
|
|
|
|
$out->addHTML( Xml::tags( 'ul', null, implode( "\n", $list ) ) );
|
|
|
|
// Add a button down the bottom.
|
|
$confirmForm = [];
|
|
$confirmForm['edittoken'] = [
|
|
'type' => 'hidden',
|
|
'name' => 'editToken',
|
|
'default' => $user->getEditToken( "abusefilter-revert-$filter" )
|
|
];
|
|
$confirmForm['title'] = [
|
|
'type' => 'hidden',
|
|
'name' => 'title',
|
|
'default' => $this->getTitle( "revert/$filter" )->getPrefixedDBkey()
|
|
];
|
|
$confirmForm['wpPeriodStart'] = [
|
|
'type' => 'hidden',
|
|
'name' => 'wpPeriodStart',
|
|
'default' => $this->origPeriodStart
|
|
];
|
|
$confirmForm['wpPeriodEnd'] = [
|
|
'type' => 'hidden',
|
|
'name' => 'wpPeriodEnd',
|
|
'default' => $this->origPeriodEnd
|
|
];
|
|
$confirmForm['reason'] = [
|
|
'type' => 'text',
|
|
'label-message' => 'abusefilter-revert-reasonfield',
|
|
'name' => 'wpReason',
|
|
'id' => 'wpReason',
|
|
];
|
|
HTMLForm::factory( 'ooui', $confirmForm, $this->getContext() )
|
|
->setAction( $this->getTitle( "revert/$filter" )->getLocalURL() )
|
|
->setWrapperLegendMsg( 'abusefilter-revert-confirm-legend' )
|
|
->setSubmitTextMsg( 'abusefilter-revert-confirm' )
|
|
->setMethod( 'post' )
|
|
->prepareForm()
|
|
->displayForm( false );
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function doLookup() {
|
|
$periodStart = $this->mPeriodStart;
|
|
$periodEnd = $this->mPeriodEnd;
|
|
$filter = $this->mPage->mFilter;
|
|
|
|
$conds = [ 'afl_filter' => $filter ];
|
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
|
|
|
if ( $periodStart ) {
|
|
$conds[] = 'afl_timestamp >= ' . $dbr->addQuotes( $dbr->timestamp( $periodStart ) );
|
|
}
|
|
if ( $periodEnd ) {
|
|
$conds[] = 'afl_timestamp <= ' . $dbr->addQuotes( $dbr->timestamp( $periodEnd ) );
|
|
}
|
|
|
|
// Database query.
|
|
$res = $dbr->select( 'abuse_filter_log', '*', $conds, __METHOD__ );
|
|
|
|
$results = [];
|
|
foreach ( $res as $row ) {
|
|
// Don't revert if there was no action, or the action was global
|
|
if ( !$row->afl_actions || $row->afl_wiki != null ) {
|
|
continue;
|
|
}
|
|
|
|
$actions = explode( ',', $row->afl_actions );
|
|
$reversibleActions = [ 'block', 'blockautopromote', 'degroup' ];
|
|
$currentReversibleActions = array_intersect( $actions, $reversibleActions );
|
|
if ( count( $currentReversibleActions ) ) {
|
|
$results[] = [
|
|
'id' => $row->afl_id,
|
|
'actions' => $currentReversibleActions,
|
|
'user' => $row->afl_user_text,
|
|
'userid' => $row->afl_user,
|
|
'vars' => AbuseFilter::loadVarDump( $row->afl_var_dump ),
|
|
'title' => Title::makeTitle( $row->afl_namespace, $row->afl_title ),
|
|
'action' => $row->afl_action,
|
|
'timestamp' => $row->afl_timestamp
|
|
];
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Loads parameters from request
|
|
*/
|
|
public function loadParameters() {
|
|
$request = $this->getRequest();
|
|
|
|
$this->origPeriodStart = $request->getText( 'wpPeriodStart' );
|
|
$this->mPeriodStart = strtotime( $this->origPeriodStart );
|
|
$this->origPeriodEnd = $request->getText( 'wpPeriodEnd' );
|
|
$this->mPeriodEnd = strtotime( $this->origPeriodEnd );
|
|
$this->mSubmit = $request->getVal( 'submit' );
|
|
$this->mReason = $request->getVal( 'wpReason' );
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function attemptRevert() {
|
|
$filter = $this->mPage->mFilter;
|
|
$token = $this->getRequest()->getVal( 'editToken' );
|
|
if ( !$this->getUser()->matchEditToken( $token, "abusefilter-revert-$filter" ) ) {
|
|
return false;
|
|
}
|
|
|
|
$results = $this->doLookup();
|
|
foreach ( $results as $result ) {
|
|
$actions = $result['actions'];
|
|
foreach ( $actions as $action ) {
|
|
$this->revertAction( $action, $result );
|
|
}
|
|
}
|
|
$this->getOutput()->wrapWikiMsg(
|
|
'<p class="success">$1</p>',
|
|
[
|
|
'abusefilter-revert-success',
|
|
$filter,
|
|
$this->getLanguage()->formatNum( $filter )
|
|
]
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param string $action
|
|
* @param array $result
|
|
* @return bool
|
|
* @throws MWException
|
|
*/
|
|
public function revertAction( $action, $result ) {
|
|
switch ( $action ) {
|
|
case 'block':
|
|
$block = Block::newFromTarget( $result['user'] );
|
|
if ( !( $block && $block->getBy() == AbuseFilter::getFilterUser()->getId() ) ) {
|
|
// Not blocked by abuse filter
|
|
return false;
|
|
}
|
|
$block->delete();
|
|
$logEntry = new ManualLogEntry( 'block', 'unblock' );
|
|
$logEntry->setTarget( Title::makeTitle( NS_USER, $result['user'] ) );
|
|
$logEntry->setComment(
|
|
$this->msg(
|
|
'abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason
|
|
)->inContentLanguage()->text()
|
|
);
|
|
$logEntry->setPerformer( $this->getUser() );
|
|
$logEntry->publish( $logEntry->insert() );
|
|
return true;
|
|
case 'blockautopromote':
|
|
ObjectCache::getMainStashInstance()->delete(
|
|
AbuseFilter::autoPromoteBlockKey( User::newFromId( $result['userid'] ) )
|
|
);
|
|
return true;
|
|
case 'degroup':
|
|
// Pull the user's groups from the vars.
|
|
$oldGroups = $result['vars']->getVar( 'user_groups' )->toNative();
|
|
$oldGroups = array_diff(
|
|
$oldGroups,
|
|
array_intersect( $oldGroups, User::getImplicitGroups() )
|
|
);
|
|
|
|
$rows = [];
|
|
foreach ( $oldGroups as $group ) {
|
|
$rows[] = [
|
|
'ug_user' => $result['userid'],
|
|
'ug_group' => $group
|
|
];
|
|
}
|
|
|
|
// Cheat a little bit. User::addGroup repeatedly is too slow.
|
|
$user = User::newFromId( $result['userid'] );
|
|
$currentGroups = $user->getGroups();
|
|
$newGroups = array_merge( $oldGroups, $currentGroups );
|
|
|
|
// Don't do anything if there are no groups to add.
|
|
if ( !count( array_diff( $newGroups, $currentGroups ) ) ) {
|
|
return false;
|
|
}
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
$dbw->insert( 'user_groups', $rows, __METHOD__, [ 'IGNORE' ] );
|
|
$user->invalidateCache();
|
|
|
|
$logEntry = new ManualLogEntry( 'rights', 'rights' );
|
|
$logEntry->setTarget( $user->getUserPage() );
|
|
$logEntry->setPerformer( $this->getUser() );
|
|
$logEntry->setComment(
|
|
$this->msg(
|
|
'abusefilter-revert-reason',
|
|
$this->mPage->mFilter,
|
|
$this->mReason
|
|
)->inContentLanguage()->text()
|
|
);
|
|
$logEntry->setParameters( [
|
|
'4::oldgroups' => $currentGroups,
|
|
'5::newgroups' => $newGroups
|
|
] );
|
|
$logEntry->publish( $logEntry->insert() );
|
|
|
|
return true;
|
|
}
|
|
|
|
throw new MWException( 'Invalid action' . $action );
|
|
}
|
|
}
|