Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F2753549
AbuseFilterViewRevert.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
AbuseFilterViewRevert.php
View Options
<?php
namespace
MediaWiki\Extension\AbuseFilter\View
;
use
MediaWiki\Context\IContextSource
;
use
MediaWiki\Exception\PermissionsError
;
use
MediaWiki\Exception\UserBlockedError
;
use
MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager
;
use
MediaWiki\Extension\AbuseFilter\ActionSpecifier
;
use
MediaWiki\Extension\AbuseFilter\Consequences\Consequence\ReversibleConsequence
;
use
MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesFactory
;
use
MediaWiki\Extension\AbuseFilter\Consequences\Parameters
;
use
MediaWiki\Extension\AbuseFilter\FilterLookup
;
use
MediaWiki\Extension\AbuseFilter\SpecsFormatter
;
use
MediaWiki\Extension\AbuseFilter\Variables\UnsetVariableException
;
use
MediaWiki\Extension\AbuseFilter\Variables\VariablesBlobStore
;
use
MediaWiki\Html\Html
;
use
MediaWiki\HTMLForm\HTMLForm
;
use
MediaWiki\Linker\Linker
;
use
MediaWiki\Linker\LinkRenderer
;
use
MediaWiki\Message\Message
;
use
MediaWiki\SpecialPage\SpecialPage
;
use
MediaWiki\Title\TitleValue
;
use
MediaWiki\User\UserFactory
;
use
UnexpectedValueException
;
use
Wikimedia\Rdbms\LBFactory
;
use
Wikimedia\Rdbms\SelectQueryBuilder
;
class
AbuseFilterViewRevert
extends
AbuseFilterView
{
/** @var int */
private
$filter
;
/**
* @var string|null The start time of the lookup period
*/
private
$periodStart
;
/**
* @var string|null The end time of the lookup period
*/
private
$periodEnd
;
/**
* @var string|null The reason provided for the revert
*/
private
$reason
;
/**
* @var LBFactory
*/
private
$lbFactory
;
/**
* @var UserFactory
*/
private
$userFactory
;
/**
* @var FilterLookup
*/
private
$filterLookup
;
/**
* @var ConsequencesFactory
*/
private
$consequencesFactory
;
/**
* @var VariablesBlobStore
*/
private
$varBlobStore
;
/**
* @var SpecsFormatter
*/
private
$specsFormatter
;
/**
* @param LBFactory $lbFactory
* @param UserFactory $userFactory
* @param AbuseFilterPermissionManager $afPermManager
* @param FilterLookup $filterLookup
* @param ConsequencesFactory $consequencesFactory
* @param VariablesBlobStore $varBlobStore
* @param SpecsFormatter $specsFormatter
* @param IContextSource $context
* @param LinkRenderer $linkRenderer
* @param string $basePageName
* @param array $params
*/
public
function
__construct
(
LBFactory
$lbFactory
,
UserFactory
$userFactory
,
AbuseFilterPermissionManager
$afPermManager
,
FilterLookup
$filterLookup
,
ConsequencesFactory
$consequencesFactory
,
VariablesBlobStore
$varBlobStore
,
SpecsFormatter
$specsFormatter
,
IContextSource
$context
,
LinkRenderer
$linkRenderer
,
string
$basePageName
,
array
$params
)
{
parent
::
__construct
(
$afPermManager
,
$context
,
$linkRenderer
,
$basePageName
,
$params
);
$this
->
lbFactory
=
$lbFactory
;
$this
->
userFactory
=
$userFactory
;
$this
->
filterLookup
=
$filterLookup
;
$this
->
consequencesFactory
=
$consequencesFactory
;
$this
->
varBlobStore
=
$varBlobStore
;
$this
->
specsFormatter
=
$specsFormatter
;
$this
->
specsFormatter
->
setMessageLocalizer
(
$this
->
getContext
()
);
}
/**
* Shows the page
*/
public
function
show
()
{
$lang
=
$this
->
getLanguage
();
$performer
=
$this
->
getAuthority
();
$out
=
$this
->
getOutput
();
if
(
!
$this
->
afPermManager
->
canRevertFilterActions
(
$performer
)
)
{
throw
new
PermissionsError
(
'abusefilter-revert'
);
}
$block
=
$performer
->
getBlock
();
if
(
$block
&&
$block
->
isSitewide
()
)
{
throw
new
UserBlockedError
(
$block
);
}
$this
->
loadParameters
();
if
(
$this
->
attemptRevert
()
)
{
return
;
}
$filter
=
$this
->
filter
;
$out
->
addWikiMsg
(
'abusefilter-revert-intro'
,
Message
::
numParam
(
$filter
)
);
// Parse wikitext in this message to allow formatting of numero signs (T343994#9209383)
$out
->
setPageTitle
(
$this
->
msg
(
'abusefilter-revert-title'
)->
numParams
(
$filter
)->
parse
()
);
// 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
(
$this
->
getTitle
(
$filter
),
$lang
->
formatNum
(
$filter
)
);
$searchFields
=
[];
$searchFields
[
'filterid'
]
=
[
'type'
=>
'info'
,
'default'
=>
$filterLink
,
'raw'
=>
true
,
'label-message'
=>
'abusefilter-revert-filter'
];
$searchFields
[
'PeriodStart'
]
=
[
'type'
=>
'datetime'
,
'label-message'
=>
'abusefilter-revert-periodstart'
,
'min'
=>
$min
,
'max'
=>
$max
];
$searchFields
[
'PeriodEnd'
]
=
[
'type'
=>
'datetime'
,
'label-message'
=>
'abusefilter-revert-periodend'
,
'min'
=>
$min
,
'max'
=>
$max
];
HTMLForm
::
factory
(
'ooui'
,
$searchFields
,
$this
->
getContext
()
)
->
setTitle
(
$this
->
getTitle
(
"revert/$filter"
)
)
->
setWrapperLegendMsg
(
'abusefilter-revert-search-legend'
)
->
setSubmitTextMsg
(
'abusefilter-revert-search'
)
->
setMethod
(
'get'
)
->
setFormIdentifier
(
'revert-select-date'
)
->
setSubmitCallback
(
[
$this
,
'showRevertableActions'
]
)
->
showAlways
();
}
/**
* Show revertable actions, called as submit callback by HTMLForm
* @param array $formData
* @param HTMLForm $dateForm
* @return bool
*/
public
function
showRevertableActions
(
array
$formData
,
HTMLForm
$dateForm
):
bool
{
$lang
=
$this
->
getLanguage
();
$user
=
$this
->
getUser
();
$filter
=
$this
->
filter
;
// Look up all of them.
$results
=
$this
->
doLookup
();
if
(
$results
===
[]
)
{
$dateForm
->
addPostHtml
(
$this
->
msg
(
'abusefilter-revert-preview-no-results'
)->
escaped
()
);
return
true
;
}
// Add a summary of everything that will be reversed.
$dateForm
->
addPostHtml
(
$this
->
msg
(
'abusefilter-revert-preview-intro'
)->
parseAsBlock
()
);
$list
=
[];
foreach
(
$results
as
$result
)
{
$displayActions
=
[];
foreach
(
$result
[
'actions'
]
as
$action
)
{
$displayActions
[]
=
$this
->
specsFormatter
->
getActionDisplay
(
$action
);
}
/** @var ActionSpecifier $spec */
$spec
=
$result
[
'spec'
];
$msg
=
$this
->
msg
(
'abusefilter-revert-preview-item'
)
->
params
(
$lang
->
userTimeAndDate
(
$result
[
'timestamp'
],
$user
)
)->
rawParams
(
Linker
::
userLink
(
$spec
->
getUser
()->
getId
(),
$spec
->
getUser
()->
getName
()
)
)->
params
(
$spec
->
getAction
()
)->
rawParams
(
$this
->
linkRenderer
->
makeLink
(
$spec
->
getTitle
()
)
)->
params
(
$lang
->
commaList
(
$displayActions
)
)->
rawParams
(
$this
->
linkRenderer
->
makeLink
(
SpecialPage
::
getTitleFor
(
'AbuseLog'
),
$this
->
msg
(
'abusefilter-log-detailslink'
)->
text
(),
[],
[
'details'
=>
$result
[
'id'
]
]
)
)->
params
(
$spec
->
getUser
()->
getName
()
)->
parse
();
$list
[]
=
Html
::
rawElement
(
'li'
,
[],
$msg
);
}
$dateForm
->
addPostHtml
(
Html
::
rawElement
(
'ul'
,
[],
implode
(
"
\n
"
,
$list
)
)
);
// Add a button down the bottom.
$confirmForm
=
[];
$confirmForm
[
'PeriodStart'
]
=
[
'type'
=>
'hidden'
,
];
$confirmForm
[
'PeriodEnd'
]
=
[
'type'
=>
'hidden'
,
];
$confirmForm
[
'Reason'
]
=
[
'type'
=>
'text'
,
'label-message'
=>
'abusefilter-revert-reasonfield'
,
'id'
=>
'wpReason'
,
];
$revertForm
=
HTMLForm
::
factory
(
'ooui'
,
$confirmForm
,
$this
->
getContext
()
)
->
setTitle
(
$this
->
getTitle
(
"revert/$filter"
)
)
->
setTokenSalt
(
"abusefilter-revert-$filter"
)
->
setWrapperLegendMsg
(
'abusefilter-revert-confirm-legend'
)
->
setSubmitTextMsg
(
'abusefilter-revert-confirm'
)
->
prepareForm
()
->
getHTML
(
true
);
$dateForm
->
addPostHtml
(
$revertForm
);
return
true
;
}
/**
* @return array[]
*/
public
function
doLookup
()
{
$periodStart
=
$this
->
periodStart
;
$periodEnd
=
$this
->
periodEnd
;
$filter
=
$this
->
filter
;
$dbr
=
$this
->
lbFactory
->
getReplicaDatabase
();
// Only hits from local filters can be reverted
$conds
=
[
'afl_filter_id'
=>
$filter
,
'afl_global'
=>
0
];
if
(
$periodStart
!==
null
)
{
$conds
[]
=
$dbr
->
expr
(
'afl_timestamp'
,
'>='
,
$dbr
->
timestamp
(
$periodStart
)
);
}
if
(
$periodEnd
!==
null
)
{
$conds
[]
=
$dbr
->
expr
(
'afl_timestamp'
,
'<='
,
$dbr
->
timestamp
(
$periodEnd
)
);
}
// Don't revert if there was no action, or the action was global
$conds
[]
=
$dbr
->
expr
(
'afl_actions'
,
'!='
,
''
);
$conds
[
'afl_wiki'
]
=
null
;
$selectFields
=
[
'afl_id'
,
'afl_user'
,
'afl_user_text'
,
'afl_ip'
,
'afl_action'
,
'afl_actions'
,
'afl_var_dump'
,
'afl_timestamp'
,
'afl_namespace'
,
'afl_title'
,
];
$res
=
$dbr
->
newSelectQueryBuilder
()
->
select
(
$selectFields
)
->
from
(
'abuse_filter_log'
)
->
where
(
$conds
)
->
caller
(
__METHOD__
)
->
orderBy
(
'afl_timestamp'
,
SelectQueryBuilder
::
SORT_DESC
)
->
fetchResultSet
();
// TODO: get the following from ConsequencesRegistry or sth else
static
$reversibleActions
=
[
'block'
,
'blockautopromote'
,
'degroup'
];
$results
=
[];
foreach
(
$res
as
$row
)
{
$actions
=
explode
(
','
,
$row
->
afl_actions
);
$currentReversibleActions
=
array_intersect
(
$actions
,
$reversibleActions
);
if
(
count
(
$currentReversibleActions
)
)
{
$vars
=
$this
->
varBlobStore
->
loadVarDump
(
$row
);
try
{
// The variable is not lazy-loaded
$accountName
=
$vars
->
getComputedVariable
(
'accountname'
)->
toNative
();
}
catch
(
UnsetVariableException
$_
)
{
$accountName
=
null
;
}
$results
[]
=
[
'id'
=>
$row
->
afl_id
,
'actions'
=>
$currentReversibleActions
,
'vars'
=>
$vars
,
'spec'
=>
new
ActionSpecifier
(
$row
->
afl_action
,
new
TitleValue
(
(
int
)
$row
->
afl_namespace
,
$row
->
afl_title
),
$this
->
userFactory
->
newFromAnyId
(
(
int
)
$row
->
afl_user
,
$row
->
afl_user_text
),
$row
->
afl_ip
,
$accountName
),
'timestamp'
=>
$row
->
afl_timestamp
];
}
}
return
$results
;
}
/**
* Loads parameters from request
*/
public
function
loadParameters
()
{
$request
=
$this
->
getRequest
();
$this
->
filter
=
(
int
)
$this
->
mParams
[
1
];
$this
->
periodStart
=
strtotime
(
$request
->
getText
(
'wpPeriodStart'
)
)
?:
null
;
$this
->
periodEnd
=
strtotime
(
$request
->
getText
(
'wpPeriodEnd'
)
)
?:
null
;
$this
->
reason
=
$request
->
getVal
(
'wpReason'
);
}
/**
* @return bool
*/
public
function
attemptRevert
()
{
$filter
=
$this
->
filter
;
$token
=
$this
->
getRequest
()->
getVal
(
'wpEditToken'
);
if
(
!
$this
->
getCsrfTokenSet
()->
matchToken
(
$token
,
"abusefilter-revert-$filter"
)
)
{
return
false
;
}
$results
=
$this
->
doLookup
();
foreach
(
$results
as
$result
)
{
foreach
(
$result
[
'actions'
]
as
$action
)
{
$this
->
revertAction
(
$action
,
$result
);
}
}
$this
->
getOutput
()->
addModuleStyles
(
'mediawiki.codex.messagebox.styles'
);
$this
->
getOutput
()->
addHTML
(
Html
::
successBox
(
$this
->
msg
(
'abusefilter-revert-success'
,
$filter
,
$this
->
getLanguage
()->
formatNum
(
$filter
)
)->
parse
()
)
);
return
true
;
}
/**
* Helper method for typing
* @param string $action
* @param array $result
* @return ReversibleConsequence
*/
private
function
getConsequence
(
string
$action
,
array
$result
):
ReversibleConsequence
{
$params
=
new
Parameters
(
$this
->
filterLookup
->
getFilter
(
$this
->
filter
,
false
),
false
,
$result
[
'spec'
]
);
switch
(
$action
)
{
case
'block'
:
return
$this
->
consequencesFactory
->
newBlock
(
$params
,
''
,
false
);
case
'blockautopromote'
:
$duration
=
$this
->
getConfig
()->
get
(
'AbuseFilterBlockAutopromoteDuration'
)
*
86400
;
return
$this
->
consequencesFactory
->
newBlockAutopromote
(
$params
,
$duration
);
case
'degroup'
:
return
$this
->
consequencesFactory
->
newDegroup
(
$params
,
$result
[
'vars'
]
);
default
:
throw
new
UnexpectedValueException
(
"Invalid action $action"
);
}
}
/**
* @param string $action
* @param array $result
* @return bool
*/
public
function
revertAction
(
string
$action
,
array
$result
):
bool
{
$message
=
$this
->
msg
(
'abusefilter-revert-reason'
,
$this
->
filter
,
$this
->
reason
)->
inContentLanguage
()->
text
();
$consequence
=
$this
->
getConsequence
(
$action
,
$result
);
return
$consequence
->
revert
(
$this
->
getAuthority
(),
$message
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, Jul 3, 21:24 (17 h, 49 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
da/a5/d8c42127db1b308e142c8b8a1907
Default Alt Text
AbuseFilterViewRevert.php (11 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment