55 private $linkRenderer;
75 $this->linkRenderer = $linkRenderer;
77 $this->hookRunner =
new HookRunner( MediaWikiServices::getInstance()->getHookContainer() );
85 if ( $this->linkRenderer !==
null ) {
86 return $this->linkRenderer;
88 return MediaWikiServices::getInstance()->getLinkRenderer();
110 public function showOptions( $types = [], $user =
'', $page =
'', $pattern =
false, $year = 0,
111 $month = 0, $day = 0, $filter =
null, $tagFilter =
'', $action =
null, $extras = [],
115 $types = ( $types ===
'' ) ? [] : (array)$types;
117 $formDescriptor = [];
120 $formDescriptor[
'type'] = $this->getTypeMenuDesc( $types );
121 $formDescriptor[
'user'] = $this->getUserInputDesc( $user );
122 $formDescriptor[
'page'] = $this->getTitleInputDesc( $page );
125 if ( !$this->
getConfig()->
get( MainConfigNames::MiserMode ) ) {
126 $formDescriptor[
'pattern'] = $this->getTitlePatternDesc( $pattern );
133 $extraInputsDescriptor = $this->getExtraInputsDesc( $types, $extras );
135 is_array( $extraInputsDescriptor ) &&
136 !empty( $extraInputsDescriptor )
138 $formDescriptor[
'extra' ] = $extraInputsDescriptor;
140 is_string( $extraInputsDescriptor ) &&
141 $extraInputsDescriptor !==
''
144 $extraInputsString = $extraInputsDescriptor;
145 wfDeprecated(
'$input in LogEventsListGetExtraInputs hook',
'1.32' );
149 $formDescriptor[
'date'] = [
151 'label-message' =>
'date',
152 'default' => $year && $month && $day ? sprintf(
"%04d-%02d-%02d", $year, $month, $day ) :
'',
156 $formDescriptor[
'tagfilter'] = [
157 'type' =>
'tagfilter',
158 'name' =>
'tagfilter',
159 'label-message' =>
'tag-filter',
160 'default' => $tagFilter,
162 $formDescriptor[
'tagInvert'] = [
164 'name' =>
'tagInvert',
165 'label-message' =>
'invert',
166 'hide-if' => [
'===',
'tagfilter',
'' ],
167 'default' => $tagInvert,
172 $formDescriptor[
'filters'] = $this->getFiltersDesc( $filter );
178 $this->allowedActions !==
null &&
179 count( $this->allowedActions ) > 0
181 $formDescriptor[
'subtype'] = $this->getActionSelectorDesc( $types, $action );
188 ->setSubmitTextMsg(
'logeventslist-submit' )
190 ->setWrapperLegendMsg(
'log' )
192 ->setFormIdentifier(
'logeventslist' );
195 if ( isset( $extraInputsString ) ) {
196 $htmlForm->addFooterText( Html::rawElement(
203 $htmlForm->prepareForm()->displayForm(
false );
210 private function getFiltersDesc( $filter ) {
213 foreach ( $filter as
$type => $val ) {
214 $optionsMsg[
"logeventslist-{$type}-log"] =
$type;
216 if ( $val ===
false ) {
221 'class' => HTMLMultiSelectField::class,
222 'label-message' =>
'logeventslist-more-filters',
224 'options-messages' => $optionsMsg,
225 'default' => $default,
233 private function getTypeMenuDesc( $queryTypes ) {
234 $queryType = count( $queryTypes ) == 1 ? $queryTypes[0] :
'';
240 $restriction = $page->getRestriction();
241 if ( $this->
getAuthority()->isAllowed( $restriction ) ) {
242 $typesByName[
$type] = $page->getName()->text();
247 asort( $typesByName );
250 $public = $typesByName[
''];
251 unset( $typesByName[
''] );
252 $typesByName = [
'' => $public ] + $typesByName;
255 'class' => HTMLSelectField::class,
257 'options' => array_flip( $typesByName ),
258 'default' => $queryType,
266 private function getUserInputDesc( $user ) {
268 'class' => HTMLUserTextField::class,
269 'label-message' =>
'specialloguserlabel',
279 private function getTitleInputDesc( $page ) {
281 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
282 $page = $titleFormatter->getPrefixedText( $page );
285 'class' => HTMLTitleTextField::class,
286 'label-message' =>
'speciallogtitlelabel',
297 private function getTitlePatternDesc( $pattern ) {
300 'label-message' =>
'log-title-wildcard',
302 'default' => $pattern,
311 private function getExtraInputsDesc( $types, $extras ) {
312 if ( count( $types ) == 1 ) {
313 if ( $types[0] ==
'suppress' ) {
316 'label-message' =>
'revdelete-offender',
317 'name' =>
'offender',
318 'default' => $extras[
'offender'] ??
'',
324 $formDescriptor = [];
325 $this->hookRunner->onLogEventsListGetExtraInputs( $types[0], $this, $input, $formDescriptor );
327 return empty( $formDescriptor ) ? $input : $formDescriptor;
340 private function getActionSelectorDesc( $types, $action ) {
342 $actionOptions[
'log-action-filter-all' ] =
'';
344 foreach ( $this->allowedActions as $value ) {
345 $msgKey =
'log-action-filter-' . $types[0] .
'-' . $value;
346 $actionOptions[ $msgKey ] = $value;
350 'class' => HTMLSelectField::class,
352 'options-messages' => $actionOptions,
353 'default' => $action,
354 'label' => $this->
msg(
'log-action-filter-' . $types[0] )->text(),
365 $this->allowedActions = $actions;
372 return "<ul class='mw-logevent-loglines'>\n";
389 $formatter->setContext( $this->
getContext() );
391 $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) );
394 $entry->getTimestamp(),
402 [
'logid' => $entry->getId() ]
405 $action = $formatter->getActionText();
407 if ( $this->flags & self::NO_ACTION_LINK ) {
410 $revert = $formatter->getActionLinks();
411 if ( $revert !=
'' ) {
412 $revert =
'<span class="mw-logevent-actionlink">' . $revert .
'</span>';
416 $comment = $formatter->getComment();
419 $del = $this->getShowHideLinks( $row );
427 $classes = array_merge(
428 [
'mw-logline-' . $entry->getType() ],
432 'data-mw-logid' => $entry->getId(),
433 'data-mw-logaction' => $entry->getFullType(),
435 $ret =
"$del $timeLink $action $comment $revert $tagDisplay";
438 $this->hookRunner->onLogEventsListLineEnding( $this, $ret, $entry, $classes, $attribs );
439 $attribs = array_filter( $attribs,
440 [ Sanitizer::class,
'isReservedDataAttribute' ],
443 $attribs[
'class'] = $classes;
445 return Html::rawElement(
'li', $attribs, $ret ) .
"\n";
452 private function getShowHideLinks( $row ) {
454 if ( $this->flags == self::NO_ACTION_LINK ) {
459 if ( $this->flags & self::USE_CHECKBOXES && $this->showTagEditUI ) {
463 [
'name' =>
'ids[' . $row->log_id .
']' ]
468 if ( $row->log_type ==
'suppress' ) {
475 if ( $authority->isAllowed(
'deletedhistory' ) ) {
476 $canHide = $authority->isAllowed(
'deletelogentry' );
477 $canViewSuppressedOnly = $authority->isAllowed(
'viewsuppressed' ) &&
478 !$authority->isAllowed(
'suppressrevision' );
480 $canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed;
481 if ( $row->log_deleted || $canHide ) {
483 if ( $canHide && $this->flags & self::USE_CHECKBOXES && !$canViewThisSuppressedEntry ) {
486 $del =
Xml::check(
'deleterevisions',
false, [
'disabled' =>
'disabled' ] );
491 [
'name' =>
'ids[' . $row->log_id .
']' ]
497 $del = Linker::revDeleteLinkDisabled( $canHide );
502 'ids' => $row->log_id,
504 $del = Linker::revDeleteLink(
507 $canHide && !$canViewThisSuppressedEntry
524 $match = is_array(
$type ) ?
525 in_array( $row->log_type,
$type ) : $row->log_type ==
$type;
527 $match = is_array( $action ) ?
528 in_array( $row->log_action, $action ) : $row->log_action == $action;
558 if ( $bitfield & $field ) {
560 return $performer->
isAllowedAny(
'suppressrevision',
'viewsuppressed' );
562 return $performer->
isAllowed(
'deletedhistory' );
577 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
591 return ( $row->log_deleted & $field ) == $field;
620 &$out, $types = [], $page =
'', $user =
'', $param = []
622 $defaultParameters = [
625 'showIfEmpty' =>
true,
629 'useRequestParams' =>
false,
630 'useMaster' =>
false,
631 'extraUrlParams' =>
false,
633 # The + operator appends elements of remaining keys from the right
634 # handed array to the left handed, whereas duplicated keys are NOT overwritten.
635 $param += $defaultParameters;
636 # Convert $param array to individual variables
637 $lim = $param[
'lim'];
638 $conds = $param[
'conds'];
639 $showIfEmpty = $param[
'showIfEmpty'];
640 $msgKey = $param[
'msgKey'];
641 $wrap = $param[
'wrap'];
643 $extraUrlParams = $param[
'extraUrlParams'];
645 $useRequestParams = $param[
'useRequestParams'];
647 if ( !is_array( $msgKey ) ) {
648 $msgKey = [ $msgKey ];
652 $context = $out->getContext();
657 $services = MediaWikiServices::getInstance();
659 $linkRenderer = $services->getLinkRenderer();
661 # Insert list of top 50 (or top $lim) items
676 $services->getLinkBatchFactory(),
677 $services->getActorNormalization()
680 if ( !$useRequestParams ) {
681 # Reset vars that may have been taken from the request
683 $pager->mDefaultLimit = 50;
684 $pager->mOffset =
"";
685 $pager->mIsBackwards =
false;
689 if ( $param[
'useMaster'] ) {
693 if ( isset( $param[
'offset'] ) ) { # Tell pager to ignore
WebRequest offset
694 $pager->setOffset( $param[
'offset'] );
699 $pager->mLimit = $lim;
702 $logBody = $pager->getBody();
703 $numRows = $pager->getNumRows();
710 $msg = $context->msg( ...$msgKey );
714 $s .= $msg->parseAsBlock();
716 $s .= $loglist->beginLogEventsList() .
718 $loglist->endLogEventsList();
720 $context->getOutput()->addModuleStyles(
'mediawiki.interface.helpers.styles' );
722 } elseif ( $showIfEmpty ) {
723 $s = Html::rawElement(
'div', [
'class' =>
'mw-warning-logempty' ],
724 $context->msg(
'logempty' )->parse() );
728 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
729 $pageName = $titleFormatter->getPrefixedDBkey( $page );
730 } elseif ( $page !=
'' ) {
736 if ( $numRows > $pager->mLimit ) { # Show
"Full log" link
739 $urlParam[
'page'] = $pageName;
743 $urlParam[
'user'] = $user;
746 if ( !is_array( $types ) ) { # Make it an array,
if it isn
't
750 # If there is exactly one log type, we can link to Special:Log?type=foo
751 if ( count( $types ) == 1 ) {
752 $urlParam['type
'] = $types[0];
755 // @phan-suppress-next-line PhanSuspiciousValueComparison
756 if ( $extraUrlParams !== false ) {
757 $urlParam = array_merge( $urlParam, $extraUrlParams );
760 $s .= $linkRenderer->makeKnownLink(
761 SpecialPage::getTitleFor( 'Log
' ),
762 $context->msg( 'log-fulllog
' )->text(),
768 if ( $logBody && $msgKey[0] ) {
769 // TODO: The condition above is weird. Should this be done in any other cases?
770 // Or is it always true in practice?
772 // Mark as interface language (T60685)
773 $dir = $context->getLanguage()->getDir();
774 $lang = $context->getLanguage()->getHtmlCode();
775 $s = Html::rawElement( 'div
', [
776 'class' => "mw-content-$dir",
781 // Wrap in warning box
782 $s = Html::warningBox(
784 'mw-warning-with-logexcerpt
'
788 // @phan-suppress-next-line PhanSuspiciousValueComparison, PhanRedundantCondition
789 if ( $wrap != '' ) { // Wrap message in html
790 $s = str_replace( '$1
', $s, $wrap );
793 /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
794 $hookRunner =
new HookRunner( $services->getHookContainer() );
817 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
819 if ( $audience !=
'public' && $performer ===
null ) {
820 throw new InvalidArgumentException(
821 'A User object must be given when checking for a user audience.'
829 foreach ( $logRestrictions as $logType => $right ) {
830 if ( $audience ==
'public' || !$performer->isAllowed( $right )
832 $hiddenLogs[] = $logType;
835 if ( count( $hiddenLogs ) == 1 ) {
836 return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] );
837 } elseif ( $hiddenLogs ) {
838 return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) .
')';
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
getContext()
Get the base IContextSource object.
setContext(IContextSource $context)
static newFromRow( $row)
Constructs new LogEntry from database result row.
An IContextSource implementation which will inherit context from another source but allow individual ...
const NO_EXTRA_USER_LINKS
static typeAction( $row, $type, $action)
showOptions( $types=[], $user='', $page='', $pattern=false, $year=0, $month=0, $day=0, $filter=null, $tagFilter='', $action=null, $extras=[], $tagInvert=false)
Show options for the log list.
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
static getExcludeClause( $db, $audience='public', Authority $performer=null)
SQL clause to skip forbidden log types for this user.
static userCan( $row, $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
static userCanBitfield( $bitfield, $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
__construct( $context, $linkRenderer=null, $flags=0)
setAllowedActions( $actions)
Sets the action types allowed for log filtering To one action type may correspond several log_actions...
static userCanViewLogType( $type, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
static isDeleted( $row, $field)
Class to simplify the use of log pages.
static validTypes()
Get the list of valid log types.
A class containing constants representing the names of configuration variables.
This is one of the Core classes and should be read at least once by any new developers.
static getMain()
Get the RequestContext object associated with the main request.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
static getTitleValueFor( $name, $subpage=false, $fragment='')
Get a localised TitleValue object for a specified special page name.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
static check( $name, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox.