Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F2753596
AbuseLogPager.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
AbuseLogPager.php
View Options
<?php
namespace
MediaWiki\Extension\AbuseFilter\Pager
;
use
HtmlArmor
;
use
MediaWiki\Cache\LinkBatchFactory
;
use
MediaWiki\Context\IContextSource
;
use
MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager
;
use
MediaWiki\Extension\AbuseFilter\AbuseFilterServices
;
use
MediaWiki\Extension\AbuseFilter\CentralDBNotAvailableException
;
use
MediaWiki\Extension\AbuseFilter\Filter\MutableFilter
;
use
MediaWiki\Extension\AbuseFilter\Special\SpecialAbuseLog
;
use
MediaWiki\Extension\AbuseFilter\Variables\VariablesBlobStore
;
use
MediaWiki\Html\Html
;
use
MediaWiki\Linker\Linker
;
use
MediaWiki\Linker\LinkRenderer
;
use
MediaWiki\Linker\LinkTarget
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Pager\ReverseChronologicalPager
;
use
MediaWiki\Parser\Sanitizer
;
use
MediaWiki\Permissions\PermissionManager
;
use
MediaWiki\SpecialPage\SpecialPage
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\UserIdentityValue
;
use
MediaWiki\WikiMap\WikiMap
;
use
stdClass
;
use
Wikimedia\Rdbms\IResultWrapper
;
class
AbuseLogPager
extends
ReverseChronologicalPager
{
/**
* @var array
*/
private
$conds
;
/** @var string */
private
$basePageName
;
/**
* @var string[] Map of [ id => show|hide ], for entries that we're currently (un)hiding
*/
private
$hideEntries
;
private
LinkBatchFactory
$linkBatchFactory
;
private
PermissionManager
$permissionManager
;
private
AbuseFilterPermissionManager
$afPermissionManager
;
private
VariablesBlobStore
$varBlobStore
;
public
function
__construct
(
IContextSource
$context
,
LinkRenderer
$linkRenderer
,
array
$conds
,
LinkBatchFactory
$linkBatchFactory
,
PermissionManager
$permManager
,
AbuseFilterPermissionManager
$afPermissionManager
,
VariablesBlobStore
$varBlobStore
,
string
$basePageName
,
array
$hideEntries
=
[]
)
{
parent
::
__construct
(
$context
,
$linkRenderer
);
$this
->
conds
=
$conds
;
$this
->
linkBatchFactory
=
$linkBatchFactory
;
$this
->
permissionManager
=
$permManager
;
$this
->
afPermissionManager
=
$afPermissionManager
;
$this
->
varBlobStore
=
$varBlobStore
;
$this
->
basePageName
=
$basePageName
;
$this
->
hideEntries
=
$hideEntries
;
}
/**
* @param stdClass $row
* @return string
*/
public
function
formatRow
(
$row
)
{
return
$this
->
doFormatRow
(
$row
);
}
/**
* @param stdClass $row
* @param bool $isListItem
* @return string
*/
public
function
doFormatRow
(
stdClass
$row
,
bool
$isListItem
=
true
):
string
{
$performer
=
$this
->
getAuthority
();
$visibility
=
SpecialAbuseLog
::
getEntryVisibilityForUser
(
$row
,
$performer
,
$this
->
afPermissionManager
);
if
(
$visibility
!==
SpecialAbuseLog
::
VISIBILITY_VISIBLE
)
{
return
''
;
}
$linkRenderer
=
$this
->
getLinkRenderer
();
$diffLink
=
false
;
if
(
!
$row
->
afl_wiki
)
{
$title
=
Title
::
makeTitle
(
$row
->
afl_namespace
,
$row
->
afl_title
);
$pageLink
=
$linkRenderer
->
makeLink
(
$title
,
null
,
[],
[
'redirect'
=>
'no'
]
);
if
(
$row
->
rev_id
)
{
$diffLink
=
$linkRenderer
->
makeKnownLink
(
$title
,
new
HtmlArmor
(
$this
->
msg
(
'abusefilter-log-diff'
)->
parse
()
),
[],
[
'diff'
=>
'prev'
,
'oldid'
=>
$row
->
rev_id
]
);
}
elseif
(
isset
(
$row
->
ar_timestamp
)
&&
$row
->
ar_timestamp
&&
$this
->
canSeeUndeleteDiffForPage
(
$title
)
)
{
$diffLink
=
$linkRenderer
->
makeKnownLink
(
SpecialPage
::
getTitleFor
(
'Undelete'
),
new
HtmlArmor
(
$this
->
msg
(
'abusefilter-log-diff'
)->
parse
()
),
[],
[
'diff'
=>
'prev'
,
'target'
=>
$title
->
getPrefixedText
(),
'timestamp'
=>
$row
->
ar_timestamp
,
]
);
}
}
else
{
$pageLink
=
WikiMap
::
makeForeignLink
(
$row
->
afl_wiki
,
$row
->
afl_title
);
if
(
$row
->
afl_rev_id
)
{
$diffUrl
=
WikiMap
::
getForeignURL
(
$row
->
afl_wiki
,
$row
->
afl_title
);
$diffUrl
=
wfAppendQuery
(
$diffUrl
,
[
'diff'
=>
'prev'
,
'oldid'
=>
$row
->
afl_rev_id
]
);
$diffLink
=
Linker
::
makeExternalLink
(
$diffUrl
,
$this
->
msg
(
'abusefilter-log-diff'
)->
text
()
);
}
}
if
(
!
$row
->
afl_wiki
)
{
// Local user
$userLink
=
SpecialAbuseLog
::
getUserLinks
(
$row
->
afl_user
,
$row
->
afl_user_text
);
}
else
{
$userLink
=
WikiMap
::
foreignUserLink
(
$row
->
afl_wiki
,
$row
->
afl_user_text
)
.
' '
.
$this
->
msg
(
'parentheses'
)->
params
(
WikiMap
::
getWikiName
(
$row
->
afl_wiki
)
)->
escaped
();
}
$lang
=
$this
->
getLanguage
();
$timestamp
=
htmlspecialchars
(
$lang
->
userTimeAndDate
(
$row
->
afl_timestamp
,
$this
->
getUser
()
)
);
$actions_takenRaw
=
$row
->
afl_actions
;
if
(
!
strlen
(
trim
(
$actions_takenRaw
)
)
)
{
$actions_taken
=
$this
->
msg
(
'abusefilter-log-noactions'
)->
escaped
();
}
else
{
$actions
=
explode
(
','
,
$actions_takenRaw
);
$displayActions
=
[];
$specsFormatter
=
AbuseFilterServices
::
getSpecsFormatter
();
$specsFormatter
->
setMessageLocalizer
(
$this
->
getContext
()
);
foreach
(
$actions
as
$action
)
{
$displayActions
[]
=
$specsFormatter
->
getActionDisplay
(
$action
);
}
$actions_taken
=
$lang
->
commaList
(
$displayActions
);
}
$filterID
=
$row
->
afl_filter_id
;
$global
=
$row
->
afl_global
;
// Pull global filter description
$lookup
=
AbuseFilterServices
::
getFilterLookup
();
try
{
$filterObj
=
$lookup
->
getFilter
(
$filterID
,
$global
);
$escaped_comments
=
Sanitizer
::
escapeHtmlAllowEntities
(
$filterObj
->
getName
()
);
}
catch
(
CentralDBNotAvailableException
$_
)
{
$escaped_comments
=
$this
->
msg
(
'abusefilter-log-description-not-available'
)->
escaped
();
// either hide all filters, including not hidden/protected, or show all, including hidden/protected
// we choose the former
$filterObj
=
MutableFilter
::
newDefault
();
$filterObj
->
setProtected
(
true
);
$filterObj
->
setHidden
(
true
);
}
// Determine if the user has access to the associated filter and also the details of the current log
// These are used to determine what links to display for the log line.
$canSeeLogDetails
=
$this
->
afPermissionManager
->
canSeeLogDetailsForFilter
(
$performer
,
$filterObj
);
$canSeeFilter
=
$canSeeLogDetails
;
if
(
$filterObj
->
isProtected
()
)
{
$canSeeFilter
=
$canSeeFilter
&&
$this
->
afPermissionManager
->
canViewProtectedVariablesInFilter
(
$performer
,
$filterObj
)->
isGood
();
if
(
$canSeeLogDetails
)
{
$vars
=
$this
->
varBlobStore
->
loadVarDump
(
$row
);
$canSeeLogDetails
=
$this
->
afPermissionManager
->
canViewProtectedVariables
(
$performer
,
array_keys
(
$vars
->
getVars
()
)
)->
isGood
();
}
}
if
(
$canSeeFilter
)
{
$actionLinks
=
[];
if
(
$canSeeLogDetails
)
{
if
(
$isListItem
)
{
$detailsLink
=
$linkRenderer
->
makeKnownLink
(
SpecialPage
::
getTitleFor
(
$this
->
basePageName
,
$row
->
afl_id
),
$this
->
msg
(
'abusefilter-log-detailslink'
)->
text
()
);
$actionLinks
[]
=
$detailsLink
;
}
$examineTitle
=
SpecialPage
::
getTitleFor
(
'AbuseFilter'
,
'examine/log/'
.
$row
->
afl_id
);
$examineLink
=
$linkRenderer
->
makeKnownLink
(
$examineTitle
,
new
HtmlArmor
(
$this
->
msg
(
'abusefilter-changeslist-examine'
)->
parse
()
)
);
$actionLinks
[]
=
$examineLink
;
}
if
(
$diffLink
)
{
$actionLinks
[]
=
$diffLink
;
}
if
(
!
$isListItem
&&
$canSeeLogDetails
&&
$this
->
afPermissionManager
->
canHideAbuseLog
(
$performer
)
)
{
// Link for hiding a single entry from the details view
$hideLink
=
$linkRenderer
->
makeKnownLink
(
SpecialPage
::
getTitleFor
(
$this
->
basePageName
,
'hide'
),
$this
->
msg
(
'abusefilter-log-hidelink'
)->
text
(),
[],
[
"hideids[$row->afl_id]"
=>
1
]
);
$actionLinks
[]
=
$hideLink
;
}
if
(
$global
)
{
$centralDb
=
$this
->
getConfig
()->
get
(
'AbuseFilterCentralDB'
);
$linkMsg
=
$this
->
msg
(
'abusefilter-log-detailedentry-global'
)
->
numParams
(
$filterID
);
if
(
$centralDb
!==
null
)
{
$globalURL
=
WikiMap
::
getForeignURL
(
$centralDb
,
'Special:AbuseFilter/'
.
$filterID
);
$filterLink
=
Linker
::
makeExternalLink
(
$globalURL
,
$linkMsg
->
text
()
);
}
else
{
$filterLink
=
$linkMsg
->
escaped
();
}
}
else
{
$title
=
SpecialPage
::
getTitleFor
(
'AbuseFilter'
,
(
string
)
$filterID
);
$linkText
=
$this
->
msg
(
'abusefilter-log-detailedentry-local'
)
->
numParams
(
$filterID
)->
text
();
$filterLink
=
$linkRenderer
->
makeKnownLink
(
$title
,
$linkText
);
}
if
(
count
(
$actionLinks
)
)
{
$msg
=
'abusefilter-log-detailedentry-meta'
;
}
else
{
$msg
=
'abusefilter-log-detailedentry-meta-without-action-links'
;
}
$description
=
$this
->
msg
(
$msg
)->
rawParams
(
$timestamp
,
$userLink
,
$filterLink
,
htmlspecialchars
(
$row
->
afl_action
),
$pageLink
,
$actions_taken
,
$escaped_comments
,
// Passing $8 to 'abusefilter-log-detailedentry-meta-without-action-links' will do nothing,
// as it's not used.
$lang
->
pipeList
(
$actionLinks
)
)->
params
(
$row
->
afl_user_text
)->
parse
();
}
else
{
if
(
$diffLink
)
{
$msg
=
'abusefilter-log-entry-withdiff'
;
}
else
{
$msg
=
'abusefilter-log-entry'
;
}
$description
=
$this
->
msg
(
$msg
)->
rawParams
(
$timestamp
,
$userLink
,
htmlspecialchars
(
$row
->
afl_action
),
$pageLink
,
$actions_taken
,
$escaped_comments
,
// Passing $7 to 'abusefilter-log-entry' will do nothing, as it's not used.
$diffLink
?:
''
)->
params
(
$row
->
afl_user_text
)->
parse
();
}
$attribs
=
[];
if
(
$this
->
isHidingEntry
(
$row
)
===
true
||
// If isHidingEntry is false, we've just unhidden the row
(
$this
->
isHidingEntry
(
$row
)
===
null
&&
$row
->
afl_deleted
)
)
{
$attribs
[
'class'
]
=
'mw-abusefilter-log-hidden-entry'
;
}
else
{
$attribs
[
'data-afl-log-id'
]
=
$row
->
afl_id
;
}
if
(
self
::
entryHasAssociatedDeletedRev
(
$row
)
)
{
$description
.=
' '
.
$this
->
msg
(
'abusefilter-log-hidden-implicit'
)->
parse
();
}
if
(
$isListItem
&&
!
$this
->
hideEntries
&&
$this
->
afPermissionManager
->
canHideAbuseLog
(
$performer
)
)
{
// Checkbox for hiding multiple entries, single entries are handled above
$description
=
Html
::
check
(
'hideids['
.
$row
->
afl_id
.
']'
)
.
' '
.
$description
;
}
if
(
$isListItem
)
{
return
Html
::
rawElement
(
'li'
,
$attribs
,
$description
);
}
else
{
return
Html
::
rawElement
(
'span'
,
$attribs
,
$description
);
}
}
/**
* Can this user see diffs generated by Special:Undelete for the page?
* @see MediaWiki\Specials\SpecialUndelete
* @param LinkTarget $page
*
* @return bool
*/
private
function
canSeeUndeleteDiffForPage
(
LinkTarget
$page
):
bool
{
if
(
!
$this
->
canSeeUndeleteDiffs
()
)
{
return
false
;
}
foreach
(
[
'deletedtext'
,
'undelete'
]
as
$action
)
{
if
(
$this
->
permissionManager
->
userCan
(
$action
,
$this
->
getUser
(),
$page
,
PermissionManager
::
RIGOR_QUICK
)
)
{
return
true
;
}
}
return
false
;
}
/**
* Can this user see diffs generated by Special:Undelete?
* @see MediaWiki\Specials\SpecialUndelete
*
* @return bool
*/
private
function
canSeeUndeleteDiffs
():
bool
{
if
(
!
$this
->
permissionManager
->
userHasRight
(
$this
->
getUser
(),
'deletedhistory'
)
)
{
return
false
;
}
return
$this
->
permissionManager
->
userHasAnyRight
(
$this
->
getUser
(),
'deletedtext'
,
'undelete'
);
}
/**
* @return array
*/
public
function
getQueryInfo
()
{
$info
=
[
'tables'
=>
[
'abuse_filter_log'
,
'revision'
],
'fields'
=>
[
'afl_id'
,
'afl_global'
,
'afl_filter_id'
,
'afl_user'
,
'afl_ip_hex'
,
'afl_user_text'
,
'afl_action'
,
'afl_actions'
,
'afl_var_dump'
,
'afl_timestamp'
,
'afl_namespace'
,
'afl_title'
,
'afl_wiki'
,
'afl_deleted'
,
'afl_rev_id'
,
'rev_id'
,
],
'conds'
=>
$this
->
conds
,
'join_conds'
=>
[
'revision'
=>
[
'LEFT JOIN'
,
[
'afl_wiki'
=>
null
,
$this
->
mDb
->
expr
(
'afl_rev_id'
,
'!='
,
null
),
'rev_id=afl_rev_id'
,
]
],
],
];
if
(
$this
->
canSeeUndeleteDiffs
()
)
{
$info
[
'tables'
][]
=
'archive'
;
$info
[
'fields'
][]
=
'ar_timestamp'
;
$info
[
'join_conds'
][
'archive'
]
=
[
'LEFT JOIN'
,
[
'afl_wiki'
=>
null
,
$this
->
mDb
->
expr
(
'afl_rev_id'
,
'!='
,
null
),
'rev_id'
=>
null
,
'ar_rev_id=afl_rev_id'
,
]
];
}
if
(
!
$this
->
afPermissionManager
->
canSeeHiddenLogEntries
(
$this
->
getAuthority
()
)
)
{
$info
[
'conds'
][
'afl_deleted'
]
=
0
;
}
return
$info
;
}
/**
* @param IResultWrapper $result
*/
protected
function
preprocessResults
(
$result
)
{
if
(
$this
->
getNumRows
()
===
0
)
{
return
;
}
$lb
=
$this
->
linkBatchFactory
->
newLinkBatch
();
$lb
->
setCaller
(
__METHOD__
);
foreach
(
$result
as
$row
)
{
// Only for local wiki results
if
(
!
$row
->
afl_wiki
)
{
$lb
->
add
(
$row
->
afl_namespace
,
$row
->
afl_title
);
$lb
->
addUser
(
new
UserIdentityValue
(
$row
->
afl_user
??
0
,
$row
->
afl_user_text
)
);
}
}
$lb
->
execute
();
$result
->
seek
(
0
);
}
/**
* @param stdClass $row
* @return bool
* @todo This should be moved elsewhere
*/
private
static
function
entryHasAssociatedDeletedRev
(
stdClass
$row
):
bool
{
if
(
!
$row
->
afl_rev_id
)
{
return
false
;
}
$revision
=
MediaWikiServices
::
getInstance
()
->
getRevisionLookup
()
->
getRevisionById
(
$row
->
afl_rev_id
);
return
$revision
&&
$revision
->
getVisibility
()
!==
0
;
}
/**
* Check whether the entry passed in is being currently hidden/unhidden.
* This is used to format the entries list shown when updating visibility, and is necessary because
* when we decide whether to display the entry as hidden the DB hasn't been updated yet.
*
* @param stdClass $row
* @return bool|null True if just hidden, false if just unhidden, null if untouched
*/
private
function
isHidingEntry
(
stdClass
$row
):
?
bool
{
if
(
isset
(
$this
->
hideEntries
[
$row
->
afl_id
]
)
)
{
return
$this
->
hideEntries
[
$row
->
afl_id
]
===
'hide'
;
}
return
null
;
}
/**
* @codeCoverageIgnore Merely declarative
* @inheritDoc
*/
public
function
getIndexField
()
{
return
'afl_timestamp'
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, Jul 3, 21:27 (21 h, 4 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d3/9f/aa160cb9b1c91894a8d1d90a40e0
Default Alt Text
AbuseLogPager.php (13 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment