MediaWiki master
LogEventsList.php
Go to the documentation of this file.
1<?php
49
51 public const NO_ACTION_LINK = 1;
52 public const NO_EXTRA_USER_LINKS = 2;
53 public const USE_CHECKBOXES = 4;
54
56 public $flags;
57
61 protected $showTagEditUI;
62
66 private $linkRenderer;
67
69 private $hookRunner;
70
71 private LogFormatterFactory $logFormatterFactory;
72
74 private $tagsCache;
75
82 public function __construct( $context, $linkRenderer = null, $flags = 0 ) {
83 $this->setContext( $context );
84 $this->flags = $flags;
85 $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getAuthority() );
86 if ( $linkRenderer instanceof LinkRenderer ) {
87 $this->linkRenderer = $linkRenderer;
88 }
89 $services = MediaWikiServices::getInstance();
90 $this->hookRunner = new HookRunner( $services->getHookContainer() );
91 $this->logFormatterFactory = $services->getLogFormatterFactory();
92 $this->tagsCache = new MapCacheLRU( 50 );
93 }
94
99 protected function getLinkRenderer() {
100 if ( $this->linkRenderer !== null ) {
101 return $this->linkRenderer;
102 } else {
103 return MediaWikiServices::getInstance()->getLinkRenderer();
104 }
105 }
106
118 public function showOptions( $type = '', $year = 0, $month = 0, $day = 0 ) {
119 $formDescriptor = [];
120
121 // Basic selectors
122 $formDescriptor['type'] = $this->getTypeMenuDesc();
123 $formDescriptor['user'] = [
124 'class' => HTMLUserTextField::class,
125 'label-message' => 'specialloguserlabel',
126 'name' => 'user',
127 'ipallowed' => true,
128 'iprange' => true,
129 'external' => true,
130 ];
131 $formDescriptor['page'] = [
132 'class' => HTMLTitleTextField::class,
133 'label-message' => 'speciallogtitlelabel',
134 'name' => 'page',
135 'required' => false,
136 ];
137
138 // Title pattern, if allowed
139 if ( !$this->getConfig()->get( MainConfigNames::MiserMode ) ) {
140 $formDescriptor['pattern'] = [
141 'type' => 'check',
142 'label-message' => 'log-title-wildcard',
143 'name' => 'pattern',
144 ];
145 }
146
147 // Add extra inputs if any
148 $extraInputsDescriptor = $this->getExtraInputsDesc( $type );
149 if ( $extraInputsDescriptor ) {
150 $formDescriptor[ 'extra' ] = $extraInputsDescriptor;
151 }
152
153 // Date menu
154 $formDescriptor['date'] = [
155 'type' => 'date',
156 'label-message' => 'date',
157 'default' => $year && $month && $day ? sprintf( "%04d-%02d-%02d", $year, $month, $day ) : '',
158 ];
159
160 // Tag filter
161 $formDescriptor['tagfilter'] = [
162 'type' => 'tagfilter',
163 'name' => 'tagfilter',
164 'label-message' => 'tag-filter',
165 ];
166 $formDescriptor['tagInvert'] = [
167 'type' => 'check',
168 'name' => 'tagInvert',
169 'label-message' => 'invert',
170 'hide-if' => [ '===', 'tagfilter', '' ],
171 ];
172
173 // Filter checkboxes, when work on all logs
174 if ( $type === '' ) {
175 $formDescriptor['filters'] = $this->getFiltersDesc();
176 }
177
178 // Action filter
179 $allowedActions = $this->getConfig()->get( MainConfigNames::ActionFilteredLogs );
180 if ( isset( $allowedActions[$type] ) ) {
181 $formDescriptor['subtype'] = $this->getActionSelectorDesc( $type, $allowedActions[$type] );
182 }
183
184 $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
185 $htmlForm
186 ->setTitle( SpecialPage::getTitleFor( 'Log' ) ) // Remove subpage
187 ->setSubmitTextMsg( 'logeventslist-submit' )
188 ->setMethod( 'GET' )
189 ->setWrapperLegendMsg( 'log' )
190 ->setFormIdentifier( 'logeventslist', true ) // T321154
191 // Set callback for data validation and log type description.
192 ->setSubmitCallback( static function ( $formData, $form ) {
193 $form->addPreHtml(
194 ( new LogPage( $formData['type'] ) )->getDescription()
195 ->setContext( $form->getContext() )->parseAsBlock()
196 );
197 return true;
198 } );
199
200 $result = $htmlForm->prepareForm()->trySubmit();
201 $htmlForm->displayForm( $result );
202 return $result === true || ( $result instanceof Status && $result->isGood() );
203 }
204
208 private function getFiltersDesc() {
209 $optionsMsg = [];
210 $filters = $this->getConfig()->get( MainConfigNames::FilterLogTypes );
211 foreach ( $filters as $type => $val ) {
212 $optionsMsg["logeventslist-{$type}-log"] = $type;
213 }
214 return [
215 'class' => HTMLMultiSelectField::class,
216 'label-message' => 'logeventslist-more-filters',
217 'flatlist' => true,
218 'options-messages' => $optionsMsg,
219 'default' => array_keys( array_intersect( $filters, [ false ] ) ),
220 ];
221 }
222
226 private function getTypeMenuDesc() {
227 $typesByName = [];
228 // Load the log names
229 foreach ( LogPage::validTypes() as $type ) {
230 $page = new LogPage( $type );
231 $pageText = $page->getName()->text();
232 if ( in_array( $pageText, $typesByName ) ) {
233 LoggerFactory::getInstance( 'translation-problem' )->error(
234 'The log type {log_type_one} has the same translation as {log_type_two} for {lang}. ' .
235 '{log_type_one} will not be displayed in the drop down menu on Special:Log.',
236 [
237 'log_type_one' => $type,
238 'log_type_two' => array_search( $pageText, $typesByName ),
239 'lang' => $this->getLanguage()->getCode(),
240 ]
241 );
242 continue;
243 }
244 if ( $this->getAuthority()->isAllowed( $page->getRestriction() ) ) {
245 $typesByName[$type] = $pageText;
246 }
247 }
248
249 asort( $typesByName );
250
251 // Always put "All public logs" on top
252 $public = $typesByName[''];
253 unset( $typesByName[''] );
254 $typesByName = [ '' => $public ] + $typesByName;
255
256 return [
257 'class' => HTMLSelectField::class,
258 'name' => 'type',
259 'options' => array_flip( $typesByName ),
260 ];
261 }
262
267 private function getExtraInputsDesc( $type ) {
268 if ( $type === 'suppress' ) {
269 return [
270 'type' => 'text',
271 'label-message' => 'revdelete-offender',
272 'name' => 'offender',
273 ];
274 } else {
275 // Allow extensions to add an extra input into the descriptor array.
276 $unused = ''; // Deprecated since 1.32, removed in 1.41
277 $formDescriptor = [];
278 $this->hookRunner->onLogEventsListGetExtraInputs( $type, $this, $unused, $formDescriptor );
279
280 return $formDescriptor;
281 }
282 }
283
290 private function getActionSelectorDesc( $type, $actions ) {
291 $actionOptions = [ 'log-action-filter-all' => '' ];
292
293 foreach ( $actions as $value => $_ ) {
294 $msgKey = "log-action-filter-$type-$value";
295 $actionOptions[ $msgKey ] = $value;
296 }
297
298 return [
299 'class' => HTMLSelectField::class,
300 'name' => 'subtype',
301 'options-messages' => $actionOptions,
302 'label-message' => 'log-action-filter-' . $type,
303 ];
304 }
305
309 public function beginLogEventsList() {
310 return "<ul class='mw-logevent-loglines'>\n";
311 }
312
316 public function endLogEventsList() {
317 return "</ul>\n";
318 }
319
324 public function logLine( $row ) {
325 $entry = DatabaseLogEntry::newFromRow( $row );
326 $formatter = $this->logFormatterFactory->newFromEntry( $entry );
327 $formatter->setContext( $this->getContext() );
328 $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) );
329
330 $time = $this->getLanguage()->userTimeAndDate(
331 $entry->getTimestamp(),
332 $this->getUser()
333 );
334 // Link the time text to the specific log entry, see T207562
335 $timeLink = $this->getLinkRenderer()->makeKnownLink(
336 SpecialPage::getTitleValueFor( 'Log' ),
337 $time,
338 [],
339 [ 'logid' => $entry->getId() ]
340 );
341
342 $action = $formatter->getActionText();
343
344 if ( $this->flags & self::NO_ACTION_LINK ) {
345 $revert = '';
346 } else {
347 $revert = $formatter->getActionLinks();
348 if ( $revert != '' ) {
349 $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
350 }
351 }
352
353 $comment = $formatter->getComment();
354
355 // Some user can hide log items and have review links
356 $del = $this->getShowHideLinks( $row );
357
358 // Any tags...
359 [ $tagDisplay, $newClasses ] = $this->tagsCache->getWithSetCallback(
360 $this->tagsCache->makeKey(
361 $row->ts_tags ?? '',
362 $this->getUser()->getName(),
363 $this->getLanguage()->getCode()
364 ),
366 $row->ts_tags,
367 'logevent',
368 $this->getContext()
369 )
370 );
371 $classes = array_merge(
372 [ 'mw-logline-' . $entry->getType() ],
373 $newClasses
374 );
375 $attribs = [
376 'data-mw-logid' => $entry->getId(),
377 'data-mw-logaction' => $entry->getFullType(),
378 ];
379 $ret = "$del $timeLink $action $comment $revert $tagDisplay";
380
381 // Let extensions add data
382 $ret .= Html::openElement( 'span', [ 'class' => 'mw-logevent-tool' ] );
383 // FIXME: this hook assumes that callers will only append to $ret value.
384 // In future this hook should be replaced with a new hook: LogTools that has a
385 // hook interface consistent with DiffTools and HistoryTools.
386 $this->hookRunner->onLogEventsListLineEnding( $this, $ret, $entry, $classes, $attribs );
387 $attribs = array_filter( $attribs,
388 [ Sanitizer::class, 'isReservedDataAttribute' ],
389 ARRAY_FILTER_USE_KEY
390 );
391 $ret .= Html::closeElement( 'span' );
392 $attribs['class'] = $classes;
393
394 return Html::rawElement( 'li', $attribs, $ret ) . "\n";
395 }
396
401 private function getShowHideLinks( $row ) {
402 // We don't want to see the links and
403 if ( $this->flags == self::NO_ACTION_LINK ) {
404 return '';
405 }
406
407 // If change tag editing is available to this user, return the checkbox
408 if ( $this->flags & self::USE_CHECKBOXES && $this->showTagEditUI ) {
409 return Xml::check(
410 'showhiderevisions',
411 false,
412 [ 'name' => 'ids[' . $row->log_id . ']' ]
413 );
414 }
415
416 // no one can hide items from the suppress log.
417 if ( $row->log_type == 'suppress' ) {
418 return '';
419 }
420
421 $del = '';
422 $authority = $this->getAuthority();
423 // Don't show useless checkbox to people who cannot hide log entries
424 if ( $authority->isAllowed( 'deletedhistory' ) ) {
425 $canHide = $authority->isAllowed( 'deletelogentry' );
426 $canViewSuppressedOnly = $authority->isAllowed( 'viewsuppressed' ) &&
427 !$authority->isAllowed( 'suppressrevision' );
428 $entryIsSuppressed = self::isDeleted( $row, LogPage::DELETED_RESTRICTED );
429 $canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed;
430 if ( $row->log_deleted || $canHide ) {
431 // Show checkboxes instead of links.
432 if ( $canHide && $this->flags & self::USE_CHECKBOXES && !$canViewThisSuppressedEntry ) {
433 // If event was hidden from sysops
434 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $authority ) ) {
435 $del = Xml::check( 'deleterevisions', false, [ 'disabled' => 'disabled' ] );
436 } else {
437 $del = Xml::check(
438 'showhiderevisions',
439 false,
440 [ 'name' => 'ids[' . $row->log_id . ']' ]
441 );
442 }
443 } else {
444 // If event was hidden from sysops
445 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $authority ) ) {
446 $del = Linker::revDeleteLinkDisabled( $canHide );
447 } else {
448 $query = [
449 'target' => SpecialPage::getTitleFor( 'Log', $row->log_type )->getPrefixedDBkey(),
450 'type' => 'logging',
451 'ids' => $row->log_id,
452 ];
453 $del = Linker::revDeleteLink(
454 $query,
455 $entryIsSuppressed,
456 $canHide && !$canViewThisSuppressedEntry
457 );
458 }
459 }
460 }
461 }
462
463 return $del;
464 }
465
472 public static function typeAction( $row, $type, $action ) {
473 $match = is_array( $type ) ?
474 in_array( $row->log_type, $type ) : $row->log_type == $type;
475 if ( $match ) {
476 $match = is_array( $action ) ?
477 in_array( $row->log_action, $action ) : $row->log_action == $action;
478 }
479
480 return $match;
481 }
482
492 public static function userCan( $row, $field, Authority $performer ) {
493 return self::userCanBitfield( $row->log_deleted, $field, $performer ) &&
494 self::userCanViewLogType( $row->log_type, $performer );
495 }
496
506 public static function userCanBitfield( $bitfield, $field, Authority $performer ) {
507 if ( $bitfield & $field ) {
508 if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
509 return $performer->isAllowedAny( 'suppressrevision', 'viewsuppressed' );
510 } else {
511 return $performer->isAllowed( 'deletedhistory' );
512 }
513 }
514 return true;
515 }
516
525 public static function userCanViewLogType( $type, Authority $performer ) {
526 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
527 if ( isset( $logRestrictions[$type] ) && !$performer->isAllowed( $logRestrictions[$type] ) ) {
528 return false;
529 }
530 return true;
531 }
532
538 public static function isDeleted( $row, $field ) {
539 return ( $row->log_deleted & $field ) == $field;
540 }
541
567 public static function showLogExtract(
568 &$out, $types = [], $page = '', $user = '', $param = []
569 ) {
570 $defaultParameters = [
571 'lim' => 25,
572 'conds' => [],
573 'showIfEmpty' => true,
574 'msgKey' => [ '' ],
575 'wrap' => "$1",
576 'flags' => 0,
577 'useRequestParams' => false,
578 'useMaster' => false,
579 'extraUrlParams' => false,
580 ];
581 # The + operator appends elements of remaining keys from the right
582 # handed array to the left handed, whereas duplicated keys are NOT overwritten.
583 $param += $defaultParameters;
584 # Convert $param array to individual variables
585 $lim = $param['lim'];
586 $conds = $param['conds'];
587 $showIfEmpty = $param['showIfEmpty'];
588 $msgKey = $param['msgKey'];
589 $wrap = $param['wrap'];
590 $flags = $param['flags'];
591 $extraUrlParams = $param['extraUrlParams'];
592
593 $useRequestParams = $param['useRequestParams'];
594 // @phan-suppress-next-line PhanRedundantCondition
595 if ( !is_array( $msgKey ) ) {
596 $msgKey = [ $msgKey ];
597 }
598
599 // ???
600 // @phan-suppress-next-line PhanRedundantCondition
601 if ( $out instanceof OutputPage ) {
602 $context = $out->getContext();
603 } else {
604 $context = RequestContext::getMain();
605 }
606
607 $services = MediaWikiServices::getInstance();
608 // FIXME: Figure out how to inject this
609 $linkRenderer = $services->getLinkRenderer();
610
611 # Insert list of top 50 (or top $lim) items
612 $loglist = new LogEventsList( $context, $linkRenderer, $flags );
613 $pager = new LogPager(
614 $loglist,
615 $types,
616 $user,
617 $page,
618 false,
619 $conds,
620 false,
621 false,
622 false,
623 '',
624 '',
625 0,
626 $services->getLinkBatchFactory(),
627 $services->getActorNormalization(),
628 $services->getLogFormatterFactory()
629 );
630 // @phan-suppress-next-line PhanImpossibleCondition
631 if ( !$useRequestParams ) {
632 # Reset vars that may have been taken from the request
633 $pager->mLimit = 50;
634 $pager->mDefaultLimit = 50;
635 $pager->mOffset = "";
636 $pager->mIsBackwards = false;
637 }
638
639 // @phan-suppress-next-line PhanImpossibleCondition
640 if ( $param['useMaster'] ) {
641 $pager->mDb = $services->getConnectionProvider()->getPrimaryDatabase();
642 }
643 // @phan-suppress-next-line PhanImpossibleCondition
644 if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset
645 $pager->setOffset( $param['offset'] );
646 }
647
648 // @phan-suppress-next-line PhanSuspiciousValueComparison
649 if ( $lim > 0 ) {
650 $pager->mLimit = $lim;
651 }
652 // Fetch the log rows and build the HTML if needed
653 $logBody = $pager->getBody();
654 $numRows = $pager->getNumRows();
655
656 $s = '';
657
658 if ( $logBody ) {
659 if ( $msgKey[0] ) {
660 // @phan-suppress-next-line PhanParamTooFewUnpack Non-emptiness checked above
661 $msg = $context->msg( ...$msgKey );
662 if ( $page instanceof PageReference ) {
663 $msg->page( $page );
664 }
665 $s .= $msg->parseAsBlock();
666 }
667 $s .= $loglist->beginLogEventsList() .
668 $logBody .
669 $loglist->endLogEventsList();
670 // add styles for change tags
671 $context->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
672 // @phan-suppress-next-line PhanRedundantCondition
673 } elseif ( $showIfEmpty ) {
674 $s = Html::rawElement( 'div', [ 'class' => 'mw-warning-logempty' ],
675 $context->msg( 'logempty' )->parse() );
676 }
677
678 if ( $page instanceof PageReference ) {
679 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
680 $pageName = $titleFormatter->getPrefixedDBkey( $page );
681 } elseif ( $page != '' ) {
682 $pageName = $page;
683 } else {
684 $pageName = null;
685 }
686
687 if ( $numRows > $pager->mLimit ) { # Show "Full log" link
688 $urlParam = [];
689 if ( $pageName ) {
690 $urlParam['page'] = $pageName;
691 }
692
693 if ( $user != '' ) {
694 $urlParam['user'] = $user;
695 }
696
697 if ( !is_array( $types ) ) { # Make it an array, if it isn't
698 $types = [ $types ];
699 }
700
701 # If there is exactly one log type, we can link to Special:Log?type=foo
702 if ( count( $types ) == 1 ) {
703 $urlParam['type'] = $types[0];
704 }
705
706 // @phan-suppress-next-line PhanSuspiciousValueComparison
707 if ( $extraUrlParams !== false ) {
708 $urlParam = array_merge( $urlParam, $extraUrlParams );
709 }
710
711 $s .= $linkRenderer->makeKnownLink(
712 SpecialPage::getTitleFor( 'Log' ),
713 $context->msg( 'log-fulllog' )->text(),
714 [],
715 $urlParam
716 );
717 }
718
719 if ( $logBody && $msgKey[0] ) {
720 // TODO: The condition above is weird. Should this be done in any other cases?
721 // Or is it always true in practice?
722
723 // Mark as interface language (T60685)
724 $dir = $context->getLanguage()->getDir();
725 $lang = $context->getLanguage()->getHtmlCode();
726 $s = Html::rawElement( 'div', [
727 'class' => "mw-content-$dir",
728 'dir' => $dir,
729 'lang' => $lang,
730 ], $s );
731
732 // Wrap in warning box
733 $s = Html::warningBox(
734 $s,
735 'mw-warning-with-logexcerpt'
736 );
737 // Add styles for warning box
738 $context->getOutput()->addModuleStyles( 'mediawiki.codex.messagebox.styles' );
739 }
740
741 // @phan-suppress-next-line PhanSuspiciousValueComparison, PhanRedundantCondition
742 if ( $wrap != '' ) { // Wrap message in html
743 $s = str_replace( '$1', $s, $wrap );
744 }
745
746 /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
747 $hookRunner = new HookRunner( $services->getHookContainer() );
748 if ( $hookRunner->onLogEventsListShowLogExtract( $s, $types, $pageName, $user, $param ) ) {
749 // $out can be either an OutputPage object or a String-by-reference
750 if ( $out instanceof OutputPage ) {
751 $out->addHTML( $s );
752 } else {
753 $out = $s;
754 }
755 }
756
757 return $numRows;
758 }
759
769 public static function getExcludeClause( $db, $audience = 'public', ?Authority $performer = null ) {
770 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
771
772 if ( $audience != 'public' && $performer === null ) {
773 throw new InvalidArgumentException(
774 'A User object must be given when checking for a user audience.'
775 );
776 }
777
778 // Reset the array, clears extra "where" clauses when $par is used
779 $hiddenLogs = [];
780
781 // Don't show private logs to unprivileged users
782 foreach ( $logRestrictions as $logType => $right ) {
783 if ( $audience == 'public' || !$performer->isAllowed( $right ) ) {
784 $hiddenLogs[] = $logType;
785 }
786 }
787 if ( count( $hiddenLogs ) == 1 ) {
788 return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] );
789 } elseif ( $hiddenLogs ) {
790 return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')';
791 }
792
793 return false;
794 }
795}
static showTagEditingUI(Authority $performer)
Indicate whether change tag editing UI is relevant.
static formatSummaryRow( $tags, $unused, ?MessageLocalizer $localizer=null)
Creates HTML for the given tags.
const NO_EXTRA_USER_LINKS
static typeAction( $row, $type, $action)
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
showOptions( $type='', $year=0, $month=0, $day=0)
Show options for the log list.
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,...
static getExcludeClause( $db, $audience='public', ?Authority $performer=null)
SQL clause to skip forbidden log types for this user.
__construct( $context, $linkRenderer=null, $flags=0)
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.
Definition LogPage.php:46
Store key-value entries in a size-limited in-memory LRU cache.
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:56
Class that generates HTML for internal links.
Some internal bits split of from Skin.php.
Definition Linker.php:62
Create PSR-3 logger objects.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
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
Parent class for all special pages.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Module of static functions for generating XML.
Definition Xml.php:37
isGood()
Returns whether the operation completed and didn't have any error or warnings.
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.