MediaWiki master
LogEventsList.php
Go to the documentation of this file.
1<?php
26namespace MediaWiki\Logging;
27
28use InvalidArgumentException;
57use stdClass;
59
61 public const NO_ACTION_LINK = 1;
62 public const NO_EXTRA_USER_LINKS = 2;
63 public const USE_CHECKBOXES = 4;
64
66 public $flags;
67
71 protected $showTagEditUI;
72
76 private $linkRenderer;
77
79 private $hookRunner;
80
81 private LogFormatterFactory $logFormatterFactory;
82
84 private $tagsCache;
85
92 public function __construct( $context, $linkRenderer = null, $flags = 0 ) {
93 $this->setContext( $context );
94 $this->flags = $flags;
95 $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getAuthority() );
96 if ( $linkRenderer instanceof LinkRenderer ) {
97 $this->linkRenderer = $linkRenderer;
98 }
100 $this->hookRunner = new HookRunner( $services->getHookContainer() );
101 $this->logFormatterFactory = $services->getLogFormatterFactory();
102 $this->tagsCache = new MapCacheLRU( 50 );
103 }
104
109 protected function getLinkRenderer() {
110 if ( $this->linkRenderer !== null ) {
111 return $this->linkRenderer;
112 } else {
113 return MediaWikiServices::getInstance()->getLinkRenderer();
114 }
115 }
116
128 public function showOptions( $type = '', $year = 0, $month = 0, $day = 0 ) {
129 $formDescriptor = [];
130
131 // Basic selectors
132 $formDescriptor['type'] = $this->getTypeMenuDesc();
133 $formDescriptor['user'] = [
134 'class' => HTMLUserTextField::class,
135 'label-message' => 'specialloguserlabel',
136 'name' => 'user',
137 'ipallowed' => true,
138 'iprange' => true,
139 'external' => true,
140 ];
141 $formDescriptor['page'] = [
142 'class' => HTMLTitleTextField::class,
143 'label-message' => 'speciallogtitlelabel',
144 'name' => 'page',
145 'required' => false,
146 ];
147
148 // Title pattern, if allowed
149 if ( !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
150 $formDescriptor['pattern'] = [
151 'type' => 'check',
152 'label-message' => 'log-title-wildcard',
153 'name' => 'pattern',
154 ];
155 }
156
157 // Add extra inputs if any
158 $extraInputsDescriptor = $this->getExtraInputsDesc( $type );
159 if ( $extraInputsDescriptor ) {
160 $formDescriptor[ 'extra' ] = $extraInputsDescriptor;
161 }
162
163 // Date menu
164 $formDescriptor['date'] = [
165 'type' => 'date',
166 'label-message' => 'date',
167 'default' => $year && $month && $day ? sprintf( "%04d-%02d-%02d", $year, $month, $day ) : '',
168 ];
169
170 // Tag filter
171 $formDescriptor['tagfilter'] = [
172 'type' => 'tagfilter',
173 'name' => 'tagfilter',
174 'label-message' => 'tag-filter',
175 ];
176 $formDescriptor['tagInvert'] = [
177 'type' => 'check',
178 'name' => 'tagInvert',
179 'label-message' => 'invert',
180 'hide-if' => [ '===', 'tagfilter', '' ],
181 ];
182
183 // Filter checkboxes, when work on all logs
184 if ( $type === '' ) {
185 $formDescriptor['filters'] = $this->getFiltersDesc();
186 }
187
188 // Action filter
189 $allowedActions = $this->getConfig()->get( MainConfigNames::ActionFilteredLogs );
190 if ( isset( $allowedActions[$type] ) ) {
191 $formDescriptor['subtype'] = $this->getActionSelectorDesc( $type, $allowedActions[$type] );
192 }
193
194 $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
195 $htmlForm
196 ->setTitle( SpecialPage::getTitleFor( 'Log' ) ) // Remove subpage
197 ->setSubmitTextMsg( 'logeventslist-submit' )
198 ->setMethod( 'GET' )
199 ->setWrapperLegendMsg( 'log' )
200 ->setFormIdentifier( 'logeventslist', true ) // T321154
201 // Set callback for data validation and log type description.
202 ->setSubmitCallback( static function ( $formData, $form ) {
203 $form->addPreHtml(
204 ( new LogPage( $formData['type'] ) )->getDescription()
205 ->setContext( $form->getContext() )->parseAsBlock()
206 );
207 return true;
208 } );
209
210 $result = $htmlForm->prepareForm()->trySubmit();
211 $htmlForm->displayForm( $result );
212 return $result === true || ( $result instanceof Status && $result->isGood() );
213 }
214
218 private function getFiltersDesc() {
219 $optionsMsg = [];
220 $filters = $this->getConfig()->get( MainConfigNames::FilterLogTypes );
221 foreach ( $filters as $type => $val ) {
222 $optionsMsg["logeventslist-{$type}-log"] = $type;
223 }
224 return [
225 'class' => HTMLMultiSelectField::class,
226 'label-message' => 'logeventslist-more-filters',
227 'flatlist' => true,
228 'options-messages' => $optionsMsg,
229 'default' => array_keys( array_intersect( $filters, [ false ] ) ),
230 ];
231 }
232
236 private function getTypeMenuDesc() {
237 $typesByName = [];
238 // Load the log names
239 foreach ( LogPage::validTypes() as $type ) {
240 $page = new LogPage( $type );
241 $pageText = $page->getName()->text();
242 if ( in_array( $pageText, $typesByName ) ) {
243 LoggerFactory::getInstance( 'translation-problem' )->error(
244 'The log type {log_type_one} has the same translation as {log_type_two} for {lang}. ' .
245 '{log_type_one} will not be displayed in the drop down menu on Special:Log.',
246 [
247 'log_type_one' => $type,
248 'log_type_two' => array_search( $pageText, $typesByName ),
249 'lang' => $this->getLanguage()->getCode(),
250 ]
251 );
252 continue;
253 }
254 if ( $this->getAuthority()->isAllowed( $page->getRestriction() ) ) {
255 $typesByName[$type] = $pageText;
256 }
257 }
258
259 asort( $typesByName );
260
261 // Always put "All public logs" on top
262 $public = $typesByName[''];
263 unset( $typesByName[''] );
264 $typesByName = [ '' => $public ] + $typesByName;
265
266 return [
267 'class' => HTMLSelectField::class,
268 'name' => 'type',
269 'options' => array_flip( $typesByName ),
270 ];
271 }
272
277 private function getExtraInputsDesc( $type ) {
278 if ( $type === 'suppress' ) {
279 return [
280 'type' => 'text',
281 'label-message' => 'revdelete-offender',
282 'name' => 'offender',
283 ];
284 } else {
285 // Allow extensions to add an extra input into the descriptor array.
286 $unused = ''; // Deprecated since 1.32, removed in 1.41
287 $formDescriptor = [];
288 $this->hookRunner->onLogEventsListGetExtraInputs( $type, $this, $unused, $formDescriptor );
289
290 return $formDescriptor;
291 }
292 }
293
300 private function getActionSelectorDesc( $type, $actions ) {
301 $actionOptions = [ 'log-action-filter-all' => '' ];
302
303 foreach ( $actions as $value => $_ ) {
304 $msgKey = "log-action-filter-$type-$value";
305 $actionOptions[ $msgKey ] = $value;
306 }
307
308 return [
309 'class' => HTMLSelectField::class,
310 'name' => 'subtype',
311 'options-messages' => $actionOptions,
312 'label-message' => 'log-action-filter-' . $type,
313 ];
314 }
315
319 public function beginLogEventsList() {
320 return "<ul class='mw-logevent-loglines'>\n";
321 }
322
326 public function endLogEventsList() {
327 return "</ul>\n";
328 }
329
334 public function logLine( $row ) {
335 $entry = DatabaseLogEntry::newFromRow( $row );
336 $formatter = $this->logFormatterFactory->newFromEntry( $entry );
337 $formatter->setContext( $this->getContext() );
338 $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) );
339
340 $time = $this->getLanguage()->userTimeAndDate(
341 $entry->getTimestamp(),
342 $this->getUser()
343 );
344 // Link the time text to the specific log entry, see T207562
345 $timeLink = $this->getLinkRenderer()->makeKnownLink(
347 $time,
348 [],
349 [ 'logid' => $entry->getId() ]
350 );
351
352 $action = $formatter->getActionText();
353
354 if ( $this->flags & self::NO_ACTION_LINK ) {
355 $revert = '';
356 } else {
357 $revert = $formatter->getActionLinks();
358 if ( $revert != '' ) {
359 $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
360 }
361 }
362
363 $comment = $formatter->getComment();
364
365 // Some user can hide log items and have review links
366 $del = $this->getShowHideLinks( $row );
367
368 // Any tags...
369 [ $tagDisplay, $newClasses ] = $this->tagsCache->getWithSetCallback(
370 $this->tagsCache->makeKey(
371 $row->ts_tags ?? '',
372 $this->getUser()->getName(),
373 $this->getLanguage()->getCode()
374 ),
375 fn () => ChangeTags::formatSummaryRow(
376 $row->ts_tags,
377 'logevent',
378 $this->getContext()
379 )
380 );
381 $classes = array_merge(
382 [ 'mw-logline-' . $entry->getType() ],
383 $newClasses
384 );
385 $attribs = [
386 'data-mw-logid' => $entry->getId(),
387 'data-mw-logaction' => $entry->getFullType(),
388 ];
389 $ret = "$del $timeLink $action $comment $revert $tagDisplay";
390
391 // Let extensions add data
392 $ret .= Html::openElement( 'span', [ 'class' => 'mw-logevent-tool' ] );
393 // FIXME: this hook assumes that callers will only append to $ret value.
394 // In future this hook should be replaced with a new hook: LogTools that has a
395 // hook interface consistent with DiffTools and HistoryTools.
396 $this->hookRunner->onLogEventsListLineEnding( $this, $ret, $entry, $classes, $attribs );
397 $attribs = array_filter( $attribs,
398 [ Sanitizer::class, 'isReservedDataAttribute' ],
399 ARRAY_FILTER_USE_KEY
400 );
401 $ret .= Html::closeElement( 'span' );
402 $attribs['class'] = $classes;
403
404 return Html::rawElement( 'li', $attribs, $ret ) . "\n";
405 }
406
411 private function getShowHideLinks( $row ) {
412 // We don't want to see the links and
413 if ( $this->flags == self::NO_ACTION_LINK ) {
414 return '';
415 }
416
417 // If change tag editing is available to this user, return the checkbox
418 if ( $this->flags & self::USE_CHECKBOXES && $this->showTagEditUI ) {
419 return Html::check( 'ids[' . $row->log_id . ']', false );
420 }
421
422 // no one can hide items from the suppress log.
423 if ( $row->log_type == 'suppress' ) {
424 return '';
425 }
426
427 $del = '';
428 $authority = $this->getAuthority();
429 // Don't show useless checkbox to people who cannot hide log entries
430 if ( $authority->isAllowed( 'deletedhistory' ) ) {
431 $canHide = $authority->isAllowed( 'deletelogentry' );
432 $canViewSuppressedOnly = $authority->isAllowed( 'viewsuppressed' ) &&
433 !$authority->isAllowed( 'suppressrevision' );
434 $entryIsSuppressed = self::isDeleted( $row, LogPage::DELETED_RESTRICTED );
435 $canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed;
436 if ( $row->log_deleted || $canHide ) {
437 // Show checkboxes instead of links.
438 if ( $canHide && $this->flags & self::USE_CHECKBOXES && !$canViewThisSuppressedEntry ) {
439 // If event was hidden from sysops
440 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $authority ) ) {
441 $del = Html::check( 'deleterevisions', false, [ 'disabled' => 'disabled' ] );
442 } else {
443 $del = Html::check( 'ids[' . $row->log_id . ']', false );
444 }
445 } else {
446 // If event was hidden from sysops
447 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $authority ) ) {
448 $del = Linker::revDeleteLinkDisabled( $canHide );
449 } else {
450 $query = [
451 'target' => SpecialPage::getTitleFor( 'Log', $row->log_type )->getPrefixedDBkey(),
452 'type' => 'logging',
453 'ids' => $row->log_id,
454 ];
455 $del = Linker::revDeleteLink(
456 $query,
457 $entryIsSuppressed,
458 $canHide && !$canViewThisSuppressedEntry
459 );
460 }
461 }
462 }
463 }
464
465 return $del;
466 }
467
474 public static function typeAction( $row, $type, $action ) {
475 $match = is_array( $type ) ?
476 in_array( $row->log_type, $type ) : $row->log_type == $type;
477 if ( $match ) {
478 $match = is_array( $action ) ?
479 in_array( $row->log_action, $action ) : $row->log_action == $action;
480 }
481
482 return $match;
483 }
484
494 public static function userCan( $row, $field, Authority $performer ) {
495 return self::userCanBitfield( $row->log_deleted, $field, $performer ) &&
496 self::userCanViewLogType( $row->log_type, $performer );
497 }
498
508 public static function userCanBitfield( $bitfield, $field, Authority $performer ) {
509 if ( $bitfield & $field ) {
510 if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
511 return $performer->isAllowedAny( 'suppressrevision', 'viewsuppressed' );
512 } else {
513 return $performer->isAllowed( 'deletedhistory' );
514 }
515 }
516 return true;
517 }
518
527 public static function userCanViewLogType( $type, Authority $performer ) {
528 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
529 if ( isset( $logRestrictions[$type] ) && !$performer->isAllowed( $logRestrictions[$type] ) ) {
530 return false;
531 }
532 return true;
533 }
534
540 public static function isDeleted( $row, $field ) {
541 return ( $row->log_deleted & $field ) == $field;
542 }
543
571 public static function showLogExtract(
572 &$out, $types = [], $page = '', $user = '', $param = []
573 ) {
574 $defaultParameters = [
575 'lim' => 25,
576 'conds' => [],
577 'showIfEmpty' => true,
578 'msgKey' => [ '' ],
579 'wrap' => "$1",
580 'flags' => 0,
581 'useRequestParams' => false,
582 'useMaster' => false,
583 'extraUrlParams' => false,
584 'footerHtmlItems' => []
585 ];
586 # The + operator appends elements of remaining keys from the right
587 # handed array to the left handed, whereas duplicated keys are NOT overwritten.
588 $param += $defaultParameters;
589 # Convert $param array to individual variables
590 $lim = $param['lim'];
591 $conds = $param['conds'];
592 $showIfEmpty = $param['showIfEmpty'];
593 $msgKey = $param['msgKey'];
594 $wrap = $param['wrap'];
595 $flags = $param['flags'];
596 $extraUrlParams = $param['extraUrlParams'];
597
598 $useRequestParams = $param['useRequestParams'];
599 // @phan-suppress-next-line PhanRedundantCondition
600 if ( !is_array( $msgKey ) ) {
601 $msgKey = [ $msgKey ];
602 }
603
604 // ???
605 // @phan-suppress-next-line PhanRedundantCondition
606 if ( $out instanceof OutputPage ) {
607 $context = $out->getContext();
608 } else {
609 $context = RequestContext::getMain();
610 }
611
612 $services = MediaWikiServices::getInstance();
613 // FIXME: Figure out how to inject this
614 $linkRenderer = $services->getLinkRenderer();
615
616 # Insert list of top 50 (or top $lim) items
617 $loglist = new LogEventsList( $context, $linkRenderer, $flags );
618 $pager = new LogPager(
619 $loglist,
620 $types,
621 $user,
622 $page,
623 false,
624 $conds,
625 false,
626 false,
627 false,
628 '',
629 '',
630 0,
631 $services->getLinkBatchFactory(),
632 $services->getActorNormalization(),
633 $services->getLogFormatterFactory()
634 );
635 if ( !$useRequestParams ) {
636 # Reset vars that may have been taken from the request
637 $pager->mLimit = 50;
638 $pager->mDefaultLimit = 50;
639 $pager->mOffset = "";
640 $pager->mIsBackwards = false;
641 }
642
643 if ( $param['useMaster'] ) {
644 $pager->mDb = $services->getConnectionProvider()->getPrimaryDatabase();
645 }
646 // @phan-suppress-next-line PhanImpossibleCondition
647 if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset
648 $pager->setOffset( $param['offset'] );
649 }
650
651 // @phan-suppress-next-line PhanSuspiciousValueComparison
652 if ( $lim > 0 ) {
653 $pager->mLimit = $lim;
654 }
655 // Fetch the log rows and build the HTML if needed
656 $logBody = $pager->getBody();
657 $numRows = $pager->getNumRows();
658
659 $s = '';
660 $footerHtmlItems = [];
661
662 if ( $logBody ) {
663 if ( $msgKey[0] ) {
664 // @phan-suppress-next-line PhanParamTooFewUnpack Non-emptiness checked above
665 $msg = $context->msg( ...$msgKey );
666 if ( $page instanceof PageReference ) {
667 $msg->page( $page );
668 }
669 $s .= $msg->parseAsBlock();
670 }
671 $s .= $loglist->beginLogEventsList() .
672 $logBody .
673 $loglist->endLogEventsList();
674 // add styles for change tags
675 $context->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
676 } elseif ( $showIfEmpty ) {
677 $s = Html::rawElement( 'div', [ 'class' => 'mw-warning-logempty' ],
678 $context->msg( 'logempty' )->parse() );
679 }
680
681 if ( $page instanceof PageReference ) {
682 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
683 $pageName = $titleFormatter->getPrefixedDBkey( $page );
684 } elseif ( $page != '' ) {
685 $pageName = $page;
686 } else {
687 $pageName = null;
688 }
689
690 if ( $numRows > $pager->mLimit ) { # Show "Full log" link
691 $urlParam = [];
692 if ( $pageName ) {
693 $urlParam['page'] = $pageName;
694 }
695
696 if ( $user != '' ) {
697 $urlParam['user'] = $user;
698 }
699
700 if ( !is_array( $types ) ) { # Make it an array, if it isn't
701 $types = [ $types ];
702 }
703
704 # If there is exactly one log type, we can link to Special:Log?type=foo
705 if ( count( $types ) == 1 ) {
706 $urlParam['type'] = $types[0];
707 }
708
709 // @phan-suppress-next-line PhanSuspiciousValueComparison
710 if ( $extraUrlParams !== false ) {
711 $urlParam = array_merge( $urlParam, $extraUrlParams );
712 }
713
714 $footerHtmlItems[] = $linkRenderer->makeKnownLink(
715 SpecialPage::getTitleFor( 'Log' ),
716 $context->msg( 'log-fulllog' )->text(),
717 [],
718 $urlParam
719 );
720 }
721 if ( $param['footerHtmlItems'] ) {
722 $footerHtmlItems = array_merge( $footerHtmlItems, $param['footerHtmlItems'] );
723 }
724 if ( $logBody && $footerHtmlItems ) {
725 $s .= '<ul class="mw-logevent-footer">';
726 foreach ( $footerHtmlItems as $item ) {
727 $s .= Html::rawElement( 'li', [], $item );
728 }
729 $s .= '</ul>';
730 }
731
732 if ( $logBody && $msgKey[0] ) {
733 // TODO: The condition above is weird. Should this be done in any other cases?
734 // Or is it always true in practice?
735
736 // Mark as interface language (T60685)
737 $dir = $context->getLanguage()->getDir();
738 $lang = $context->getLanguage()->getHtmlCode();
739 $s = Html::rawElement( 'div', [
740 'class' => "mw-content-$dir",
741 'dir' => $dir,
742 'lang' => $lang,
743 ], $s );
744
745 // Wrap in warning box
746 $s = Html::warningBox(
747 $s,
748 'mw-warning-with-logexcerpt'
749 );
750 // Add styles for warning box
751 $context->getOutput()->addModuleStyles( 'mediawiki.codex.messagebox.styles' );
752 }
753
754 // @phan-suppress-next-line PhanSuspiciousValueComparison
755 if ( $wrap != '' ) { // Wrap message in html
756 $s = str_replace( '$1', $s, $wrap );
757 }
758
759 /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
760 $hookRunner = new HookRunner( $services->getHookContainer() );
761 if ( $hookRunner->onLogEventsListShowLogExtract( $s, $types, $pageName, $user, $param ) ) {
762 // $out can be either an OutputPage object or a String-by-reference
763 if ( $out instanceof OutputPage ) {
764 $out->addHTML( $s );
765 } else {
766 $out = $s;
767 }
768 }
769
770 return $numRows;
771 }
772
782 public static function getExcludeClause( $db, $audience = 'public', ?Authority $performer = null ) {
783 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
784
785 if ( $audience != 'public' && $performer === null ) {
786 throw new InvalidArgumentException(
787 'A User object must be given when checking for a user audience.'
788 );
789 }
790
791 // Reset the array, clears extra "where" clauses when $par is used
792 $hiddenLogs = [];
793
794 // Don't show private logs to unprivileged users
795 foreach ( $logRestrictions as $logType => $right ) {
796 if ( $audience == 'public' || !$performer->isAllowed( $right ) ) {
797 $hiddenLogs[] = $logType;
798 }
799 }
800 if ( count( $hiddenLogs ) == 1 ) {
801 return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] );
802 } elseif ( $hiddenLogs ) {
803 return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')';
804 }
805
806 return false;
807 }
808
823 public static function getBlockLogWarningBox(
824 DatabaseBlockStore $blockStore,
825 NamespaceInfo $namespaceInfo,
826 MessageLocalizer $localizer,
827 LinkRenderer $linkRenderer,
828 $user,
829 Title $title
830 ) {
831 if ( !$user ) {
832 return null;
833 }
834 $appliesToTitle = false;
835 $logTargetPage = '';
836 $blockTargetName = '';
837 $blocks = $blockStore->newListFromTarget( $user, $user, false,
838 DatabaseBlockStore::AUTO_NONE );
839 foreach ( $blocks as $block ) {
840 if ( $block->appliesToTitle( $title ) ) {
841 $appliesToTitle = true;
842 }
843 $blockTargetName = $block->getTargetName();
844 $logTargetPage = $namespaceInfo->getCanonicalName( NS_USER ) .
845 ':' . $blockTargetName;
846 }
847
848 // Show log extract if the user is sitewide blocked or is partially
849 // blocked and not allowed to edit their user page or user talk page
850 if ( !count( $blocks ) || !$appliesToTitle ) {
851 return null;
852 }
853 $msgKey = count( $blocks ) === 1
854 ? 'blocked-notice-logextract' : 'blocked-notice-logextract-multi';
855 $params = [
856 'lim' => 1,
857 'showIfEmpty' => false,
858 'msgKey' => [
859 $msgKey,
860 $user->getName(), # Support GENDER in notice
861 count( $blocks )
862 ],
863 ];
864 if ( count( $blocks ) > 1 ) {
865 $params['footerHtmlItems'] = [
866 $linkRenderer->makeKnownLink(
867 SpecialPage::getTitleFor( 'BlockList' ),
868 $localizer->msg( 'blocked-notice-list-link' )->text(),
869 [],
870 [ 'wpTarget' => $blockTargetName ]
871 ),
872 ];
873 }
874
875 $outString = '';
876 self::showLogExtract( $outString, 'block', $logTargetPage, '', $params );
877 return $outString ?: null;
878 }
879}
880
882class_alias( LogEventsList::class, 'LogEventsList' );
const NS_USER
Definition Defines.php:67
newListFromTarget( $specificTarget, $vagueTarget=null, $fromPrimary=false, $auto=self::AUTO_ALL)
This is similar to DatabaseBlockStore::newFromTarget, but it returns all the relevant blocks.
Recent changes tagging.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
setContext(IContextSource $context)
getContext()
Get the base IContextSource object.
Group all the pieces relevant to the context of a request into one instance.
Implements a text input field for page titles.
Implements a text input field for user names.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:209
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
onLogEventsListShowLogExtract(&$s, $types, $page, $user, $param)
This hook is called before the string is added to OutputPage.
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
Class that generates HTML for internal links.
makeKnownLink( $target, $text=null, array $extraAttribs=[], array $query=[])
Make a link that's styled as if the target page exists (usually a "blue link", although the styling m...
Some internal bits split of from Skin.php.
Definition Linker.php:61
Create PSR-3 logger objects.
static newFromRow( $row)
Constructs new LogEntry from database result row.
static isDeleted( $row, $field)
static getExcludeClause( $db, $audience='public', ?Authority $performer=null)
SQL clause to skip forbidden log types for this user.
showOptions( $type='', $year=0, $month=0, $day=0)
Show options for the log list.
__construct( $context, $linkRenderer=null, $flags=0)
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
static typeAction( $row, $type, $action)
static getBlockLogWarningBox(DatabaseBlockStore $blockStore, NamespaceInfo $namespaceInfo, MessageLocalizer $localizer, LinkRenderer $linkRenderer, $user, Title $title)
static userCanBitfield( $bitfield, $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
static userCanViewLogType( $type, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
static userCan( $row, $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this log row,...
Class to simplify the use of log pages.
Definition LogPage.php:50
static validTypes()
Get the list of valid log types.
Definition LogPage.php:221
A class containing constants representing the names of configuration variables.
const LogRestrictions
Name constant for the LogRestrictions setting, for use with Config::get()
const ActionFilteredLogs
Name constant for the ActionFilteredLogs setting, for use with Config::get()
const FilterLogTypes
Name constant for the FilterLogTypes setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
This is one of the Core classes and should be read at least once by any new developers.
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:46
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
Parent class for all special pages.
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.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
getCanonicalName( $index)
Returns the canonical (English) name for a given index.
Represents a title within MediaWiki.
Definition Title.php:78
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Store key-value entries in a size-limited in-memory LRU cache.
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:37
isAllowed(string $permission, ?PermissionStatus $status=null)
Checks whether this authority has the given permission in general.
isAllowedAny(... $permissions)
Checks whether this authority has any of the given permissions in general.
Interface for objects representing user identity.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...