Merge "logging: Deprecate LogEventsList::$mDefaultQuery member"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 30 Aug 2019 00:15:30 +0000 (00:15 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 30 Aug 2019 00:15:30 +0000 (00:15 +0000)
25 files changed:
includes/OutputPage.php
includes/Permissions/PermissionManager.php
includes/TemplatesOnThisPageFormatter.php
includes/actions/pagers/HistoryPager.php
includes/api/ApiQueryAllUsers.php
includes/api/ApiQueryContributors.php
includes/block/AbstractBlock.php
includes/block/CompositeBlock.php
includes/block/DatabaseBlock.php
includes/block/SystemBlock.php
includes/changes/ChangesList.php
includes/diff/DifferenceEngine.php
includes/page/Article.php
includes/page/ImageHistoryList.php
includes/page/ImagePage.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialSearch.php
includes/specials/pagers/ContribsPager.php
includes/user/User.php
resources/src/jquery/jquery.highlightText.js
resources/src/jquery/jquery.suggestions.js
tests/phpunit/includes/Permissions/PermissionManagerTest.php
tests/phpunit/structure/AvailableRightsTest.php

index b2ca53a..9af16d3 100644 (file)
@@ -3311,12 +3311,10 @@ class OutputPage extends ContextSource {
                        $vars['wgUserVariant'] = $contLang->getPreferredVariant();
                }
                // Same test as SkinTemplate
-               $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user )
-                       && ( $title->exists() || $title->quickUserCan( 'create', $user ) );
+               $vars['wgIsProbablyEditable'] = $this->userCanEditOrCreate( $user, $title );
 
-               $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle
-                       && $relevantTitle->quickUserCan( 'edit', $user )
-                       && ( $relevantTitle->exists() || $relevantTitle->quickUserCan( 'create', $user ) );
+               $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle &&
+                       $this->userCanEditOrCreate( $user, $relevantTitle );
 
                foreach ( $title->getRestrictionTypes() as $type ) {
                        // Following keys are set in $vars:
@@ -3383,6 +3381,21 @@ class OutputPage extends ContextSource {
                return true;
        }
 
+       /**
+        * @param User $user
+        * @param LinkTarget $title
+        * @return bool
+        */
+       private function userCanEditOrCreate(
+               User $user,
+               LinkTarget $title
+       ) {
+               $pm = MediaWikiServices::getInstance()->getPermissionManager();
+               return $pm->quickUserCan( 'edit', $user, $title )
+               && ( $this->getTitle()->exists() ||
+                        $pm->quickUserCan( 'create', $user, $title ) );
+       }
+
        /**
         * @return array Array in format "link name or number => 'link html'".
         */
@@ -3447,11 +3460,7 @@ class OutputPage extends ContextSource {
 
                # Universal edit button
                if ( $config->get( 'UniversalEditButton' ) && $this->isArticleRelated() ) {
-                       $user = $this->getUser();
-                       if ( $this->getTitle()->quickUserCan( 'edit', $user )
-                               && ( $this->getTitle()->exists() ||
-                                       $this->getTitle()->quickUserCan( 'create', $user ) )
-                       ) {
+                       if ( $this->userCanEditOrCreate( $this->getUser(), $this->getTitle() ) ) {
                                // Original UniversalEditButton
                                $msg = $this->msg( 'edit' )->text();
                                $tags['universal-edit-button'] = Html::element( 'link', [
index f9ad3eb..37791d0 100644 (file)
@@ -231,6 +231,25 @@ class PermissionManager {
                return !count( $this->getPermissionErrorsInternal( $action, $user, $page, $rigor, true ) );
        }
 
+       /**
+        * A convenience method for calling PermissionManager::userCan
+        * with PermissionManager::RIGOR_QUICK
+        *
+        * Suitable for use for nonessential UI controls in common cases, but
+        * _not_ for functional access control.
+        * May provide false positives, but should never provide a false negative.
+        *
+        * @see PermissionManager::userCan()
+        *
+        * @param string $action
+        * @param User $user
+        * @param LinkTarget $page
+        * @return bool
+        */
+       public function quickUserCan( $action, User $user, LinkTarget $page ) {
+               return $this->userCan( $action, $user, $page, self::RIGOR_QUICK );
+       }
+
        /**
         * Can $user perform $action on a page?
         *
index bca1ef6..215e4ec 100644 (file)
@@ -20,6 +20,7 @@
 
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Handles formatting for the "templates used on this page"
@@ -158,11 +159,13 @@ class TemplatesOnThisPageFormatter {
         * Return a link to the edit page, with the text
         * saying "view source" if the user can't edit the page
         *
-        * @param Title $titleObj
+        * @param LinkTarget $titleObj
         * @return string
         */
-       private function buildEditLink( Title $titleObj ) {
-               if ( $titleObj->quickUserCan( 'edit', $this->context->getUser() ) ) {
+       private function buildEditLink( LinkTarget $titleObj ) {
+               if ( MediaWikiServices::getInstance()->getPermissionManager()
+                               ->quickUserCan( 'edit', $this->context->getUser(), $titleObj )
+               ) {
                        $linkMsg = 'editlink';
                } else {
                        $linkMsg = 'viewsourcelink';
index fd2fbd0..f178911 100644 (file)
@@ -401,8 +401,11 @@ class HistoryPager extends ReverseChronologicalPager {
                $tools = [];
 
                # Rollback and undo links
-               if ( $prevRev && $this->getTitle()->quickUserCan( 'edit', $user ) ) {
-                       if ( $latest && $this->getTitle()->quickUserCan( 'rollback', $user ) ) {
+
+               if ( $prevRev && $permissionManager->quickUserCan( 'edit', $user, $this->getTitle() ) ) {
+                       if ( $latest && $permissionManager->quickUserCan( 'rollback',
+                                       $user, $this->getTitle() )
+                       ) {
                                // Get a rollback link without the brackets
                                $rollbackLink = Linker::generateRollback(
                                        $rev,
index 023b88f..e0513e2 100644 (file)
@@ -356,7 +356,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                ApiBase::PARAM_ISMULTI => true,
                        ],
                        'rights' => [
-                               ApiBase::PARAM_TYPE => User::getAllRights(),
+                               ApiBase::PARAM_TYPE => $this->getPermissionManager()->getAllPermissions(),
                                ApiBase::PARAM_ISMULTI => true,
                        ],
                        'prop' => [
index fd2d199..a1945c4 100644 (file)
@@ -231,7 +231,7 @@ class ApiQueryContributors extends ApiQueryBase {
 
        public function getAllowedParams() {
                $userGroups = User::getAllGroups();
-               $userRights = User::getAllRights();
+               $userRights = $this->getPermissionManager()->getAllPermissions();
 
                return [
                        'group' => [
index fcc624e..4d4bb07 100644 (file)
@@ -90,13 +90,13 @@ abstract class AbstractBlock {
        /**
         * Create a new block with specified parameters on a user, IP or IP range.
         *
-        * @param array $options Parameters of the block:
-        *     address string|User  Target user name, User object, IP address or IP range
-        *     by int               User ID of the blocker
-        *     reason string        Reason of the block
-        *     timestamp string     The time at which the block comes into effect
-        *     byText string        Username of the blocker (for foreign users)
-        *     hideName bool        Hide the target user name
+        * @param array $options Parameters of the block, with supported options:
+        *  - address: (string|User) Target user name, User object, IP address or IP range
+        *  - by: (int) User ID of the blocker
+        *  - reason: (string) Reason of the block
+        *  - timestamp: (string) The time at which the block comes into effect
+        *  - byText: (string) Username of the blocker (for foreign users)
+        *  - hideName: (bool) Hide the target user name
         */
        public function __construct( array $options = [] ) {
                $defaults = [
index 45a6301..3f3e2d3 100644 (file)
@@ -40,8 +40,9 @@ class CompositeBlock extends AbstractBlock {
        /**
         * Create a new block with specified parameters on a user, IP or IP range.
         *
-        * @param array $options Parameters of the block:
-        *     originalBlocks Block[] Blocks that this block is composed from
+        * @param array $options Parameters of the block, with options supported by
+        *  `AbstractBlock::__construct`, and also:
+        *  - originalBlocks: (Block[]) Blocks that this block is composed from
         */
        public function __construct( array $options = [] ) {
                parent::__construct( $options );
index 79286c5..6007abd 100644 (file)
@@ -86,18 +86,18 @@ class DatabaseBlock extends AbstractBlock {
        /**
         * Create a new block with specified option parameters on a user, IP or IP range.
         *
-        * @param array $options Parameters of the block:
-        *     user int             Override target user ID (for foreign users)
-        *     auto bool            Is this an automatic block?
-        *     expiry string        Timestamp of expiration of the block or 'infinity'
-        *     anonOnly bool        Only disallow anonymous actions
-        *     createAccount bool   Disallow creation of new accounts
-        *     enableAutoblock bool Enable automatic blocking
-        *     blockEmail bool      Disallow sending emails
-        *     allowUsertalk bool   Allow the target to edit its own talk page
-        *     sitewide bool        Disallow editing all pages and all contribution
-        *                          actions, except those specifically allowed by
-        *                          other block flags
+        * @param array $options Parameters of the block, with options supported by
+        *  `AbstractBlock::__construct`, and also:
+        *  - user: (int) Override target user ID (for foreign users)
+        *  - auto: (bool) Is this an automatic block?
+        *  - expiry: (string) Timestamp of expiration of the block or 'infinity'
+        *  - anonOnly: (bool) Only disallow anonymous actions
+        *  - createAccount: (bool) Disallow creation of new accounts
+        *  - enableAutoblock: (bool) Enable automatic blocking
+        *  - blockEmail: (bool) Disallow sending emails
+        *  - allowUsertalk: (bool) Allow the target to edit its own talk page
+        *  - sitewide: (bool) Disallow editing all pages and all contribution actions,
+        *    except those specifically allowed by other block flags
         *
         * @since 1.26 $options array
         */
index 0cbf125..494a7b9 100644 (file)
@@ -39,11 +39,11 @@ class SystemBlock extends AbstractBlock {
        /**
         * Create a new block with specified parameters on a user, IP or IP range.
         *
-        * @param array $options Parameters of the block:
-        *     systemBlock string   Indicate that this block is automatically
-        *                          created by MediaWiki rather than being stored
-        *                          in the database. Value is a string to return
-        *                          from self::getSystemBlockType().
+        * @param array $options Parameters of the block, with options supported by
+        *  `AbstractBlock::__construct`, and also:
+        *  - systemBlock: (string) Indicate that this block is automatically created by
+        *    MediaWiki rather than being stored in the database. Value is a string to
+        *    return from self::getSystemBlockType().
         */
        public function __construct( array $options = [] ) {
                parent::__construct( $options );
index 7807877..0382d73 100644 (file)
@@ -716,7 +716,9 @@ class ChangesList extends ContextSource {
                        /** Check for rollback permissions, disallow special pages, and only
                         * show a link on the top-most revision
                         */
-                       if ( $title->quickUserCan( 'rollback', $this->getUser() ) ) {
+                       if ( MediaWikiServices::getInstance()->getPermissionManager()
+                               ->quickUserCan( 'rollback', $this->getUser(), $title )
+                       ) {
                                $rev = new Revision( [
                                        'title' => $title,
                                        'id' => $rc->mAttribs['rc_this_oldid'],
index 9723d5a..b8697e5 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 use MediaWiki\MediaWikiServices;
-use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Revision\RevisionRecord;
 use MediaWiki\Revision\SlotRecord;
 use MediaWiki\Storage\NameTableAccessException;
@@ -542,8 +541,8 @@ class DifferenceEngine extends ContextSource {
 
                        $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
 
-                       if ( $samePage && $this->mNewPage && $permissionManager->userCan(
-                               'edit', $user, $this->mNewPage, PermissionManager::RIGOR_QUICK
+                       if ( $samePage && $this->mNewPage && $permissionManager->quickUserCan(
+                               'edit', $user, $this->mNewPage
                        ) ) {
                                if ( $this->mNewRev->isCurrent() && $permissionManager->userCan(
                                        'rollback', $user, $this->mNewPage
@@ -766,12 +765,14 @@ class DifferenceEngine extends ContextSource {
        protected function getMarkPatrolledLinkInfo() {
                $user = $this->getUser();
                $config = $this->getConfig();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
 
                // Prepare a change patrol link, if applicable
                if (
                        // Is patrolling enabled and the user allowed to?
                        $config->get( 'UseRCPatrol' ) &&
-                       $this->mNewPage && $this->mNewPage->quickUserCan( 'patrol', $user ) &&
+                       $this->mNewPage &&
+                       $permissionManager->quickUserCan( 'patrol', $user, $this->mNewPage ) &&
                        // Only do this if the revision isn't more than 6 hours older
                        // than the Max RC age (6h because the RC might not be cleaned out regularly)
                        RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 )
@@ -804,8 +805,7 @@ class DifferenceEngine extends ContextSource {
                        // Build the link
                        if ( $rcid ) {
                                $this->getOutput()->preventClickjacking();
-                               if ( MediaWikiServices::getInstance()->getPermissionManager()
-                                               ->userHasRight( $user, 'writeapi' ) ) {
+                               if ( $permissionManager->userHasRight( $user, 'writeapi' ) ) {
                                        $this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' );
                                }
 
@@ -900,7 +900,11 @@ class DifferenceEngine extends ContextSource {
                                        ) {
                                                $out->addParserOutput( $parserOutput, [
                                                        'enableSectionEditLinks' => $this->mNewRev->isCurrent()
-                                                               && $this->mNewRev->getTitle()->quickUserCan( 'edit', $this->getUser() ),
+                                                               && MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+                                                                       'edit',
+                                                                       $this->getUser(),
+                                                                       $this->mNewRev->getTitle()
+                                                               )
                                                ] );
                                        }
                                }
@@ -1557,7 +1561,8 @@ class DifferenceEngine extends ContextSource {
                                $editQuery['oldid'] = $rev->getId();
                        }
 
-                       $key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold';
+                       $key = MediaWikiServices::getInstance()->getPermissionManager()
+                               ->quickUserCan( 'edit', $user, $title ) ? 'editold' : 'viewsourceold';
                        $msg = $this->msg( $key )->escaped();
                        $editLink = $this->msg( 'parentheses' )->rawParams(
                                Linker::linkKnown( $title, $msg, [], $editQuery ) )->escaped();
index fcfb83d..d8cd1c5 100644 (file)
@@ -635,8 +635,9 @@ class Article implements Page {
                if ( $outputPage->isPrintable() ) {
                        $parserOptions->setIsPrintable( true );
                        $poOptions['enableSectionEditLinks'] = false;
-               } elseif ( $this->viewIsRenderAction
-                       || !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user )
+               } elseif ( $this->viewIsRenderAction || !$this->isCurrent() ||
+                       !MediaWikiServices::getInstance()->getPermissionManager()
+                               ->quickUserCan( 'edit', $user, $this->getTitle() )
                ) {
                        $poOptions['enableSectionEditLinks'] = false;
                }
@@ -1181,7 +1182,8 @@ class Article implements Page {
                $title = $this->getTitle();
                $rc = false;
 
-               if ( !$title->quickUserCan( 'patrol', $user )
+               if ( !MediaWikiServices::getInstance()->getPermissionManager()
+                               ->quickUserCan( 'patrol', $user, $title )
                        || !( $wgUseRCPatrol || $wgUseNPPatrol
                                || ( $wgUseFilePatrol && $title->inNamespace( NS_FILE ) ) )
                ) {
@@ -1450,6 +1452,7 @@ class Article implements Page {
 
                # Show error message
                $oldid = $this->getOldID();
+               $pm = MediaWikiServices::getInstance()->getPermissionManager();
                if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
                        // use fake Content object for system message
                        $parserOptions = ParserOptions::newCanonical( 'canonical' );
@@ -1457,8 +1460,8 @@ class Article implements Page {
                } else {
                        if ( $oldid ) {
                                $text = wfMessage( 'missing-revision', $oldid )->plain();
-                       } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
-                               && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
+                       } elseif ( $pm->quickUserCan( 'create', $this->getContext()->getUser(), $title ) &&
+                               $pm->quickUserCan( 'edit', $this->getContext()->getUser(), $title )
                        ) {
                                $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
                                $text = wfMessage( $message )->plain();
index 2de82bf..dc75541 100644 (file)
@@ -118,6 +118,7 @@ class ImageHistoryList extends ContextSource {
        public function imageHistoryLine( $iscur, $file ) {
                $user = $this->getUser();
                $lang = $this->getLanguage();
+               $pm = MediaWikiServices::getInstance()->getPermissionManager();
                $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
                $img = $iscur ? $file->getName() : $file->getArchiveName();
                $userId = $file->getUser( 'id' );
@@ -128,9 +129,7 @@ class ImageHistoryList extends ContextSource {
                $row = $selected = '';
 
                // Deletion link
-               if ( $local && ( MediaWikiServices::getInstance()
-                               ->getPermissionManager()
-                               ->userHasAnyRight( $user, 'delete', 'deletedhistory' ) )
+               if ( $local && ( $pm->userHasAnyRight( $user, 'delete', 'deletedhistory' ) )
                ) {
                        $row .= '<td>';
                        # Link to remove from history
@@ -173,8 +172,8 @@ class ImageHistoryList extends ContextSource {
                $row .= '<td>';
                if ( $iscur ) {
                        $row .= $this->msg( 'filehist-current' )->escaped();
-               } elseif ( $local && $this->title->quickUserCan( 'edit', $user )
-                       && $this->title->quickUserCan( 'upload', $user )
+               } elseif ( $local && $pm->quickUserCan( 'edit', $user, $this->title )
+                       && $pm->quickUserCan( 'upload', $user, $this->title )
                ) {
                        if ( $file->isDeleted( File::DELETED_FILE ) ) {
                                $row .= $this->msg( 'filehist-revert' )->escaped();
index 4f08995..2e43e8c 100644 (file)
@@ -748,7 +748,8 @@ EOT
                        return;
                }
 
-               $canUpload = $this->getTitle()->quickUserCan( 'upload', $this->getContext()->getUser() );
+               $canUpload = MediaWikiServices::getInstance()->getPermissionManager()
+                       ->quickUserCan( 'upload', $this->getContext()->getUser(), $this->getTitle() );
                if ( $canUpload && UploadBase::userCanReUpload(
                                $this->getContext()->getUser(),
                                $this->mPage->getFile() )
index 212ac47..b0d0678 100644 (file)
@@ -461,7 +461,9 @@ abstract class Skin extends ContextSource {
                                $type = 'ns-subject';
                        }
                        // T208315: add HTML class when the user can edit the page
-                       if ( $title->quickUserCan( 'edit', $user ) ) {
+                       if ( MediaWikiServices::getInstance()->getPermissionManager()
+                                       ->quickUserCan( 'edit', $user, $title )
+                       ) {
                                $type .= ' mw-editable';
                        }
                }
@@ -725,14 +727,17 @@ abstract class Skin extends ContextSource {
                $action = $this->getRequest()->getVal( 'action', 'view' );
                $title = $this->getTitle();
                $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
 
                if ( ( !$title->exists() || $action == 'history' ) &&
-                       $title->quickUserCan( 'deletedhistory', $this->getUser() )
+                       $permissionManager->quickUserCan( 'deletedhistory', $this->getUser(), $title )
                ) {
                        $n = $title->isDeleted();
 
                        if ( $n ) {
-                               if ( $this->getTitle()->quickUserCan( 'undelete', $this->getUser() ) ) {
+                               if ( $permissionManager->quickUserCan( 'undelete',
+                                               $this->getUser(), $this->getTitle() )
+                               ) {
                                        $msg = 'thisisdeleted';
                                } else {
                                        $msg = 'viewdeleted';
index aeca016..3e8972c 100644 (file)
@@ -884,6 +884,7 @@ class SkinTemplate extends Skin {
                $out = $this->getOutput();
                $request = $this->getRequest();
                $user = $this->getUser();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
 
                $content_navigation = [
                        'namespaces' => [],
@@ -895,7 +896,7 @@ class SkinTemplate extends Skin {
                // parameters
                $action = $request->getVal( 'action', 'view' );
 
-               $userCanRead = $title->quickUserCan( 'read', $user );
+               $userCanRead = $permissionManager->quickUserCan( 'read', $user, $title );
 
                // Avoid PHP 7.1 warning of passing $this by reference
                $skinTemplate = $this;
@@ -965,8 +966,9 @@ class SkinTemplate extends Skin {
                                }
 
                                // Checks if user can edit the current page if it exists or create it otherwise
-                               if ( $title->quickUserCan( 'edit', $user )
-                                       && ( $title->exists() || $title->quickUserCan( 'create', $user ) )
+                               if ( $permissionManager->quickUserCan( 'edit', $user, $title ) &&
+                                        ( $title->exists() ||
+                                                $permissionManager->quickUserCan( 'create', $user, $title ) )
                                ) {
                                        // Builds CSS class for talk page links
                                        $isTalkClass = $isTalk ? ' istalk' : '';
@@ -1031,7 +1033,7 @@ class SkinTemplate extends Skin {
                                                'href' => $title->getLocalURL( 'action=history' ),
                                        ];
 
-                                       if ( $title->quickUserCan( 'delete', $user ) ) {
+                                       if ( $permissionManager->quickUserCan( 'delete', $user, $title ) ) {
                                                $content_navigation['actions']['delete'] = [
                                                        'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
                                                        'text' => wfMessageFallback( "$skname-action-delete", 'delete' )
@@ -1040,7 +1042,7 @@ class SkinTemplate extends Skin {
                                                ];
                                        }
 
-                                       if ( $title->quickUserCan( 'move', $user ) ) {
+                                       if ( $permissionManager->quickUserCan( 'move', $user, $title ) ) {
                                                $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
                                                $content_navigation['actions']['move'] = [
                                                        'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
@@ -1051,13 +1053,14 @@ class SkinTemplate extends Skin {
                                        }
                                } else {
                                        // article doesn't exist or is deleted
-                                       if ( $title->quickUserCan( 'deletedhistory', $user ) ) {
+                                       if ( $permissionManager->quickUserCan( 'deletedhistory', $user, $title ) ) {
                                                $n = $title->isDeleted();
                                                if ( $n ) {
                                                        $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
                                                        // If the user can't undelete but can view deleted
                                                        // history show them a "View .. deleted" tab instead.
-                                                       $msgKey = $title->quickUserCan( 'undelete', $user ) ? 'undelete' : 'viewdeleted';
+                                                       $msgKey = $permissionManager->quickUserCan( 'undelete',
+                                                               $user, $title ) ? 'undelete' : 'viewdeleted';
                                                        $content_navigation['actions']['undelete'] = [
                                                                'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
                                                                'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
@@ -1068,9 +1071,10 @@ class SkinTemplate extends Skin {
                                        }
                                }
 
-                               if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() &&
-                                       MediaWikiServices::getInstance()->getPermissionManager()
-                                               ->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
+                               if ( $permissionManager->quickUserCan( 'protect', $user, $title ) &&
+                                        $title->getRestrictionTypes() &&
+                                        $permissionManager->getNamespaceRestrictionLevels( $title->getNamespace(),
+                                                $user ) !== [ '' ]
                                ) {
                                        $mode = $title->isProtected() ? 'unprotect' : 'protect';
                                        $content_navigation['actions'][$mode] = [
@@ -1082,9 +1086,8 @@ class SkinTemplate extends Skin {
                                }
 
                                // Checks if the user is logged in
-                               if ( $this->loggedin && MediaWikiServices::getInstance()
-                                               ->getPermissionManager()
-                                               ->userHasAllRights( $user, 'viewmywatchlist', 'editmywatchlist' )
+                               if ( $this->loggedin && $permissionManager->userHasAllRights( $user,
+                                               'viewmywatchlist', 'editmywatchlist' )
                                ) {
                                        /**
                                         * The following actions use messages which, if made particular to
index da34d81..85f65bb 100644 (file)
@@ -197,7 +197,8 @@ class MovePageForm extends UnlistedSpecialPage {
                }
 
                if ( count( $err ) == 1 && isset( $err[0][0] ) && $err[0][0] == 'articleexists'
-                       && $newTitle->quickUserCan( 'delete', $user )
+                       && MediaWikiServices::getInstance()->getPermissionManager()
+                                ->quickUserCan( 'delete', $user, $newTitle )
                ) {
                        $out->wrapWikiMsg(
                                "<div class='warningbox'>\n$1\n</div>\n",
index ad045e4..2ae4afc 100644 (file)
@@ -518,7 +518,8 @@ class SpecialSearch extends SpecialPage {
                                $messageName = 'searchmenu-exists';
                                $linkClass = 'mw-search-exists';
                        } elseif ( ContentHandler::getForTitle( $title )->supportsDirectEditing()
-                               && $title->quickUserCan( 'create', $this->getUser() )
+                               && MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan( 'create',
+                                       $this->getUser(), $title )
                        ) {
                                $messageName = 'searchmenu-new';
                        }
index d62951c..b80a584 100644 (file)
@@ -439,6 +439,16 @@ class ContribsPager extends RangeChronologicalPager {
                return $this->tagFilter;
        }
 
+       /**
+        * @deprecated since 1.34, redundant.
+        *
+        * @return string "users"
+        */
+       public function getContribs() {
+               // Brought back for backwards compatibility, see T231540.
+               return 'users';
+       }
+
        /**
         * @return string
         */
@@ -573,6 +583,7 @@ class ContribsPager extends RangeChronologicalPager {
                $attribs = [];
 
                $linkRenderer = $this->getLinkRenderer();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
 
                $page = null;
                // Create a title for the revision if possible
@@ -598,8 +609,9 @@ class ContribsPager extends RangeChronologicalPager {
                                $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
                                $classes[] = 'mw-contributions-current';
                                # Add rollback link
-                               if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user )
-                                       && $page->quickUserCan( 'edit', $user )
+                               if ( !$row->page_is_new &&
+                                       $permissionManager->quickUserCan( 'rollback', $user, $page ) &&
+                                       $permissionManager->quickUserCan( 'edit', $user, $page )
                                ) {
                                        $this->preventClickjacking();
                                        $topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext(),
index 0553c92..b0ee5cb 100644 (file)
@@ -4864,8 +4864,7 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Get a list of all available permissions.
         *
-        * @deprecated since 1.34, use MediaWikiServices::getInstance()->getPermissionManager()
-        *             ->getAllPermissions() instead
+        * @deprecated since 1.34, use PermissionManager::getAllPermissions() instead
         *
         * @return string[] Array of permission names
         */
index 7205620..de08607 100644 (file)
                        );
                },
 
+               // match prefix plus any combining characters to prevent ugly rendering (see T35242)
+               prefixPlusComboHighlight: function ( node, prefix ) {
+
+                       // Equivalent to \p{Mark} (which is not currently available in JavaScript)
+                       var comboMarks = '[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]';
+
+                       $.highlightText.innerHighlight(
+                               node,
+                               new RegExp( '(^)' + mw.RegExp.escape( prefix ) + comboMarks + '*', 'i' )
+                       );
+               },
+
                // scans a node looking for the pattern and wraps a span around each match
                innerHighlight: function ( node, pat ) {
                        var i, match, pos, spannode, middlebit, middleclone;
@@ -81,6 +93,8 @@
         * @param {string} [options.method='splitAndHighlight'] Method of matching to use, one of:
         *   - 'splitAndHighlight': Split `matchString` on spaces, then match each word separately.
         *   - 'prefixHighlight': Match `matchString` at the beginning of text only.
+        *   - 'prefixPlusComboHighlight': Match `matchString` plus any combining characters at
+        *     the beginning of text only.
         * @return {jQuery}
         * @chainable
         */
index f4aea72..31afe3e 100644 (file)
                                                        }
 
                                                        if ( context.config.highlightInput ) {
-                                                               $result.highlightText( context.data.prevText, { method: 'prefixHighlight' } );
+                                                               $result.highlightText( context.data.prevText, { method: 'prefixPlusComboHighlight' } );
                                                        }
 
                                                        // Widen results box if needed (new width is only calculated here, applied later).
index 8398ea4..0e788e7 100644 (file)
@@ -448,8 +448,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                                        ->userCan( $action, $this->user, $this->title, true ) );
                        $this->assertEquals( $check[$action][3],
                                MediaWikiServices::getInstance()->getPermissionManager()
-                                       ->userCan( $action, $this->user, $this->title,
-                                       PermissionManager::RIGOR_QUICK ) );
+                                       ->quickUserCan( $action, $this->user, $this->title ) );
                        # count( User::getGroupsWithPermissions( $action ) ) < 1
                }
        }
@@ -888,7 +887,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $this->assertEquals( true,
                        MediaWikiServices::getInstance()->getPermissionManager()
-                               ->userCan( 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+                               ->quickUserCan( 'edit', $this->user, $this->title ) );
 
                $this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
                        "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
@@ -934,11 +933,11 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $this->assertEquals( false,
                        MediaWikiServices::getInstance()->getPermissionManager()
-                               ->userCan( 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+                               ->quickUserCan( 'bogus', $this->user, $this->title ) );
 
                $this->assertEquals( false,
-                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
-                               'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+                               'edit', $this->user, $this->title ) );
 
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
@@ -954,12 +953,12 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
 
                $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
                $this->assertEquals( false,
-                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
-                               'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+                               'bogus', $this->user, $this->title ) );
 
                $this->assertEquals( false,
-                       MediaWikiServices::getInstance()->getPermissionManager()->userCan(
-                               'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
+                       MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(
+                               'edit', $this->user, $this->title ) );
 
                $this->assertEquals( [ [ 'badaccess-group0' ],
                        [ 'protectedpagetext', 'bogus', 'bogus' ],
@@ -1176,8 +1175,7 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        ->userCan( 'move-target', $this->user, $this->title ) );
                // quickUserCan should ignore user blocks
                $this->assertEquals( true, MediaWikiServices::getInstance()->getPermissionManager()
-                       ->userCan( 'move-target', $this->user, $this->title,
-                               PermissionManager::RIGOR_QUICK ) );
+                       ->quickUserCan( 'move-target', $this->user, $this->title ) );
 
                global $wgLocalTZoffset;
                $wgLocalTZoffset = -60;
@@ -1852,6 +1850,22 @@ class PermissionManagerTest extends MediaWikiLangTestCase {
                        ->getNamespaceRestrictionLevels( $ns, $user ) );
        }
 
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::getAllPermissions
+        */
+       public function testGetAllPermissions() {
+               $this->setMwGlobals( [
+                       'wgAvailableRights' => [ 'test_right' ]
+               ] );
+               $this->resetServices();
+               $this->assertContains(
+                       'test_right',
+                       MediaWikiServices::getInstance()
+                               ->getPermissionManager()
+                               ->getAllPermissions()
+               );
+       }
+
        /**
         * @covers \MediaWiki\Permissions\PermissionManager::getRightsCacheKey
         * @throws \Exception
index 2a6575a..2037036 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Try to make sure that extensions register all rights in $wgAvailableRights
  * or via the 'UserGetAllRights' hook.
@@ -19,7 +21,7 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
        private function getAllVisibleRights() {
                global $wgGroupPermissions, $wgRevokePermissions;
 
-               $rights = User::getAllRights();
+               $rights = MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions();
 
                foreach ( $wgGroupPermissions as $permissions ) {
                        $rights = array_merge( $rights, array_keys( $permissions ) );
@@ -38,7 +40,7 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
        public function testAvailableRights() {
                $missingRights = array_diff(
                        $this->getAllVisibleRights(),
-                       User::getAllRights()
+                       MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions()
                );
 
                $this->assertEquals(
@@ -76,7 +78,7 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
         */
        private function checkMessagesExist( $prefix ) {
                // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
-               $allRights = User::getAllRights();
+               $allRights = MediaWikiServices::getInstance()->getPermissionManager()->getAllPermissions();
                $allMessageKeys = Language::getMessageKeysFor( 'en' );
 
                $messagesToCheck = [];