skinOptions = $skinOptions; $this->languagesHelper = $languagesHelper; $this->permissionManager = $permissionManager; $this->contentHandlerFactory = $contentHandlerFactory; $this->userFactory = $userFactory; } /** * @param IContextSource $context * @return $this */ public function setContext( IContextSource $context ) { $this->title = $context->getTitle(); $this->config = $context->getConfig(); $this->performer = $context->getAuthority(); // Title may be undefined in certain contexts (T179833) // TODO: Check if this is still true if we always pass a context instead of using global one if ( $this->title ) { $this->contentHandler = $this->contentHandlerFactory->getContentHandler( $this->title->getContentModel() ); } return $this; } /** * Gets whether or not the action is allowed. * * Actions isn't allowed when: * * * The "edit" action is not allowed if editing is not possible on the page * @see method isCurrentPageContentModelEditable * * The "switch-language" is allowed if there are interlanguage links on the page, * or $wgMinervaAlwaysShowLanguageButton is truthy. * * @inheritDoc * @throws ConfigException */ public function isAllowed( $action ) { global $wgHideInterlanguageLinks; if ( !$this->title ) { return false; } // T206406: Enable "Talk" or "Discussion" button on Main page, also, not forgetting // the "switch-language" button. But disable "edit" and "watch" actions. if ( $this->title->isMainPage() ) { if ( $action === self::SWITCH_LANGUAGE ) { return !$wgHideInterlanguageLinks; } // Only the talk page is allowed on the main page provided user is registered. // talk page permission is disabled on mobile for anons // https://phabricator.wikimedia.org/T54165 return $action === self::TALK && $this->performer->isRegistered(); } if ( $action === self::TALK ) { return ( $this->title->isTalkPage() || $this->title->canHaveTalkPage() ); } if ( $action === self::HISTORY && $this->title->exists() ) { return $this->skinOptions->get( SkinOptions::HISTORY_IN_PAGE_ACTIONS ); } if ( $action === SkinOptions::TOOLBAR_SUBMENU ) { return $this->skinOptions->get( SkinOptions::TOOLBAR_SUBMENU ); } if ( $action === self::EDIT_OR_CREATE ) { return $this->canEditOrCreate(); } if ( $action === self::CONTENT_EDIT ) { return $this->isCurrentPageContentModelEditable(); } if ( $action === self::WATCHABLE || $action === self::WATCH ) { $isWatchable = MediaWikiServices::getInstance()->getWatchlistManager()->isWatchable( $this->title ); if ( $action === self::WATCHABLE ) { return $isWatchable; } if ( $action === self::WATCH ) { return $isWatchable && $this->performer->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' ); } } if ( $action === self::SWITCH_LANGUAGE ) { if ( $wgHideInterlanguageLinks ) { return false; } return $this->languagesHelper->doesTitleHasLanguagesOrVariants( $this->title ) || $this->config->get( 'MinervaAlwaysShowLanguageButton' ); } if ( $action === self::MOVE ) { return $this->canMove(); } if ( $action === self::DELETE ) { return $this->canDelete(); } if ( $action === self::PROTECT ) { return $this->canProtect(); } // Unknown action has been passed. return false; } /** * @inheritDoc */ public function isTalkAllowed() { return $this->isAllowed( self::TALK ); } /** * Checks whether the editor can handle the existing content handler type. * * @return bool */ protected function isCurrentPageContentModelEditable() { if ( !$this->contentHandler ) { return false; } if ( $this->contentHandler->supportsDirectEditing() && $this->contentHandler->supportsDirectApiEditing() ) { return true; } // For content types with custom action=edit handlers, let them do their thing if ( array_key_exists( 'edit', $this->contentHandler->getActionOverrides() ?? [] ) ) { return true; } return false; } /** * Returns true if $title page exists and is editable or is creatable by $user as determined by * quick checks. * @return bool */ private function canEditOrCreate() { if ( !$this->title ) { return false; } $userQuickEditCheck = $this->performer->probablyCan( 'edit', $this->title ) && ( $this->title->exists() || $this->performer->probablyCan( 'create', $this->title ) ); if ( $this->performer->isRegistered() ) { $legacyUser = $this->userFactory->newFromAuthority( $this->performer ); $blocked = $this->permissionManager->isBlockedFrom( $legacyUser, $this->title, true ); } else { $blocked = false; } return $this->isCurrentPageContentModelEditable() && $userQuickEditCheck && !$blocked; } /** * Checks whether the user has the permissions to move the current page. * * @return bool */ private function canMove() { if ( !$this->title ) { return false; } return $this->performer->probablyCan( 'move', $this->title ) && $this->title->exists(); } /** * Checks whether the user has the permissions to delete the current page. * * @return bool */ private function canDelete() { if ( !$this->title ) { return false; } return $this->performer->probablyCan( 'delete', $this->title ) && $this->title->exists(); } /** * Checks whether the user has the permissions to change the protections status of the current page. * * @return bool */ private function canProtect() { if ( !$this->title ) { return false; } return $this->performer->probablyCan( 'protect', $this->title ) && $this->title->exists(); } }