Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5995014
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\Flags
;
use
MediaWiki\Extension\AbuseFilter\Special\SpecialAbuseLog
;
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\WikiMap\WikiMap
;
use
stdClass
;
use
Wikimedia\Rdbms\IResultWrapper
;
class
AbuseLogPager
extends
ReverseChronologicalPager
{
/**
* @var array
*/
private
$conds
;
/** @var LinkBatchFactory */
private
$linkBatchFactory
;
/** @var PermissionManager */
private
$permissionManager
;
/** @var AbuseFilterPermissionManager */
private
$afPermissionManager
;
/** @var string */
private
$basePageName
;
/**
* @var string[] Map of [ id => show|hide ], for entries that we're currently (un)hiding
*/
private
$hideEntries
;
/**
* @param IContextSource $context
* @param LinkRenderer $linkRenderer
* @param array $conds
* @param LinkBatchFactory $linkBatchFactory
* @param PermissionManager $permManager
* @param AbuseFilterPermissionManager $afPermissionManager
* @param string $basePageName
* @param string[] $hideEntries
*/
public
function
__construct
(
IContextSource
$context
,
LinkRenderer
$linkRenderer
,
array
$conds
,
LinkBatchFactory
$linkBatchFactory
,
PermissionManager
$permManager
,
AbuseFilterPermissionManager
$afPermissionManager
,
string
$basePageName
,
array
$hideEntries
=
[]
)
{
parent
::
__construct
(
$context
,
$linkRenderer
);
$this
->
conds
=
$conds
;
$this
->
linkBatchFactory
=
$linkBatchFactory
;
$this
->
permissionManager
=
$permManager
;
$this
->
afPermissionManager
=
$afPermissionManager
;
$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
;
if
(
$global
)
{
// Pull global filter description
$lookup
=
AbuseFilterServices
::
getFilterLookup
();
try
{
$filterObj
=
$lookup
->
getFilter
(
$filterID
,
true
);
$globalDesc
=
$filterObj
->
getName
();
$escaped_comments
=
Sanitizer
::
escapeHtmlAllowEntities
(
$globalDesc
);
$privacyLevel
=
$filterObj
->
getPrivacyLevel
();
}
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
$privacyLevel
=
Flags
::
FILTER_HIDDEN
|
Flags
::
FILTER_USES_PROTECTED_VARS
;
}
}
else
{
$escaped_comments
=
Sanitizer
::
escapeHtmlAllowEntities
(
$row
->
af_public_comments
??
''
);
$privacyLevel
=
$row
->
af_hidden
;
}
if
(
$this
->
afPermissionManager
->
canSeeLogDetailsForFilter
(
$performer
,
$privacyLevel
)
)
{
$actionLinks
=
[];
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
&&
$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
);
}
$description
=
$this
->
msg
(
'abusefilter-log-detailedentry-meta'
)->
rawParams
(
$timestamp
,
$userLink
,
$filterLink
,
htmlspecialchars
(
$row
->
afl_action
),
$pageLink
,
$actions_taken
,
$escaped_comments
,
$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'
;
}
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'
,
'abuse_filter'
,
'revision'
],
'fields'
=>
[
'afl_id'
,
'afl_global'
,
'afl_filter_id'
,
'afl_user'
,
'afl_ip'
,
'afl_user_text'
,
'afl_action'
,
'afl_actions'
,
'afl_var_dump'
,
'afl_timestamp'
,
'afl_namespace'
,
'afl_title'
,
'afl_wiki'
,
'afl_deleted'
,
'afl_rev_id'
,
'af_public_comments'
,
'af_hidden'
,
'rev_id'
,
],
'conds'
=>
$this
->
conds
,
'join_conds'
=>
[
'abuse_filter'
=>
[
'LEFT JOIN'
,
[
'af_id=afl_filter_id'
,
'afl_global'
=>
0
],
],
'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
->
add
(
NS_USER
,
$row
->
afl_user_text
);
$lb
->
add
(
NS_USER_TALK
,
$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
Oct 4 2026, 03:36 (4 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
9c/38/5811e9e36d6a95ea6e7656b95418
Default Alt Text
AbuseLogPager.php (13 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment